a13n
Build AI agents and run them on cloud.
A USB conference speakerphone as a Home Assistant voice satellite — say a wake word, give a command, hear the answer.
Translation pending
Developer toolsShellGitHub @RobertasTaOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Use a USB conference speakerphone as a Home Assistant voice satellite: Linux-Voice-Assistant on Proxmox LXC, tuned, with your own wake word. Guide in English, Lithuanian and Russian.
Taken from the repository README
Loading the full README.
Read the full README ↗Use a USB conference speakerphone as a Home Assistant voice satellite — say a wake word, give a command, hear the answer. The official Linux satellite software, connected and tuned the right way, with the parts that are hard to find written down: Proxmox LXC audio, PipeWire without udev, and your own wake word.
🌐 English · Lietuvių · Русский
ℹ️ Made with AI: the scripts and texts were written by Claude (Anthropic) together with Robertas and tested on real hardware; the illustration was created with AI.
Tested on 2026-10-10 with an EMEET Luna Plus (A350 USB dongle) in an unprivileged Proxmox LXC container: "Okay Nabu" → chime → «Который час?» ("What time is it?", asked in Russian) → the answer is spoken by the speakerphone. Wake word detected 3 times out of 3. Home Assistant found the device on its own.
A speakerphone is made for exactly this job: a microphone array that hears a whole room, echo cancellation in hardware, a loud speaker and a single USB plug (or a small USB radio dongle). You buy it ready-made — no soldering, no microphone boards, no 3D-printed case.
speakerphone ──USB──► Linux (PipeWire) ──► Linux-Voice-Assistant ──ESPHome protocol, port 6053──► Home Assistant
▲ (speech-to-text → intent → text-to-speech)
└──────────────────────────────── spoken answer ◄─────────────────────────────────────────────┘
wyoming-satellite is deprecated — do not start new installs with it.| Your setup | What to do |
|---|---|
| Speakerphone plugged into the Home Assistant OS machine | Use the official Assist Satellite app from OHF-Voice/apps. Not tested by us. |
| A normal Linux machine (mini PC, VM, 64-bit Raspberry Pi) | PipeWire finds the speakerphone by itself there — follow the official install guide, then tune it as below. Our setup-lva.sh is made and tested for containers. |
| Proxmox with an LXC container | Steps 1–4 below. ✅ This is what we tested. |
arecord -l:
card 2: A350 [EMEET Adapter A350], device 0: USB Audio → the card id is A350.1. Create a container — Ubuntu 24.04 template, unprivileged, nesting on, 2 cores, 2 GB RAM, 8 GB disk. Leave it stopped.
2. On the Proxmox host, give the container the sound devices:
./pve-speakerphone-lxc.sh 120 # dry run: lists your sound cards and shows what will be added
./pve-speakerphone-lxc.sh 120 --apply # writes it (backs up the old config first)
It adds three things to /etc/pve/lxc/120.conf — access to ALSA devices (c 116:*), a bind mount of /dev/snd
and an idmap for the audio group — and the matching root:29:1 line to /etc/subgid. Without the idmap an
unprivileged container sees the devices as nobody:nogroup and cannot open them.
3. Inside the container:
./setup-lva.sh --card A350 --name living-room
It installs PipeWire and LVA, creates the user lva, describes the speakerphone to PipeWire statically
(see Troubleshooting — containers have no udev) and starts the linux-voice-assistant service.
Options: --wake hey_jarvis (wake word), --user, --ref (LVA version).
4. In Home Assistant: Settings → Devices & services → Discovered → lva-‹MAC address› (ESPHome) → Add.
After adding, the device carries the name you gave with --name. If nothing is discovered:
Add integration → ESPHome → the container's IP, port 6053.
Everything is on the device page — no files to edit.
| Setting | What it does | Our advice |
|---|---|---|
| Assistant (×2) | Which Assist pipeline answers | Two slots: one wake word can use an English assistant, the other a different language |
| Wake word (×2) | Bundled: Okay Nabu, Hey Jarvis, Alexa, Hey Mycroft, Okay Computer, Hey Home Assistant, Hey Luna, … | "Hey Luna" suits an EMEET Luna 🙂 |
| Wake word sensitivity | The detection threshold (higher = stricter) | Wakes up by itself → raise it. Misses you → lower it a little |
| Mic volume / auto gain / noise suppression | Software processing before the wake word | A speakerphone already cleans the sound — start with gain and suppression off |
| Finished speaking detection | When it decides you have stopped talking | relaxed if it cuts you off, aggressive for faster answers |
| Mute, thinking sound | Microphone off; a sound while waiting | — |
Three things that are not on that page but matter:
Speaker volume: the media player volume in Home Assistant, and the hardware level with alsamixer -c <card id>
(control PCM). Microphone hardware level: control Mic (85 % on our unit).
LVA loads every *.json it finds in its wake word folders; each one appears in the Home Assistant wake word list.
setup-lva.sh adds the folder ~lva/wakewords for your own models. Two model types:
{ "type": "openWakeWord", "wake_word": "Okay Jenny", "model": "okay_jenny.tflite",
"openWakeWord": { "probability_cutoff": 0.6 } }
{ "type": "micro", "wake_word": "Okay Jenny", "model": "okay_jenny.tflite",
"micro": { "probability_cutoff": 0.85, "feature_step_size": 10, "sliding_window_size": 5 } }
Put okay_jenny.json and okay_jenny.tflite into /home/lva/wakewords/, run
systemctl restart linux-voice-assistant and choose it in Home Assistant. The model must be .tflite.
openWakeWord training (below) gives you the first kind; the second is for microWakeWord models.
Making the model. The openWakeWord training notebook creates thousands of synthetic voices saying your phrase and trains a small model (about an hour on a GPU or in Colab). What we measured while training our own non-English name:
Asking an AI assistant for help? Give it AI_CONSULTANT_BRIEF.md — it contains this method.
| Symptom | Cause and fix |
|---|---|
PipeWire shows only a dummy device (auto_null) | Containers have no udev, so PipeWire cannot discover the card. setup-lva.sh adds static nodes (~lva/.config/pipewire/pipewire.conf.d/50-speakerphone.conf). |
| PipeWire does not start | Most often the card is busy — something else has it open. Check journalctl --user -u pipewire. |
Devices inside the container belong to nobody:nogroup | The audio group idmap or the /etc/subgid line is missing — run pve-speakerphone-lxc.sh again. |
arecord/aplay as root inside the container says "No such device" | Not a missing device — container root is not in the audio group. Test as the lva user: runuser -u lva -- arecord -l. |
| "Access to … is not granted" / "not exposed" | Expose the device to Assist (see above). |
Failed to load cookie file | Harmless. |
| The speaker refuses 16 kHz | Normal for EMEET (plays 48–96 kHz). PipeWire resamples. |
| It suddenly "hears" only noise, no USB errors | The EMEET dongle can lock up without disconnecting. Switch the speakerphone off and on. |
Deaf after the dongle dropped off USB (dmesg shows a USB disconnect and reconnect) | The audio server probably still holds the old device. Restart it and the satellite: runuser -u lva -- env XDG_RUNTIME_DIR=/run/user/$(id -u lva) systemctl --user restart pipewire pipewire-pulse wireplumber && systemctl restart linux-voice-assistant. We met this on our own (non-LVA) speakerphone setup; not reproduced with LVA. |
| Two identical speakerphones | Tell them apart by serial number (/dev/snd/by-id/). Card ids (A350, A350_1) may swap after a reboot — one speakerphone per container is the simplest setup. |
| Speakerphone | EMEET Luna Plus with A350 USB dongle (328f:007b): microphone mono 16–48 kHz, speaker stereo 48–96 kHz |
| Host | Proxmox VE 9.2.6, unprivileged LXC, Ubuntu 24.04 |
| Software | PipeWire 1.0.5, WirePlumber 0.4.17, Python 3.12, Linux-Voice-Assistant b49fd8d (2026-09-29) |
| Home Assistant | 2026.10.0 |
| Scripts | pve-speakerphone-lxc.sh and setup-lva.sh run end-to-end on a fresh container — tested with the host's built-in sound card, because the speakerphone was busy at the time; the voice test above went through the same steps by hand (passing only the speakerphone's device nodes instead of all of /dev/snd). setup-lva.sh is safe to run again |
The scripts and texts in this repository: GPL-3.0-or-later. Linux-Voice-Assistant itself is not included; the setup script downloads it from its own repository (Apache-2.0).