Edit esp-bedside-panel.yaml

This commit is contained in:
ESPHome Device Builder
2026-07-20 12:01:52 +12:00
parent 241a4954bd
commit ea604b8a30
+558 -6
View File
@@ -6,6 +6,8 @@
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedside-panel.yaml # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedside-panel.yaml
#:########################################################################################:# #:########################################################################################:#
# VERSIONS: # VERSIONS:
# V1.40 2026-07-20 Added ES8311 speaker output, persistent alarm volume and local speaker test controls
# V1.39 2026-07-19 Removed the Alarm Clock editor title format-truncation warning
# V1.38 2026-07-19 Added per-alarm Snooze controls and a reusable 24-hour time editor # V1.38 2026-07-19 Added per-alarm Snooze controls and a reusable 24-hour time editor
# V1.37 2026-07-19 Added four persistent Alarm Clock configuration rows # V1.37 2026-07-19 Added four persistent Alarm Clock configuration rows
# V1.36 2026-07-19 Added Alarm Clock navigation button and initial empty page # V1.36 2026-07-19 Added Alarm Clock navigation button and initial empty page
@@ -98,6 +100,9 @@
# - Battery-backed RTC: RX8130 # - Battery-backed RTC: RX8130
# - RTC I2C address: 0x32 # - RTC I2C address: 0x32
# - TEMT6000 ambient-light sensor signal: GPIO20 / ADC1 # - TEMT6000 ambient-light sensor signal: GPIO20 / ADC1
# - ES8311 audio codec: I2C address 0x18
# - Audio I2S: MCLK GPIO13, BCLK GPIO12, LRCLK GPIO10, DOUT GPIO9
# - Speaker amplifier enable: GPIO11 (active high on this board revision)
#:########################################################################################:# #:########################################################################################:#
# OPERATION NOTES: # OPERATION NOTES:
# - This build returns to the proven V0.8a structure. # - This build returns to the proven V0.8a structure.
@@ -134,6 +139,9 @@
# - Enable, days, Snooze, vibration, sound and lamp choices are active. # - Enable, days, Snooze, vibration, sound and lamp choices are active.
# - Tapping a time opens a shared circular 24-hour hour/minute roller editor. # - Tapping a time opens a shared circular 24-hour hour/minute roller editor.
# - The Snooze duration is a persistent Home Assistant configuration entity. # - The Snooze duration is a persistent Home Assistant configuration entity.
# - Alarm speaker volume is persistent and adjustable from Home Assistant or the display.
# - The Alarm Clock page provides local Beep, repeating Alarm and Stop hardware tests.
# - Speaker tests generate audio locally and do not require Home Assistant or media files.
#:########################################################################################:# #:########################################################################################:#
# OFFLINE NOTES: # OFFLINE NOTES:
# - LVGL, the clock, touch and backlight operate locally. # - LVGL, the clock, touch and backlight operate locally.
@@ -152,12 +160,12 @@ substitutions:
# Device Naming # Device Naming
device_name: "esp-bedside-panel" device_name: "esp-bedside-panel"
friendly_name: "ESP Bedside Panel" friendly_name: "ESP Bedside Panel"
description_comment: "Guition JC1060P470C_I_W_Y ESP32-P4 bedside control panel. Four-row Alarm Clock interface with Snooze controls and a reusable 24-hour roller time editor. (Layout V1.1)" description_comment: "Guition JC1060P470C_I_W_Y ESP32-P4 bedside control panel. Four-row Alarm Clock interface with local ES8311 speaker testing, persistent alarm volume and a reusable 24-hour roller time editor. (Layout V1.1)"
device_area: "Bedroom" device_area: "Bedroom"
# Project Naming # Project Naming
project_name: "Guition.JC1060P470C_I_W_Y" project_name: "Guition.JC1060P470C_I_W_Y"
project_version: "v1.38" project_version: "v1.40"
# Passwords & Secrets # Passwords & Secrets
api_key: !secret esp-api_key api_key: !secret esp-api_key
@@ -219,6 +227,18 @@ substitutions:
# Alarm Clock Defaults # Alarm Clock Defaults
alarm_snooze_minutes_default: "10" alarm_snooze_minutes_default: "10"
alarm_volume_default: "35"
# Alarm Speaker Hardware
# GPIO11 is the onboard speaker power-amplifier enable pin.
# The rear expansion header diagram confirms GPIO20 is a separate exposed
# GPIO; this project already uses it for the external TEMT6000 sensor.
alarm_i2s_lrclk_pin: "GPIO10"
alarm_i2s_bclk_pin: "GPIO12"
alarm_i2s_mclk_pin: "GPIO13"
alarm_i2s_dout_pin: "GPIO9"
alarm_speaker_enable_pin: "GPIO11"
alarm_audio_sample_rate: "16000"
# Security Camera Settings # Security Camera Settings
# Change this only if homeassistant.local is not reachable from the panel. # Change this only if homeassistant.local is not reachable from the panel.
@@ -380,6 +400,7 @@ esphome:
- script.execute: refresh_navigation_time - script.execute: refresh_navigation_time
- script.execute: refresh_jobs_page - script.execute: refresh_jobs_page
- script.execute: refresh_alarm_clock_page - script.execute: refresh_alarm_clock_page
- script.execute: refresh_alarm_audio_controls
#:########################################################################################:# #:########################################################################################:#
# ESP PLATFORM AND FRAMEWORK: # ESP PLATFORM AND FRAMEWORK:
@@ -510,6 +531,49 @@ i2c:
frequency: 400kHz frequency: 400kHz
scan: true scan: true
#:########################################################################################:#
# I2S AUDIO BUS:
# ES8311 clock and playback data connections
# https://esphome.io/components/i2s_audio/
#:########################################################################################:#
i2s_audio:
- id: alarm_i2s_audio_bus
i2s_lrclk_pin: "${alarm_i2s_lrclk_pin}"
i2s_bclk_pin: "${alarm_i2s_bclk_pin}"
i2s_mclk_pin: "${alarm_i2s_mclk_pin}"
#:########################################################################################:#
# AUDIO DAC:
# Onboard ES8311 mono audio codec
# https://esphome.io/components/audio_dac/es8311/
#:########################################################################################:#
audio_dac:
- platform: es8311
id: alarm_audio_dac
i2c_id: touch_i2c
address: 0x18
bits_per_sample: 16bit
sample_rate: "${alarm_audio_sample_rate}"
use_mclk: true
use_microphone: false
#:########################################################################################:#
# SPEAKER:
# Local 16-bit mono output through the onboard ES8311 and speaker amplifier
# https://esphome.io/components/speaker/i2s_audio/
#:########################################################################################:#
speaker:
- platform: i2s_audio
id: alarm_speaker
i2s_audio_id: alarm_i2s_audio_bus
i2s_dout_pin: "${alarm_i2s_dout_pin}"
dac_type: external
audio_dac: alarm_audio_dac
sample_rate: "${alarm_audio_sample_rate}"
bits_per_sample: 16bit
channel: mono
buffer_duration: 100ms
#:########################################################################################:# #:########################################################################################:#
# OUTPUT: # OUTPUT:
# https://esphome.io/components/output/ledc.html # https://esphome.io/components/output/ledc.html
@@ -955,6 +1019,29 @@ number:
step: 1 step: 1
mode: box mode: box
- platform: template
id: alarm_volume
name: "${friendly_name} Alarm Volume"
icon: mdi:volume-high
entity_category: config
optimistic: true
restore_value: true
initial_value: "${alarm_volume_default}"
unit_of_measurement: "%"
min_value: 5
max_value: 100
step: 5
mode: slider
on_value:
then:
- audio_dac.set_volume:
id: alarm_audio_dac
volume: !lambda |-
return x / 100.0f;
- script.execute: refresh_alarm_audio_controls
#:########################################################################################:# #:########################################################################################:#
# HOME ASSISTANT NUMERIC SENSORS: # HOME ASSISTANT NUMERIC SENSORS:
# https://esphome.io/components/sensor/homeassistant.html # https://esphome.io/components/sensor/homeassistant.html
@@ -1657,6 +1744,12 @@ globals:
restore_value: false restore_value: false
initial_value: "0" initial_value: "0"
# True while the repeating local alarm speaker test is active.
- id: alarm_audio_test_active
type: bool
restore_value: false
initial_value: "false"
#:########################################################################################:# #:########################################################################################:#
# SCRIPTS: # SCRIPTS:
# Refresh all state-dependent LVGL button colours # Refresh all state-dependent LVGL button colours
@@ -2210,6 +2303,285 @@ script:
(1U << 7) (1U << 7)
) != 0; ) != 0;
- script.execute: refresh_alarm_audio_controls
#:######################################################################################:#
# ALARM CLOCK AUDIO TESTING
#:######################################################################################:#
- id: refresh_alarm_audio_controls
mode: restart
then:
- audio_dac.set_volume:
id: alarm_audio_dac
volume: !lambda |-
float volume = id(alarm_volume).state;
if (isnan(volume)) {
volume = 35.0f;
}
return volume / 100.0f;
- if:
condition:
lambda: |-
return id(lvgl_ready);
then:
- lvgl.label.update:
id: alarm_audio_volume_label
text: !lambda |-
float volume = id(alarm_volume).state;
if (isnan(volume)) {
volume = 35.0f;
}
char buffer[16];
snprintf(
buffer,
sizeof(buffer),
"Vol\n%.0f%%",
volume
);
return std::string(buffer);
- lvgl.widget.update:
id: alarm_audio_alarm_button
bg_color: !lambda |-
return id(alarm_audio_test_active)
? lv_color_hex(0x8A3D2D)
: lv_color_hex(0x4D3B24);
border_color: !lambda |-
return id(alarm_audio_test_active)
? lv_color_hex(0xD97055)
: lv_color_hex(0x846338);
- lvgl.label.update:
id: alarm_audio_alarm_label
text: !lambda |-
return id(alarm_audio_test_active)
? std::string("Alarm\nON")
: std::string("Alarm");
- id: alarm_audio_beep
mode: restart
then:
- lambda: |-
id(alarm_audio_test_active) = false;
- script.stop: alarm_audio_alarm_test
- speaker.stop:
id: alarm_speaker
- switch.turn_on: alarm_speaker_amplifier
- delay: 40ms
- audio_dac.set_volume:
id: alarm_audio_dac
volume: !lambda |-
float volume = id(alarm_volume).state;
if (isnan(volume)) {
volume = 35.0f;
}
return volume / 100.0f;
- audio_dac.mute_off:
id: alarm_audio_dac
- lvgl.label.update:
id: alarm_audio_beep_label
text: "Beep\nON"
- speaker.play:
id: alarm_speaker
data: !lambda |-
const uint32_t sample_rate = 16000;
const uint32_t duration_ms = 360;
const uint32_t sample_count =
(sample_rate * duration_ms) / 1000;
const float frequency = 880.0f;
const uint32_t fade_samples = sample_rate / 100;
std::vector<uint8_t> audio;
audio.reserve(sample_count * 2);
for (uint32_t i = 0; i < sample_count; i++) {
float envelope = 1.0f;
if (i < fade_samples) {
envelope =
static_cast<float>(i) / fade_samples;
} else if (i > sample_count - fade_samples) {
envelope =
static_cast<float>(sample_count - i) /
fade_samples;
}
const float phase =
6.28318530718f * frequency *
static_cast<float>(i) / sample_rate;
const int16_t sample = static_cast<int16_t>(
12000.0f * envelope * sinf(phase)
);
audio.push_back(
static_cast<uint8_t>(sample & 0xFF)
);
audio.push_back(
static_cast<uint8_t>((sample >> 8) & 0xFF)
);
}
return audio;
- delay: 430ms
- speaker.finish:
id: alarm_speaker
- delay: 80ms
- audio_dac.mute_on:
id: alarm_audio_dac
- switch.turn_off: alarm_speaker_amplifier
- lvgl.label.update:
id: alarm_audio_beep_label
text: "Beep"
- script.execute: refresh_alarm_audio_controls
- id: alarm_audio_alarm_test
mode: restart
then:
- script.stop: alarm_audio_beep
- speaker.stop:
id: alarm_speaker
- lambda: |-
id(alarm_audio_test_active) = true;
- script.execute: refresh_alarm_audio_controls
- switch.turn_on: alarm_speaker_amplifier
- delay: 40ms
- audio_dac.set_volume:
id: alarm_audio_dac
volume: !lambda |-
float volume = id(alarm_volume).state;
if (isnan(volume)) {
volume = 35.0f;
}
return volume / 100.0f;
- audio_dac.mute_off:
id: alarm_audio_dac
- while:
condition:
lambda: |-
return id(alarm_audio_test_active);
then:
- speaker.play:
id: alarm_speaker
data: !lambda |-
const uint32_t sample_rate = 16000;
const uint32_t duration_ms = 900;
const uint32_t sample_count =
(sample_rate * duration_ms) / 1000;
const uint32_t fade_samples = sample_rate / 80;
std::vector<uint8_t> audio;
audio.reserve(sample_count * 2);
for (uint32_t i = 0; i < sample_count; i++) {
const uint32_t time_ms =
(i * 1000) / sample_rate;
float frequency = 0.0f;
uint32_t burst_start = 0;
uint32_t burst_end = 0;
if (time_ms < 280) {
frequency = 740.0f;
burst_start = 0;
burst_end =
(sample_rate * 280) / 1000;
} else if (time_ms >= 360 && time_ms < 640) {
frequency = 990.0f;
burst_start =
(sample_rate * 360) / 1000;
burst_end =
(sample_rate * 640) / 1000;
}
int16_t sample = 0;
if (frequency > 0.0f) {
float envelope = 1.0f;
if (i < burst_start + fade_samples) {
envelope = static_cast<float>(
i - burst_start
) / fade_samples;
} else if (i > burst_end - fade_samples) {
envelope = static_cast<float>(
burst_end - i
) / fade_samples;
}
const float phase =
6.28318530718f * frequency *
static_cast<float>(i) / sample_rate;
sample = static_cast<int16_t>(
12000.0f * envelope * sinf(phase)
);
}
audio.push_back(
static_cast<uint8_t>(sample & 0xFF)
);
audio.push_back(
static_cast<uint8_t>((sample >> 8) & 0xFF)
);
}
return audio;
- delay: 950ms
- id: stop_alarm_audio
mode: restart
then:
- lambda: |-
id(alarm_audio_test_active) = false;
- script.stop: alarm_audio_beep
- script.stop: alarm_audio_alarm_test
- speaker.stop:
id: alarm_speaker
- audio_dac.mute_on:
id: alarm_audio_dac
- delay: 20ms
- switch.turn_off: alarm_speaker_amplifier
- if:
condition:
lambda: |-
return id(lvgl_ready);
then:
- lvgl.label.update:
id: alarm_audio_beep_label
text: "Beep"
- script.execute: refresh_alarm_audio_controls
#:######################################################################################:# #:######################################################################################:#
# ALARM CLOCK TIME EDITOR # ALARM CLOCK TIME EDITOR
@@ -2250,7 +2622,7 @@ script:
- lvgl.label.update: - lvgl.label.update:
id: alarm_time_editor_title id: alarm_time_editor_title
text: !lambda |- text: !lambda |-
char buffer[20]; char buffer[32];
snprintf( snprintf(
buffer, buffer,
sizeof(buffer), sizeof(buffer),
@@ -4795,10 +5167,24 @@ interval:
- script.execute: refresh_security_camera - script.execute: refresh_security_camera
#:########################################################################################:# #:########################################################################################:#
# HOME ASSISTANT SWITCH COMPONENT: # SWITCH COMPONENTS:
# https://esphome.io/components/switch/homeassistant/ # Onboard speaker amplifier plus imported Home Assistant switches
#:########################################################################################:# #:########################################################################################:#
switch: switch:
#:######################################################################################:#
# ALARM SPEAKER AMPLIFIER
#:######################################################################################:#
- platform: gpio
id: alarm_speaker_amplifier
pin:
number: "${alarm_speaker_enable_pin}"
mode:
output: true
restore_mode: ALWAYS_OFF
#:######################################################################################:#
# HOME ASSISTANT SWITCHES
#:######################################################################################:#
- platform: homeassistant - platform: homeassistant
id: ha_garage_lights id: ha_garage_lights
entity_id: "${garage_lights_entity}" entity_id: "${garage_lights_entity}"
@@ -10562,6 +10948,168 @@ lvgl:
- lambda: |- - lambda: |-
id(alarm_lamp_enabled)[3] = x; id(alarm_lamp_enabled)[3] = x;
#:################################################################################:#
# ALARM SPEAKER TEST CONTROLS
#:################################################################################:#
- obj:
id: alarm_audio_test_panel
x: 10
y: 475
width: 594
height: 92
bg_color: 0x171F29
bg_opa: COVER
border_width: 1
border_color: 0x364250
outline_width: 0
shadow_width: 0
radius: 14
pad_all: 0
clickable: false
widgets:
- button:
id: alarm_audio_volume_down_button
x: 8
y: 10
width: 52
height: 72
bg_color: 0x28313D
bg_opa: COVER
border_width: 2
border_color: 0x557895
radius: 11
pressed:
bg_color: 0x496681
widgets:
- label:
align: CENTER
text: "-"
text_font: font_button
text_color: 0xFFFFFF
on_click:
- number.decrement:
id: alarm_volume
cycle: false
- obj:
x: 66
y: 10
width: 108
height: 72
bg_color: 0x202A36
bg_opa: COVER
border_width: 1
border_color: 0x445365
radius: 11
clickable: false
widgets:
- label:
id: alarm_audio_volume_label
align: CENTER
text: "Vol\n35%"
text_font: font_small
text_align: CENTER
text_color: 0xB9D9ED
- button:
id: alarm_audio_volume_up_button
x: 180
y: 10
width: 52
height: 72
bg_color: 0x28313D
bg_opa: COVER
border_width: 2
border_color: 0x557895
radius: 11
pressed:
bg_color: 0x496681
widgets:
- label:
align: CENTER
text: "+"
text_font: font_button
text_color: 0xFFFFFF
on_click:
- number.increment:
id: alarm_volume
cycle: false
- button:
id: alarm_audio_beep_button
x: 238
y: 10
width: 112
height: 72
bg_color: 0x315843
bg_opa: COVER
border_width: 2
border_color: 0x72AE88
radius: 11
pressed:
bg_color: 0x416F55
widgets:
- label:
id: alarm_audio_beep_label
align: CENTER
text: "Beep"
text_font: font_small
text_align: CENTER
text_color: 0xFFFFFF
on_click:
- script.execute: alarm_audio_beep
- button:
id: alarm_audio_alarm_button
x: 356
y: 10
width: 132
height: 72
bg_color: 0x4D3B24
bg_opa: COVER
border_width: 2
border_color: 0x846338
radius: 11
pressed:
bg_color: 0x6B502B
widgets:
- label:
id: alarm_audio_alarm_label
align: CENTER
text: "Alarm"
text_font: font_small
text_align: CENTER
text_color: 0xFFFFFF
on_click:
- script.execute: alarm_audio_alarm_test
- button:
id: alarm_audio_stop_button
x: 494
y: 10
width: 92
height: 72
bg_color: 0x673238
bg_opa: COVER
border_width: 2
border_color: 0xA45A63
radius: 11
pressed:
bg_color: 0x82414A
widgets:
- label:
align: CENTER
text: "Stop"
text_font: font_small
text_color: 0xFFFFFF
on_click:
- script.execute: stop_alarm_audio
#:################################################################################:# #:################################################################################:#
# BOTTOM NAVIGATION # BOTTOM NAVIGATION
#:################################################################################:# #:################################################################################:#
@@ -10586,6 +11134,8 @@ lvgl:
text_color: 0xFFFFFF text_color: 0xFFFFFF
on_click: on_click:
- script.execute: stop_alarm_audio
- lvgl.page.show: - lvgl.page.show:
id: bedroom_page id: bedroom_page
animation: MOVE_RIGHT animation: MOVE_RIGHT
@@ -10615,6 +11165,8 @@ lvgl:
text_color: 0xFFFFFF text_color: 0xFFFFFF
on_click: on_click:
- script.execute: stop_alarm_audio
- lvgl.page.show: - lvgl.page.show:
id: clock_page id: clock_page
animation: FADE_IN animation: FADE_IN
@@ -11148,4 +11700,4 @@ lvgl:
text: "" text: ""
text_font: font_small text_font: font_small
text_color: 0x887799 text_color: 0x887799
clickable: false clickable: false