Files
hassos_config/esphome/widgets/home/home_widget.yaml
2026-03-26 12:10:21 +01:00

769 lines
23 KiB
YAML

substitutions:
weather_entity: "weather.forecast_home"
temperature_entity: "sensor.outside_temperature"
humidity_entity: "sensor.outside_humidity"
co2_entity: "sensor.carbon_dioxide"
lock_icon: "\U0000e92e"
air_conditioner_icon: "\U0000e93b"
heating_icon: "\U0000e936"
info_icon: "\U0000e904"
ha_icon: "\U0000e935" # home assistant
wifi_25_icon: "\U0000e931" # wifi signal from 25% to 1%
wifi_50_icon: "\U0000e932" # wifi signal from 50% to 25%
wifi_75_icon: "\U0000e933" # wifi signal from 75% to 50%
wifi_100_icon: "\U0000e934" # wifi signal from 100% to 75% or disable
humidity_icon: "\U0000e938"
co2_icon: "\U0000e937"
tvoc: "\U0000e93a" # air quality
temperature_icon: "\U0000e939"
illumination: "\U0000e92f" # lux
lightbulb_icon: "\U0000e908"
globals:
- id: display_lock
type: bool
restore_value: true
initial_value: "false"
sensor:
# WI-FI Signal
- platform: wifi_signal
id: wifi_signal_percent
update_interval: 30s
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "%"
on_value:
then:
- lvgl.label.update:
id: wifi_status
text_color: !lambda |-
if (id(wifi_signal_percent).state > 0) {
return lv_color_hex(0x5CA848);
}
return lv_color_hex(0x5CA848);
text: !lambda |-
if (id(wifi_signal_percent).state > 0 && id(wifi_signal_percent).state < 26) {
return "${wifi_25_icon}";
} else if (id(wifi_signal_percent).state > 25 && id(wifi_signal_percent).state < 51) {
return "${wifi_50_icon}";
} else if (id(wifi_signal_percent).state > 50 && id(wifi_signal_percent).state < 76) {
return "${wifi_75_icon}";
} else if (id(wifi_signal_percent).state > 75) {
return "${wifi_100_icon}";
}
return "${wifi_100_icon}";
# Weather temperature sensor
- platform: homeassistant
id: weather_temp
entity_id: "${weather_entity}"
attribute: temperature
on_value:
then:
- lvgl.label.update:
id: weather_temperature
text:
format: "%.0f°"
args: [id(weather_temp).state]
# Temperature Home Sensor
- platform: homeassistant
id: temperature_sensor
entity_id: "${temperature_entity}"
on_value:
then:
- lvgl.label.update:
id: temperature_sensor_label
text:
format: "%.1f °C"
args: [id(temperature_sensor).state]
# Humidity Home Sensor
- platform: homeassistant
id: humidity_sensor
entity_id: "${humidity_entity}"
on_value:
then:
- lvgl.label.update:
id: humidity_sensor_label
text:
format: "%.1f %%"
args: [id(humidity_sensor).state]
# CO2 Home Sensor
- platform: homeassistant
id: co2_sensor
entity_id: "${co2_entity}"
on_value:
then:
- lvgl.label.update:
id: co2_sensor_label
text:
format: "%.0f PPM"
args: [id(co2_sensor).state]
text_sensor:
# Sun horizon sensor
- platform: homeassistant
id: sun_state_sensor
entity_id: sun.sun
# Weather state sensor
- platform: homeassistant
id: weather_state_sensor
entity_id: "${weather_entity}"
on_value:
then:
- delay: 1s
- script.execute:
id: weather_get_and_set_translated_state
state_str: !lambda 'return id(weather_state_sensor).state;'
- script.execute: update_weather_image
lvgl:
pages:
- id: home_page
bg_color: color_slate_blue_gray
widgets:
# indicators
- obj:
id: home_bg_indicators
y: 20
width: 440
height: 40
align: TOP_MID
pad_all: 0
bg_color: color_steel_blue
bg_opa: 20%
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
radius: 10
widgets:
# date
- label:
id: display_date
x: 20
align: LEFT_MID
text_font: nunito_16
text_color: color_misty_blue
text: "31.01"
# Wi-Fi status
- label:
id: wifi_status
align: RIGHT_MID
x: -20
text: "${wifi_100_icon}"
text_color: color_steel_blue
text_font: icons_24
# Home Assistant status
- label:
id: ha_status
align: RIGHT_MID
x: -60
text: "${ha_icon}"
text_color: color_steel_blue
text_font: icons_24
# Heating status
- label:
id: heating_status
align: RIGHT_MID
x: -100
text: "${heating_icon}"
text_color: color_steel_blue
text_font: icons_24
# AC status
- label:
id: ac_status
align: RIGHT_MID
x: -140
y: 2
text: "${air_conditioner_icon}"
text_color: color_steel_blue
text_font: icons_24
# Lock status
- label:
id: lock_status
align: RIGHT_MID
x: -180
text: "${lock_icon}"
text_color: color_steel_blue
text_font: icons_24
# Alarm panel status
# - label:
# id: alarm_panel_status
# align: RIGHT_MID
# x: -220
# text: "${shield_arming_icon}"
# text_color: color_steel_blue
# text_font: mdi_icons_24
# time
- obj:
id: home_bg_weather_time
x: 20
y: 80
width: 440
height: 220
align: TOP_LEFT
pad_all: 0
bg_color: color_steel_blue
bg_opa: 20%
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
radius: 10
widgets:
- label:
id: display_time
align: CENTER
text_font: nunito_84 #nunito_64
text_color: color_misty_blue
text: "23:59"
# weather
- obj:
id: home_bg_weather
x: 20
y: 340
width: 440
height: 300
align: TOP_LEFT
pad_all: 0
bg_color: color_steel_blue
bg_opa: 20%
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
radius: 10
widgets:
- image:
id: weather_sunny_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: sunny_img
- image:
id: weather_clear_night_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: clear_night_img
- image:
id: weather_cloudy_image
hidden: true
y: 20
x: 10
align: TOP_LEFT
src: cloudy_img
- image:
id: weather_partlycloudy_sun_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: partlycloudy_sun_img
- image:
id: weather_partlycloudy_moon_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: partlycloudy_moon_img
- image:
id: weather_rainy_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: rainy_img
- image:
id: weather_pouring_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: pouring_img
- image:
id: weather_snowy_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: snowy_img
- image:
id: weather_snowy_rainy_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: snowy_rainy_img
- image:
id: weather_fog_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: fog_img
- image:
id: weather_hail_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: hail_img
- image:
id: weather_lightning_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: lightning_img
- image:
id: weather_lightning_rainy_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: lightning_rainy_img
- image:
id: weather_windy_image
hidden: true
y: 10
x: 25
align: TOP_LEFT
src: windy_img
- image:
id: weather_windy_variant_image
hidden: true
y: 10
x: 10
align: TOP_LEFT
src: windy_variant_img
- label:
x: -10
y: 10
align: TOP_RIGHT
id: weather_temperature
text_font: nunito_48
text_color: color_misty_blue
text: "-25°"
- label:
id: weather_state_label
y: -10
width: 180
height: 30
align: BOTTOM_MID
text_font: nunito_16
text_color: color_misty_blue
long_mode: SCROLL_CIRCULAR
text: " "
# sensors
- obj:
id: home_bg_sensors
x: -20
y: 80
width: 200
height: 200
align: TOP_RIGHT
pad_all: 0
bg_color: color_steel_blue
bg_opa: 20%
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
radius: 10
widgets:
# temperature
- obj:
y: 20
width: 160
height: 40
align: TOP_MID
pad_all: 0
bg_opa: TRANSP
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
widgets:
- label:
id: temperature_sensor_icon
align: LEFT_MID
x: 20
text: "${temperature_icon}"
text_color: color_green
text_font: icons_28
- label:
id: temperature_sensor_label
align: LEFT_MID
x: 55
text: " "
text_color: color_misty_blue
text_font: nunito_16
# humidity
- obj:
y: 80
width: 160
height: 40
align: TOP_MID
pad_all: 0
bg_opa: TRANSP
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
widgets:
- label:
id: humidity_sensor_icon
align: LEFT_MID
x: 20
text: "${humidity_icon}"
text_color: color_blue
text_font: icons_28
- label:
id: humidity_sensor_label
align: LEFT_MID
x: 55
text: " "
text_color: color_misty_blue
text_font: nunito_16
# co2
- obj:
y: 140
width: 160
height: 40
align: TOP_MID
pad_all: 0
bg_opa: TRANSP
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
widgets:
- label:
id: co2_sensor_icon
align: LEFT_MID
x: 20
text: "${co2_icon}"
text_color: color_yellow
text_font: icons_28
- label:
id: co2_sensor_label
align: LEFT_MID
x: 55
text: " "
text_color: color_misty_blue
text_font: nunito_16
# display lock
- obj:
id: home_bg_display_lock
x: 480
y: 580
width: 60
height: 60
align: TOP_LEFT
pad_all: 0
bg_color: color_steel_blue
bg_opa: 20%
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
radius: 10
widgets:
- label:
id: display_lock_btn
align: CENTER
text_font: icons_36
text_color: color_misty_blue
text: "${lock_icon}"
on_long_press:
then:
- if:
condition:
lambda: 'return id(display_lock) == false;'
then:
- switch.turn_on: display_lock_switch
else:
- switch.turn_off: display_lock_switch
# display backlight off
- obj:
id: home_bg_display_backlight_off
x: 550
y: 580
width: 60
height: 60
align: TOP_LEFT
pad_all: 0
bg_color: color_steel_blue
bg_opa: 20%
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
radius: 10
widgets:
- label:
id: display_backlight_off_btn
align: CENTER
text_font: icons_36
text_color: color_misty_blue
text: "${lightbulb_icon}"
on_click:
- delay: 1s
- light.turn_off: display_backlight
- lvgl.pause:
# display info
- obj:
id: home_bg_display_info
x: 620
y: 580
width: 60
height: 60
align: TOP_LEFT
pad_all: 0
bg_color: color_steel_blue
bg_opa: 20%
border_opa: TRANSP
border_width: 0
shadow_opa: TRANSP
radius: 10
widgets:
- label:
id: display_info_btn
align: CENTER
text_font: icons_36
text_color: color_misty_blue
text: "${info_icon}"
on_press:
- lvgl.page.show:
id: system_info_page
animation: OUT_RIGHT
time: 300ms
time:
- platform: sntp
id: sntp_time
timezone: Europe/Moscow
servers:
- ntp0.ntp-servers.net
- ntp1.ntp-servers.net
- ntp2.ntp-servers.net
on_time_sync:
- script.execute: time_update
on_time:
- minutes: '*'
seconds: 0
then:
- script.execute: time_update
script:
- id: time_update
then:
- lvgl.label.update:
id: display_time
text: !lambda |-
static char time_buf[16];
auto now = id(sntp_time).now();
snprintf(time_buf, sizeof(time_buf), "%02d:%02d", now.hour, now.minute);
return time_buf;
- lvgl.label.update:
id: display_date
text: !lambda |-
static char date_buf[16];
auto now = id(sntp_time).now();
snprintf(date_buf, sizeof(date_buf), "%02d.%02d", now.day_of_month, now.month);
return date_buf;
- id: weather_get_and_set_translated_state
parameters:
state_str: string
then:
- lambda: |-
std::string state = state_str;
auto it = id(weather_translations).find(state);
std::string translated_state = (it != id(weather_translations).end()) ? it->second : state;
lv_label_set_text(id(weather_state_label), translated_state.c_str());
- id: update_weather_image
then:
- lambda: |-
std::string weather = id(weather_state_sensor).state;
bool is_night = (id(sun_state_sensor).state == "below_horizon");
if (weather == "cloudy") {
lv_obj_clear_flag(id(weather_cloudy_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "partlycloudy") {
if (is_night) {
lv_obj_clear_flag(id(weather_partlycloudy_moon_image), LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_clear_flag(id(weather_partlycloudy_sun_image), LV_OBJ_FLAG_HIDDEN);
}
} else if (weather == "sunny" || weather == "clear-night") {
if (is_night) {
lv_obj_clear_flag(id(weather_clear_night_image), LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_clear_flag(id(weather_sunny_image), LV_OBJ_FLAG_HIDDEN);
}
} else if (weather == "rainy") {
lv_obj_clear_flag(id(weather_rainy_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "lightning-rainy") {
lv_obj_clear_flag(id(weather_lightning_rainy_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "lightning") {
lv_obj_clear_flag(id(weather_lightning_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "pouring") {
lv_obj_clear_flag(id(weather_pouring_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "snowy") {
lv_obj_clear_flag(id(weather_snowy_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "snowy-rainy") {
lv_obj_clear_flag(id(weather_snowy_rainy_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "fog") {
lv_obj_clear_flag(id(weather_fog_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "hail") {
lv_obj_clear_flag(id(weather_hail_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "windy") {
lv_obj_clear_flag(id(weather_windy_image), LV_OBJ_FLAG_HIDDEN);
} else if (weather == "windy-variant") {
lv_obj_clear_flag(id(weather_windy_variant_image), LV_OBJ_FLAG_HIDDEN);
}
select:
- platform: lvgl
widget: language_dropdown
id: weather_select_language
on_value:
then:
- lambda: |-
ESP_LOGI("LANGUAGE", "Language changed, updating weather translations");
- delay: 300ms
- script.execute:
id: weather_get_and_set_translated_state
state_str: !lambda 'return id(weather_state_sensor).state;'
- lambda: |-
ESP_LOGI("LANGUAGE", "Weather translations updated");
esphome:
on_boot:
priority: -100
then:
- if:
condition:
lambda: 'return id(weather_state_sensor).has_state();'
then:
- script.execute:
id: weather_get_and_set_translated_state
state_str: !lambda 'return id(weather_state_sensor).state;'
# - if:
# condition:
# lambda: 'return id(display_lock) == true;'
# then:
# - switch.turn_on: display_lock_switch
# else:
# - switch.turn_off: display_lock_switch
api:
on_client_connected:
- if:
condition:
lambda: 'return (0 == client_info.find("Home Assistant "));'
then:
- lvgl.label.update:
id: ha_status
text_color: color_blue
- if:
condition:
lambda: 'return id(weather_state_sensor).has_state();'
then:
- script.execute:
id: weather_get_and_set_translated_state
state_str: !lambda 'return id(weather_state_sensor).state;'
# - if:
# condition:
# lambda: 'return id(display_lock) == true;'
# then:
# - switch.turn_on: display_lock_switch
# else:
# - switch.turn_off: display_lock_switch
on_client_disconnected:
- if:
condition:
lambda: 'return (0 == client_info.find("Home Assistant "));'
then:
- lvgl.label.update:
id: ha_status
text_color: color_steel_blue
switch:
- platform: template
name: "Touchscreen block"
id: display_lock_switch
lambda: |-
return id(display_lock);
turn_on_action:
- lambda: 'id(display_lock) = true;'
- lvgl.button.update:
id: home_page_btn
clickable: false
- lvgl.button.update:
id: lights_group_page_btn
clickable: false
- lvgl.button.update:
id: devices_page_btn
clickable: false
- lvgl.button.update:
id: settings_page_btn
clickable: false
- lvgl.label.update:
id: lock_status
text_color: color_green
turn_off_action:
- lambda: 'id(display_lock) = false;'
- lvgl.button.update:
id: home_page_btn
clickable: true
- lvgl.button.update:
id: lights_group_page_btn
clickable: true
- lvgl.button.update:
id: devices_page_btn
clickable: true
- lvgl.button.update:
id: settings_page_btn
clickable: true
- lvgl.label.update:
id: lock_status
text_color: color_steel_blue