Edit esp-bedside-panel.yaml
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedside-panel.yaml
|
||||
#:########################################################################################:#
|
||||
# VERSIONS:
|
||||
# V1.3 2026-07-16 Added Security page with 640x360 Doorbell camera snapshot
|
||||
# V1.2 2026-07-16 Removed Climate title and aligned Heat Pump heading above Off
|
||||
# V1.1 2026-07-16 Increased Clock to 280px and date to 64px
|
||||
# V1.0 2026-07-16 First full Bedroom/Climate/Clock release; added 2-hour Sleep timer
|
||||
@@ -96,12 +97,12 @@ substitutions:
|
||||
# Device Naming
|
||||
device_name: "esp-bedside-panel"
|
||||
friendly_name: "ESP Bedside Panel"
|
||||
description_comment: "Guition JC1060P470C_I_W_Y ESP32-P4 bedside control panel. Simplified Climate heading layout with aligned Heat Pump label. (Layout V1.1)"
|
||||
description_comment: "Guition JC1060P470C_I_W_Y ESP32-P4 bedside control panel. Security page with Home Assistant Doorbell camera snapshots. (Layout V1.1)"
|
||||
device_area: "Bedroom"
|
||||
|
||||
# Project Naming
|
||||
project_name: "Guition.JC1060P470C_I_W_Y"
|
||||
project_version: "v1.2"
|
||||
project_version: "v1.3"
|
||||
|
||||
# Passwords & Secrets
|
||||
api_key: !secret esp-api_key
|
||||
@@ -126,6 +127,12 @@ substitutions:
|
||||
control_brightness: "80%"
|
||||
clock_brightness: "4%"
|
||||
|
||||
# Security Camera Settings
|
||||
# Change this only if homeassistant.local is not reachable from the panel.
|
||||
home_assistant_internal_url: "http://homeassistant.local:8123"
|
||||
security_camera_refresh_interval: "5s"
|
||||
security_doorbell_camera_entity: "camera.view_road_front_door_fluent"
|
||||
|
||||
# Home Assistant Entities - Status / Environment
|
||||
moon_phase_entity: "sensor.astroweather_moon_phase"
|
||||
outdoor_temperature_entity: "sensor.lounge_outside_temperature"
|
||||
@@ -796,6 +803,12 @@ globals:
|
||||
restore_value: true
|
||||
initial_value: "0"
|
||||
|
||||
# True only while the Security page is visible.
|
||||
- id: security_page_active
|
||||
type: bool
|
||||
restore_value: false
|
||||
initial_value: "false"
|
||||
|
||||
#:########################################################################################:#
|
||||
# SCRIPTS:
|
||||
# Refresh all state-dependent LVGL button colours
|
||||
@@ -1237,6 +1250,75 @@ script:
|
||||
? lv_color_hex(0x6B4A86)
|
||||
: lv_color_hex(0x28313D);
|
||||
|
||||
# Download a current Doorbell image through the authenticated proxy path
|
||||
# supplied by the Home Assistant camera entity.
|
||||
- id: refresh_security_camera
|
||||
mode: restart
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: |-
|
||||
return (
|
||||
id(lvgl_ready) &&
|
||||
id(security_page_active)
|
||||
);
|
||||
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: |-
|
||||
const auto path =
|
||||
id(ha_doorbell_entity_picture).state;
|
||||
|
||||
return (
|
||||
!path.empty() &&
|
||||
path != "unknown" &&
|
||||
path != "unavailable"
|
||||
);
|
||||
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: security_camera_status_label
|
||||
text: "Loading Doorbell..."
|
||||
|
||||
- online_image.set_url:
|
||||
id: security_camera_image
|
||||
url: !lambda |-
|
||||
const std::string path =
|
||||
id(ha_doorbell_entity_picture).state;
|
||||
|
||||
std::string url;
|
||||
|
||||
if (
|
||||
path.rfind("http://", 0) == 0 ||
|
||||
path.rfind("https://", 0) == 0
|
||||
) {
|
||||
url = path;
|
||||
} else {
|
||||
url =
|
||||
std::string(
|
||||
"${home_assistant_internal_url}"
|
||||
) + path;
|
||||
}
|
||||
|
||||
char suffix[32];
|
||||
snprintf(
|
||||
suffix,
|
||||
sizeof(suffix),
|
||||
"%ctime=%lu",
|
||||
url.find('?') == std::string::npos
|
||||
? '?'
|
||||
: '&',
|
||||
static_cast<unsigned long>(millis())
|
||||
);
|
||||
|
||||
return url + suffix;
|
||||
|
||||
else:
|
||||
- lvgl.label.update:
|
||||
id: security_camera_status_label
|
||||
text: "Waiting for Doorbell camera"
|
||||
|
||||
- id: release_climate_profile_optimistic
|
||||
mode: restart
|
||||
then:
|
||||
@@ -1340,6 +1422,16 @@ interval:
|
||||
else:
|
||||
- script.execute: refresh_sleep_timer
|
||||
|
||||
- interval: "${security_camera_refresh_interval}"
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: |-
|
||||
return id(security_page_active);
|
||||
|
||||
then:
|
||||
- script.execute: refresh_security_camera
|
||||
|
||||
#:########################################################################################:#
|
||||
# TEXT SENSOR COMPONENT:
|
||||
# https://esphome.io/components/text_sensor/
|
||||
@@ -1383,6 +1475,23 @@ text_sensor:
|
||||
then:
|
||||
- script.execute: refresh_climate_controls
|
||||
|
||||
# Home Assistant supplies a short-lived authenticated camera proxy URL in
|
||||
# the entity_picture attribute. This avoids storing an HA token in firmware.
|
||||
- platform: homeassistant
|
||||
id: ha_doorbell_entity_picture
|
||||
entity_id: "${security_doorbell_camera_entity}"
|
||||
attribute: entity_picture
|
||||
internal: true
|
||||
on_value:
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: |-
|
||||
return id(security_page_active);
|
||||
|
||||
then:
|
||||
- script.execute: refresh_security_camera
|
||||
|
||||
- platform: version
|
||||
name: "${friendly_name} ESPHome Version"
|
||||
hide_timestamp: true
|
||||
@@ -1400,6 +1509,64 @@ text_sensor:
|
||||
mac_address:
|
||||
name: "${friendly_name} MAC Address"
|
||||
|
||||
#:########################################################################################:#
|
||||
# HTTP REQUEST:
|
||||
# Used by the online Doorbell image
|
||||
# https://esphome.io/components/http_request/
|
||||
#:########################################################################################:#
|
||||
http_request:
|
||||
timeout: 10s
|
||||
follow_redirects: true
|
||||
|
||||
#:########################################################################################:#
|
||||
# ONLINE SECURITY CAMERA IMAGE:
|
||||
# Home Assistant camera proxy image, resized for the Security page
|
||||
# https://esphome.io/components/image/online_image/
|
||||
#:########################################################################################:#
|
||||
image:
|
||||
- platform: online_image
|
||||
id: security_camera_image
|
||||
url: "${home_assistant_internal_url}/"
|
||||
format: JPEG
|
||||
type: RGB565
|
||||
resize: 640x360
|
||||
update_interval: never
|
||||
buffer_size: 32768
|
||||
|
||||
on_download_finished:
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: |-
|
||||
return (
|
||||
id(lvgl_ready) &&
|
||||
id(security_page_active)
|
||||
);
|
||||
|
||||
then:
|
||||
- lvgl.image.update:
|
||||
id: security_camera_widget
|
||||
src: security_camera_image
|
||||
|
||||
- lvgl.label.update:
|
||||
id: security_camera_status_label
|
||||
text: ""
|
||||
|
||||
on_error:
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: |-
|
||||
return (
|
||||
id(lvgl_ready) &&
|
||||
id(security_page_active)
|
||||
);
|
||||
|
||||
then:
|
||||
- lvgl.label.update:
|
||||
id: security_camera_status_label
|
||||
text: "Camera image unavailable"
|
||||
|
||||
#:########################################################################################:#
|
||||
# LVGL:
|
||||
# https://esphome.io/components/lvgl/
|
||||
@@ -1427,6 +1594,11 @@ lvgl:
|
||||
on_idle:
|
||||
- timeout: "${clock_idle_timeout}"
|
||||
then:
|
||||
- lambda: |-
|
||||
id(security_page_active) = false;
|
||||
|
||||
- online_image.release: security_camera_image
|
||||
|
||||
- lvgl.page.show:
|
||||
id: clock_page
|
||||
animation: FADE_IN
|
||||
@@ -1863,25 +2035,41 @@ lvgl:
|
||||
bg_color: 0x34404F
|
||||
|
||||
- button:
|
||||
id: future_2_navigation_button
|
||||
id: security_navigation_button
|
||||
x: 612
|
||||
y: 475
|
||||
width: 190
|
||||
height: 92
|
||||
widgets:
|
||||
- label:
|
||||
id: future_2_navigation_button_label
|
||||
id: security_navigation_button_label
|
||||
align: CENTER
|
||||
text: "Future2"
|
||||
text: "Security"
|
||||
text_font: font_button
|
||||
text_color: 0xAEB8C4
|
||||
bg_color: 0x28313D
|
||||
text_color: 0xFFFFFF
|
||||
bg_color: 0x493535
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x445365
|
||||
border_color: 0x805858
|
||||
radius: 16
|
||||
pressed:
|
||||
bg_color: 0x34404F
|
||||
bg_color: 0x654949
|
||||
|
||||
on_click:
|
||||
- lambda: |-
|
||||
id(security_page_active) = true;
|
||||
|
||||
- lvgl.page.show:
|
||||
id: security_page
|
||||
animation: MOVE_LEFT
|
||||
time: 220ms
|
||||
|
||||
- light.turn_on:
|
||||
id: display_backlight
|
||||
brightness: "${control_brightness}"
|
||||
transition_length: 250ms
|
||||
|
||||
- script.execute: refresh_security_camera
|
||||
|
||||
- button:
|
||||
id: clock_now_button
|
||||
@@ -2579,6 +2767,200 @@ lvgl:
|
||||
brightness: "${clock_brightness}"
|
||||
transition_length: 1500ms
|
||||
|
||||
#:####################################################################################:#
|
||||
# SECURITY PAGE
|
||||
#:####################################################################################:#
|
||||
- id: security_page
|
||||
skip: true
|
||||
bg_color: 0x0D1218
|
||||
bg_opa: COVER
|
||||
|
||||
widgets:
|
||||
#:################################################################################:#
|
||||
# CAMERA SELECTION
|
||||
#:################################################################################:#
|
||||
- button:
|
||||
id: security_doorbell_button
|
||||
x: 25
|
||||
y: 18
|
||||
width: 220
|
||||
height: 70
|
||||
bg_color: 0x493535
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x9A6666
|
||||
radius: 16
|
||||
pressed:
|
||||
bg_color: 0x654949
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text: "Doorbell"
|
||||
text_font: font_button
|
||||
text_color: 0xFFFFFF
|
||||
on_click:
|
||||
- script.execute: refresh_security_camera
|
||||
|
||||
- button:
|
||||
id: security_camera_2_button
|
||||
x: 272
|
||||
y: 18
|
||||
width: 220
|
||||
height: 70
|
||||
bg_color: 0x28313D
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x445365
|
||||
radius: 16
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text: "Camera2"
|
||||
text_font: font_button
|
||||
text_color: 0x8D98A6
|
||||
|
||||
- button:
|
||||
id: security_camera_3_button
|
||||
x: 519
|
||||
y: 18
|
||||
width: 220
|
||||
height: 70
|
||||
bg_color: 0x28313D
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x445365
|
||||
radius: 16
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text: "Camera3"
|
||||
text_font: font_button
|
||||
text_color: 0x8D98A6
|
||||
|
||||
- button:
|
||||
id: security_camera_4_button
|
||||
x: 766
|
||||
y: 18
|
||||
width: 220
|
||||
height: 70
|
||||
bg_color: 0x28313D
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x445365
|
||||
radius: 16
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text: "Camera4"
|
||||
text_font: font_button
|
||||
text_color: 0x8D98A6
|
||||
|
||||
#:################################################################################:#
|
||||
# 640x360 CAMERA IMAGE
|
||||
#:################################################################################:#
|
||||
- obj:
|
||||
x: 190
|
||||
y: 98
|
||||
width: 644
|
||||
height: 364
|
||||
bg_color: 0x020304
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x445365
|
||||
radius: 13
|
||||
shadow_width: 0
|
||||
clickable: false
|
||||
|
||||
- image:
|
||||
id: security_camera_widget
|
||||
x: 192
|
||||
y: 100
|
||||
width: 640
|
||||
height: 360
|
||||
src: security_camera_image
|
||||
radius: 11
|
||||
clip_corner: true
|
||||
clickable: false
|
||||
|
||||
- label:
|
||||
id: security_camera_status_label
|
||||
x: 192
|
||||
y: 260
|
||||
width: 640
|
||||
text: "Waiting for Doorbell camera"
|
||||
text_font: font_button
|
||||
text_align: CENTER
|
||||
text_color: 0xD4D8DE
|
||||
clickable: false
|
||||
|
||||
#:################################################################################:#
|
||||
# BOTTOM NAVIGATION
|
||||
#:################################################################################:#
|
||||
- button:
|
||||
id: security_back_button
|
||||
x: 612
|
||||
y: 475
|
||||
width: 190
|
||||
height: 92
|
||||
bg_color: 0x315843
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x548C6C
|
||||
radius: 16
|
||||
pressed:
|
||||
bg_color: 0x416F55
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text: "Back"
|
||||
text_font: font_button
|
||||
text_color: 0xFFFFFF
|
||||
on_click:
|
||||
- lambda: |-
|
||||
id(security_page_active) = false;
|
||||
|
||||
- online_image.release: security_camera_image
|
||||
|
||||
- lvgl.page.show:
|
||||
id: bedroom_page
|
||||
animation: MOVE_RIGHT
|
||||
time: 220ms
|
||||
|
||||
- button:
|
||||
id: security_clock_button
|
||||
x: 810
|
||||
y: 475
|
||||
width: 190
|
||||
height: 92
|
||||
bg_color: 0x214F72
|
||||
bg_opa: COVER
|
||||
border_width: 2
|
||||
border_color: 0x3E7FA7
|
||||
radius: 16
|
||||
pressed:
|
||||
bg_color: 0x2E6A96
|
||||
widgets:
|
||||
- label:
|
||||
align: CENTER
|
||||
text: "Clock"
|
||||
text_font: font_button
|
||||
text_color: 0xFFFFFF
|
||||
on_click:
|
||||
- lambda: |-
|
||||
id(security_page_active) = false;
|
||||
|
||||
- online_image.release: security_camera_image
|
||||
|
||||
- lvgl.page.show:
|
||||
id: clock_page
|
||||
animation: FADE_IN
|
||||
time: 250ms
|
||||
|
||||
- light.turn_on:
|
||||
id: display_backlight
|
||||
brightness: "${clock_brightness}"
|
||||
transition_length: 1500ms
|
||||
|
||||
#:####################################################################################:#
|
||||
# CLOCK PAGE
|
||||
#:####################################################################################:#
|
||||
|
||||
Reference in New Issue
Block a user