diff --git a/fonts/materialdesignicons-webfont.ttf b/fonts/materialdesignicons-webfont.ttf new file mode 100644 index 0000000..bba7dcf Binary files /dev/null and b/fonts/materialdesignicons-webfont.ttf differ diff --git a/fonts/vm.ttf b/fonts/vm.ttf new file mode 100644 index 0000000..f786d0f Binary files /dev/null and b/fonts/vm.ttf differ diff --git a/nesp.yml b/nesp.yml new file mode 100644 index 0000000..4c77b6a --- /dev/null +++ b/nesp.yml @@ -0,0 +1,1501 @@ +# neo-nesp UI + +packages: + colors: !include colors/HOMEASSISTANT + +font: + - file: 'gfonts://Roboto@400' + glyphs: ' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ°.:/+-%–' + id: roboto_reg + size: 24 + bpp: 4 + extras: + # https://pictogrammers.github.io + - file: "fonts/materialdesignicons-webfont.ttf" + glyphs: [ + "\U000F050F", # mdi:thermometer + "\U000F058E", # mdi:water-percent + "\U000F0425", # mdi:power + "\U000F0238", # mdi:fire + "\U000F1A45", # mdi:heat-wave + "\U000F0717", # mdi:snowflake + "\U000F1A79", # mdi:sun-snowflake-variant + "\U000F0210", # mdi:fan + "\U000F171D", # mdi:fan-auto + "\U000F1472", # mdi:fan-speed-1 + "\U000F1473", # mdi:fan-speed-2 + "\U000F1474", # mdi:fan-speed-3 + "\U000F032A", # mdi:leaf + "\U000F04B9", # mdi:sofa + "\U000F14DE", # mdi:rocket-launch + "\U000F0D80", # mdi:home-floor-1 + "\U000F0D81", # mdi:home-floor-2 + "\U000F004D", # mdi:arrow-left + "\U000F09DF", # mdi:circle-small + "\U000F0E03", # mdi:thermometer-chevron-up + "\U000F0E02", # mdi:thermometer-chevron-down + "\U000F0594", # mdi:weather-night (clear) + "\U000F0590", # mdi:weather-cloudy (cloudy) + "\U000F0898", # mdi:weather-hurricane (cyclone, tropical_cyclone) + "\U000F0F30", # mdi:weather-hazy (dust, dusty, haze, hazy) + "\U000F0591", # mdi:weather-fog (fog) + "\U000F12CB", # mdi:snowflake-melt (frost) + "\U000F0596", # mdi:weather-pouring (heavy_shower, heavy_showers, rain) + "\U000F0F33", # mdi:weather-partly-rainy (light_rain) + # mdi:weather-light-showers (light_shower, light_showers) + "\U000F0599", # mdi:weather-sunny (mostly_sunny, sunny) + "\U000F0595", # mdi:weather-partly-cloudy (partly_cloudy) + "\U000F0597", # mdi:weather-rainy (shower, showers) + "\U000F0598", # mdi:weather-snowy (snow) + "\U000F0593", # mdi:weather-lightning + "\U000F067E", # mdi:weather-lightning-rainy (storm, storms) + "\U000F059D", # mdi:weather-windy (wind, windy) + "\U000F0592", # mdi:weather-hail + ] + + - file: 'gfonts://Roboto@400' + glyphs: ' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ°.:/+-%–' + id: roboto_med + size: 48 + bpp: 4 + extras: + # https://pictogrammers.github.io + - file: "fonts/materialdesignicons-webfont.ttf" + glyphs: [ + "\U000F050F", # mdi:thermometer + "\U000F058E", # mdi:water-percent + "\U000F0425", # mdi:power + "\U000F0238", # mdi:fire + "\U000F1A45", # mdi:heat-wave + "\U000F0717", # mdi:snowflake + "\U000F1A79", # mdi:sun-snowflake-variant + "\U000F0210", # mdi:fan + "\U000F171D", # mdi:fan-auto + "\U000F1472", # mdi:fan-speed-1 + "\U000F1473", # mdi:fan-speed-2 + "\U000F1474", # mdi:fan-speed-3 + "\U000F032A", # mdi:leaf + "\U000F04B9", # mdi:sofa + "\U000F14DE", # mdi:rocket-launch + "\U000F0D80", # mdi:home-floor-1 + "\U000F0D81", # mdi:home-floor-2 + "\U000F004D", # mdi:arrow-left + "\U000F09DF", # mdi:circle-small + "\U000F0E03", # mdi:thermometer-chevron-up + "\U000F0E02", # mdi:thermometer-chevron-down + "\U000F0594", # mdi:weather-night (clear) + "\U000F0590", # mdi:weather-cloudy (cloudy) + "\U000F0898", # mdi:weather-hurricane (cyclone, tropical_cyclone) + "\U000F0F30", # mdi:weather-hazy (dust, dusty, haze, hazy) + "\U000F0591", # mdi:weather-fog (fog) + "\U000F12CB", # mdi:snowflake-melt (frost) + "\U000F0596", # mdi:weather-pouring (heavy_shower, heavy_showers, rain) + "\U000F0F33", # mdi:weather-partly-rainy (light_rain) + # mdi:weather-light-showers (light_shower, light_showers) + "\U000F0599", # mdi:weather-sunny (mostly_sunny, sunny) + "\U000F0595", # mdi:weather-partly-cloudy (partly_cloudy) + "\U000F0597", # mdi:weather-rainy (shower, showers) + "\U000F0598", # mdi:weather-snowy (snow) + "\U000F0593", # mdi:weather-lightning + "\U000F067E", # mdi:weather-lightning-rainy (storm, storms) + "\U000F059D", # mdi:weather-windy (wind, windy) + "\U000F0592", # mdi:weather-hail + ] + + - file: 'gfonts://Roboto@400' + glyphs: ' -0123456789.°C' + id: roboto_huge + size: 90 + bpp: 4 + extras: + # https://pictogrammers.github.io + - file: "fonts/materialdesignicons-webfont.ttf" + glyphs: [ + "\U000F171D", # mdi:fan-auto + "\U000F1472", # mdi:fan-speed-1 + "\U000F1473", # mdi:fan-speed-2 + "\U000F1474", # mdi:fan-speed-3 + "\U000F0594", # mdi:weather-night (clear) + "\U000F0590", # mdi:weather-cloudy (cloudy) + "\U000F0898", # mdi:weather-hurricane (cyclone, tropical_cyclone) + "\U000F0F30", # mdi:weather-hazy (dust, dusty, haze, hazy) + "\U000F0591", # mdi:weather-fog (fog) + "\U000F12CB", # mdi:snowflake-melt (frost) + "\U000F0596", # mdi:weather-pouring (heavy_shower, heavy_showers, rain) + "\U000F0F33", # mdi:weather-partly-rainy (light_rain) + # mdi:weather-light-showers (light_shower, light_showers) + "\U000F0599", # mdi:weather-sunny (mostly_sunny, sunny) + "\U000F0595", # mdi:weather-partly-cloudy (partly_cloudy) + "\U000F0597", # mdi:weather-rainy (shower, showers) + "\U000F0598", # mdi:weather-snowy (snow) + "\U000F0593", # mdi:weather-lightning + "\U000F067E", # mdi:weather-lightning-rainy (storm, storms) + "\U000F059D", # mdi:weather-windy (wind, windy) + "\U000F0592", # mdi:weather-hail + ] + +globals: + - id: active_lvgl_page + type: std::string + +lvgl: + encoders: + enter_button: push_button + sensor: rotary + bg_color: black + scrollbar_mode: "OFF" + default_font: roboto_reg + text_color: white + style_definitions: + - id: style_menu_button + align: CENTER + bg_opa: TRANSP + shadow_opa: TRANSP + height: 50 + width: 50 + radius: 50% + - id: style_menu_button_label + align: CENTER + y: 3 + text_font: roboto_med + + pages: + ### GUI - THERMOSTAT + - id: main_page + on_load: + - globals.set: + id: active_lvgl_page + value: '"main_page"' + widgets: + - arc: + id: arc_bg + height: 468 + width: 468 + align: CENTER + arc_color: graylight + arc_opa: COVER + arc_width: 2 + arc_rounded: false + - arc: + id: current_temp_arc + adjustable: true + state: + disabled: true + min_value: 120 # 12°C (* 10 because decimals not supported) + max_value: 340 # 34°C + height: 468 + width: 468 + align: CENTER + arc_color: graylight + arc_opa: COVER + arc_width: 2 + arc_rounded: false + indicator: + arc_color: graylight + arc_opa: COVER + arc_width: 2 + arc_rounded: false + knob: + bg_color: white + value: 230 + - meter: + id: meter_ticks + height: 480 + width: 480 + align: CENTER + bg_opa: TRANSP + border_width: 0 + scales: + range_from: 120 # 12°C (* 10 because decimals not supported) + range_to: 340 # 34°C + ticks: + count: 89 + length: 37 + width: 3 + color: graylight + indicators: + - line: + id: set_temp_needle + color: white + width: 8 + r_mod: 10 + value: 230 + - arc: + id: diff_temp_arc + start_value: 120 + end_value: 230 + color: white + width: 2 + r_mod: 10 + - obj: + id: mode_bg + height: 350 + width: 350 + radius: 175 + align: CENTER + border_width: 0 + bg_color: black + - roller: + id: set_temp_roller + state: + disabled: true + align: CENTER + anim_time: 500ms + text_font: roboto_med + text_opa: TRANSP + bg_opa: TRANSP + border_width: 0 + text_line_space: 30 + visible_row_count: 2 + selected: + text_font: roboto_huge + text_opa: COVER + bg_opa: TRANSP + border_width: 0 + options: + - 16.0 + - 16.5 + - 17.0 + - 17.5 + - 18.0 + - 18.5 + - 19.0 + - 19.5 + - 20.0 + - 20.5 + - 21.0 + - 21.5 + - 22.0 + - 22.5 + - 23.0 + - 23.5 + - 24.0 + - 24.5 + - 25.0 + - 25.5 + - 26.0 + - 26.5 + - 27.0 + - 27.5 + - 28.0 + - 28.5 + - 29.0 + - 29.5 + - 30.0 + selected_index: 14 + - label: + id: celsius_label + align: CENTER + x: 100 + y: -43 + text: "°C" + - label: + id: mode_label + align: CENTER + y: -100 + text: "NESP" + - label: + id: weather_icon_label + hidden: true + align: CENTER + y: -100 + text_font: roboto_huge + text: " " + - label: + id: weather_temp_label + hidden: true + align: CENTER + text_font: roboto_huge + text: " " + - label: + id: weather_forecast_label + hidden: true + align: CENTER + y: 70 + text: " " + - label: + id: weather_feels_like_label + hidden: true + align: CENTER + y: 130 + text: " " + - label: + id: big_fan_icon_label + hidden: true + align: CENTER + text_font: roboto_huge + text: " " + - label: + id: zone_1_label + align: CENTER + x: -15 + y: 90 + text_color: graydarker + text: "\U000F0D80" + - label: + id: zone_2_label + align: CENTER + x: 15 + y: 90 + text_color: graydarker + text: "\U000F0D81" + - label: + id: current_temp_label + align: CENTER + y: 120 + text: " " + - label: + id: fan_icon_label + align: CENTER + y: 210 + text_font: roboto_med + text: " " + + ### GUI - MENU + - id: menu_page + on_load: + - globals.set: + id: active_lvgl_page + value: '"menu_page"' + - script.execute: update_menu_date_label + - lvgl.widget.enable: + - menu_zone_2_button + - menu_zone_1_button + - menu_back_button + - menu_power_button + - menu_mode_button + - menu_preset_button + - menu_fan_button + - lvgl.widget.focus: menu_power_button + on_unload: + - lvgl.widget.disable: + - menu_zone_2_button + - menu_zone_1_button + - menu_back_button + - menu_power_button + - menu_mode_button + - menu_preset_button + - menu_fan_button + widgets: + - label: + id: menu_date_label + align: LEFT_MID + x: 30 + y: -60 + text_align: LEFT + text_color: graydark + text: "SUN 00:00" + - label: + id: menu_weather_icon_label + align: LEFT_MID + x: 30 + y: -27 + text_align: LEFT + text: "\U000F0599" + - label: + id: menu_weather_label + align: LEFT_MID + x: 60 + y: -30 + text_align: LEFT + text: "00°C" + - label: + id: menu_indoor_label + align: LEFT_MID + x: 30 + y: 10 + text_align: LEFT + text_color: graydark + text: "INDOOR" + - label: + id: menu_zone_icon_label + align: LEFT_MID + x: 30 + y: 58 + text_align: LEFT + text: "\U000F0D81\n\U000F0D80" + - label: + id: menu_zone_temp_label + align: LEFT_MID + x: 60 + y: 55 + text_align: LEFT + text: "00°C 00%H\n00°C 00%H" + - label: + id: selected_menu_label + align: CENTER + x: 55 + text_font: roboto_med + text_align: RIGHT + - button: + id: menu_zone_2_button + state: + disabled: true + x: 0 + y: -210 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F0D81" + on_focus: + - lvgl.label.update: + id: selected_menu_label + text: "Upstairs\nZone" + on_press: + - homeassistant.action: + action: cover.toggle + data: + entity_id: ${zone_2_entity} + - button: + id: menu_zone_1_button + state: + disabled: true + x: 105 # 210sin(30) clock coords + y: -182 # 210cos(30) + styles: style_menu_button + widgets: + - label: + align: CENTER + y: 3 + text_font: roboto_med + text: "\U000F0D80" + on_focus: + - lvgl.label.update: + id: selected_menu_label + text: "Downstairs\nZone" + on_press: + - homeassistant.action: + action: cover.toggle + data: + entity_id: ${zone_1_entity} + - button: + id: menu_back_button + state: + disabled: true + x: 182 + y: -105 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F004D" + on_focus: + - lvgl.label.update: + id: selected_menu_label + text: "Back" + on_press: + - script.execute: goto_main_page + - button: + id: menu_power_button + state: + disabled: true + x: 210 + y: 0 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F0425" + on_focus: + - if: + condition: + lambda: 'return strcmp(id(hvac_mode).state.c_str(), "off") == 0;' + then: + lvgl.label.update: + id: selected_menu_label + text: "Turn On" + else: + lvgl.label.update: + id: selected_menu_label + text: "Turn Off" + on_press: + - homeassistant.action: + action: climate.toggle + data: + entity_id: ${climate_entity} + - script.execute: goto_main_page + - button: + id: menu_mode_button + state: + disabled: true + x: 182 + y: 105 + styles: style_menu_button + widgets: + - label: + id: menu_mode_button_label + styles: style_menu_button_label + text: "\U000F0238" + on_focus: + - lvgl.label.update: + id: selected_menu_label + text: "Mode" + on_press: + - script.execute: goto_mode_page + - button: + id: menu_preset_button + state: + disabled: true + x: 105 + y: 182 + styles: style_menu_button + widgets: + - label: + id: menu_preset_button_label + styles: style_menu_button_label + text: "\U000F032A" + on_focus: + - lvgl.label.update: + id: selected_menu_label + text: "Presets" + on_press: + - script.execute: goto_preset_page + - button: + id: menu_fan_button + state: + disabled: true + styles: style_menu_button + x: 0 + y: 210 + widgets: + - label: + id: menu_fan_button_label + styles: style_menu_button_label + text: "\U000F0210" + on_focus: + - lvgl.label.update: + id: selected_menu_label + text: "Fan\nSpeed" + on_press: + - script.execute: goto_fan_page + + ### GUI - MODE SELECT + - id: mode_page + on_load: + - globals.set: + id: active_lvgl_page + value: '"mode_page"' + - lvgl.widget.enable: + - mode_back_button + - mode_heat_cool_button + - mode_cool_button + - mode_heat_button + - mode_fan_button + - mode_dry_button + - lvgl.widget.focus: mode_cool_button + on_unload: + - lvgl.widget.disable: + - mode_back_button + - mode_heat_cool_button + - mode_cool_button + - mode_heat_button + - mode_fan_button + - mode_dry_button + widgets: + - label: + id: selected_mode_label + align: CENTER + x: 55 + text_font: roboto_med + text_align: RIGHT + - button: + id: mode_back_button + state: + disabled: true + x: 105 # 210sin(30) clock coords + y: -182 # 210cos(30) + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F004D" + on_focus: + - lvgl.label.update: + id: selected_mode_label + text: "Back" + on_press: + - script.execute: goto_menu_page + - button: + id: mode_heat_cool_button + state: + disabled: true + x: 182 + y: -105 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F1A79" + on_focus: + - lvgl.label.update: + id: selected_mode_label + text: "Auto" + on_press: + - homeassistant.action: + action: climate.set_hvac_mode + data: + entity_id: ${climate_entity} + hvac_mode: "heat_cool" + - script.execute: goto_main_page + - button: + id: mode_cool_button + state: + disabled: true + x: 210 + y: 0 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F0717" + on_focus: + - lvgl.label.update: + id: selected_mode_label + text: "Cool" + on_press: + - homeassistant.action: + action: climate.set_hvac_mode + data: + entity_id: ${climate_entity} + hvac_mode: "cool" + - script.execute: goto_main_page + - button: + id: mode_heat_button + state: + disabled: true + x: 182 + y: 105 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F0238" + on_focus: + - lvgl.label.update: + id: selected_mode_label + text: "Heat" + on_press: + - homeassistant.action: + action: climate.set_hvac_mode + data: + entity_id: ${climate_entity} + hvac_mode: "heat" + - script.execute: goto_main_page + - button: + id: mode_fan_button + state: + disabled: true + x: 105 + y: 182 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F0210" + on_focus: + - lvgl.label.update: + id: selected_mode_label + text: "Fan" + on_press: + - homeassistant.action: + action: climate.set_hvac_mode + data: + entity_id: ${climate_entity} + hvac_mode: "fan_only" + - script.execute: goto_main_page + - button: + id: mode_dry_button + state: + disabled: true + x: 0 + y: 210 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F058E" + on_focus: + - lvgl.label.update: + id: selected_mode_label + text: "Dehumidify" + on_press: + - homeassistant.action: + action: climate.set_hvac_mode + data: + entity_id: ${climate_entity} + hvac_mode: "dry" + - script.execute: goto_main_page + + ### GUI - PRESET SELECT + - id: preset_page + on_load: + - globals.set: + id: active_lvgl_page + value: '"preset_page"' + - lvgl.widget.enable: + - preset_back_button + - preset_eco_button + - preset_comfort_button + - preset_boost_button + - lvgl.widget.focus: preset_eco_button + on_unload: + - lvgl.widget.disable: + - preset_back_button + - preset_eco_button + - preset_comfort_button + - preset_boost_button + widgets: + - label: + id: selected_preset_label + align: CENTER + x: 55 + text_font: roboto_med + text_align: RIGHT + - button: + id: preset_back_button + state: + disabled: true + x: 182 + y: -105 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F004D" + on_focus: + - lvgl.label.update: + id: selected_preset_label + text: "Back" + on_press: + - script.execute: goto_menu_page + - button: + id: preset_eco_button + state: + disabled: true + x: 210 + y: 0 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F032A" + on_focus: + - lvgl.label.update: + id: selected_preset_label + text: "Eco" + on_press: + - if: + condition: + lambda: 'return strcmp(id(preset_mode).state.c_str(), "eco") == 0;' + then: + - homeassistant.action: + action: climate.set_preset_mode + data: + entity_id: ${climate_entity} + preset_mode: "none" + else: + - homeassistant.action: + action: climate.set_preset_mode + data: + entity_id: ${climate_entity} + preset_mode: "eco" + - script.execute: goto_main_page + - button: + id: preset_comfort_button + state: + disabled: true + x: 182 + y: 105 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F04B9" + on_focus: + - lvgl.label.update: + id: selected_preset_label + text: "Comfort" + on_press: + - if: + condition: + lambda: 'return strcmp(id(preset_mode).state.c_str(), "comfort") == 0;' + then: + - homeassistant.action: + action: climate.set_preset_mode + data: + entity_id: ${climate_entity} + preset_mode: "none" + else: + - homeassistant.action: + action: climate.set_preset_mode + data: + entity_id: ${climate_entity} + preset_mode: "comfort" + - script.execute: goto_main_page + - button: + id: preset_boost_button + state: + disabled: true + x: 105 + y: 182 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F14DE" + on_focus: + - lvgl.label.update: + id: selected_preset_label + text: "Boost" + on_press: + - if: + condition: + lambda: 'return strcmp(id(preset_mode).state.c_str(), "boost") == 0;' + then: + - homeassistant.action: + action: climate.set_preset_mode + data: + entity_id: ${climate_entity} + preset_mode: "none" + else: + - homeassistant.action: + action: climate.set_preset_mode + data: + entity_id: ${climate_entity} + preset_mode: "boost" + - script.execute: goto_main_page + + ### GUI - FAN SPEED SELECT + - id: fan_page + on_load: + - globals.set: + id: active_lvgl_page + value: '"fan_page"' + - lvgl.widget.enable: + - fan_back_button + - fan_auto_button + - fan_high_button + - fan_medium_button + - fan_low_button + - lvgl.widget.focus: fan_auto_button + on_unload: + - lvgl.widget.disable: + - fan_back_button + - fan_auto_button + - fan_high_button + - fan_medium_button + - fan_low_button + widgets: + - label: + id: selected_fan_label + align: CENTER + x: 55 + text_font: roboto_med + text_align: RIGHT + - button: + id: fan_back_button + state: + disabled: true + x: 182 + y: -105 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F004D" + on_focus: + - lvgl.label.update: + id: selected_fan_label + text: "Back" + on_press: + - script.execute: goto_menu_page + - button: + id: fan_auto_button + state: + disabled: true + x: 210 + y: 0 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F171D" + on_focus: + - lvgl.label.update: + id: selected_fan_label + text: "Auto" + on_press: + - homeassistant.action: + action: climate.set_fan_mode + data: + entity_id: ${climate_entity} + fan_mode: "auto" + - script.execute: goto_main_page + - button: + id: fan_high_button + state: + disabled: true + x: 182 + y: 105 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F1474" + on_focus: + - lvgl.label.update: + id: selected_fan_label + text: "High" + on_press: + - homeassistant.action: + action: climate.set_fan_mode + data: + entity_id: ${climate_entity} + fan_mode: "high" + - script.execute: goto_main_page + - button: + id: fan_medium_button + state: + disabled: true + x: 105 + y: 182 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F1473" + on_focus: + - lvgl.label.update: + id: selected_fan_label + text: "Medium" + on_press: + - homeassistant.action: + action: climate.set_fan_mode + data: + entity_id: ${climate_entity} + fan_mode: "medium" + - script.execute: goto_main_page + - button: + id: fan_low_button + state: + disabled: true + x: 0 + y: 210 + styles: style_menu_button + widgets: + - label: + styles: style_menu_button_label + text: "\U000F1472" + on_focus: + - lvgl.label.update: + id: selected_fan_label + text: "Low" + on_press: + - homeassistant.action: + action: climate.set_fan_mode + data: + entity_id: ${climate_entity} + fan_mode: "low" + - script.execute: goto_main_page + +script: + - id: vibrate + parameters: + length_ms: int + then: + # XXX doesn't delay properly for short lengths (10-100ms) + - switch.turn_on: vibration + - delay: !lambda return length_ms; + - switch.turn_off: vibration + + # navigate to pages with animation + - id: goto_main_page + then: + - lvgl.page.show: + id: main_page + animation: FADE_OUT + time: 500ms + - id: goto_menu_page + then: + - lvgl.page.show: + id: menu_page + animation: FADE_IN + time: 500ms + - id: goto_mode_page + then: + - lvgl.page.show: + id: mode_page + animation: FADE_IN + time: 500ms + - id: goto_preset_page + then: + - lvgl.page.show: + id: preset_page + animation: FADE_IN + time: 500ms + - id: goto_fan_page + then: + - lvgl.page.show: + id: fan_page + animation: FADE_IN + time: 500ms + + # hvac mode UI scripts + - id: update_menu_date_label + then: + - lvgl.label.update: + id: menu_date_label + text: !lambda |- + auto now = id(hass_time).now(); + static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; + static char buf[10]; + snprintf(buf, sizeof(buf), "%s %02d:%02d", day_names[now.day_of_week-1], now.hour, now.minute); + return buf; + - id: update_menu_zone_temp_label + then: + - lvgl.label.update: + id: menu_zone_temp_label + text: + format: "%.0f°C \U000F058E %.0f%%\n%.0f°C \U000F058E %.0f%%" + args: [ 'round(id(zone_2_temp).state)', 'round(id(zone_2_humidity).state)', 'round(id(zone_1_temp).state)', 'round(id(zone_1_humidity).state)' ] + + - id: set_mode_off + then: + - script.execute: hide_widgets + - lvgl.label.update: + id: mode_label + text: "OFF" + - lvgl.widget.update: + id: mode_bg + bg_color: black + - light.turn_off: rgb_ring + - lvgl.label.update: + id: menu_mode_button_label + text_color: white + text: "\U000F0717" + - lvgl.widget.update: + id: menu_power_button + text_color: graydark + - lvgl.widget.update: + id: mode_heat_button + text_color: white + - lvgl.widget.update: + id: mode_cool_button + text_color: white + - lvgl.widget.update: + id: mode_fan_button + text_color: white + - lvgl.widget.update: + id: mode_dry_button + text_color: white + - lvgl.widget.update: + id: mode_heat_cool_button + text_color: white + - id: set_mode_heat + then: + - script.execute: show_widgets + - lvgl.label.update: + id: mode_label + text: "HEAT TO" + - lvgl.widget.update: + id: mode_bg + bg_color: mode_heat + - light.turn_on: + id: rgb_ring + brightness: 100% + red: 1.000 + green: 0.533 + blue: 0.118 + - lvgl.label.update: + id: menu_mode_button_label + text_color: mode_heat + text: "\U000F0238" + - lvgl.widget.update: + id: menu_power_button + text_color: white + - lvgl.widget.update: + id: mode_heat_button + text_color: mode_heat + - lvgl.widget.update: + id: mode_cool_button + text_color: white + - lvgl.widget.update: + id: mode_fan_button + text_color: white + - lvgl.widget.update: + id: mode_dry_button + text_color: white + - lvgl.widget.update: + id: mode_heat_cool_button + text_color: white + - id: set_mode_cool + then: + - script.execute: show_widgets + - lvgl.label.update: + id: mode_label + text: "COOL TO" + - lvgl.widget.update: + id: mode_bg + bg_color: mode_cool + - light.turn_on: + id: rgb_ring + brightness: 100% + red: 0.498 + green: 0.675 + blue: 1.000 + - lvgl.label.update: + id: menu_mode_button_label + text_color: mode_cool + text: "\U000F0717" + - lvgl.widget.update: + id: menu_power_button + text_color: white + - lvgl.widget.update: + id: mode_heat_button + text_color: white + - lvgl.widget.update: + id: mode_cool_button + text_color: mode_cool + - lvgl.widget.update: + id: mode_fan_button + text_color: white + - lvgl.widget.update: + id: mode_dry_button + text_color: white + - lvgl.widget.update: + id: mode_heat_cool_button + text_color: white + - id: set_mode_fan + then: + - script.execute: show_widgets + - lvgl.widget.hide: + - current_temp_arc + - set_temp_roller + - celsius_label + - current_temp_label + - fan_icon_label + - lvgl.indicator.update: + id: set_temp_needle + opa: TRANSP + - lvgl.indicator.update: + id: diff_temp_arc + opa: TRANSP + - lvgl.widget.show: + - big_fan_icon_label + - lvgl.label.update: + id: mode_label + text: "FAN ONLY" + - lvgl.widget.update: + id: mode_bg + bg_color: mode_fan + - light.turn_on: + id: rgb_ring + brightness: 100% + red: 0.749 + green: 0.980 + blue: 1.000 + - lvgl.label.update: + id: menu_mode_button_label + text_color: mode_fan + text: "\U000F0210" + - lvgl.widget.update: + id: menu_power_button + text_color: white + - lvgl.widget.update: + id: mode_heat_button + text_color: white + - lvgl.widget.update: + id: mode_cool_button + text_color: white + - lvgl.widget.update: + id: mode_fan_button + text_color: mode_fan + - lvgl.widget.update: + id: mode_dry_button + text_color: white + - lvgl.widget.update: + id: mode_heat_cool_button + text_color: white + - id: set_mode_dry + then: + - script.execute: show_widgets + - lvgl.label.update: + id: mode_label + text: "DEHUMIDIFY" + - lvgl.widget.update: + id: mode_bg + bg_color: mode_dry + - light.turn_on: + id: rgb_ring + brightness: 100% + red: 1.000 + green: 0.753 + blue: 0.549 + - lvgl.label.update: + id: menu_mode_button_label + text_color: mode_dry + text: "\U000F058E" + - lvgl.widget.update: + id: menu_power_button + text_color: white + - lvgl.widget.update: + id: mode_heat_button + text_color: white + - lvgl.widget.update: + id: mode_cool_button + text_color: white + - lvgl.widget.update: + id: mode_fan_button + text_color: white + - lvgl.widget.update: + id: mode_dry_button + text_color: mode_dry + - lvgl.widget.update: + id: mode_heat_cool_button + text_color: white + - id: set_mode_heat_cool + then: + - script.execute: show_widgets + - lvgl.label.update: + id: mode_label + text: "AUTO TO" + - lvgl.widget.update: + id: mode_bg + bg_color: graylight + - light.turn_on: + id: rgb_ring + brightness: 100% + red: 1.000 + green: 0.894 + blue: 0.804 + - lvgl.label.update: + id: menu_mode_button_label + text_color: mode_heat_cool + text: "\U000F1A79" + - lvgl.widget.update: + id: menu_power_button + text_color: white + - lvgl.widget.update: + id: mode_heat_button + text_color: white + - lvgl.widget.update: + id: mode_cool_button + text_color: white + - lvgl.widget.update: + id: mode_fan_button + text_color: white + - lvgl.widget.update: + id: mode_dry_button + text_color: white + - lvgl.widget.update: + id: mode_heat_cool_button + text_color: mode_heat_cool + + # preset mode UI scripts + - id: set_preset_none + then: + - lvgl.label.update: + id: menu_preset_button_label + text_color: white + text: "\U000F032A" + - lvgl.widget.update: + id: preset_eco_button + text_color: white + - lvgl.widget.update: + id: preset_comfort_button + text_color: white + - lvgl.widget.update: + id: preset_boost_button + text_color: white + - id: set_preset_eco + then: + - lvgl.label.update: + id: menu_preset_button_label + text_color: green + text: "\U000F032A" + - lvgl.widget.update: + id: preset_eco_button + text_color: green + - lvgl.widget.update: + id: preset_comfort_button + text_color: white + - lvgl.widget.update: + id: preset_boost_button + text_color: white + - id: set_preset_comfort + then: + - lvgl.label.update: + id: menu_preset_button_label + text_color: amber + text: "\U000F04B9" + - lvgl.widget.update: + id: preset_eco_button + text_color: white + - lvgl.widget.update: + id: preset_comfort_button + text_color: amber + - lvgl.widget.update: + id: preset_boost_button + text_color: white + - id: set_preset_boost + then: + - lvgl.label.update: + id: menu_preset_button_label + text_color: red + text: "\U000F14DE" + - lvgl.widget.update: + id: preset_eco_button + text_color: white + - lvgl.widget.update: + id: preset_comfort_button + text_color: white + - lvgl.widget.update: + id: preset_boost_button + text_color: red + + # fan UI scripts + - id: set_fan_auto + then: + - lvgl.label.update: + id: big_fan_icon_label + text: "\U000F171D" + - lvgl.label.update: + id: fan_icon_label + text: "\U000F171D" + - lvgl.label.update: + id: menu_fan_button_label + text: "\U000F171D" + - id: set_fan_low + then: + - lvgl.label.update: + id: big_fan_icon_label + text: "\U000F1472" + - lvgl.label.update: + id: fan_icon_label + text: "\U000F1472" + - lvgl.label.update: + id: menu_fan_button_label + text: "\U000F1472" + - id: set_fan_medium + then: + - lvgl.label.update: + id: big_fan_icon_label + text: "\U000F1473" + - lvgl.label.update: + id: fan_icon_label + text: "\U000F1473" + - lvgl.label.update: + id: menu_fan_button_label + text: "\U000F1473" + - id: set_fan_high + then: + - lvgl.label.update: + id: big_fan_icon_label + text: "\U000F1474" + - lvgl.label.update: + id: fan_icon_label + text: "\U000F1474" + - lvgl.label.update: + id: menu_fan_button_label + text: "\U000F1474" + + # zone UI scripts + - id: set_zone_1 + then: + - lvgl.label.update: + id: zone_1_label + text_color: white + - lvgl.widget.update: + id: menu_zone_1_button + text_color: white + - id: unset_zone_1 + then: + - lvgl.label.update: + id: zone_1_label + text_color: graydark + - lvgl.widget.update: + id: menu_zone_1_button + text_color: graydark + - id: set_zone_2 + then: + - lvgl.label.update: + id: zone_2_label + text_color: white + - lvgl.widget.update: + id: menu_zone_2_button + text_color: white + - id: unset_zone_2 + then: + - lvgl.label.update: + id: zone_2_label + text_color: graydark + - lvgl.widget.update: + id: menu_zone_2_button + text_color: graydark + + # OFF mode weather UI scripts + - id: update_weather_forecast_label + then: + lvgl.label.update: + id: weather_forecast_label + text: !lambda |- + auto low = round(id(bom_low_temp).state); + auto high = round(id(bom_high_temp).state); + auto rain = round(id(bom_rain_chance).state); + static char buf[32]; + if (!isnan(low)) { + snprintf(buf, sizeof(buf), "\U000F0E03 %.0f–%.0f°C \U000F0597 %.0f%%", low, high, rain); + } else { + snprintf(buf, sizeof(buf), "\U000F0E03 %.0f°C \U000F0597 %.0f%%", high, rain); + } + return buf; + + - id: show_widgets + then: + - lvgl.widget.show: + - current_temp_arc + - set_temp_roller + - celsius_label + - fan_icon_label + - current_temp_label + - zone_1_label + - zone_2_label + - meter_ticks + - mode_label + - lvgl.widget.hide: + - big_fan_icon_label + - weather_icon_label + - weather_temp_label + - weather_forecast_label + - weather_feels_like_label + - lvgl.indicator.update: + id: set_temp_needle + opa: COVER + - lvgl.indicator.update: + id: diff_temp_arc + opa: COVER + - id: hide_widgets + then: + - lvgl.widget.hide: + - big_fan_icon_label + - current_temp_arc + - set_temp_roller + - celsius_label + - fan_icon_label + - current_temp_label + - zone_1_label + - zone_2_label + - meter_ticks + - mode_label + - lvgl.widget.show: + - weather_icon_label + - weather_temp_label + - weather_forecast_label + - weather_feels_like_label + - lvgl.indicator.update: + id: set_temp_needle + opa: TRANSP + - lvgl.indicator.update: + id: diff_temp_arc + opa: TRANSP diff --git a/thermostat.yml b/thermostat.yml index 1695944..388aaf4 100644 --- a/thermostat.yml +++ b/thermostat.yml @@ -1,3 +1,13 @@ +substitutions: + color_bg: '0x282A36' + color_bg_alt: '0x34353e' + color_white: '0xE2E4E5' + color_temp_current: '0x57c7ff' + color_dark_blue: '0x57c7ff' + color_light_blue: '0x9aedfe' + color_green: '0x5AF78E' + color_red: '0xff5c57' + color_darker_white: '0xA5A5A9' esphome: name: thermostat @@ -13,7 +23,7 @@ esphome: # CONFIG_SPIRAM_RODATA: y esp32: - board: esp32-s3-devkitc-1 + board: esp32s3box variant: esp32s3 flash_size: 8MB framework: @@ -41,12 +51,15 @@ psram: # Enable logging logger: + level: DEBUG + # baud_rate: 0 ch422g: # address: 0x24 # Enable Home Assistant API api: + reboot_timeout: 10s password: "" ota: @@ -54,11 +67,20 @@ ota: password: "" wifi: - # ssid: "Cochrun" - # password: "GreasyChicken784" + ssid: "Cochrun" + password: "GreasyChicken784" + power_save_mode: none + reboot_timeout: 10s + # output_power: 20.5dB + # enable_btm: true + # enable_rrm: true + manual_ip: + static_ip: 192.168.1.123 + gateway: 192.168.1.1 + subnet: 255.255.255.0 - ssid: "TFC" - password: "Disciple77" + # ssid: "TFC" + # password: "Disciple77" # Enable fallback hotspot (captive portal) in case wifi connection fails ap: @@ -66,39 +88,67 @@ wifi: password: "RUfAhbEfZmOU" captive_portal: - + +# external_components: +# # replace 1234 with the number of the Pull Request +# - source: github://pr#5198 +# components: +# # list all components modified by this Pull Request here +# - aht10 i2c: - id: bus_a sda: GPIO08 scl: GPIO09 scan: True - # - id: bus_b - # sda: - # pin: - # ch422g: - # number: 6 - # scl: - # pin: - # ch422g: - # number: 5 - # scan: True + frequency: 400kHz # uart: # tx_pin: GPIO27 # rx_pin: GPIO26 # baud_rate: 115200 +time: + - platform: homeassistant + id: hass_time + on_time: + - seconds: /5 # Update every second + then: + - lvgl.label.update: + id: time_label + text: !lambda |- + auto time = id(hass_time).now(); + return time.strftime("%a %m/%d/%y %I:%M"); + # - script.execute: update_date_time_label sensor: - - platform: aht10 - variant: AHT20 + # - platform: aht10 + # variant: AHT20 + # temperature: + # name: "Temperature" + # id: temperature + # humidity: + # name: "Humidity" + # id: humidity + # address: 0x66 + - platform: bme280_i2c temperature: name: "Temperature" id: temperature + filters: + - offset: 1.0 + on_value: + then: + - lvgl.label.update: + id: temp_label + text: !lambda |- + auto temp = x * (9.0/5.0) + 32.0; + return str_truncate(to_string(temp), 4); humidity: name: "Humidity" id: humidity - # address: 0x76 - + pressure: + name: "Pressure" + id: pressure + address: 0x76 # dfrobot_sen0395: # binary_sensor: @@ -128,45 +178,38 @@ sensor: # mode: INPUT_PULLDOWN switch: -# # Switch to turn on/off detection -# - platform: dfrobot_sen0395 -# type: sensor_active -# name: Mmwave Active - -# - platform: dfrobot_sen0395 -# type: presence_via_uart -# name: Mmwave UART active -# restore_mode: always_on - -# - platform: dfrobot_sen0395 -# type: turn_on_led -# name: Mmwave Led -# restore_mode: always_on -# icon: "mdi:led-on" - -# - platform: dfrobot_sen0395 -# type: start_after_boot -# name: Mmwave Start -# restore_mode: always_on -# on_turn_on: -# then: -# - number.set: -# id: sensitivity -# value: !lambda |- -# return id(mmwave_uart).state + 1; - - platform: gpio - pin: 16 + pin: + ch422g: + number: 5 + mode: + output: true + input: false + inverted: true id: heater - restore_mode: RESTORE_DEFAULT_OFF + restore_mode: ALWAYS_OFF - platform: gpio - pin: 44 + pin: + ch422g: + number: 8 + mode: + output: true + input: false + open_drain: false + inverted: true id: ac - restore_mode: RESTORE_DEFAULT_OFF + restore_mode: ALWAYS_OFF - platform: gpio - pin: 15 + pin: + ch422g: + number: 9 + mode: + output: true + input: false + open_drain: false + inverted: true id: fan - restore_mode: RESTORE_DEFAULT_OFF + restore_mode: ALWAYS_OFF # button: # - platform: template @@ -197,6 +240,7 @@ switch: climate: - platform: thermostat + id: climape name: "Thermostat" sensor: temperature humidity_sensor: humidity @@ -204,6 +248,8 @@ climate: min_cooling_run_time: 10s min_heating_off_time: 10s min_heating_run_time: 10s + min_fanning_off_time: 10s + min_fanning_run_time: 10s min_idle_time: 30s cool_action: - switch.turn_off: heater @@ -217,11 +263,135 @@ climate: - switch.turn_off: ac - switch.turn_off: heater - switch.turn_off: fan + fan_only_action: + - lambda: !lambda ESP_LOGD("fan", "DA FAN"); default_preset: Home preset: - name: Home default_target_temperature_low: 67 °F - default_target_temperature_high: 76 °F + default_target_temperature_high: 78 °F + on_state: + then: + - if: + condition: + lambda: "return x.mode != CLIMATE_MODE_OFF;" + then: + - lvgl.label.update: + id: action_label + text: + format: "%s" + args: [ 'climate_action_to_string(x.action)' ] + else: + - lvgl.label.update: + id: set_temp_label + text: "CLIMATE_OFF" + - if: + condition: + lambda: "return x.mode == CLIMATE_MODE_COOL;" + then: + - lvgl.widget.update: + id: cool_button + state: + checked: true + - lvgl.widget.update: + id: heat_button + state: + checked: false + - lvgl.widget.update: + id: fan_button + state: + checked: false + - lvgl.widget.update: + id: off_button + state: + checked: false + # - lvgl.arc.update: + # id: current_temp_arc + # value: !lambda |- + # return x.target_temperature_high * (9.0/5.0) + 32.0; + - lvgl.label.update: + id: set_temp_label + text: + format: "%.1f°" + args: [ 'x.target_temperature_high * (9.0/5.0) + 32.0' ] + - if: + condition: + lambda: "return x.mode == CLIMATE_MODE_HEAT;" + then: + - lvgl.widget.update: + id: cool_button + state: + checked: false + - lvgl.widget.update: + id: heat_button + state: + checked: true + - lvgl.widget.update: + id: fan_button + state: + checked: false + - lvgl.widget.update: + id: off_button + state: + checked: false + # - lvgl.arc.update: + # id: current_temp_arc + # value: !lambda |- + # return x.target_temperature_low * (9.0/5.0) + 32.0; + - lvgl.label.update: + id: set_temp_label + text: + format: "%.1f°" + args: [ 'x.target_temperature_low * (9.0/5.0) + 32.0' ] + - if: + condition: + lambda: "return x.mode == CLIMATE_MODE_FAN_ONLY;" + then: + - lvgl.widget.update: + id: cool_button + state: + checked: false + - lvgl.widget.update: + id: heat_button + state: + checked: false + - lvgl.widget.update: + id: fan_button + state: + checked: true + - lvgl.widget.update: + id: off_button + state: + checked: false + # - lvgl.arc.update: + # id: current_temp_arc + # value: !lambda |- + # return x.target_temperature_high * (9.0/5.0) + 32.0; + - lvgl.label.update: + id: set_temp_label + text: + format: "%.1f°" + args: [ 'x.target_temperature_high * (9.0/5.0) + 32.0' ] + - if: + condition: + lambda: "return x.mode == CLIMATE_MODE_OFF;" + then: + - lvgl.widget.update: + id: cool_button + state: + checked: false + - lvgl.widget.update: + id: heat_button + state: + checked: false + - lvgl.widget.update: + id: fan_button + state: + checked: false + - lvgl.widget.update: + id: off_button + state: + checked: true # Example minimal configuration entry display: @@ -230,10 +400,16 @@ display: auto_clear_enabled: false update_interval: never color_order: RGB - pclk_frequency: 14MHz + pclk_frequency: 16MHz dimensions: width: 800 height: 480 + reset_pin: + ch422g: + number: 3 + enable_pin: + ch422g: + number: 2 de_pin: number: 5 hsync_pin: @@ -243,38 +419,98 @@ display: number: 3 ignore_strapping_warning: true pclk_pin: 7 - pclk_inverted: false - hsync_back_porch: 10 #30 - hsync_front_porch: 20 #210 - hsync_pulse_width: 10 #30 - vsync_back_porch: 10 #4 - vsync_front_porch: 10 #4 - vsync_pulse_width: 10 #4 + hsync_back_porch: 30 + hsync_front_porch: 210 + hsync_pulse_width: 30 + vsync_back_porch: 4 + vsync_front_porch: 4 + vsync_pulse_width: 4 data_pins: - red: - - 1 #r3 - - 2 #r4 - - 42 #r5 - - 41 #r6 - - 40 #r7 - blue: - - 14 #b3 - - 38 #b4 - - 18 #b5 - - 17 #b6 - - 10 #b7 - green: - - 39 #g2 - - 0 #g3 - - 45 #g4 - - 48 #g5 - - 47 #g6 - - 21 #g7 + red: [1, 2, 42, 41, 40] + blue: [14, 38, 18, 17, 10] + green: [39, 0, 45, 48, 47, 21] font: - - file: "gfonts://Roboto" - id: chu_nano + - file: + type: gfonts + family: Quicksand + weight: 500 + id: h2 + size: 40 + - file: + type: gfonts + family: Quicksand + weight: 400 + id: h3 + size: 20 + - file: + type: gfonts + family: Quicksand + weight: 400 + id: body size: 18 + - file: + type: gfonts + family: Quicksand + weight: 700 + id: h1 + size: 120 + - file: "fonts/vm.ttf" + id: md_icons + size: 30 + glyphs: [ + "󰖩", # nf:wifi + ] + - file: "fonts/vm.ttf" + id: sm_icons + size: 20 + glyphs: [ + "󰖩", # nf:wifi + ] + - file: "fonts/materialdesignicons-webfont.ttf" + id: icons + size: 30 + glyphs: [ + "\U000F050F", # mdi:thermometer + "\U000F058E", # mdi:water-percent + "\U000F0425", # mdi:power + "\U000F0238", # mdi:fire + "\U000F1A45", # mdi:heat-wave + "\U000F0717", # mdi:snowflake + "\U000F1A79", # mdi:sun-snowflake-variant + "\U000F0210", # mdi:fan + "\U000F171D", # mdi:fan-auto + "\U000F1472", # mdi:fan-speed-1 + "\U000F1473", # mdi:fan-speed-2 + "\U000F1474", # mdi:fan-speed-3 + "\U000F032A", # mdi:leaf + "\U000F04B9", # mdi:sofa + "\U000F14DE", # mdi:rocket-launch + "\U000F0D80", # mdi:home-floor-1 + "\U000F0D81", # mdi:home-floor-2 + "\U000F004D", # mdi:arrow-left + "\U000F09DF", # mdi:circle-small + "\U000F0E03", # mdi:thermometer-chevron-up + "\U000F0E02", # mdi:thermometer-chevron-down + "\U000F0594", # mdi:weather-night (clear) + "\U000F0590", # mdi:weather-cloudy (cloudy) + "\U000F0898", # mdi:weather-hurricane (cyclone, tropical_cyclone) + "\U000F0F30", # mdi:weather-hazy (dust, dusty, haze, hazy) + "\U000F0591", # mdi:weather-fog (fog) + "\U000F12CB", # mdi:snowflake-melt (frost) + "\U000F0596", # mdi:weather-pouring (heavy_shower, heavy_showers, rain) + "\U000F0F33", # mdi:weather-partly-rainy (light_rain) + # mdi:weather-light-showers (light_shower, light_showers) + "\U000F0599", # mdi:weather-sunny (mostly_sunny, sunny) + "\U000F0595", # mdi:weather-partly-cloudy (partly_cloudy) + "\U000F0597", # mdi:weather-rainy (shower, showers) + "\U000F0598", # mdi:weather-snowy (snow) + "\U000F0593", # mdi:weather-lightning + "\U000F067E", # mdi:weather-lightning-rainy (storm, storms) + "\U000F059D", # mdi:weather-windy (wind, windy) + "\U000F0592", # mdi:weather-hail + ] + touchscreen: - platform: gt911 @@ -297,69 +533,445 @@ color: hex: 282A36 lvgl: - buffer_size: 25% - default_font: chu_nano + # buffer_size: 25% + default_font: h2 + theme: + slider: + bg_color: 0x57c7ff + knob: + bg_color: 0x57c7ff pages: - - id: page + - id: main_page bg_color: 0x282A36 + layout: + type: flex + pad_row: 4 + pad_column: 4 + flex_align_main: CENTER + flex_align_cross: CENTER + flex_align_track: CENTER widgets: - obj: align: top_mid - width: 800 + bg_color: 0x282A36 + height: 480 + flex_grow: 1 + border_width: 0 widgets: - - slider: # Clock container - pad_top: 30px - align: top_mid - width: 600 - id: heat_id - value: 76 - min_value: 50 - max_value: 100 - label: - pad_top: 40px - align: center - text: "Hello World" - text_color: 0xE2E4E5 - - slider: # Clock container - pad_top: 60px - align: top_mid - width: 600 - id: cool_id - value: 68 - min_value: 50 - max_value: 100 + id: time_label + text: "" + text_color: ${color_darker_white} + text_font: h3 + align: top_left + x: 10 + y: 10 - label: - pad_top: 70px + id: wifi_label + text: "󰖩" + text_color: ${color_darker_white} + align: top_right + text_font: sm_icons + y: 10 + x: -10 + - button: + id: beat_button + height: 60 + width: 60 + x: 30 + y: 50 + bg_color: 0x34353e + border_width: 2 + border_color: 0xE2E4E5 + radius: 20 + checkable: true + checked: + bg_color: 0xff5c57 + on_click: + then: + - switch.toggle: heater + widgets: + - label: + text: "\U000F0238" + align: center + text_font: icons + text_color: 0xE2E4E5 + - button: + id: k_button + height: 60 + width: 60 + x: 40 + y: 120 + bg_color: 0x34353e + border_width: 2 + border_color: 0xE2E4E5 + radius: 20 + checkable: true + checked: + bg_color: 0x9aedfe + on_click: + then: + - switch.toggle: ac + widgets: + - label: + text: "\U000F0717" + align: center + text_font: icons + text_color: 0xE2E4E5 + - button: + id: f_button + height: 60 + width: 60 + x: 40 + y: 200 + bg_color: 0x34353e + border_width: 2 + border_color: 0xE2E4E5 + radius: 20 + checkable: true + checked: + bg_color: 0x9aedfe + on_click: + then: + - switch.toggle: fan + widgets: + - label: + text: "\U000F0717" + align: center + text_font: icons + text_color: 0xE2E4E5 + - obj: + bg_color: 0x282A36 + height: 480 + flex_grow: 2 + border_width: 0 + widgets: + - obj: + align: BOTTOM_MID + width: 100% + bg_color: 0x282A36 + border_width: 0 + layout: + type: flex + pad_row: 4 + pad_column: 4 + flex_align_main: CENTER + flex_align_cross: END + flex_align_track: END + widgets: + - button: + id: heat_button + height: 60 + width: 60 + bg_color: 0x34353e + border_width: 2 + border_color: 0xE2E4E5 + radius: 20 + checkable: true + checked: + bg_color: 0xff5c57 + on_click: + then: + - lvgl.widget.update: + id: off_button + state: + checked: false + - lvgl.widget.update: + id: fan_button + state: + checked: false + - lvgl.widget.update: + id: cool_button + state: + checked: false + - climate.control: + id: climape + mode: HEAT + widgets: + - label: + text: "\U000F0238" + align: center + text_font: icons + text_color: 0xE2E4E5 + - button: + id: cool_button + height: 60 + width: 60 + bg_color: 0x34353e + border_width: 2 + border_color: 0xE2E4E5 + radius: 20 + checkable: true + checked: + bg_color: 0x9aedfe + on_click: + then: + - lvgl.widget.update: + id: off_button + state: + checked: false + - lvgl.widget.update: + id: fan_button + state: + checked: false + - lvgl.widget.update: + id: heat_button + state: + checked: false + - climate.control: + id: climape + mode: COOL + widgets: + - label: + text: "\U000F0717" + align: center + text_font: icons + text_color: 0xE2E4E5 + - button: + id: fan_button + height: 60 + width: 60 + bg_color: 0x34353e + border_width: 2 + border_color: 0xE2E4E5 + radius: 20 + checkable: true + checked: + bg_color: 0x5AF78E + on_click: + then: + - lvgl.widget.update: + id: off_button + state: + checked: false + - lvgl.widget.update: + id: cool_button + state: + checked: false + - lvgl.widget.update: + id: heat_button + state: + checked: false + - climate.control: + id: climape + mode: FAN_ONLY + widgets: + - label: + text: "\U000F0210" + align: center + text_font: icons + text_color: 0xE2E4E5 + - button: + id: off_button + height: 60 + width: 60 + bg_color: 0x34353E + border_width: 2 + border_color: 0xE2E4E5 + radius: 20 + checkable: true + checked: + bg_color: 0xFF5C57 + on_click: + then: + - lvgl.widget.update: + id: fan_button + state: + checked: false + - lvgl.widget.update: + id: cool_button + state: + checked: false + - lvgl.widget.update: + id: heat_button + state: + checked: false + - climate.control: + id: climape + mode: 'OFF' + widgets: + - label: + text: "\U000F09DF" + text_font: icons + align: center + text_color: 0xE2E4E5 + + # Arc Outer Ring only for visual effect + - arc: + id: arc_ring_outer + height: 370 + width: 370 + y: -20 + align: CENTER + arc_color: ${color_light_blue} + arc_opa: COVER + arc_width: 5 + knob: + bg_color: ${color_white} + # Meter ticks and needle + - meter: + id: meter_ticks + hidden: false + height: 360 + width: 360 + y: -20 + align: CENTER + bg_opa: TRANSP + border_width: 0 + scales: + range_from: 160 # 16°C + range_to: 340 # 34°C + # Set temperature ticks background + ticks: + count: 60 + length: 18 + width: 2 + color: ${color_white} + indicators: + # Curremt temperature needle + - line: + id: current_temp_needle + color: ${color_green} + width: 3 + r_mod: 10 + value: 340 # 34°C Should be the same as the current temperature label + # Set temperature ticks + - tick_style: + id: hvac_temp_ticks + start_value: 160 + end_value: 240 # 24°C Should be the same as the set temperature label + color_start: ${color_red} + color_end: ${color_red} + width: 2 + # Meter inner Ring only for visual effect + - obj: + id: meter_ring_inner + height: 300 + width: 300 + y: -20 + radius: 150 + align: CENTER + border_width: 12 + border_color: ${color_bg} + bg_color: ${color_bg_alt} + # Set temperature knob, should change with the set temperature ticks + - arc: + id: hvac_temp_knob + hidden: false + align: CENTER + arc_opa: TRANSP + adjustable: true + value: 240 # 24°C (24x10) Should be the same as the set temperature needle + min_value: 160 + max_value: 340 + width: 335 + height: 335 + y: -20 + arc_width: 16 + change_rate: 30 + indicator: + arc_opa: TRANSP + arc_width: 16 + knob: + bg_color: ${color_dark_blue} + border_width: 4 + border_color: ${color_white} + on_change: + then: + - if: + condition: + lambda: "return id(climape).mode == CLIMATE_MODE_COOL;" + then: + - climate.control: + id: climape + target_temperature_high: !lambda |- + return (x - 32.0) / (9.0 / 5.0); + - if: + condition: + lambda: "return id(climape).mode == CLIMATE_MODE_FAN_ONLY;" + then: + - climate.control: + id: climape + target_temperature_high: !lambda |- + return (x - 32.0) / (9.0 / 5.0); + - if: + condition: + lambda: "return id(climape).mode == CLIMATE_MODE_HEAT;" + then: + - climate.control: + id: climape + target_temperature_low: !lambda |- + return (x - 32.0) / (9.0 / 5.0); + + + + + + + # - arc: + # id: current_temp_arc + # adjustable: true + # min_value: 40 # 12°C (* 10 because decimals not supported) + # max_value: 95 # 34°C + # height: 360 + # width: 360 + # align: CENTER + # arc_width: 20 + # indicator: + # arc_width: 20 + # knob: + # width: 30 + # value: !lambda |- + # auto mode = id(climape).mode; + # if (mode == CLIMATE_MODE_COOL) + # return id(climape).target_temperature_high * (9.0 / 5.0) + 32; + # on_change: + # then: + # - if: + # condition: + # lambda: "return id(climape).mode == CLIMATE_MODE_COOL;" + # then: + # - climate.control: + # id: climape + # target_temperature_high: !lambda |- + # return (x - 32.0) / (9.0 / 5.0); + # - if: + # condition: + # lambda: "return id(climape).mode == CLIMATE_MODE_FAN_ONLY;" + # then: + # - climate.control: + # id: climape + # target_temperature_high: !lambda |- + # return (x - 32.0) / (9.0 / 5.0); + # - if: + # condition: + # lambda: "return id(climape).mode == CLIMATE_MODE_HEAT;" + # then: + # - climate.control: + # id: climape + # target_temperature_low: !lambda |- + # return (x - 32.0) / (9.0 / 5.0); + + - label: + id: set_temp_label + text_font: h2 + text: "Loading..." align: center - text: "Hello World" + y: -90 + text_color: 0xA5A5A9 + - label: + id: action_label + text_font: h3 + text: "Loading..." + align: center + # x: 145 + y: 70 + text_color: 0xA5A5A9 + - label: + id: temp_label + text_font: h1 + text: "Loading..." + align: center + y: -10 text_color: 0xE2E4E5 - - label: - align: center - text: "Hello World" - text_color: 0xE2E4E5 -# time: -# - platform: homeassistant -# id: time_comp - -# interval: -# - interval: 30s -# then: -# if: -# condition: -# time.has_time: -# then: -# - script.execute: time_update - -# script: -# - id: time_update -# then: -# - lvgl.indicator.update: -# id: minute_hand -# value: !lambda |- -# return id(time_comp).now().minute; -# - lvgl.indicator.update: -# id: hour_hand -# value: !lambda |- -# auto now = id(time_comp).now(); -# return std::fmod(now.hour, 12) * 60 + now.minute;