163 lines
6.4 KiB
Markdown
163 lines
6.4 KiB
Markdown
# 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 <your-repo> 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
|
|
```
|