diff --git a/README.md b/README.md index 0f31703..964a499 100755 --- a/README.md +++ b/README.md @@ -3,189 +3,311 @@ Remote voice satellite using the [Wyoming protocol](https://github.com/rhasspy/wyoming). * Works with [Home Assistant](https://www.home-assistant.io/integrations/wyoming) -* Local wake word detection using [Wyoming services](https://github.com/rhasspy/wyoming#wyoming-projects) +* Local wake word detection using [Vosk](https://alphacephei.com/vosk/) * Audio enhancements using [webrtc](https://github.com/rhasspy/webrtc-noise-gain/) - -See [the tutorial](docs/tutorial_2mic.md) to build a satellite using a [Raspberry Pi Zero 2 W](https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/) and a [ReSpeaker 2Mic HAT](https://wiki.keyestudio.com/Ks0314_keyestudio_ReSpeaker_2-Mic_Pi_HAT_V1.0). - -Video tutorials: - -* [Wyoming Voice Satellite with ChatGPT](https://www.youtube.com/watch?v=eTKgc0YDCwE) -* [Local ChatGPT Voice Assistant](https://www.youtube.com/watch?v=pAKqKTkx5X4) +* MQTT integration for LED control and Home Assistant discovery [![An open standard from the Open Home Foundation](https://www.openhomefoundation.org/badges/ohf-open-standard.png)](https://www.openhomefoundation.org/) + --- -Requires: +## 📋 Requirements -* Python 3.7+ (tested on 3.9+) -* A microphone +* Python 3.9+ +* Linux (tested on Raspberry Pi OS) +* Microphone (USB or HAT) +* Optional: ReSpeaker XVF3800 USB 4-MIC Array (for LED control) -## Installation +--- -Install the necessary system dependencies: +## 🚀 Quick Start -``` sh -sudo apt-get install python3-venv python3-pip +### 1. Clone and Install + +```bash +git clone ~/projects/Satellite +cd ~/projects/Satellite + +# Create virtual environment +python3 -m venv ~/.venv_satellite +source ~/.venv_satellite/bin/activate + +# Install dependencies +pip install -r requirements.txt ``` -Then run the install script: +### 2. Install systemd Services -``` sh -script/setup +```bash +sudo ./install_systemd_services.sh ``` -The examples below uses `alsa-utils` to record and play audio: +This script automatically: +- Detects your virtual environment location +- Substitutes correct paths in service files +- Installs the `satellite-python` wrapper -``` sh -sudo apt-get install alsa-utils +### 3. Start Services + +```bash +# LED control (optional, requires ReSpeaker) +sudo systemctl enable wyoming-event.service +sudo systemctl start wyoming-event.service + +# Wyoming Satellite +sudo systemctl enable wyoming-satelite-vosk.service +sudo systemctl start wyoming-satelite-vosk.service + +# Wake word detection (Vosk) +sudo systemctl enable wyoming-wakeword-vosk.service +sudo systemctl start wyoming-wakeword-vosk.service ``` +### 4. Verify -## Remote Wake Word Detection +```bash +sudo systemctl status wyoming-satelite-vosk.service +journalctl -u wyoming-satelite-vosk.service -f +``` -Run the satellite with remote wake word detection: +--- -``` sh -cd wyoming-satellite/ -script/run \ - --name 'my satellite' \ +## 📦 Installation + +### System Dependencies + +```bash +sudo apt-get install python3-venv python3-pip alsa-utils +``` + +### Python Dependencies + +```bash +# Create and activate venv +python3 -m venv ~/.venv_satellite +source ~/.venv_satellite/bin/activate + +# Install requirements +pip install -r requirements.txt +``` + +--- + +## 🔧 Configuration + +### Service Files + +All service files are in `service/` directory and use placeholders that are automatically replaced during installation: + +| Placeholder | Description | +|-------------|-------------| +| `__SAT_BASE_DIR__` | Path to Satellite repository | +| `__SAT_VENV__` | Path to virtual environment | +| `__CURRENT_USER__` | Current username | +| `__HOME_DIR__` | User home directory | + +### Available Services + +| Service | Description | Port | +|---------|-------------|------| +| `wyoming-satelite-vosk.service` | Main Wyoming satellite | 10700 | +| `wyoming-wakeword-vosk.service` | Vosk wake word detection | 10400 | +| `wyoming-event.service` | LED control + MQTT | 10500 | + +### Configuration Files + +| File | Location | Description | +|------|----------|-------------| +| `config.yaml` | `local/vosk-wake-dev/wyoming_vosk_wake/` | VAD and wake word settings | +| `led_brightness_config.json` | `examples/` | LED brightness levels (auto-created) | + +--- + +## 🎤 Usage + +### Manual Start (without systemd) + +```bash +# Activate venv +source ~/.venv_satellite/bin/activate + +# Start satellite +./start_satellite.sh + +# Or directly +python3 -m wyoming_satellite \ + --name 'my-satellite' \ --uri 'tcp://0.0.0.0:10700' \ --mic-command 'arecord -r 16000 -c 1 -f S16_LE -t raw' \ --snd-command 'aplay -r 22050 -c 1 -f S16_LE -t raw' ``` -This will use the default microphone and playback devices. +### Wake Word Configuration -Use `arecord -D ...` if you need to use a different microphone (list them with `arecord -L` and prefer `plughw:` devices). -Use `aplay -D ...` if you need to use a different playback device (list them with `aplay -L` and prefer `plughw:` devices). +Edit `local/vosk-wake-dev/wyoming_vosk_wake/config.yaml`: -Add `--debug` to print additional logs. +```yaml +vad: + vad_enabled: true + energy_threshold: 800 + speech_threshold: 0.5 + min_speech_duration_ms: 200 -In the [Home Assistant](https://www.home-assistant.io/) settings "Devices & services" page, you should see the satellite discovered automatically. If not, click "Add Integration", choose "Wyoming Protocol", and enter the IP address of the satellite (port 10700). - -Audio will be continuously streamed to the server, where wake word detection, etc. will occur. - -### Voice Activity Detection - -Rather than always streaming audio to Home Assistant, the satellite can wait until speech is detected. - -**NOTE:** This will not work on the 32-bit version of Raspberry Pi OS. - -Install the dependencies for silero VAD: - -``` sh -.venv/bin/pip3 install 'pysilero-vad==1.0.0' +logging_level: debug # debug, info, warning, error ``` -Run the satellite with VAD enabled: +### LED Control (ReSpeaker) -``` sh -script/run \ - ... \ - --vad +The LED service requires the [ReSpeaker XVF3800 control scripts](https://github.com/respeaker/usb_4mic_array): + +```bash +# Clone ReSpeaker repo +git clone https://github.com/respeaker/usb_4mic_array.git ~/projects/reSpeaker_XVF3800_USB_4MIC_ARRAY + +# The LED service will automatically find xvf_host.py ``` -Now, audio will only start streaming once speech has been detected. +MQTT Topics: +- `wyoming/led/command` - Send commands +- `wyoming/led/brightness/set` - Set brightness (0-255) +- `wyoming/led/brightness/state` - Brightness state +- `wyoming/led/state` - Current LED state +- `wyoming/led/availability` - Online/offline status -## Local Wake Word Detection +--- -Install a wake word detection service, such as [wyoming-openwakeword](https://github.com/rhasspy/wyoming-openwakeword/) and start it: +## 🔍 Examples -``` sh -cd wyoming-openwakeword/ -script/run \ - --uri 'tcp://0.0.0.0:10400' \ - --preload-model 'ok_nabu' +See `examples/` directory for additional scripts: + +| File | Description | +|------|-------------| +| `wyoming-led.py` | LED control with MQTT and Home Assistant discovery | +| `2mic_service.py` | Configuration for 2-mic HAT | +| `4mic_service.py` | Configuration for 4-mic array | +| `usbmic_service.py` | Configuration for USB microphone | + +--- + +## 🛠️ Development + +### Project Structure + +``` +Satellite/ +├── service/ # systemd service files +├── examples/ # Example scripts +├── local/ # Local wake word services +│ └── vosk-wake-dev/ # Vosk wake word detection +├── scripts/ # Helper scripts +├── install_systemd_services.sh # Auto-install services +├── requirements.txt # Python dependencies +├── start_satellite.sh # Main startup script +└── DEPLOY.md # Deployment guide ``` -Add `--debug` to print additional logs. See `--help` for more information. +### Running Tests -Included wake words are: +```bash +# Run linters +pylint wyoming_satellite/ +mypy wyoming_satellite/ -* `ok_nabu` -* `hey_jarvis` -* `alexa` -* `hey_mycroft` -* `hey_rhasspy` - -[Community trained wake words](https://github.com/fwartner/home-assistant-wakewords-collection) are also available and can be included with `--custom-model-dir ` where `` contains `.tflite` file(s). - -Next, start the satellite with some additional arguments: - -``` sh -cd wyoming-satellite/ -script/run \ - --name 'my satellite' \ - --uri 'tcp://0.0.0.0:10700' \ - --mic-command 'arecord -r 16000 -c 1 -f S16_LE -t raw' \ - --snd-command 'aplay -r 22050 -c 1 -f S16_LE -t raw' \ - --wake-uri 'tcp://127.0.0.1:10400' \ - --wake-word-name 'ok_nabu' +# Run tests (if available) +pytest tests/ ``` -Audio will only be streamed to the server after the wake word has been detected. +### Updating Dependencies -Once a wake word has been detected, it can not be detected again for several seconds (called the "refractory period"). You can change this with `--wake-refractory-seconds `. - -Note that `--vad` is unnecessary when connecting to a local instance of openwakeword. - -## Sounds - -You can play a WAV file when the wake word is detected (locally or remotely), and when speech-to-text has completed: - -* `--awake-wav ` - played when the wake word is detected -* `--done-wav ` - played when the voice command is finished -* `--timer-finished-wav ` - played when a timer is finished - -If you want to play audio files other than WAV, use [event commands](#event-commands). Specifically, the `--detection-command` to replace `--awake-wav` and `--transcript-command` to replace `--done-wav`. - -The timer finished sound can be repeated with `--timer-finished-wav-repeat ` where `` is the number of times to repeat the WAV, and `` is the number of seconds to wait between repeats. - -## Audio Enhancements - -Install the dependencies for webrtc: - -``` sh -.venv/bin/pip3 install 'webrtc-noise-gain==1.2.3' +```bash +# Update requirements.txt from current venv +pip freeze > requirements.txt ``` -Run the satellite with automatic gain control and noise suppression: +--- -``` sh -script/run \ - ... \ - --mic-auto-gain 5 \ - --mic-noise-suppression 2 +## 📖 Documentation + +* [Deployment Guide](DEPLOY.md) - Full deployment instructions +* [Wyoming Protocol](https://github.com/rhasspy/wyoming) - Protocol documentation +* [Home Assistant Integration](https://www.home-assistant.io/integrations/wyoming) - HA setup +* [Vosk](https://alphacephei.com/vosk/) - Wake word recognition + +--- + +## 🎥 Video Tutorials + +* [Wyoming Voice Satellite with ChatGPT](https://www.youtube.com/watch?v=eTKgc0YDCwE) +* [Local ChatGPT Voice Assistant](https://www.youtube.com/watch?v=pAKqKTkx5X4) + +--- + +## ⚙️ Audio Enhancements + +### WebRTC Noise Suppression + +Enabled by default via `requirements.txt` (webrtc-noise-gain==1.2.3) + +Configure in satellite startup: +```bash +--mic-auto-gain 5 \ +--mic-noise-suppression 2 ``` -Automatic gain control is between 0-31 dbFS, which 31 being the loudest. -Noise suppression is from 0-4, with 4 being maximum suppression (may cause audio distortion). +### VAD (Voice Activity Detection) -You can also use `--mic-volume-multiplier X` to multiply all audio samples by `X`. For example, using 2 for `X` will double the microphone volume (but may cause audio distortion). The corresponding `--snd-volume-multiplier` does the same for audio playback. +Configured in `config.yaml`: +```yaml +vad: + vad_enabled: true + mode: 3 # 0-3, higher = more aggressive + sample_rate: 16000 +``` -## Event Commands +--- -Satellites can respond to events from the server by running commands: +## 🐛 Troubleshooting -* `--startup-command` - run when satellite starts (no stdin) -* `--detect-command` - wake word detection has started, but not detected yet (no stdin) -* `--streaming-start-command` - audio has started streaming to server (no stdin) -* `--streaming-stop-command` - audio has stopped streaming to server (no stdin) -* `--detection-command` - wake word is detected (wake word name on stdin) -* `--transcript-command` - speech-to-text transcript is returned (text on stdin) -* `--stt-start-command` - user started speaking (no stdin) -* `--stt-stop-command` - user stopped speaking (no stdin) -* `--synthesize-command` - text-to-speech text is returned (text on stdin) -* `--tts-start-command` - text-to-speech response started streaming from server (no stdin) -* `--tts-stop-command` - text-to-speech response stopped streaming from server. Can still being played by snd service (no stdin) -* `--tts-played-command` - text-to-speech audio finished playing (no stdin) -* `--error-command` - an error was sent from the server (text on stdin) -* `--connected-command` - satellite connected to server -* `--disconnected-command` - satellite disconnected from server -* `--timer-started-command` - new timer has started (json on stdin) -* `--timer-updated-command` - timer has been paused/unpaused or has time added/removed (json on stdin) -* `--timer-cancelled-command` - timer has been cancelled (timer id on stdin) -* `--timer-finished-command` - timer has finished (timer id on stdin) +### Service won't start -For more advanced scenarios, use an event service (`--event-uri`). See `wyoming_satellite/example_event_client.py` for a basic client that just logs events. +```bash +# Check status +sudo systemctl status wyoming-satelite-vosk.service + +# View logs +journalctl -u wyoming-satelite-vosk.service -f + +# Check Python path +which satellite-python +satellite-python --version +``` + +### Microphone not detected + +```bash +# List audio devices +arecord -L +aplay -L + +# Test recording +arecord -r 16000 -c 1 -f S16_LE -t raw -d 5 test.wav +aplay test.wav +``` + +### MQTT Connection Issues + +Check broker settings in `examples/wyoming-led.py`: +```python +MQTT_BROKER = "192.168.200.100" +MQTT_PORT = 1883 +MQTT_USER = "mqtt" +MQTT_PASS = "mqtt" +``` + +--- + +## 📝 License + +This project is part of the Open Home Foundation ecosystem. + +[![An open standard from the Open Home Foundation](https://www.openhomefoundation.org/badges/ohf-open-standard.png)](https://www.openhomefoundation.org/)