signalk-piper
v0.2.0
Published
Piper text-to-speech as a managed container for Signal K, speaking the Wyoming protocol. Part of the signalk-wyoming voice assistant family.
Maintainers
Readme
signalk-piper
Status: ALPHA — This SignalK Wyoming system is 100% vibecoded slop. I don't have the right hardware yet to test it, so I'm putting it out there for people to test in the meantime. It should work. File issues for anything that doesn't.
signalk-piper gives your Signal K server a voice. It runs Piper, a fast, natural-sounding text-to-speech engine, in a container that the plugin installs, configures, and monitors for you. Once a voice is downloaded, everything runs fully offline — no cloud, no internet needed at sea.
It is the speaking half of the signalk-wyoming voice assistant family: install it alongside the orchestrator and the plugins below for spoken announcements and a full on-boat voice assistant. It also works standalone — anything that speaks the Wyoming protocol, including Home Assistant, can use it directly.
| Plugin | Role | | ---------------------------------------------------------------------- | --------------------------------------------------- | | signalk-wyoming | Orchestrator — family spec and discussion live here | | signalk-whisper | Speech-to-text | | signalk-piper | Text-to-speech | | signalk-openwakeword | Wake word detection |
Requirements
- The signalk-container plugin with a working podman or docker runtime — install and enable it first.
- Node.js ≥ 24 (Signal K server ≥ 2.x).
- RAM: about 150 MB while a voice is loaded; the container is capped at 512 MB by default. Piper plus the orchestrator run comfortably alongside Signal K on a Pi 4 with 2 GB.
- Disk: roughly 400 MB for the container image, plus ~60 MB per voice. Images are available for
linux/amd64andlinux/arm64(no 32-bit armv7).
Install
- Install and enable signalk-container (Appstore → Available).
- Install signalk-piper from the App Store (search "piper").
- Enable it in Server → Plugin Config.
First start needs internet
On first start the container downloads your chosen voice (~60 MB) from HuggingFace. The plugin status shows "Starting — first start downloads ~60 MB per voice" until the service is actually up and answering. The voice is stored in the plugin's data directory, so it survives restarts, container recreation, and image updates.
Do the first start at the dock, not at sea. After the download, everything runs fully offline. The same applies to every voice you plan to use: each one downloads on first use, so pre-download any voice you rely on while you still have internet.
Configuration
The plugin ships a graphical configuration panel (Server → Plugin Config → Piper TTS) with a live container status card, a one-click image update check/apply, a version dropdown fed by Docker Hub, and all the settings below — with inline warnings if you pick an unsupported voice or open the service to the network. On servers without custom-panel support you get a plain settings form with the same options.
| Setting | Default | Description |
| -------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| voice | en_US-lessac-medium | The Piper voice to load and serve. See Choosing a voice. |
| imageTag | auto | Version of the rhasspy/wyoming-piper image to run. auto runs the pinned, tested release (2.3.1) and follows plugin updates; set an explicit tag to pin a version. |
| port | 10200 | Host port for the Wyoming TTS service. Leave it alone unless it collides with something else. |
| advanced.bind | 127.0.0.1 | 127.0.0.1: only Signal K can reach the service (recommended). 0.0.0.0: share it with other machines on the network (see Security). |
| advanced.memoryLimit | 512m | Hard memory cap for the container. |
| advanced.restartPolicy | unless-stopped | Container restart policy (no / unless-stopped / always). |
| advanced.updateVoices | false | Refresh the list of available voices from HuggingFace each time the container starts (needs internet; off by default for offline-first boats). |
| advanced.sentenceSilence | (unset) | Seconds of silence added after each sentence. |
| advanced.lengthScale | (unset) | Speech speed tuning; values above 1 slow speech down. |
Choosing a voice
Browse and listen to voices at rhasspy/piper-voices. Stick to -medium or -high quality voices — voices ending in -low or -x_low use a lower sample rate (16 kHz) that the voice assistant family doesn't support; the plugin warns if you pick one but won't stop you. Each voice is a ~60 MB download on first use.
Using the service
The service is a standard Wyoming TTS endpoint at tcp://<host>:10200.
- With signalk-wyoming: nothing to set up — the orchestrator discovers the service automatically and uses it for all spoken output.
- With Home Assistant (standalone): set
advanced.bindto0.0.0.0, then add a Wyoming Protocol integration pointing attcp://<boat-ip>:10200. - Any other Wyoming client works the same way. Clients may request a different voice per request; a voice that was never downloaded triggers a download mid-request, so pre-download the voices you use.
Status, health, and alarms
The plugin doesn't just start the container and hope — it checks that the service really answers before reporting ready, and keeps checking every 30 seconds after that.
If the service stops answering (three failed checks in a row, about 90 seconds), the plugin raises the Signal K notification notifications.voice.piper (state: "alarm") and shows an error in Plugin Config. When the service comes back, the alarm clears itself (state: "normal") — no action needed. Any dashboard or alerting setup that watches Signal K notifications can subscribe to this path.
HTTP API
The plugin serves a small REST API under /plugins/signalk-piper:
| Endpoint | Method | Access | Returns |
| ------------------- | ------ | -------- | ------------------------------------------------------------------------------------------- |
| /api/status | GET | readonly | { status, uri, tag, containerState, lastHealth, info } — live service and container state |
| /api/versions | GET | readonly | Available rhasspy/wyoming-piper releases from Docker Hub, newest first |
| /api/update/check | GET | admin | Whether a newer container image is available |
| /api/update/apply | POST | admin | Pulls and switches to a new image version |
Security
Wyoming has no authentication — anyone who can reach the port can use the service. The default bind: 127.0.0.1 keeps it reachable only from the Signal K host, which is right for almost everyone; leave it that way unless another machine genuinely needs TTS. If you do set bind: 0.0.0.0 (e.g. to share with Home Assistant), firewall the port at the boat router or keep it on a trusted network. See the family spec's security section for the full picture — the satellite microphone ports are the truly sensitive ones; a TTS port mostly risks someone making your boat talk.
Troubleshooting
- Stuck on "Starting" — the first start of a voice is a ~60 MB download and can take a while on a slow connection; the plugin waits up to 10 minutes. No internet, no voice: connect and restart the plugin.
notifications.voice.piperalarm — the container stopped answering. Check the container status in the config panel or/api/status; the alarm clears automatically once the service recovers.- Speech too fast/slow or sentences run together — tune
advanced.lengthScaleandadvanced.sentenceSilence.
Development
Build instructions, architecture notes, and the internals (readiness gating, health checks, discovery emissions, the config panel) live in DEVELOPMENT.md.
License
Apache-2.0
