# javis-slave on a Raspberry Pi Turn a Raspberry Pi with a USB microphone and a speaker into a Javis satellite: it detects the wake word locally, streams the utterance to the Javis master on your LAN, and plays the spoken reply. No GPU, no models beyond the tiny openWakeWord ONNX file. ## Hardware | Part | Notes | |------|-------| | Raspberry Pi 3B+ / 4 / 5 / Zero 2 W | 64-bit Raspberry Pi OS (Bookworm or newer). Zero 2 W works headless; wake-word inference uses ~15 % of one core. | | USB microphone or USB sound card + mic | Most USB mics only offer 44.1/48 kHz — the slave resamples to 16 kHz automatically. Conference-style mics (e.g. Jabra, Anker) give the best wake-word range. | | Speaker | 3.5 mm jack, HDMI, USB DAC or an I²S HAT. | | Optional: official 7" touch display | Use `setup-pi.sh --gui` for the same touch UI as the Surface build; brightness control works via `/sys/class/backlight`. | ## Install (5 minutes) ```bash # On the Pi git clone javis && cd javis/javis-slave # or scp the javis-slave folder sudo ./setup-pi.sh # headless # sudo ./setup-pi.sh --gui # with touch display # add --with-vad for silero-vad end-pointing (pulls PyTorch, ~200 MB; RMS gate is used otherwise) ``` The script installs apt dependencies, creates `/opt/javis-slave/.venv`, pre-downloads the wake-word models, grants the service user audio/backlight/power permissions and installs a `systemd` unit (`javis-slave.service`, enabled but not started). ## Configure & pair 1. **Pick audio devices** ```bash cd /opt/javis-slave export JAVIS_SLAVE_CONFIG_DIR=/opt/javis-slave/config .venv/bin/python -m javis_slave --list-devices ``` Note the index of your mic (`max_input_channels > 0`) and speaker. 2. **Enable the API on the master** (`config.yaml`), then restart Javis: ```yaml api: enabled: true host: 0.0.0.0 port: 8765 ``` Open the **Devices** tab → *Generate pairing code*. The tab shows the master's LAN address and the 6-digit code (valid 5 min, single use). 3. **Pair and test in the foreground** ```bash .venv/bin/python -m javis_slave --headless \ --input-device 1 --output-device 0 \ --pair 192.168.1.10:8765 123456 --name Kueche ``` Say the wake word (default *hey jarvis*) — you should hear the ascending two-tone chime, speak, and hear the reply. Device settings are persisted in `$JAVIS_SLAVE_CONFIG_DIR/slave_config.json`. Stop with Ctrl+C. 4. **Run as a service** ```bash sudo systemctl start javis-slave journalctl -u javis-slave -f ``` Assign a room in the master's Devices tab (e.g. `Küche`); the slave picks it up within a minute and every utterance is tagged with it for the LLM. With `setup-pi.sh --gui` the system service stays disabled and the touch UI autostarts in the desktop session instead (`~/.config/autostart/javis-slave.desktop`, `--kiosk` = fullscreen, hidden cursor; Esc leaves fullscreen, F11 toggles). Logs: `journalctl -u javis-slave` (service) and `$JAVIS_SLAVE_CONFIG_DIR/logs/slave.log` (rotating, both modes). ## Audible feedback (no screen needed) | Sound | Meaning | |-------|---------| | Two rising tones | Wake word heard — speak now | | Two falling low tones | Something failed (master unreachable, mic error) | | Spoken error phrase | The master received the request but its turn failed (STT/LLM); it sends its configured `agent.error_phrase` as speech | ## Remote control from the master The slave runs a small HTTP control server on port 8766 (`/mcp/v1/...`) that the [javis-slave-mcp](../javis-slave-mcp/README.md) server exposes as tools, so you can say *"mach die Küche leiser"*. On Linux the endpoints map to: | Endpoint | Backend | |----------|---------| | `/mcp/v1/volume/*` | `pactl` (PipeWire/Pulse) → falls back to `amixer` (ALSA) | | `/mcp/v1/brightness/*` | `/sys/class/backlight/*/brightness` (udev rule from `setup-pi.sh`) | | `/mcp/v1/power/*` | `systemctl suspend`, `shutdown` via a scoped sudoers entry | | `/mcp/v1/mic/*`, `/status`, `/restart` | Engine mute / status / restart | ## CLI reference ``` javis-slave --headless service mode, no window javis-slave --fullscreen | --kiosk GUI fullscreen / fullscreen + hidden cursor javis-slave --pair HOST:PORT CODE --name N pair (works with and without --headless) javis-slave --list-devices print sounddevice table javis-slave --input-device N --output-device N --input-gain G --api-port P persist settings and start ``` Environment: `JAVIS_SLAVE_CONFIG_DIR` overrides the config folder (default `~/.javis-slave`). ## Troubleshooting **No devices listed / "Error querying device"** — `sudo apt install libportaudio2` and make sure the user is in the `audio` group (`groups`; log out/in after `setup-pi.sh`). **Mic opens at 48 kHz, wake word never fires** — normal; the log line `mic started @ 48000Hz→16000Hz` confirms resampling is active. Raise `--input-gain 2.0` if the level is low; check with `arecord -d 3 test.wav`. Stereo-only USB cards are opened with both channels and mixed to mono. **USB mic unplugged / stops delivering audio** — after ~2 minutes of silence from the device the engine logs `reopening device` and re-opens it; if the device is gone the engine start is retried every 10 s. **"Master … not reachable"** — the master must have `api.enabled: true` and its Windows firewall must allow inbound TCP 8765 (Javis is a Python process; allow `python.exe` on private networks). **Wake word too sensitive / not sensitive enough** — change `wake_word.threshold` on the *master*; slaves pull it on the next config poll (≤ 60 s). **Reply is silent but text appears in the master's log** — the master's TTS has no voice profile with reference clips; add one in the Voices tab. Playback device problems show up as `speaker does not support … Hz` (auto-resampled) or an ALSA error in `journalctl`. **Service dies at boot** — USB audio may enumerate after the service starts; `Restart=always` + `RestartSec=5` recover automatically. The engine also retries every 10 s while the mic is unavailable. **Pi Zero 2 W CPU load** — skip `--with-vad`; the RMS gate is much cheaper than Silero on a single core. Keep only one wake-word model. ## Uninstall ```bash sudo systemctl disable --now javis-slave sudo rm /etc/systemd/system/javis-slave.service /etc/sudoers.d/javis-slave \ /etc/udev/rules.d/90-javis-backlight.rules sudo rm -rf /opt/javis-slave ```