Voice
Radio
Talk to OpenClaw over ham radio β ham radio voice channel plugin
Install
npm install
npm
README
# openclaw-radio
### Turn any sound card into a radio channel.
**What if your AI assistant could talk on the radio?** openclaw-radio is an [OpenClaw](https://github.com/openclaw/openclaw) plugin that connects any USB sound card interface β [DigiRig](https://digirig.net/), AIOC, Signalink, or a CM108 dongle β to your AI assistant over ham radio. Plug in your interface, set your callsign, and you're on the air.
**Status:** First QSO completed on-air 2026-03-30. W6RGC/BOSS responding to voice transmissions on UHF FM. π»
---
## Features
- **Any audio interface** β DigiRig, AIOC, Signalink, CM108, or any USB sound card
- **Any PTT method** β serial (RTS/DTR), GPIO, VOX, or RX-only monitor mode
- **Dual-threshold carrier sense** β detects speech vs. squelch, handles mid-sentence pauses
- **Noise rejection** β sustained energy gate + post-STT word filter suppresses static hallucinations
- **FCC compliant** β callsign on every transmission, ID timer per Part 97.119
- **TX safety** β hardware watchdog prevents stuck transmissions
- **Ham radio personality** β AI knows how to talk on the radio (brevity, prowords, phonetics, signal reports)
- **Full observability** β JSONL logs with every TX/RX transcript and per-stage latency timing
- **Linux-first, Mac-supported** β ALSA/PulseAudio/PipeWire on Linux, CoreAudio via `sox` on macOS
---
## Quick Start
```bash
# 1. Install the plugin
openclaw plugins install /path/to/openclaw-radio
# 2. Set your callsign
openclaw config set channels.openclaw-radio.tx.callsign "W6RGC/BOSS"
# 3. Configure your interface (DigiRig example)
openclaw config set channels.openclaw-radio.audioInput "plughw:CARD=Device"
openclaw config set channels.openclaw-radio.audioOutput "plughw:CARD=Device"
openclaw config set channels.openclaw-radio.ptt.type serial
openclaw config set channels.openclaw-radio.ptt.port /dev/ttyUSB0
openclaw config set channels.openclaw-radio.ptt.lines '["RTS"]'
# 4. Enable the channel
openclaw config set channels.openclaw-radio '{"enabled":true}'
# 5. Restart gateway
openclaw gateway restart
# 6. Verify
/radio doctor
```
---
## Interface Configuration
### DigiRig
```
audioInput: plughw:CARD=Device
audioOutput: plughw:CARD=Device
ptt.port: /dev/ttyUSB0
ptt.lines: ["RTS"]
```
### AIOC (All-In-One-Cable)
```
audioInput: plughw:CARD=AllInOneCable
audioOutput: plughw:CARD=AllInOneCable
ptt.port: /dev/ttyACM0
ptt.lines: ["DTR"]
```
> β οΈ AIOC firmware 1.00 is common in the wild. CM108 HID PTT requires upgrading to firmware 1.2.0+. Serial PTT (DTR) works on all firmware versions.
> β οΈ **Serial PTT note:** The `serialport` npm `.set()` method is broken on some Linux kernels (notably Jetson + ttyACM). openclaw-radio uses a Python daemon with `ioctl(TIOCMSET)` instead β no action required, but `python3` must be in PATH.
---
## Commands
| Command | Description |
|---|---|
| `/radio tx <text>` | Manually transmit text over the air |
| `/radio doctor` | Diagnose audio devices, serial ports, STT config, and show full radio config |
| `/radio setup` | Same as doctor, plus shows config set commands to apply |
| `/radio status` | Current state and uptime |
---
## How It Works
```
Radio β Sound Card β arecord β Carrier Sense β WAV file
β OpenClaw STT β Agent β OpenClaw TTS β aplay β Sound Card β Radio TX
β
PTT daemon (serial)
```
1. **Listen** β `arecord` streams audio. Carrier sense monitors energy levels.
2. **Record** β when sustained speech is detected (3+ consecutive frames), audio accumulates until squelch closes.
3. **Transcribe** β utterance written to temp WAV, passed to OpenClaw's STT pipeline.
4. **Think** β transcribed text + ham radio persona + signal report routed to agent.
5. **Speak** β reply goes through OpenClaw's TTS pipeline β raw PCM.
6. **Transmit** β PTT keyed, audio played via `aplay`, PTT released.
---
## Requirements
- [OpenClaw](https://github.com/openclaw/openclaw) with a configured STT provider (e.g., OpenAI Whisper API)
- Linux: `alsa-utils` (`arecord`/`aplay`)
- macOS: `sox` (`brew install sox`)
- `python3` in PATH (for serial PTT daemon)
- For serial PTT: USB-to-serial adapter
---
## Configuration Reference
All config lives under `channels.openclaw-radio` in `openclaw.json`.
| Key | Default | Description |
|---|---|---|
| `audioInput` | `plughw:0,0` | ALSA input device |
| `audioOutput` | `plughw:0,0` | ALSA output device |
| `sampleRate` | `16000` | Capture sample rate (Hz) |
| `ptt.type` | `none` | `none` / `serial` / `gpio` / `vox` |
| `ptt.port` | `/dev/ttyUSB0` | Serial port or GPIO path |
| `ptt.lines` | `["RTS"]` | Lines to assert: `["RTS"]`, `["DTR"]`, or `["RTS","DTR"]` |
| `ptt.leadMs` | `350` | Pre-audio delay after PTT key |
| `ptt.tailMs` | `120` | Post-audio delay before PTT release |
| `rx.speechThreshold` | `0.3` | RMS energy to trigger recording |
| `rx.carrierSenseThreshold` | `0.0008` | RMS floor for open squelch |
| `rx.maxSilenceMs` | `2000` | Silence before end-of-utterance |
| `rx.minSpeechFrames` | `3` | Consecutive frames required to start recording |
| `rx.minSpeechMs` | `200` | Anti-kerchunk minimum (ms) |
| `rx.cooldownMs` | `3000` | Post-RX cooldown |
| `tx.callsign` | `N0CALL/AI` | Your callsign, appended to every TX |
| `tx.policy` | `direct-only` | `direct-only` (callsign/alias required) or `proactive` |
| `tx.aliases` | `Boss,Overlord,Lord,Seven,7` | Trigger words for direct-only mode |
| `tx.maxTxMs` | `120000` | TX watchdog (ms) |
| `tx.postTxMuteMs` | `3000` | Post-TX mute window (ms) |
| `persona` | `true` | Inject ham radio personality prompt |
---
## Observability
Every exchange logged to `~/.openclaw/logs/radio-YYYY-MM-DD.log`:
```jsonl
{"summary":"RX: Boss this is W6RGC radio check","type":"RX","text":"Boss this is W6RGC radio check","rmsDb":-21.3,"peakDb":-1.2}
{"summary":"TX: W6RGC this is Boss, loud and clear. W6RGC/BOSS","type":"TX","text":"..."}
{"summary":"METRIC: sttMs=1568 dispatchMs=6148 responseTimeMs=2100","type":"METRIC","responseTimeMs":2100}
```
`responseTimeMs` is the key metric β dead air between squelch-close and PTT-key. Target: under 3 seconds.
---
## Development
```bash
git clone https://github.com/richcannings/openclaw-radio.git
cd openclaw-radio
npm install
npm test # unit tests
npm run typecheck # TypeScript strict mode
```
See [docs/DESIGN.md](docs/DESIGN.md) for architecture, [docs/PRD.md](docs/PRD.md) for requirements status, and [docs/INSIGHTS.md](docs/INSIGHTS.md) for hard-won lessons from the first on-air tests.
---
## Links
- **OpenClaw** β [github.com/openclaw/openclaw](https://github.com/openclaw/openclaw)
- **DigiRig** β [digirig.net](https://digirig.net/)
- **AIOC** β [github.com/skuep/AIOC](https://github.com/skuep/AIOC)
- **w6rgc-ai** (predecessor) β [github.com/richcannings/w6rgc-ai](https://github.com/richcannings/w6rgc-ai)
## License
Apache 2.0
---
*73 de W6RGC/BOSS* π»
voice
Comments
Sign in to leave a comment