diff --git a/esphome/esp-bedside-panel.yaml b/esphome/esp-bedside-panel.yaml index ae5da62..a5b03ce 100644 --- a/esphome/esp-bedside-panel.yaml +++ b/esphome/esp-bedside-panel.yaml @@ -6,6 +6,7 @@ # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedside-panel.yaml #:########################################################################################:# # VERSIONS: +# V1.18 2026-07-18 Added Lounge Fire, six Security cameras, Jobs page and weather/tide header # V1.17 2026-07-18 Swapped Bedroom Climate/Atto buttons and removed Garage test logs # V1.16 2026-07-17 Removed garage-door influence from Garage Lights button state # V1.15 2026-07-17 Changed Garage Lights to an imported controllable HA switch @@ -88,7 +89,9 @@ # - Moon, Outdoor, Indoor and Humidity readings are positioned near the bottom. # - The display remains in its native 1024x600 landscape orientation. # - The default page contains nine Bedroom / nearby controls. -# - The bottom navigation row contains Bedtime, Climate, Future1, Future2 and Clock. +# - The bottom navigation row contains Bedtime, Atto, Climate, Security and Clock. +# - Jobs Summary opens a reserved Jobs page with Back and Clock navigation. +# - The Security page supports six selectable camera views. # - After the configured idle period: # - The large clock page is displayed. # - Backlight brightness is reduced. @@ -116,12 +119,12 @@ substitutions: # Device Naming device_name: "esp-bedside-panel" friendly_name: "ESP Bedside Panel" - description_comment: "Guition JC1060P470C_I_W_Y ESP32-P4 bedside control panel. Bedroom Climate/Atto navigation swapped and Garage Lights test logging removed. (Layout V1.1)" + description_comment: "Guition JC1060P470C_I_W_Y ESP32-P4 bedside control panel. Lounge Fire, six-camera Security, Jobs page and expanded weather/tide status. (Layout V1.1)" device_area: "Bedroom" # Project Naming project_name: "Guition.JC1060P470C_I_W_Y" - project_version: "v1.17" + project_version: "v1.18" # Passwords & Secrets api_key: !secret esp-api_key @@ -152,13 +155,21 @@ substitutions: home_assistant_internal_url: "http://homeassistant.local:8123" security_camera_refresh_interval: "5s" security_doorbell_camera_entity: "camera.view_road_front_door_fluent" + security_front_door_camera_entity: "camera.camera2" security_driveway_camera_entity: "camera.camera5" + security_garage_camera_entity: "camera.camera6" + security_caravan_camera_entity: "camera.camera4" + security_bike_shed_camera_entity: "camera.trailer" # Home Assistant Entities - Status / Environment + local_tides_entity: "sensor.local_tides" + rain_today_entity: "sensor.astroweather_deepsky_forecast_today" + rain_tomorrow_entity: "sensor.astroweather_deepsky_forecast_tomorrow" moon_phase_entity: "sensor.astroweather_moon_phase" outdoor_temperature_entity: "sensor.lounge_outside_temperature" bedroom_temperature_entity: "sensor.bedroom_1_environment_z19th_temperature" bedroom_humidity_entity: "sensor.bedroom_1_environment_z19th_humidity" + jobs_summary_entity: "sensor.jobs_tracker_summary" # Home Assistant Entities - Bedroom / Nearby Controls north_lights_entity: "light.tasmo_ifan02_3793_bedrm1_1" @@ -178,6 +189,8 @@ substitutions: bedtime_button_entity: "input_button.bedtime_mode" # Home Assistant Entities - Climate + lounge_fire_entity: "switch.rinnai_neo_gas_heater_heater_operation" + lounge_fire_status_entity: "sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_status_text" climate_entity: "climate.master_bedroom" climate_requested_mode_entity: "input_select.master_bedroom_hvac_requested_mode" climate_profile_entity: "input_select.master_bedroom_heat_pump_profile" @@ -205,6 +218,10 @@ substitutions: atto_cabin_temperature_entity: "sensor.atto_3_cabin_temperature" atto_climate_entity: "climate.atto_3_climate" + # Home Assistant Entities - Security Controls + downstairs_guests_occupied_entity: "input_boolean.downstairs_flat_occupied" + external_garage_light_entity: "switch.esp_garageextcornerlight_garage_external_light" + #:########################################################################################:# # PACKAGES: # Included Common Packages @@ -512,6 +529,15 @@ font: - "abcdefghijklmnopqrstuvwxyz" - "0123456789, .:/-%°+()" + # Compact headings and long summary values in the status strips. + - file: "gfonts://Roboto" + id: font_header + size: 14 + glyphs: + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "abcdefghijklmnopqrstuvwxyz" + - "0123456789, .:/-%°+()" + # Dedicated MDI font for reliable setpoint chevron icons. - file: "https://raw.githubusercontent.com/Templarian/MaterialDesign-Webfont/master/fonts/materialdesignicons-webfont.ttf" id: font_mdi_setpoint @@ -653,6 +679,22 @@ sensor: format: "%.0f%%" args: [x] + - platform: homeassistant + id: rain_today + entity_id: "${rain_today_entity}" + internal: true + on_value: + then: + - script.execute: refresh_header_status + + - platform: homeassistant + id: rain_tomorrow + entity_id: "${rain_tomorrow_entity}" + internal: true + on_value: + then: + - script.execute: refresh_header_status + # Current heat-pump target temperature. - platform: homeassistant id: ha_climate_setpoint @@ -888,6 +930,14 @@ binary_sensor: - script.execute: refresh_climate_controls + - platform: homeassistant + id: ha_downstairs_guests_occupied + entity_id: "${downstairs_guests_occupied_entity}" + internal: true + on_state: + then: + - script.execute: refresh_security_controls + - platform: homeassistant id: ha_quiet_time entity_id: "${quiet_time_entity}" @@ -967,7 +1017,8 @@ globals: restore_value: false initial_value: "false" - # 1 = Doorbell, 2 = Driveway. Camera3 and Camera4 remain placeholders. + # 1 = Doorbell, 2 = Front Door, 3 = Driveway, 4 = Garage, + # 5 = Caravan, 6 = Bike Shed. - id: security_camera_selection type: int restore_value: false @@ -978,6 +1029,105 @@ globals: # Refresh all state-dependent LVGL button colours #:########################################################################################:# script: + # Update Bedroom and Clock status values after LVGL has finished constructing. + - id: refresh_header_status + mode: restart + then: + - if: + condition: + lambda: |- + return id(lvgl_ready); + + then: + - lvgl.label.update: + id: bedroom_high_tide_value_label + text: !lambda |- + const auto value = id(high_tide_time).state; + + if (value.size() >= 16) { + return value.substr(11, 5); + } + + return std::string("--:--"); + + - lvgl.label.update: + id: clock_high_tide_value_label + text: !lambda |- + const auto value = id(high_tide_time).state; + + if (value.size() >= 16) { + return value.substr(11, 5); + } + + return std::string("--:--"); + + - lvgl.label.update: + id: bedroom_rain_today_value_label + text: !lambda |- + const float value = id(rain_today).state; + + if (isnan(value)) { + return std::string("--%"); + } + + char buffer[12]; + snprintf(buffer, sizeof(buffer), "%.0f%%", value); + return std::string(buffer); + + - lvgl.label.update: + id: clock_rain_today_value_label + text: !lambda |- + const float value = id(rain_today).state; + + if (isnan(value)) { + return std::string("--%"); + } + + char buffer[12]; + snprintf(buffer, sizeof(buffer), "%.0f%%", value); + return std::string(buffer); + + - lvgl.label.update: + id: bedroom_rain_tomorrow_value_label + text: !lambda |- + const float value = id(rain_tomorrow).state; + + if (isnan(value)) { + return std::string("--%"); + } + + char buffer[12]; + snprintf(buffer, sizeof(buffer), "%.0f%%", value); + return std::string(buffer); + + - lvgl.label.update: + id: clock_rain_tomorrow_value_label + text: !lambda |- + const float value = id(rain_tomorrow).state; + + if (isnan(value)) { + return std::string("--%"); + } + + char buffer[12]; + snprintf(buffer, sizeof(buffer), "%.0f%%", value); + return std::string(buffer); + + - lvgl.label.update: + id: bedroom_jobs_summary_value_label + text: !lambda |- + const auto value = id(jobs_summary).state; + + if ( + value.empty() || + value == "unknown" || + value == "unavailable" + ) { + return std::string("--"); + } + + return value; + # Update the API status indicator only after LVGL has finished constructing. - id: refresh_api_indicator mode: restart @@ -1096,8 +1246,10 @@ script: ? std::string("Quiet Time active") : std::string(""); + - script.execute: refresh_header_status - script.execute: refresh_climate_controls - script.execute: refresh_vehicle_controls + - script.execute: refresh_security_controls #:######################################################################################:# # VEHICLES PAGE STATE REFRESH @@ -1367,6 +1519,29 @@ script: return id(lvgl_ready); then: + # Lounge gas-heater state and user-facing status text. + - lvgl.label.update: + id: lounge_fire_button_label + text: !lambda |- + const auto status = id(ha_lounge_fire_status).state; + + if ( + status.empty() || + status == "unknown" || + status == "unavailable" + ) { + return std::string("Fire: --"); + } + + return std::string("Fire: ") + status; + + - lvgl.widget.update: + id: lounge_fire_button + bg_color: !lambda |- + return id(ha_lounge_fire).state + ? lv_color_hex(0x8A3F22) + : lv_color_hex(0x28313D); + # Heat-pump mode buttons. The requested mode wins while a change is # pending; when it is "none", the actual climate state is used. - lvgl.widget.update: @@ -1669,6 +1844,30 @@ script: ? lv_color_hex(0x6B4A86) : lv_color_hex(0x28313D); + # Update Security-page non-camera control button colours. + - id: refresh_security_controls + mode: restart + then: + - if: + condition: + lambda: |- + return id(lvgl_ready); + + then: + - lvgl.widget.update: + id: security_downstairs_guests_button + bg_color: !lambda |- + return id(ha_downstairs_guests_occupied).state + ? lv_color_hex(0x315843) + : lv_color_hex(0x28313D); + + - lvgl.widget.update: + id: security_external_garage_light_button + bg_color: !lambda |- + return id(ha_ext_garage_light).state + ? lv_color_hex(0xB88918) + : lv_color_hex(0x28313D); + # Highlight the selected Security camera. - id: refresh_security_camera_buttons mode: restart @@ -1690,12 +1889,40 @@ script: : lv_color_hex(0x28313D); - lvgl.widget.update: - id: security_driveway_button + id: security_front_door_button bg_color: !lambda |- return id(security_camera_selection) == 2 ? lv_color_hex(0x493535) : lv_color_hex(0x28313D); + - lvgl.widget.update: + id: security_driveway_button + bg_color: !lambda |- + return id(security_camera_selection) == 3 + ? lv_color_hex(0x493535) + : lv_color_hex(0x28313D); + + - lvgl.widget.update: + id: security_garage_camera_button + bg_color: !lambda |- + return id(security_camera_selection) == 4 + ? lv_color_hex(0x493535) + : lv_color_hex(0x28313D); + + - lvgl.widget.update: + id: security_caravan_camera_button + bg_color: !lambda |- + return id(security_camera_selection) == 5 + ? lv_color_hex(0x493535) + : lv_color_hex(0x28313D); + + - lvgl.widget.update: + id: security_bike_shed_camera_button + bg_color: !lambda |- + return id(security_camera_selection) == 6 + ? lv_color_hex(0x493535) + : lv_color_hex(0x28313D); + # Download the selected Security camera image through the authenticated # proxy path supplied by Home Assistant. - id: refresh_security_camera @@ -1717,10 +1944,25 @@ script: lambda: |- std::string path; - if (id(security_camera_selection) == 2) { - path = id(ha_driveway_entity_picture).state; - } else { - path = id(ha_doorbell_entity_picture).state; + switch (id(security_camera_selection)) { + case 2: + path = id(ha_front_door_entity_picture).state; + break; + case 3: + path = id(ha_driveway_entity_picture).state; + break; + case 4: + path = id(ha_garage_camera_entity_picture).state; + break; + case 5: + path = id(ha_caravan_entity_picture).state; + break; + case 6: + path = id(ha_bike_shed_entity_picture).state; + break; + default: + path = id(ha_doorbell_entity_picture).state; + break; } return ( @@ -1733,19 +1975,55 @@ script: - lvgl.label.update: id: security_camera_status_label text: !lambda |- - return id(security_camera_selection) == 2 - ? std::string("Loading Driveway...") - : std::string("Loading Doorbell..."); + std::string camera_name; + + switch (id(security_camera_selection)) { + case 2: + camera_name = "Front Door"; + break; + case 3: + camera_name = "Driveway"; + break; + case 4: + camera_name = "Garage"; + break; + case 5: + camera_name = "Caravan"; + break; + case 6: + camera_name = "Bike Shed"; + break; + default: + camera_name = "Doorbell"; + break; + } + + return std::string("Loading ") + camera_name + "..."; - online_image.set_url: id: security_camera_image url: !lambda |- std::string path; - if (id(security_camera_selection) == 2) { - path = id(ha_driveway_entity_picture).state; - } else { - path = id(ha_doorbell_entity_picture).state; + switch (id(security_camera_selection)) { + case 2: + path = id(ha_front_door_entity_picture).state; + break; + case 3: + path = id(ha_driveway_entity_picture).state; + break; + case 4: + path = id(ha_garage_camera_entity_picture).state; + break; + case 5: + path = id(ha_caravan_entity_picture).state; + break; + case 6: + path = id(ha_bike_shed_entity_picture).state; + break; + default: + path = id(ha_doorbell_entity_picture).state; + break; } std::string url; @@ -1779,9 +2057,30 @@ script: - lvgl.label.update: id: security_camera_status_label text: !lambda |- - return id(security_camera_selection) == 2 - ? std::string("Waiting for Driveway camera") - : std::string("Waiting for Doorbell camera"); + std::string camera_name; + + switch (id(security_camera_selection)) { + case 2: + camera_name = "Front Door"; + break; + case 3: + camera_name = "Driveway"; + break; + case 4: + camera_name = "Garage"; + break; + case 5: + camera_name = "Caravan"; + break; + case 6: + camera_name = "Bike Shed"; + break; + default: + camera_name = "Doorbell"; + break; + } + + return std::string("Waiting for ") + camera_name + " camera"; - id: release_climate_profile_optimistic mode: restart @@ -1918,11 +2217,65 @@ switch: id: garage_lights_button bg_color: 0x28313D + - platform: homeassistant + id: ha_lounge_fire + entity_id: "${lounge_fire_entity}" + internal: true + + on_turn_on: + then: + - script.execute: refresh_climate_controls + + on_turn_off: + then: + - script.execute: refresh_climate_controls + + - platform: homeassistant + id: ha_ext_garage_light + entity_id: "${external_garage_light_entity}" + internal: true + + on_turn_on: + then: + - script.execute: refresh_security_controls + + on_turn_off: + then: + - script.execute: refresh_security_controls + #:########################################################################################:# # TEXT SENSOR COMPONENT: # https://esphome.io/components/text_sensor/ #:########################################################################################:# text_sensor: + #:######################################################################################:# + # BEDROOM / CLOCK STATUS TEXT + #:######################################################################################:# + - platform: homeassistant + id: high_tide_time + entity_id: "${local_tides_entity}" + attribute: next_high_tide_time + internal: true + on_value: + then: + - script.execute: refresh_header_status + + - platform: homeassistant + id: jobs_summary + entity_id: "${jobs_summary_entity}" + internal: true + on_value: + then: + - script.execute: refresh_header_status + + - platform: homeassistant + id: ha_lounge_fire_status + entity_id: "${lounge_fire_status_entity}" + internal: true + on_value: + then: + - script.execute: refresh_climate_controls + #:######################################################################################:# # ATTO 3 TEXT STATES #:######################################################################################:# @@ -2033,6 +2386,24 @@ text_sensor: then: - script.execute: refresh_security_camera + - platform: homeassistant + id: ha_front_door_entity_picture + entity_id: "${security_front_door_camera_entity}" + attribute: entity_picture + internal: true + on_value: + then: + - if: + condition: + lambda: |- + return ( + id(security_page_active) && + id(security_camera_selection) == 2 + ); + + then: + - script.execute: refresh_security_camera + - platform: homeassistant id: ha_driveway_entity_picture entity_id: "${security_driveway_camera_entity}" @@ -2045,7 +2416,61 @@ text_sensor: lambda: |- return ( id(security_page_active) && - id(security_camera_selection) == 2 + id(security_camera_selection) == 3 + ); + + then: + - script.execute: refresh_security_camera + + - platform: homeassistant + id: ha_garage_camera_entity_picture + entity_id: "${security_garage_camera_entity}" + attribute: entity_picture + internal: true + on_value: + then: + - if: + condition: + lambda: |- + return ( + id(security_page_active) && + id(security_camera_selection) == 4 + ); + + then: + - script.execute: refresh_security_camera + + - platform: homeassistant + id: ha_caravan_entity_picture + entity_id: "${security_caravan_camera_entity}" + attribute: entity_picture + internal: true + on_value: + then: + - if: + condition: + lambda: |- + return ( + id(security_page_active) && + id(security_camera_selection) == 5 + ); + + then: + - script.execute: refresh_security_camera + + - platform: homeassistant + id: ha_bike_shed_entity_picture + entity_id: "${security_bike_shed_camera_entity}" + attribute: entity_picture + internal: true + on_value: + then: + - if: + condition: + lambda: |- + return ( + id(security_page_active) && + id(security_camera_selection) == 6 ); then: @@ -2070,7 +2495,7 @@ text_sensor: #:########################################################################################:# # HTTP REQUEST: -# Used by the online Doorbell image +# Used by the online Security camera image # https://esphome.io/components/http_request/ #:########################################################################################:# http_request: @@ -2185,91 +2610,258 @@ lvgl: # Green = connected, red = disconnected. - obj: id: bedroom_connection_indicator - x: 30 - y: 25 - width: 18 - height: 18 - radius: 9 + x: 22 + y: 31 + width: 16 + height: 16 + radius: 8 bg_color: 0xF06A6A bg_opa: COVER border_width: 0 shadow_width: 0 clickable: false - # Four status readings across the top + # Jobs Summary opens the future Jobs page. + - button: + id: jobs_summary_navigation_button + x: 50 + y: 8 + width: 210 + height: 68 + bg_color: 0x263443 + bg_opa: COVER + border_width: 2 + border_color: 0x52677B + radius: 13 + pressed: + bg_color: 0x34495C + widgets: + - label: + x: 10 + y: 6 + width: 190 + text: "Jobs Summary" + text_font: font_header + text_align: CENTER + text_color: 0xAFC7DC + + - label: + id: bedroom_jobs_summary_value_label + x: 10 + y: 32 + width: 190 + text: "--" + text_font: font_header + text_align: CENTER + text_color: 0xFFFFFF + on_click: + - lvgl.page.show: + id: jobs_page + animation: MOVE_LEFT + time: 220ms + + # Divider between Jobs Summary and the compact status strip. + - obj: + x: 268 + y: 11 + width: 1 + height: 54 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + # Seven compact status readings across the top-right. - label: - x: 355 - y: 12 - width: 150 - text: "Moon" + x: 274 + y: 9 + width: 104 + text: "High Tide" + text_font: font_header + text_align: CENTER + text_color: 0x6EBCC9 + + - label: + id: bedroom_high_tide_value_label + x: 274 + y: 36 + width: 104 + text: "--:--" text_font: font_small text_align: CENTER + text_color: 0x8BD6E1 + + - obj: + x: 377 + y: 11 + width: 1 + height: 54 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 378 + y: 9 + width: 104 + text: "Rain Today" + text_font: font_header + text_align: CENTER + text_color: 0x6C9FD2 + + - label: + id: bedroom_rain_today_value_label + x: 378 + y: 36 + width: 104 + text: "--%" + text_font: font_small + text_align: CENTER + text_color: 0x85B8E8 + + - obj: + x: 481 + y: 11 + width: 1 + height: 54 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 482 + y: 9 + width: 104 + text: "Rain Tomorrow" + text_font: font_header + text_align: CENTER + text_color: 0x6C9FD2 + + - label: + id: bedroom_rain_tomorrow_value_label + x: 482 + y: 36 + width: 104 + text: "--%" + text_font: font_small + text_align: CENTER + text_color: 0x85B8E8 + + - obj: + x: 585 + y: 11 + width: 1 + height: 54 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 586 + y: 9 + width: 104 + text: "Moon" + text_font: font_header + text_align: CENTER text_color: 0xA9A0D4 - label: id: bedroom_moon_value_label - x: 355 - y: 39 - width: 150 + x: 586 + y: 36 + width: 104 text: "--.-%" - text_font: font_button + text_font: font_small text_align: CENTER text_color: 0xC6BDEC + - obj: + x: 689 + y: 11 + width: 1 + height: 54 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + - label: - x: 510 - y: 12 - width: 150 + x: 690 + y: 9 + width: 104 text: "Outdoor" - text_font: font_small + text_font: font_header text_align: CENTER text_color: 0x84B5D8 - label: id: bedroom_outdoor_value_label - x: 510 - y: 39 - width: 150 + x: 690 + y: 36 + width: 104 text: "--.-°C" - text_font: font_button + text_font: font_small text_align: CENTER text_color: 0x9CCBEA + - obj: + x: 793 + y: 11 + width: 1 + height: 54 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + - label: - x: 665 - y: 12 - width: 150 + x: 794 + y: 9 + width: 104 text: "Indoor" - text_font: font_small + text_font: font_header text_align: CENTER text_color: 0xD6B78F - label: id: bedroom_temperature_label - x: 665 - y: 39 - width: 150 + x: 794 + y: 36 + width: 104 text: "--.-°C" - text_font: font_button + text_font: font_small text_align: CENTER text_color: 0xE8C79D + - obj: + x: 897 + y: 11 + width: 1 + height: 54 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + - label: - x: 820 - y: 12 - width: 165 + x: 898 + y: 9 + width: 104 text: "Humidity" - text_font: font_small + text_font: font_header text_align: CENTER text_color: 0x80BDA4 - label: id: bedroom_humidity_label - x: 820 - y: 39 - width: 165 + x: 898 + y: 36 + width: 104 text: "--%" - text_font: font_button + text_font: font_small text_align: CENTER text_color: 0x97D2B7 @@ -2714,6 +3306,7 @@ lvgl: brightness: "${control_brightness}" transition_length: 250ms + - script.execute: refresh_security_controls - script.execute: refresh_security_camera_buttons - script.execute: refresh_security_camera @@ -2749,6 +3342,71 @@ lvgl: brightness: "${clock_brightness}" transition_length: 1500ms + #:####################################################################################:# + # JOBS PAGE + #:####################################################################################:# + - id: jobs_page + skip: true + bg_color: 0x111923 + bg_opa: COVER + + widgets: + # Reserved for the future Jobs interface. + - button: + id: jobs_back_button + x: 612 + y: 475 + width: 190 + height: 92 + bg_color: 0x315843 + bg_opa: COVER + border_width: 2 + border_color: 0x548C6C + radius: 16 + pressed: + bg_color: 0x416F55 + widgets: + - label: + align: CENTER + text: "Back" + text_font: font_button + text_color: 0xFFFFFF + on_click: + - lvgl.page.show: + id: bedroom_page + animation: MOVE_RIGHT + time: 220ms + + - button: + id: jobs_clock_button + x: 810 + y: 475 + width: 190 + height: 92 + bg_color: 0x214F72 + bg_opa: COVER + border_width: 2 + border_color: 0x3E7FA7 + radius: 16 + pressed: + bg_color: 0x2E6A96 + widgets: + - label: + align: CENTER + text: "Clock" + text_font: font_button + text_color: 0xFFFFFF + on_click: + - lvgl.page.show: + id: clock_page + animation: FADE_IN + time: 250ms + + - light.turn_on: + id: display_backlight + brightness: "${clock_brightness}" + transition_length: 1500ms + #:####################################################################################:# # VEHICLES PAGE #:####################################################################################:# @@ -3436,22 +4094,56 @@ lvgl: widgets: - label: - x: 25 + x: 18 y: 41 - width: 220 + width: 180 + text: "Lounge Gas Heater" + text_font: font_small + text_align: CENTER + text_color: 0x8FA0B3 + + - label: + x: 220 + y: 41 + width: 782 text: "Heat Pump" text_font: font_small text_align: CENTER text_color: 0x8FA0B3 #:################################################################################:# - # HEAT-PUMP MODES + # LOUNGE GAS HEATER / HEAT-PUMP MODES #:################################################################################:# - button: - id: climate_off_button - x: 25 + id: lounge_fire_button + x: 18 y: 72 - width: 220 + width: 180 + height: 96 + bg_color: 0x28313D + bg_opa: COVER + border_width: 2 + border_color: 0x9B5B42 + radius: 17 + pressed: + bg_color: 0x8A3F22 + widgets: + - label: + id: lounge_fire_button_label + align: CENTER + text: "Fire: --" + text_font: font_small + text_align: CENTER + text_color: 0xFFFFFF + on_click: + - switch.toggle: ha_lounge_fire + + # A 22-pixel gap separates the Lounge Fire from the Heat Pump group. + - button: + id: climate_off_button + x: 220 + y: 72 + width: 188 height: 96 bg_color: 0x28313D bg_opa: COVER @@ -3474,9 +4166,9 @@ lvgl: - button: id: climate_heat_button - x: 272 + x: 418 y: 72 - width: 220 + width: 188 height: 96 bg_color: 0x28313D bg_opa: COVER @@ -3499,9 +4191,9 @@ lvgl: - button: id: climate_cool_button - x: 519 + x: 616 y: 72 - width: 220 + width: 188 height: 96 bg_color: 0x28313D bg_opa: COVER @@ -3524,9 +4216,9 @@ lvgl: - button: id: climate_dry_button - x: 766 + x: 814 y: 72 - width: 220 + width: 188 height: 96 bg_color: 0x28313D bg_opa: COVER @@ -4101,101 +4793,163 @@ lvgl: widgets: #:################################################################################:# - # CAMERA SELECTION + # SIX-CAMERA SELECTION ROW #:################################################################################:# - button: id: security_doorbell_button - x: 25 + x: 18 y: 18 - width: 220 + width: 156 height: 70 bg_color: 0x493535 bg_opa: COVER border_width: 2 border_color: 0x9A6666 - radius: 16 + radius: 14 pressed: bg_color: 0x654949 widgets: - label: align: CENTER text: "Doorbell" - text_font: font_button + text_font: font_small text_color: 0xFFFFFF on_click: - lambda: |- id(security_camera_selection) = 1; - - script.execute: refresh_security_camera_buttons - script.execute: refresh_security_camera - button: - id: security_driveway_button - x: 272 + id: security_front_door_button + x: 184 y: 18 - width: 220 + width: 156 height: 70 bg_color: 0x28313D bg_opa: COVER border_width: 2 border_color: 0x9A6666 - radius: 16 + radius: 14 + pressed: + bg_color: 0x654949 + widgets: + - label: + align: CENTER + text: "Front Door" + text_font: font_small + text_color: 0xFFFFFF + on_click: + - lambda: |- + id(security_camera_selection) = 2; + - script.execute: refresh_security_camera_buttons + - script.execute: refresh_security_camera + + - button: + id: security_driveway_button + x: 350 + y: 18 + width: 156 + height: 70 + bg_color: 0x28313D + bg_opa: COVER + border_width: 2 + border_color: 0x9A6666 + radius: 14 pressed: bg_color: 0x654949 widgets: - label: align: CENTER text: "Driveway" - text_font: font_button + text_font: font_small text_color: 0xFFFFFF on_click: - lambda: |- - id(security_camera_selection) = 2; - + id(security_camera_selection) = 3; - script.execute: refresh_security_camera_buttons - script.execute: refresh_security_camera - button: - id: security_camera_3_button - x: 519 + id: security_garage_camera_button + x: 516 y: 18 - width: 220 + width: 156 height: 70 bg_color: 0x28313D bg_opa: COVER border_width: 2 - border_color: 0x445365 - radius: 16 + border_color: 0x9A6666 + radius: 14 + pressed: + bg_color: 0x654949 widgets: - label: align: CENTER - text: "Camera3" - text_font: font_button - text_color: 0x8D98A6 + text: "Garage" + text_font: font_small + text_color: 0xFFFFFF + on_click: + - lambda: |- + id(security_camera_selection) = 4; + - script.execute: refresh_security_camera_buttons + - script.execute: refresh_security_camera - button: - id: security_camera_4_button - x: 766 + id: security_caravan_camera_button + x: 682 y: 18 - width: 220 + width: 156 height: 70 bg_color: 0x28313D bg_opa: COVER border_width: 2 - border_color: 0x445365 - radius: 16 + border_color: 0x9A6666 + radius: 14 + pressed: + bg_color: 0x654949 widgets: - label: align: CENTER - text: "Camera4" - text_font: font_button - text_color: 0x8D98A6 + text: "Caravan" + text_font: font_small + text_color: 0xFFFFFF + on_click: + - lambda: |- + id(security_camera_selection) = 5; + - script.execute: refresh_security_camera_buttons + - script.execute: refresh_security_camera + + - button: + id: security_bike_shed_camera_button + x: 848 + y: 18 + width: 156 + height: 70 + bg_color: 0x28313D + bg_opa: COVER + border_width: 2 + border_color: 0x9A6666 + radius: 14 + pressed: + bg_color: 0x654949 + widgets: + - label: + align: CENTER + text: "Bike Shed" + text_font: font_small + text_color: 0xFFFFFF + on_click: + - lambda: |- + id(security_camera_selection) = 6; + - script.execute: refresh_security_camera_buttons + - script.execute: refresh_security_camera #:################################################################################:# - # FUTURE SECURITY CONTROLS + # SECURITY CONTROLS #:################################################################################:# - button: - id: security_future_1_button + id: security_downstairs_guests_button x: 25 y: 105 width: 290 @@ -4203,14 +4957,23 @@ lvgl: bg_color: 0x28313D bg_opa: COVER border_width: 2 - border_color: 0x445365 + border_color: 0x548C6C radius: 16 + pressed: + bg_color: 0x416F55 widgets: - label: align: CENTER - text: "Future1" - text_font: font_button - text_color: 0x8D98A6 + text: "Downstairs Guests\nOccupied (Hold)" + text_font: font_small + text_align: CENTER + text_color: 0xFFFFFF + on_long_press: + then: + - homeassistant.action: + action: input_boolean.toggle + data: + entity_id: "${downstairs_guests_occupied_entity}" - button: id: security_future_2_button @@ -4249,7 +5012,7 @@ lvgl: text_color: 0x8D98A6 - button: - id: security_future_4_button + id: security_external_garage_light_button x: 25 y: 360 width: 290 @@ -4257,14 +5020,18 @@ lvgl: bg_color: 0x28313D bg_opa: COVER border_width: 2 - border_color: 0x445365 + border_color: 0x806D45 radius: 16 + pressed: + bg_color: 0xA87500 widgets: - label: align: CENTER - text: "Future4" + text: "Ext Garage Light" text_font: font_button - text_color: 0x8D98A6 + text_color: 0xFFFFFF + on_click: + - switch.toggle: ha_ext_garage_light #:################################################################################:# # 640x360 CAMERA IMAGE - RIGHT SIDE @@ -4423,87 +5190,210 @@ lvgl: text_color: 0xA8A198 clickable: false - # Four status readings + # Seven compact status readings. - label: - x: 80 + x: 22 + y: 454 + width: 138 + text: "High Tide" + text_font: font_header + text_align: CENTER + text_color: 0x6EBCC9 + clickable: false + + - label: + id: clock_high_tide_value_label + x: 22 + y: 483 + width: 138 + text: "--:--" + text_font: font_button + text_align: CENTER + text_color: 0x8BD6E1 + clickable: false + + - obj: + x: 160 y: 455 - width: 205 + width: 1 + height: 65 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 162 + y: 454 + width: 138 + text: "Rain Today" + text_font: font_header + text_align: CENTER + text_color: 0x6C9FD2 + clickable: false + + - label: + id: clock_rain_today_value_label + x: 162 + y: 483 + width: 138 + text: "--%" + text_font: font_button + text_align: CENTER + text_color: 0x85B8E8 + clickable: false + + - obj: + x: 300 + y: 455 + width: 1 + height: 65 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 302 + y: 454 + width: 138 + text: "Rain Tomorrow" + text_font: font_header + text_align: CENTER + text_color: 0x6C9FD2 + clickable: false + + - label: + id: clock_rain_tomorrow_value_label + x: 302 + y: 483 + width: 138 + text: "--%" + text_font: font_button + text_align: CENTER + text_color: 0x85B8E8 + clickable: false + + - obj: + x: 440 + y: 455 + width: 1 + height: 65 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 442 + y: 454 + width: 138 text: "Moon" - text_font: font_small + text_font: font_header text_align: CENTER text_color: 0xA9A0D4 clickable: false - label: id: clock_moon_value_label - x: 80 - y: 490 - width: 205 + x: 442 + y: 483 + width: 138 text: "--.-%" - text_font: font_title + text_font: font_button text_align: CENTER text_color: 0xC6BDEC clickable: false - - label: - x: 285 + - obj: + x: 580 y: 455 - width: 205 + width: 1 + height: 65 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 582 + y: 454 + width: 138 text: "Outdoor" - text_font: font_small + text_font: font_header text_align: CENTER text_color: 0x84B5D8 clickable: false - label: id: clock_outdoor_value_label - x: 285 - y: 490 - width: 205 + x: 582 + y: 483 + width: 138 text: "--.-°C" - text_font: font_title + text_font: font_button text_align: CENTER text_color: 0x9CCBEA clickable: false - - label: - x: 490 + - obj: + x: 720 y: 455 - width: 205 + width: 1 + height: 65 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 722 + y: 454 + width: 138 text: "Indoor" - text_font: font_small + text_font: font_header text_align: CENTER text_color: 0xD6B78F clickable: false - label: id: clock_temperature_label - x: 490 - y: 490 - width: 205 + x: 722 + y: 483 + width: 138 text: "--.-°C" - text_font: font_title + text_font: font_button text_align: CENTER text_color: 0xE8C79D clickable: false - - label: - x: 695 + - obj: + x: 860 y: 455 - width: 245 + width: 1 + height: 65 + bg_color: 0x354454 + bg_opa: COVER + border_width: 0 + clickable: false + + - label: + x: 862 + y: 454 + width: 140 text: "Humidity" - text_font: font_small + text_font: font_header text_align: CENTER text_color: 0x80BDA4 clickable: false - label: id: clock_humidity_label - x: 695 - y: 490 - width: 245 + x: 862 + y: 483 + width: 140 text: "--%" - text_font: font_title + text_font: font_button text_align: CENTER text_color: 0x97D2B7 clickable: false