4 Commits
Author SHA1 Message Date
gronod ccf9c68322 Update waveshare-va.yaml 2026-09-23 19:23:35 +01:00
Michal ZaniewiczandClaude Sonnet 5 083b2954b6 Fix mic gain slider snapping back and restore gain at boot
The mic_gain_db template number had a set_action but no optimistic flag, so
TemplateNumber::control() never published the new value: the ES7210 was
reprogrammed but HA kept showing the old value and the slider snapped back.

TemplateNumber::setup() also only publishes the restored value without running
set_action, so a gain saved in flash showed in HA while the codec booted with
the default from audio_adc. Apply it to the ES7210 in on_boot (-100), which is
safe because set_mic_gain() stores the value even before setup completes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 20:08:01 +02:00
Michal ZaniewiczandClaude Sonnet 5 c59223ee77 Add opt-in deep sleep and un-hide the Restart button
Two lifecycle controls, both requested in an issue.

Restart: the `restart_button` already existed but was `disabled_by_default`,
so it showed up as a disabled entity nobody could press without digging into
the entity settings. Dropped the flag - it now lands ready to use under the
device's config section.

Deep sleep: new `deep_sleep` component plus a `boot_button` GPIO binary_sensor
on GPIO0 (the onboard BOOT key, wired direct, not via the expander). A 2-10 s
long-press calls `deep_sleep.enter`, but only when the new `enable_deep_sleep`
substitution is 'true' - off by default, so the stock build is unchanged and
nobody gets a power toggle on BOOT they did not ask for. Wake is a low level on
GPIO0 (BOOT pressed), handled by the deep_sleep wakeup_pin; `INVERT_WAKEUP`
covers BOOT still being held at sleep time. GPIO0 is shared between the
wakeup_pin and the binary_sensor via `allow_other_uses`.

Untested on hardware, hence the beta branch. The power saving on this board is
limited: the ES8311/ES7210 codecs and the WS2812 strip have no hardware
shutdown line and stay powered, so deep sleep here is a low-power idle rather
than a true off. Sleep current not yet measured.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 07:10:40 +02:00
Michal Zaniewicz 935b513fb9 Loosen wake-word VAD to reduce premature STT cutoff
Default vad model (cutoff 0.50, window 5) was ending STT capture after
~1.2-1.4s of a brief pause, truncating longer commands
(stt-no-text-recognized). Untested on hardware, hence beta branch.
2026-08-01 15:32:35 +02:00
2 changed files with 65 additions and 2 deletions
+64 -1
View File
@@ -56,6 +56,13 @@ substitutions:
# ---------------------------------------------------------------------------
hidden_ssid: 'false' # true = fast_connect, required for a hidden SSID
# Software off: long-press the onboard BOOT button (GPIO0) for ~2 s to enter
# deep sleep; a short press wakes the board again. Off by default - set to
# 'true' in your thin config to enable it. Note the savings on this board are
# modest: the ES8311/ES7210 codecs and the LED strip stay powered (no hardware
# shutdown line), so this is closer to a low-power idle than a true power off.
enable_deep_sleep: 'false'
# Media player volume clamps (the onboard amp distorts near the top).
volume_min: '0.4'
volume_max: '0.8'
@@ -104,6 +111,11 @@ esphome:
- lambda: |-
setenv("TZ", id(saved_time_zone).c_str(), 1);
tzset();
# Push the mic gain restored from flash into the ES7210. The codec boots
# with `mic_gain` from audio_adc, so without this a saved value would show
# in HA while the hardware sat at the default.
- lambda: |-
id(adc_mic).set_mic_gain(id(mic_gain_db).state);
# Diagnostics: an explicit OFF switch that silences the mic completely.
# ON = microphone disabled. (This used to be inverted, so the mic was
# stopped on every boot with the switch in its default OFF position.)
@@ -204,6 +216,19 @@ ota:
- platform: esphome
id: ota_esphome
# Software off. No run_duration / sleep_duration, so the node never sleeps on
# its own: the only path in is the BOOT-button long-press below, which calls
# deep_sleep.enter only when ${enable_deep_sleep} is 'true'. Wake is a low level
# on GPIO0 (BOOT pressed). GPIO0 is a strapping pin - holding BOOT through a
# power cycle still drops the chip into the serial bootloader, unavoidably.
deep_sleep:
id: deep_sleep_ctrl
wakeup_pin:
number: GPIO0
inverted: true # BOOT is active-low; wake when it is pulled low
allow_other_uses: true # GPIO0 is also the boot_button binary_sensor
wakeup_pin_mode: INVERT_WAKEUP # BOOT still held at sleep time -> flip, don't loop
i2c:
- id: internal_i2c
sda: ${i2c_sda}
@@ -397,6 +422,11 @@ micro_wake_word:
id: okay_nabu
vad:
model: https://github.com/esphome/micro-wake-word-models/raw/main/models/v2/vad.json
# Defaults (cutoff 0.50, window 5) end STT capture after ~1.2-1.4s of a
# short pause, cutting off longer commands. Looser cutoff + wider window
# = more tolerance for pauses/breaths before "end of speech" fires.
probability_cutoff: 0.3
sliding_window_size: 10
on_wake_word_detected:
# Muted (software mute switch)? Do nothing at all.
- if:
@@ -1286,6 +1316,12 @@ number:
restore_value: true
initial_value: 24
mode: slider
# Without `optimistic`, a template number with only a set_action never
# publishes the new value back: the slider snapped back to 24 dB in HA even
# though the ES7210 had already been reprogrammed. The restored value is
# applied to the codec in on_boot (-100), since TemplateNumber::setup() only
# publishes it and does not run set_action.
optimistic: true
set_action:
- lambda: |-
id(adc_mic).set_mic_gain(x);
@@ -1350,7 +1386,6 @@ button:
id: restart_button
name: "Restart"
entity_category: config
disabled_by_default: true
icon: "mdi:restart"
binary_sensor:
@@ -1380,3 +1415,31 @@ binary_sensor:
inverted: true
on_press:
- media_player.volume_up: external_media_player
# Onboard BOOT button (GPIO0, a strapping pin, direct - not via the expander).
# Held for 2 to 10 s it enters deep sleep, but only when ${enable_deep_sleep}
# is 'true'; otherwise the long-press does nothing. A short press wakes the
# board from deep sleep (handled by the deep_sleep wakeup_pin, not this
# sensor). Disabled in HA by default - it exists here for the sleep gesture.
- platform: gpio
id: boot_button
name: "BOOT button"
entity_category: diagnostic
disabled_by_default: true
pin:
number: GPIO0
mode:
input: true
pullup: true
inverted: true
allow_other_uses: true
on_click:
min_length: 2s
max_length: 10s
then:
- if:
condition:
lambda: 'return strcmp("${enable_deep_sleep}", "true") == 0;'
then:
- logger.log: "BOOT long-press: entering deep sleep"
- deep_sleep.enter: deep_sleep_ctrl
+1 -1
View File
@@ -43,7 +43,7 @@ substitutions:
packages:
core:
url: https://github.com/MichalZaniewicz/esphome-waveshare-esp32-s3-audio-va
url: https://git.i3omb.com/gronod/esphome-waveshare-esp32-s3-audio-va
ref: v1.0.0 # pinned release; bump to a newer tag, or use 'main' to track latest
files:
- base/core.yaml