esphome: name: ha-remote-1 friendly_name: ha-remote-1 on_boot: priority: -10 then: - light.turn_on: ha_remote_backlight - lvgl.page.show: home - lambda: |- id(last_activity_ms) = millis(); esp32: board: esp32-s3-devkitc-1 framework: type: esp-idf logger: level: WARN api: encryption: key: "mn3Lv3ud5jCSOqH/QKcspUu7ShdZ0OGotm0G01p9r94=" ota: - platform: esphome password: "680170fb1d63d3490b2fc710fe064749" wifi: ssid: !secret wifi_ssid password: !secret wifi_password power_save_mode: LIGHT fast_connect: true psram: mode: octal speed: 80MHz i2c: sda: 8 scl: 9 # CH422G I/O expander (Waveshare uses it for LCD reset/backlight/touch reset) ch422g: - id: ch422g_hub # --- Backlight control (CH422G IO2 is common for Waveshare LCD BL) --- switch: - platform: gpio name: "LCD Backlight Raw" id: lcd_backlight_raw restore_mode: ALWAYS_ON pin: ch422g: ch422g_hub number: 2 mode: output: true # A nicer HA-exposed control (so you can also automate it from HA) light: - platform: binary name: "HA Remote Backlight" output: lcd_backlight_out id: ha_remote_backlight output: - platform: template id: lcd_backlight_out type: binary write_action: - if: condition: lambda: return state; then: - switch.turn_on: lcd_backlight_raw else: - switch.turn_off: lcd_backlight_raw # --- Inactivity tracking (dim/off + wake on touch) --- globals: - id: last_activity_ms type: uint32_t restore_value: no initial_value: '0' interval: - interval: 1s then: - lambda: |- if (id(last_activity_ms) == 0) id(last_activity_ms) = millis(); # Turn off backlight ONCE at 15 seconds idle (no spamming every second) - if: condition: lambda: |- const uint32_t idle_s = (millis() - id(last_activity_ms)) / 1000; return idle_s == 15; then: - light.turn_off: ha_remote_backlight # Deep sleep after 60 seconds idle - if: condition: lambda: |- const uint32_t idle_s = (millis() - id(last_activity_ms)) / 1000; return idle_s >= 60; then: - deep_sleep.enter: deep_sleep_ctrl deep_sleep: id: deep_sleep_ctrl wakeup_pin: number: 4 mode: input: true ignore_pin_validation_error: true wakeup_pin_mode: INVERT_WAKEUP # If it wakes instantly, change to KEEP_AWAKE # --- Display --- display: - platform: mipi_rgb model: ESP32-S3-TOUCH-LCD-7-800X480 id: main_display update_interval: never reset_pin: ch422g: ch422g_hub number: 3 mode: output: true # --- Touch --- touchscreen: platform: gt911 id: touch_panel interrupt_pin: number: 4 mode: input: true ignore_pin_validation_error: true reset_pin: ch422g: ch422g_hub number: 1 mode: output: true on_touch: then: - lambda: |- id(last_activity_ms) = millis(); - light.turn_on: ha_remote_backlight # --- LVGL UI --- text_sensor: - platform: wifi_info ip_address: name: "HA Remote IP" id: ip_addr lvgl: displays: - main_display touchscreens: - touch_panel pages: - id: home widgets: - label: id: status_label x: 20 y: 10 text: "HA Remote" - label: x: 20 y: 40 text: "Tap to wake • Idle 60s to sleep" - button: x: 40 y: 100 width: 220 height: 100 on_click: - homeassistant.service: service: light.toggle data: entity_id: light.living_room widgets: - label: align: center text: "Living Room\nLights" - button: x: 290 y: 100 width: 220 height: 100 on_click: - homeassistant.service: service: light.toggle data: entity_id: light.kitchen widgets: - label: align: center text: "Kitchen\nLights" - button: x: 540 y: 100 width: 220 height: 100 on_click: - homeassistant.service: service: script.turn_off_everything widgets: - label: align: center text: "All Off" - button: x: 40 y: 230 width: 220 height: 100 on_click: - homeassistant.service: service: scene.turn_on data: entity_id: scene.movie_time widgets: - label: align: center text: "Movie Time" - button: x: 290 y: 230 width: 220 height: 100 on_click: - homeassistant.service: service: scene.turn_on data: entity_id: scene.good_night widgets: - label: align: center text: "Good Night" - button: x: 540 y: 230 width: 220 height: 100 on_click: - light.toggle: ha_remote_backlight widgets: - label: align: center text: "Backlight\nToggle"