20260326
This commit is contained in:
1823
esphome/widgets/air_conditioner/air_conditioner_widget.yaml
Normal file
1823
esphome/widgets/air_conditioner/air_conditioner_widget.yaml
Normal file
File diff suppressed because it is too large
Load Diff
870
esphome/widgets/alarm_panel/alarm_panel.yaml
Normal file
870
esphome/widgets/alarm_panel/alarm_panel.yaml
Normal file
@@ -0,0 +1,870 @@
|
||||
substitutions:
|
||||
|
||||
alarm_panel_entity: "alarm_control_panel.security"
|
||||
pin_code: "1234"
|
||||
|
||||
shield_home_icon: "\U000F068A" # home
|
||||
shield_away_icon: "\U000F099D" # away
|
||||
shield_night_icon: "\U000F1828" # night
|
||||
shield_vacation_icon: "\U000F06BB" # vacation
|
||||
shield_disarm_icon: "\U000F099E" # disarmed
|
||||
shield_arming_icon: "\U000F0498" # arming
|
||||
|
||||
globals:
|
||||
- id: alarm_panel_pending_action
|
||||
type: std::string
|
||||
restore_value: no
|
||||
initial_value: ""
|
||||
|
||||
|
||||
lvgl:
|
||||
pages:
|
||||
- id: alarm_panel_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- obj:
|
||||
id: alarm_panel_state_bg
|
||||
x: 20
|
||||
y: 20
|
||||
width: 440
|
||||
height: 80
|
||||
pad_all: 0
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
id: alarm_panel_state_icon_bg
|
||||
x: 20
|
||||
align: LEFT_MID
|
||||
width: 60
|
||||
height: 60
|
||||
radius: 30
|
||||
pad_all: 0
|
||||
bg_color: color_blue
|
||||
bg_opa: 60%
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
|
||||
- label:
|
||||
id: alarm_panel_state_icon
|
||||
x: 30
|
||||
align: LEFT_MID
|
||||
text_font: mdi_icons_40
|
||||
text_color: color_blue
|
||||
text: "${shield_disarm_icon}"
|
||||
|
||||
- label:
|
||||
x: 110
|
||||
id: alarm_panel_state_text
|
||||
align: LEFT_MID
|
||||
text_font: nunito_18
|
||||
text_color: color_misty_blue
|
||||
text: " "
|
||||
|
||||
- obj:
|
||||
id: alarm_panel_state_control
|
||||
hidden: false
|
||||
x: 20
|
||||
y: 120
|
||||
width: 440
|
||||
height: 260
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
id: alarm_panel_button_disarmed
|
||||
width: 200
|
||||
height: 200
|
||||
align: center
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 160
|
||||
height: 160
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 80
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 25
|
||||
shadow_spread: 4
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 7
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(alarm_panel_pending_action) = std::string("disarm");
|
||||
- lvgl.widget.show: alarm_panel_keypad_page
|
||||
- lvgl.widget.hide: alarm_panel_state_bg
|
||||
- lvgl.widget.hide: alarm_panel_state_control
|
||||
- obj:
|
||||
width: 152
|
||||
height: 152
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 80
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 8
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -6
|
||||
shadow_ofs_y: -3
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 152
|
||||
height: 152
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 80
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 8
|
||||
shadow_color: 0x000000
|
||||
shadow_ofs_x: 6
|
||||
shadow_ofs_y: 3
|
||||
|
||||
- obj:
|
||||
width: 156
|
||||
height: 156
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 80
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
id: alarm_panel_state_btn_disarmed
|
||||
align: center
|
||||
text_font: mdi_icons_68
|
||||
text_color: color_steel_blue
|
||||
text: "${shield_disarm_icon}"
|
||||
|
||||
|
||||
- obj:
|
||||
id: alarm_panel_button_home
|
||||
hidden: true
|
||||
width: 110
|
||||
height: 110
|
||||
x: -60
|
||||
y: -60
|
||||
align: center
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 90
|
||||
height: 90
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 15
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(alarm_panel_pending_action) = std::string("arm_home");
|
||||
- lvgl.widget.show: alarm_panel_keypad_page
|
||||
- lvgl.widget.hide: alarm_panel_state_bg
|
||||
- lvgl.widget.hide: alarm_panel_state_control
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0x000000
|
||||
shadow_ofs_x: 4
|
||||
shadow_ofs_y: 2
|
||||
|
||||
- obj:
|
||||
width: 85
|
||||
height: 85
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
id: alarm_panel_state_btn_home
|
||||
align: center
|
||||
text_font: mdi_icons_52
|
||||
text_color: color_steel_blue
|
||||
text: "${shield_home_icon}"
|
||||
|
||||
|
||||
|
||||
- obj:
|
||||
id: alarm_panel_button_away
|
||||
hidden: true
|
||||
width: 110
|
||||
height: 110
|
||||
x: 60
|
||||
y: -60
|
||||
align: center
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 90
|
||||
height: 90
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 15
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(alarm_panel_pending_action) = std::string("arm_away");
|
||||
- lvgl.widget.show: alarm_panel_keypad_page
|
||||
- lvgl.widget.hide: alarm_panel_state_bg
|
||||
- lvgl.widget.hide: alarm_panel_state_control
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0x000000
|
||||
shadow_ofs_x: 4
|
||||
shadow_ofs_y: 2
|
||||
|
||||
- obj:
|
||||
width: 85
|
||||
height: 85
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
id: alarm_panel_state_btn_away
|
||||
align: center
|
||||
text_font: mdi_icons_52
|
||||
text_color: color_steel_blue
|
||||
text: "${shield_away_icon}"
|
||||
|
||||
|
||||
- obj:
|
||||
id: alarm_panel_button_night
|
||||
hidden: true
|
||||
width: 110
|
||||
height: 110
|
||||
x: -60
|
||||
y: 60
|
||||
align: center
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 90
|
||||
height: 90
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 15
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(alarm_panel_pending_action) = std::string("arm_night");
|
||||
- lvgl.widget.show: alarm_panel_keypad_page
|
||||
- lvgl.widget.hide: alarm_panel_state_bg
|
||||
- lvgl.widget.hide: alarm_panel_state_control
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0x000000
|
||||
shadow_ofs_x: 4
|
||||
shadow_ofs_y: 2
|
||||
|
||||
- obj:
|
||||
width: 85
|
||||
height: 85
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
id: alarm_panel_state_btn_night
|
||||
align: center
|
||||
text_font: mdi_icons_52
|
||||
text_color: color_steel_blue
|
||||
text: "${shield_night_icon}"
|
||||
|
||||
|
||||
- obj:
|
||||
id: alarm_panel_button_vacation
|
||||
hidden: true
|
||||
width: 110
|
||||
height: 110
|
||||
x: 60
|
||||
y: 60
|
||||
align: center
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 90
|
||||
height: 90
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 15
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(alarm_panel_pending_action) = std::string("arm_vacation");
|
||||
- lvgl.widget.show: alarm_panel_keypad_page
|
||||
- lvgl.widget.hide: alarm_panel_state_bg
|
||||
- lvgl.widget.hide: alarm_panel_state_control
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 80
|
||||
height: 80
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0x000000
|
||||
shadow_ofs_x: 4
|
||||
shadow_ofs_y: 2
|
||||
|
||||
- obj:
|
||||
width: 85
|
||||
height: 85
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
id: alarm_panel_state_btn_vacation
|
||||
align: center
|
||||
text_font: mdi_icons_52
|
||||
text_color: color_steel_blue
|
||||
text: "${shield_vacation_icon}"
|
||||
|
||||
|
||||
- obj:
|
||||
id: alarm_panel_keypad_page
|
||||
hidden: true
|
||||
x: 20
|
||||
y: 20
|
||||
width: 440
|
||||
height: 360
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
width: 400
|
||||
height: 40
|
||||
align: top_mid
|
||||
border_width: 1
|
||||
border_color: color_steel_blue
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: alarm_panel_keypad_code_label
|
||||
align: center
|
||||
text_font: nunito_18
|
||||
text: "Enter code"
|
||||
text_color: color_misty_blue
|
||||
text_align: center
|
||||
- buttonmatrix:
|
||||
id: alarm_panel_keypad
|
||||
width: 400
|
||||
height: 270
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
x: 2
|
||||
y: 30
|
||||
align: center
|
||||
items:
|
||||
bg_opa: transp
|
||||
border_color: color_steel_blue
|
||||
border_width: 1
|
||||
shadow_opa: transp
|
||||
text_font: montserrat_20
|
||||
text_color: color_misty_blue
|
||||
pressed:
|
||||
bg_color: color_steel_blue
|
||||
rows:
|
||||
- buttons:
|
||||
- text: 1
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: 2
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: 3
|
||||
control:
|
||||
no_repeat: true
|
||||
- buttons:
|
||||
- text: 4
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: 5
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: 6
|
||||
control:
|
||||
no_repeat: true
|
||||
- buttons:
|
||||
- text: 7
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: 8
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: 9
|
||||
control:
|
||||
no_repeat: true
|
||||
- buttons:
|
||||
- text: "\uF55A"
|
||||
key_code: "*"
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: 0
|
||||
control:
|
||||
no_repeat: true
|
||||
- text: "\uF00C"
|
||||
key_code: "#"
|
||||
control:
|
||||
no_repeat: true
|
||||
|
||||
# Return
|
||||
- button:
|
||||
x: 20
|
||||
y: 400
|
||||
width: 60
|
||||
height: 60
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show: devices_page
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
|
||||
|
||||
# alarm panel entity friendly name
|
||||
- obj:
|
||||
id: alarm_panel_bg_name
|
||||
x: -20
|
||||
y: 400
|
||||
width: 360
|
||||
height: 60
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: alarm_panel_label_name
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "friendly name"
|
||||
|
||||
key_collector:
|
||||
- source_id: alarm_panel_keypad
|
||||
min_length: 4
|
||||
max_length: 4
|
||||
end_keys: "#"
|
||||
end_key_required: true
|
||||
back_keys: "*"
|
||||
allowed_keys: "0123456789*#"
|
||||
timeout: 5s
|
||||
on_progress:
|
||||
- if:
|
||||
condition:
|
||||
lambda: return (0 != x.compare(std::string{""}));
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_keypad_code_label
|
||||
text: !lambda 'return x.c_str();'
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_keypad_code_label
|
||||
text_font: nunito_18
|
||||
text_color: color_misty_blue
|
||||
text: "Enter code"
|
||||
on_result:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "${pin_code}";'
|
||||
then:
|
||||
# Если код верный, отправляем команду в Home Assistant для снятия с охраны
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(alarm_panel_pending_action) == "disarm";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: alarm_control_panel.alarm_disarm
|
||||
data:
|
||||
entity_id: "${alarm_panel_entity}"
|
||||
code: "${pin_code}"
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(alarm_panel_pending_action) == "arm_home";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: alarm_control_panel.alarm_arm_home
|
||||
data:
|
||||
entity_id: "${alarm_panel_entity}"
|
||||
code: "${pin_code}"
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(alarm_panel_pending_action) == "arm_away";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: alarm_control_panel.alarm_arm_away
|
||||
data:
|
||||
entity_id: "${alarm_panel_entity}"
|
||||
code: "${pin_code}"
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(alarm_panel_pending_action) == "arm_night";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: alarm_control_panel.alarm_arm_night
|
||||
data:
|
||||
entity_id: "${alarm_panel_entity}"
|
||||
code: "${pin_code}"
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(alarm_panel_pending_action) == "arm_vacation";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: alarm_control_panel.alarm_arm_vacation
|
||||
data:
|
||||
entity_id: "${alarm_panel_entity}"
|
||||
code: "${pin_code}"
|
||||
|
||||
- lvgl.widget.hide: alarm_panel_keypad_page
|
||||
- lvgl.widget.show: alarm_panel_state_bg
|
||||
- lvgl.widget.show: alarm_panel_state_control
|
||||
|
||||
|
||||
# Получаем статус сигнализации из Home Assistant
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
id: alarm_panel_sensor_state
|
||||
entity_id: ${alarm_panel_entity}
|
||||
on_value:
|
||||
then:
|
||||
- script.execute:
|
||||
id: alarm_panel_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(alarm_panel_sensor_state).state;'
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "disarmed";'
|
||||
then:
|
||||
- lvgl.widget.show: alarm_panel_button_home
|
||||
- lvgl.widget.show: alarm_panel_button_away
|
||||
- lvgl.widget.show: alarm_panel_button_night
|
||||
- lvgl.widget.show: alarm_panel_button_vacation
|
||||
- lvgl.widget.hide: alarm_panel_button_disarmed
|
||||
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_status
|
||||
text_color: color_steel_blue
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_state_icon
|
||||
text_color: color_blue
|
||||
text: "${shield_disarm_icon}"
|
||||
- lvgl.obj.update:
|
||||
id: alarm_panel_state_icon_bg
|
||||
bg_color: color_blue
|
||||
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_status
|
||||
text_color: color_crimson
|
||||
- lvgl.widget.hide: alarm_panel_button_home
|
||||
- lvgl.widget.hide: alarm_panel_button_away
|
||||
- lvgl.widget.hide: alarm_panel_button_night
|
||||
- lvgl.widget.hide: alarm_panel_button_vacation
|
||||
- lvgl.widget.show: alarm_panel_button_disarmed
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "arming";'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_state_icon
|
||||
text_color: color_gray
|
||||
text: "${shield_arming_icon}"
|
||||
- lvgl.obj.update:
|
||||
id: alarm_panel_state_icon_bg
|
||||
bg_color: color_gray
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "armed_home";'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_state_icon
|
||||
text_color: color_green
|
||||
text: "${shield_home_icon}"
|
||||
- lvgl.obj.update:
|
||||
id: alarm_panel_state_icon_bg
|
||||
bg_color: color_green
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "armed_away";'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_state_icon
|
||||
text_color: color_green
|
||||
text: "${shield_away_icon}"
|
||||
- lvgl.obj.update:
|
||||
id: alarm_panel_state_icon_bg
|
||||
bg_color: color_green
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "armed_night";'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_state_icon
|
||||
text_color: color_green
|
||||
text: "${shield_night_icon}"
|
||||
- lvgl.obj.update:
|
||||
id: alarm_panel_state_icon_bg
|
||||
bg_color: color_green
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "armed_vacation";'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_state_icon
|
||||
text_color: color_green
|
||||
text: "${shield_vacation_icon}"
|
||||
- lvgl.obj.update:
|
||||
id: alarm_panel_state_icon_bg
|
||||
bg_color: color_green
|
||||
|
||||
- platform: homeassistant
|
||||
id: alarm_panel_sensor_name
|
||||
entity_id: ${alarm_panel_entity}
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: alarm_panel_label_name
|
||||
text: !lambda return x;
|
||||
|
||||
|
||||
script:
|
||||
- id: alarm_panel_get_and_set_translated_state
|
||||
parameters:
|
||||
state_str: string
|
||||
then:
|
||||
- lambda: |-
|
||||
std::string state = state_str;
|
||||
|
||||
auto it = id(alarm_panel_translations).find(state);
|
||||
std::string translated_state = (it != id(alarm_panel_translations).end()) ? it->second : state;
|
||||
|
||||
lv_label_set_text(id(alarm_panel_state_text), translated_state.c_str());
|
||||
|
||||
|
||||
select:
|
||||
- platform: lvgl
|
||||
widget: language_dropdown
|
||||
id: alarm_panel_select_language
|
||||
on_value:
|
||||
then:
|
||||
- delay: 300ms
|
||||
- script.execute:
|
||||
id: alarm_panel_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(alarm_panel_sensor_state).state;'
|
||||
|
||||
esphome:
|
||||
on_boot:
|
||||
priority: -100
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(alarm_panel_sensor_state).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: alarm_panel_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(alarm_panel_sensor_state).state;'
|
||||
|
||||
api:
|
||||
on_client_connected:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(alarm_panel_sensor_state).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: alarm_panel_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(alarm_panel_sensor_state).state;'
|
||||
48
esphome/widgets/colors.yaml
Normal file
48
esphome/widgets/colors.yaml
Normal file
@@ -0,0 +1,48 @@
|
||||
- id: color_sky_blue
|
||||
hex: 3FA7F3
|
||||
- id: color_slate_blue_gray
|
||||
hex: 343645
|
||||
- id: color_steel_blue
|
||||
hex: 606682
|
||||
- id: color_misty_blue
|
||||
hex: 9BA2BC
|
||||
- id: color_black
|
||||
hex: 0d0d0d
|
||||
- id: color_dark_gray
|
||||
hex: 333333
|
||||
- id: color_gray
|
||||
hex: 666666
|
||||
- id: color_white
|
||||
hex: f2f0eb
|
||||
- id: color_red
|
||||
hex: ff0000
|
||||
- id: color_crimson
|
||||
hex: f5075c
|
||||
- id: color_light_blue
|
||||
hex: 2fc0ff
|
||||
- id: color_blue
|
||||
hex: 4C9FFF
|
||||
- id: color_yellow
|
||||
hex: e7c12c
|
||||
- id: color_light_yellow
|
||||
hex: f0d45c
|
||||
- id: color_amber
|
||||
hex: f4a900
|
||||
- id: color_mint
|
||||
hex: 39d19c
|
||||
- id: color_light_mint
|
||||
hex: 66dcb3
|
||||
- id: color_light_green
|
||||
hex: 00ff00
|
||||
- id: color_green
|
||||
hex: 5CA848
|
||||
- id: color_orange
|
||||
hex: f07c40
|
||||
- id: color_deep_orange
|
||||
hex: ff6600
|
||||
- id: color_violet
|
||||
hex: 926BC7
|
||||
- id: color_dark_blue
|
||||
hex: 4867aa
|
||||
- id: color_deep_purple
|
||||
hex: 543D72
|
||||
194
esphome/widgets/devices.yaml
Normal file
194
esphome/widgets/devices.yaml
Normal file
@@ -0,0 +1,194 @@
|
||||
substitutions:
|
||||
|
||||
music_icon: "\U0000e91b"
|
||||
#shutter_icon: "\U0000e91d"
|
||||
vacuum_icon: "\U0000e922"
|
||||
thermostat_icon: "\U0000e925"
|
||||
#air_conditioner_icon: "\U0000e93b"
|
||||
|
||||
packages:
|
||||
media_player: !include media_player/media_player.yaml
|
||||
vacuum: !include vacuum/vacuum_widget.yaml
|
||||
#shutter: !include shutter/shutter_config.yaml
|
||||
thermostat: !include thermostat/thermostat_widget.yaml
|
||||
#air_conditioner: !include air_conditioner/air_conditioner_widget.yaml
|
||||
#alarm_panel: !include alarm_panel/alarm_panel.yaml
|
||||
|
||||
|
||||
lvgl:
|
||||
pages:
|
||||
- id: devices_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- obj:
|
||||
id: devices_main
|
||||
y: 20
|
||||
width: 440
|
||||
height: 340
|
||||
pad_all: 0
|
||||
align: TOP_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
y: 10
|
||||
width: 440
|
||||
height: 150
|
||||
pad_all: 0
|
||||
align: TOP_MID
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
radius: 10
|
||||
widgets:
|
||||
|
||||
- button:
|
||||
id: media_player_page_btn
|
||||
x: 35
|
||||
align: LEFT_MID
|
||||
width: 100
|
||||
height: 100
|
||||
radius: 10
|
||||
bg_color: color_slate_blue_gray
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${music_icon}"
|
||||
on_press:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: media_player_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
# - button:
|
||||
# id: shutters_page_btn
|
||||
# x: 170
|
||||
# align: LEFT_MID
|
||||
# width: 100
|
||||
# height: 100
|
||||
# radius: 10
|
||||
# bg_color: color_slate_blue_gray
|
||||
# shadow_opa: TRANSP
|
||||
# widgets:
|
||||
# - label:
|
||||
# align: CENTER
|
||||
# text_color: color_steel_blue
|
||||
# text_font: icons_72
|
||||
# text: "${shutter_icon}"
|
||||
# on_press:
|
||||
# - lvgl.page.show:
|
||||
# id: shutter_group_page
|
||||
# animation: OUT_RIGHT
|
||||
# time: 300ms
|
||||
|
||||
- button:
|
||||
id: vacuum_page_btn
|
||||
x: 305
|
||||
align: LEFT_MID
|
||||
width: 100
|
||||
height: 100
|
||||
radius: 10
|
||||
bg_color: color_slate_blue_gray
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_72
|
||||
text: "${vacuum_icon}"
|
||||
on_press:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: vacuum_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
- obj:
|
||||
y: 120
|
||||
width: 440
|
||||
height: 150
|
||||
pad_all: 0
|
||||
align: TOP_MID
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
radius: 10
|
||||
widgets:
|
||||
|
||||
- button:
|
||||
id: thermostat_page_btn
|
||||
x: 35
|
||||
align: LEFT_MID
|
||||
width: 100
|
||||
height: 100
|
||||
radius: 10
|
||||
bg_color: color_slate_blue_gray
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_72
|
||||
text: "${thermostat_icon}"
|
||||
on_press:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: thermostat_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
# - button:
|
||||
# id: air_conditioner_page_btn
|
||||
# x: 170
|
||||
# align: LEFT_MID
|
||||
# width: 100
|
||||
# height: 100
|
||||
# radius: 10
|
||||
# bg_color: color_slate_blue_gray
|
||||
# shadow_opa: TRANSP
|
||||
# widgets:
|
||||
# - label:
|
||||
# align: CENTER
|
||||
# text_color: color_steel_blue
|
||||
# text_font: icons_72
|
||||
# text: "${air_conditioner_icon}"
|
||||
# on_press:
|
||||
# - lvgl.widget.hide: menu_controls_main
|
||||
# - lvgl.page.show:
|
||||
# id: air_conditioner_page
|
||||
# animation: OUT_RIGHT
|
||||
# time: 300ms
|
||||
|
||||
|
||||
# - button:
|
||||
# id: alarm_panel_page_btn
|
||||
# x: 305
|
||||
# align: LEFT_MID
|
||||
# width: 100
|
||||
# height: 100
|
||||
# radius: 10
|
||||
# bg_color: color_slate_blue_gray
|
||||
# shadow_opa: TRANSP
|
||||
# widgets:
|
||||
# - label:
|
||||
# align: CENTER
|
||||
# text_color: color_steel_blue
|
||||
# text_font: mdi_icons_72
|
||||
# text: "${shield_away_icon}"
|
||||
# on_press:
|
||||
# - lvgl.widget.hide: menu_controls_main
|
||||
# - lvgl.page.show:
|
||||
# id: alarm_panel_page
|
||||
# animation: OUT_RIGHT
|
||||
# time: 300ms
|
||||
|
||||
346
esphome/widgets/fonts.yaml
Normal file
346
esphome/widgets/fonts.yaml
Normal file
@@ -0,0 +1,346 @@
|
||||
- file: "fonts/Nunito-SemiBold.ttf"
|
||||
id: nunito_16
|
||||
size: 16
|
||||
bpp: 4
|
||||
glyphsets:
|
||||
- GF_Latin_Core
|
||||
# - GF_Greek_Core
|
||||
- GF_Cyrillic_Core
|
||||
- GF_Latin_Vietnamese
|
||||
glyphs: "²"
|
||||
extras:
|
||||
- file: "fonts/Jua-Regular.ttf"
|
||||
glyphs: [
|
||||
"\U0000C774",
|
||||
"\U0000B8E8",
|
||||
"\U0000B9C8",
|
||||
]
|
||||
|
||||
# # - file: "fonts/MPLUSRounded1c-Regular.ttf"
|
||||
# # id: mplus_16
|
||||
# # size: 16
|
||||
# # bpp: 4
|
||||
# # glyphs: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя .,!?-_:°²³¹"
|
||||
|
||||
- file: "fonts/Nunito-SemiBold.ttf"
|
||||
id: nunito_18
|
||||
size: 18
|
||||
bpp: 4
|
||||
glyphsets:
|
||||
- GF_Latin_Core
|
||||
# - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
- file: "fonts/Nunito-SemiBold.ttf"
|
||||
id: nunito_20
|
||||
size: 20
|
||||
bpp: 4
|
||||
glyphsets:
|
||||
- GF_Latin_Core
|
||||
# - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
- file: "fonts/Nunito-SemiBold.ttf"
|
||||
id: nunito_30
|
||||
size: 30
|
||||
bpp: 4
|
||||
glyphsets:
|
||||
- GF_Latin_Core
|
||||
# - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
# - file: "fonts/Nunito-SemiBold.ttf"
|
||||
# id: nunito_32
|
||||
# size: 32
|
||||
# bpp: 4
|
||||
# glyphsets:
|
||||
# - GF_Latin_Core
|
||||
# # - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
- file: "fonts/Nunito-SemiBold.ttf"
|
||||
id: nunito_36
|
||||
size: 36
|
||||
bpp: 4
|
||||
glyphsets:
|
||||
- GF_Latin_Core
|
||||
# - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
- file: "fonts/Nunito-SemiBold.ttf"
|
||||
id: nunito_48
|
||||
size: 48
|
||||
bpp: 4
|
||||
glyphsets:
|
||||
- GF_Latin_Core
|
||||
# - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
# - file: "fonts/Nunito-SemiBold.ttf"
|
||||
# id: nunito_64
|
||||
# size: 64
|
||||
# bpp: 4
|
||||
# glyphsets:
|
||||
# - GF_Latin_Core
|
||||
# # - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
# - file: "fonts/Nunito-SemiBold.ttf"
|
||||
# id: nunito_72
|
||||
# size: 72
|
||||
# bpp: 4
|
||||
# glyphsets:
|
||||
# - GF_Latin_Core
|
||||
# # - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
- file: "fonts/Nunito-SemiBold.ttf"
|
||||
id: nunito_84
|
||||
size: 84
|
||||
bpp: 4
|
||||
glyphsets:
|
||||
- GF_Latin_Core
|
||||
# - GF_Greek_Core
|
||||
# - GF_Cyrillic_Core
|
||||
# - GF_Latin_Vietnamese
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_24
|
||||
size: 24
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e900", # brightness
|
||||
"\U0000e901", # saturation
|
||||
"\U0000e925", # thermostat
|
||||
"\U0000e93b", # air_conditioner
|
||||
"\U0000e936", # heating
|
||||
"\U0000e92e", # lock
|
||||
"\U0000e935", # home assistant
|
||||
"\U0000e931", # wifi signal from 25% to 1%
|
||||
"\U0000e932", # wifi signal from 50% to 25%
|
||||
"\U0000e933", # wifi signal from 75% to 50%
|
||||
"\U0000e934", # wifi signal from 100% to 75% or disable
|
||||
]
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_28
|
||||
size: 28
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e902", # exit
|
||||
"\U0000e926", # fan
|
||||
"\U0000e927", # room_plan
|
||||
"\U0000e938", # humidity
|
||||
"\U0000e937", # co2
|
||||
"\U0000e93a", # air quality (tvoc)
|
||||
"\U0000e939", # temperature
|
||||
"\U0000e92f", # illumination (lux)
|
||||
]
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_32
|
||||
size: 32
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e91f", # arrow_up
|
||||
"\U0000e920", # arrow_down
|
||||
"\U0000e91c", # stop
|
||||
"\U0000e90e", # volume_off
|
||||
"\U0000e90f", # volume_on
|
||||
"\U0000e910", # volume_minus
|
||||
"\U0000e911", # volume_plus
|
||||
]
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_36
|
||||
size: 36
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e903", # settings
|
||||
"\U0000e904", # info
|
||||
"\U0000e905", # devices
|
||||
"\U0000e906", # home
|
||||
"\U0000e907", # ceiling
|
||||
"\U0000e908", # lightbulb
|
||||
"\U0000e91a", # swipe
|
||||
"\U0000e92e", # lock
|
||||
]
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_38
|
||||
size: 38
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e909", # power
|
||||
"\U0000e90c", # back step
|
||||
"\U0000e90d", # forward step
|
||||
"\U0000e912", # repeat_all
|
||||
"\U0000e913", # repeat_off
|
||||
"\U0000e914", # repeat_one
|
||||
"\U0000e90a", # play
|
||||
"\U0000e90b", # pause
|
||||
"\U0000e91c", # stop
|
||||
"\U0000e923", # locate
|
||||
"\U0000e924", # docked
|
||||
]
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_48
|
||||
size: 48
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e90a", # play
|
||||
"\U0000e90b", # pause
|
||||
"\U0000e91f", # arrow_up
|
||||
"\U0000e920", # arrow_down
|
||||
"\U0000e91c", # stop
|
||||
"\U0000e923", # locate
|
||||
"\U0000e924", # docked
|
||||
"\U0000e93b", # air_conditioner
|
||||
"\U0000e936", # heating
|
||||
"\U0000e938", # humidity
|
||||
"\U0000e939", # temperature
|
||||
]
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_72
|
||||
size: 72
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e91b", # music
|
||||
"\U0000e91d", # shutter_close
|
||||
"\U0000e922", # vacuum
|
||||
"\U0000e925", # thermostat
|
||||
"\U0000e93b", # air_conditioner
|
||||
]
|
||||
|
||||
- file: "fonts/icons_v2.ttf"
|
||||
id: icons_90
|
||||
size: 90
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U0000e908", # lightbulb
|
||||
"\U0000e915", # spotlights_group
|
||||
"\U0000e916", # desk_lamp
|
||||
"\U0000e917", # pendant_lamp
|
||||
"\U0000e918", # ceiling_lamp
|
||||
"\U0000e921", # ceiling_lamp_variant
|
||||
"\U0000e919", # night_lamp
|
||||
"\U0000e91d", # 0 - shutter_closed
|
||||
# "\U0000e93d", # 10 - shutter
|
||||
# "\U0000e93e", # 20 - shutter
|
||||
# "\U0000e93f", # 30 - shutter
|
||||
# "\U0000e940", # 40 - shutter
|
||||
# "\U0000e941", # 50 - shutter
|
||||
# "\U0000e93c", # 60 - shutter
|
||||
# "\U0000e943", # 70 - shutter
|
||||
# "\U0000e944", # 80 - shutter
|
||||
# "\U0000e942", # 90 - shutter
|
||||
"\U0000e91e", # 100 - shutter_open
|
||||
"\U0000e91b", # music
|
||||
"\U0000e91f", # arrow_up
|
||||
"\U0000e920", # arrow_down
|
||||
"\U0000e922", # vacuum
|
||||
]
|
||||
|
||||
# - file: "fonts/icons_v2.ttf"
|
||||
# id: icons_300
|
||||
# size: 300
|
||||
# bpp: 4
|
||||
# glyphs: [
|
||||
# "\U0000e91d", # 0 - shutter_closed
|
||||
# "\U0000e93d", # 10 - shutter
|
||||
# "\U0000e93e", # 20 - shutter
|
||||
# "\U0000e93f", # 30 - shutter
|
||||
# "\U0000e940", # 40 - shutter
|
||||
# "\U0000e941", # 50 - shutter
|
||||
# "\U0000e93c", # 60 - shutter
|
||||
# "\U0000e943", # 70 - shutter
|
||||
# "\U0000e944", # 80 - shutter
|
||||
# "\U0000e942", # 90 - shutter
|
||||
# "\U0000e91e" # 100 - shutter_open
|
||||
# ]
|
||||
|
||||
# - file: "fonts/materialdesignicons-webfont.ttf"
|
||||
# id: mdi_icons_24
|
||||
# size: 24
|
||||
# bpp: 4
|
||||
# glyphs: [
|
||||
# "\U000F068A", # shield home
|
||||
# "\U000F1828", # shield moon
|
||||
# "\U000F099D", # shield lock
|
||||
# "\U000F06BB", # shield plane
|
||||
# "\U000F099E", # shield off
|
||||
# "\U000F0498", # shield
|
||||
# ]
|
||||
|
||||
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
id: mdi_icons_28
|
||||
size: 28
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U000F0238", # heat
|
||||
"\U000F0717", # cool
|
||||
"\U000F0210", # fan
|
||||
"\U000F1B18", # auto
|
||||
"\U000F0425", # off
|
||||
]
|
||||
|
||||
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
id: mdi_icons_40
|
||||
size: 40
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U000F068A", # shield home
|
||||
"\U000F1828", # shield moon
|
||||
"\U000F099D", # shield lock
|
||||
"\U000F06BB", # shield plane
|
||||
"\U000F099E", # shield off
|
||||
"\U000F0498", # shield
|
||||
]
|
||||
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
id: mdi_icons_52
|
||||
size: 52
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U000F068A", # shield home
|
||||
"\U000F1828", # shield moon
|
||||
"\U000F099D", # shield lock
|
||||
"\U000F06BB", # shield plane
|
||||
"\U000F099E", # shield off
|
||||
"\U000F0498", # shield
|
||||
"\U000F0826", # home
|
||||
"\U000F1A46", # away
|
||||
]
|
||||
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
id: mdi_icons_68
|
||||
size: 68
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U000F068A", # shield home
|
||||
"\U000F1828", # shield moon
|
||||
"\U000F099D", # shield lock
|
||||
"\U000F06BB", # shield plane
|
||||
"\U000F099E", # shield off
|
||||
"\U000F0498", # shield
|
||||
]
|
||||
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
id: mdi_icons_72
|
||||
size: 72
|
||||
bpp: 4
|
||||
glyphs: [
|
||||
"\U000F099D", # shield lock
|
||||
]
|
||||
3
esphome/widgets/home/home.yaml
Normal file
3
esphome/widgets/home/home.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
packages:
|
||||
home: !include home_widget.yaml
|
||||
info: !include info_page.yaml
|
||||
768
esphome/widgets/home/home_widget.yaml
Normal file
768
esphome/widgets/home/home_widget.yaml
Normal file
@@ -0,0 +1,768 @@
|
||||
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
|
||||
380
esphome/widgets/home/info_page.yaml
Normal file
380
esphome/widgets/home/info_page.yaml
Normal file
@@ -0,0 +1,380 @@
|
||||
# System sensors
|
||||
sensor:
|
||||
# 1. Total SRAM memory usage
|
||||
- platform: template
|
||||
name: "SRAM Usage"
|
||||
id: sram_usage
|
||||
icon: mdi:memory
|
||||
unit_of_measurement: "KB"
|
||||
device_class: data_size
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 10s
|
||||
lambda: |-
|
||||
// Total SRAM size for ESP32-S3 = 512KB
|
||||
const size_t total_sram = 512 * 1024;
|
||||
size_t free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
size_t used_sram = total_sram - free_sram;
|
||||
return used_sram / 1024.0; // Return used memory in KB
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.bar.update:
|
||||
id: sram_memory_bar
|
||||
value: !lambda |-
|
||||
const size_t total_sram = 512 * 1024; // 512KB for ESP32-S3
|
||||
size_t free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
size_t used_sram = total_sram - free_sram;
|
||||
return (int)(((double)used_sram / total_sram) * 100);
|
||||
- lvgl.label.update:
|
||||
id: sram_memory_label
|
||||
text: !lambda |-
|
||||
const size_t total_sram = 512 * 1024;
|
||||
size_t free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
size_t used_sram = total_sram - free_sram;
|
||||
static char sram_buf[32];
|
||||
snprintf(sram_buf, sizeof(sram_buf), "%.1f/%.0f KB",
|
||||
used_sram/1024.0, total_sram/1024.0);
|
||||
return sram_buf;
|
||||
|
||||
# 2. Total PSRAM memory usage
|
||||
- platform: template
|
||||
name: "PSRAM Usage"
|
||||
id: psram_usage
|
||||
icon: mdi:memory
|
||||
unit_of_measurement: "MB"
|
||||
device_class: data_size
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 10s
|
||||
lambda: |-
|
||||
// Total PSRAM size = 8MB
|
||||
const size_t total_psram = 8 * 1024 * 1024;
|
||||
size_t free_psram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
|
||||
// If PSRAM is not available, return 0
|
||||
if (heap_caps_get_total_size(MALLOC_CAP_SPIRAM) == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
size_t used_psram = total_psram - free_psram;
|
||||
return used_psram / (1024.0 * 1024.0); // Return used memory in MB
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.bar.update:
|
||||
id: psram_memory_bar
|
||||
value: !lambda |-
|
||||
const size_t total_psram = 8 * 1024 * 1024; // 8MB
|
||||
size_t free_psram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
|
||||
if (heap_caps_get_total_size(MALLOC_CAP_SPIRAM) == 0) return 0;
|
||||
|
||||
size_t used_psram = total_psram - free_psram;
|
||||
return (int)(((double)used_psram / total_psram) * 100);
|
||||
- lvgl.label.update:
|
||||
id: psram_memory_label
|
||||
text: !lambda |-
|
||||
const size_t total_psram = 8 * 1024 * 1024;
|
||||
size_t free_psram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
static char psram_buf[32];
|
||||
|
||||
if (heap_caps_get_total_size(MALLOC_CAP_SPIRAM) == 0) {
|
||||
snprintf(psram_buf, sizeof(psram_buf), "No PSRAM");
|
||||
} else {
|
||||
size_t used_psram = total_psram - free_psram;
|
||||
snprintf(psram_buf, sizeof(psram_buf), "%.1f/%.0f MB",
|
||||
used_psram/(1024.0*1024.0), total_psram/(1024.0*1024.0));
|
||||
}
|
||||
return psram_buf;
|
||||
|
||||
# 3. Chip temperature
|
||||
- platform: internal_temperature
|
||||
name: "ESP32 Internal Temperature"
|
||||
id: esp32_temperature
|
||||
update_interval: 30s
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: chip_temperature_label
|
||||
text:
|
||||
format: "%.1f°C"
|
||||
args: [id(esp32_temperature).state]
|
||||
|
||||
# 4. WiFi Signal Strength in dBm
|
||||
- platform: wifi_signal
|
||||
name: "WiFi Signal"
|
||||
id: wifi_signal_db
|
||||
update_interval: 30s
|
||||
unit_of_measurement: "dBm"
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: wifi_signal_label
|
||||
text:
|
||||
format: "%.0f dBm"
|
||||
args: [id(wifi_signal_db).state]
|
||||
|
||||
# Text sensors for WiFi information
|
||||
text_sensor:
|
||||
# 5. IP address
|
||||
- platform: wifi_info
|
||||
ip_address:
|
||||
name: "IP Address"
|
||||
id: wifi_ip_address
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ip_address_label
|
||||
text: !lambda return id(wifi_ip_address).state.c_str();
|
||||
|
||||
# 6. MAC address
|
||||
- platform: wifi_info
|
||||
mac_address:
|
||||
name: "WiFi MAC"
|
||||
id: wifi_mac_address
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: wifi_mac_label
|
||||
text: !lambda return id(wifi_mac_address).state.c_str();
|
||||
|
||||
# 7. ESPHome version with compilation date
|
||||
- platform: template
|
||||
name: "ESPHome Version"
|
||||
id: esphome_version
|
||||
lambda: |-
|
||||
return {ESPHOME_VERSION};
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: esphome_version_label
|
||||
text: !lambda 'return id(esphome_version).state;'
|
||||
|
||||
# LVGL interface for displaying system information
|
||||
lvgl:
|
||||
pages:
|
||||
- id: system_info_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- obj:
|
||||
id: system_info_container
|
||||
x: 20
|
||||
y: 20
|
||||
width: 440
|
||||
height: 340
|
||||
align: TOP_LEFT
|
||||
pad_all: 0
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
# SRAM memory (show used from total)
|
||||
- obj:
|
||||
y: 10
|
||||
width: 400
|
||||
height: 50
|
||||
align: TOP_MID
|
||||
bg_opa: TRANSP
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: TOP_LEFT
|
||||
text: "SRAM Used:"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
- label:
|
||||
id: sram_memory_label
|
||||
align: TOP_RIGHT
|
||||
text: "0/512 KB"
|
||||
text_font: nunito_16
|
||||
text_color: color_green
|
||||
- bar:
|
||||
id: sram_memory_bar
|
||||
y: 30
|
||||
width: 390
|
||||
height: 12
|
||||
align: TOP_MID
|
||||
pad_all: 0
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
value: 0
|
||||
bg_color: color_gray
|
||||
bg_opa: 50%
|
||||
indicator:
|
||||
bg_color: color_green
|
||||
|
||||
# PSRAM memory (show used from total)
|
||||
- obj:
|
||||
y: 70
|
||||
width: 400
|
||||
height: 50
|
||||
align: TOP_MID
|
||||
bg_opa: TRANSP
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: TOP_LEFT
|
||||
text: "PSRAM Used:"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
- label:
|
||||
id: psram_memory_label
|
||||
align: TOP_RIGHT
|
||||
text: "0/8 MB"
|
||||
text_font: nunito_16
|
||||
text_color: color_blue
|
||||
- bar:
|
||||
id: psram_memory_bar
|
||||
y: 30
|
||||
width: 390
|
||||
height: 12
|
||||
align: TOP_MID
|
||||
pad_all: 0
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
value: 0
|
||||
bg_color: color_gray
|
||||
bg_opa: 50%
|
||||
indicator:
|
||||
bg_color: color_blue
|
||||
|
||||
# Chip temperature
|
||||
- obj:
|
||||
y: 130
|
||||
width: 400
|
||||
height: 30
|
||||
align: TOP_MID
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: LEFT_MID
|
||||
text: "CPU Temperature:"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
- label:
|
||||
id: chip_temperature_label
|
||||
align: RIGHT_MID
|
||||
text: "0°C"
|
||||
text_font: nunito_16
|
||||
text_color: color_yellow
|
||||
|
||||
# WiFi signal
|
||||
- obj:
|
||||
y: 170
|
||||
width: 400
|
||||
height: 30
|
||||
align: TOP_MID
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: LEFT_MID
|
||||
text: "WiFi Signal:"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
- label:
|
||||
id: wifi_signal_label
|
||||
align: RIGHT_MID
|
||||
text: "0 dBm"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
|
||||
# IP Address
|
||||
- obj:
|
||||
y: 210
|
||||
width: 400
|
||||
height: 30
|
||||
align: TOP_MID
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: LEFT_MID
|
||||
text: "IP Address:"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
- label:
|
||||
id: ip_address_label
|
||||
align: RIGHT_MID
|
||||
text: "192.168.3.3"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
|
||||
# MAC Address
|
||||
- obj:
|
||||
y: 250
|
||||
width: 400
|
||||
height: 30
|
||||
align: TOP_MID
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
border_color: color_white
|
||||
border_width: 1
|
||||
border_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: LEFT_MID
|
||||
text: "MAC Address:"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
- label:
|
||||
id: wifi_mac_label
|
||||
align: RIGHT_MID
|
||||
text: "11:22:A1:B2:C3:D4"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
|
||||
# ESPHome version
|
||||
- obj:
|
||||
y: 290
|
||||
width: 400
|
||||
height: 30
|
||||
align: TOP_MID
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: LEFT_MID
|
||||
text: "ESPHome Version:"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
- label:
|
||||
id: esphome_version_label
|
||||
align: RIGHT_MID
|
||||
text: "2020.0.0"
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
|
||||
# Interval for periodic logging
|
||||
interval:
|
||||
- interval: 60s
|
||||
then:
|
||||
- lambda: |-
|
||||
// Log real memory usage
|
||||
const size_t total_sram = 512 * 1024;
|
||||
const size_t total_psram = 8 * 1024 * 1024;
|
||||
|
||||
size_t free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
size_t used_sram = total_sram - free_sram;
|
||||
|
||||
size_t free_psram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
size_t used_psram = total_psram - free_psram;
|
||||
|
||||
ESP_LOGI("system_info", "SRAM: %u/%u KB used (%.1f%%)",
|
||||
used_sram/1024, total_sram/1024,
|
||||
(used_sram * 100.0) / total_sram);
|
||||
|
||||
if (heap_caps_get_total_size(MALLOC_CAP_SPIRAM) > 0) {
|
||||
ESP_LOGI("system_info", "PSRAM: %u/%u MB used (%.1f%%)",
|
||||
used_psram/(1024*1024), total_psram/(1024*1024),
|
||||
(used_psram * 100.0) / total_psram);
|
||||
} else {
|
||||
ESP_LOGI("system_info", "PSRAM: Not available");
|
||||
}
|
||||
413
esphome/widgets/image.yaml
Normal file
413
esphome/widgets/image.yaml
Normal file
@@ -0,0 +1,413 @@
|
||||
#############################
|
||||
########### LOGO ############
|
||||
#############################
|
||||
|
||||
- file: 'img/loading/homeassistant.png'
|
||||
id: ha_img
|
||||
type: rgb565
|
||||
resize: 400x82
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/loading/esphome.png'
|
||||
id: esphome_img
|
||||
type: rgb565
|
||||
resize: 320x95
|
||||
transparency: alpha_channel
|
||||
|
||||
#############################
|
||||
########## LIGHT ############
|
||||
#############################
|
||||
|
||||
- file: 'img/light/lightbulb.png'
|
||||
id: lightbulb_image
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/light/rgb_ring.png'
|
||||
id: rgb_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
#############################
|
||||
########## VACUUM ###########
|
||||
#############################
|
||||
|
||||
- file: 'img/vacuum/vacuum.png'
|
||||
id: vacuum_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_0_10.png'
|
||||
id: vacuum_0_10_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_0_20.png'
|
||||
id: vacuum_0_20_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_0_30.png'
|
||||
id: vacuum_0_30_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_5.png'
|
||||
id: vacuum_5_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_10.png'
|
||||
id: vacuum_10_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_15.png'
|
||||
id: vacuum_15_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_20.png'
|
||||
id: vacuum_20_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_20_10.png'
|
||||
id: vacuum_20_10_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_20_20.png'
|
||||
id: vacuum_20_20_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_20_30.png'
|
||||
id: vacuum_20_30_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_355.png'
|
||||
id: vacuum_355_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_350.png'
|
||||
id: vacuum_350_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_345.png'
|
||||
id: vacuum_345_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_340.png'
|
||||
id: vacuum_340_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_340_10.png'
|
||||
id: vacuum_340_10_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_340_20.png'
|
||||
id: vacuum_340_20_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/vacuum/vacuum_340_30.png'
|
||||
id: vacuum_340_30_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
#############################
|
||||
########## WEATHER ##########
|
||||
#############################
|
||||
|
||||
- file: 'img/weather/sunny.png'
|
||||
id: sunny_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/clear_night.png'
|
||||
id: clear_night_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/cloudy.png'
|
||||
id: cloudy_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/partlycloudy_sun.png'
|
||||
id: partlycloudy_sun_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/partlycloudy_moon.png'
|
||||
id: partlycloudy_moon_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/rainy.png'
|
||||
id: rainy_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/pouring.png'
|
||||
id: pouring_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/snowy.png'
|
||||
id: snowy_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/snowy_rainy.png'
|
||||
id: snowy_rainy_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/fog.png'
|
||||
id: fog_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/hail.png'
|
||||
id: hail_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/lightning.png'
|
||||
id: lightning_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/lightning_rainy.png'
|
||||
id: lightning_rainy_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/windy.png'
|
||||
id: windy_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/weather/windy_variant.png'
|
||||
id: windy_variant_img
|
||||
type: rgb565
|
||||
resize: 200x200
|
||||
transparency: alpha_channel
|
||||
|
||||
#############################
|
||||
########## FLAGS ############
|
||||
#############################
|
||||
|
||||
- file: 'img/flags/de.png'
|
||||
id: flags_de_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/es.png'
|
||||
id: flags_es_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/fr.png'
|
||||
id: flags_fr_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/gb.png'
|
||||
id: flags_gb_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/it.png'
|
||||
id: flags_it_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/kr.png'
|
||||
id: flags_kr_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/pt.png'
|
||||
id: flags_pt_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/ru.png'
|
||||
id: flags_ru_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/us.png'
|
||||
id: flags_us_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/pl.png'
|
||||
id: flags_pl_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/tr.png'
|
||||
id: flags_tr_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/sv.png'
|
||||
id: flags_sv_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/id.png'
|
||||
id: flags_id_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/vi.png'
|
||||
id: flags_vi_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/ro.png'
|
||||
id: flags_ro_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/nl.png'
|
||||
id: flags_nl_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/hu.png'
|
||||
id: flags_hu_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/cs.png'
|
||||
id: flags_cs_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/flags/fi.png'
|
||||
id: flags_fi_img
|
||||
type: rgb565
|
||||
resize: 60x80
|
||||
transparency: alpha_channel
|
||||
|
||||
#############################
|
||||
########## BATTERY ##########
|
||||
#############################
|
||||
|
||||
- file: 'img/battery/battery_very_high.png'
|
||||
id: battery_very_high_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_high.png'
|
||||
id: battery_high_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_middle.png'
|
||||
id: battery_middle_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_low.png'
|
||||
id: battery_low_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_very_low.png'
|
||||
id: battery_very_low_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_empty.png'
|
||||
id: battery_empty_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_80.png'
|
||||
id: battery_80_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_60.png'
|
||||
id: battery_60_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_40.png'
|
||||
id: battery_40_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_20.png'
|
||||
id: battery_20_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
- file: 'img/battery/battery_0.png'
|
||||
id: battery_0_img
|
||||
type: rgb565
|
||||
transparency: alpha_channel
|
||||
|
||||
292
esphome/widgets/light/light_brightness_widget.yaml
Normal file
292
esphome/widgets/light/light_brightness_widget.yaml
Normal file
@@ -0,0 +1,292 @@
|
||||
substitutions:
|
||||
|
||||
exit_icon: "\U0000e902"
|
||||
|
||||
globals:
|
||||
- id: ${widget_name}_light_is_on
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_current_brightness
|
||||
type: float
|
||||
initial_value: '1.0'
|
||||
- id: ${widget_name}_updating_from_ha
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_ha_data_received
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_sensors_ready_count
|
||||
type: int
|
||||
initial_value: '0'
|
||||
|
||||
sensor:
|
||||
# Brightness sensor
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_brightness
|
||||
entity_id: "${light_entity}"
|
||||
attribute: brightness
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !std::isnan(x);'
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_brightness_received = false;
|
||||
if (!first_brightness_received) {
|
||||
first_brightness_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
value: !lambda return int(x);
|
||||
else:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: '0.0'
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
value: 0
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_state
|
||||
entity_id: "${light_entity}"
|
||||
on_value:
|
||||
- lambda: |-
|
||||
bool is_on = (x == "on");
|
||||
bool was_on = id(${widget_name}_light_is_on);
|
||||
id(${widget_name}_light_is_on) = is_on;
|
||||
|
||||
static bool first_state_received = false;
|
||||
if (!first_state_received) {
|
||||
first_state_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: color_amber
|
||||
shadow_color: color_amber
|
||||
shadow_opa: 100%
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: color_amber
|
||||
|
||||
else:
|
||||
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: color_white
|
||||
shadow_opa: TRANSP
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: color_steel_blue
|
||||
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_name
|
||||
entity_id: "${light_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
text: !lambda return x;
|
||||
|
||||
lvgl:
|
||||
pages:
|
||||
- id: ${widget_name}_light_rgb_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_name
|
||||
y: 20
|
||||
width: 440
|
||||
height: 40
|
||||
align: TOP_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "lightbulb"
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_lightbulb
|
||||
x: 20
|
||||
y: 80
|
||||
width: 200
|
||||
height: 280
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
width: 70
|
||||
height: 70
|
||||
y: 74
|
||||
align: TOP_MID
|
||||
bg_color: color_white
|
||||
shadow_color: color_white
|
||||
shadow_ofs_y: -3
|
||||
shadow_spread: 3
|
||||
shadow_width: 15
|
||||
radius: 40
|
||||
- image:
|
||||
y: 30
|
||||
align: CENTER
|
||||
src: lightbulb_image
|
||||
id: ${widget_name}_lightbulb_image
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on_btn
|
||||
width: 200
|
||||
height: 280
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
on_press:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_bg_slider
|
||||
x: -20
|
||||
y: 80
|
||||
width: 220
|
||||
height: 380
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 20
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_brightness_gradient
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 300
|
||||
align: CENTER
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
shadow_opa: TRANSP
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 300
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
min_value: 3
|
||||
max_value: 255
|
||||
indicator:
|
||||
bg_color: color_amber
|
||||
radius: 10
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_light_is_on) && x > 3;'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
brightness: !lambda return int(x);
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x <= 3;'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_off
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
else:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
brightness: !lambda return int(x);
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_exit_on_btn
|
||||
x: 20
|
||||
y: -20
|
||||
width: 200
|
||||
height: 80
|
||||
align: BOTTOM_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_exit_on_icon
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
then:
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: lights_group_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
script:
|
||||
- id: ${widget_name}_check_all_data_ready
|
||||
mode: restart
|
||||
then:
|
||||
- delay: 500ms
|
||||
- lambda: |-
|
||||
if (id(${widget_name}_sensors_ready_count) >= 2) {
|
||||
if (!id(${widget_name}_ha_data_received)) {
|
||||
id(${widget_name}_ha_data_received) = true;
|
||||
id(${widget_name}_updating_from_ha) = false;
|
||||
}
|
||||
}
|
||||
798
esphome/widgets/light/light_rgb_widget.yaml
Normal file
798
esphome/widgets/light/light_rgb_widget.yaml
Normal file
@@ -0,0 +1,798 @@
|
||||
substitutions:
|
||||
|
||||
brightness_icon: "\U0000e900"
|
||||
saturation_icon: "\U0000e901"
|
||||
exit_icon: "\U0000e902"
|
||||
|
||||
globals:
|
||||
- id: ${widget_name}_light_is_on
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_current_hue
|
||||
type: float
|
||||
initial_value: '0.0'
|
||||
- id: ${widget_name}_current_saturation
|
||||
type: float
|
||||
initial_value: '0.0'
|
||||
- id: ${widget_name}_current_brightness
|
||||
type: float
|
||||
initial_value: '1.0'
|
||||
- id: ${widget_name}_current_color_temp
|
||||
type: float
|
||||
initial_value: '3000.0'
|
||||
- id: ${widget_name}_updating_from_ha
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_ha_data_received
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_sensors_ready_count
|
||||
type: int
|
||||
initial_value: '0'
|
||||
- id: ${widget_name}_is_temp_mode
|
||||
type: bool
|
||||
initial_value: 'true'
|
||||
- id: ${widget_name}_mode_switching
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
|
||||
sensor:
|
||||
# Brightness sensor
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_brightness
|
||||
entity_id: "${light_entity}"
|
||||
attribute: brightness
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !std::isnan(x);'
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_brightness_received = false;
|
||||
if (!first_brightness_received) {
|
||||
first_brightness_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
value: !lambda return int(x);
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
text: !lambda |-
|
||||
int percent = int((x / 255.0f) * 100 + 0.5f);
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "%d%%", percent);
|
||||
return std::string(buf);
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
# Color temp sensor
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_color_temp
|
||||
entity_id: "${light_entity}"
|
||||
attribute: color_temp_kelvin
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !std::isnan(x);'
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_temp_received = false;
|
||||
if (!first_temp_received) {
|
||||
first_temp_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_color_temp
|
||||
value: !lambda return x;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_color_temp_slider
|
||||
value: !lambda return int(x);
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_is_temp_mode) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${widget_name}_update_color_temp_preview
|
||||
kelvin: !lambda return x;
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
text_sensor:
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_state
|
||||
entity_id: "${light_entity}"
|
||||
on_value:
|
||||
- lambda: |-
|
||||
bool is_on = (x == "on");
|
||||
bool was_on = id(${widget_name}_light_is_on);
|
||||
id(${widget_name}_light_is_on) = is_on;
|
||||
|
||||
static bool first_state_received = false;
|
||||
if (!first_state_received) {
|
||||
first_state_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: color_steel_blue
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: color_white
|
||||
shadow_opa: TRANSP
|
||||
else:
|
||||
- lambda: |-
|
||||
if (id(${widget_name}_mode_switching)) return;
|
||||
std::string rgb_str = id(${widget_name}_light_rgb_color).state;
|
||||
size_t start = rgb_str.find('(') + 1;
|
||||
size_t first_comma = rgb_str.find(',', start);
|
||||
size_t second_comma = rgb_str.find(',', first_comma + 1);
|
||||
size_t end = rgb_str.find(')', second_comma);
|
||||
if (start < first_comma && first_comma < second_comma && second_comma < end) {
|
||||
int red = atoi(rgb_str.substr(start, first_comma - start).c_str());
|
||||
int green = atoi(rgb_str.substr(first_comma + 1, second_comma - first_comma - 1).c_str());
|
||||
int blue = atoi(rgb_str.substr(second_comma + 1, end - second_comma - 1).c_str());
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
}
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_hs
|
||||
entity_id: "${light_entity}"
|
||||
attribute: hs_color
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: "return x != \"None\" && !x.empty();"
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_hs_received = false;
|
||||
if (!first_hs_received) {
|
||||
first_hs_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- lambda: |-
|
||||
id(${widget_name}_updating_from_ha) = true;
|
||||
std::string s = x;
|
||||
size_t start = s.find('(') + 1;
|
||||
size_t comma = s.find(',');
|
||||
size_t end = s.find(')');
|
||||
float hue = 0.0f, sat = 0.0f;
|
||||
if (start < comma && comma < end) {
|
||||
hue = atof(s.substr(start, comma - start).c_str());
|
||||
sat = atof(s.substr(comma + 1, end - comma - 1).c_str());
|
||||
}
|
||||
id(${widget_name}_current_hue) = hue;
|
||||
id(${widget_name}_current_saturation) = sat;
|
||||
- lvgl.arc.update:
|
||||
id: ${widget_name}_light_rgb_hue_arc
|
||||
value: !lambda "return id(${widget_name}_current_hue);"
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_saturation_slider
|
||||
value: !lambda "return id(${widget_name}_current_saturation) * 255.0f / 100.0f;"
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_saturation_state
|
||||
text: !lambda |-
|
||||
return (std::to_string((int)id(${widget_name}_current_saturation)) + "%").c_str();
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_is_temp_mode) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- script.execute: ${widget_name}_update_light_color_from_current_values
|
||||
- lambda: |-
|
||||
id(${widget_name}_updating_from_ha) = false;
|
||||
else:
|
||||
- lambda: |-
|
||||
static bool first_hs_received = false;
|
||||
if (!first_hs_received) {
|
||||
first_hs_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_color
|
||||
entity_id: "${light_entity}"
|
||||
attribute: rgb_color
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_name
|
||||
entity_id: "${light_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
text: !lambda return x;
|
||||
|
||||
lvgl:
|
||||
gradients:
|
||||
|
||||
- id: ${widget_name}_color_temp_gradient
|
||||
direction: ver
|
||||
dither: none
|
||||
stops:
|
||||
- color: 0xA0C8FF
|
||||
position: 0
|
||||
- color: 0xE0F7FF
|
||||
position: 80
|
||||
- color: 0xFFFFFF
|
||||
position: 128
|
||||
- color: 0xFFFFE0
|
||||
position: 175
|
||||
- color: 0xFFD6A0
|
||||
position: 255
|
||||
|
||||
pages:
|
||||
- id: ${widget_name}_light_rgb_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_name
|
||||
y: 20
|
||||
width: 440
|
||||
height: 40
|
||||
align: TOP_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "lightbulb"
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_lightbulb
|
||||
x: 20
|
||||
y: 80
|
||||
width: 200
|
||||
height: 180
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
width: 70
|
||||
height: 70
|
||||
y: 24
|
||||
align: TOP_MID
|
||||
bg_color: color_white
|
||||
shadow_color: color_white
|
||||
shadow_ofs_y: -3
|
||||
shadow_spread: 3
|
||||
shadow_width: 15
|
||||
radius: 40
|
||||
- image:
|
||||
y: 30
|
||||
align: CENTER
|
||||
src: lightbulb_image
|
||||
id: ${widget_name}_lightbulb_image
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on_btn
|
||||
width: 200
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
on_press:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_mode_btn
|
||||
x: 20
|
||||
y: 60
|
||||
width: 200
|
||||
height: 40
|
||||
align: LEFT_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
checkable: true
|
||||
state:
|
||||
checked: false
|
||||
checked:
|
||||
bg_color: color_misty_blue
|
||||
bg_opa: 30%
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_mode_label
|
||||
text_color: color_misty_blue
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text: "TEMP MODE"
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(${widget_name}_is_temp_mode) = !id(${widget_name}_is_temp_mode);
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_is_temp_mode);'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_mode_label
|
||||
text: "TEMP MODE"
|
||||
- script.execute: ${widget_name}_switch_to_temp_mode
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_mode_label
|
||||
text: "RGB MODE"
|
||||
- script.execute: ${widget_name}_switch_to_rgb_mode
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_bg_slider
|
||||
x: -20
|
||||
y: 80
|
||||
width: 220
|
||||
height: 240
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- image:
|
||||
id: ${widget_name}_light_rgb_hue_gradient
|
||||
align: CENTER
|
||||
src: rgb_img
|
||||
hidden: true
|
||||
|
||||
- arc:
|
||||
id: ${widget_name}_light_rgb_hue_arc
|
||||
arc_opa: TRANSP
|
||||
arc_width: 50
|
||||
start_angle: 0
|
||||
end_angle: 360
|
||||
adjustable: true
|
||||
adv_hittest: true
|
||||
align: CENTER
|
||||
width: 190
|
||||
height: 190
|
||||
min_value: 0
|
||||
max_value: 360
|
||||
hidden: true
|
||||
indicator:
|
||||
arc_opa: TRANSP
|
||||
arc_width: 50
|
||||
knob:
|
||||
border_color: color_white
|
||||
border_width: 3
|
||||
bg_opa: TRANSP
|
||||
pad_all: -7
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_hue
|
||||
value: !lambda "return (float)x;"
|
||||
- script.execute: ${widget_name}_update_light_color_from_current_values
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- script.execute: ${widget_name}_send_hs_color_to_ha
|
||||
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_color_temp_gradient
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_grad: ${widget_name}_color_temp_gradient
|
||||
bg_grad_dir: ver
|
||||
shadow_opa: TRANSP
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_color_temp_slider
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
min_value: 2000
|
||||
max_value: 6500
|
||||
indicator:
|
||||
bg_opa: TRANSP
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_color_temp
|
||||
value: !lambda return x;
|
||||
- script.execute:
|
||||
id: ${widget_name}_update_color_temp_preview
|
||||
kelvin: !lambda return x;
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
color_temp_kelvin: !lambda return int(x);
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_bg_bs_sliders
|
||||
x: -20
|
||||
y: -20
|
||||
width: 360
|
||||
height: 120
|
||||
align: BOTTOM_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_brightness_pos
|
||||
pad_all: 0
|
||||
width: 320
|
||||
height: 40
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_brightness_icon
|
||||
x: 0
|
||||
y: 0
|
||||
align: LEFT_MID
|
||||
text_font: icons_24
|
||||
text_color: color_misty_blue
|
||||
text: "${brightness_icon}"
|
||||
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
x: 0
|
||||
y: 0
|
||||
align: RIGHT_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "100%"
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
align: CENTER
|
||||
x: -10
|
||||
y: 1
|
||||
width: 220
|
||||
height: 10
|
||||
min_value: 3
|
||||
max_value: 255
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
radius: 30
|
||||
knob:
|
||||
bg_color: color_misty_blue
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
text: !lambda |-
|
||||
int percent = int((x / 255.0f) * 100 + 0.5f);
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "%d%%", percent);
|
||||
return std::string(buf);
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
brightness: !lambda return int(x);
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_saturation_container
|
||||
pad_all: 0
|
||||
width: 320
|
||||
height: 40
|
||||
align: BOTTOM_MID
|
||||
bg_opa: TRANSP
|
||||
border_width: 0
|
||||
hidden: true
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_saturation_icon
|
||||
x: 0
|
||||
y: 0
|
||||
align: LEFT_MID
|
||||
text_font: icons_24
|
||||
text_color: color_misty_blue
|
||||
text: "${saturation_icon}"
|
||||
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_saturation_state
|
||||
x: 0
|
||||
y: 0
|
||||
align: RIGHT_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "100%"
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_saturation_slider
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
align: CENTER
|
||||
x: -10
|
||||
y: 0
|
||||
width: 220
|
||||
height: 10
|
||||
min_value: 1
|
||||
max_value: 255
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
knob:
|
||||
bg_color: color_misty_blue
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_saturation
|
||||
value: !lambda "return (float)x * 100.0f / 255.0f;"
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_saturation_state
|
||||
text: !lambda |-
|
||||
int percent = int((float)x * 100.0f / 255.0f + 0.5f);
|
||||
return (std::to_string(percent) + "%").c_str();
|
||||
- script.execute: ${widget_name}_update_light_color_from_current_values
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- script.execute: ${widget_name}_send_hs_color_to_ha
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_exit_on_btn
|
||||
x: 20
|
||||
y: -20
|
||||
width: 60
|
||||
height: 120
|
||||
align: BOTTOM_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_exit_on_icon
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
then:
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: lights_group_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
script:
|
||||
- id: ${widget_name}_check_all_data_ready
|
||||
mode: restart
|
||||
then:
|
||||
- delay: 500ms
|
||||
- lambda: |-
|
||||
if (id(${widget_name}_sensors_ready_count) >= 4) {
|
||||
if (!id(${widget_name}_ha_data_received)) {
|
||||
id(${widget_name}_ha_data_received) = true;
|
||||
id(${widget_name}_updating_from_ha) = false;
|
||||
id(${widget_name}_switch_to_temp_mode).execute();
|
||||
}
|
||||
}
|
||||
|
||||
- id: ${widget_name}_switch_to_temp_mode
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'true'
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_hue_arc
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_hue_gradient
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_saturation_container
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_color_temp_slider
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_color_temp_gradient
|
||||
- lvgl.obj.update:
|
||||
id: ${widget_name}_light_rgb_brightness_pos
|
||||
align: CENTER
|
||||
- delay: 500ms
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'false'
|
||||
|
||||
- id: ${widget_name}_switch_to_rgb_mode
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'true'
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_hue_arc
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_hue_gradient
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_saturation_container
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_color_temp_slider
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_color_temp_gradient
|
||||
- lvgl.obj.update:
|
||||
id: ${widget_name}_light_rgb_brightness_pos
|
||||
align: TOP_MID
|
||||
- delay: 500ms
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'false'
|
||||
|
||||
- id: ${widget_name}_update_light_color_from_current_values
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${widget_name}_hsv_to_rgb_and_update
|
||||
hue: !lambda "return id(${widget_name}_current_hue);"
|
||||
saturation: !lambda "return id(${widget_name}_current_saturation);"
|
||||
brightness: 1.0
|
||||
|
||||
- id: ${widget_name}_update_color_temp_preview
|
||||
parameters:
|
||||
kelvin: float
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- lambda: |-
|
||||
float temp = kelvin / 100.0f;
|
||||
float r, g, b;
|
||||
|
||||
if (temp <= 66.0f) {
|
||||
r = 255.0f;
|
||||
g = 99.4708025861f * logf(temp) - 161.1195681661f;
|
||||
if (temp <= 19.0f) {
|
||||
b = 0.0f;
|
||||
} else {
|
||||
b = 138.5177312231f * logf(temp - 10.0f) - 305.0447927307f;
|
||||
}
|
||||
} else {
|
||||
r = 329.698727446f * powf(temp - 60.0f, -0.1332047592f);
|
||||
g = 288.1221695283f * powf(temp - 60.0f, -0.0755148492f);
|
||||
b = 255.0f;
|
||||
}
|
||||
|
||||
r = std::clamp(r, 0.0f, 255.0f);
|
||||
g = std::clamp(g, 0.0f, 255.0f);
|
||||
b = std::clamp(b, 0.0f, 255.0f);
|
||||
|
||||
int red = static_cast<int>(r);
|
||||
int green = static_cast<int>(g);
|
||||
int blue = static_cast<int>(b);
|
||||
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
|
||||
- id: ${widget_name}_update_light_button_color
|
||||
parameters:
|
||||
red: int
|
||||
green: int
|
||||
blue: int
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
shadow_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
shadow_opa: 100%
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
|
||||
- id: ${widget_name}_hsv_to_rgb_and_update
|
||||
parameters:
|
||||
hue: float
|
||||
saturation: float
|
||||
brightness: float
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lambda: |-
|
||||
float h = hue;
|
||||
float s = saturation / 100.0f;
|
||||
float v = brightness;
|
||||
|
||||
float c = v * s;
|
||||
float x_val = c * (1.0f - abs(fmod(h / 60.0f, 2.0f) - 1.0f));
|
||||
float m = v - c;
|
||||
|
||||
float r, g, b;
|
||||
if (h >= 0 && h < 60) {
|
||||
r = c; g = x_val; b = 0;
|
||||
} else if (h >= 60 && h < 120) {
|
||||
r = x_val; g = c; b = 0;
|
||||
} else if (h >= 120 && h < 180) {
|
||||
r = 0; g = c; b = x_val;
|
||||
} else if (h >= 180 && h < 240) {
|
||||
r = 0; g = x_val; b = c;
|
||||
} else if (h >= 240 && h < 300) {
|
||||
r = x_val; g = 0; b = c;
|
||||
} else {
|
||||
r = c; g = 0; b = x_val;
|
||||
}
|
||||
|
||||
int red = (int)((r + m) * 255.0f);
|
||||
int green = (int)((g + m) * 255.0f);
|
||||
int blue = (int)((b + m) * 255.0f);
|
||||
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
|
||||
- id: ${widget_name}_send_hs_color_to_ha
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
data_template:
|
||||
hs_color: "{{ (hue|float, sat|float)|list }}"
|
||||
variables:
|
||||
hue: !lambda "return id(${widget_name}_current_hue);"
|
||||
sat: !lambda "return id(${widget_name}_current_saturation);"
|
||||
815
esphome/widgets/light/light_rgb_widget_slider.yaml
Normal file
815
esphome/widgets/light/light_rgb_widget_slider.yaml
Normal file
@@ -0,0 +1,815 @@
|
||||
substitutions:
|
||||
|
||||
brightness_icon: "\U0000e900"
|
||||
saturation_icon: "\U0000e901"
|
||||
exit_icon: "\U0000e902"
|
||||
|
||||
globals:
|
||||
- id: ${widget_name}_light_is_on
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_current_hue
|
||||
type: float
|
||||
initial_value: '0.0'
|
||||
- id: ${widget_name}_current_saturation
|
||||
type: float
|
||||
initial_value: '0.0'
|
||||
- id: ${widget_name}_current_brightness
|
||||
type: float
|
||||
initial_value: '1.0'
|
||||
- id: ${widget_name}_current_color_temp
|
||||
type: float
|
||||
initial_value: '3000.0'
|
||||
- id: ${widget_name}_updating_from_ha
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_ha_data_received
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_sensors_ready_count
|
||||
type: int
|
||||
initial_value: '0'
|
||||
- id: ${widget_name}_is_temp_mode
|
||||
type: bool
|
||||
initial_value: 'true'
|
||||
- id: ${widget_name}_mode_switching
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
|
||||
sensor:
|
||||
# Brightness sensor
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_brightness
|
||||
entity_id: "${light_entity}"
|
||||
attribute: brightness
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !std::isnan(x);'
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_brightness_received = false;
|
||||
if (!first_brightness_received) {
|
||||
first_brightness_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
value: !lambda return int(x);
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
text: !lambda |-
|
||||
int percent = int((x / 255.0f) * 100 + 0.5f);
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "%d%%", percent);
|
||||
return std::string(buf);
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
# Color temp sensor
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_color_temp
|
||||
entity_id: "${light_entity}"
|
||||
attribute: color_temp_kelvin
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !std::isnan(x);'
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_temp_received = false;
|
||||
if (!first_temp_received) {
|
||||
first_temp_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_color_temp
|
||||
value: !lambda return x;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_color_temp_slider
|
||||
value: !lambda return int(x);
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_is_temp_mode) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${widget_name}_update_color_temp_preview
|
||||
kelvin: !lambda return x;
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_state
|
||||
entity_id: "${light_entity}"
|
||||
on_value:
|
||||
- lambda: |-
|
||||
bool is_on = (x == "on");
|
||||
bool was_on = id(${widget_name}_light_is_on);
|
||||
id(${widget_name}_light_is_on) = is_on;
|
||||
|
||||
static bool first_state_received = false;
|
||||
if (!first_state_received) {
|
||||
first_state_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: color_steel_blue
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: color_white
|
||||
shadow_opa: TRANSP
|
||||
else:
|
||||
- lambda: |-
|
||||
if (id(${widget_name}_mode_switching)) return;
|
||||
std::string rgb_str = id(${widget_name}_light_rgb_color).state;
|
||||
size_t start = rgb_str.find('(') + 1;
|
||||
size_t first_comma = rgb_str.find(',', start);
|
||||
size_t second_comma = rgb_str.find(',', first_comma + 1);
|
||||
size_t end = rgb_str.find(')', second_comma);
|
||||
if (start < first_comma && first_comma < second_comma && second_comma < end) {
|
||||
int red = atoi(rgb_str.substr(start, first_comma - start).c_str());
|
||||
int green = atoi(rgb_str.substr(first_comma + 1, second_comma - first_comma - 1).c_str());
|
||||
int blue = atoi(rgb_str.substr(second_comma + 1, end - second_comma - 1).c_str());
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
}
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_hs
|
||||
entity_id: "${light_entity}"
|
||||
attribute: hs_color
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: "return x != \"None\" && !x.empty();"
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_hs_received = false;
|
||||
if (!first_hs_received) {
|
||||
first_hs_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- lambda: |-
|
||||
id(${widget_name}_updating_from_ha) = true;
|
||||
std::string s = x;
|
||||
size_t start = s.find('(') + 1;
|
||||
size_t comma = s.find(',');
|
||||
size_t end = s.find(')');
|
||||
float hue = 0.0f, sat = 0.0f;
|
||||
if (start < comma && comma < end) {
|
||||
hue = atof(s.substr(start, comma - start).c_str());
|
||||
sat = atof(s.substr(comma + 1, end - comma - 1).c_str());
|
||||
}
|
||||
id(${widget_name}_current_hue) = hue;
|
||||
id(${widget_name}_current_saturation) = sat;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_hue_slider
|
||||
value: !lambda "return id(${widget_name}_current_hue);"
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_saturation_slider
|
||||
value: !lambda "return id(${widget_name}_current_saturation) * 255.0f / 100.0f;"
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_saturation_state
|
||||
text: !lambda |-
|
||||
return (std::to_string((int)id(${widget_name}_current_saturation)) + "%").c_str();
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_is_temp_mode) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- script.execute: ${widget_name}_update_light_color_from_current_values
|
||||
- lambda: |-
|
||||
id(${widget_name}_updating_from_ha) = false;
|
||||
else:
|
||||
- lambda: |-
|
||||
static bool first_hs_received = false;
|
||||
if (!first_hs_received) {
|
||||
first_hs_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_color
|
||||
entity_id: "${light_entity}"
|
||||
attribute: rgb_color
|
||||
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_name
|
||||
entity_id: "${light_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
text: !lambda return x;
|
||||
|
||||
lvgl:
|
||||
gradients:
|
||||
- id: ${widget_name}_hue_gradient
|
||||
direction: ver
|
||||
dither: none
|
||||
stops:
|
||||
- color: 0xFF0000
|
||||
position: 0
|
||||
- color: 0xFF00FF
|
||||
position: 42
|
||||
- color: 0x0000FF
|
||||
position: 84
|
||||
- color: 0x00FFFF
|
||||
position: 127
|
||||
- color: 0x00FF00
|
||||
position: 169
|
||||
- color: 0xFFFF00
|
||||
position: 212
|
||||
- color: 0xFF0000
|
||||
position: 255
|
||||
|
||||
- id: ${widget_name}_color_temp_gradient
|
||||
direction: ver
|
||||
dither: none
|
||||
stops:
|
||||
- color: 0xA0C8FF
|
||||
position: 0
|
||||
- color: 0xE0F7FF
|
||||
position: 80
|
||||
- color: 0xFFFFFF
|
||||
position: 128
|
||||
- color: 0xFFFFE0
|
||||
position: 175
|
||||
- color: 0xFFD6A0
|
||||
position: 255
|
||||
|
||||
pages:
|
||||
- id: ${widget_name}_light_rgb_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_name
|
||||
y: 20
|
||||
width: 440
|
||||
height: 40
|
||||
align: TOP_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "lightbulb"
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_lightbulb
|
||||
x: 20
|
||||
y: 80
|
||||
width: 200
|
||||
height: 180
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
width: 70
|
||||
height: 70
|
||||
y: 24
|
||||
align: TOP_MID
|
||||
bg_color: color_white
|
||||
shadow_color: color_white
|
||||
shadow_ofs_y: -3
|
||||
shadow_spread: 3
|
||||
shadow_width: 15
|
||||
radius: 40
|
||||
- image:
|
||||
y: 30
|
||||
align: CENTER
|
||||
src: lightbulb_image
|
||||
id: ${widget_name}_lightbulb_image
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on_btn
|
||||
width: 200
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
on_press:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_mode_btn
|
||||
x: 20
|
||||
y: 60
|
||||
width: 200
|
||||
height: 40
|
||||
align: LEFT_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
checkable: true
|
||||
state:
|
||||
checked: false
|
||||
checked:
|
||||
bg_color: color_misty_blue
|
||||
bg_opa: 30%
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_mode_label
|
||||
text_color: color_misty_blue
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text: "TEMP MODE"
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(${widget_name}_is_temp_mode) = !id(${widget_name}_is_temp_mode);
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_is_temp_mode);'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_mode_label
|
||||
text: "TEMP MODE"
|
||||
- script.execute: ${widget_name}_switch_to_temp_mode
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_mode_label
|
||||
text: "RGB MODE"
|
||||
- script.execute: ${widget_name}_switch_to_rgb_mode
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_bg_slider
|
||||
x: -20
|
||||
y: 80
|
||||
width: 220
|
||||
height: 240
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_hue_gradient
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_grad: ${widget_name}_hue_gradient
|
||||
bg_grad_dir: ver
|
||||
shadow_opa: TRANSP
|
||||
hidden: true
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_hue_slider
|
||||
radius: 20
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
width: 100
|
||||
height: 200
|
||||
min_value: 0
|
||||
max_value: 360
|
||||
hidden: true
|
||||
indicator:
|
||||
bg_opa: TRANSP
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_hue
|
||||
value: !lambda "return (float)x;"
|
||||
- script.execute: ${widget_name}_update_light_color_from_current_values
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- script.execute: ${widget_name}_send_hs_color_to_ha
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_color_temp_gradient
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_grad: ${widget_name}_color_temp_gradient
|
||||
bg_grad_dir: ver
|
||||
shadow_opa: TRANSP
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_color_temp_slider
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
min_value: 2000
|
||||
max_value: 6500
|
||||
indicator:
|
||||
bg_opa: TRANSP
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_color_temp
|
||||
value: !lambda return x;
|
||||
- script.execute:
|
||||
id: ${widget_name}_update_color_temp_preview
|
||||
kelvin: !lambda return x;
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
color_temp_kelvin: !lambda return int(x);
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_bg_bs_sliders
|
||||
x: -20
|
||||
y: -20
|
||||
width: 360
|
||||
height: 120
|
||||
align: BOTTOM_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_brightness_pos
|
||||
pad_all: 0
|
||||
width: 320
|
||||
height: 40
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_brightness_icon
|
||||
x: 0
|
||||
y: 0
|
||||
align: LEFT_MID
|
||||
text_font: icons_24
|
||||
text_color: color_misty_blue
|
||||
text: "${brightness_icon}"
|
||||
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
x: 0
|
||||
y: 0
|
||||
align: RIGHT_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "100%"
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
align: CENTER
|
||||
x: -10
|
||||
y: 1
|
||||
width: 220
|
||||
height: 10
|
||||
min_value: 3
|
||||
max_value: 255
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
radius: 30
|
||||
knob:
|
||||
bg_color: color_misty_blue
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
text: !lambda |-
|
||||
int percent = int((x / 255.0f) * 100 + 0.5f);
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "%d%%", percent);
|
||||
return std::string(buf);
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
brightness: !lambda return int(x);
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_saturation_container
|
||||
pad_all: 0
|
||||
width: 320
|
||||
height: 40
|
||||
align: BOTTOM_MID
|
||||
bg_opa: TRANSP
|
||||
border_width: 0
|
||||
hidden: true
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_saturation_icon
|
||||
x: 0
|
||||
y: 0
|
||||
align: LEFT_MID
|
||||
text_font: icons_24
|
||||
text_color: color_misty_blue
|
||||
text: "${saturation_icon}"
|
||||
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_saturation_state
|
||||
x: 0
|
||||
y: 0
|
||||
align: RIGHT_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "100%"
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_saturation_slider
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
align: CENTER
|
||||
x: -10
|
||||
y: 0
|
||||
width: 220
|
||||
height: 10
|
||||
min_value: 1
|
||||
max_value: 255
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
knob:
|
||||
bg_color: color_misty_blue
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_saturation
|
||||
value: !lambda "return (float)x * 100.0f / 255.0f;"
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_saturation_state
|
||||
text: !lambda |-
|
||||
int percent = int((float)x * 100.0f / 255.0f + 0.5f);
|
||||
return (std::to_string(percent) + "%").c_str();
|
||||
- script.execute: ${widget_name}_update_light_color_from_current_values
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- script.execute: ${widget_name}_send_hs_color_to_ha
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_exit_on_btn
|
||||
x: 20
|
||||
y: -20
|
||||
width: 60
|
||||
height: 120
|
||||
align: BOTTOM_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_exit_on_icon
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
then:
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: lights_group_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
script:
|
||||
- id: ${widget_name}_check_all_data_ready
|
||||
mode: restart
|
||||
then:
|
||||
- delay: 500ms
|
||||
- lambda: |-
|
||||
if (id(${widget_name}_sensors_ready_count) >= 4) {
|
||||
if (!id(${widget_name}_ha_data_received)) {
|
||||
id(${widget_name}_ha_data_received) = true;
|
||||
id(${widget_name}_updating_from_ha) = false;
|
||||
id(${widget_name}_switch_to_temp_mode).execute();
|
||||
}
|
||||
}
|
||||
|
||||
- id: ${widget_name}_switch_to_temp_mode
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'true'
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_hue_slider
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_hue_gradient
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_saturation_container
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_color_temp_slider
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_color_temp_gradient
|
||||
- lvgl.obj.update:
|
||||
id: ${widget_name}_light_rgb_brightness_pos
|
||||
align: CENTER
|
||||
- delay: 500ms
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'false'
|
||||
|
||||
- id: ${widget_name}_switch_to_rgb_mode
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'true'
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_hue_slider
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_hue_gradient
|
||||
- lvgl.widget.show: ${widget_name}_light_rgb_saturation_container
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_color_temp_slider
|
||||
- lvgl.widget.hide: ${widget_name}_light_rgb_color_temp_gradient
|
||||
- lvgl.obj.update:
|
||||
id: ${widget_name}_light_rgb_brightness_pos
|
||||
align: TOP_MID
|
||||
- delay: 500ms
|
||||
- globals.set:
|
||||
id: ${widget_name}_mode_switching
|
||||
value: 'false'
|
||||
|
||||
- id: ${widget_name}_update_light_color_from_current_values
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${widget_name}_hsv_to_rgb_and_update
|
||||
hue: !lambda "return id(${widget_name}_current_hue);"
|
||||
saturation: !lambda "return id(${widget_name}_current_saturation);"
|
||||
brightness: 1.0
|
||||
|
||||
- id: ${widget_name}_update_color_temp_preview
|
||||
parameters:
|
||||
kelvin: float
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on) && !id(${widget_name}_mode_switching);'
|
||||
then:
|
||||
- lambda: |-
|
||||
float temp = kelvin / 100.0f;
|
||||
float r, g, b;
|
||||
|
||||
if (temp <= 66.0f) {
|
||||
r = 255.0f;
|
||||
g = 99.4708025861f * logf(temp) - 161.1195681661f;
|
||||
if (temp <= 19.0f) {
|
||||
b = 0.0f;
|
||||
} else {
|
||||
b = 138.5177312231f * logf(temp - 10.0f) - 305.0447927307f;
|
||||
}
|
||||
} else {
|
||||
r = 329.698727446f * powf(temp - 60.0f, -0.1332047592f);
|
||||
g = 288.1221695283f * powf(temp - 60.0f, -0.0755148492f);
|
||||
b = 255.0f;
|
||||
}
|
||||
|
||||
r = std::clamp(r, 0.0f, 255.0f);
|
||||
g = std::clamp(g, 0.0f, 255.0f);
|
||||
b = std::clamp(b, 0.0f, 255.0f);
|
||||
|
||||
int red = static_cast<int>(r);
|
||||
int green = static_cast<int>(g);
|
||||
int blue = static_cast<int>(b);
|
||||
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
|
||||
- id: ${widget_name}_update_light_button_color
|
||||
parameters:
|
||||
red: int
|
||||
green: int
|
||||
blue: int
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
shadow_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
shadow_opa: 100%
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
|
||||
- id: ${widget_name}_hsv_to_rgb_and_update
|
||||
parameters:
|
||||
hue: float
|
||||
saturation: float
|
||||
brightness: float
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lambda: |-
|
||||
float h = hue;
|
||||
float s = saturation / 100.0f;
|
||||
float v = brightness;
|
||||
|
||||
float c = v * s;
|
||||
float x_val = c * (1.0f - abs(fmod(h / 60.0f, 2.0f) - 1.0f));
|
||||
float m = v - c;
|
||||
|
||||
float r, g, b;
|
||||
if (h >= 0 && h < 60) {
|
||||
r = c; g = x_val; b = 0;
|
||||
} else if (h >= 60 && h < 120) {
|
||||
r = x_val; g = c; b = 0;
|
||||
} else if (h >= 120 && h < 180) {
|
||||
r = 0; g = c; b = x_val;
|
||||
} else if (h >= 180 && h < 240) {
|
||||
r = 0; g = x_val; b = c;
|
||||
} else if (h >= 240 && h < 300) {
|
||||
r = x_val; g = 0; b = c;
|
||||
} else {
|
||||
r = c; g = 0; b = x_val;
|
||||
}
|
||||
|
||||
int red = (int)((r + m) * 255.0f);
|
||||
int green = (int)((g + m) * 255.0f);
|
||||
int blue = (int)((b + m) * 255.0f);
|
||||
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
|
||||
- id: ${widget_name}_send_hs_color_to_ha
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
data_template:
|
||||
hs_color: "{{ (hue|float, sat|float)|list }}"
|
||||
variables:
|
||||
hue: !lambda "return id(${widget_name}_current_hue);"
|
||||
sat: !lambda "return id(${widget_name}_current_saturation);"
|
||||
|
||||
|
||||
18
esphome/widgets/light/light_state.yaml
Normal file
18
esphome/widgets/light/light_state.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_state
|
||||
entity_id: "${light_entity}"
|
||||
on_value:
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "on";'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: color_amber
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: color_steel_blue
|
||||
|
||||
470
esphome/widgets/light/light_temp_color_widget.yaml
Normal file
470
esphome/widgets/light/light_temp_color_widget.yaml
Normal file
@@ -0,0 +1,470 @@
|
||||
substitutions:
|
||||
|
||||
brightness_icon: "\U0000e900"
|
||||
exit_icon: "\U0000e902"
|
||||
|
||||
globals:
|
||||
- id: ${widget_name}_light_is_on
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_current_brightness
|
||||
type: float
|
||||
initial_value: '1.0'
|
||||
- id: ${widget_name}_current_color_temp
|
||||
type: float
|
||||
initial_value: '3000.0'
|
||||
- id: ${widget_name}_updating_from_ha
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_ha_data_received
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
- id: ${widget_name}_sensors_ready_count
|
||||
type: int
|
||||
initial_value: '0'
|
||||
|
||||
sensor:
|
||||
# Brightness sensor
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_brightness
|
||||
entity_id: "${light_entity}"
|
||||
attribute: brightness
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !std::isnan(x);'
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_brightness_received = false;
|
||||
if (!first_brightness_received) {
|
||||
first_brightness_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
value: !lambda return int(x);
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
text: !lambda |-
|
||||
int percent = int((x / 255.0f) * 100 + 0.5f);
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "%d%%", percent);
|
||||
return std::string(buf);
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
# Color temp sensor
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_sensor_color_temp
|
||||
entity_id: "${light_entity}"
|
||||
attribute: color_temp_kelvin
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !std::isnan(x);'
|
||||
then:
|
||||
- lambda: |-
|
||||
static bool first_temp_received = false;
|
||||
if (!first_temp_received) {
|
||||
first_temp_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_color_temp
|
||||
value: !lambda return x;
|
||||
- lvgl.slider.update:
|
||||
id: ${widget_name}_light_rgb_color_temp_slider
|
||||
value: !lambda return int(x);
|
||||
- script.execute:
|
||||
id: ${widget_name}_update_color_temp_preview
|
||||
kelvin: !lambda return x;
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_state
|
||||
entity_id: "${light_entity}"
|
||||
on_value:
|
||||
- lambda: |-
|
||||
bool is_on = (x == "on");
|
||||
bool was_on = id(${widget_name}_light_is_on);
|
||||
id(${widget_name}_light_is_on) = is_on;
|
||||
|
||||
static bool first_state_received = false;
|
||||
if (!first_state_received) {
|
||||
first_state_received = true;
|
||||
id(${widget_name}_sensors_ready_count) += 1;
|
||||
}
|
||||
|
||||
# Обновляем UI только при выключении
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: color_steel_blue
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: color_white
|
||||
shadow_opa: TRANSP
|
||||
else:
|
||||
- lambda: |-
|
||||
std::string rgb_str = id(${widget_name}_light_rgb_color).state;
|
||||
size_t start = rgb_str.find('(') + 1;
|
||||
size_t first_comma = rgb_str.find(',', start);
|
||||
size_t second_comma = rgb_str.find(',', first_comma + 1);
|
||||
size_t end = rgb_str.find(')', second_comma);
|
||||
if (start < first_comma && first_comma < second_comma && second_comma < end) {
|
||||
int red = atoi(rgb_str.substr(start, first_comma - start).c_str());
|
||||
int green = atoi(rgb_str.substr(first_comma + 1, second_comma - first_comma - 1).c_str());
|
||||
int blue = atoi(rgb_str.substr(second_comma + 1, end - second_comma - 1).c_str());
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
}
|
||||
- script.execute: ${widget_name}_check_all_data_ready
|
||||
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_color
|
||||
entity_id: "${light_entity}"
|
||||
attribute: rgb_color
|
||||
|
||||
|
||||
- platform: homeassistant
|
||||
id: ${widget_name}_light_rgb_name
|
||||
entity_id: "${light_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
text: !lambda return x;
|
||||
|
||||
lvgl:
|
||||
gradients:
|
||||
- id: ${widget_name}_color_temp_gradient
|
||||
direction: ver
|
||||
dither: none
|
||||
stops:
|
||||
- color: 0xA0C8FF
|
||||
position: 0
|
||||
- color: 0xE0F7FF
|
||||
position: 80
|
||||
- color: 0xFFFFFF
|
||||
position: 128
|
||||
- color: 0xFFFFE0
|
||||
position: 175
|
||||
- color: 0xFFD6A0
|
||||
position: 255
|
||||
|
||||
pages:
|
||||
- id: ${widget_name}_light_rgb_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_name
|
||||
y: 20
|
||||
width: 440
|
||||
height: 40
|
||||
align: TOP_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_lable_name
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "lightbulb"
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_bg_lightbulb
|
||||
x: 20
|
||||
y: 80
|
||||
width: 200
|
||||
height: 280
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
width: 70
|
||||
height: 70
|
||||
y: 74
|
||||
align: TOP_MID
|
||||
bg_color: color_white
|
||||
shadow_color: color_white
|
||||
shadow_ofs_y: -3
|
||||
shadow_spread: 3
|
||||
shadow_width: 15
|
||||
radius: 40
|
||||
- image:
|
||||
y: 30
|
||||
align: CENTER
|
||||
src: lightbulb_image
|
||||
id: ${widget_name}_lightbulb_image
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_light_on_btn
|
||||
width: 200
|
||||
height: 280
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
on_press:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_bg_slider
|
||||
x: -20
|
||||
y: 80
|
||||
width: 220
|
||||
height: 280
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_color_temp_gradient
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_grad: ${widget_name}_color_temp_gradient
|
||||
bg_grad_dir: ver
|
||||
shadow_opa: TRANSP
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_color_temp_slider
|
||||
radius: 20
|
||||
width: 100
|
||||
height: 200
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
min_value: 2000
|
||||
max_value: 6500
|
||||
indicator:
|
||||
bg_opa: TRANSP
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_color_temp
|
||||
value: !lambda return x;
|
||||
- script.execute:
|
||||
id: ${widget_name}_update_color_temp_preview
|
||||
kelvin: !lambda return x;
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
color_temp_kelvin: !lambda return int(x);
|
||||
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_bg_bs_sliders
|
||||
x: -20
|
||||
y: -20
|
||||
width: 360
|
||||
height: 80
|
||||
align: BOTTOM_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
id: ${widget_name}_light_rgb_brightness_pos
|
||||
pad_all: 0
|
||||
width: 320
|
||||
height: 40
|
||||
align: CENTER
|
||||
bg_opa: TRANSP
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_brightness_icon
|
||||
x: 0
|
||||
y: 0
|
||||
align: LEFT_MID
|
||||
text_font: icons_24
|
||||
text_color: color_misty_blue
|
||||
text: "${brightness_icon}"
|
||||
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
x: 0
|
||||
y: 0
|
||||
align: RIGHT_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "100%"
|
||||
|
||||
- slider:
|
||||
id: ${widget_name}_light_rgb_brightness_slider
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
align: CENTER
|
||||
x: -10
|
||||
y: 1
|
||||
width: 220
|
||||
height: 10
|
||||
min_value: 3
|
||||
max_value: 255
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
radius: 30
|
||||
knob:
|
||||
bg_color: color_misty_blue
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(${widget_name}_updating_from_ha) && id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- globals.set:
|
||||
id: ${widget_name}_current_brightness
|
||||
value: !lambda return x;
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_rgb_brightness_state
|
||||
text: !lambda |-
|
||||
int percent = int((x / 255.0f) * 100 + 0.5f);
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "%d%%", percent);
|
||||
return std::string(buf);
|
||||
on_release:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_ha_data_received);'
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: "${light_entity}"
|
||||
brightness: !lambda return int(x);
|
||||
|
||||
- button:
|
||||
id: ${widget_name}_light_rgb_exit_on_btn
|
||||
x: 20
|
||||
y: -20
|
||||
width: 60
|
||||
height: 80
|
||||
align: BOTTOM_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${widget_name}_light_rgb_exit_on_icon
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
then:
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: lights_group_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
script:
|
||||
- id: ${widget_name}_check_all_data_ready
|
||||
mode: restart
|
||||
then:
|
||||
- delay: 500ms
|
||||
- lambda: |-
|
||||
if (id(${widget_name}_sensors_ready_count) >= 3) {
|
||||
if (!id(${widget_name}_ha_data_received)) {
|
||||
id(${widget_name}_ha_data_received) = true;
|
||||
id(${widget_name}_updating_from_ha) = false;
|
||||
}
|
||||
}
|
||||
|
||||
- id: ${widget_name}_update_color_temp_preview
|
||||
parameters:
|
||||
kelvin: float
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lambda: |-
|
||||
float temp = kelvin / 100.0f;
|
||||
float r, g, b;
|
||||
|
||||
if (temp <= 66.0f) {
|
||||
r = 255.0f;
|
||||
g = 99.4708025861f * logf(temp) - 161.1195681661f;
|
||||
if (temp <= 19.0f) {
|
||||
b = 0.0f;
|
||||
} else {
|
||||
b = 138.5177312231f * logf(temp - 10.0f) - 305.0447927307f;
|
||||
}
|
||||
} else {
|
||||
r = 329.698727446f * powf(temp - 60.0f, -0.1332047592f);
|
||||
g = 288.1221695283f * powf(temp - 60.0f, -0.0755148492f);
|
||||
b = 255.0f;
|
||||
}
|
||||
|
||||
r = std::clamp(r, 0.0f, 255.0f);
|
||||
g = std::clamp(g, 0.0f, 255.0f);
|
||||
b = std::clamp(b, 0.0f, 255.0f);
|
||||
|
||||
int red = static_cast<int>(r);
|
||||
int green = static_cast<int>(g);
|
||||
int blue = static_cast<int>(b);
|
||||
|
||||
id(${widget_name}_update_light_button_color).execute(red, green, blue);
|
||||
|
||||
- id: ${widget_name}_update_light_button_color
|
||||
parameters:
|
||||
red: int
|
||||
green: int
|
||||
blue: int
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${widget_name}_light_is_on);'
|
||||
then:
|
||||
- lvgl.button.update:
|
||||
id: ${widget_name}_light_rgb_light_on
|
||||
bg_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
shadow_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
shadow_opa: 100%
|
||||
- lvgl.label.update:
|
||||
id: ${widget_name}_light_on
|
||||
text_color: !lambda |-
|
||||
return lv_color_make(red, green, blue);
|
||||
46
esphome/widgets/light/lights_config.yaml
Normal file
46
esphome/widgets/light/lights_config.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
substitutions:
|
||||
|
||||
light_entity_1: "light.lamp_tafel"
|
||||
light_entity_2: "light.ikea_of_sweden_tradfri_bulb_e27_ww_clear_250lm"
|
||||
light_entity_3: "light.ikea_of_sweden_stoftmoln_ceiling_wall_lamp_ww37"
|
||||
light_entity_4: "light.lamp_kast"
|
||||
|
||||
light_widget_name_1: "lamptafel"
|
||||
light_widget_name_2: "lampbank"
|
||||
light_widget_name_3: "lampzitkamer"
|
||||
light_widget_name_4: "lampkast"
|
||||
|
||||
|
||||
light_label_name_1: "Tafel"
|
||||
light_label_name_2: "Bank"
|
||||
light_label_name_3: "Zithoek"
|
||||
light_label_name_4: "Kast"
|
||||
|
||||
packages:
|
||||
light_panel: !include lights_panel.yaml
|
||||
|
||||
light_1: !include
|
||||
file: light_rgb_widget.yaml
|
||||
vars:
|
||||
light_entity: "${light_entity_1}"
|
||||
widget_name: "${light_widget_name_1}"
|
||||
|
||||
light_2: !include
|
||||
file: light_rgb_widget_slider.yaml
|
||||
vars:
|
||||
light_entity: "${light_entity_2}"
|
||||
widget_name: "${light_widget_name_2}"
|
||||
|
||||
light_3: !include
|
||||
file: light_temp_color_widget.yaml
|
||||
vars:
|
||||
light_entity: "${light_entity_3}"
|
||||
widget_name: "${light_widget_name_3}"
|
||||
|
||||
light_4: !include
|
||||
file: light_brightness_widget.yaml
|
||||
vars:
|
||||
light_entity: "${light_entity_4}"
|
||||
widget_name: "${light_widget_name_4}"
|
||||
|
||||
|
||||
208
esphome/widgets/light/lights_panel.yaml
Normal file
208
esphome/widgets/light/lights_panel.yaml
Normal file
@@ -0,0 +1,208 @@
|
||||
substitutions:
|
||||
|
||||
exit_icon: "\U0000e902"
|
||||
settings_icon: "\U0000e903"
|
||||
info_icon: "\U0000e904"
|
||||
devices_icon: "\U0000e905"
|
||||
home_icon: "\U0000e906"
|
||||
ceiling_icon: "\U0000e907"
|
||||
lightbulb_icon: "\U0000e908"
|
||||
spotlight_group_icon: "\U0000e915"
|
||||
desk_lamp_icon: "\U0000e916"
|
||||
pendant_lamp_icon: "\U0000e917"
|
||||
ceiling_lamp_icon: "\U0000e918"
|
||||
ceiling_lamp_variant_icon: "\U0000e921"
|
||||
night_lamp_icon: "\U0000e919"
|
||||
swipe_icon: "\U0000e91a"
|
||||
|
||||
|
||||
lvgl:
|
||||
pages:
|
||||
- id: lights_group_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
|
||||
- button:
|
||||
id: ${light_widget_name_1}_btn
|
||||
x: 20
|
||||
y: 20
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${light_widget_name_1}_light_on
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${spotlight_group_icon}"
|
||||
- label:
|
||||
id: ${light_widget_name_1}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${light_label_name_1}"
|
||||
|
||||
|
||||
- button:
|
||||
id: ${light_widget_name_2}_btn
|
||||
x: 250
|
||||
y: 20
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${light_widget_name_2}_light_on
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${pendant_lamp_icon}"
|
||||
- label:
|
||||
id: ${light_widget_name_2}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${light_label_name_2}"
|
||||
|
||||
|
||||
- button:
|
||||
id: ${light_widget_name_3}_btn
|
||||
x: 20
|
||||
y: 200
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${light_widget_name_3}_light_on
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${ceiling_lamp_variant_icon}"
|
||||
- label:
|
||||
id: ${light_widget_name_3}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${light_label_name_3}"
|
||||
|
||||
|
||||
- button:
|
||||
id: ${light_widget_name_4}_btn
|
||||
x: 250
|
||||
y: 200
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${light_widget_name_4}_light_on
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${night_lamp_icon}"
|
||||
- label:
|
||||
id: ${light_widget_name_4}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${light_label_name_4}"
|
||||
|
||||
binary_sensor:
|
||||
- platform: lvgl
|
||||
id: ${light_widget_name_1}_btn_long_sensor
|
||||
widget: ${light_widget_name_1}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity_1}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${light_widget_name_1}_light_rgb_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
- platform: lvgl
|
||||
id: ${light_widget_name_2}_btn_long_sensor
|
||||
widget: ${light_widget_name_2}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity_2}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${light_widget_name_2}_light_rgb_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
- platform: lvgl
|
||||
id: ${light_widget_name_3}_btn_long_sensor
|
||||
widget: ${light_widget_name_3}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity_3}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${light_widget_name_3}_light_rgb_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
- platform: lvgl
|
||||
id: ${light_widget_name_4}_btn_long_sensor
|
||||
widget: ${light_widget_name_4}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: light.toggle
|
||||
data:
|
||||
entity_id: "${light_entity_4}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${light_widget_name_4}_light_rgb_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
139
esphome/widgets/loading_page.yaml
Normal file
139
esphome/widgets/loading_page.yaml
Normal file
@@ -0,0 +1,139 @@
|
||||
globals:
|
||||
- id: ha_connected
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
|
||||
lvgl:
|
||||
top_layer:
|
||||
widgets:
|
||||
- button:
|
||||
id: loading_page
|
||||
bg_color: color_slate_blue_gray
|
||||
shadow_opa: TRANSP
|
||||
width: 100%
|
||||
height: 100%
|
||||
widgets:
|
||||
- image:
|
||||
y: 30
|
||||
align: TOP_MID
|
||||
src: ha_img
|
||||
|
||||
- obj:
|
||||
id: boot_homeassistant
|
||||
y: 180
|
||||
width: 300
|
||||
height: 100
|
||||
pad_all: 0
|
||||
align: TOP_MID
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: boot_homeassistant_label
|
||||
align: LEFT_MID
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
text: "Connecting to API..."
|
||||
- spinner:
|
||||
id: boot_homeassistant_spiner
|
||||
width: 50
|
||||
height: 50
|
||||
align: RIGHT_MID
|
||||
spin_time: 2s
|
||||
arc_length: 60deg
|
||||
arc_width: 5
|
||||
arc_color: color_steel_blue
|
||||
indicator:
|
||||
arc_color: color_misty_blue
|
||||
arc_width: 5
|
||||
- obj:
|
||||
id: boot_synchronization
|
||||
y: 180
|
||||
width: 300
|
||||
height: 60
|
||||
pad_all: 0
|
||||
align: TOP_MID
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
radius: 10
|
||||
hidden: true
|
||||
widgets:
|
||||
- label:
|
||||
id: boot_synchronization_label
|
||||
align: TOP_MID
|
||||
y: 0
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
text: "Synchronization..."
|
||||
- bar:
|
||||
id: boot_synchronization_bar
|
||||
y: 0
|
||||
width: 300
|
||||
value: 0
|
||||
align: BOTTOM_MID
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
animated: true
|
||||
bg_color: color_steel_blue
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
- image:
|
||||
y: -30
|
||||
align: BOTTOM_MID
|
||||
src: esphome_img
|
||||
|
||||
|
||||
script:
|
||||
- id: check_boot_status
|
||||
then:
|
||||
- lambda: |-
|
||||
if (id(ha_connected)) {
|
||||
lv_obj_add_flag(id(boot_homeassistant), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(id(boot_synchronization), LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
id(start_sync_animation).execute();
|
||||
}
|
||||
|
||||
- id: start_sync_animation
|
||||
then:
|
||||
- delay: 1s
|
||||
- lvgl.bar.update:
|
||||
id: boot_synchronization_bar
|
||||
value: 50
|
||||
|
||||
- delay: 1s
|
||||
- lvgl.bar.update:
|
||||
id: boot_synchronization_bar
|
||||
value: 100
|
||||
|
||||
- delay: 500ms
|
||||
|
||||
- lvgl.widget.hide: loading_page
|
||||
|
||||
|
||||
- id: on_ha_connected
|
||||
then:
|
||||
- lambda: |-
|
||||
if (!id(ha_connected)) {
|
||||
id(ha_connected) = true;
|
||||
lv_label_set_text(id(boot_homeassistant_label), "Home Assistant Connected!");
|
||||
lv_obj_add_flag(id(boot_homeassistant_spiner), LV_OBJ_FLAG_HIDDEN);
|
||||
id(check_boot_status).execute();
|
||||
}
|
||||
|
||||
api:
|
||||
on_client_connected:
|
||||
- lambda: |-
|
||||
if (0 == client_info.find("Home Assistant ")) {
|
||||
id(on_ha_connected).execute();
|
||||
}
|
||||
on_client_disconnected:
|
||||
- lambda: |-
|
||||
if (0 == client_info.find("Home Assistant ")) {
|
||||
id(ha_connected) = false;
|
||||
}
|
||||
560
esphome/widgets/media_player/media_player.yaml
Normal file
560
esphome/widgets/media_player/media_player.yaml
Normal file
@@ -0,0 +1,560 @@
|
||||
substitutions:
|
||||
ha_server: "http://192.168.1.44:8123"
|
||||
media_player_entity: "media_player.yandex_station_m00bv9j00dc7sg"
|
||||
|
||||
power_icon: "\U0000e909"
|
||||
play_icon: "\U0000e90a"
|
||||
pause_icon: "\U0000e90b"
|
||||
back_step_icon: "\U0000e90c"
|
||||
forward_step_icon: "\U0000e90d"
|
||||
volume_off_icon: "\U0000e90e"
|
||||
volume_on_icon: "\U0000e90f"
|
||||
volume_minus_icon: "\U0000e910"
|
||||
volume_plus_icon: "\U0000e911"
|
||||
repeat_all_icon: "\U0000e912"
|
||||
repeat_off_icon: "\U0000e913"
|
||||
repeat_one_icon: "\U0000e914"
|
||||
|
||||
globals:
|
||||
- id: repeat_modes
|
||||
type: std::vector<std::string>
|
||||
initial_value: '{"all", "one", "off"}'
|
||||
- id: repeat_icons
|
||||
type: std::vector<std::string>
|
||||
initial_value: '{"${repeat_all_icon}", "${repeat_one_icon}", "${repeat_off_icon}"}'
|
||||
- id: current_repeat_mode_idx
|
||||
type: int
|
||||
initial_value: '0'
|
||||
- id: tmp_repeat_mode
|
||||
type: std::string
|
||||
restore_value: no
|
||||
initial_value: '"all"'
|
||||
- id: tmp_repeat_icon
|
||||
type: std::string
|
||||
restore_value: no
|
||||
initial_value: '"${repeat_all_icon}"'
|
||||
- id: cover_url
|
||||
type: std::string
|
||||
restore_value: no
|
||||
initial_value: '""'
|
||||
- id: duration_slider_user_interaction
|
||||
type: bool
|
||||
restore_value: no
|
||||
initial_value: 'false'
|
||||
- id: slider_position
|
||||
type: float
|
||||
restore_value: no
|
||||
initial_value: '0.0'
|
||||
- id: pending_cover_url
|
||||
type: std::string
|
||||
restore_value: no
|
||||
initial_value: '""'
|
||||
- id: pending_repeat_value
|
||||
type: std::string
|
||||
restore_value: no
|
||||
initial_value: '""'
|
||||
|
||||
script:
|
||||
- id: update_cover_script
|
||||
mode: restart
|
||||
then:
|
||||
- lambda: |-
|
||||
std::string url = id(pending_cover_url);
|
||||
id(cover_url) = url;
|
||||
- homeassistant.action:
|
||||
action: display_tools.save_media_cover
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
size: small
|
||||
- delay: 1s
|
||||
- online_image.release: media_image_jpeg
|
||||
- online_image.set_url:
|
||||
id: media_image_jpeg
|
||||
url: "${ha_server}/local/display_tools/cover.jpeg"
|
||||
|
||||
- id: update_repeat_mode_script
|
||||
mode: restart
|
||||
then:
|
||||
- lambda: |-
|
||||
std::string x = id(pending_repeat_value);
|
||||
auto modes = id(repeat_modes);
|
||||
auto icons = id(repeat_icons);
|
||||
for (int i = 0; i < modes.size(); i++) {
|
||||
if (modes[i] == x) {
|
||||
id(current_repeat_mode_idx) = i;
|
||||
id(tmp_repeat_mode) = modes[i];
|
||||
id(tmp_repeat_icon) = icons[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
- lvgl.label.update:
|
||||
id: media_player_repeat_label
|
||||
text: !lambda 'return id(tmp_repeat_icon);'
|
||||
|
||||
- id: handle_repeat_press_script
|
||||
mode: restart
|
||||
then:
|
||||
- lambda: |-
|
||||
int idx = id(current_repeat_mode_idx);
|
||||
auto modes = id(repeat_modes);
|
||||
auto icons = id(repeat_icons);
|
||||
idx = (idx + 1) % modes.size();
|
||||
id(current_repeat_mode_idx) = idx;
|
||||
std::string new_mode = modes[idx];
|
||||
std::string new_icon = icons[idx];
|
||||
id(tmp_repeat_mode) = new_mode;
|
||||
id(tmp_repeat_icon) = new_icon;
|
||||
- lvgl.label.update:
|
||||
id: media_player_repeat_label
|
||||
text: !lambda 'return id(tmp_repeat_icon);'
|
||||
- homeassistant.action:
|
||||
action: media_player.repeat_set
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
repeat: !lambda 'return id(tmp_repeat_mode);'
|
||||
|
||||
- id: handle_duration_slider_release_script
|
||||
mode: restart
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: media_player.media_seek
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
seek_position: !lambda 'return std::to_string(int(id(slider_position)));'
|
||||
- delay: 2s
|
||||
- lambda: |-
|
||||
id(duration_slider_user_interaction) = false;
|
||||
|
||||
lvgl:
|
||||
pages:
|
||||
- id: media_player_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
|
||||
# Cover
|
||||
- obj:
|
||||
id: media_cover
|
||||
x: 10
|
||||
y: 10
|
||||
width: 140
|
||||
height: 140
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_image_src: media_image_jpeg
|
||||
border_color: color_slate_blue_gray
|
||||
border_width: 10
|
||||
shadow_opa: TRANSP
|
||||
radius: 20
|
||||
|
||||
# Title/Artist/Duration
|
||||
- obj:
|
||||
x: -20
|
||||
y: 20
|
||||
width: 300
|
||||
height: 120
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: media_player_title_label
|
||||
height: 40
|
||||
width: 260
|
||||
long_mode: DOT
|
||||
y: -25
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: nunito_20
|
||||
text: "Title"
|
||||
- label:
|
||||
id: media_player_artist_label
|
||||
height: 30
|
||||
width: 260
|
||||
long_mode: DOT
|
||||
y: 3
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: nunito_16
|
||||
text: "Artist"
|
||||
- slider:
|
||||
id: media_player_duration_pos_slider
|
||||
radius: 2
|
||||
y: 35
|
||||
bg_color: color_slate_blue_gray
|
||||
align: CENTER
|
||||
width: 260
|
||||
height: 5
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
radius: 2
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(duration_slider_user_interaction) = true;
|
||||
on_release:
|
||||
- lambda: |-
|
||||
id(slider_position) = x;
|
||||
- script.execute: handle_duration_slider_release_script
|
||||
|
||||
# Controls
|
||||
- obj:
|
||||
y: 160
|
||||
width: 440
|
||||
height: 120
|
||||
align: TOP_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
# Off
|
||||
- label:
|
||||
x: 10
|
||||
align: LEFT_MID
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_38
|
||||
text: "${power_icon}"
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: media_player.turn_off
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
# back
|
||||
- label:
|
||||
x: -80
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${back_step_icon}"
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: media_player.media_previous_track
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
|
||||
# play / pause
|
||||
- obj:
|
||||
id: media_player_control_play_bg
|
||||
height: 90
|
||||
width: 90
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 80%
|
||||
border_opa: TRANSP
|
||||
radius: 50
|
||||
align: CENTER
|
||||
widgets:
|
||||
- label:
|
||||
id: media_player_state_label
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_48
|
||||
text: "${play_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(media_player_state).state == "playing";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: media_player.media_pause
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
else:
|
||||
- homeassistant.action:
|
||||
action: media_player.media_play
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
|
||||
# forward
|
||||
- label:
|
||||
x: 80
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${forward_step_icon}"
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: media_player.media_next_track
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
|
||||
# repeat
|
||||
- label:
|
||||
id: media_player_repeat_label
|
||||
x: -10
|
||||
align: RIGHT_MID
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_38
|
||||
text: "${repeat_all_icon}"
|
||||
on_press:
|
||||
- script.execute: handle_repeat_press_script
|
||||
|
||||
# Volume
|
||||
- obj:
|
||||
y: 300
|
||||
width: 440
|
||||
height: 80
|
||||
align: TOP_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
# mute
|
||||
- label:
|
||||
id: media_player_mute_label
|
||||
x: 10
|
||||
align: LEFT_MID
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_32
|
||||
text: "${volume_on_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(media_player_is_volume_muted).state;'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: media_player.volume_mute
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
is_volume_muted: "false"
|
||||
else:
|
||||
- homeassistant.action:
|
||||
action: media_player.volume_mute
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
is_volume_muted: "true"
|
||||
|
||||
# vol down
|
||||
- label:
|
||||
id: media_player_vol_down_label
|
||||
x: -280
|
||||
align: RIGHT_MID
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_32
|
||||
text: "${volume_minus_icon}"
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: media_player.volume_down
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
|
||||
# set vol
|
||||
- slider:
|
||||
id: media_player_volume_slider
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
align: RIGHT_MID
|
||||
x: -60
|
||||
width: 200
|
||||
height: 10
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
knob:
|
||||
bg_color: color_misty_blue
|
||||
on_release:
|
||||
- homeassistant.action:
|
||||
action: media_player.volume_set
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
volume_level: !lambda 'return float(x) / 100.0;'
|
||||
|
||||
# vol up
|
||||
- label:
|
||||
id: media_player_vol_up_label
|
||||
x: -10
|
||||
align: RIGHT_MID
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_32
|
||||
text: "${volume_plus_icon}"
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: media_player.volume_up
|
||||
data:
|
||||
entity_id: "${media_player_entity}"
|
||||
|
||||
# Media player name
|
||||
- obj:
|
||||
x: -20
|
||||
y: 400
|
||||
width: 360
|
||||
height: 60
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: media_player_name_label
|
||||
align: CENTER
|
||||
long_mode: DOT
|
||||
text_color: color_misty_blue
|
||||
text_font: nunito_16
|
||||
text: "Friendly name"
|
||||
|
||||
# Return
|
||||
- button:
|
||||
x: 20
|
||||
y: 400
|
||||
width: 60
|
||||
height: 60
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show: devices_page
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
id: media_player_state
|
||||
entity_id: "${media_player_entity}"
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "paused";'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: media_player_state_label
|
||||
x: 0
|
||||
text: "${play_icon}"
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: media_player_state_label
|
||||
x: 0
|
||||
text: "${pause_icon}"
|
||||
|
||||
- platform: homeassistant
|
||||
id: media_player_cover
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: entity_picture
|
||||
on_value:
|
||||
- lambda: |-
|
||||
id(pending_cover_url) = x;
|
||||
- script.execute: update_cover_script
|
||||
|
||||
- platform: homeassistant
|
||||
id: media_player_title_sensor
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: media_title
|
||||
on_value:
|
||||
- delay: 1s
|
||||
- lvgl.label.update:
|
||||
id: media_player_title_label
|
||||
text: !lambda return x;
|
||||
|
||||
- platform: homeassistant
|
||||
id: media_player_artist_sensor
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: media_artist
|
||||
on_value:
|
||||
- delay: 1s
|
||||
- lvgl.label.update:
|
||||
id: media_player_artist_label
|
||||
text: !lambda return x;
|
||||
|
||||
- platform: homeassistant
|
||||
id: media_player_repeat
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: repeat
|
||||
on_value:
|
||||
- lambda: |-
|
||||
id(pending_repeat_value) = x;
|
||||
- script.execute: update_repeat_mode_script
|
||||
|
||||
- platform: homeassistant
|
||||
id: media_player_friendly_name
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
- lvgl.label.update:
|
||||
id: media_player_name_label
|
||||
text: !lambda return x;
|
||||
|
||||
sensor:
|
||||
- platform: homeassistant
|
||||
id: media_player_volume_level
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: volume_level
|
||||
on_value:
|
||||
- lvgl.slider.update:
|
||||
id: media_player_volume_slider
|
||||
value: !lambda 'return int(x * 100);'
|
||||
|
||||
- platform: homeassistant
|
||||
id: media_player_media_duration
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: media_duration
|
||||
on_value:
|
||||
- lambda: |-
|
||||
lv_slider_set_range(id(media_player_duration_pos_slider), 0, x);
|
||||
|
||||
- platform: homeassistant
|
||||
id: media_player_media_position
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: media_position
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return !id(duration_slider_user_interaction);'
|
||||
then:
|
||||
- lvgl.slider.update:
|
||||
id: media_player_duration_pos_slider
|
||||
value: !lambda return x;
|
||||
|
||||
|
||||
binary_sensor:
|
||||
- platform: homeassistant
|
||||
id: media_player_is_volume_muted
|
||||
entity_id: "${media_player_entity}"
|
||||
attribute: is_volume_muted
|
||||
on_state:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x;'
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: media_player_mute_label
|
||||
text: "${volume_off_icon}"
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: media_player_mute_label
|
||||
text: "${volume_on_icon}"
|
||||
|
||||
online_image:
|
||||
- url: "https://www.example.com/example.jpeg"
|
||||
format: JPEG
|
||||
type: RGB565
|
||||
resize: 120x120
|
||||
id: media_image_jpeg
|
||||
on_download_finished:
|
||||
- lvgl.obj.update:
|
||||
id: media_cover
|
||||
bg_image_src: media_image_jpeg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
151
esphome/widgets/menu_controls_main.yaml
Normal file
151
esphome/widgets/menu_controls_main.yaml
Normal file
@@ -0,0 +1,151 @@
|
||||
lvgl:
|
||||
top_layer:
|
||||
widgets:
|
||||
- obj:
|
||||
id: menu_controls_main
|
||||
x: 0
|
||||
y: -20
|
||||
width: 440
|
||||
height: 80
|
||||
pad_all: 10
|
||||
align: BOTTOM_MID
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
radius: 10
|
||||
layout:
|
||||
type: FLEX
|
||||
flex_align_main: SPACE_AROUND
|
||||
flex_align_cross: CENTER
|
||||
widgets:
|
||||
- button:
|
||||
id: home_page_btn
|
||||
clickable: true
|
||||
width: 60
|
||||
height: 60
|
||||
radius: 10
|
||||
bg_color: color_slate_blue_gray
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_36
|
||||
text: "${home_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show:
|
||||
id: home_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
- lvgl.button.update:
|
||||
id: home_page_btn
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
- lvgl.button.update:
|
||||
id: lights_group_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: devices_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: settings_page_btn
|
||||
bg_opa: TRANSP
|
||||
|
||||
- button:
|
||||
id: lights_group_page_btn
|
||||
clickable: true
|
||||
width: 60
|
||||
height: 60
|
||||
radius: 10
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_36
|
||||
text: "${ceiling_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show:
|
||||
id: lights_group_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
- lvgl.button.update:
|
||||
id: lights_group_page_btn
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
- lvgl.button.update:
|
||||
id: home_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: devices_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: settings_page_btn
|
||||
bg_opa: TRANSP
|
||||
- button:
|
||||
id: devices_page_btn
|
||||
clickable: true
|
||||
width: 60
|
||||
height: 60
|
||||
radius: 10
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_36
|
||||
text: "${devices_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show:
|
||||
id: devices_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
- lvgl.button.update:
|
||||
id: devices_page_btn
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
- lvgl.button.update:
|
||||
id: home_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: lights_group_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: settings_page_btn
|
||||
bg_opa: TRANSP
|
||||
- button:
|
||||
id: settings_page_btn
|
||||
clickable: true
|
||||
width: 60
|
||||
height: 60
|
||||
radius: 10
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_36
|
||||
text: "${settings_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show:
|
||||
id: settings_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
- lvgl.button.update:
|
||||
id: settings_page_btn
|
||||
bg_color: color_slate_blue_gray
|
||||
bg_opa: 100%
|
||||
- lvgl.button.update:
|
||||
id: home_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: lights_group_page_btn
|
||||
bg_opa: TRANSP
|
||||
- lvgl.button.update:
|
||||
id: devices_page_btn
|
||||
bg_opa: TRANSP
|
||||
622
esphome/widgets/settings.yaml
Normal file
622
esphome/widgets/settings.yaml
Normal file
@@ -0,0 +1,622 @@
|
||||
globals:
|
||||
|
||||
- id: display_timeout
|
||||
type: int
|
||||
restore_value: true
|
||||
initial_value: "2"
|
||||
|
||||
- id: current_language
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: '6'
|
||||
|
||||
- id: vacuum_translations
|
||||
type: std::map<std::string, std::string>
|
||||
- id: cover_translations
|
||||
type: std::map<std::string, std::string>
|
||||
- id: climate_translations
|
||||
type: std::map<std::string, std::string>
|
||||
- id: weather_translations
|
||||
type: std::map<std::string, std::string>
|
||||
- id: alarm_panel_translations
|
||||
type: std::map<std::string, std::string>
|
||||
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
id: translations_lang
|
||||
entity_id: sensor.display_tools
|
||||
on_value:
|
||||
- lambda: |-
|
||||
std::string lang_code = x;
|
||||
|
||||
int lang_index = id(flag_icon_mapping_index).get(lang_code);
|
||||
if (lang_index != 0 || lang_code == "de") {
|
||||
id(current_language) = lang_index;
|
||||
}
|
||||
|
||||
- lvgl.dropdown.update:
|
||||
id: language_dropdown
|
||||
selected_index: !lambda |-
|
||||
int index = id(flag_icon_mapping_index).get(x);
|
||||
if (index != 0 || x == "de") {
|
||||
return index;
|
||||
}
|
||||
return 6;
|
||||
|
||||
- lvgl.image.update:
|
||||
id: flag_language_image
|
||||
src: !lambda |-
|
||||
int index = id(flag_icon_mapping_index).get(x);
|
||||
if (index != 0 || x == "de") {
|
||||
return id(flag_icon_mapping_image)[index];
|
||||
}
|
||||
return id(flag_icon_mapping_image)[6];
|
||||
|
||||
- platform: homeassistant
|
||||
id: translations_vacuum
|
||||
entity_id: sensor.display_tools
|
||||
attribute: vacuum
|
||||
on_value:
|
||||
then:
|
||||
- lambda: |-
|
||||
if (x.length() > 0) {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, x);
|
||||
|
||||
if (!error) {
|
||||
id(vacuum_translations).clear();
|
||||
for (auto kv : doc.as<JsonObject>()) {
|
||||
id(vacuum_translations)[kv.key().c_str()] = kv.value().as<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- platform: homeassistant
|
||||
id: translations_cover
|
||||
entity_id: sensor.display_tools
|
||||
attribute: cover
|
||||
on_value:
|
||||
then:
|
||||
- lambda: |-
|
||||
if (x.length() > 0) {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, x);
|
||||
|
||||
if (!error) {
|
||||
id(cover_translations).clear();
|
||||
for (auto kv : doc.as<JsonObject>()) {
|
||||
id(cover_translations)[kv.key().c_str()] = kv.value().as<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- platform: homeassistant
|
||||
id: translations_climate
|
||||
entity_id: sensor.display_tools
|
||||
attribute: climate
|
||||
on_value:
|
||||
then:
|
||||
- lambda: |-
|
||||
if (x.length() > 0) {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, x);
|
||||
|
||||
if (!error) {
|
||||
id(climate_translations).clear();
|
||||
for (auto kv : doc.as<JsonObject>()) {
|
||||
id(climate_translations)[kv.key().c_str()] = kv.value().as<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- platform: homeassistant
|
||||
id: translations_weather
|
||||
entity_id: sensor.display_tools
|
||||
attribute: weather
|
||||
on_value:
|
||||
then:
|
||||
- lambda: |-
|
||||
if (x.length() > 0) {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, x);
|
||||
|
||||
if (!error) {
|
||||
id(weather_translations).clear();
|
||||
for (auto kv : doc.as<JsonObject>()) {
|
||||
id(weather_translations)[kv.key().c_str()] = kv.value().as<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- platform: homeassistant
|
||||
id: translations_alarm_panel
|
||||
entity_id: sensor.display_tools
|
||||
attribute: alarm_control_panel
|
||||
on_value:
|
||||
then:
|
||||
- lambda: |-
|
||||
if (x.length() > 0) {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, x);
|
||||
|
||||
if (!error) {
|
||||
id(alarm_panel_translations).clear();
|
||||
for (auto kv : doc.as<JsonObject>()) {
|
||||
id(alarm_panel_translations)[kv.key().c_str()] = kv.value().as<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
script:
|
||||
- id: get_translation
|
||||
parameters:
|
||||
component_param: string
|
||||
key_param: string
|
||||
then:
|
||||
- lambda: |-
|
||||
std::string component = component_param;
|
||||
std::string key = key_param;
|
||||
std::string result = key;
|
||||
|
||||
if (component == "vacuum") {
|
||||
auto it = id(vacuum_translations).find(key);
|
||||
if (it != id(vacuum_translations).end()) {
|
||||
result = it->second;
|
||||
}
|
||||
} else if (component == "cover") {
|
||||
auto it = id(cover_translations).find(key);
|
||||
if (it != id(cover_translations).end()) {
|
||||
result = it->second;
|
||||
}
|
||||
} else if (component == "climate") {
|
||||
auto it = id(climate_translations).find(key);
|
||||
if (it != id(climate_translations).end()) {
|
||||
result = it->second;
|
||||
}
|
||||
} else if (component == "weather") {
|
||||
auto it = id(weather_translations).find(key);
|
||||
if (it != id(weather_translations).end()) {
|
||||
result = it->second;
|
||||
}
|
||||
} else if (component == "alarm_panel") {
|
||||
auto it = id(alarm_panel_translations).find(key);
|
||||
if (it != id(alarm_panel_translations).end()) {
|
||||
result = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
lvgl:
|
||||
|
||||
on_idle:
|
||||
timeout: !lambda "return (id(display_timeout_number).state * 60 * 1000);"
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(display_timeout_number).state >= 0;'
|
||||
then:
|
||||
- logger.log: "LVGL is idle"
|
||||
- light.turn_off: display_backlight
|
||||
- lvgl.pause:
|
||||
else:
|
||||
- logger.log: "LVGL idle, but backlight is on"
|
||||
|
||||
pages:
|
||||
- id: settings_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
# language:
|
||||
- obj:
|
||||
id: language_bg
|
||||
x: 20
|
||||
y: 20
|
||||
width: 440
|
||||
height: 100
|
||||
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: language_label
|
||||
x: 20
|
||||
align: LEFT_MID
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
text: "Language"
|
||||
|
||||
- image:
|
||||
id: flag_language_image
|
||||
x: 160
|
||||
align: LEFT_MID
|
||||
src: !lambda return id(flag_icon_mapping_image)[id(current_language)];
|
||||
|
||||
- dropdown:
|
||||
id: language_dropdown
|
||||
x: 240
|
||||
width: 200
|
||||
align: LEFT_MID
|
||||
options:
|
||||
- Deutsch # de
|
||||
- Español # es
|
||||
- Français # fr
|
||||
- English (GB) # en-GB
|
||||
- Italiano # it
|
||||
- Português # pt
|
||||
- Русский # ru
|
||||
- English (US) # en
|
||||
- Polski # pl
|
||||
- Türkçe # tr
|
||||
- Svenska # sv
|
||||
- Română # ro
|
||||
- Nederlands # nl
|
||||
- Magyar # hu
|
||||
- Bahasa Indonesia # id
|
||||
- Tiếng Việt # vi
|
||||
- Čeština # cs
|
||||
- Suomi # fi
|
||||
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
dropdown_list:
|
||||
bg_color: color_slate_blue_gray
|
||||
shadow_opa: TRANSP
|
||||
border_color: color_misty_blue
|
||||
border_width: 2
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
text_line_space: 7
|
||||
pad_all: 8
|
||||
max_height: 280
|
||||
selected:
|
||||
checked:
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
text_color: color_misty_blue
|
||||
pressed:
|
||||
bg_opa: TRANSP
|
||||
text_color: color_misty_blue
|
||||
indicator:
|
||||
text_opa: TRANSP
|
||||
on_value:
|
||||
- lvgl.image.update:
|
||||
id: flag_language_image
|
||||
src: !lambda return id(flag_icon_mapping_image)[x];
|
||||
- homeassistant.action:
|
||||
action: display_tools.get_translations_esphome
|
||||
data:
|
||||
language: !lambda return id(flag_icon_mapping_name).get(x).c_str();
|
||||
category: entity_component
|
||||
keys: '[
|
||||
"component.vacuum.entity_component._.state.cleaning",
|
||||
"component.vacuum.entity_component._.state.docked",
|
||||
"component.vacuum.entity_component._.state.error",
|
||||
"component.vacuum.entity_component._.state.idle",
|
||||
"component.vacuum.entity_component._.state.off",
|
||||
"component.vacuum.entity_component._.state.on",
|
||||
"component.vacuum.entity_component._.state.paused",
|
||||
"component.vacuum.entity_component._.state.returning",
|
||||
"component.cover.entity_component._.state.closed",
|
||||
"component.cover.entity_component._.state.closing",
|
||||
"component.cover.entity_component._.state.open",
|
||||
"component.cover.entity_component._.state.opening",
|
||||
"component.cover.entity_component._.state.stopped",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.cooling",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.defrosting",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.drying",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.fan",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.heating",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.idle",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.off",
|
||||
"component.weather.entity_component._.state.clear-night",
|
||||
"component.weather.entity_component._.state.cloudy",
|
||||
"component.weather.entity_component._.state.exceptional",
|
||||
"component.weather.entity_component._.state.fog",
|
||||
"component.weather.entity_component._.state.hail",
|
||||
"component.weather.entity_component._.state.lightning",
|
||||
"component.weather.entity_component._.state.lightning-rainy",
|
||||
"component.weather.entity_component._.state.partlycloudy",
|
||||
"component.weather.entity_component._.state.pouring",
|
||||
"component.weather.entity_component._.state.rainy",
|
||||
"component.weather.entity_component._.state.snowy",
|
||||
"component.weather.entity_component._.state.snowy-rainy",
|
||||
"component.weather.entity_component._.state.sunny",
|
||||
"component.weather.entity_component._.state.windy",
|
||||
"component.weather.entity_component._.state.windy-variant",
|
||||
"component.alarm_control_panel.entity_component._.state.armed",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_away",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_custom_bypass",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_home",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_night",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_vacation",
|
||||
"component.alarm_control_panel.entity_component._.state.arming",
|
||||
"component.alarm_control_panel.entity_component._.state.disarmed",
|
||||
"component.alarm_control_panel.entity_component._.state.disarming",
|
||||
"component.alarm_control_panel.entity_component._.state.pending",
|
||||
"component.alarm_control_panel.entity_component._.state.triggered"
|
||||
]'
|
||||
|
||||
# backlight:
|
||||
- obj:
|
||||
id: backlight_bg
|
||||
x: 20
|
||||
y: 140
|
||||
width: 440
|
||||
height: 100
|
||||
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_label
|
||||
x: 20
|
||||
align: LEFT_MID
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
text: "Backlight"
|
||||
|
||||
- slider:
|
||||
id: display_backlight_brightness_slider
|
||||
x: -20
|
||||
radius: 10
|
||||
bg_color: color_slate_blue_gray
|
||||
align: RIGHT_MID
|
||||
width: 260
|
||||
height: 60
|
||||
min_value: 35
|
||||
max_value: 100
|
||||
value: 100
|
||||
indicator:
|
||||
bg_color: color_misty_blue
|
||||
radius: 10
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_release:
|
||||
then:
|
||||
- light.turn_on:
|
||||
id: display_backlight
|
||||
brightness: !lambda return int(x)/ 100.0;
|
||||
|
||||
# sleep mode:
|
||||
- obj:
|
||||
id: sleep_mode_bg
|
||||
x: 20
|
||||
y: 260
|
||||
width: 440
|
||||
height: 100
|
||||
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_timeout_label
|
||||
x: 20
|
||||
align: LEFT_MID
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
text: "Sleep mode"
|
||||
|
||||
- dropdown:
|
||||
id: display_timeout_dropdown
|
||||
x: 220
|
||||
width: 200
|
||||
align: LEFT_MID
|
||||
selected_index: !lambda return id(display_timeout);
|
||||
options:
|
||||
- Never
|
||||
- 1 minute
|
||||
- 5 minutes
|
||||
- 10 minutes
|
||||
- 30 minutes
|
||||
- 1 hour
|
||||
- 6 hours
|
||||
- 12 hours
|
||||
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
dropdown_list:
|
||||
align: CENTER
|
||||
bg_color: color_slate_blue_gray
|
||||
shadow_opa: TRANSP
|
||||
border_color: color_misty_blue
|
||||
border_width: 2
|
||||
text_font: nunito_20
|
||||
text_color: color_misty_blue
|
||||
text_line_space: 10
|
||||
pad_all: 8
|
||||
max_height: 360
|
||||
selected:
|
||||
checked:
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
text_color: color_misty_blue
|
||||
pressed:
|
||||
bg_opa: TRANSP
|
||||
text_color: color_misty_blue
|
||||
indicator:
|
||||
text_opa: TRANSP
|
||||
on_value:
|
||||
then:
|
||||
- number.set:
|
||||
id: display_timeout_number
|
||||
value: !lambda |-
|
||||
static const int backlight_time[] = {-1, 1, 5, 10, 30, 60, 360, 720};
|
||||
return backlight_time[x];
|
||||
- globals.set:
|
||||
id: display_timeout
|
||||
value: !lambda return x;
|
||||
|
||||
number:
|
||||
- platform: template
|
||||
id: display_timeout_number
|
||||
name: LVGL screen timeout
|
||||
optimistic: true
|
||||
unit_of_measurement: "m"
|
||||
initial_value: 10
|
||||
restore_value: true
|
||||
min_value: -1
|
||||
max_value: 720
|
||||
step: 1
|
||||
mode: box
|
||||
|
||||
mapping:
|
||||
- id: flag_icon_mapping_image
|
||||
from: int
|
||||
to: image
|
||||
entries:
|
||||
0: flags_de_img
|
||||
1: flags_es_img
|
||||
2: flags_fr_img
|
||||
3: flags_gb_img
|
||||
4: flags_it_img
|
||||
5: flags_pt_img
|
||||
6: flags_ru_img
|
||||
7: flags_us_img
|
||||
8: flags_pl_img
|
||||
9: flags_tr_img
|
||||
10: flags_sv_img
|
||||
11: flags_ro_img
|
||||
12: flags_nl_img
|
||||
13: flags_hu_img
|
||||
14: flags_id_img
|
||||
15: flags_vi_img
|
||||
16: flags_cs_img
|
||||
17: flags_fi_img
|
||||
|
||||
- id: flag_icon_mapping_name
|
||||
from: int
|
||||
to: string
|
||||
entries:
|
||||
0: de
|
||||
1: es
|
||||
2: fr
|
||||
3: en-GB
|
||||
4: it
|
||||
5: pt
|
||||
6: ru
|
||||
7: en
|
||||
8: pl
|
||||
9: tr
|
||||
10: sv
|
||||
11: ro
|
||||
12: nl
|
||||
13: hu
|
||||
14: id
|
||||
15: vi
|
||||
16: cs
|
||||
17: fi
|
||||
|
||||
- id: flag_icon_mapping_index
|
||||
from: string
|
||||
to: int
|
||||
entries:
|
||||
de: 0
|
||||
es: 1
|
||||
fr: 2
|
||||
en-GB: 3
|
||||
it: 4
|
||||
pt: 5
|
||||
ru: 6
|
||||
en: 7
|
||||
pl: 8
|
||||
tr: 9
|
||||
sv: 10
|
||||
ro: 11
|
||||
nl: 12
|
||||
hu: 13
|
||||
id: 14
|
||||
vi: 15
|
||||
cs: 16
|
||||
fi: 17
|
||||
|
||||
esphome:
|
||||
on_boot:
|
||||
- priority: -100
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: display_tools.get_translations_esphome
|
||||
data:
|
||||
language: !lambda return id(flag_icon_mapping_name).get(id(current_language)).c_str();
|
||||
category: entity_component
|
||||
keys: '[
|
||||
"component.vacuum.entity_component._.state.cleaning",
|
||||
"component.vacuum.entity_component._.state.docked",
|
||||
"component.vacuum.entity_component._.state.error",
|
||||
"component.vacuum.entity_component._.state.idle",
|
||||
"component.vacuum.entity_component._.state.off",
|
||||
"component.vacuum.entity_component._.state.on",
|
||||
"component.vacuum.entity_component._.state.paused",
|
||||
"component.vacuum.entity_component._.state.returning",
|
||||
"component.cover.entity_component._.state.closed",
|
||||
"component.cover.entity_component._.state.closing",
|
||||
"component.cover.entity_component._.state.open",
|
||||
"component.cover.entity_component._.state.opening",
|
||||
"component.cover.entity_component._.state.stopped",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.cooling",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.defrosting",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.drying",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.fan",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.heating",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.idle",
|
||||
"component.climate.entity_component._.state_attributes.hvac_action.state.off",
|
||||
"component.weather.entity_component._.state.clear-night",
|
||||
"component.weather.entity_component._.state.cloudy",
|
||||
"component.weather.entity_component._.state.exceptional",
|
||||
"component.weather.entity_component._.state.fog",
|
||||
"component.weather.entity_component._.state.hail",
|
||||
"component.weather.entity_component._.state.lightning",
|
||||
"component.weather.entity_component._.state.lightning-rainy",
|
||||
"component.weather.entity_component._.state.partlycloudy",
|
||||
"component.weather.entity_component._.state.pouring",
|
||||
"component.weather.entity_component._.state.rainy",
|
||||
"component.weather.entity_component._.state.snowy",
|
||||
"component.weather.entity_component._.state.snowy-rainy",
|
||||
"component.weather.entity_component._.state.sunny",
|
||||
"component.weather.entity_component._.state.windy",
|
||||
"component.weather.entity_component._.state.windy-variant",
|
||||
"component.alarm_control_panel.entity_component._.state.armed",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_away",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_custom_bypass",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_home",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_night",
|
||||
"component.alarm_control_panel.entity_component._.state.armed_vacation",
|
||||
"component.alarm_control_panel.entity_component._.state.arming",
|
||||
"component.alarm_control_panel.entity_component._.state.disarmed",
|
||||
"component.alarm_control_panel.entity_component._.state.disarming",
|
||||
"component.alarm_control_panel.entity_component._.state.pending",
|
||||
"component.alarm_control_panel.entity_component._.state.triggered"
|
||||
]'
|
||||
|
||||
- lvgl.dropdown.update:
|
||||
id: display_timeout_dropdown
|
||||
selected_index: !lambda return id(display_timeout);
|
||||
|
||||
api:
|
||||
on_client_connected:
|
||||
- lvgl.dropdown.update:
|
||||
id: display_timeout_dropdown
|
||||
selected_index: !lambda return id(display_timeout);
|
||||
46
esphome/widgets/shutter/shutter_config.yaml
Normal file
46
esphome/widgets/shutter/shutter_config.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
substitutions:
|
||||
|
||||
shutter_entity_1: "cover.hall_window"
|
||||
shutter_entity_2: "cover.living_room_window"
|
||||
shutter_entity_3: "cover.hall_window"
|
||||
shutter_entity_4: "cover.living_room_window"
|
||||
|
||||
shutter_widget_name_1: "shutter1"
|
||||
shutter_widget_name_2: "shutter2"
|
||||
shutter_widget_name_3: "shutter3"
|
||||
shutter_widget_name_4: "shutter4"
|
||||
|
||||
|
||||
shutter_label_name_1: "shutter 1"
|
||||
shutter_label_name_2: "shutter 2"
|
||||
shutter_label_name_3: "shutter 3"
|
||||
shutter_label_name_4: "shutter 4"
|
||||
|
||||
|
||||
packages:
|
||||
shutter_panel: !include shutter_panel.yaml
|
||||
|
||||
shutter_1: !include
|
||||
file: shutter_widget.yaml
|
||||
vars:
|
||||
shutter_entity: "${shutter_entity_1}"
|
||||
shutter_widget_name: "${shutter_widget_name_1}"
|
||||
|
||||
shutter_2: !include
|
||||
file: shutter_widget.yaml
|
||||
vars:
|
||||
shutter_entity: "${shutter_entity_2}"
|
||||
shutter_widget_name: "${shutter_widget_name_2}"
|
||||
|
||||
shutter_3: !include
|
||||
file: shutter_widget.yaml
|
||||
vars:
|
||||
shutter_entity: "${shutter_entity_3}"
|
||||
shutter_widget_name: "${shutter_widget_name_3}"
|
||||
|
||||
shutter_4: !include
|
||||
file: shutter_widget.yaml
|
||||
vars:
|
||||
shutter_entity: "${shutter_entity_4}"
|
||||
shutter_widget_name: "${shutter_widget_name_4}"
|
||||
|
||||
203
esphome/widgets/shutter/shutter_panel.yaml
Normal file
203
esphome/widgets/shutter/shutter_panel.yaml
Normal file
@@ -0,0 +1,203 @@
|
||||
substitutions:
|
||||
|
||||
exit_icon: "\U0000e902"
|
||||
shutter_close_icon: "\U0000e91d"
|
||||
swipe_icon: "\U0000e91a"
|
||||
|
||||
|
||||
lvgl:
|
||||
pages:
|
||||
- id: shutter_group_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
|
||||
- button:
|
||||
id: ${shutter_widget_name_1}_btn
|
||||
x: 20
|
||||
y: 20
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${shutter_widget_name_1}_shutter
|
||||
y: 15
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${shutter_close_icon}"
|
||||
|
||||
- label:
|
||||
id: ${shutter_widget_name_1}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${shutter_label_name_1}"
|
||||
|
||||
- button:
|
||||
id: ${shutter_widget_name_2}_btn
|
||||
x: -20
|
||||
y: 20
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${shutter_widget_name_2}_shutter
|
||||
y: 15
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${shutter_close_icon}"
|
||||
|
||||
- label:
|
||||
id: ${shutter_widget_name_2}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${shutter_label_name_2}"
|
||||
|
||||
- button:
|
||||
id: ${shutter_widget_name_3}_btn
|
||||
x: 20
|
||||
y: 200
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${shutter_widget_name_3}_shutter
|
||||
y: 15
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${shutter_close_icon}"
|
||||
|
||||
- label:
|
||||
id: ${shutter_widget_name_3}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${shutter_label_name_3}"
|
||||
|
||||
- button:
|
||||
id: ${shutter_widget_name_4}_btn
|
||||
x: -20
|
||||
y: 200
|
||||
width: 210
|
||||
height: 160
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${shutter_widget_name_4}_shutter
|
||||
y: 15
|
||||
align: CENTER
|
||||
text_color: color_steel_blue
|
||||
text_font: icons_90
|
||||
text: "${shutter_close_icon}"
|
||||
|
||||
- label:
|
||||
id: ${shutter_widget_name_4}_lable_name
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "${shutter_label_name_4}"
|
||||
|
||||
|
||||
binary_sensor:
|
||||
- platform: lvgl
|
||||
id: ${shutter_widget_name_1}_btn_long_sensor
|
||||
widget: ${shutter_widget_name_1}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: cover.toggle
|
||||
data:
|
||||
entity_id: "${shutter_entity_1}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${shutter_widget_name_1}_shutter_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
- platform: lvgl
|
||||
id: ${shutter_widget_name_2}_btn_long_sensor
|
||||
widget: ${shutter_widget_name_2}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: cover.toggle
|
||||
data:
|
||||
entity_id: "${shutter_entity_2}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${shutter_widget_name_2}_shutter_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
- platform: lvgl
|
||||
id: ${shutter_widget_name_3}_btn_long_sensor
|
||||
widget: ${shutter_widget_name_3}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: cover.toggle
|
||||
data:
|
||||
entity_id: "${shutter_entity_3}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${shutter_widget_name_3}_shutter_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
- platform: lvgl
|
||||
id: ${shutter_widget_name_4}_btn_long_sensor
|
||||
widget: ${shutter_widget_name_4}_btn
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 500ms
|
||||
then:
|
||||
- homeassistant.service:
|
||||
service: cover.toggle
|
||||
data:
|
||||
entity_id: "${shutter_entity_4}"
|
||||
- min_length: 800ms
|
||||
max_length: 3000ms
|
||||
then:
|
||||
- lvgl.widget.hide: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: ${shutter_widget_name_4}_shutter_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
|
||||
543
esphome/widgets/shutter/shutter_widget.yaml
Normal file
543
esphome/widgets/shutter/shutter_widget.yaml
Normal file
@@ -0,0 +1,543 @@
|
||||
substitutions:
|
||||
arrow_up_icon: "\U0000e91f"
|
||||
arrow_down_icon: "\U0000e920"
|
||||
stop_icon: "\U0000e91c"
|
||||
shutter_open_icon: "\U0000e91e"
|
||||
shutter_close_icon: "\U0000e91d"
|
||||
|
||||
sensor:
|
||||
# Shutter Current Position
|
||||
- platform: homeassistant
|
||||
id: ${shutter_widget_name}_shutter_current_pos
|
||||
entity_id: "${shutter_entity}"
|
||||
attribute: current_position
|
||||
on_value:
|
||||
then:
|
||||
- script.execute: ${shutter_widget_name}_shutter_state_update
|
||||
- lambda: |-
|
||||
int pos = round(id(${shutter_widget_name}_shutter_current_pos).state / 10) * 10;
|
||||
|
||||
static const char* glyphs[] = {
|
||||
"\U0000e91d", // 0 - shutter_closed
|
||||
"\U0000e93d", // 10
|
||||
"\U0000e93e", // 20
|
||||
"\U0000e93f", // 30
|
||||
"\U0000e940", // 40
|
||||
"\U0000e941", // 50
|
||||
"\U0000e93c", // 60
|
||||
"\U0000e943", // 70
|
||||
"\U0000e944", // 80
|
||||
"\U0000e942", // 90
|
||||
"\U0000e91e" // 100 - shutter_open
|
||||
};
|
||||
|
||||
int idx = pos / 10;
|
||||
if (idx < 0) idx = 0;
|
||||
if (idx > 10) idx = 10;
|
||||
|
||||
lv_label_set_text(id(${shutter_widget_name}_shutter_icon), glyphs[idx]);
|
||||
lv_label_set_text(id(${shutter_widget_name}_shutter), glyphs[idx]);
|
||||
|
||||
text_sensor:
|
||||
# Shutter Name
|
||||
- platform: homeassistant
|
||||
id: ${shutter_widget_name}_shutter_name
|
||||
entity_id: "${shutter_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
- lvgl.label.update:
|
||||
id: ${shutter_widget_name}_shutter_label_name
|
||||
text: !lambda return x;
|
||||
|
||||
# Shutter State
|
||||
- platform: homeassistant
|
||||
id: ${shutter_widget_name}_shutter_state
|
||||
entity_id: "${shutter_entity}"
|
||||
on_value:
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${shutter_widget_name}_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(${shutter_widget_name}_shutter_state).state;'
|
||||
|
||||
- lvgl.label.update:
|
||||
id: ${shutter_widget_name}_shutter_label_state
|
||||
y: 5
|
||||
align: TOP_MID
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "opening";'
|
||||
then:
|
||||
- lvgl.widget.show: ${shutter_widget_name}_shutter_label_pos
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "closing";'
|
||||
then:
|
||||
- lvgl.widget.show: ${shutter_widget_name}_shutter_label_pos
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "open";'
|
||||
then:
|
||||
- lvgl.widget.show: ${shutter_widget_name}_shutter_label_pos
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "closed";'
|
||||
then:
|
||||
- lvgl.widget.hide: ${shutter_widget_name}_shutter_label_pos
|
||||
- lvgl.label.update:
|
||||
id: ${shutter_widget_name}_shutter_label_state
|
||||
y: 0
|
||||
align: CENTER
|
||||
lvgl:
|
||||
pages:
|
||||
- id: ${shutter_widget_name}_shutter_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- obj:
|
||||
id: ${shutter_widget_name}_shutter_bg_state
|
||||
x: -20
|
||||
y: 40
|
||||
width: 320
|
||||
height: 54
|
||||
align: TOP_RIGHT
|
||||
bg_opa: transp
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${shutter_widget_name}_shutter_label_state
|
||||
y: 5
|
||||
align: TOP_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: " "
|
||||
- label:
|
||||
id: ${shutter_widget_name}_shutter_label_pos
|
||||
y: -5
|
||||
align: BOTTOM_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: " "
|
||||
|
||||
- obj:
|
||||
id: ${shutter_widget_name}_shutter_bg_controls
|
||||
x: 20
|
||||
y: 20
|
||||
width: 100
|
||||
height: 320
|
||||
align: TOP_LEFT
|
||||
# bg_color: color_steel_blue
|
||||
bg_opa: transp
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
y: 20
|
||||
width: 90
|
||||
height: 90
|
||||
align: top_mid
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 70
|
||||
height: 70
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 8
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: cover.open_cover
|
||||
data:
|
||||
entity_id: "${shutter_entity}"
|
||||
- obj:
|
||||
width: 60
|
||||
height: 60
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 65
|
||||
height: 65
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_font: icons_32
|
||||
text_color: color_misty_blue
|
||||
text: "${arrow_up_icon}"
|
||||
|
||||
|
||||
- obj:
|
||||
width: 90
|
||||
height: 90
|
||||
align: center
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 70
|
||||
height: 70
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 8
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: cover.stop_cover
|
||||
data:
|
||||
entity_id: "${shutter_entity}"
|
||||
- obj:
|
||||
width: 60
|
||||
height: 60
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 65
|
||||
height: 65
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_font: icons_32
|
||||
text_color: color_misty_blue
|
||||
text: "${stop_icon}"
|
||||
|
||||
- obj:
|
||||
y: -20
|
||||
width: 90
|
||||
height: 90
|
||||
align: bottom_mid
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 70
|
||||
height: 70
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 8
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
- homeassistant.action:
|
||||
action: cover.close_cover
|
||||
data:
|
||||
entity_id: "${shutter_entity}"
|
||||
- obj:
|
||||
width: 60
|
||||
height: 60
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 65
|
||||
height: 65
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_font: icons_32
|
||||
text_color: color_misty_blue
|
||||
text: "${arrow_down_icon}"
|
||||
|
||||
- obj:
|
||||
id: ${shutter_widget_name}_shutter_bg_slider
|
||||
x: -20
|
||||
y: 94
|
||||
width: 320
|
||||
height: 310
|
||||
align: TOP_RIGHT
|
||||
# bg_color: color_steel_blue
|
||||
bg_opa: transp
|
||||
pad_all: 0
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${shutter_widget_name}_shutter_icon
|
||||
align: CENTER
|
||||
text_font: icons_300
|
||||
text_color: color_misty_blue
|
||||
text: "\U0000e91d"
|
||||
|
||||
- slider:
|
||||
id: ${shutter_widget_name}_shutter_set_pos_slider
|
||||
hidden: false
|
||||
radius: 0
|
||||
bg_opa: TRANSP
|
||||
y: -32
|
||||
align: BOTTOM_MID
|
||||
width: 210
|
||||
height: 220
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
indicator:
|
||||
bg_opa: TRANSP
|
||||
radius: 0
|
||||
knob:
|
||||
bg_opa: TRANSP
|
||||
on_value:
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${shutter_widget_name}_shutter_slider_preview_update
|
||||
value: !lambda 'return x;'
|
||||
on_release:
|
||||
- homeassistant.action:
|
||||
action: cover.set_cover_position
|
||||
data:
|
||||
entity_id: "${shutter_entity}"
|
||||
position: !lambda return int(x);
|
||||
|
||||
|
||||
- obj:
|
||||
id: ${shutter_widget_name}_shutter_back
|
||||
x: 20
|
||||
y: 360
|
||||
width: 100
|
||||
height: 100
|
||||
align: TOP_LEFT
|
||||
bg_opa: transp
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- obj:
|
||||
width: 90
|
||||
height: 90
|
||||
align: center
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 70
|
||||
height: 70
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 10
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 8
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
then:
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
- lvgl.page.show:
|
||||
id: shutter_group_page
|
||||
animation: OUT_RIGHT
|
||||
time: 300ms
|
||||
- label:
|
||||
id: ${shutter_widget_name}_shutter_back_label
|
||||
align: center
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
|
||||
|
||||
- obj:
|
||||
id: ${shutter_widget_name}_shutter_bg_name
|
||||
x: -20
|
||||
y: 400
|
||||
width: 320
|
||||
height: 36
|
||||
align: TOP_RIGHT
|
||||
bg_opa: transp
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: ${shutter_widget_name}_shutter_label_name
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "shutter"
|
||||
|
||||
script:
|
||||
- id: ${shutter_widget_name}_shutter_state_update
|
||||
then:
|
||||
|
||||
- lvgl.slider.update:
|
||||
id: ${shutter_widget_name}_shutter_set_pos_slider
|
||||
value: !lambda |-
|
||||
return round(id(${shutter_widget_name}_shutter_current_pos).state / 10) * 10;
|
||||
|
||||
- lvgl.label.update:
|
||||
id: ${shutter_widget_name}_shutter_label_pos
|
||||
text: !lambda |-
|
||||
return to_string((int)id(${shutter_widget_name}_shutter_current_pos).state) + "%";
|
||||
|
||||
|
||||
- id: ${shutter_widget_name}_shutter_slider_preview_update
|
||||
parameters:
|
||||
value: int
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: ${shutter_widget_name}_shutter_label_pos
|
||||
text: !lambda |-
|
||||
return to_string((int)value) + "%";
|
||||
- lambda: |-
|
||||
int pos = round(value / 10) * 10;
|
||||
|
||||
static const char* glyphs[] = {
|
||||
"\U0000e91d", // 0 - shutter_closed
|
||||
"\U0000e93d", // 10
|
||||
"\U0000e93e", // 20
|
||||
"\U0000e93f", // 30
|
||||
"\U0000e940", // 40
|
||||
"\U0000e941", // 50
|
||||
"\U0000e93c", // 60
|
||||
"\U0000e943", // 70
|
||||
"\U0000e944", // 80
|
||||
"\U0000e942", // 90
|
||||
"\U0000e91e" // 100 - shutter_open
|
||||
};
|
||||
int idx = pos / 10;
|
||||
if (idx < 0) idx = 0;
|
||||
if (idx > 10) idx = 10;
|
||||
lv_label_set_text(id(${shutter_widget_name}_shutter_icon), glyphs[idx]);
|
||||
lv_label_set_text(id(${shutter_widget_name}_shutter), glyphs[idx]);
|
||||
|
||||
- id: ${shutter_widget_name}_get_and_set_translated_state
|
||||
parameters:
|
||||
state_str: string
|
||||
then:
|
||||
- lambda: |-
|
||||
std::string state = state_str;
|
||||
|
||||
auto it = id(cover_translations).find(state);
|
||||
std::string translated_state = (it != id(cover_translations).end()) ? it->second : state;
|
||||
|
||||
lv_label_set_text(id(${shutter_widget_name}_shutter_label_state), translated_state.c_str());
|
||||
|
||||
select:
|
||||
- platform: lvgl
|
||||
widget: language_dropdown
|
||||
id: ${shutter_widget_name}_select_language
|
||||
on_value:
|
||||
then:
|
||||
- delay: 300ms
|
||||
- script.execute:
|
||||
id: ${shutter_widget_name}_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(${shutter_widget_name}_shutter_state).state;'
|
||||
|
||||
esphome:
|
||||
on_boot:
|
||||
priority: -100
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${shutter_widget_name}_shutter_state).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${shutter_widget_name}_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(${shutter_widget_name}_shutter_state).state;'
|
||||
|
||||
api:
|
||||
on_client_connected:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(${shutter_widget_name}_shutter_state).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: ${shutter_widget_name}_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(${shutter_widget_name}_shutter_state).state;'
|
||||
95
esphome/widgets/themes/blue.yaml
Normal file
95
esphome/widgets/themes/blue.yaml
Normal file
@@ -0,0 +1,95 @@
|
||||
lvgl:
|
||||
theme:
|
||||
label:
|
||||
text_font: my_font # set all your labels to use your custom defined font
|
||||
button:
|
||||
bg_color: 0x2F8CD8
|
||||
bg_grad_color: 0x005782
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
border_color: 0x0077b3
|
||||
border_width: 1
|
||||
text_color: 0xFFFFFF
|
||||
pressed: # set some button colors to be different in pressed state
|
||||
bg_color: 0x006699
|
||||
bg_grad_color: 0x00334d
|
||||
checked: # set some button colors to be different in checked state
|
||||
bg_color: 0x1d5f96
|
||||
bg_grad_color: 0x03324A
|
||||
text_color: 0xfff300
|
||||
buttonmatrix:
|
||||
bg_opa: TRANSP
|
||||
border_color: 0x0077b3
|
||||
border_width: 0
|
||||
text_color: 0xFFFFFF
|
||||
pad_all: 0
|
||||
items: # set all your buttonmatrix buttons to use your custom defined styles and font
|
||||
bg_color: 0x2F8CD8
|
||||
bg_grad_color: 0x005782
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
border_color: 0x0077b3
|
||||
border_width: 1
|
||||
text_color: 0xFFFFFF
|
||||
text_font: my_font
|
||||
pressed:
|
||||
bg_color: 0x006699
|
||||
bg_grad_color: 0x00334d
|
||||
checked:
|
||||
bg_color: 0x1d5f96
|
||||
bg_grad_color: 0x03324A
|
||||
text_color: 0x005580
|
||||
switch:
|
||||
bg_color: 0xC0C0C0
|
||||
bg_grad_color: 0xb0b0b0
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
checked:
|
||||
bg_color: 0x1d5f96
|
||||
bg_grad_color: 0x03324A
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
knob:
|
||||
bg_color: 0xFFFFFF
|
||||
bg_grad_color: 0xC0C0C0
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
slider:
|
||||
border_width: 1
|
||||
border_opa: 15%
|
||||
bg_color: 0xcccaca
|
||||
bg_opa: 15%
|
||||
indicator:
|
||||
bg_color: 0x1d5f96
|
||||
bg_grad_color: 0x03324A
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
knob:
|
||||
bg_color: 0x2F8CD8
|
||||
bg_grad_color: 0x005782
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
border_color: 0x0077b3
|
||||
border_width: 1
|
||||
text_color: 0xFFFFFF
|
||||
spinbox:
|
||||
cursor:
|
||||
bg_opa: 0x00
|
||||
bg_color: 0x00
|
||||
text_color: 0xFFFFFF
|
||||
style_definitions:
|
||||
- id: header_footer
|
||||
bg_color: 0x2F8CD8
|
||||
bg_grad_color: 0x005782
|
||||
bg_grad_dir: VER
|
||||
bg_opa: COVER
|
||||
border_opa: TRANSP
|
||||
radius: 0
|
||||
pad_all: 0
|
||||
pad_row: 0
|
||||
pad_column: 0
|
||||
border_color: 0x0077b3
|
||||
text_color: 0xFFFFFF
|
||||
width: 100%
|
||||
height: 30
|
||||
|
||||
79
esphome/widgets/themes/habbit.yaml
Normal file
79
esphome/widgets/themes/habbit.yaml
Normal file
@@ -0,0 +1,79 @@
|
||||
lvgl:
|
||||
- style_definitions:
|
||||
- id: button_menu
|
||||
width: 60
|
||||
height: 60
|
||||
pad_all: 0
|
||||
bg_color: 0x000000
|
||||
border_color: 0x000000
|
||||
align: BOTTOM_RIGHT
|
||||
- id: button_more
|
||||
width: 60
|
||||
height: 60
|
||||
pad_all: 0
|
||||
bg_color: 0x000000
|
||||
border_color: 0x000000
|
||||
align: TOP_RIGHT
|
||||
- id: button_device_1
|
||||
width: 130
|
||||
height: 130
|
||||
pad_all: 0
|
||||
translate_x: 30
|
||||
bg_color: 0x000000
|
||||
border_color: 0x000000
|
||||
align: LEFT_MID
|
||||
- id: button_device_2
|
||||
width: 130
|
||||
height: 130
|
||||
pad_all: 0
|
||||
translate_x: 160
|
||||
bg_color: 0x000000
|
||||
border_color: 0x000000
|
||||
align: LEFT_MID
|
||||
- id: button_device_3
|
||||
width: 130
|
||||
height: 130
|
||||
pad_all: 0
|
||||
translate_x: 290
|
||||
bg_color: 0x000000
|
||||
border_color: 0x000000
|
||||
align: LEFT_MID
|
||||
- id: button_device_4
|
||||
width: 130
|
||||
height: 130
|
||||
pad_all: 0
|
||||
translate_x: 420
|
||||
bg_color: 0x000000
|
||||
border_color: 0x000000
|
||||
align: LEFT_MID
|
||||
|
||||
- id: slider_front_cover
|
||||
width: 530
|
||||
height: 160
|
||||
translate_x: -25
|
||||
bg_color: 0x9c9c79
|
||||
radius: 10
|
||||
align: CENTER
|
||||
- id: slider_back_cover
|
||||
width: 530
|
||||
height: 160
|
||||
translate_x: -25
|
||||
bg_color: 0xb4b4a9
|
||||
radius: 10
|
||||
align: CENTER
|
||||
- id: slider_label_values_cover
|
||||
align: CENTER
|
||||
translate_x: -10
|
||||
text_font: font_slider_value
|
||||
text_color: 0xffffff
|
||||
|
||||
- id: device_status_top
|
||||
align: TOP_LEFT
|
||||
pad_left: 20
|
||||
text_font: font_device_status
|
||||
text_color: ${text_color_secondary}
|
||||
- id: device_status_bottom
|
||||
align: BOTTOM_LEFT
|
||||
pad_left: 20
|
||||
text_font: font_device_status
|
||||
text_color: 0xffffff
|
||||
63
esphome/widgets/thermostat/small_thermostat.yaml
Normal file
63
esphome/widgets/thermostat/small_thermostat.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
sensor:
|
||||
- platform: homeassistant
|
||||
id: room_thermostat
|
||||
entity_id: ${climate}
|
||||
attribute: temperature
|
||||
on_value:
|
||||
- lvgl.spinbox.update:
|
||||
id: spinbox_id
|
||||
value: !lambda return x;
|
||||
|
||||
lvgl:
|
||||
top_layer:
|
||||
widgets:
|
||||
- obj:
|
||||
align: BOTTOM_MID
|
||||
y: -50
|
||||
layout:
|
||||
type: FLEX
|
||||
flex_flow: ROW
|
||||
flex_align_cross: CENTER
|
||||
width: SIZE_CONTENT
|
||||
height: SIZE_CONTENT
|
||||
widgets:
|
||||
- button:
|
||||
id: spin_down
|
||||
width: 100
|
||||
height: 70
|
||||
on_click:
|
||||
- lvgl.spinbox.decrement: spinbox_id
|
||||
widgets:
|
||||
- label:
|
||||
text: "-"
|
||||
text_font: my_font
|
||||
- spinbox:
|
||||
id: spinbox_id
|
||||
align: CENTER
|
||||
text_align: CENTER
|
||||
width: 100
|
||||
height: 70
|
||||
range_from: 15
|
||||
range_to: 35
|
||||
selected_digit: 0
|
||||
rollover: false
|
||||
digits: 2
|
||||
decimal_places: 0
|
||||
text_font: my_font
|
||||
on_value:
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: climate.set_temperature
|
||||
data:
|
||||
temperature: !lambda return x;
|
||||
entity_id: ${climate}
|
||||
- button:
|
||||
id: spin_up
|
||||
width: 100
|
||||
height: 70
|
||||
on_click:
|
||||
- lvgl.spinbox.increment: spinbox_id
|
||||
widgets:
|
||||
- label:
|
||||
text: "+"
|
||||
text_font: my_font
|
||||
813
esphome/widgets/thermostat/thermostat_widget.yaml
Normal file
813
esphome/widgets/thermostat/thermostat_widget.yaml
Normal file
@@ -0,0 +1,813 @@
|
||||
# https://esphome.io/components/climate/thermostat.html
|
||||
|
||||
substitutions:
|
||||
|
||||
thermostat_name: "thermostat"
|
||||
thermostat_temperature_entity: "sensor.outside_temperature"
|
||||
thermostat_entity: "climate.smart_radiator_thermostat_x_2"
|
||||
|
||||
heating_icon: "\U0000e936"
|
||||
temperature_icon: "\U0000e939"
|
||||
pm_home_icon: "\U000F0826"
|
||||
pm_away_icon: "\U000F1A46"
|
||||
|
||||
climate:
|
||||
- platform: thermostat
|
||||
name: "${thermostat_name}"
|
||||
id: climate_thermostat
|
||||
sensor: thermostate_temperature_sensor
|
||||
on_boot_restore_from: memory
|
||||
min_heating_off_time: 5s
|
||||
min_heating_run_time: 5s
|
||||
min_idle_time: 5s
|
||||
startup_delay: true
|
||||
heat_deadband: 0.5
|
||||
heat_overrun: 0.5
|
||||
visual:
|
||||
min_temperature: 10
|
||||
max_temperature: 30
|
||||
temperature_step: 0.5
|
||||
heat_action:
|
||||
- delay: 500ms
|
||||
idle_action:
|
||||
- delay: 500ms
|
||||
default_preset: Home
|
||||
preset:
|
||||
- name: Home
|
||||
default_target_temperature_low: 22 °C
|
||||
- name: Away
|
||||
default_target_temperature_low: 18 °C
|
||||
|
||||
# switch:
|
||||
# - platform: gpio
|
||||
# id: thermostat_relay
|
||||
# name: "Heating Relay"
|
||||
# pin: GPIO40
|
||||
# on_turn_on:
|
||||
|
||||
# - lvgl.meter.update:
|
||||
# id: thermostat_meter
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: heating_status
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_state_icon
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_icon
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_value
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_whole
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_fraction
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_measurement
|
||||
# text_color: color_deep_orange
|
||||
|
||||
# on_turn_off:
|
||||
|
||||
# - lvgl.meter.update:
|
||||
# id: thermostat_meter
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: heating_status
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_state_icon
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_icon
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_value
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_whole
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_fraction
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# - lvgl.label.update:
|
||||
# id: thermostat_target_temperature_measurement
|
||||
# text_color: color_steel_blue
|
||||
|
||||
# restore_mode: RESTORE_DEFAULT_ON
|
||||
|
||||
|
||||
sensor:
|
||||
|
||||
# Thermostat temperature sensor
|
||||
- platform: homeassistant
|
||||
id: thermostate_temperature_sensor
|
||||
entity_id: "${thermostat_temperature_entity}"
|
||||
|
||||
# Thermostat target temperature
|
||||
- platform: homeassistant
|
||||
id: thermostat_sensor_target_temp
|
||||
entity_id: "${thermostat_entity}"
|
||||
attribute: temperature
|
||||
on_value:
|
||||
then:
|
||||
- lvgl.arc.update:
|
||||
id: thermostat_arc_main
|
||||
value: !lambda return x;
|
||||
|
||||
- lvgl.label.update:
|
||||
id: thermostat_target_temperature_whole
|
||||
text: !lambda |-
|
||||
static char buf[10];
|
||||
int whole_part = static_cast<int>(id(thermostat_sensor_target_temp).state);
|
||||
snprintf(buf, 10, "%d", whole_part);
|
||||
return buf;
|
||||
|
||||
- lvgl.label.update:
|
||||
id: thermostat_target_temperature_fraction
|
||||
text: !lambda |-
|
||||
static char buf[10];
|
||||
int whole_part = static_cast<int>(id(thermostat_sensor_target_temp).state);
|
||||
int fractional_part = static_cast<int>((id(thermostat_sensor_target_temp).state - whole_part) * 10);
|
||||
snprintf(buf, 10, ".%01d", fractional_part);
|
||||
return buf;
|
||||
|
||||
# Thermostat current temperature
|
||||
- platform: homeassistant
|
||||
id: thermostat_sensor_current_temp
|
||||
entity_id: "${thermostat_entity}"
|
||||
attribute: current_temperature
|
||||
on_value:
|
||||
- lvgl.label.update:
|
||||
id: thermostat_target_temperature_value
|
||||
text: !lambda |-
|
||||
char buf[8];
|
||||
sprintf(buf, "%.1f", x);
|
||||
return std::string(buf);
|
||||
|
||||
- lvgl.arc.update:
|
||||
id: thermostat_arc_current_temp
|
||||
value: !lambda return x;
|
||||
|
||||
|
||||
text_sensor:
|
||||
|
||||
# Thermostat name
|
||||
- platform: homeassistant
|
||||
id: thermostat_sensor_name
|
||||
entity_id: "${thermostat_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
- lvgl.label.update:
|
||||
id: thermostat_name_label
|
||||
text: !lambda return x;
|
||||
|
||||
# Thermostat preset mode
|
||||
- platform: homeassistant
|
||||
id: thermostat_sensor_preset_mode
|
||||
entity_id: "${thermostat_entity}"
|
||||
attribute: preset_mode
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(thermostat_sensor_preset_mode).state == "home";'
|
||||
then:
|
||||
- lvgl.obj.update:
|
||||
id: thermostat_preset_mode_bg
|
||||
bg_color: color_green
|
||||
- lvgl.label.update:
|
||||
id: thermostat_preset_mode_icon
|
||||
text: "${pm_home_icon}"
|
||||
text_color: color_green
|
||||
else:
|
||||
- lvgl.obj.update:
|
||||
id: thermostat_preset_mode_bg
|
||||
bg_color: color_red
|
||||
- lvgl.label.update:
|
||||
id: thermostat_preset_mode_icon
|
||||
text: "${pm_away_icon}"
|
||||
text_color: color_red
|
||||
|
||||
|
||||
# Thermostat hvac mode
|
||||
- platform: homeassistant
|
||||
id: thermostat_sensor_hvac_mode
|
||||
entity_id: "${thermostat_entity}"
|
||||
attribute: hvac_action
|
||||
on_value:
|
||||
- script.execute:
|
||||
id: thermostat_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(thermostat_sensor_hvac_mode).state;'
|
||||
|
||||
# Thermostat state
|
||||
- platform: homeassistant
|
||||
id: thermostat_sensor_state
|
||||
entity_id: "${thermostat_entity}"
|
||||
on_value:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(thermostat_sensor_state).state == "off";'
|
||||
then:
|
||||
- lvgl.obj.update:
|
||||
id: thermostat_power_bg
|
||||
bg_color: color_misty_blue
|
||||
- lvgl.label.update:
|
||||
id: thermostat_power_icon
|
||||
text_color: color_misty_blue
|
||||
else:
|
||||
- lvgl.obj.update:
|
||||
id: thermostat_power_bg
|
||||
bg_color: color_deep_orange
|
||||
- lvgl.label.update:
|
||||
id: thermostat_power_icon
|
||||
text_color: color_deep_orange
|
||||
lvgl:
|
||||
|
||||
gradients:
|
||||
- id: thermostat_temp_gradient
|
||||
direction: ver
|
||||
dither: none
|
||||
stops:
|
||||
- color: 0xFF0000
|
||||
position: 0
|
||||
- color: 0xFF3300
|
||||
position: 32
|
||||
- color: 0xFF6600
|
||||
position: 64
|
||||
- color: 0xFF8000
|
||||
position: 96
|
||||
- color: 0xFF9900
|
||||
position: 128
|
||||
- color: 0xFFB300
|
||||
position: 160
|
||||
- color: 0xFFCC00
|
||||
position: 192
|
||||
- color: 0xFFE600
|
||||
position: 224
|
||||
- color: 0xFFFF00
|
||||
position: 255
|
||||
|
||||
pages:
|
||||
- id: thermostat_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
|
||||
# State
|
||||
- obj:
|
||||
id: thermostat_state
|
||||
x: 20
|
||||
y: 20
|
||||
width: 400
|
||||
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: thermostat_state_label
|
||||
x: 20
|
||||
align: LEFT_MID
|
||||
text_font: nunito_18
|
||||
text_color: color_misty_blue
|
||||
text: " "
|
||||
|
||||
# Preset Mode and Power Toggle
|
||||
- obj:
|
||||
id: thermostat_controls
|
||||
x: 535
|
||||
y: 100
|
||||
width: 260
|
||||
height: 280
|
||||
#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:
|
||||
- obj:
|
||||
id: thermostat_preset_mode_bg
|
||||
x: 35
|
||||
y: -60
|
||||
align: left_mid
|
||||
width: 70
|
||||
height: 70
|
||||
radius: 35
|
||||
pad_all: 0
|
||||
bg_color: color_green
|
||||
bg_opa: 60%
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
id: thermostat_preset_mode_icon
|
||||
align: center
|
||||
text_font: mdi_icons_52
|
||||
text_color: color_green
|
||||
text: "${pm_home_icon}"
|
||||
on_click:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(thermostat_sensor_preset_mode).state == "home";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: climate.set_preset_mode
|
||||
data:
|
||||
entity_id: "${thermostat_entity}"
|
||||
preset_mode: away
|
||||
else:
|
||||
- homeassistant.action:
|
||||
action: climate.set_preset_mode
|
||||
data:
|
||||
entity_id: "${thermostat_entity}"
|
||||
preset_mode: home
|
||||
|
||||
- obj:
|
||||
id: thermostat_power_bg
|
||||
x: 35
|
||||
y: 60
|
||||
align: left_mid
|
||||
width: 70
|
||||
height: 70
|
||||
radius: 35
|
||||
pad_all: 0
|
||||
bg_color: color_deep_orange
|
||||
bg_opa: 30%
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
id: thermostat_power_icon
|
||||
align: center
|
||||
text_font: icons_38
|
||||
text_color: color_deep_orange
|
||||
text: "${power_icon}"
|
||||
on_click:
|
||||
- homeassistant.action:
|
||||
action: climate.toggle
|
||||
data:
|
||||
entity_id: "${thermostat_entity}"
|
||||
|
||||
# Temperature controls
|
||||
- obj:
|
||||
x: 5
|
||||
y: -60
|
||||
width: 90
|
||||
height: 90
|
||||
align: left_mid
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 70
|
||||
height: 70
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 8
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
then:
|
||||
- lambda: |-
|
||||
auto temp = id(thermostat_sensor_target_temp).state + 0.5;
|
||||
id(thermostat_sensor_target_temp).publish_state(temp);
|
||||
- homeassistant.service:
|
||||
service: climate.set_temperature
|
||||
data:
|
||||
entity_id: "${thermostat_entity}"
|
||||
temperature: !lambda 'return id(thermostat_sensor_target_temp).state;'
|
||||
- obj:
|
||||
width: 60
|
||||
height: 60
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 65
|
||||
height: 65
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
y: -2
|
||||
align: center
|
||||
text_font: nunito_48
|
||||
text_color: color_misty_blue
|
||||
text: "+"
|
||||
|
||||
- obj:
|
||||
x: 5
|
||||
y: 60
|
||||
width: 90
|
||||
height: 90
|
||||
align: left_mid
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
shadow_opa: transp
|
||||
border_opa: transp
|
||||
widgets:
|
||||
- obj:
|
||||
width: 70
|
||||
height: 70
|
||||
align: center
|
||||
clickable: true
|
||||
radius: 50
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
border_width: 0
|
||||
shadow_width: 8
|
||||
shadow_spread: 2
|
||||
shadow_color: color_black
|
||||
pressed:
|
||||
bg_color: 0x3A3A4C
|
||||
shadow_width: 5
|
||||
on_press:
|
||||
then:
|
||||
- lambda: |-
|
||||
auto temp = id(thermostat_sensor_target_temp).state - 0.5;
|
||||
id(thermostat_sensor_target_temp).publish_state(temp);
|
||||
- homeassistant.service:
|
||||
service: climate.set_temperature
|
||||
data:
|
||||
entity_id: "${thermostat_entity}"
|
||||
temperature: !lambda 'return id(thermostat_sensor_target_temp).state;'
|
||||
- obj:
|
||||
width: 60
|
||||
height: 60
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 45
|
||||
pad_all: 0
|
||||
bg_opa: transp
|
||||
border_opa: transp
|
||||
shadow_width: 4
|
||||
shadow_color: 0xFFFFFF
|
||||
shadow_ofs_x: -4
|
||||
shadow_ofs_y: -2
|
||||
shadow_opa: 30%
|
||||
|
||||
- obj:
|
||||
width: 65
|
||||
height: 65
|
||||
pad_all: 0
|
||||
align: center
|
||||
clickable: false
|
||||
radius: 50
|
||||
border_opa: transp
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
- label:
|
||||
y: -2
|
||||
align: CENTER
|
||||
text_font: nunito_48
|
||||
text_color: color_misty_blue
|
||||
text: "-"
|
||||
|
||||
|
||||
# Name
|
||||
- obj:
|
||||
id: thermostat_name
|
||||
x: 100
|
||||
y: 400
|
||||
width: 360
|
||||
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: thermostat_name_label
|
||||
x: 20
|
||||
align: LEFT_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "friendly name"
|
||||
|
||||
# main
|
||||
- obj:
|
||||
id: thermostat_bg_main
|
||||
width: 250
|
||||
height: 480
|
||||
y: 20
|
||||
align: TOP_RIGHT
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
scrollable: false
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
|
||||
- obj:
|
||||
id: thermostat_bg_placeholder
|
||||
radius: 240
|
||||
x: 235
|
||||
width: 480
|
||||
height: 480
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_slate_blue_gray
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
|
||||
- obj:
|
||||
id: thermostat_temp_arc_bg
|
||||
radius: 230
|
||||
x: 230
|
||||
y: 250
|
||||
width: 460
|
||||
height: 460
|
||||
align: TOP_RIGHT
|
||||
bg_grad: thermostat_temp_gradient
|
||||
bg_grad_dir: ver
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
|
||||
- meter:
|
||||
id: thermostat_meter
|
||||
x: 320 # was 200
|
||||
y: 400 # was 250
|
||||
height: 640 # was 400
|
||||
width: 640 # was 400
|
||||
border_width: 0
|
||||
bg_color: color_slate_blue_gray
|
||||
align: TOP_RIGHT
|
||||
text_color: color_steel_blue
|
||||
scales:
|
||||
- range_from: 10
|
||||
range_to: 30
|
||||
angle_range: 160
|
||||
rotation: 100.0
|
||||
ticks:
|
||||
width: 1
|
||||
count: 21
|
||||
length: 10
|
||||
color: color_white
|
||||
major:
|
||||
stride: 5
|
||||
width: 5
|
||||
length: 15
|
||||
color: color_white
|
||||
label_gap: 15
|
||||
indicators:
|
||||
- tick_style:
|
||||
start_value: 10
|
||||
end_value: 30
|
||||
color_start: color_yellow
|
||||
color_end: color_red
|
||||
width: 1
|
||||
|
||||
- arc:
|
||||
id: thermostat_arc_main
|
||||
align: TOP_RIGHT
|
||||
x: 375 # was 235
|
||||
y: 400 # was 250
|
||||
width: 750 # was 470
|
||||
height: 750 # was 470
|
||||
arc_width: 64 # was 40
|
||||
min_value: 10
|
||||
max_value: 30
|
||||
adjustable: true
|
||||
adv_hittest: true
|
||||
rotation: 90.0
|
||||
start_angle: 10
|
||||
end_angle: 170
|
||||
arc_opa: TRANSP
|
||||
indicator:
|
||||
arc_opa: TRANSP
|
||||
arc_width: 40
|
||||
knob:
|
||||
border_color: color_misty_blue
|
||||
border_width: 7
|
||||
bg_color: color_dark_gray
|
||||
bg_opa: 80%
|
||||
on_release:
|
||||
- homeassistant.service:
|
||||
service: climate.turn_on
|
||||
data:
|
||||
entity_id: "${thermostat_entity}"
|
||||
|
||||
- homeassistant.service:
|
||||
service: climate.set_temperature
|
||||
data:
|
||||
entity_id: "${thermostat_entity}"
|
||||
temperature: !lambda return x;
|
||||
|
||||
- arc:
|
||||
id: thermostat_arc_current_temp
|
||||
clickable: false
|
||||
align: TOP_RIGHT
|
||||
arc_width: 10
|
||||
x: 230
|
||||
y: 250
|
||||
width: 450
|
||||
height: 450
|
||||
min_value: 10
|
||||
max_value: 30
|
||||
adjustable: true
|
||||
adv_hittest: true
|
||||
rotation: 90.0
|
||||
start_angle: 10
|
||||
end_angle: 170
|
||||
arc_opa: TRANSP
|
||||
indicator:
|
||||
arc_opa: TRANSP
|
||||
knob:
|
||||
bg_color: color_dark_gray
|
||||
border_width: 0
|
||||
bg_opa: 80%
|
||||
|
||||
- obj:
|
||||
width: 140
|
||||
height: 120
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_slate_blue_gray
|
||||
pad_all: 0
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
|
||||
- label:
|
||||
id: thermostat_target_temperature_whole
|
||||
x: -40
|
||||
y: 240
|
||||
align: TOP_RIGHT
|
||||
text_font: nunito_84
|
||||
text_color: color_steel_blue
|
||||
text: " "
|
||||
|
||||
- label:
|
||||
id: thermostat_target_temperature_fraction
|
||||
x: -10
|
||||
y: 255
|
||||
align: TOP_RIGHT
|
||||
text_font: nunito_36
|
||||
text_color: color_steel_blue
|
||||
text: " "
|
||||
|
||||
- label:
|
||||
id: thermostat_target_temperature_measurement
|
||||
x: -12
|
||||
y: 220
|
||||
align: TOP_RIGHT
|
||||
text_font: nunito_30
|
||||
text_color: color_steel_blue
|
||||
text: "°C"
|
||||
|
||||
- label:
|
||||
id: thermostat_state_icon
|
||||
x: -10
|
||||
y: 150
|
||||
align: TOP_RIGHT
|
||||
text_font: icons_48
|
||||
text_color: color_steel_blue
|
||||
text: "${heating_icon}"
|
||||
|
||||
- label:
|
||||
id: thermostat_target_temperature_icon
|
||||
x: -70
|
||||
y: 300
|
||||
align: TOP_RIGHT
|
||||
text_font: icons_28
|
||||
text_color: color_steel_blue
|
||||
text: "${temperature_icon}"
|
||||
|
||||
- label:
|
||||
id: thermostat_target_temperature_value
|
||||
x: -10
|
||||
y: 300
|
||||
align: TOP_RIGHT
|
||||
text_font: nunito_30
|
||||
text_color: color_steel_blue
|
||||
text: " "
|
||||
|
||||
# Return
|
||||
- button:
|
||||
id: thermostat_back
|
||||
x: 20
|
||||
y: 400
|
||||
width: 60
|
||||
height: 60
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: thermostat_back_label
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show: devices_page
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
|
||||
|
||||
script:
|
||||
- id: thermostat_get_and_set_translated_state
|
||||
parameters:
|
||||
state_str: string
|
||||
then:
|
||||
- lambda: |-
|
||||
std::string state = state_str;
|
||||
|
||||
auto it = id(climate_translations).find(state);
|
||||
std::string translated_state = (it != id(climate_translations).end()) ? it->second : state;
|
||||
|
||||
lv_label_set_text(id(thermostat_state_label), translated_state.c_str());
|
||||
|
||||
select:
|
||||
- platform: lvgl
|
||||
widget: language_dropdown
|
||||
id: thermostat_select_language
|
||||
on_value:
|
||||
then:
|
||||
- delay: 300ms
|
||||
- script.execute:
|
||||
id: thermostat_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(thermostat_sensor_hvac_mode).state;'
|
||||
|
||||
|
||||
esphome:
|
||||
on_boot:
|
||||
priority: -100
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(thermostat_sensor_hvac_mode).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: thermostat_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(thermostat_sensor_hvac_mode).state;'
|
||||
|
||||
api:
|
||||
on_client_connected:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(thermostat_sensor_hvac_mode).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: thermostat_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(thermostat_sensor_hvac_mode).state;'
|
||||
922
esphome/widgets/vacuum/vacuum_widget.yaml
Normal file
922
esphome/widgets/vacuum/vacuum_widget.yaml
Normal file
@@ -0,0 +1,922 @@
|
||||
substitutions:
|
||||
|
||||
vacuum_entity: "vacuum.roborock_qrevo_s"
|
||||
|
||||
start_icon: "\U0000e90a"
|
||||
play_icon: "\U0000e90a"
|
||||
pause_icon: "\U0000e90b"
|
||||
stop_icon: "\U0000e91c"
|
||||
locate_icon: "\U0000e923"
|
||||
docked_icon: "\U0000e924"
|
||||
fan_icon: "\U0000e926"
|
||||
room_plan_icon: "\U0000e927"
|
||||
battery_0_icon: "\U0000e928"
|
||||
battery_20_icon: "\U0000e929"
|
||||
battery_40_icon: "\U0000e92a"
|
||||
battery_60_icon: "\U0000e92b"
|
||||
battery_80_icon: "\U0000e92c"
|
||||
battery_100_icon: "\U0000e92d"
|
||||
|
||||
globals:
|
||||
- id: vacuum_fan_speeds
|
||||
type: std::vector<std::string>
|
||||
restore_value: false
|
||||
|
||||
- id: vacuum_selected_fan_speed_index
|
||||
type: int
|
||||
restore_value: false
|
||||
|
||||
sensor:
|
||||
# Battery level
|
||||
- platform: homeassistant
|
||||
id: vacuum_battery_level_sensor
|
||||
entity_id: "${vacuum_entity}"
|
||||
attribute: battery_level
|
||||
on_value:
|
||||
- lvgl.label.update:
|
||||
id: vacuum_battery_level_label
|
||||
text: !lambda |-
|
||||
if (isnan(x)) return " ";
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.0f%%", x);
|
||||
return std::string(buffer);
|
||||
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_battery_level_sensor).state >= 80;'
|
||||
then:
|
||||
- lvgl.image.update:
|
||||
id: vacuum_battery_level_img
|
||||
src: battery_very_high_img
|
||||
else:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_battery_level_sensor).state >= 60;'
|
||||
then:
|
||||
- lvgl.image.update:
|
||||
id: vacuum_battery_level_img
|
||||
src: battery_high_img
|
||||
else:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_battery_level_sensor).state >= 40;'
|
||||
then:
|
||||
- lvgl.image.update:
|
||||
id: vacuum_battery_level_img
|
||||
src: battery_middle_img
|
||||
else:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_battery_level_sensor).state >= 20;'
|
||||
then:
|
||||
- lvgl.image.update:
|
||||
id: vacuum_battery_level_img
|
||||
src: battery_low_img
|
||||
else:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_battery_level_sensor).state >= 1;'
|
||||
then:
|
||||
- lvgl.image.update:
|
||||
id: vacuum_battery_level_img
|
||||
src: battery_very_low_img
|
||||
else:
|
||||
|
||||
- lvgl.image.update:
|
||||
id: vacuum_battery_level_img
|
||||
src: battery_empty_img
|
||||
|
||||
# Cleaned area
|
||||
- platform: homeassistant
|
||||
id: vacuum_cleaned_area_sensor
|
||||
entity_id: "${vacuum_entity}"
|
||||
attribute: cleaned_area
|
||||
on_value:
|
||||
- lvgl.label.update:
|
||||
id: vacuum_cleaned_area_label
|
||||
text: !lambda |-
|
||||
if (isnan(x)) return " ";
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.2f m²", x);
|
||||
return std::string(buffer);
|
||||
|
||||
text_sensor:
|
||||
|
||||
- platform: homeassistant
|
||||
id: vacuum_fan_speed_list_sensor
|
||||
entity_id: "${vacuum_entity}"
|
||||
attribute: fan_speed_list
|
||||
on_value:
|
||||
- lambda: |-
|
||||
ESP_LOGD("vacuum", "Fan speed list received: %s", x.c_str());
|
||||
|
||||
std::vector<std::string> options;
|
||||
std::string input = x;
|
||||
|
||||
if (!input.empty() && input != "unknown") {
|
||||
|
||||
input.erase(std::remove(input.begin(), input.end(), '['), input.end());
|
||||
input.erase(std::remove(input.begin(), input.end(), ']'), input.end());
|
||||
input.erase(std::remove(input.begin(), input.end(), '\''), input.end());
|
||||
input.erase(std::remove(input.begin(), input.end(), '"'), input.end());
|
||||
|
||||
std::stringstream ss(input);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, ',')) {
|
||||
item.erase(0, item.find_first_not_of(" \t"));
|
||||
item.erase(item.find_last_not_of(" \t") + 1);
|
||||
if (!item.empty()) {
|
||||
options.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.empty()) {
|
||||
options = {"Silent", "Standard", "Medium", "High"};
|
||||
}
|
||||
|
||||
id(vacuum_fan_speeds) = options;
|
||||
|
||||
auto dropdown = id(vacuum_fan_speed_dropdown);
|
||||
if (dropdown != nullptr) {
|
||||
dropdown->set_options(options);
|
||||
}
|
||||
|
||||
|
||||
- platform: homeassistant
|
||||
id: vacuum_fan_speed_sensor
|
||||
entity_id: "${vacuum_entity}"
|
||||
attribute: fan_speed
|
||||
on_value:
|
||||
- lambda: |-
|
||||
auto& speeds = id(vacuum_fan_speeds);
|
||||
|
||||
if (!speeds.empty()) {
|
||||
for (int i = 0; i < (int)speeds.size(); i++) {
|
||||
if (speeds[i] == x) {
|
||||
id(vacuum_selected_fan_speed_index) = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- lvgl.dropdown.update:
|
||||
id: vacuum_fan_speed_dropdown
|
||||
selected_index: !lambda return id(vacuum_selected_fan_speed_index);
|
||||
|
||||
- platform: homeassistant
|
||||
id: vacuum_name_sensor
|
||||
entity_id: "${vacuum_entity}"
|
||||
attribute: friendly_name
|
||||
on_value:
|
||||
- lvgl.label.update:
|
||||
id: vacuum_label_name
|
||||
text: !lambda return x;
|
||||
|
||||
- platform: homeassistant
|
||||
id: vacuum_state_sensor
|
||||
entity_id: "${vacuum_entity}"
|
||||
on_value:
|
||||
then:
|
||||
- script.execute:
|
||||
id: vacuum_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(vacuum_state_sensor).state;'
|
||||
|
||||
- lvgl.widget.hide: vacuum_battery_level_img
|
||||
- lvgl.widget.hide: vacuum_charging_animation
|
||||
|
||||
- lvgl.widget.hide: vacuum_cleaning_animation
|
||||
- lvgl.widget.hide: vacuum_go_home_animation
|
||||
- lvgl.widget.hide: vacuum_not_animation
|
||||
|
||||
- lvgl.widget.hide: vacuum_bg_controls_cleaning
|
||||
- lvgl.widget.hide: vacuum_bg_controls_paused
|
||||
- lvgl.widget.hide: vacuum_bg_controls_docked
|
||||
- lvgl.widget.hide: vacuum_bg_controls_idle
|
||||
- lvgl.widget.hide: vacuum_bg_controls_returning
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "cleaning";'
|
||||
then:
|
||||
- lvgl.widget.show: vacuum_cleaning_animation
|
||||
- lvgl.widget.show: vacuum_bg_controls_cleaning
|
||||
- lvgl.widget.show: vacuum_battery_level_img
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "returning";'
|
||||
then:
|
||||
- lvgl.widget.show: vacuum_go_home_animation
|
||||
- lvgl.widget.show: vacuum_bg_controls_returning
|
||||
- lvgl.widget.show: vacuum_battery_level_img
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "docked";'
|
||||
then:
|
||||
- lvgl.widget.show: vacuum_not_animation
|
||||
- lvgl.widget.show: vacuum_bg_controls_docked
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_battery_level_sensor).state != 100;'
|
||||
then:
|
||||
- lvgl.widget.show: vacuum_charging_animation
|
||||
else:
|
||||
- lvgl.widget.show: vacuum_battery_level_img
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "paused";'
|
||||
then:
|
||||
- lvgl.widget.show: vacuum_not_animation
|
||||
- lvgl.widget.show: vacuum_bg_controls_paused
|
||||
- lvgl.widget.show: vacuum_battery_level_img
|
||||
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return x == "idle";'
|
||||
then:
|
||||
- lvgl.widget.show: vacuum_not_animation
|
||||
- lvgl.widget.show: vacuum_bg_controls_idle
|
||||
- lvgl.widget.show: vacuum_battery_level_img
|
||||
|
||||
|
||||
lvgl:
|
||||
pages:
|
||||
- id: vacuum_page
|
||||
bg_color: color_slate_blue_gray
|
||||
widgets:
|
||||
# main
|
||||
- obj:
|
||||
id: vacuum_bg_main
|
||||
y: 20
|
||||
width: 440
|
||||
height: 240
|
||||
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:
|
||||
- obj:
|
||||
x: 10
|
||||
y: 0
|
||||
width: 140
|
||||
height: 50
|
||||
align: TOP_LEFT
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
align: LEFT_MID
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${fan_icon}"
|
||||
- dropdown:
|
||||
id: vacuum_fan_speed_dropdown
|
||||
x: 30
|
||||
width: 80
|
||||
height: 40
|
||||
align: LEFT_MID
|
||||
options: []
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
dropdown_list:
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text_line_space: 5
|
||||
pad_all: 8
|
||||
max_height: 200
|
||||
selected:
|
||||
checked:
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
text_color: color_misty_blue
|
||||
pressed:
|
||||
bg_opa: TRANSP
|
||||
indicator:
|
||||
text_opa: TRANSP
|
||||
on_value:
|
||||
- homeassistant.action:
|
||||
action: vacuum.set_fan_speed
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
fan_speed: !lambda |-
|
||||
auto& speeds = id(vacuum_fan_speeds);
|
||||
if (x >= 0 && x < (int)speeds.size()) {
|
||||
return speeds[x];
|
||||
}
|
||||
return std::string("");
|
||||
|
||||
# battery level label
|
||||
- obj:
|
||||
x: 10
|
||||
y: 0
|
||||
width: 140
|
||||
height: 50
|
||||
align: BOTTOM_LEFT
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
widgets:
|
||||
# state
|
||||
- image:
|
||||
align: LEFT_MID
|
||||
id: vacuum_battery_level_img
|
||||
src: battery_very_high_img
|
||||
|
||||
# charging animation
|
||||
- animimg:
|
||||
id: vacuum_charging_animation
|
||||
align: LEFT_MID
|
||||
hidden: true
|
||||
src: [
|
||||
battery_0_img,
|
||||
battery_20_img,
|
||||
battery_40_img,
|
||||
battery_60_img,
|
||||
battery_80_img,
|
||||
battery_very_high_img,
|
||||
]
|
||||
duration: 1500ms
|
||||
|
||||
- label:
|
||||
id: vacuum_battery_level_label
|
||||
x: 20
|
||||
align: LEFT_MID
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: " "
|
||||
|
||||
# state label
|
||||
- obj:
|
||||
x: -10
|
||||
y: 0
|
||||
width: 340
|
||||
height: 50
|
||||
align: TOP_RIGHT
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
align: RIGHT_MID
|
||||
id: vacuum_state_label
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: ""
|
||||
|
||||
# cleaned area label
|
||||
- obj:
|
||||
x: -10
|
||||
y: 0
|
||||
width: 140
|
||||
height: 50
|
||||
align: BOTTOM_RIGHT
|
||||
pad_all: 0
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
widgets:
|
||||
- label:
|
||||
align: RIGHT_MID
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${room_plan_icon}"
|
||||
- label:
|
||||
x: -40
|
||||
align: RIGHT_MID
|
||||
id: vacuum_cleaned_area_label
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: ""
|
||||
|
||||
# without animation
|
||||
- image:
|
||||
id: vacuum_not_animation
|
||||
y: 10
|
||||
align: CENTER
|
||||
src: vacuum_img
|
||||
|
||||
# return to base animation
|
||||
- animimg:
|
||||
id: vacuum_go_home_animation
|
||||
hidden: true
|
||||
y: 10
|
||||
align: CENTER
|
||||
src: [
|
||||
vacuum_img,
|
||||
vacuum_5_img,
|
||||
vacuum_10_img,
|
||||
vacuum_15_img,
|
||||
vacuum_10_img,
|
||||
vacuum_5_img,
|
||||
vacuum_img,
|
||||
vacuum_355_img,
|
||||
vacuum_350_img,
|
||||
vacuum_345_img,
|
||||
vacuum_350_img,
|
||||
vacuum_355_img,
|
||||
]
|
||||
duration: 2000ms
|
||||
|
||||
# cleaning animation
|
||||
- animimg:
|
||||
id: vacuum_cleaning_animation
|
||||
hidden: true
|
||||
y: 0
|
||||
align: CENTER
|
||||
src: [
|
||||
vacuum_img,
|
||||
vacuum_0_10_img,
|
||||
vacuum_0_20_img,
|
||||
vacuum_0_30_img,
|
||||
vacuum_0_20_img,
|
||||
vacuum_0_10_img,
|
||||
vacuum_img,
|
||||
vacuum_5_img,
|
||||
vacuum_10_img,
|
||||
vacuum_15_img,
|
||||
vacuum_20_img,
|
||||
vacuum_20_10_img,
|
||||
vacuum_20_20_img,
|
||||
vacuum_20_30_img,
|
||||
vacuum_20_20_img,
|
||||
vacuum_20_10_img,
|
||||
vacuum_20_img,
|
||||
vacuum_15_img,
|
||||
vacuum_10_img,
|
||||
vacuum_5_img,
|
||||
vacuum_img,
|
||||
vacuum_0_10_img,
|
||||
vacuum_0_20_img,
|
||||
vacuum_0_30_img,
|
||||
vacuum_0_20_img,
|
||||
vacuum_0_10_img,
|
||||
vacuum_img,
|
||||
vacuum_355_img,
|
||||
vacuum_350_img,
|
||||
vacuum_345_img,
|
||||
vacuum_340_img,
|
||||
vacuum_340_10_img,
|
||||
vacuum_340_20_img,
|
||||
vacuum_340_30_img,
|
||||
vacuum_340_20_img,
|
||||
vacuum_340_10_img,
|
||||
vacuum_340_img,
|
||||
vacuum_345_img,
|
||||
vacuum_350_img,
|
||||
vacuum_355_img,
|
||||
]
|
||||
duration: 6000ms
|
||||
|
||||
# docked state controls
|
||||
- obj:
|
||||
id: vacuum_bg_controls_docked
|
||||
x: 20
|
||||
y: 280
|
||||
width: 440
|
||||
height: 100
|
||||
pad_all: 10
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
layout:
|
||||
type: FLEX
|
||||
flex_align_main: SPACE_AROUND
|
||||
flex_align_cross: CENTER
|
||||
widgets:
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${play_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "docked";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.start
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${locate_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "docked";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.locate
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
|
||||
# cleaning state controls
|
||||
- obj:
|
||||
id: vacuum_bg_controls_cleaning
|
||||
hidden: true
|
||||
x: 20
|
||||
y: 280
|
||||
width: 440
|
||||
height: 100
|
||||
pad_all: 10
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
layout:
|
||||
type: FLEX
|
||||
flex_align_main: SPACE_AROUND
|
||||
flex_align_cross: CENTER
|
||||
widgets:
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${pause_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "cleaning";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.pause
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${stop_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "cleaning";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.stop
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${docked_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "cleaning";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.return_to_base
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
|
||||
# paused state controls
|
||||
- obj:
|
||||
id: vacuum_bg_controls_paused
|
||||
hidden: true
|
||||
x: 20
|
||||
y: 280
|
||||
width: 440
|
||||
height: 100
|
||||
pad_all: 10
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
layout:
|
||||
type: FLEX
|
||||
flex_align_main: SPACE_AROUND
|
||||
flex_align_cross: CENTER
|
||||
widgets:
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${play_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "paused";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.start
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${docked_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "paused";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.return_to_base
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
# idle state controls
|
||||
- obj:
|
||||
id: vacuum_bg_controls_idle
|
||||
hidden: true
|
||||
x: 20
|
||||
y: 280
|
||||
width: 440
|
||||
height: 100
|
||||
pad_all: 10
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
layout:
|
||||
type: FLEX
|
||||
flex_align_main: SPACE_AROUND
|
||||
flex_align_cross: CENTER
|
||||
widgets:
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${play_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "idle";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.start
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${locate_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "idle";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.locate
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${docked_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "idle";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.return_to_base
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
# returning state controls
|
||||
- obj:
|
||||
id: vacuum_bg_controls_returning
|
||||
hidden: true
|
||||
x: 20
|
||||
y: 280
|
||||
width: 440
|
||||
height: 100
|
||||
pad_all: 10
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
layout:
|
||||
type: FLEX
|
||||
flex_align_main: SPACE_AROUND
|
||||
flex_align_cross: CENTER
|
||||
widgets:
|
||||
- button:
|
||||
width: 80
|
||||
height: 80
|
||||
bg_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_color: color_misty_blue
|
||||
text_font: icons_38
|
||||
text: "${play_icon}"
|
||||
on_press:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).state == "returning";'
|
||||
then:
|
||||
- homeassistant.action:
|
||||
action: vacuum.start
|
||||
data:
|
||||
entity_id: "${vacuum_entity}"
|
||||
|
||||
# Return
|
||||
- button:
|
||||
x: 20
|
||||
y: 400
|
||||
width: 60
|
||||
height: 60
|
||||
align: TOP_LEFT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text_font: icons_28
|
||||
text_color: color_misty_blue
|
||||
text: "${exit_icon}"
|
||||
on_press:
|
||||
- lvgl.page.show: devices_page
|
||||
- lvgl.widget.show: menu_controls_main
|
||||
|
||||
|
||||
# vacuum entity friendly name
|
||||
- obj:
|
||||
id: vacuum_bg_name
|
||||
x: -20
|
||||
y: 400
|
||||
width: 360
|
||||
height: 60
|
||||
align: TOP_RIGHT
|
||||
bg_color: color_steel_blue
|
||||
bg_opa: 20%
|
||||
border_opa: TRANSP
|
||||
border_width: 0
|
||||
shadow_opa: TRANSP
|
||||
radius: 10
|
||||
widgets:
|
||||
- label:
|
||||
id: vacuum_label_name
|
||||
align: CENTER
|
||||
text_font: nunito_16
|
||||
text_color: color_misty_blue
|
||||
text: "friendly name"
|
||||
|
||||
|
||||
script:
|
||||
- id: vacuum_get_and_set_translated_state
|
||||
parameters:
|
||||
state_str: string
|
||||
then:
|
||||
- lambda: |-
|
||||
std::string state = state_str;
|
||||
|
||||
auto it = id(vacuum_translations).find(state);
|
||||
std::string translated_state = (it != id(vacuum_translations).end()) ? it->second : state;
|
||||
|
||||
lv_label_set_text(id(vacuum_state_label), translated_state.c_str());
|
||||
|
||||
|
||||
select:
|
||||
- platform: lvgl
|
||||
widget: language_dropdown
|
||||
id: vacuum_select_language
|
||||
on_value:
|
||||
then:
|
||||
- delay: 300ms
|
||||
- script.execute:
|
||||
id: vacuum_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(vacuum_state_sensor).state;'
|
||||
|
||||
esphome:
|
||||
on_boot:
|
||||
priority: -100
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: vacuum_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(vacuum_state_sensor).state;'
|
||||
|
||||
api:
|
||||
on_client_connected:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(vacuum_state_sensor).has_state();'
|
||||
then:
|
||||
- script.execute:
|
||||
id: vacuum_get_and_set_translated_state
|
||||
state_str: !lambda 'return id(vacuum_state_sensor).state;'
|
||||
Reference in New Issue
Block a user