Architecture (Advanced)
August 10, 2026 · View on GitHub
This page describes exactly what runs on the satellite device, what crosses the wire, and why the design fits low-power hardware.
On-device components
Microphone plugin → VAD engine → HiveMessageBusClient (WebSocket)
↑
PlaybackThread ← TTSHandler
↑
AudioService (optional media)
PHAL (optional HW abstraction)
The on-device processing pipeline works as follows.
- Microphone plugin (
OVOSMicrophoneFactory) reads raw audio chunks at the configured sample rate. - VAD engine (
OVOSVADFactory) classifies each chunk as speech or silence. - Streaming logic emits each chunk over the HiveMind connection as a
HiveMessageType.BINARYmessage with payload typeHiveMindBinaryPayloadType.RAW_AUDIO, once speech starts. Streaming continues until 6 seconds of continuous silence have passed since the last speech chunk. - PlaybackThread dequeues TTS audio files and plays them through
ovos-audio. - TTSHandler, a
BinaryDataCallbackssubclass, receives binary TTS audio from the hive, writes it to/tmp/<filename>, and queues it for playback.
What crosses the wire
Satellite to hive (upstream)
- Raw audio chunks as
HiveMessageType.BINARY/HiveMindBinaryPayloadType.RAW_AUDIO. The satellite sends only chunks during detected voice activity; the VAD suppresses silence.
Hive to satellite (downstream)
-
OVOS bus messages wrapped in
HiveMessageType.BUS:recognizer_loop:wakeword: wakeword detected (logged)recognizer_loop:record_begin/record_end: STT phase started/endedrecognizer_loop:utterance: transcription resultrecognizer_loop:speech.recognition.unknown: STT failedmycroft.audio.play_sound: play a local sound filespeak: TTS request (satellite requests audio back)speak:b64_audio.response: base64-encoded TTS audioovos.utterance.handled: intent was handled
-
Binary TTS audio received via
BinaryDataCallbacks.handle_receive_tts(the satellite requested synthesis throughspeak:synth).
Scaling: homelab vs service
mic-satellite has no local wakeword, so the VAD ships every speech segment to the hive, not just post-activation commands. That keeps the device cheap but turns the upstream into a continuous raw-audio stream, and the server bears the full STT cost for all speech. This works well for a homelab with a few personal devices. It does not scale for a multi-tenant HiveMind-as-a-service offering, because per-client raw-audio streaming costs too much in bandwidth and compute. A voice-relay device, which streams only after a local wakeword fires, fits a service deployment better. Both delegate STT and TTS to the hive, owned and authenticated; they differ in how much audio crosses the wire, and therefore in how they scale.
TTS playback path
When the hive sends a speak message:
- The satellite sends back a
speak:synthrequest (orspeak:b64_audioifprefer_b64=True). - The hive synthesizes speech and sends the audio back as binary or base64.
TTSHandler.handle_receive_ttswrites the audio to/tmp/<hash>.wav.- The file is queued in
PlaybackThread. PlaybackThread, fromovos-audio, plays the file and, if a G2P plugin is configured, generates mouth movement visemes.
Session and identity
- Each satellite has a
NodeIdentity, stored in~/.config/hivemind/_identity.json, with anaccess_key,password,default_master(host), and an optionalsite_id. - The
site_id/--siteidflag is injected intomessage.contextso the hive knows which physical location the audio came from. - A
Sessionis created locally (FakeBus(session=Session())) and shared between the internal bus and the playback thread for message routing.
Reconnection
HiveMessageBusClient handles connection management. On startup the client calls connect() and then waits on connected_event. hivemind-bus-client provides reconnection behavior, including retry and backoff.
Sound files
The package ships three local sound files used by mycroft.audio.play_sound events from the hive:
hivemind_mic_sat/res/snd/acknowledge.mp3
hivemind_mic_sat/res/snd/error.mp3
hivemind_mic_sat/res/snd/start_listening.wav
If the URI in a play_sound message starts with snd/, the satellite resolves it against this bundled resource directory.
Why thin? Trade-offs vs heavier satellites
| Factor | mic-satellite | voice-relay | voice-sat |
|---|---|---|---|
| Local model downloads | None | Wakeword model | Wakeword + STT + TTS models |
| RAM/CPU on device | Minimal (mic + VAD only) | Low | Moderate-high |
| Network bandwidth | Moderate (raw audio stream) | Moderate (raw audio) | Low (text only) |
| Server dependency | High: server does everything | Medium: wakeword is local | Low: server is optional fallback |
| Privacy | Audio leaves device | Audio leaves device | Only text leaves device |
| Latency | Depends on server round-trip time and STT speed | Depends on server round-trip time | Mostly local |
mic-satellite is the right choice when:
- Hardware is too constrained for local models (Raspberry Pi Zero, microcontrollers with a companion SBC, embedded Linux)
- You control the server and trust the network
- You want to centralize model management and updates on the hive
voice-sat is better when:
- Audio privacy is critical (only text crosses the wire)
- The device has enough RAM/CPU for local STT and TTS
- Low latency matters more than hardware cost
PHAL integration
If ovos-PHAL is importable at startup, the satellite creates a PHAL instance and connects it to the HiveMind bus (self.hm_bus). This lets hardware plugins, such as LED rings, buttons, or a faceplate, react to bus events forwarded from the hive and inject hardware-triggered events back to the hive.