# TODO: # - auto turn off # - navigation bar at bottom # - buttons for home assistant actions substitutions: device_name: kinderhandy friendly_name: Kinder Handy esphome: name: $device_name friendly_name: $friendly_name esp32: board: esp32dev framework: type: arduino logger: api: encryption: key: !secret api_encryption_key actions: - action: rtttl_play variables: song_str: string then: - rtttl.play: rtttl: !lambda 'return song_str;' wifi: ssid: WLAN password: !secret wifi_password # ============================================================ # Hardware # ============================================================ light: - platform: monochromatic output: backlight_pwm name: Display Backlight id: display_backlight restore_mode: ALWAYS_ON spi: - id: tft clk_pin: GPIO14 mosi_pin: GPIO13 miso_pin: GPIO12 - id: touch clk_pin: GPIO25 mosi_pin: GPIO32 miso_pin: GPIO39 # Setup a pin to control the backlight output: - platform: ledc pin: GPIO21 id: backlight_pwm - platform: ledc pin: GPIO1 id: buzzer_output display: - platform: ili9xxx model: ili9341 spi_id: tft cs_pin: GPIO15 dc_pin: GPIO2 invert_colors: false auto_clear_enabled: false update_interval: never # Set up the xpt2046 touch platform touchscreen: platform: xpt2046 spi_id: touch cs_pin: GPIO33 interrupt_pin: GPIO36 update_interval: never threshold: 400 calibration: x_min: 280 x_max: 3850 y_min: 190 y_max: 3765 transform: swap_xy: false mirror_x: true on_release: - if: condition: lvgl.is_paused then: - logger.log: "LVGL resuming" - lvgl.resume: - lvgl.widget.redraw: - light.turn_on: display_backlight # on_touch: # - lambda: |- # ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d", # touch.x, # touch.y, # touch.x_raw, # touch.y_raw # ); # ============================================================ # Globals # ============================================================ globals: - id: timer_seconds type: int initial_value: '120' - id: timer_running type: bool initial_value: 'false' # ============================================================ # Variables # ============================================================ number: - platform: template name: LVGL Screen timeout optimistic: true id: display_timeout unit_of_measurement: "s" initial_value: 45 restore_value: true min_value: 10 max_value: 180 step: 5 mode: box # ============================================================ # Display # ============================================================ font: - file: "fonts/RobotoCondensed-Regular.ttf" id: roboto_icons_42 size: 42 bpp: 4 extras: - file: "fonts/materialdesignicons-webfont.ttf" glyphs: [ "\U000F0335", # mdi-lightbulb "\U000F0954", # mdi-clock "\U000F0142", # mdi-chevron-right "\U000F004C", # mdi-bed "\U000F0761", # mdi-window-shutter-open "\U000F075E", # mdi-window-shutter ] lvgl: on_idle: timeout: !lambda "return id(timer_running) ? 60 * 5 * 1000: (id(display_timeout).state * 1000);" then: - logger.log: "LVGL is idle" - light.turn_off: display_backlight - lvgl.pause: buffer_size: 50% style_definitions: - id: header_footer bg_color: 0x2F8CD8 bg_grad_color: 0x005782 bg_grad_dir: VER bg_opa: COVER border_opa: TRANSP border_width: 0 outline_width: 0 radius: 0 pad_all: 0 pad_row: 0 pad_column: 0 border_color: 0x0077b3 text_color: 0xFFFFFF width: 100% height: 60 top_layer: widgets: - buttonmatrix: align: bottom_mid styles: header_footer pad_all: 0 outline_width: 0 id: top_layer items: styles: header_footer text_font: roboto_icons_42 rows: - buttons: - id: page_light text: "\U000F0335" on_press: then: - lvgl.page.show: kinderzimmer_page - id: page_timer text: "\U000F0954" on_press: then: - lvgl.page.show: timer_page pages: - id: timer_page widgets: - label: align: TOP_MID y: 10 text: "Lukas und Hannas\nZahnputz Timer" text_font: montserrat_20 text_align: CENTER - container: id: arc_container align: CENTER y: 15 width: 200 height: 200 on_press: then: - if: condition: lambda: 'return id(timer_running);' then: - globals.set: id: timer_running value: 'false' - logger.log: format: "Pause" - lvgl.arc.update: id: arc_timer indicator: arc_color: 0x888888 else: - globals.set: id: timer_running value: 'true' - logger.log: format: "Gestartet" - lvgl.arc.update: id: arc_timer value: !lambda return id(timer_seconds); indicator: arc_color: 0xFF0000 on_long_press: then: - globals.set: id: timer_seconds value: '120' - globals.set: id: timer_running value: 'false' - lvgl.arc.update: id: arc_timer value: 0 indicator: arc_color: 0xFF0000 - lvgl.label.update: id: timer_label text: !lambda 'return std::string("02:00");' - logger.log: format: "Timer reset (long press)" widgets: - arc: id: arc_timer align: CENTER width: 180 height: 180 min_value: 0 max_value: 120 value: 0 arc_width: 8 arc_color: 0x404040 # Indicator arc styling (the progress) indicator: arc_width: 20 arc_opa: COVER arc_color: 0xFF0000 # Start with red - label: id: timer_label align: CENTER text_font: montserrat_28 text: "02:00" - id: kinderzimmer_page widgets: - label: align: TOP_MID y: 10 text: "Kinderzimmer" text_font: montserrat_20 text_align: CENTER - buttonmatrix: align: CENTER width: 280 height: 200 items: text_font: roboto_icons_42 rows: - buttons: - id: btn_shelf_light text: "\U000F0335" - id: btn_cover_open text: "\U000F0761" - buttons: - id: btn_cover_close text: "\U000F075E" - id: btn_bed text: "\U000F004C" interval: - interval: 1s then: - if: condition: lambda: 'return id(timer_running);' then: - globals.set: id: timer_seconds value: !lambda 'return max(0, (int)id(timer_seconds) - 1);' - lvgl.arc.update: id: arc_timer value: !lambda 'return (int)(id(timer_seconds));' indicator: arc_color: !lambda | float f = (120.0 - (float)id(timer_seconds)) / 120.0; if (f < 0) f = 0; if (f > 1) f = 1; if (f <= 0.5) { // Red to Yellow (f: 0.0 to 0.5) float t = f / 0.5; int r = 255; int g = (int)(255 * t + 0.5); int b = 0; int hex = (r << 16) | (g << 8) | b; return lv_color_hex(hex); } else { // Yellow to Green (f: 0.5 to 1.0) float t = (f - 0.5) / 0.5; int r = (int)(255 * (1.0 - t) + 0.5); int g = 255; int b = 0; int hex = (r << 16) | (g << 8) | b; return lv_color_hex(hex); } - lambda: |- ESP_LOGI("timer", "timer_seconds=%d fraction=%.2f", id(timer_seconds), (float)id(timer_seconds)/120.0); - lvgl.label.update: id: timer_label text: !lambda 'char buf[6]; sprintf(buf, "%02d:%02d", id(timer_seconds)/60, id(timer_seconds)%60); return std::string(buf);' - if: condition: lambda: 'return id(timer_seconds) <= 0;' then: - globals.set: id: timer_running value: 'false' - logger.log: format: "Timer finished" - lvgl.arc.update: id: arc_timer value: 120 indicator: arc_color: 0x00FF00 # Buzzer rtttl: output: buzzer_output id: my_buzzer_rtttl gain: 60% on_finished_playback: - logger.log: 'Song ended!' #Entchen:d=4,o=5,b=120:c,d,e,f,2g,2g,a,a,a,a,1g,a,a,a,a,1g,f,f,f,f,2e,2e,g,g,g,g,1c #MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d