diff --git a/esphome/esp-bedside-panel.yaml b/esphome/esp-bedside-panel.yaml index fdf23de..90157ba 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.10 2026-07-17 Refined Atto status layout and updated Garage Lights entity # V1.9 2026-07-17 Corrected Atto lock/climate/setpoint controls and added vehicle icons # V1.8 2026-07-17 Added hold-to-open Atto Vehicles page and vehicle controls # V1.7 2026-07-17 Added Bedroom button icons and corrected Panasonic Nanoe-X naming @@ -107,12 +108,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. Vehicles page with corrected BYD lock, climate and setpoint controls. (Layout V1.1)" + description_comment: "Guition JC1060P470C_I_W_Y ESP32-P4 bedside control panel. Refined Atto status layout, optimistic controls and corrected Garage Lights entity. (Layout V1.1)" device_area: "Bedroom" # Project Naming project_name: "Guition.JC1060P470C_I_W_Y" - project_version: "v1.9" + project_version: "v1.10" # Passwords & Secrets api_key: !secret esp-api_key @@ -159,7 +160,7 @@ substitutions: hall_lights_entity: "switch.main_hallway_lightswitch_relay_1_main_hallway_lights" bathroom_lights_entity: "switch.main_bathroom_lightswitch_3_2_all_main_bathroom_lights" patio_lights_entity: "switch.esp_garageentrylights_relay_2_patio_lights" - garage_lights_entity: "switch.esp_garageentrylights_relay_3_garage_lights" + garage_lights_entity: "switch.esp_garagelights_garage_lights" bathroom_fan_entity: "switch.esp_mainbathfancombo_relay_1_extract_fan" # Home Assistant Entities - Status @@ -545,6 +546,19 @@ font: - "\U000F0238" # mdi-fire - "\U000F0717" # mdi-snowflake + # Bold Atto status/value font used for prominent second-line values. + - file: + type: gfonts + family: Roboto + weight: 700 + id: font_vehicle_bold + size: 27 + bpp: 4 + glyphs: + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "abcdefghijklmnopqrstuvwxyz" + - "0123456789 .:/-%°()" + #:########################################################################################:# # HOME ASSISTANT NUMERIC SENSORS: # https://esphome.io/components/sensor/homeassistant.html @@ -696,7 +710,16 @@ sensor: on_value: then: - lambda: |- - if (!isnan(x)) { + if (isnan(x)) { + return; + } + + # BYD cloud polling can briefly return the previous target after + # a command. Do not let that stale value reverse the display. + if ( + !id(atto_setpoint_optimistic) || + fabsf(x - id(atto_setpoint_local)) < 0.1f + ) { id(atto_setpoint_local) = x; id(atto_setpoint_optimistic) = false; } @@ -1175,21 +1198,29 @@ script: ? lv_color_hex(0x315843) : lv_color_hex(0x6B3A3A); - # Charging and schedule status. + # Charging: prominent status and bright red active button. - lvgl.label.update: - id: atto_charging_label + id: atto_charging_state_label text: !lambda |- return id(ha_atto_charging).state - ? std::string("Atto Charging\nCharging") - : std::string("Atto Charging\nNot Charging"); + ? std::string("CHARGING") + : std::string("NOT CHARGING"); - lvgl.widget.update: id: atto_charging_status bg_color: !lambda |- return id(ha_atto_charging).state - ? lv_color_hex(0x315843) + ? lv_color_hex(0xD32F2F) : lv_color_hex(0x28313D); + # Charging schedule state. + - lvgl.label.update: + id: atto_schedule_state_label + text: !lambda |- + return id(ha_atto_schedule_enabled).state + ? std::string("ENABLED") + : std::string("NOT ENABLED"); + - lvgl.widget.update: id: atto_schedule_button bg_color: !lambda |- @@ -1199,102 +1230,74 @@ script: # Vehicle values. - lvgl.label.update: - id: atto_range_label + id: atto_range_value_label text: !lambda |- const float value = id(ha_atto_range).state; if (isnan(value)) { - return std::string("Atto Range\n-- km"); + return std::string("-- km"); } - char buffer[32]; - snprintf(buffer, sizeof(buffer), "Atto Range\n%.0f km", value); + char buffer[20]; + snprintf(buffer, sizeof(buffer), "%.0f km", value); return std::string(buffer); - lvgl.label.update: - id: atto_battery_label + id: atto_battery_value_label text: !lambda |- const float value = id(ha_atto_battery_level).state; if (isnan(value)) { - return std::string("Battery Level\n--%"); + return std::string("--%"); } - char buffer[32]; - snprintf(buffer, sizeof(buffer), "Battery Level\n%.0f%%", value); + char buffer[20]; + snprintf(buffer, sizeof(buffer), "%.0f%%", value); return std::string(buffer); - lvgl.label.update: - id: atto_cabin_temperature_label + id: atto_cabin_temperature_value_label text: !lambda |- const float value = id(ha_atto_cabin_temperature).state; if (isnan(value)) { - return std::string("Cabin Temp\n--.-°C"); + return std::string("--.-°C"); } - char buffer[32]; - snprintf(buffer, sizeof(buffer), "Cabin Temp\n%.1f°C", value); + char buffer[20]; + snprintf(buffer, sizeof(buffer), "%.1f°C", value); return std::string(buffer); - # Seat-heating states. - - lvgl.label.update: - id: atto_passenger_seat_button_label - text: !lambda |- - const auto value = id(ha_atto_passenger_seat_heating).state; - - if (value == "low" || value == "Low") { - return std::string("Passenger Seat (Hold)\nLow"); - } - - if (value == "high" || value == "High") { - return std::string("Passenger Seat (Hold)\nHigh"); - } - - return std::string("Passenger Seat (Hold)\nOff"); - + # Seat-heating colour only; the label remains clean and fixed. - lvgl.widget.update: id: atto_passenger_seat_button bg_color: !lambda |- const auto value = id(ha_atto_passenger_seat_heating).state; - return ( - value == "low" || - value == "Low" || - value == "high" || - value == "High" - ) - ? lv_color_hex(0x7A4A22) - : lv_color_hex(0x28313D); - - - lvgl.label.update: - id: atto_driver_seat_button_label - text: !lambda |- - const auto value = id(ha_atto_driver_seat_heating).state; + if (value == "high" || value == "High") { + return lv_color_hex(0xB76822); + } if (value == "low" || value == "Low") { - return std::string("Driver Seat (Hold)\nLow"); + return lv_color_hex(0x7A4A22); } - if (value == "high" || value == "High") { - return std::string("Driver Seat (Hold)\nHigh"); - } - - return std::string("Driver Seat (Hold)\nOff"); + return lv_color_hex(0x28313D); - lvgl.widget.update: id: atto_driver_seat_button bg_color: !lambda |- const auto value = id(ha_atto_driver_seat_heating).state; - return ( - value == "low" || - value == "Low" || - value == "high" || - value == "High" - ) - ? lv_color_hex(0x7A4A22) - : lv_color_hex(0x28313D); + if (value == "high" || value == "High") { + return lv_color_hex(0xB76822); + } + + if (value == "low" || value == "Low") { + return lv_color_hex(0x7A4A22); + } + + return lv_color_hex(0x28313D); # BYD heating/cooling intent is represented by max presets. - lvgl.widget.update: @@ -1374,7 +1377,7 @@ script: - id: release_atto_setpoint_optimistic mode: restart then: - - delay: 12s + - delay: 30s - lambda: |- id(atto_setpoint_optimistic) = false; @@ -2786,9 +2789,9 @@ lvgl: widgets: - label: id: atto_lock_icon_label - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 14 + y: 5 text: "\U000F033E" text_font: font_mdi_vehicle text_color: 0xFFFFFF @@ -2796,7 +2799,7 @@ lvgl: - label: id: atto_lock_button_label align: CENTER - x: 10 + x: 14 text: "Locked (Hold)" text_font: font_small text_align: CENTER @@ -2845,26 +2848,36 @@ lvgl: bg_color: 0x28313D bg_opa: COVER border_width: 2 - border_color: 0x548C6C + border_color: 0xA96363 radius: 17 widgets: - label: - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 13 + y: 5 text: "\U000F0084" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: - id: atto_charging_label - align: CENTER - x: 10 - text: "Atto Charging\nNot Charging" + x: 48 + y: 10 + width: 162 + text: "Atto Charging" text_font: font_small text_align: CENTER text_color: 0xFFFFFF + - label: + id: atto_charging_state_label + x: 48 + y: 42 + width: 162 + text: "NOT CHARGING" + text_font: font_vehicle_bold + text_align: CENTER + text_color: 0xFFFFFF + - button: id: atto_schedule_button x: 519 @@ -2880,20 +2893,31 @@ lvgl: bg_color: 0x315E82 widgets: - label: - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 13 + y: 5 text: "\U000F00F0" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: - align: CENTER - x: 10 - text: "Schedule Enabled" + x: 48 + y: 10 + width: 162 + text: "Schedule" text_font: font_small text_align: CENTER text_color: 0xFFFFFF + + - label: + id: atto_schedule_state_label + x: 48 + y: 42 + width: 162 + text: "NOT ENABLED" + text_font: font_vehicle_bold + text_align: CENTER + text_color: 0xFFFFFF on_click: - homeassistant.action: action: switch.toggle @@ -2913,20 +2937,30 @@ lvgl: radius: 17 widgets: - label: - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 13 + y: 5 text: "\U000F08F0" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: - id: atto_range_label - align: CENTER - x: 10 - text: "Atto Range\n-- km" + x: 48 + y: 10 + width: 162 + text: "Range" text_font: font_small text_align: CENTER + text_color: 0xAEB8C4 + + - label: + id: atto_range_value_label + x: 48 + y: 41 + width: 162 + text: "-- km" + text_font: font_vehicle_bold + text_align: CENTER text_color: 0xFFFFFF #:################################################################################:# @@ -2945,20 +2979,30 @@ lvgl: radius: 17 widgets: - label: - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 13 + y: 5 text: "\U000F0079" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: - id: atto_battery_label - align: CENTER - x: 10 - text: "Battery Level\n--%" + x: 48 + y: 10 + width: 162 + text: "Level" text_font: font_small text_align: CENTER + text_color: 0xAEB8C4 + + - label: + id: atto_battery_value_label + x: 48 + y: 41 + width: 162 + text: "--%" + text_font: font_vehicle_bold + text_align: CENTER text_color: 0xFFFFFF - button: @@ -2974,23 +3018,32 @@ lvgl: radius: 17 widgets: - label: - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 13 + y: 5 text: "\U000F050F" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: - id: atto_cabin_temperature_label - align: CENTER - x: 10 - text: "Cabin Temp\n--.-°C" + x: 48 + y: 10 + width: 162 + text: "Cabin" text_font: font_small text_align: CENTER + text_color: 0xAEB8C4 + + - label: + id: atto_cabin_temperature_value_label + x: 48 + y: 41 + width: 162 + text: "--.-°C" + text_font: font_vehicle_bold + text_align: CENTER text_color: 0xFFFFFF - # Passenger seat is intentionally before Driver seat. - button: id: atto_passenger_seat_button x: 519 @@ -3006,18 +3059,19 @@ lvgl: bg_color: 0x7A4A22 widgets: - label: - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 13 + y: 5 text: "\U000F0FA6" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: id: atto_passenger_seat_button_label - align: CENTER - x: 10 - text: "Passenger Seat (Hold)\nOff" + x: 48 + y: 20 + width: 162 + text: "Passenger Seat\n(Hold)" text_font: font_small text_align: CENTER text_color: 0xFFFFFF @@ -3082,18 +3136,19 @@ lvgl: bg_color: 0x7A4A22 widgets: - label: - align: TOP_LEFT - x: 10 - y: 8 + align: LEFT_MID + x: 13 + y: 5 text: "\U000F0FA6" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: id: atto_driver_seat_button_label - align: CENTER - x: 10 - text: "Driver Seat (Hold)\nOff" + x: 48 + y: 20 + width: 162 + text: "Driver Seat\n(Hold)" text_font: font_small text_align: CENTER text_color: 0xFFFFFF @@ -3171,14 +3226,14 @@ lvgl: widgets: - label: align: LEFT_MID - x: 18 + x: 10 text: "\U000F0238" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: align: CENTER - x: 15 + x: 28 text: "Heat (Hold)" text_font: font_button text_color: 0xFFFFFF @@ -3213,14 +3268,14 @@ lvgl: widgets: - label: align: LEFT_MID - x: 18 + x: 10 text: "\U000F0717" text_font: font_mdi_vehicle text_color: 0xFFFFFF - label: align: CENTER - x: 15 + x: 28 text: "Cool (Hold)" text_font: font_button text_color: 0xFFFFFF