Experimental Linux-Voice-Assistant for Home Assistant that uses the ESPHome protocol/API (via aioesphomeapi).
- Works with Home Assistant
- Local wake word detection using integrated OpenWakeWord or MicroWakeWord
- External wake word detection mode (
--external-wake-word): streams audio to Home Assistant continuously, stop word detection still runs locally — useful for resource-constrained devices - Wyoming wake word detection mode (
--wake-uri): connects directly to a wyoming-microwakeword (or compatible) service via TCP, bypassing Home Assistant for wake word detection - Supports multiple architectures (linux/amd64 and linux/aarch64)
- Automated builds with artifact attestation for security
- Supports multiple wake words and languages
- Supports announcments, start/continue conversation, and timers
- Tested with Python 3.13 and Python 3.11.
- Prebuild docker image available on GitHub Container Registry
- Prebuild Raspberry Pi image
You can for example use the Raspberry Pi Zero 2W with the Satellite1 Hat Board, the Respeaker Lite or the Respeaker 2Mic_Hat.
A list for possible compatible hardware can be found in the PiCompose documentation but basically any microphone that works with Pipewire can be used with the prebuild image.
For Raspberry Pi users, we provide a prebuild image that can be flashed to a SD card. See PiCompose.
For all other users we have different installation methods available (Docker, systemd), each with its own dedicated instructions. See Linux-Voice-Assistant - Installation.
💡 Note: There is a environment variable for each parameter if you use docker or systemd based setup.
usage: __main__.py [-h] [--name NAME] [--audio-input-device AUDIO_INPUT_DEVICE] [--list-input-devices] [--audio-input-block-size AUDIO_INPUT_BLOCK_SIZE] [--audio-output-device AUDIO_OUTPUT_DEVICE] [--list-output-devices] [--wake-word-dir WAKE_WORD_DIR]
[--wake-model WAKE_MODEL] [--stop-model STOP_MODEL] [--download-dir DOWNLOAD_DIR] [--refractory-seconds REFRACTORY_SECONDS] [--wakeup-sound WAKEUP_SOUND] [--timer-finished-sound TIMER_FINISHED_SOUND] [--processing-sound PROCESSING_SOUND]
[--mute-sound MUTE_SOUND] [--unmute-sound UNMUTE_SOUND] [--preferences-file PREFERENCES_FILE] [--host HOST] [--network-interface NETWORK_INTERFACE] [--port PORT] [--enable-thinking-sound] [--external-wake-word]
[--wake-uri WAKE_URI] [--wake-word-name WAKE_WORD_NAME] [--debug]| Parameter | Description | Default |
|---|---|---|
--name |
Name of the voice assistant device (required) | Autogenerated (lva-MAC-ADDRESS) |
--audio-input-device |
ALSA device name for input (e.g. plughw:CARD=USB,DEV=0), use --list-input-devices to list |
Autodetected |
--audio-input-block-size |
Audio input block size in samples | 1024 |
--audio-output-device |
ALSA device name for output (e.g. plughw:CARD=USB,DEV=0), use --list-output-devices to list |
Autodetected |
--wake-word-dir |
Directory with wake word models (.tflite) and configs (.json) | wakewords/ |
--wake-model |
ID of active wake word model | okay_nabu |
--stop-model |
ID of stop model | stop |
--download-dir |
Directory to download custom wake word models, etc. | local/ |
--refractory-seconds |
Seconds before wake word can be activated again | 2.0 |
--wakeup-sound |
Sound file played when wake word is detected | sounds/wake_word_triggered.flac |
--timer-finished-sound |
Sound file played when timer finishes | sounds/timer_finished.flac |
--processing-sound |
Sound played while assistant is processing | sounds/processing.wav |
--mute-sound |
Sound played when muting the assistant | sounds/mute_switch_on.flac |
--unmute-sound |
Sound played when unmuting the assistant | sounds/mute_switch_off.flac |
--preferences-file |
Path to preferences JSON file | preferences.json |
--host |
IP-Address for ESPHome server, use 0.0.0.0 for all | Autodetected |
--network-interface |
Network interface for ESPHome server | Autodetected |
--port |
Port for ESPHome server | 6053 |
--enable-thinking-sound |
Enable thinking sound on startup | False |
--external-wake-word |
Offload wake word detection to Home Assistant; audio is streamed continuously while stop word detection still runs locally. Mutually exclusive with --wake-uri |
False |
--wake-uri |
URI of a Wyoming wake word service (e.g. tcp://192.168.178.52:10400). Connects directly to wyoming-microwakeword, bypassing HA for wake word detection. Mutually exclusive with --external-wake-word |
None |
--wake-word-name |
Wake word name to request from the Wyoming service (only used with --wake-uri) |
okay_nabu |
--debug |
Print DEBUG messages to console | False |
Image builds can be tracked in this repository's Actions tab, and utilize artifact attestation to certify provenance.
The Docker images are built using GitHub Actions, which provides:
- Automated builds for different architectures
- Artifact attestation for build provenance verification
- Regular updates and maintenance
The documentation for the build process can be found in the GitHub Actions Workflows file.
The project uses the following tools to ensure code quality:
- Black: Code formatting (88 characters per line, PEP 8 compliant)
- isort: Import sorting compatible with Black
- flake8: Style and syntax checks
- pylint: Code quality checks
- mypy: Static type analysis
To use the development tools (linting, testing, etc.), you need to install the required dependencies:
./script/setup --dev
source .venv/bin/activate./script/lint...| Script | Description | Auto-fix Available? |
|---|---|---|
./script/lint_black |
Checks Python code formatting with Black | Yes, use --auto flag |
./script/lint_flake8 |
Runs style and syntax checks with flake8 | No |
./script/lint_isort |
Checks import sorting with isort | Yes, use --auto flag |
./script/lint_mypy |
Runs static type analysis with mypy | No |
./script/lint_pylint |
Runs code quality checks with pylint | Yes, use --auto flag |
Run a specific lint check:
./script/lint_blackAuto-fix formatting issues (Black + isort):
./script/lint_black --auto
./script/lint_isort --autoRun the test suite:
./script/testThis project is licensed under the Apache 2.0 License - see the LICENSE file for details.
