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:
- ESP32-8048S070 A 7inch LCD display powered by an esp32 without touch
- one sided mirror glas 4mm thickness, coatet with chrome with 8% light transmission
- Display housing is an own 3D print
- USB-C Cable
- Frame is a special build from a local frame builder
Software and APIs that i used:
- Home Assistant with MQTT Broker “mosquitto”
- openHASP as FW for the esp32
- API for the local forecast
The result
My Star Trek affection is a bit visible here.
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 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:- raintext
- rainin30min
- rainin60min
- rainin120min
resource: https://morgenwirdes.de/api/v3/rain.php?lat=XXXXXXX&long=XXXXXXXXX #insert here your own coordinates
value_template: “{{ value_json.raintext }}”
- 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}}”
- platform: time_pattern
- 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
- unique_id: mullabfuhr_template #https://www.youtube.com/watch?v=SoBjbW4zjWs
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”}’
- condition: trigger
- 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
- condition: trigger
- conditions:
- platform: device
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
- platform: device
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 **