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
|
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedside-panel.yaml
|
||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
# VERSIONS:
|
# VERSIONS:
|
||||||
|
# V1.42 2026-07-20 Changed tests to higher single-tone sounds and added a useful perceptual volume curve
|
||||||
# V1.41 2026-07-20 Fixed raw alarm audio startup and buffering so tones play instead of amplifier clicks
|
# V1.41 2026-07-20 Fixed raw alarm audio startup and buffering so tones play instead of amplifier clicks
|
||||||
# V1.40 2026-07-20 Added ES8311 speaker output, persistent alarm volume and local speaker test controls
|
# 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.39 2026-07-19 Removed the Alarm Clock editor title format-truncation warning
|
||||||
@@ -141,7 +142,10 @@
|
|||||||
# - 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.
|
# - Alarm speaker volume is persistent and adjustable from Home Assistant or the display.
|
||||||
|
# - The ES8311 remains at its 75% / 0 dB reference while local PCM amplitude
|
||||||
|
# follows a perceptual 24 dB volume curve across the displayed 5-100% range.
|
||||||
# - The Alarm Clock page provides local Beep, repeating Alarm and Stop hardware tests.
|
# - The Alarm Clock page provides local Beep, repeating Alarm and Stop hardware tests.
|
||||||
|
# - Beep is a short 1800 Hz tone; Alarm repeats one 1600 Hz tone.
|
||||||
# - Speaker tests generate audio locally and do not require Home Assistant or media files.
|
# - Speaker tests generate audio locally and do not require Home Assistant or media files.
|
||||||
#:########################################################################################:#
|
#:########################################################################################:#
|
||||||
# OFFLINE NOTES:
|
# OFFLINE NOTES:
|
||||||
@@ -161,12 +165,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 local ES8311 speaker testing, persistent alarm volume 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 higher-pitched single-tone speaker testing, perceptual PCM volume control 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.41"
|
project_version: "v1.42"
|
||||||
|
|
||||||
# Passwords & Secrets
|
# Passwords & Secrets
|
||||||
api_key: !secret esp-api_key
|
api_key: !secret esp-api_key
|
||||||
@@ -241,6 +245,18 @@ substitutions:
|
|||||||
alarm_speaker_enable_pin: "GPIO11"
|
alarm_speaker_enable_pin: "GPIO11"
|
||||||
alarm_audio_sample_rate: "48000"
|
alarm_audio_sample_rate: "48000"
|
||||||
|
|
||||||
|
# Alarm Test Sound
|
||||||
|
# The ES8311 uses 75% as its 0 dB reference. Keep the codec at that
|
||||||
|
# reference and apply the user volume to the generated PCM samples.
|
||||||
|
alarm_dac_reference_volume: "0.75"
|
||||||
|
alarm_pcm_max_amplitude: "28000"
|
||||||
|
alarm_volume_attenuation_db: "24"
|
||||||
|
alarm_beep_frequency_hz: "1800"
|
||||||
|
alarm_beep_duration_ms: "250"
|
||||||
|
alarm_tone_frequency_hz: "1600"
|
||||||
|
alarm_tone_on_ms: "350"
|
||||||
|
alarm_tone_off_ms: "250"
|
||||||
|
|
||||||
# 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.
|
||||||
home_assistant_internal_url: "http://homeassistant.local:8123"
|
home_assistant_internal_url: "http://homeassistant.local:8123"
|
||||||
@@ -1042,7 +1058,7 @@ number:
|
|||||||
- audio_dac.set_volume:
|
- audio_dac.set_volume:
|
||||||
id: alarm_audio_dac
|
id: alarm_audio_dac
|
||||||
volume: !lambda |-
|
volume: !lambda |-
|
||||||
return x / 100.0f;
|
return ${alarm_dac_reference_volume}f;
|
||||||
|
|
||||||
- script.execute: refresh_alarm_audio_controls
|
- script.execute: refresh_alarm_audio_controls
|
||||||
|
|
||||||
@@ -2319,11 +2335,7 @@ script:
|
|||||||
- audio_dac.set_volume:
|
- audio_dac.set_volume:
|
||||||
id: alarm_audio_dac
|
id: alarm_audio_dac
|
||||||
volume: !lambda |-
|
volume: !lambda |-
|
||||||
float volume = id(alarm_volume).state;
|
return ${alarm_dac_reference_volume}f;
|
||||||
if (isnan(volume)) {
|
|
||||||
volume = 35.0f;
|
|
||||||
}
|
|
||||||
return volume / 100.0f;
|
|
||||||
|
|
||||||
- if:
|
- if:
|
||||||
condition:
|
condition:
|
||||||
@@ -2396,11 +2408,7 @@ script:
|
|||||||
- audio_dac.set_volume:
|
- audio_dac.set_volume:
|
||||||
id: alarm_audio_dac
|
id: alarm_audio_dac
|
||||||
volume: !lambda |-
|
volume: !lambda |-
|
||||||
float volume = id(alarm_volume).state;
|
return ${alarm_dac_reference_volume}f;
|
||||||
if (isnan(volume)) {
|
|
||||||
volume = 35.0f;
|
|
||||||
}
|
|
||||||
return volume / 100.0f;
|
|
||||||
|
|
||||||
- switch.turn_on: alarm_speaker_amplifier
|
- switch.turn_on: alarm_speaker_amplifier
|
||||||
- delay: 20ms
|
- delay: 20ms
|
||||||
@@ -2428,12 +2436,30 @@ script:
|
|||||||
# a loop so the complete sound is queued even when it is larger than the
|
# a loop so the complete sound is queued even when it is larger than the
|
||||||
# speaker buffer's immediately available space.
|
# speaker buffer's immediately available space.
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
const uint32_t sample_rate = 48000;
|
const uint32_t sample_rate = ${alarm_audio_sample_rate};
|
||||||
const uint32_t duration_ms = 480;
|
const uint32_t duration_ms = ${alarm_beep_duration_ms};
|
||||||
const uint32_t sample_count =
|
const uint32_t sample_count =
|
||||||
(sample_rate * duration_ms) / 1000;
|
(sample_rate * duration_ms) / 1000;
|
||||||
const float frequency = 880.0f;
|
const float frequency = ${alarm_beep_frequency_hz}.0f;
|
||||||
const uint32_t fade_samples = sample_rate / 80;
|
const uint32_t fade_samples = sample_rate / 100;
|
||||||
|
|
||||||
|
float ui_volume = id(alarm_volume).state;
|
||||||
|
if (isnan(ui_volume)) {
|
||||||
|
ui_volume = ${alarm_volume_default}.0f;
|
||||||
|
}
|
||||||
|
ui_volume = fminf(fmaxf(ui_volume, 5.0f), 100.0f);
|
||||||
|
|
||||||
|
// Equal steps in the displayed percentage produce roughly equal
|
||||||
|
// perceived loudness changes. At 75%, this gives approximately the
|
||||||
|
// same PCM level as the proven V1.41 test at the codec's 0 dB point.
|
||||||
|
const float volume_position =
|
||||||
|
(ui_volume - 5.0f) / 95.0f;
|
||||||
|
const float attenuation_db =
|
||||||
|
-${alarm_volume_attenuation_db}.0f *
|
||||||
|
(1.0f - volume_position);
|
||||||
|
const float peak_amplitude =
|
||||||
|
${alarm_pcm_max_amplitude}.0f *
|
||||||
|
powf(10.0f, attenuation_db / 20.0f);
|
||||||
|
|
||||||
std::vector<uint8_t> audio;
|
std::vector<uint8_t> audio;
|
||||||
audio.reserve(sample_count * 2);
|
audio.reserve(sample_count * 2);
|
||||||
@@ -2452,7 +2478,7 @@ script:
|
|||||||
6.28318530718f * frequency *
|
6.28318530718f * frequency *
|
||||||
static_cast<float>(i) / sample_rate;
|
static_cast<float>(i) / sample_rate;
|
||||||
const int16_t sample = static_cast<int16_t>(
|
const int16_t sample = static_cast<int16_t>(
|
||||||
14000.0f * envelope * sinf(phase)
|
peak_amplitude * envelope * sinf(phase)
|
||||||
);
|
);
|
||||||
|
|
||||||
audio.push_back(static_cast<uint8_t>(sample & 0xFF));
|
audio.push_back(static_cast<uint8_t>(sample & 0xFF));
|
||||||
@@ -2535,46 +2561,50 @@ script:
|
|||||||
return id(alarm_audio_test_active);
|
return id(alarm_audio_test_active);
|
||||||
|
|
||||||
then:
|
then:
|
||||||
# A two-tone 800 ms alarm cycle. The direct write loop prevents
|
# A higher-pitched single-tone alarm pulse. The direct write loop
|
||||||
# truncation when the clip is larger than the free ring-buffer area.
|
# prevents truncation when the clip is larger than the free
|
||||||
|
# ring-buffer area.
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
const uint32_t sample_rate = 48000;
|
const uint32_t sample_rate = ${alarm_audio_sample_rate};
|
||||||
const uint32_t duration_ms = 800;
|
const uint32_t tone_ms = ${alarm_tone_on_ms};
|
||||||
|
const uint32_t silence_ms = ${alarm_tone_off_ms};
|
||||||
|
const uint32_t duration_ms = tone_ms + silence_ms;
|
||||||
const uint32_t sample_count =
|
const uint32_t sample_count =
|
||||||
(sample_rate * duration_ms) / 1000;
|
(sample_rate * duration_ms) / 1000;
|
||||||
|
const uint32_t tone_end =
|
||||||
|
(sample_rate * tone_ms) / 1000;
|
||||||
const uint32_t fade_samples = sample_rate / 100;
|
const uint32_t fade_samples = sample_rate / 100;
|
||||||
|
const float frequency = ${alarm_tone_frequency_hz}.0f;
|
||||||
|
|
||||||
|
float ui_volume = id(alarm_volume).state;
|
||||||
|
if (isnan(ui_volume)) {
|
||||||
|
ui_volume = ${alarm_volume_default}.0f;
|
||||||
|
}
|
||||||
|
ui_volume = fminf(fmaxf(ui_volume, 5.0f), 100.0f);
|
||||||
|
|
||||||
|
const float volume_position =
|
||||||
|
(ui_volume - 5.0f) / 95.0f;
|
||||||
|
const float attenuation_db =
|
||||||
|
-${alarm_volume_attenuation_db}.0f *
|
||||||
|
(1.0f - volume_position);
|
||||||
|
const float peak_amplitude =
|
||||||
|
${alarm_pcm_max_amplitude}.0f *
|
||||||
|
powf(10.0f, attenuation_db / 20.0f);
|
||||||
|
|
||||||
std::vector<uint8_t> audio;
|
std::vector<uint8_t> audio;
|
||||||
audio.reserve(sample_count * 2);
|
audio.reserve(sample_count * 2);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sample_count; i++) {
|
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 < 300) {
|
|
||||||
frequency = 740.0f;
|
|
||||||
burst_start = 0;
|
|
||||||
burst_end = (sample_rate * 300) / 1000;
|
|
||||||
} else if (time_ms >= 400 && time_ms < 700) {
|
|
||||||
frequency = 990.0f;
|
|
||||||
burst_start = (sample_rate * 400) / 1000;
|
|
||||||
burst_end = (sample_rate * 700) / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t sample = 0;
|
int16_t sample = 0;
|
||||||
|
|
||||||
if (frequency > 0.0f) {
|
if (i < tone_end) {
|
||||||
float envelope = 1.0f;
|
float envelope = 1.0f;
|
||||||
|
|
||||||
if (i < burst_start + fade_samples) {
|
if (i < fade_samples) {
|
||||||
envelope = static_cast<float>(i - burst_start) /
|
envelope = static_cast<float>(i) /
|
||||||
fade_samples;
|
fade_samples;
|
||||||
} else if (i > burst_end - fade_samples) {
|
} else if (i > tone_end - fade_samples) {
|
||||||
envelope = static_cast<float>(burst_end - i) /
|
envelope = static_cast<float>(tone_end - i) /
|
||||||
fade_samples;
|
fade_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2582,7 +2612,7 @@ script:
|
|||||||
6.28318530718f * frequency *
|
6.28318530718f * frequency *
|
||||||
static_cast<float>(i) / sample_rate;
|
static_cast<float>(i) / sample_rate;
|
||||||
sample = static_cast<int16_t>(
|
sample = static_cast<int16_t>(
|
||||||
14000.0f * envelope * sinf(phase)
|
peak_amplitude * envelope * sinf(phase)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2639,7 +2669,7 @@ script:
|
|||||||
id: alarm_speaker
|
id: alarm_speaker
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
|
|
||||||
- delay: 250ms
|
- delay: 20ms
|
||||||
|
|
||||||
- id: stop_alarm_audio
|
- id: stop_alarm_audio
|
||||||
mode: restart
|
mode: restart
|
||||||
|
|||||||
Reference in New Issue
Block a user