diff --git a/automations.yaml b/automations.yaml index 02c9895..7415ed3 100644 --- a/automations.yaml +++ b/automations.yaml @@ -139,6 +139,10 @@ trigger: time conditions: [] actions: + - action: notify.mobile_app_apollo + data: + message: Lodere es, Lustknabe. + title: 420! - data: title: 420! message: Lodere es, Lustknabe. @@ -179,10 +183,6 @@ topic: awtrix_desk/notify payload: '{"text": "420, lodere es, Lustknabe!"}' action: mqtt.publish - - action: notify.mobile_app_apollo - data: - message: Lodere es, Lustknabe. - title: 420! mode: single - id: '1623911524804' alias: TV Anti-Reflexion (undo) @@ -227,28 +227,28 @@ action: light.turn_on - data: cache: true - media_player_entity_id: media_player.home_assistant_voice_0a7c6b_media_player + media_player_entity_id: media_player.home_assistant_voice_0a7c6b message: Ab ins Bett, Schlafenszeit. target: entity_id: tts.piper - enabled: true action: tts.speak + enabled: true - data: cache: true - media_player_entity_id: media_player.home_assistant_voice_09c0e7_media_player + media_player_entity_id: media_player.home_assistant_voice_09c0e7_media_player_2 message: Ab ins Bett, Schlafenszeit. target: entity_id: tts.piper - enabled: true action: tts.speak + enabled: true - data: cache: true media_player_entity_id: media_player.m5stack_atom_echo message: Ab ins Bett, Schlafenszeit. target: entity_id: tts.piper - enabled: true action: tts.speak + enabled: true mode: single - id: '1623954512941' alias: Licht im Schlafzimmer zum Aufwachen einschalten @@ -278,10 +278,8 @@ alias: 'Anruf: Beim Klingeln grün blinken' description: '' triggers: - - entity_id: - - sensor.fritz_box_7690_anrufmonitor_dem_commander1024_seine_cloud - to: - - ringing + - entity_id: sensor.fritz_box_7490_call_monitor_dem_commander1024_seine_cloud + to: ringing trigger: state - entity_id: - sensor.le2123_phone_state_2 @@ -303,8 +301,8 @@ - 0 target: entity_id: - - light.awtrix_b8658c_indicator_1 - - light.awtrix_528bd4_indicator_1 + - light.awtrix_desk_indicator_1 + - light.awtrix_kitchen_indicator_1 action: light.turn_on - data: scene_id: wled_last_state @@ -337,18 +335,16 @@ - data: {} target: entity_id: - - light.awtrix_b8658c_indicator_1 - - light.awtrix_528bd4_indicator_1 + - light.awtrix_desk_indicator_1 + - light.awtrix_kitchen_indicator_1 action: light.turn_off mode: single - id: '1625481640348' alias: 'Anruf: Beim Telefonieren Musik pausieren' description: '' triggers: - - entity_id: - - sensor.fritz_box_7690_anrufmonitor_dem_commander1024_seine_cloud - to: - - talking + - entity_id: sensor.fritz_box_7490_call_monitor_telefonbuch + to: talking trigger: state - entity_id: - sensor.le2123_phone_state_2 @@ -366,8 +362,9 @@ - data: scene_id: media_last_state snapshot_entities: - - media_player.wohnzimmer + - media_player.wohnzimmer_main - media_player.lg_webos_smart_tv + - media_player.ccze - media_player.spotify_marcus_scholz - media_player.xboxonex action: scene.create @@ -388,7 +385,7 @@ trigger: state - target: entity_id: - - scene.wled_last_state + - scene.media_last_state action: scene.turn_on data: {} mode: single @@ -618,33 +615,12 @@ action: notify.mobile_app_le2123 - data: cache: true - media_player_entity_id: media_player.home_assistant_voice_0a7c6b_media_player + media_player_entity_id: media_player.raspiaudio_muse_luxe message: '{{message}} ' target: entity_id: tts.piper - enabled: true - action: tts.speak - - data: - cache: true - media_player_entity_id: media_player.home_assistant_voice_09c0e7_media_player - message: '{{message}} - - ' - target: - entity_id: tts.piper - enabled: true - action: tts.speak - - data: - cache: true - media_player_entity_id: media_player.m5stack_atom_echo - message: '{{message}} - - ' - target: - entity_id: tts.piper - enabled: true action: tts.speak variables: message: 'Die Außentemperatur ist mit {{states(''sensor.aussentemperatur'')}} @@ -689,33 +665,12 @@ action: notify.mobile_app_le2123 - data: cache: true - media_player_entity_id: media_player.home_assistant_voice_0a7c6b_media_player + media_player_entity_id: media_player.raspiaudio_muse_luxe message: '{{message}} ' target: entity_id: tts.piper - enabled: true - action: tts.speak - - data: - cache: true - media_player_entity_id: media_player.home_assistant_voice_09c0e7_media_player - message: '{{message}} - - ' - target: - entity_id: tts.piper - enabled: true - action: tts.speak - - data: - cache: true - media_player_entity_id: media_player.m5stack_atom_echo - message: '{{message}} - - ' - target: - entity_id: tts.piper - enabled: true action: tts.speak mode: single variables: @@ -1438,3 +1393,113 @@ device_id: 6d1be741876624a70ab5b01b54c6fd6f entity_id: 621e4377a089b7f5d92c7c9f2cc171a1 domain: switch +- id: '1773000000001' + alias: epaperframe - Kalender Events laden + description: Ruft alle Events von calendar.privat und calendar.tkrz_kalender für heute und morgen ab und schreibt sie in input_text-Helfer. + triggers: + # Täglich um 00:01 neu holen + - trigger: time + at: '00:01:00' + id: daily + actions: + # ── Events für heute (00:00 bis 23:59) holen ── + - action: calendar.get_events + target: + entity_id: + - calendar.privat + - calendar.tkrz_kalender + data: + start_date_time: "{{ now().replace(hour=0, minute=0, second=0) }}" + end_date_time: "{{ (now().replace(hour=0, minute=0, second=0) + timedelta(days=1)) }}" + response_variable: today_evts + + # ── Events für morgen (00:00 bis 23:59) holen ── + - action: calendar.get_events + target: + entity_id: + - calendar.privat + - calendar.tkrz_kalender + data: + start_date_time: "{{ (now() + timedelta(days=1)).replace(hour=0, minute=0, second=0) }}" + end_date_time: "{{ (now() + timedelta(days=1)).replace(hour=0, minute=0, second=0) + timedelta(days=1) }}" + response_variable: tomorrow_evts + + # ── Helper: Events als kompakte Liste formatieren ── + + # Privat heute + - set_var: + name: fmt_today_privat + value: >- + {%- set evts = today_evts['calendar.privat']['events'] if 'calendar.privat' in today_evts else [] %} + {%- set items = [] %} + {%- for e in evts[:5] %} + {%- set s = (e['summary'] | default('', true) | string)[:40] if e is mapping and 'summary' in e else '-' %} + {%- set st = e['start'] if e is mapping and 'start' in e else '' %} + {%- set hhmm = st[11:16] if st|length >= 16 else '??' %} + {%- set items = items + [hhmm ~ ' - ' ~ s] %} + {%- endfor -%} + {{ items | join('│') if items else '-' }} + + # Arbeit heute + - set_var: + name: fmt_today_arbeit + value: >- + {%- set evts = today_evts['calendar.tkrz_kalender']['events'] if 'calendar.tkrz_kalender' in today_evts else [] %} + {%- set items = [] %} + {%- for e in evts[:5] %} + {%- set s = (e['summary'] | default('', true) | string)[:40] if e is mapping and 'summary' in e else '-' %} + {%- set st = e['start'] if e is mapping and 'start' in e else '' %} + {%- set hhmm = st[11:16] if st|length >= 16 else '??' %} + {%- set items = items + [hhmm ~ ' - ' ~ s] %} + {%- endfor -%} + {{ items | join('│') if items else '-' }} + + # Privat morgen + - set_var: + name: fmt_tomorrow_privat + value: >- + {%- set evts = tomorrow_evts['calendar.privat']['events'] if 'calendar.privat' in tomorrow_evts else [] %} + {%- set items = [] %} + {%- for e in evts[:5] %} + {%- set s = (e['summary'] | default('', true) | string)[:40] if e is mapping and 'summary' in e else '-' %} + {%- set st = e['start'] if e is mapping and 'start' in e else '' %} + {%- set hhmm = st[11:16] if st|length >= 16 else '??' %} + {%- set items = items + [hhmm ~ ' - ' ~ s] %} + {%- endfor -%} + {{ items | join('│') if items else '-' }} + + # Arbeit morgen + - set_var: + name: fmt_tomorrow_arbeit + value: >- + {%- set evts = tomorrow_evts['calendar.tkrz_kalender']['events'] if 'calendar.tkrz_kalender' in tomorrow_evts else [] %} + {%- set items = [] %} + {%- for e in evts[:5] %} + {%- set s = (e['summary'] | default('', true) | string)[:40] if e is mapping and 'summary' in e else '-' %} + {%- set st = e['start'] if e is mapping and 'start' in e else '' %} + {%- set hhmm = st[11:16] if st|length >= 16 else '??' %} + {%- set items = items + [hhmm ~ ' - ' ~ s] %} + {%- endfor -%} + {{ items | join('│') if items else '-' }} + + # ── input_text Helfer schreiben ── + - action: input_text.set_value + target: + entity_id: input_text.kalender_heute_privat + data: + value: "{{ fmt_today_privat }}" + - action: input_text.set_value + target: + entity_id: input_text.kalender_heute_arbeit + data: + value: "{{ fmt_today_arbeit }}" + - action: input_text.set_value + target: + entity_id: input_text.kalender_morgen_privat + data: + value: "{{ fmt_tomorrow_privat }}" + - action: input_text.set_value + target: + entity_id: input_text.kalender_morgen_arbeit + data: + value: "{{ fmt_tomorrow_arbeit }}" diff --git a/configuration.yaml b/configuration.yaml index 56cfcf1..4a55430 100644 --- a/configuration.yaml +++ b/configuration.yaml @@ -49,6 +49,9 @@ sql: # calendar integration calendar: !include calendars.yaml +# Helpers for epaperframe calendar display +input_text: !include text_helpers.yaml + # DB-recorder configuration recorder: !include recorder.yaml @@ -82,8 +85,3 @@ generic_hygrostat: frontend: themes: !include_dir_merge_named themes - -freedns: - url: !secret freedns6_url -# - name: IPv4 -# url: !secret freedns4_url diff --git a/esphome/epaperframe.yaml b/esphome/epaperframe.yaml index eba92fd..484a06f 100644 --- a/esphome/epaperframe.yaml +++ b/esphome/epaperframe.yaml @@ -15,7 +15,7 @@ esphome: priority: -10 then: - delay: 10s - - display.page.show: power # temporary for power page dev + - display.page.show: calendar # temporary for power page dev - component.update: epaper esp32: @@ -29,7 +29,7 @@ network: wifi: ssid: "Voltage-legacy" password: !secret voltage_legacy_psk - #use_address: epaperframe.home +# use_address: epaperframe.home power_save_mode: high fast_connect: on min_auth_mode: WPA2 @@ -81,7 +81,7 @@ binary_sensor: then: - logger.log: level: INFO - format: 'Button doubleclick, rendering next page!' + format: "Button doubleclick, rendering next page!" - display.page.show_next: epaper - component.update: epaper - timing: @@ -90,7 +90,7 @@ binary_sensor: then: - logger.log: level: INFO - format: 'Button click, refreshing screen!' + format: "Button click, refreshing screen!" - component.update: epaper # HA pushbutton configuration @@ -102,7 +102,7 @@ button: on_press: - logger.log: level: INFO - format: 'HA Button click, refreshing screen!' + format: "HA Button click, refreshing screen!" - component.update: epaper - platform: template name: Next screen @@ -111,7 +111,7 @@ button: on_press: - logger.log: level: INFO - format: 'HA Button click, rendering next page!' + format: "HA Button click, rendering next page!" - display.page.show_next: epaper - component.update: epaper @@ -122,10 +122,6 @@ sensor: id: wifisignal update_interval: 60s - - platform: homeassistant - entity_id: sensor.livingroom_wohnzimmer_feinstaub_pm_2_5_m - id: pm25_livingroom - - platform: homeassistant entity_id: sensor.wohnzimmer_temperatur id: temp_livingroom @@ -139,8 +135,8 @@ sensor: id: co2_livingroom - platform: homeassistant - entity_id: sensor.alpstuga_air_quality_monitor_pm25_2 - id: pm25_sleepingroom + entity_id: sensor.livingroom_wohnzimmer_feinstaub_pm_2_5_m + id: pm25_livingroom - platform: homeassistant entity_id: sensor.alpstuga_air_quality_monitor_temperatur_2 @@ -154,6 +150,26 @@ sensor: entity_id: sensor.alpstuga_air_quality_monitor_kohlendioxid_2 id: co2_sleepingroom + - platform: homeassistant + entity_id: sensor.alpstuga_air_quality_monitor_pm25_2 + id: pm25_sleepingroom + + - platform: homeassistant + entity_id: sensor.alpstuga_air_quality_monitor_temperatur + id: temp_childrensroom + + - platform: homeassistant + entity_id: sensor.alpstuga_air_quality_monitor_luftfeuchtigkeit + id: humid_childrensroom + + - platform: homeassistant + entity_id: sensor.alpstuga_air_quality_monitor_kohlendioxid + id: co2_childrensroom + + - platform: homeassistant + entity_id: sensor.alpstuga_air_quality_monitor_pm25 + id: pm25_childrensroom + - platform: homeassistant entity_id: sensor.aussentemperatur id: temp_outdoor @@ -189,11 +205,11 @@ sensor: - platform: homeassistant entity_id: sensor.schlafzimmer_bett_power id: bedlight_sleepingroom - + - platform: homeassistant entity_id: sensor.schlafzimmer_heimkino_power id: media_sleepingroom - + - platform: homeassistant entity_id: sensor.radioaktive_strahlungsleistung id: radiation @@ -205,7 +221,7 @@ text_sensor: entity_id: sensor.sun_rising_template id: sun_rising internal: true - + - platform: homeassistant name: "Sun Setting ESP" #entity_id: sensor.sun_next_setting @@ -221,21 +237,26 @@ text_sensor: entity_id: weather.zuhause id: weather + # ── Kalender-Ereignisse (from HA input_text helpers) ── - platform: homeassistant - entity_id: sensor.schlafzimmer_co2_warnstufe - id: szco2 + entity_id: sensor.kalender_heute_privat + id: kalender_heute_privat + internal: true - platform: homeassistant - entity_id: sensor.schlafzimmer_feinstaub_warnstufe - id: szpm + entity_id: sensor.kalender_heute_arbeit + id: kalender_heute_arbeit + internal: true - platform: homeassistant - entity_id: sensor.wohnzimmer_co2_warnstufe - id: wzco2 + entity_id: sensor.kalender_morgen_privat + id: kalender_morgen_privat + internal: true - platform: homeassistant - entity_id: sensor.wohnzimmer_feinstaub_warnstufe - id: wzpm + entity_id: sensor.kalender_morgen_arbeit + id: kalender_morgen_arbeit + internal: true graph: - id: line_power_graph @@ -248,144 +269,476 @@ time: - platform: homeassistant id: homeassistant_time on_time: - # Every 10 seconds - - seconds: /10 - then: - - logger.log: - level: INFO - format: 'Power button press' - - output.turn_on: power_key - - delay: 0.5s - - output.turn_off: power_key - # Every 10 minutes - - seconds: 0 - minutes: /10 - then: - - logger.log: - level: INFO - format: 'Timer based screen refresh' - - component.update: epaper + # Every 10 seconds + - seconds: /10 + then: + - logger.log: + level: INFO + format: "Power button press" + - output.turn_on: power_key + - delay: 0.5s + - output.turn_off: power_key + # Every 10 minutes + - seconds: 0 + minutes: /10 + then: + - logger.log: + level: INFO + format: "Timer based screen refresh" + - component.update: epaper # Font definitions font: - - file: 'fonts/Roboto-Medium.ttf' + - file: "fonts/Roboto-Medium.ttf" id: roboto_med_30 size: 30 - - file: 'fonts/Roboto-Regular.ttf' + - file: "fonts/Roboto-Regular.ttf" id: footer_font size: 15 glyphs: - ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'Ä', 'ä', 'ö', '/', 'º', 'µ', '³', 'ß', - 'Ü', 'ü', 'Ö', '0'] + [ + "&", + "@", + "!", + ",", + ".", + '"', + "%", + "(", + ")", + "+", + "-", + "_", + ":", + "°", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + " ", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "Ä", + "ä", + "ö", + "/", + "º", + "µ", + "³", + "ß", + "Ü", + "ü", + "Ö", + "0", + ] - - file: 'fonts/Roboto-Regular.ttf' + - file: "fonts/Roboto-Regular.ttf" id: sensor_unit size: 20 glyphs: - ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'Ä', 'ä', 'ö', '/', 'º', 'µ', '³', 'ß', - 'Ü', 'ü', 'Ö', '0'] + [ + "&", + "@", + "!", + ",", + ".", + '"', + "%", + "(", + ")", + "+", + "-", + "_", + ":", + "°", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + " ", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "Ä", + "ä", + "ö", + "/", + "º", + "µ", + "³", + "ß", + "Ü", + "ü", + "Ö", + "0", + ] - - file: 'fonts/Roboto-Medium.ttf' + - file: "fonts/Roboto-Medium.ttf" id: sub_sensor_font size: 30 glyphs: - ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'Ä', 'ä', 'ö', '/', 'º', 'µ', '³', 'ß', - 'Ü', 'ü', 'Ö', '0'] + [ + "&", + "@", + "!", + ",", + ".", + '"', + "%", + "(", + ")", + "+", + "-", + "_", + ":", + "°", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + " ", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "Ä", + "ä", + "ö", + "/", + "º", + "µ", + "³", + "ß", + "Ü", + "ü", + "Ö", + "0", + ] - - file: 'fonts/Roboto-Bold.ttf' + - file: "fonts/Roboto-Bold.ttf" id: big_sensor_font size: 50 glyphs: - ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'Ä', 'ä', 'ö', '/', 'º', 'µ', '³', 'ß', - 'Ü', 'ü', 'Ö', '0'] + [ + "&", + "@", + "!", + ",", + ".", + '"', + "%", + "(", + ")", + "+", + "-", + "_", + ":", + "°", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + " ", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "Ä", + "ä", + "ö", + "/", + "º", + "µ", + "³", + "ß", + "Ü", + "ü", + "Ö", + "0", + ] - - file: 'fonts/materialdesignicons-webfont.ttf' - id: mdi_small + - file: "fonts/materialdesignicons-webfont.ttf" + id: mdi_small size: 31 glyphs: [ - '󰔏', # mdi-thermometer - '󰖎', # mdi-water-percent - '󰮬', # mdi-molecule (pm2.5) - '󰟤', # mdi-co2 - '󰊚', # mdi-gauge (air pressure) - '󰖙', # mdi-weather-sunny - '󰖛', # mdi-weather-sunset-down - '󰖜', # mdi-weather-sunset-up - '󱐋', # mdi-lightning-bolt - '󰴾', # mdi-transmission-tower - '󰚥', # mdi-power-plug - '󱈹', # mdi-desk - '󰔂', # mdi-television - '󰐼' # mdi-radiation + "󰔏", # mdi-thermometer + "󰖎", # mdi-water-percent + "󰮬", # mdi-molecule (pm2.5) + "󰟤", # mdi-co2 + "󰊚", # mdi-gauge (air pressure) + "󰖙", # mdi-weather-sunny + "󰖛", # mdi-weather-sunset-down + "󰖜", # mdi-weather-sunset-up + "󱐋", # mdi-lightning-bolt + "󰴾", # mdi-transmission-tower + "󰚥", # mdi-power-plug + "󱈹", # mdi-desk + "󰔂", # mdi-television + "󰐼", # mdi-radiation ] - - file: 'fonts/materialdesignicons-webfont.ttf' - id: mdi_weather + - file: "fonts/materialdesignicons-webfont.ttf" + id: mdi_weather size: 80 glyphs: [ - '󰽡', # mdi-moon-first-quarter - '󰽢', # mdi-moon-full - '󰽣', # mdi-moon-last-quarter - '󰽤', # mdi-moon-new - '󰽥', # mdi-moon-waning-crescent - '󰽦', # mdi-moon-waning-gibbous - '󰽧', # mdi-moon-waxing-crescent - '󰽨', # mdi-moon-waxing-gibbous - '󰖔', # mdi-weather-night - '󰖐', # mdi-weather-cloudy - '󰖑', # mdi-weather-fog - '󰖒', # mdi-weather-hail - '󰖓', # mdi-weather-lightning - '󰙾', # mdi-weather-lightning-rainy - '󰖕', # mdi-weather-partly-cloudy - '󰖖', # mdi-weather-pouring - '󰖗', # mdi-weather-rainy - '󰖘', # mdi-weather-snowy - '󰙿', # mdi-weather-snowy-rainy - '󰖙', # mdi-weather-sunny - '󰖝', # mdi-weather-windy - '󰖞', # mdi-weather-windy-variant - '󰳥' # mdi-weather-exceptional + "󰽡", # mdi-moon-first-quarter + "󰽢", # mdi-moon-full + "󰽣", # mdi-moon-last-quarter + "󰽤", # mdi-moon-new + "󰽥", # mdi-moon-waning-crescent + "󰽦", # mdi-moon-waning-gibbous + "󰽧", # mdi-moon-waxing-crescent + "󰽨", # mdi-moon-waxing-gibbous + "󰖔", # mdi-weather-night + "󰖐", # mdi-weather-cloudy + "󰖑", # mdi-weather-fog + "󰖒", # mdi-weather-hail + "󰖓", # mdi-weather-lightning + "󰙾", # mdi-weather-lightning-rainy + "󰖕", # mdi-weather-partly-cloudy + "󰖖", # mdi-weather-pouring + "󰖗", # mdi-weather-rainy + "󰖘", # mdi-weather-snowy + "󰙿", # mdi-weather-snowy-rainy + "󰖙", # mdi-weather-sunny + "󰖝", # mdi-weather-windy + "󰖞", # mdi-weather-windy-variant + "󰳥", # mdi-weather-exceptional ] - - file: 'fonts/materialdesignicons-webfont.ttf' - id: mdi_wifi + - file: "fonts/materialdesignicons-webfont.ttf" + id: mdi_wifi size: 20 glyphs: [ - # WiFi - '󰤫', # mdi-wifi-strength-alert-outline - '󰤟', # mdi-wifi-strength-1 - '󰤢', # mdi-wifi-strength-2 - '󰤥', # mdi-wifi-strength-3 - '󰤨' # mdi-wifi-strength-4 + # WiFi + "󰤫", # mdi-wifi-strength-alert-outline + "󰤟", # mdi-wifi-strength-1 + "󰤢", # mdi-wifi-strength-2 + "󰤥", # mdi-wifi-strength-3 + "󰤨", # mdi-wifi-strength-4 ] - - file: 'fonts/materialdesignicons-webfont.ttf' - id: mdi_med + - file: "fonts/materialdesignicons-webfont.ttf" + id: mdi_med size: 60 glyphs: [ - '󰀦' # mdi-alert + "󰀦", # mdi-alert ] image: @@ -412,20 +765,29 @@ display: pages: - id: environment lambda: |- - + /* Outdoor */ float outdoor_temp = id(temp_outdoor).state; int outdoor_humid = int(id(humid_outdoor).state); float air_pressure = id(airpressure).state; float outdoor_radiation = id(radiation).state; + /* Living room */ float livingroom_temp = id(temp_livingroom).state; int livingroom_humid = int(id(humid_livingroom).state); - int livingroom_pm25 = int(id(pm25_livingroom).state); float livingroom_co2 = id(co2_livingroom).state; + int livingroom_pm25 = int(id(pm25_livingroom).state); + /* Serverroom */ + float serverroom_temp = id(temp_serverroom).state; + /* Sleeping room */ float sleepingroom_temp = id(temp_sleepingroom).state; int sleepingroom_humid = int(id(humid_sleepingroom).state); - int sleepingroom_pm25 = int(id(pm25_sleepingroom).state); float sleepingroom_co2 = id(co2_sleepingroom).state; - float serverroom_temp = id(temp_serverroom).state; + int sleepingroom_pm25 = int(id(pm25_sleepingroom).state); + /* Children's room */ + float childrensroom_temp = id(temp_childrensroom).state; + int childrensroom_humid = int(id(humid_childrensroom).state); + float childrensroom_co2 = id(co2_childrensroom).state; + int childrensroom_pm25 = int(id(pm25_childrensroom).state); + int offsetX = 0; int offsetY = 0; @@ -477,90 +839,89 @@ display: it.print(225, 130, id(sensor_unit), TextAlign::BASELINE_LEFT, "hPa"); } - /* Livingroom */ offsetY = 127; it.print(10, 10 + offsetY, id(sensor_unit), "Wohnzimmer"); - it.filled_rectangle(136, 21 + offsetY, 247, 3); + it.filled_rectangle(136, 21 + offsetY, 169, 3); it.print(10, 125 + offsetY, id(mdi_small), TextAlign::BASELINE_LEFT, "󰮬"); // PM2.5 - it.print(375, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); // thermometer - it.print(375, 125 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰖎"); // water percent + it.print(305, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); // thermometer + it.print(305, 125 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰖎"); // water percent it.print(10, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_LEFT, "󰟤"); // CO2 if(livingroom_temp > -100 && livingroom_temp < 100) { - it.printf(357, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1fºC", livingroom_temp); + it.printf(287, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1fºC", livingroom_temp); } else { - it.print(357, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); + it.print(287, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); } if(livingroom_humid >=0 && livingroom_humid <= 100) { - it.printf(357, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%3d%%", livingroom_humid); + it.printf(287, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%3d%%", livingroom_humid); } else { - it.print(357, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - %"); + it.print(287, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - %"); } if(livingroom_co2 >=380 && livingroom_co2 <= 20000) { - it.printf(170, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%4.0f", livingroom_co2); - it.print(175, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm"); + it.printf(150, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%4.0f", livingroom_co2); + it.print(155, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm"); } else { - it.print(170, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); - it.print(175, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm³"); + it.print(150, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); + it.print(155, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm³"); } if(livingroom_pm25 < 255 && livingroom_pm25 >=0) { - it.printf(220, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%3d", livingroom_pm25); - it.print(225, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); + it.printf(150, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%3d", livingroom_pm25); + it.print(155, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); } else { - it.print(220, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); - it.print(225, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); + it.print(150, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); + it.print(155, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); } /* Sleepingroom */ offsetY = 247; it.print(10, 10 + offsetY, id(sensor_unit), "Schlafzimmer"); - it.filled_rectangle(144, 21 + offsetY, 239, 3); - it.print(10, 124 + offsetY, id(mdi_small), TextAlign::BASELINE_LEFT, "󰮬"); // PM2.5 - it.print(375, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); // thermometer - it.print(375, 124 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰖎"); // water percent + it.filled_rectangle(144, 21 + offsetY, 161, 3); + it.print(10, 125 + offsetY, id(mdi_small), TextAlign::BASELINE_LEFT, "󰮬"); // PM2.5 + it.print(305, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); // thermometer + it.print(305, 125 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰖎"); // water percent it.print(10, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_LEFT, "󰟤"); // CO2 if(sleepingroom_temp > -100 && sleepingroom_temp < 100) { - it.printf(357, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1fºC", sleepingroom_temp); + it.printf(287, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1fºC", sleepingroom_temp); } else { - it.print(357, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); + it.print(287, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); } if(sleepingroom_humid >=0 && sleepingroom_humid <= 100) { - it.printf(357, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%3d%%", sleepingroom_humid); + it.printf(287, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%3d%%", sleepingroom_humid); } else { - it.print(357, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - %"); + it.print(287, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - %"); } if(sleepingroom_co2 >=380 && sleepingroom_co2 <= 20000) { - it.printf(170, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%4.0f", sleepingroom_co2); - it.print(175, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm"); + it.printf(150, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%4.0f", sleepingroom_co2); + it.print(155, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm"); } else { - it.print(170, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); - it.print(175, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm³"); + it.print(150, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); + it.print(155, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm³"); } if(sleepingroom_pm25 < 255 && sleepingroom_pm25 >=0) { - it.printf(220, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%3d", sleepingroom_pm25); - it.print(225, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); + it.printf(150, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%3d", sleepingroom_pm25); + it.print(155, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); } else { - it.print(220, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); - it.print(225, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); + it.print(150, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); + it.print(155, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); } /* Weather */ @@ -571,7 +932,7 @@ display: /* Current weather */ if(id(weather).has_state()) { int x = 227 + offsetX; - int y = 116; + int y = 96; if (id(weather).state == "clear-night") { // clear night it.print(x, y, id(mdi_weather), TextAlign::BASELINE_RIGHT, "󰖔"); @@ -642,7 +1003,7 @@ display: /* Moon phase display */ if(id(moonphase).has_state()) { int x = 10 + offsetX; - int y = 116; + int y = 96; if (id(moonphase).state == "new_moon") { // new moon it.print(x, y, id(mdi_weather), TextAlign::BASELINE_LEFT, "󰽤"); @@ -682,30 +1043,66 @@ display: } } - /* Warnings */ - if(id(szco2).state == "rot" || id(szpm).state == "rot" || id(wzco2).state == "rot" || id(wzpm).state == "rot") { - it.print(10 + offsetX, 200, id(mdi_med), TextAlign::BASELINE_LEFT, "󰀦"); - it.print(80 + offsetX, 200, id(big_sensor_font), TextAlign::BASELINE_LEFT, "Lüften!"); + it.print(10 + offsetX, 130, id(mdi_small), TextAlign::BASELINE_LEFT, "󰖜"); // sun-up + it.printf(50 + offsetX, 130, id(sensor_unit), TextAlign::BASELINE_LEFT, "%s", id(sun_rising).state.c_str()); + it.print(135 + offsetX, 130, id(mdi_small), TextAlign::BASELINE_LEFT, "󰖛"); // sun-down + it.printf(175 + offsetX, 130, id(sensor_unit), TextAlign::BASELINE_LEFT, "%s", id(sun_setting).state.c_str()); + + /* Children's room */ + offsetX = 320; + offsetY = 127; + it.print(10 + offsetX, 10 + offsetY, id(sensor_unit), "Kinderzimmer"); + it.filled_rectangle(148 + offsetX, 21 + offsetY, 157, 3); + it.print(10 + offsetX, 125 + offsetY, id(mdi_small), TextAlign::BASELINE_LEFT, "󰮬"); // PM2.5 + it.print(305 + offsetX, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); // thermometer + it.print(305 + offsetX, 125 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰖎"); // water percent + it.print(10 + offsetX, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_LEFT, "󰟤"); // CO2 + + if(childrensroom_temp > -100 && childrensroom_temp < 100) { + it.printf(287 + offsetX, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1fºC", childrensroom_temp); + } + else { + it.print(287 + offsetX, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); } - it.print(10 + offsetX, 250, id(mdi_small), TextAlign::BASELINE_LEFT, "󰖜"); // sun-up - it.printf(50 + offsetX, 250, id(sensor_unit), TextAlign::BASELINE_LEFT, "%s", id(sun_rising).state.c_str()); - it.print(135 + offsetX, 250, id(mdi_small), TextAlign::BASELINE_LEFT, "󰖛"); // sun-down - it.printf(175 + offsetX, 250, id(sensor_unit), TextAlign::BASELINE_LEFT, "%s", id(sun_setting).state.c_str()); + if(childrensroom_humid >=0 && childrensroom_humid <= 100) { + it.printf(287 + offsetX, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%3d%%", childrensroom_humid); + } + else { + it.print(287 + offsetX, 125 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - %"); + } + + if(childrensroom_co2 >=380 && childrensroom_co2 <= 20000) { + it.printf(150 + offsetX, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%4.0f", childrensroom_co2); + it.print(155 + offsetX, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm"); + } + else { + it.print(150 + offsetX, 75 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); + it.print(155 + offsetX, 50 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "ppm³"); + } + + if(childrensroom_pm25 < 255 && childrensroom_pm25 >=0) { + it.printf(150 + offsetX, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%3d", childrensroom_pm25); + it.print(155 + offsetX, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); + } + else { + it.print(150 + offsetX, 125 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "- "); + it.print(155 + offsetX, 125 + offsetY, id(sensor_unit), TextAlign::BASELINE_LEFT, "µg/m³"); + } /* Serverroom */ offsetY = 247; it.print(10 + offsetX, 10 + offsetY, id(sensor_unit), "Serverraum"); - it.filled_rectangle(125 + offsetX, 21 + offsetY, 110, 3); + it.filled_rectangle(125 + offsetX, 21 + offsetY, 180, 3); - it.print(227 + offsetX, 110 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); // thermometer + it.print(305 + offsetX, 110 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); // thermometer if(serverroom_temp > -100 && serverroom_temp < 100) { - it.printf(207 + offsetX, 110 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "ºC"); - it.printf(170 + offsetX, 110 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1f", serverroom_temp); + it.printf(287 + offsetX, 110 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "ºC"); + it.printf(250 + offsetX, 110 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1f", serverroom_temp); } else { - it.print(207 + offsetX, 110 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); + it.print(287 + offsetX, 110 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); } /* FOOTER */ @@ -737,6 +1134,117 @@ display: ESP_LOGI("WiFi", "Unlikely"); } } + - id: calendar + lambda: |- + /* Fetch today and tomorrow dates */ + auto now = id(homeassistant_time).now(); + int today_day = now.day_of_month; + int today_month = now.month; + int today_wday = now.day_of_week; // 0=Sunday .. 6=Saturday + const char* weekdays[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"}; + const char* today_weekday_str = weekdays[today_wday]; + int today_year = now.year; + + /* Tomorrow's date */ + int tomorrow_day = today_day + 1; + int tomorrow_month = today_month; + int tomorrow_wday = (today_wday + 1) % 7; + const char* tomorrow_weekday_str = weekdays[tomorrow_wday]; + int tomorrow_year = today_year; + + /* C1024 logo */ + it.image(10, 37, id(c1024_logo)); + + /* ── LEFT PANE: Today ── */ + int leftX = 10; + int leftY = 70; // start below header row + + it.print(15 + leftX, 10 + leftY, id(sensor_unit), "Heute"); + it.filled_rectangle(80 + leftX, 21 + leftY, 240, 3); + + /* Today's date strip */ + it.printf(50 + leftX, 50 + leftY, id(big_sensor_font), "%d", today_day); + it.printf(145 + leftX, 45 + leftY, id(sub_sensor_font), "%s.", today_weekday_str); + it.printf(205 + leftX, 45 + leftY, id(sensor_unit), "%02d.%04d.", today_month, today_year); + + /* Event lines (Privat / Arbeit) */ + int eventOffsetY = 90; + + // Helper lambda: draw one event line at given Y offset with the given text sensor id + // Privat today + if (id(kalender_heute_privat).has_state() && !id(kalender_heute_privat).state.empty()) { + it.print(10 + leftX, 50 + leftY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + // Split by │ separator and display first line of events + auto parts = id(kalender_heute_privat).state.c_str(); + it.printf(40 + leftX, 50 + leftY + eventOffsetY, id(sub_sensor_font), "%s", + id(kalender_heute_privat).state.substr(0, 60).c_str()); + } else { + it.print(10 + leftX, 50 + leftY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + it.printf(40 + leftX, 50 + leftY + eventOffsetY, id(sub_sensor_font), "Kein Termin"); + } + + // Arbeit today + if (id(kalender_heute_arbeit).has_state() && !id(kalender_heute_arbeit).state.empty()) { + it.print(10 + leftX, 85 + leftY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + it.printf(40 + leftX, 85 + leftY + eventOffsetY, id(sub_sensor_font), "%s", + id(kalender_heute_arbeit).state.substr(0, 60).c_str()); + } else { + it.print(10 + leftX, 85 + leftY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + it.printf(40 + leftX, 85 + leftY + eventOffsetY, id(sub_sensor_font), "Kein Termin"); + } + + /* ── RIGHT PANE: Tomorrow ── */ + int rightX = 315; + int rightY = 70; + + it.print(45 + rightX, 10 + rightY, id(sensor_unit), "Morgen"); + it.filled_rectangle(130 + rightX, 21 + rightY, 200, 3); + + /* Date strip */ + it.printf(50 + rightX, 50 + rightY, id(big_sensor_font), "%d", tomorrow_day); + it.printf(145 + rightX, 45 + rightY, id(sub_sensor_font), "%s.", tomorrow_weekday_str); + it.printf(205 + rightX, 45 + rightY, id(sensor_unit), "%02d.%04d.", tomorrow_month, tomorrow_year); + + /* Event lines (Privat / Arbeit) */ + // Privat tomorrow + if (id(kalender_morgen_privat).has_state() && !id(kalender_morgen_privat).state.empty()) { + it.print(10 + rightX, 50 + rightY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + it.printf(40 + rightX, 50 + rightY + eventOffsetY, id(sub_sensor_font), "%s", + id(kalender_morgen_privat).state.substr(0, 60).c_str()); + } else { + it.print(10 + rightX, 50 + rightY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + it.printf(40 + rightX, 50 + rightY + eventOffsetY, id(sub_sensor_font), "Kein Termin"); + } + // Arbeit tomorrow + if (id(kalender_morgen_arbeit).has_state() && !id(kalender_morgen_arbeit).state.empty()) { + it.print(10 + rightX, 85 + rightY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + it.printf(40 + rightX, 85 + rightY + eventOffsetY, id(sub_sensor_font), "%s", + id(kalender_morgen_arbeit).state.substr(0, 60).c_str()); + } else { + it.print(10 + rightX, 85 + rightY + eventOffsetY, id(mdi_med), TextAlign::BASELINE_LEFT, "\U0001f32e" ); + it.printf(40 + rightX, 85 + leftY + eventOffsetY, id(sub_sensor_font), "Kein Termin"); + } + + /* FOOTER */ + it.strftime(614, 380, id(footer_font), TextAlign::BASELINE_RIGHT, "Aktualisiert um %d.%m.%Y %H:%M", id(homeassistant_time).now()); + + /* WiFi Signal strength */ + if(id(wifisignal).has_state()) { + int x = 630; + int y = 384; + if (id(wifisignal).state >= -50) { + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤨"); + } else if (id(wifisignal).state >= -60) { + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤥"); + } else if (id(wifisignal).state >= -75) { + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤢"); + } else if (id(wifisignal).state >= -100) { + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤟"); + } else { + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤫"); + } + } + - id: power lambda: |- @@ -763,7 +1271,7 @@ display: offsetY = 127; it.print(10, 10 + offsetY, id(sensor_unit), "Wohnzimmer"); it.filled_rectangle(136, 21 + offsetY, 247, 3); - + it.print(375, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰚥"); // power-plug it.print(375, 115 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰚥"); // power-plug @@ -834,7 +1342,7 @@ display: /* FOOTER */ it.strftime(614, 380, id(footer_font), TextAlign::BASELINE_RIGHT , "Aktualisiert um %d.%m.%Y %H:%M", id(homeassistant_time).now()); - /* WiFi Signal Strenght */ + /* WiFi Signal strength */ if(id(wifisignal).has_state()) { int x = 630; int y = 384; diff --git a/template.yaml b/template.yaml index 18b08ee..2a7d6b6 100644 --- a/template.yaml +++ b/template.yaml @@ -143,5 +143,30 @@ state: > {{ (( states('sensor.wan_out_derivative') | float * 8 / 1000000 ) | round(2)) }} unit_of_measurement: 'Mbps' - attributes: - last_reset: '1970-01-01T00:00:00+00:00' + +# ── Kalender-Ereignisse für epaperframe ── +# Alle Events werden per Automation (automations.yaml) in input_text Helfer geschrieben. +# Diese template sensors lesen nur noch daraus. Das verhindert doppelte Logik und garantiert, +# dass sowohl "heute" als auch "morgen" Events mit Titeln, Uhrzeiten und Beschreibungen verfügbar sind. + - text_sensor: + # ── HEUTE ── + - name: "Kalender heute Privat" + unique_id: kalender_heute_privat + state: "{{ states('input_text.kalender_heute_privat') }}" + icon: mdi:calendar-account + + - name: "Kalender heute Arbeit" + unique_id: kalender_heute_arbeit + state: "{{ states('input_text.kalender_heute_arbeit') }}" + icon: mdi:calendar-account + + # ── MORGEN ── + - name: "Kalender morgen Privat" + unique_id: kalender_morgen_privat + state: "{{ states('input_text.kalender_morgen_privat') }}" + icon: mdi:calendar-calendar-today + + - name: "Kalender morgen Arbeit" + unique_id: kalender_morgen_arbeit + state: "{{ states('input_text.kalender_morgen_arbeit') }}" + icon: mdi:calendar-calendar-today diff --git a/text_helpers.yaml b/text_helpers.yaml new file mode 100644 index 0000000..5afae03 --- /dev/null +++ b/text_helpers.yaml @@ -0,0 +1,18 @@ +# Helpers for epaperframe calendar display +input_text: + - name: "Kalender heute Privat" + initial: "-" + icon: mdi:calendar-account + mode: text + - name: "Kalender heute Arbeit" + initial: "-" + icon: mdi:calendar-account + mode: text + - name: "Kalender morgen Privat" + initial: "-" + icon: mdi:calendar-calendar-today + mode: text + - name: "Kalender morgen Arbeit" + initial: "-" + icon: mdi:calendar-calendar-today + mode: text