Smart Mirror with HA, openHASP a 7" Display powered by esp32

Hello everybody,
I just want to show you my (just another) smart mirror project.
Look here for my first iteration: LINK

The goals:
I wanted to build energy-saving smart mirror witch is showing data of my HA System and is completely in open software.

Material that I used:

Software and APIs that i used:

The result

My Star Trek affection is a bit visible here. :upside_down_face:

What do you see from top:
Sorry for the german language on the screen
Top left:

  • Temperature from my balkony sensor
  • Temperature from my livingroom sensor
  • Forcast if it will rain the next 30min. See Used tutorials
  • Time and date from HA

Bottom left:

  • Check if there is a switch/light still on
  • Then is my next vegatable delivery. Same principle as garbage collection
  • When the next garbage collection will take place. See Used tutorials

Right:

  • Todays forecast from weather.home (HA default forecast)

How it looks like.


The rear.

How does this work:
When iam pressing a classic light switch (zigbee switch) or switch it via HA on, the display activates for 2min and the Informations are visible throgh the mirror. Otherwise the display is completely dark and not visible and its a standard mirror.

The architecture
The system has 4ish parts

  • The display configuration based on openHASP
  • The HA automatations for switching on/off and screen saving
  • The HA config files to process es sent the Infomrations to the display…
  • … via the MQTT broker

The Display
To flash the esp32 on the Sunton display is easy via the installer of open HASP.
See the openHasp tutorials for the first configuration steps.
Note: If you using the no touch version you have to change both Display idle settings to “0” under “Display settings”
If you want to use the weather forecast with the icons you have to upload this icons directly into the file editor.

Under the File Editor and “pages.jsonl” you can start and configure your display layout.

Here is my config of the display layout

{“page”:1,“comment”:“Layout top left - Top beam”}
{“page”:1,“id”:50,“obj”:“obj”,“x”:0,“y”:0,“w”:50,“h”:50,“radius”:25,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:51,“obj”:“obj”,“x”:25,“y”:0,“w”:30,“h”:50,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}

{“page”:1,“id”:52,“obj”:“obj”,“x”:165,“y”:0,“w”:260,“h”:50,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:53,“obj”:“obj”,“x”:400,“y”:0,“w”:70,“h”:50,“radius”:25,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:54,“obj”:“obj”,“x”:400,“y”:25,“w”:70,“h”:70,“radius”:1,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:55,“obj”:“obj”,“x”:375,“y”:50,“w”:25,“h”:25,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:56,“obj”:“obj”,“x”:350,“y”:50,“w”:50,“h”:50,“radius”:25,“bg_color”:“#000000”,“border_opa”:0}

{“page”:1,“comment”:“Layout top left - balcony boxes”}
{“page”:1,“id”:120,“obj”:“obj”,“x”:15,“y”:68,“w”:30,“h”:45,“radius”:15,“bg_color”:“#DD6743”,“border_opa”:0}
{“page”:1,“id”:121,“obj”:“obj”,“x”:30,“y”:68,“w”:15,“h”:45,“radius”:1,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“id”:122,“obj”:“obj”,“x”:52,“y”:68,“w”:215,“h”:45,“radius”:1,“bg_color”:“#96A0FF”,“border_opa”:0}

{“page”:1,“id”:123,“obj”:“obj”,“x”:274,“y”:68,“w”:77,“h”:45,“radius”:1,“bg_color”:“#FF9935”,“border_opa”:0}

{“page”:1,“id”:124,“obj”:“obj”,“x”:359,“y”:68,“w”:30,“h”:45,“radius”:15,“bg_color”:“#DD6743”,“border_opa”:0}
{“page”:1,“id”:125,“obj”:“obj”,“x”:359,“y”:68,“w”:15,“h”:45,“radius”:1,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“comment”:“Layout top left - living room boxes”}
{“page”:1,“id”:130,“obj”:“obj”,“x”:15,“y”:123,“w”:30,“h”:45,“radius”:15,“bg_color”:“#DD6743”,“border_opa”:0}
{“page”:1,“id”:131,“obj”:“obj”,“x”:30,“y”:123,“w”:15,“h”:45,“radius”:1,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“id”:132,“obj”:“obj”,“x”:52,“y”:123,“w”:215,“h”:45,“radius”:1,“bg_color”:“#96A0FF”,“border_opa”:0}

{“page”:1,“id”:133,“obj”:“obj”,“x”:274,“y”:123,“w”:77,“h”:45,“radius”:1,“bg_color”:“#FF9935”,“border_opa”:0}

{“page”:1,“id”:134,“obj”:“obj”,“x”:359,“y”:123,“w”:30,“h”:45,“radius”:15,“bg_color”:“#DD6743”,“border_opa”:0}
{“page”:1,“id”:135,“obj”:“obj”,“x”:359,“y”:123,“w”:15,“h”:45,“radius”:1,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“comment”:“Layout top left - top middle beam”}
{“page”:1,“id”:60,“obj”:“obj”,“x”:0,“y”:232,“w”:40,“h”:30,“radius”:15,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:61,“obj”:“obj”,“x”:25,“y”:232,“w”:32,“h”:30,“radius”:0,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:62,“obj”:“obj”,“x”:40,“y”:232,“w”:105,“h”:7,“radius”:0,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:200,“obj”:“obj”,“x”:145,“y”:232,“w”:60,“h”:30,“radius”:0,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:201,“obj”:“obj”,“x”:205,“y”:232,“w”:130,“h”:11,“radius”:0,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:63,“obj”:“obj”,“x”:335,“y”:232,“w”:90,“h”:30,“radius”:0,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:64,“obj”:“obj”,“x”:400,“y”:212,“w”:70,“h”:50,“radius”:25,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:65,“obj”:“obj”,“x”:400,“y”:187,“w”:70,“h”:50,“radius”:1,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:66,“obj”:“obj”,“x”:375,“y”:208,“w”:25,“h”:25,“radius”:0,“bg_color”:“#FF9935”,“border_opa”:0}
{“page”:1,“id”:67,“obj”:“obj”,“x”:350,“y”:182,“w”:50,“h”:50,“radius”:25,“bg_color”:“#000000”,“border_opa”:0}

{“page”:1,“comment”:“Layout top left - top Status rectangle”}
{“page”:1,“id”:68,“obj”:“obj”,“x”:400,“y”:103,“w”:70,“h”:75,“radius”:1,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“comment”:“Layout right - top beam”}
{“page”:1,“id”:70,“obj”:“obj”,“x”:490,“y”:0,“w”:70,“h”:50,“radius”:25,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:71,“obj”:“obj”,“x”:535,“y”:0,“w”:88,“h”:50,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:72,“obj”:“obj”,“x”:490,“y”:25,“w”:70,“h”:70,“radius”:2,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:75,“obj”:“obj”,“x”:723,“y”:0,“w”:48,“h”:50,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:76,“obj”:“obj”,“x”:750,“y”:0,“w”:50,“h”:50,“radius”:25,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:77,“obj”:“obj”,“x”:560,“y”:50,“w”:25,“h”:25,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:78,“obj”:“obj”,“x”:560,“y”:50,“w”:50,“h”:50,“radius”:25,“bg_color”:“#000000”,“border_opa”:0}

{“page”:1,“comment”:“Layout right - Today rectangle”}
{“page”:1,“id”:73,“obj”:“obj”,“x”:490,“y”:103,“w”:70,“h”:140,“radius”:2,“bg_color”:“#96A0FF”,“border_opa”:0}

{“page”:1,“comment”:“Layout right - Next Days rectangle”}
{“page”:1,“id”:74,“obj”:“obj”,“x”:490,“y”:250,“w”:70,“h”:170,“radius”:2,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“comment”:“Layout right - buttom beam”}
{“page”:1,“id”:80,“obj”:“obj”,“x”:490,“y”:428,“w”:70,“h”:30,“radius”:2,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:81,“obj”:“obj”,“x”:490,“y”:430,“w”:70,“h”:50,“radius”:25,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:82,“obj”:“obj”,“x”:520,“y”:450,“w”:280,“h”:30,“radius”:15,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:83,“obj”:“obj”,“x”:560,“y”:425,“w”:25,“h”:25,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:84,“obj”:“obj”,“x”:560,“y”:400,“w”:50,“h”:50,“radius”:25,“bg_color”:“#000000”,“border_opa”:0}

{“page”:1,“comment”:“Layout button left - light check boxes”}
{“page”:1,“id”:110,“obj”:“obj”,“x”:45,“y”:310,“w”:30,“h”:35,“radius”:15,“bg_color”:“#DD6743”,“border_opa”:0}
{“page”:1,“id”:111,“obj”:“obj”,“x”:60,“y”:310,“w”:15,“h”:35,“radius”:1,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“id”:112,“obj”:“obj”,“x”:82,“y”:310,“w”:160,“h”:35,“radius”:1,“bg_color”:“#96A0FF”,“border_opa”:0}

{“page”:1,“id”:113,“obj”:“obj”,“x”:251,“y”:310,“w”:55,“h”:35,“radius”:1,“bg_color”:“#FF9935”,“border_opa”:0}

{“page”:1,“id”:114,“obj”:“obj”,“x”:314,“y”:310,“w”:30,“h”:35,“radius”:15,“bg_color”:“#DD6743”,“border_opa”:0}
{“page”:1,“id”:115,“obj”:“obj”,“x”:314,“y”:310,“w”:15,“h”:35,“radius”:1,“bg_color”:“#DD6743”,“border_opa”:0}

{“page”:1,“comment”:“Layout button left - buttom middle beam”}
{“page”:1,“id”:90,“obj”:“obj”,“x”:0,“y”:268,“w”:40,“h”:30,“radius”:15,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:91,“obj”:“obj”,“x”:25,“y”:268,“w”:32,“h”:30,“radius”:0,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:92,“obj”:“obj”,“x”:40,“y”:291,“w”:203,“h”:7,“radius”:0,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:210,“obj”:“obj”,“x”:145,“y”:268,“w”:60,“h”:30,“radius”:0,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:211,“obj”:“obj”,“x”:205,“y”:287,“w”:130,“h”:11,“radius”:0,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:93,“obj”:“obj”,“x”:335,“y”:268,“w”:90,“h”:30,“radius”:0,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:94,“obj”:“obj”,“x”:400,“y”:268,“w”:70,“h”:50,“radius”:25,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:95,“obj”:“obj”,“x”:400,“y”:290,“w”:70,“h”:94,“radius”:1,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:100,“obj”:“obj”,“x”:375,“y”:298,“w”:25,“h”:25,“radius”:0,“bg_color”:“#96A0FF”,“border_opa”:0}
{“page”:1,“id”:101,“obj”:“obj”,“x”:350,“y”:298,“w”:50,“h”:50,“radius”:25,“bg_color”:“#000000”,“border_opa”:0}

{“page”:1,“comment”:“Layout button left - buttom beam”}
{“page”:1,“id”:96,“obj”:“obj”,“x”:0,“y”:450,“w”:440,“h”:30,“radius”:15,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:97,“obj”:“obj”,“x”:400,“y”:430,“w”:70,“h”:50,“radius”:25,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:98,“obj”:“obj”,“x”:400,“y”:395,“w”:70,“h”:60,“radius”:1,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:102,“obj”:“obj”,“x”:375,“y”:425,“w”:25,“h”:25,“radius”:0,“bg_color”:“#D69B6F”,“border_opa”:0}
{“page”:1,“id”:103,“obj”:“obj”,“x”:350,“y”:400,“w”:50,“h”:50,“radius”:25,“bg_color”:“#000000”,“border_opa”:0}

{“page”:1,“comment”:“Data/texts top left”}
{“page”:1,“id”:1,“obj”:“label”,“x”:60,“y”:0,“w”:200,“h”:50,“text”:“Guten Tag”,“text_color”:“#FF0000”,“text_font”:“OkudaBold42”}
{“page”:1,“id”:3,“obj”:“label”,“x”:56,“y”:60,“w”:208,“h”:50,“text”:“Temp. Balkon:”,“text_font”:“Okuda45”,“align”:“right”,“text_color”:“#000000”}
{“page”:1,“id”:2,“obj”:“label”,“x”:277,“y”:62,“w”:70,“text”:“Balkon tmp °C”,“text_font”:“Okuda45”,“align”:“right”,“text_color”:“#000000”}
{“page”:1,“id”:5,“obj”:“label”,“x”:56,“y”:115,“w”:208,“h”:50,“text”:“Temp.Wohnzimmer:”,“text_font”:“Okuda45”,“align”:“right”,“text_color”:“#000000”}
{“page”:1,“id”:4,“obj”:“label”,“x”:277,“y”:117,“w”:70,“text”:“Wohnz. tmp °C”,“text_font”:“Okuda45”,“align”:“right”,“text_color”:“#000000”}
{“page”:1,“id”:16,“obj”:“label”,“x”:35,“y”:169,“w”:350,“text”:“rain status”,“text_font”:“Okuda40”,“align”:“right”}

{“page”:1,“id”:12,“obj”:“label”,“x”:400,“y”:140,“w”:70,“text”:“Status”,“text_font”:“OkudaBold30”,“align”:“center”}

{“page”:1,“comment”:“Clock”}
{“page”:1,“id”:14,“obj”:“label”,“x”:56,“y”:223,“w”:90,“h”:65 ,“align”:“center”,“text”:“00:00”,“text_color”:“#ffe135”,“text_font”:“OkudaBold65”}
{“page”:1,“id”:15,“obj”:“label”,“x”:195,“y”:239,“w”:150,“h”:42 ,“align”:“center”,“text”:“date”,“text_color”:“#FF0000”,“text_font”:“OkudaBold42”}

{“page”:1,“comment”:“Data/texts buttom left”}
{“page”:1,“id”:8,“obj”:“label”,“x”:251,“y”:300,“w”:55,“text”:“-”,“text_font”:“Okuda40”,“align”:“center”,“text_color”:“#000000”}
{“page”:1,“id”:10,“obj”:“label”,“x”:90,“y”:302,“w”:180,“text”:“Alles Licht aus:”,“text_font”:“Okuda40”,“text_color”:“#000000”}
{“page”:1,“id”:20,“obj”:“label”,“x”:37,“y”:350,“w”:350,“text”:“Grüne Kiste status”,“text_font”:“Okuda40”,“align”:“right”}
{“page”:1,“id”:18,“obj”:“label”,“x”:37,“y”:395,“w”:350,“text”:“Gelber Sack status”,“text_font”:“Okuda40”,“align”:“right”}
{“page”:1,“id”:22,“obj”:“label”,“x”:400,“y”:346,“w”:70,“text”:“Info”,“text_font”:“OkudaBold30”,“align”:“center”}

{“page”:1,“comment”:“Data/texts right”}
{“page”:1,“id”:30,“obj”:“label”,“x”:630,“y”:0,“w”:200,“h”:50,“text”:“Forecast”,“text_color”:“#FF0000”,“text_font”:“OkudaBold42”}
{“page”:1,“id”:31,“obj”:“label”,“x”:490,“y”:201,“w”:70,“h”:50,“text”:“Today”,“text_font”:“OkudaBold30”,“align”:“center”}
{“page”:1,“id”:34,“obj”:“label”,“x”:575,“y”:190,“w”:70,“text”:“Temp. heute”,“text_font”:“Okuda40”,“align”:“center”}
{“page”:1,“id”:32,“obj”:“label”,“x”:615,“y”:190,“w”:200,“text”:“Wetter heute”,“text_font”:“Okuda40”,“align”:“center”}
{“page”:1,“id”:33,“obj”:“img”,“src”:“L:/openhasp_dummy_img.png”,“x”:615,“y”:55}

{“page”:1,“id”:35,“obj”:“label”,“x”:490,“y”:351,“w”:70,“h”:50,“text”:“Next”,“text_font”:“OkudaBold30”,“align”:“center”}
{“page”:1,“id”:36,“obj”:“label”,“x”:490,“y”:381,“w”:70,“h”:50,“text”:“Days”,“text_font”:“OkudaBold30”,“align”:“center”}
{“page”:1,“id”:37,“obj”:“label”,“x”:580,“y”:250,“w”:100,“text”:“Tag +1”,“text_font”:“Okuda40”}
{“page”:1,“id”:38,“obj”:“label”,“x”:660,“y”:250,“w”:70,“text”:“Tmp. Tag +1”,“text_font”:“Okuda40”,“align”:“right”}
{“page”:1,“id”:39,“obj”:“img”,“src”:“L:/openhasp_dummy_img.png”,“x”:750,“y”:255}
{“page”:1,“id”:40,“obj”:“label”,“x”:580,“y”:310,“w”:100,“text”:“Tag +2”,“text_font”:“Okuda40”}
{“page”:1,“id”:41,“obj”:“label”,“x”:660,“y”:310,“w”:70,“text”:“Tmp. Tag +2”,“text_font”:“Okuda40”,“align”:“right”}
{“page”:1,“id”:42,“obj”:“img”,“src”:“L:/openhasp_dummy_img.png”,“x”:750,“y”:315}
{“page”:1,“id”:43,“obj”:“label”,“x”:580,“y”:370,“w”:100,“text”:“Tag +3”,“text_font”:“Okuda40”}
{“page”:1,“id”:44,“obj”:“label”,“x”:660,“y”:370,“w”:70,“text”:“Tmp. Tag +3”,“text_font”:“Okuda40”,“align”:“right”}
{“page”:1,“id”:45,“obj”:“img”,“src”:“L:/openhasp_dummy_img.png”,“x”:750,“y”:375}

The HA configuration
To have the informations displayed as shown above you have to code a bit into the “configuration.yaml” of HA

Here is my config in configuration.yaml of HA

template: !include template.yaml
openhasp: !include openhasp.yaml

sensor: # Sensor zur detektion ob es in 30min,60min oder 120min regnet.

  • platform: rest #Rain Warning Sensor with Home Assistant
    name: regenradar
    scan_interval: 300
    json_attributes:
  • platform: template
    sensors:
    rrraintext:
    friendly_name: “Vorhersage”
    value_template: “{{ state_attr(‘sensor.regenradar’, ‘raintext’) }}”
    rrrainin30min:
    friendly_name: “Regen in 30min”
    value_template: “{{ state_attr(‘sensor.regenradar’, ‘rainin30min’) }}”
    rrrainin60min:
    friendly_name: “Regen in 60min”
    value_template: “{{ state_attr(‘sensor.regenradar’, ‘rainin60min’) }}”
    rrrainin120min:
    friendly_name: “Regen in 120min”
    value_template: “{{ state_attr(‘sensor.regenradar’, ‘rainin120min’) }}”
  • platform: time_date
    display_options:
    • ‘time’
    • ‘date’
    • ‘date_time’
    • ‘date_time_utc’
    • ‘date_time_iso’
    • ‘time_date’
    • ‘time_utc’
      logger: #stehen lassen! Sorgt für die Kommunikation mit dem Smartmirror
      default: warning
      logs:
      custom_components.openhasp: debug
Here is my config in template.yaml of HA

Tägliche Wettervorhersagen

  • trigger:
    • platform: time_pattern
      hours: /1
      action:
    • service: weather.get_forecasts
      target:
      entity_id:
      - weather.home
      data:
      type: daily
      response_variable: tagesvorhersage
      sensor:
    • name: Wettervorhersage daily complett
      unique_id: weather_forecast_daily_complett
      state: “{{ now().isoformat() }}”
      icon: mdi:hours-24
      attributes:
      forecast: “{{tagesvorhersage[‘weather.home’].forecast}}”
  • sensor:
    • unique_id: mullabfuhr_template #https://www.youtube.com/watch?v=SoBjbW4zjWs
      name: mullabfuhr_wann
      state: “{{(((as_timestamp(state_attr(‘calendar.mullabfuhr’, ‘start_time’)))-as_timestamp(now())) | int /60/1440) | round(0,‘ceil’)}}”
      icon: mdi:trash-can
    • unique_id: grunekiste_template #https://www.youtube.com/watch?v=SoBjbW4zjWs
      name: grunekiste_wann
      state: “{{(((as_timestamp(state_attr(‘calendar.grunekiste’, ‘start_time’)))-as_timestamp(now())) | int /60/1440) | round(0,‘ceil’)}}”
      icon: mdi:basket-fill
Here is my config in openhasp.yaml of HA

smartmirror:
objects:
- obj: “p1b2” # temperature of balkony on page 1
properties:
“text”: “{{ states(‘sensor.temperature_18’) | round(1) }}°C”
- obj: “p1b4” # temperature of living room on page 1
properties:
“text”: “{{ states(‘sensor.temperature_2’) | round(1) }}°C”
- obj: “p1b16” # will it rain in next 30min?
properties:
“text”: “{{ ‘Kein Regen’ if is_state(‘sensor.rrrainin30min’,‘0’) else ‘Es regnet’ | e}} in den nächsten 30min.”
- obj: “p1b14” # Clock
properties:
“text”: “{{ states(‘sensor.time’) }}”
- obj: “p1b15” # Date
properties:
“text”: “{{ states(‘sensor.date’) }}”
- obj: “p1b8” # Check if any light is on
properties:
“text”: “{{ ‘nein’ if is_state(‘light.alle_lichter’ or ‘switch.alle_lichtschalter’,‘on’) else ‘ja’ | e}}”
- obj: “p1b18” # When is the next garbage collection
properties: #based on: Example Configurations - openHASP
# Calculation is done in Template.yaml
“text”: >
{% if is_state(‘sensor.mullabfuhr_wann’,‘0’) -%}
Gelber Sack ist heute.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘1’) -%}
Gelber Sack ist morgen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘2’) -%}
Gelber Sack ist ubermorgen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘3’) -%}
Gelber Sack ist in drei Tagen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘4’) -%}
Gelber Sack ist in vier Tagen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘5’) -%}
Gelber Sack ist in funf Tagen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘6’) -%}
Gelber Sack ist in sechs Tagen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘7’) -%}
Gelber Sack ist nächste Woche.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘8’) -%}
Gelber Sack ist nächste Woche.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘9’) -%}
Gelber Sack ist nächste Woche.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘10’) -%}
Gelber Sack ist nächste Woche.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘11’) -%}
Gelber Sack ist in zwei Wochen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘12’) -%}
Gelber Sack ist in zwei Wochen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘13’) -%}
Gelber Sack ist in zwei Wochen.
{% elif is_state(‘sensor.mullabfuhr_wann’,‘14’) -%}
Gelber Sack ist in zwei Wochen.
{% else %}
{{ states(‘sensor.mullabfuhr_wann’) }}
{%- endif %}
- obj: “p1b20” # When is the next green box delivery
properties: #based on: Example Configurations - openHASP
# Calculation is done in Template.yaml
“text”: >
{% if is_state(‘sensor.grunekiste_wann’,‘0’) -%}
Grüne Kiste ist heute.
{% elif is_state(‘sensor.grunekiste_wann’,‘1’) -%}
Grüne Kiste ist morgen.
{% elif is_state(‘sensor.grunekiste_wann’,‘2’) -%}
Grüne Kiste ist ubermorgen.
{% elif is_state(‘sensor.grunekiste_wann’,‘3’) -%}
Grüne Kiste ist in drei Tagen.
{% elif is_state(‘sensor.grunekiste_wann’,‘4’) -%}
Grüne Kiste ist in vier Tagen.
{% elif is_state(‘sensor.grunekiste_wann’,‘5’) -%}
Grüne Kiste ist in funf Tagen.
{% elif is_state(‘sensor.grunekiste_wann’,‘6’) -%}
Grüne Kiste ist in sechs Tagen.
{% elif is_state(‘sensor.grunekiste_wann’,‘7’) -%}
Grüne Kiste ist nächste Woche.
{% elif is_state(‘sensor.grunekiste_wann’,‘8’) -%}
Grüne Kiste ist nächste Woche.
{% elif is_state(‘sensor.grunekiste_wann’,‘9’) -%}
Grüne Kiste ist nächste Woche.
{% elif is_state(‘sensor.grunekiste_wann’,‘10’) -%}
Grüne Kiste ist nächste Woche.
{% elif is_state(‘sensor.grunekiste_wann’,‘11’) -%}
Grüne Kiste ist in zwei Wochen.
{% elif is_state(‘sensor.grunekiste_wann’,‘12’) -%}
Grüne Kiste ist in zwei Wochen.
{% elif is_state(‘sensor.grunekiste_wann’,‘13’) -%}
Grüne Kiste ist in zwei Wochen.
{% elif is_state(‘sensor.grunekiste_wann’,‘14’) -%}
Grüne Kiste ist in zwei Wochen.
{% else %}
{{ states(‘sensor.grunekiste_wann’) }}
{%- endif %}
- obj: “p1b34” # Current temp (you can use your own outdoor temp sensor if you have one)
properties:
“text”: “{{ state_attr(‘weather.home’,‘temperature’) |string + ‘°C’ if not is_state(‘weather.home’,‘unavailable’) }}”
- obj: “p1b32” # Current weather condition
properties: #based on: Example Configurations - openHASP
“text”: >
{% if is_state(‘weather.home’,‘clear-night’) -%}
Clear night
{% elif is_state(‘weather.home’,‘cloudy’) -%}
Cloudy
{% elif is_state(‘weather.home’,‘fog’) -%}
Fog
{% elif is_state(‘weather.home’,‘hail’) -%}
Hail
{% elif is_state(‘weather.home’,‘lightning’) -%}
Lightning
{% elif is_state(‘weather.home’,‘lightning-rainy’) -%}
Thunderstorms
{% elif is_state(‘weather.home’,‘partlycloudy’) -%}
Partly cloudy
{% elif is_state(‘weather.home’,‘pouring’) -%}
Pouring rain
{% elif is_state(‘weather.home’,‘rainy’) -%}
Rainy
{% elif is_state(‘weather.home’,‘snowy’) -%}
Snowy
{% elif is_state(‘weather.home’,‘snowy-rainy’) -%}
Snowy-rainy
{% elif is_state(‘weather.home’,‘sunny’) -%}
Sunny
{% elif is_state(‘weather.home’,‘windy’) -%}
Windy
{% elif is_state(‘weather.home’,‘windy-variant’) -%}
Windy
{% elif is_state(‘weather.home’,‘exceptional’) -%}
Exceptional
{% elif is_state(‘weather.home’,‘unavailable’) -%}
(not available)
{% else -%}
{{ states(‘weather.home’) }}
{% endif -%}
- obj: “p1b33” # Icon for the weather today
properties: #based on: Example Configurations - openHASP
“src”: “{{ ‘L:/z-128-’ + states(‘weather.home’) + ‘.png’ if not is_state(‘weather.home’,‘unavailable’) }}”
- obj: “p1b37” # Forecast date +1d
properties: #based on: Example Configurations - openHASP
“text”: >
{%- if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) %}
{%- set now = as_timestamp(strptime(state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[0][‘datetime’], ‘%Y-%m-%dT%H:%M:%S%z’, default=‘2020-01-00T00:00:00+00:00’)) %}
{%- set day = now | timestamp_custom(“%w”) %}
{%- set days = [“Mo.”, “Di.”, “Mi.”, “Do.”, “Fr.”, “Sa.”, “So.”] %}
{{- now | timestamp_custom(" %d") }}. {{ days[ day | int -1 ] }}
{%- endif %}
- obj: “p1b38” # Forecast temp +1d
properties: #based on: Example Configurations - openHASP
“text”: “{{ state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[0][‘temperature’] if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) else ‘-’ }}°C”
- obj: “p1b39” # Forecast icon +1d
properties:
“src”: >
{%- if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) %}
L:/z-32-{{ state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[0][‘condition’] }}.png
{%- endif %}
- obj: “p1b40” # Forecast date +2d
properties: #based on: Example Configurations - openHASP
“text”: >
{%- if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) %}
{%- set now = as_timestamp(strptime(state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[1][‘datetime’], ‘%Y-%m-%dT%H:%M:%S%z’, default=‘2020-01-00T00:00:00+00:00’)) %}
{%- set day = now | timestamp_custom(“%w”) %}
{%- set days = [“Mo.”, “Di.”, “Mi.”, “Do.”, “Fr.”, “Sa.”, “So.”] %}
{{- now | timestamp_custom(" %d") }}. {{ days[ day | int -1 ] }}
{%- endif %}
- obj: “p1b41” # Forecast temp +2d
properties: #based on: Example Configurations - openHASP
“text”: “{{ state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[1][‘temperature’] if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) else ‘-’ }}°C”
- obj: “p1b42” # Forecast icon +2d
properties:
“src”: >
{%- if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) %}
L:/z-32-{{ state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[1][‘condition’] }}.png
{%- endif %}
- obj: “p1b43” # Forecast date +3d
properties: #based on: Example Configurations - openHASP
“text”: >
{%- if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) %}
{%- set now = as_timestamp(strptime(state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[2][‘datetime’], ‘%Y-%m-%dT%H:%M:%S%z’, default=‘2020-01-00T00:00:00+00:00’)) %}
{%- set day = now | timestamp_custom(“%w”) %}
{%- set days = [“Mo.”, “Di.”, “Mi.”, “Do.”, “Fr.”, “Sa.”, “So.”] %}
{{- now | timestamp_custom(" %d") }}. {{ days[ day | int -1 ] }}
{%- endif %}
- obj: “p1b44” # Forecast temp +3d
properties: #based on: Example Configurations - openHASP
“text”: “{{ state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[2][‘temperature’] if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) else ‘-’ }}°C”
- obj: “p1b45” # Forecast icon +3d
properties:
“src”: >
{%- if not is_state(‘sensor.wettervorhersage_daily_complett’,‘unavailable’) %}
L:/z-32-{{ state_attr(‘sensor.wettervorhersage_daily_complett’,‘forecast’)[2][‘condition’] }}.png
{%- endif %}

Important note: For an easy implementation of the Display into the HA its recommended to install the openHASP addon.

The HA automations

To prevent a burn in of the pixels I used the recommended automation from openHASP

Automations for preventing burn in
  • id: ‘1685561328035’
    alias: 'Smartmirror blackout screen ’
    description: ‘Renders black overlay when backlight is off to prevent burn in.
    Deletes when back light on.’
    trigger:
    • platform: device
      type: turned_off
      device_id: 1019d326c076966c3bc2ce8282143654
      entity_id: light.smartmirror_backlight
      domain: light
      id: backlight off
    • platform: device
      type: turned_on
      device_id: 1019d326c076966c3bc2ce8282143654
      entity_id: light.smartmirror_backlight
      domain: light
      id: backlight on
      condition:
      action:
    • choose:
      • conditions:
        • condition: trigger
          id: backlight off
          sequence:
        • service: mqtt.publish
          data:
          qos: 0
          topic: hasp/smartmirror/command/jsonl
          payload: ‘{“page”:0,“id”:99,“obj”:“obj”,“x”:0,“y”:0,“w”:800,“h”:480,“radius”:0,“hidden”:0,“bg_grad_dir”:0,“bg_color”:“black”}’
      • conditions:
        • condition: trigger
          id: backlight on
          sequence:
        • service: mqtt.publish
          data:
          qos: 0
          topic: hasp/smartmirror/command/p0b99.hidden
          payload: ‘1’
        • service: mqtt.publish
          data:
          qos: 0
          topic: hasp/desk1/command/p0b99.delete
          payload: ‘’
          mode: single
example automation for switching after 2min off
  • id: ‘1686344325037’
    alias: Smartmirror 2min off
    description: switching the Smartmirror backlight after some time off
    trigger:
    • platform: device
      type: turned_on
      device_id: 1019d326c076966c3bc2ce8282143654
      entity_id: light.smartmirror_backlight
      domain: light
      condition:
      action:
    • delay:
      hours: 0
      minutes: 2
      seconds: 0
      milliseconds: 0
    • type: turn_off
      device_id: 1019d326c076966c3bc2ce8282143654
      entity_id: light.smartmirror_backlight
      domain: light
      mode: single

The Hardware
So far as mentioned I let somone build me the frame arount the glass. I only 3D printed the housing for the display witch is glued to the back of the frame. To provide electricity I decided to have plug at the underside. Theoretically it is possible to use a power bank as a electricity source but I have a Socet right under the mirror witch i dont need.

So far here my explanation about my setup. If you have further questions feel free to ask me.

** Used Tutorials **

  • How to make events in the local HA calendar and present them in espHome LINK
  • How to implement an Rain Forcast for the next 30-120min LINK
  • a comparable project LINK
  • How to use the new Weather forecasts LINK
8 Likes

LCARS!! Whooohooo :slight_smile:

Regen, übermorgen and Tagen could do with a bit more descender space though :wink:

1 Like

Nice! If I had a dollar for each LCARS system I have or have made in the past… It’s a cool looking system but very difficult to use it in real life and have it make any real sense :slight_smile:

Actually, since i use the system we dont forget the garbage anymore when we leave the house. :smiley:
Also the check for lights is helpful.
But the most important part is the check if it rains in the next 30min. We use the bycicle a lot and this helps a lot in choosing the correct jacket or dont leave the house at all. :smiley:

I never really liked LCARS, can’t see the attraction.

But I really like this magic mirror! I always thought a touch one would just get grubby, so the info only concept is quite nice.

Yeah, LCARS is of course a personal preference. Its just a layout.

I, also never understood why anyone what touch on a mirror. :smiley: