I wanted a local voice puck without reviving a lapsed Nabu Casa subscription. The Home Assistant Voice Preview Edition is ESP32-S3 hardware with Wyoming STT/TTS into Assist on my HA VM (101 on Proxmox, Ryzen 5650G). After an evening of USB and language-code friction it works. I skipped Alexa-style “study off” room control; announcements and Q&A are enough.

The setup

  • Host: ASRock DeskMini X300M-STX / 5650G, Proxmox 8
  • HA: VM 101, cpu: host (Piper/Whisper addons need x86_v2 flags)
  • Voice PE: study area, firmware 26.6.0, wake word “Okay Nabu”
  • Pipeline: faster-whisper (STT) + Piper (TTS), full local processing
  • Public URL: Caddy on ubuntu-cloud -> https://ha.home.aioue.net (no :8123)

No Home Assistant Cloud. Firmware via esphome.github.io/home-assistant-voice-pe, onboarding via the Voice Satellite wizard.

USB and flashing

Chrome showed no serial device. Bootloader mode (hold centre button, plug in) left the LED ring dark - normal, not dead.

What fixed detection:

  1. Different USB-C cable - the first was charge-only or flaky.
  2. Direct Mac USB-C port - not through a Digital AV adapter.

The installer then saw the puck (existing 25.12.1 -> update to 26.6.0). First flash failed mid-write (Failed to write compressed data to flash after seq 106). Second attempt on a direct port succeeded.

Onboarding traps

External URL with :8123

“Add to Home Assistant” redirected to https://ha.home.aioue.net:8123/.... Caddy serves HA on 443; nothing listens on 8123 at that hostname. Fix: Settings -> System -> Network -> external URL https://ha.home.aioue.net (no port). LAN http://192.168.1.240:8123 stays as internal.

Piper language tags

Try and the wake word flashed red. HA reported:

Failed to perform the action assist_satellite/announce. Language 'en-gb' not supported

British English in the wizard had set tts_language: en-gb. Piper Wyoming only accepts tags like en_GB and en_US - not en, not en-gb. Querying the Wyoming describe payload confirmed it.

Working pipeline fields:

Field Value
language en-GB
stt_language en
tts_language en_GB
tts_voice en_GB-jenny_dioco-medium

Pipeline voice ≠ Piper addon default

Piper addon was set to “English female low”; I heard a male voice. Assist uses the pipeline tts_voice, not the addon default. After aligning both to the same en_GB-* voice, behaviour matched.

Latency (state history, not log scraping)

From assist_satellite state transitions on the HA recorder:

Phase Typical
Listening (user speaking) 2.5-5.7 s
Processing (STT + intent) <0.5 s
Responding (TTS playback) 1.7-3.1 s
Total (short phrase) ~4-5 s

Announce-only (“Try” in the wizard): ~2.7 s average TTS. STT is not the bottleneck; listening time scales with how long you talk. Moving Whisper to a dedicated LXC or Vulkan on the 5650G iGPU is deferred - not urgent at these numbers.

“Study off”

Alexa maps “study off” to a room light group. I had 24 study-related entities exposed to Assist: 14 Hue scenes (Study Bright, Study Relax, …), four lights, two Cast players named study, plus sensors. Assist answered:

There are multiple devices called study

You can fix that with tighter exposure (room groups only) or a custom {area} off sentence. I did not want to maintain per-room voice aliases on this puck, so I use it for prompts and Q&A instead (morning study motion -> weather, chore check-in; maybe ask_question later). OpenAI Conversation (gpt-4o-mini, prefer_local_intents) when open-ended chat is worth the API cost.

Redo list

If I set this up again:

  • Flash from a direct Mac USB-C port; skip hubs and AV adapters
  • Set the external URL (no :8123) before “Add to Home Assistant”
  • Set tts_language: en_GB before the first Try
  • Do not expose every Hue scene to Assist if you care about room names

Planned automation: binary_sensor.top_study_motion_osram_occupancy -> assist_satellite.announce on assist_satellite.home_assistant_voice_09414f_assist_satellite with weather + chore state. Later: ask_question for yes/no, then OpenAI for follow-up chat.

Ansible repo: proxmox-setup (roles/vm_homeassistant, Wyoming pipeline defaults in configure-homeassistant.yml).