ESPHome Voice Assistant for the Waveshare ESP32-S3-AUDIO-Board
A Home Assistant voice satellite running on the Waveshare ESP32-S3-AUDIO-Board, the little AI smart-speaker devkit with a dual-mic array, an ES8311 codec, three buttons and a 7-LED RGB ring. Pure ESPHome, no custom C firmware: an always-on core you pull as a package, plus one thin config file you actually edit.
Status: stable (v1.0.1). Wake word, STT/TTS, clean playback and the LED ring are confirmed on-device. Full docs are in the Wiki; the release history is in CHANGELOG.md.
You ──▶ Waveshare ESP32-S3 ──▶ Home Assistant Assist
(wake word + audio) (STT / LLM / TTS)
Tip
⭐ Enjoying this project? Every star is real motivation to keep it going.
What it does
- Voice assistant: on-device wake word (
alexa,okay_nabu) viamicro_wake_word, the full Home Assistant Assist pipeline (STT / LLM / TTS), a wake beep and music ducking while it listens. - Simultaneous music and announcements: a mixer speaker blends the media and announcement pipelines, so a doorbell announcement ducks the music instead of fighting it. Both are exposed to Music Assistant.
- LED ring: one state machine drives it. Boot, no-Wi-Fi, no-HA, listening, thinking, replying, timer counting, ringing, volume changed - each a distinct colour/effect. Brightness and the animation for the listening / thinking / replying phases are pickable from HA: solid plus 14 animations - pulses, breathe, wipe, scan, spinner, comet, twinkle, fireworks, fire, rainbows.
- Timers: set by voice, with an on-ring countdown and a "Next timer" sensor in HA. (A daily-alarm engine is present but its entities are hidden by default.)
- Buttons: the three onboard keys do volume down, play-pause, volume up.
- Boot chime: a short "ready" sound once the device connects to HA (toggleable, and it also settles the amp so the ring boots silent).
- Tunable live from HA: microphone mute, ES7210 mic gain, LED brightness and wake-word sensitivity are all entities, so there's no reflashing to tune it.
Quick start
Requires ESPHome 2025.8.0+.
- Copy
secrets.example.yamltosecrets.yamland fill in your Wi-Fi. The native API is unencrypted by default; enable encryption inbase/core.yamlif you want it (see the commented block there). - Copy
waveshare-va.yamlnext to it and edit thesubstitutions:at the top (device name, timezone, volume limits). That thin file is the only firmware file you keep. The core is pulled from GitHub at compile time, see itspackages:block. - First flash over USB, then updates go wireless:
Or drop both files into the ESPHome dashboard's
esphome run waveshare-va.yaml/config/esphome/and hit Install. - In Home Assistant: the new ESPHome device appears, open Configure and assign an Assist pipeline.
- Say "Alexa" (or "OK Nabu"). The ring should go violet.
The example config pins the v1.0.1 release tag, so a build is reproducible. To
move to a newer release, bump ref: in the packages: block to a later tag (or
main to track the latest), then esphome clean waveshare-va.yaml (clears the
package cache) and esphome run waveshare-va.yaml.
Documentation
The Wiki has the full guide:
- Installation: first flash, Home Assistant setup, updating.
- Configuration: every substitution and every Home Assistant entity.
- Audio architecture: the shared-I2S two-bus design, in depth.
- LED ring: the state machine and every ring effect.
- Hardware: pinout, I2C map, and sourced gotchas.
- Troubleshooting and FAQ.
How the shared I2S bus is handled
The board wires the ES8311 (DAC) and the ES7210 (ADC) to the same BCLK/LRCLK pins, and only one device can drive those clocks. ESPHome also cannot run a single I2S bus full-duplex: a microphone and a speaker on one bus each try to init the port, and the second fails with "Parent bus is busy".
The layout that works, all on stock ESPHome components:
- Two I2S buses (two ports) over the shared pins. The mic bus is the I2S master: it is always capturing for the wake word, so it drives BCLK/LRCLK/MCLK continuously. The speaker bus is a slave that reads the mic's clock, so it never needs a port of its own to master.
- The ES8311 and ES7210 are stock and slave to the mic's clock.
- The mic is pinned to 16-bit (the i2s_audio default is 32-bit); since the mic is master it sets the frame's slot width, and a 32-bit frame against the 16-bit DAC comes out as noise.
This gives simultaneous capture + playback with no custom component. The
annotated config is in the audio section of base/core.yaml.
Repository layout
waveshare-va.yaml # YOUR config: copy + edit this (pulls the rest from GitHub)
secrets.example.yaml # copy to secrets.yaml
base/
core.yaml # the always-on core, pulled as a remote package
docs/
HARDWARE.md # pinout, I2C map, gotchas
scripts/
validate.py # offline YAML check (syntax, substitutions, duplicate ids)
esplog.py # stream device logs over the native API
skill/
waveshare-esp32-s3-audio/ # Claude Code skill: pinout + hard-won gotchas
Configuration
Everything worth changing day to day is a Home Assistant entity, not a config edit: mic gain, LED brightness, the ring animation per assistant phase (Listening / Thinking / Replying effect), wake-word sensitivity, wake sound, boot sound, microphone mute.
What lives in waveshare-va.yaml:
| Substitution | Default | What it does |
|---|---|---|
name / friendly_name |
waveshare-va / Waveshare Voice |
Device name. Changing name re-creates every entity in HA. |
posix_timezone |
CET-1CEST,... |
Clock zone in POSIX form (the device has no IANA database). DST automatic. |
volume_min / volume_max |
0.4 / 0.8 |
Media player clamps, because the onboard amp distorts near the top. |
hidden_ssid |
false |
true enables fast_connect for a hidden SSID. |
boot_sound_file |
repo startup.mp3 |
The connect-to-HA chime. Any URL or local MP3/FLAC/WAV. |
Pins and the audio format are substitutions too (in base/core.yaml), but you
should not need them unless you are porting to another board.
Claude Code skill
This repo ships a Claude Code skill at
skill/waveshare-esp32-s3-audio/:
the pinout, the shared-I2S constraint, and the gotchas that cost real debugging
time. Install it user-wide so any session picks it up:
cp -r skill/waveshare-esp32-s3-audio ~/.claude/skills/
Credits
- jensenbox: the ESP-master I2S layout for this board that the audio setup is based on.
- ESPHome: everything the firmware is built out of.
- Home Assistant Voice PE: the sounds, and the phase/ducking model the LED state machine follows.

