- CHANGELOG 1.0.0 entry (boot-loop fix, bundled startup sound, Flicker removal); corrected the 0.2.0 note that miscounted Scan as a custom lambda. - README: 1.0 status, Documentation section linking the new wiki, updating and release-pinning guidance, hero banner. - Example thin config pins ref: v1.0.0 for reproducible builds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.9 KiB
Changelog
[1.0.0] - 2026-07-18
First stable release. The full voice assistant is confirmed on hardware, the
regressions found during bring-up testing are fixed, and the project ships with
complete documentation and a wiki. Tagged v1.0.0; the example config pins this
tag so a build is reproducible instead of tracking a moving main.
Fixed
- Boot loop into safe mode after selecting a ring effect. The three
effect selects restore their saved option during
setup()(at HARDWARE priority), which firedon_valueand ran the LED state machine before the light/RMT and voice_assistant were initialised, painting an effect on an uninitialised strip and crashing the boot. Theon_valueis now gated oninit_in_progress(cleared byon_bootat priority -100), so it only runs once setup is complete; a live effect change from HA still repaints the ring.
Changed
- Boot chime is now a bundled sound, not the wake-word beep.
base/sounds/startup.mp3(16 kHz mono, ~11 KB) plays on connect to HA and is swappable through theboot_sound_filesubstitution (any URL or local MP3/FLAC/WAV; the media player decodes all three).
Removed
- The Flicker ring effect (weak visually); 15 effects remain.
[0.2.0] - 2026-07-18
First on-hardware bring-up. The full voice assistant works: on-device wake word, STT/intent/TTS, clean playback, no boot hiss - all on stock ESPHome components.
Changed
- Audio reworked to two I2S buses with the mic as master; the patched es8311
and
force_masterare gone. The board shares BCLK/LRCLK between the DAC and ADC, and ESPHome can't run one bus full-duplex (the speaker hits "Parent bus is busy"). Two buses over the shared pins, with the always-capturing mic mastering the clock and the speaker slaving to it, gives simultaneous capture and playback on stock components. The mic is pinned to 16-bit so its master frame matches the DAC (a 32-bit frame played back as noise). - The amplifier is gated on playback (
ALWAYS_OFFat boot, turned on by the media_playeron_state) to remove the idle hiss the always-on amp produced before the first playback. - API encryption dropped (LAN-only device);
secrets.yamlis now just Wi-Fi. Re-enable it via the commented block inbase/core.yamlif you want it. - Timers are visible in HA (the "Next timer" / "Next timer name" sensors are
no longer
disabled_by_default). - Boot chime: a short "ready" sound plays once the device connects to HA,
played after the mic (I2S master) is clocking so the slave speaker can output
it. New
boot_soundswitch toggles it. The sound ships with the repo (base/sounds/startup.mp3, 16 kHz mono) and is swappable via theboot_sound_filesubstitution (any URL or local MP3/FLAC/WAV).
Added
- Per-phase ring animation, pickable from HA. New "Listening effect",
"Thinking effect" and "Replying effect" selects choose the animation for those
voice-assistant phases (the phase colour stays fixed). 15 effects to choose
from: solid, three pulses, Breathe, Wipe, Scan, Spinner, Comet, Twinkle,
Random Twinkle, Fireworks, Fire, and two rainbows. Breathe / Spinner /
Comet / Fire are custom
addressable_lambdaeffects.
Fixed
- The Pulse LED effects showed a solid colour instead of pulsing. Their
update_interval(16 ms) was shorter than the transition (300-1000 ms);update_intervalis how often the pulse flips its brightness target, so it flipped faster than the brightness could move. Now ~2x the transition, with 30-100% min/max brightness. - Compile-time issues found during bring-up: a quoted
mclk_multiplesubstitution (string vs the int acv.one_ofwants), atemplate selectmissing itsoptions:,select.state->current_option(), the dead microWakeWord model URLs (404), and a/in a switch name.
Removed
- The
stopwake word. This board has no usable hardware AEC, so the mic hears the device's own TTS far louder than the user; "stop" is detected only weakly and too late to be useful. - The daily-alarm entities (Alarm time / Alarm on / Alarm action), the
device-clock text sensor, and the diagnostic mic-disable switch are now
internal:(hidden from HA). The logic stays; the clutter is gone. - The dead "Mute and unmute sound" switch and its unused sound files.
components/es8311/and theexternal_components:block - no longer needed.
[0.1.0] - 2026-07-17
First cut. A working single-file config for the Waveshare ESP32-S3-AUDIO-Board,
restructured into a core package + a thin user config, with the patched
es8311 component brought in-tree so nothing depends on an upstream repo that
has gone quiet.
Added
base/core.yaml: the always-on core with ES8311 speaker, ES7210 dual mic, on-device wake word (alexa+okay_nabu), the HA Assist pipeline, music/announcement mixing with ducking, the 7x WS2812 status ring state machine, the three onboard buttons, voice timers and an alarm clock.waveshare-va.yaml: thin user config. Pulls the core from GitHub at compile time, so it is the only file you keep.components/es8311/: vendored fork of ESPHome'ses8311addingforce_master+mclk_multiple. Origin, credits and the licensing situation are in the README.docs/HARDWARE.md: board pinout and the I2C device map.skill/waveshare-esp32-s3-audio/: Claude Code skill with pinout + gotchas.scripts/validate.py: offline YAML check (syntax, substitutions, duplicate ids) so a typo does not cost a dashboard round trip.scripts/esplog.py: stream device logs over the native API.
Fixed
Bugs carried over from the config this started as:
- The mic was stopped on every boot. The
diag_disable_miccheck was inverted: with the switch in its default OFF positionon_bootranmicro_wake_word.stop+microphone.stop_capture. It only ever recovered becauseon_client_connectedrestarted the wake word, so the switch also did not actually work, in either direction. - "Microphone Mute" did not mute. It dropped the ES7210 gain to
0.0f, but 0 dB is unity gain, not silence. The mic kept hearing the room and only the wake-word handler ignored it. It now uses ESPHome's ownmicrophone.mute, which hands every consumer a zero-filled buffer, so the wake word hears actual silence with no I2S restart. - A test sound fired on every LED repaint during boot. A leftover
id(play_sound).execute(1, id(wake_word_triggered_sound)); //TESTsat in theinit_in_progressbranch ofcontrol_leds. - Wake word sensitivity did nothing. The select only set cutoffs on
okay_nabu, while the primary wake word isalexa. It now sets both. - Mic gain slider promised 42 dB. The ES7210 caps at 37.5 dB and the driver
silently clamps, so the top third of the slider was a lie. Range is now
0 to 37.5 dB in 1.5 dB steps (the chip's real granularity), and the boot value
in
audio_adcmatches the number entity instead of contradicting it (24 dB vs a 32 dB global). - The API encryption key was hard-coded in the config. It now comes from
!secret api_encryption_key. - The
time:block was half-commented-out, leavingid: rtcdangling underplatform: homeassistant. Cleaned up. PCF85063 support is not in this build. - Two
on_boot: priority: -100blocks ran in an order nobody had chosen. Merged into one.
Changed
- All pins, audio format and the HA-facing values are
substitutions:with documented defaults, instead of literals scattered through the file. ${mic_channel_${which_mic}}nested-substitution trickery replaced with two plainly named knobs:mic_channel(the I2S slot) andmic_va_channel(the index handed to Assist). These are genuinely different things and the old names implied they were the same one.- Dropped dead substitutions (
i2s_bits_per_sample,i2s_mode_speaker,rtc_int,mic_channel_2) and the now-unusedmic_gain_savedglobal. - Timezone is a
posix_timezonesubstitution rather than a hard-codedUTC0.