diff --git a/firmware/components/climate.yaml b/firmware/components/climate.yaml index 9638e99..0439893 100644 --- a/firmware/components/climate.yaml +++ b/firmware/components/climate.yaml @@ -42,3 +42,14 @@ climate: - switch.turn_off: relay_heat2 - switch.turn_off: relay_cool1 - switch.turn_off: relay_cool2 + on_state: + then: + - lvgl.label.update: + id: home_mode_label + text: !lambda |- + switch (id(main_thermostat).mode) { + case climate::CLIMATE_MODE_HEAT: return "Mode: Heat"; + case climate::CLIMATE_MODE_COOL: return "Mode: Cool"; + case climate::CLIMATE_MODE_OFF: return "Mode: Off"; + default: return "Mode: Idle"; + } diff --git a/firmware/components/diagnostics.yaml b/firmware/components/diagnostics.yaml new file mode 100644 index 0000000..8a91790 --- /dev/null +++ b/firmware/components/diagnostics.yaml @@ -0,0 +1,25 @@ +text_sensor: + - platform: wifi_info + ip_address: + name: "IP Address" + id: wifi_ip_text + on_value: + then: + - lvgl.label.update: + id: settings_ip_label + text: + format: "IP: %s" + args: ["x.c_str()"] + +sensor: + - platform: uptime + name: "Uptime" + id: uptime_sensor + update_interval: 60s + on_value: + then: + - lvgl.label.update: + id: settings_uptime_label + text: + format: "Uptime: %.0f min" + args: ["x / 60.0f"] diff --git a/firmware/components/display.yaml b/firmware/components/display.yaml index 604e5c5..57d4e0f 100644 --- a/firmware/components/display.yaml +++ b/firmware/components/display.yaml @@ -37,11 +37,276 @@ display: number: 6 # EXIO6 = LCD_VDD_EN (VCOM enable) — the built-in preset doesn't set # this, but the Waveshare wiki confirms VCOM must be driven high on # this board or the panel won't display correctly. Added explicitly. - lambda: |- - it.fill(Color::BLACK); - it.print(512, 300, id(font_label), TextAlign::CENTER, "Thermostat — Phase 1 OK"); -font: - - file: "gfonts://Roboto" - id: font_label - size: 32 +lvgl: + id: lvgl_comp + displays: + - lcd_display + touchscreens: + - touch_gt911 + pages: + - id: page_home + widgets: + - obj: + width: 100% + height: 510px + pad_all: 16 + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: column + flex_align_cross: center + flex_align_track: center + flex_align_main: space_evenly + widgets: + - label: + id: home_temp_label + text: "-- °C" + text_font: montserrat_48 + - label: + id: home_mode_label + text: "Mode: --" + text_font: montserrat_28 + - obj: + width: 100% + height: size_content + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: row + flex_align_cross: center + flex_align_track: center + flex_align_main: space_evenly + widgets: + - button: + width: 140px + height: 100px + on_click: + climate.control: + id: main_thermostat + target_temperature_low: !lambda "return id(main_thermostat).target_temperature_low - 0.5f;" + target_temperature_high: !lambda "return id(main_thermostat).target_temperature_high - 0.5f;" + widgets: + - label: + text: "-" + text_font: montserrat_40 + - button: + width: 140px + height: 100px + on_click: + climate.control: + id: main_thermostat + target_temperature_low: !lambda "return id(main_thermostat).target_temperature_low + 0.5f;" + target_temperature_high: !lambda "return id(main_thermostat).target_temperature_high + 0.5f;" + widgets: + - label: + text: "+" + text_font: montserrat_40 + - id: page_sensors + widgets: + - obj: + width: 100% + height: 510px + pad_all: 16 + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: column + flex_align_cross: center + flex_align_track: center + flex_align_main: space_evenly + widgets: + - label: + id: sensors_temp_label + text: "Temperature: -- °C" + text_font: montserrat_28 + - label: + id: sensors_humidity_label + text: "Humidity: -- %" + text_font: montserrat_28 + - label: + id: sensors_pressure_label + text: "Pressure: -- hPa" + text_font: montserrat_28 + - id: page_settings + widgets: + - obj: + width: 100% + height: 510px + pad_all: 16 + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: column + flex_align_cross: center + flex_align_track: start + flex_align_main: start + widgets: + - label: + id: settings_ip_label + text: "IP: --" + text_font: montserrat_20 + - label: + id: settings_uptime_label + text: "Uptime: -- min" + text_font: montserrat_20 + - label: + text: "Manual relay override (bypasses thermostat):" + text_font: montserrat_16 + - obj: + width: 100% + height: size_content + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: row_wrap + flex_align_cross: start + flex_align_track: start + flex_align_main: start + widgets: + - checkbox: + text: "Fan" + on_click: + switch.toggle: relay_fan + - checkbox: + text: "Cool 1" + on_click: + switch.toggle: relay_cool1 + - checkbox: + text: "Cool 2" + on_click: + switch.toggle: relay_cool2 + - checkbox: + text: "Heat 1" + on_click: + switch.toggle: relay_heat1 + - checkbox: + text: "Heat 2" + on_click: + switch.toggle: relay_heat2 + - id: page_schedule + widgets: + - obj: + width: 100% + height: 510px + pad_all: 16 + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: column + flex_align_cross: center + flex_align_track: center + flex_align_main: space_evenly + widgets: + - label: + text: "Preset" + text_font: montserrat_28 + - obj: + width: 100% + height: size_content + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: row + flex_align_cross: center + flex_align_track: center + flex_align_main: space_evenly + widgets: + - button: + width: 300px + height: 100px + on_click: + climate.control: + id: main_thermostat + preset: home + widgets: + - label: + text: "Home" + text_font: montserrat_28 + - button: + width: 300px + height: 100px + on_click: + climate.control: + id: main_thermostat + preset: away + widgets: + - label: + text: "Away" + text_font: montserrat_28 + - label: + text: "Time-based scheduling runs in Home Assistant, not on this device." + text_font: montserrat_16 + top_layer: + widgets: + - obj: + id: nav_bar + align: bottom_mid + width: 100% + height: 90px + pad_all: 4 + radius: 0 + border_width: 0 + outline_width: 0 + scrollable: false + layout: + type: flex + flex_flow: row + flex_align_cross: center + flex_align_track: center + flex_align_main: space_evenly + widgets: + - button: + id: nav_btn_home + width: 220px + height: 78px + on_click: + lvgl.page.show: page_home + widgets: + - label: + text: "Home" + text_font: montserrat_20 + - button: + id: nav_btn_sensors + width: 220px + height: 78px + on_click: + lvgl.page.show: page_sensors + widgets: + - label: + text: "Sensors" + text_font: montserrat_20 + - button: + id: nav_btn_settings + width: 220px + height: 78px + on_click: + lvgl.page.show: page_settings + widgets: + - label: + text: "Settings" + text_font: montserrat_20 + - button: + id: nav_btn_schedule + width: 220px + height: 78px + on_click: + lvgl.page.show: page_schedule + widgets: + - label: + text: "Schedule" + text_font: montserrat_20 diff --git a/firmware/components/sensors.yaml b/firmware/components/sensors.yaml index 54e3e96..a78a4d3 100644 --- a/firmware/components/sensors.yaml +++ b/firmware/components/sensors.yaml @@ -6,9 +6,35 @@ sensor: temperature: name: "Ambient Temperature" id: bme280_temperature + on_value: + then: + - lvgl.label.update: + id: home_temp_label + text: + format: "%.1f °C" + args: ["x"] + - lvgl.label.update: + id: sensors_temp_label + text: + format: "Temperature: %.1f °C" + args: ["x"] humidity: name: "Ambient Humidity" id: bme280_humidity + on_value: + then: + - lvgl.label.update: + id: sensors_humidity_label + text: + format: "Humidity: %.1f %%" + args: ["x"] pressure: name: "Ambient Pressure" id: bme280_pressure + on_value: + then: + - lvgl.label.update: + id: sensors_pressure_label + text: + format: "Pressure: %.1f hPa" + args: ["x"] diff --git a/firmware/waveshare-thermostat.yaml b/firmware/waveshare-thermostat.yaml index f1d9d69..37301d8 100644 --- a/firmware/waveshare-thermostat.yaml +++ b/firmware/waveshare-thermostat.yaml @@ -48,3 +48,4 @@ packages: sensors: !include components/sensors.yaml relays: !include components/relays.yaml climate: !include components/climate.yaml + diagnostics: !include components/diagnostics.yaml