ha-voice
Home Assistant Voice Control
Configure Assist pipelines, custom intents, wake words, speech processing, and voice satellites for local voice control.
Quick Start
Setting up Assist Pipeline
# configuration.yaml
assist_pipeline:
pipelines:
- language: en
name: Default Pipeline
stt_engine: faster_whisper # Local STT
tts_engine: tts.piper # Local TTS
conversation_engine: conversation.home_assistant
wake_word_entity: binary_sensor.wake_word
Why this matters: The pipeline connects all components (STT, TTS, intent, conversation agent) into a single voice workflow.
Creating Custom Intents
# custom_sentences/en/turn_on.yaml
language: en
version: 1
intents:
TurnOn:
data:
- sentences:
- "turn on the [area] {name:list}"
- "turn on {name:list}"
- "[please] activate {name:list}"
lists:
name: light_names
lists:
light_names:
- "bedroom light"
- "kitchen overhead"
- "living room"
Why this matters: Custom sentence patterns enable natural voice commands tailored to your home.
Configuring Text-to-Speech (TTS)
Local Option - Piper:
tts:
- platform: piper
language: en_GB
voice: jenny_dioco
Cloud Option - OpenAI:
tts:
- platform: tts
service: google_translate_say # or openai, google cloud
language: en
Why this matters: TTS gives voice feedback; local options require no cloud dependencies.
Configuring Speech-to-Text (STT)
Local Option - Faster Whisper:
stt:
- platform: faster_whisper
language: en
Cloud Option - Google Cloud Speech:
stt:
- platform: google_cloud
language_code: en-US
Why this matters: STT converts spoken commands to text; local options provide privacy.
Critical Rules
✅ Always Do
- ✅ Use
custom_sentences/directory for intent configuration (not deprecatedsentences/) - ✅ Test intents with Assist Developer Tools before deploying
- ✅ Use
{name:list}syntax for slot-based entity matching - ✅ Configure both STT and TTS engines in the same pipeline
- ✅ Verify wake word entity exists before enabling in pipeline
- ✅ Document intent lists so voice commands are discoverable
❌ Never Do
- ❌ Don't hardcode entity IDs in sentence patterns (use lists and slots)
- ❌ Don't forget
version: 1in custom_sentences YAML files - ❌ Don't mix old
sentences/directory with newcustom_sentences/(usecustom_sentences/only) - ❌ Don't enable Piper TTS without adequate disk space (models are 100+ MB)
- ❌ Don't use wildcard
{query}for every slot (makes intents ambiguous) - ❌ Don't skip testing with Assist Developer Tools
Common Mistakes
❌ Wrong - Hardcoded entity IDs:
intents:
TurnOn:
data:
- sentences:
- "turn on light.bedroom"
- "turn on light.kitchen"
✅ Correct - Using slot lists:
intents:
TurnOn:
data:
- sentences:
- "turn on [the] {name:list}"
lists:
name: light_names
lists:
light_names:
- "bedroom"
- "kitchen"
Why: Lists are dynamic and can be generated from Home Assistant entities programmatically.
Sentence Pattern Syntax
Slots
Named slots match list values:
sentences:
- "turn on {name:list}" # Matches list value, captures as 'name' slot
Lists
List matching provides slot values:
lists:
room:
- "bedroom"
- "kitchen"
- "living room"
Optional Groups
Square brackets make words optional:
sentences:
- "[please] turn on the {name:list}"
- "activate [the] {device:list}"
Wildcards
Wildcard slots capture any text:
sentences:
- "remind me {reminder:text}" # Captures any text as 'reminder'
- "set a timer for {duration:text}"
Combined Pattern Example
intents:
TurnOn:
data:
- sentences:
- "[please] [turn on | switch on | activate] [the] {area} {name:list}"
- "[please] turn on {name:list}"
- "activate {name:list} [in the] {room:list}"
lists:
name: light_names
room: room_names
Reminder:
data:
- sentences:
- "remind me {reminder:text}"
- "[please] [create | set] a reminder [for me] [to] {reminder:text}"
lists:
light_names:
- "bedroom light"
- "kitchen overhead"
- "living room lamps"
room_names:
- "bedroom"
- "kitchen"
- "living room"
Why this matters: Flexible patterns enable natural phrasing while maintaining intent recognition accuracy.
Built-In Intents Reference
Home Assistant provides default intents:
Navigation Intents
HassTurnOn/HassTurnOff- Control devicesHassToggle- Toggle switches/lightsHassOpenCover/HassCloseCover- Control coversHassSetClimate- Control climate (heat/cool)
Information Intents
HassGetState- Get entity stateHassGetHistory- Query automation history
Home Control Intents
HassArmAlarm/HassDisarmAlarm- Arm/disarm alarmsHassLockDoor/HassUnlockDoor- Control locks
Custom Intents
You create additional intents in custom_sentences/ by defining new intent blocks:
intents:
CustomIntentName:
data:
- sentences: [...]
Wake Word Configuration
openWakeWord (Local)
conversation:
engine: openai
# Enable openWakeWord
binary_sensor:
- platform: openwakeword
models:
- alexa # "Alexa, help"
- hey_google # "Hey Google, ..."
- hey_siri
Porcupine (Local, Paid)
binary_sensor:
- platform: porcupine
access_key: !secret porcupine_key
keywords:
- hey_home_assistant
Voice Satellite Setup
Hardware Requirements
- Microphone: INMP441 (I2S digital) or similar
- Speaker: MAX98357A amplifier or similar
- Board: ESP32-S3, ESP32-S3-BOX-3 preferred
- Connectivity: WiFi required
ESPHome Voice Assistant Config
# ESPHome device
packages:
voice_assistant: !include packages/voice_assistant.yaml
# Or inline configuration:
i2s_audio:
i2s_lrclk_pin: GPIO33
i2s_bclk_pin: GPIO34
i2s_mclk_pin: GPIO32
microphone:
- platform: i2s_audio
id: mic
adc_type: external
i2s_din_pin: GPIO35
pdm: false
speaker:
- platform: i2s_audio
id: speaker
dac_type: external
i2s_dout_pin: GPIO36
mode: mono
voice_assistant:
microphone: mic
speaker: speaker
noise_suppression_level: 2
auto_gain: 80dB
volume_multiplier: 0.8
Why this matters: Voice satellites extend Assist to multiple rooms with local processing.
Speech Processing Configuration
Language Support
Full Support (20+ languages): en, de, fr, it, es, nl, pl, pt, ru, sv, tr, uk, zh, ja, ko, and more
Partial Support (40+ languages): Regional variants and additional languages with varying STT/TTS availability
Community Support (80+ languages): Community-contributed sentence templates
Language Config:
assist_pipeline:
pipelines:
- language: de # German
name: Deutsche Pipeline
tts_engine: tts.piper # Set voice per language
Performance Tuning
STT (Faster Whisper):
stt:
- platform: faster_whisper
language: en
model: base # tiny, base, small, medium, large
acceleration: gpu # CPU or GPU
TTS (Piper):
tts:
- platform: piper
voice: en_GB-jenny
rate: 11025 # Audio sample rate
volume_normalize: true
Conversation Agent Integration
Built-in Agent:
conversation:
engine: home_assistant
OpenAI Agent:
conversation:
engine: openai
api_key: !secret openai_api_key
model: gpt-4
Custom Conversation Agent:
conversation:
engine: custom
module: custom_components.my_agent
Common Intent Patterns
Device Control Pattern
intents:
TurnOn:
data:
- sentences:
- "turn on [the] {name:list}"
- "[please] activate {name:list}"
lists:
name: light_names
Climate Control Pattern
intents:
SetClimate:
data:
- sentences:
- "set [the] {room:list} [thermostat] to {temp:number} degrees"
- "make it {temp:number} in [the] {room:list}"
lists:
room: room_names
Query Pattern
intents:
GetState:
data:
- sentences:
- "what is the temperature [in the] {room:list}"
- "is [the] {name:list} on"
lists:
room: room_names
name: device_names
Testing with Developer Tools
- Go to Developer Tools → Assist
- Enter test sentence: "turn on the bedroom light"
- Check:
- ✅ Intent matched correctly
- ✅ Slots extracted properly
- ✅ Audio plays (if TTS configured)
- Debug mismatches by:
- Reviewing sentence patterns
- Checking list values
- Verifying slot names
Troubleshooting
Intent Not Recognized
Symptoms: Voice command doesn't match any intent
Solution:
# Check custom_sentences directory structure
ls -R config/custom_sentences/
# Verify YAML syntax
cat config/custom_sentences/en/custom.yaml
# Test in Assist Developer Tools with exact phrase
# Adjust sentence patterns to match expected phrasing
TTS/STT Engine Not Working
Symptoms: "Engine not available" error in Assist
Solution:
# Verify engine is configured
service: tts.piper # Must exist
# Check dependencies installed
pip install piper-tts # for Piper
pip install faster-whisper # for Whisper
# Restart Home Assistant to load engines
Wake Word Not Triggering
Symptoms: Binary sensor stays off despite noise
Solution:
# Verify entity_id is correct
service: homeassistant.update_entity
target:
entity_id: binary_sensor.wake_word
# Check binary sensor configuration
# Review noise levels and model sensitivity
# Test microphone separately
Voice Satellite Connection Issues
Symptoms: ESP32 disconnects from WiFi or Assist pipeline
Solution:
# Check WiFi signal strength in ESPHome logs
# Reduce WiFi distance or add access point
# Update ESPHome firmware
esphome run voice_assistant.yaml --upload-speed 115200
Dependencies
Required
| Component | Version | Purpose |
|---|---|---|
| Home Assistant | 2024.1+ | Assist platform |
| Faster Whisper | 0.5+ | Local STT engine |
| Piper TTS | 1.0+ | Local TTS engine |
Optional
| Component | Version | Purpose |
|---|---|---|
| OpenWakeWord | 0.3+ | Wake word detection |
| Porcupine | Latest | Premium wake word |
| ESPHome | 2024.1+ | Voice satellite devices |
Official Documentation
- Home Assistant Voice Control
- Assist Pipeline Configuration
- Intent Recognition Guide
- Conversation Integration
Setup Checklist
Before using voice commands, verify:
- Assist pipeline configured with STT, TTS, and conversation engine
-
custom_sentences/en/directory created with intent definitions - Sentence patterns tested in Assist Developer Tools
- Wake word entity exists (if using wake word)
- Microphone and speaker working (test via Developer Tools)
- Intent lists contain correct entity aliases
- Language setting matches your configuration
- All YAML syntax is valid (no tabs, proper indentation)