General-purpose Python library for controlling ka9q-radio
Control radiod channels for any application: AM/FM/SSB radio, WSPR monitoring, SuperDARN radar, CODAR oceanography, HF fax, satellite downlinks, and more.
Note: Package name is ka9q-python out of respect for KA9Q (Phil Karn's callsign). Import as import ka9q.
✅ Zero assumptions - Works for any SDR application
✅ Complete API - All 85+ radiod parameters exposed
✅ Channel control - Create, configure, discover channels
✅ RTP recording - Generic recorder with timing support and state machine
✅ Precise timing - GPS_TIME/RTP_TIMESNAP for accurate timestamps
✅ Multi-homed support - Works on systems with multiple network interfaces
✅ Pure Python - No compiled dependencies
✅ Well tested - Comprehensive test coverage
✅ Documented - Comprehensive examples and API reference included
pip install ka9q-pythonOr install from source:
git clone https://github.com/mijahauan/ka9q-python.git
cd ka9q-python
pip install -e .Host selection: All examples reference
bee1-hf-status.local, which is the default integration test radiod in this repo. Replace it with your own radiod host or setRADIOD_HOST,RADIOD_ADDRESS, or the--radiod-hostpytest option when running in other environments.
from ka9q import RadiodControl
# Connect to radiod (default test host: bee1-hf-status.local)
control = RadiodControl("bee1-hf-status.local")
# Create AM channel on 10 MHz WWV
control.create_channel(
ssrc=10000000,
frequency_hz=10.0e6,
preset="am",
sample_rate=12000
)
# RTP stream now available with SSRC 10000000
### Request Specific Output Encoding
```python
from ka9q import RadiodControl, Encoding
control = RadiodControl("bee1-hf-status.local")
# Create a channel with 32-bit float output (highest quality)
control.ensure_channel(
frequency_hz=14.074e6,
preset="usb",
sample_rate=12000,
encoding=Encoding.F32
)
### Monitor WSPR Bands
```python
from ka9q import RadiodControl
control = RadiodControl("bee1-hf-status.local")
wspr_bands = [
(1.8366e6, "160m"),
(3.5686e6, "80m"),
(7.0386e6, "40m"),
(10.1387e6, "30m"),
(14.0956e6, "20m"),
]
for freq, band in wspr_bands:
control.create_channel(
ssrc=int(freq),
frequency_hz=freq,
preset="usb",
sample_rate=12000
)
print(f"{band} WSPR channel created")
from ka9q import discover_channels
channels = discover_channels("bee1-hf-status.local")
for ssrc, info in channels.items():
print(f"{ssrc}: {info.frequency/1e6:.3f} MHz, {info.preset}, {info.sample_rate} Hz")from ka9q import discover_channels, RTPRecorder
import time
# Get channel with timing info
channels = discover_channels("bee1-hf-status.local")
channel = channels[14074000]
# Define packet handler
def handle_packet(header, payload, wallclock):
print(f"Packet at {wallclock}: {len(payload)} bytes")
# Create and start recorder
recorder = RTPRecorder(channel=channel, on_packet=handle_packet)
recorder.start()
recorder.start_recording()
time.sleep(60) # Record for 60 seconds
recorder.stop_recording()
recorder.stop()For systems with multiple network interfaces, specify which interface to use:
from ka9q import RadiodControl, discover_channels
# Specify your interface IP address
my_interface = "192.168.1.100"
# Create control with specific interface
control = RadiodControl("bee1-hf-status.local", interface=my_interface)
# Discovery on specific interface
channels = discover_channels("bee1-hf-status.local", interface=my_interface)ensure your channels survive radiod restarts:
from ka9q import RadiodControl, ChannelMonitor
control = RadiodControl("bee1-hf-status.local")
monitor = ChannelMonitor(control)
monitor.start()
# This channel will be automatically re-created if it disappears
monitor.monitor_channel(
frequency_hz=14.074e6,
preset="usb",
sample_rate=12000
)
### Channel Cleanup (frequency = 0)
`radiod` removes channels by polling for streams whose frequency is set to `0 Hz`. Always call `remove_channel(ssrc)` (or explicitly set `set_frequency(ssrc, 0.0)` if you build TLVs yourself) when tearing down a stream so the background poller can reclaim it:
```python
with RadiodControl("bee1-hf-status.local") as control:
info = control.ensure_channel(
frequency_hz=10e6,
preset="iq",
sample_rate=16000
)
# ... use channel ...
control.remove_channel(info.ssrc) # marks frequency=0Note:
remove_channel()finishes instantly on the client; radiod’s poller typically purges the channel within the next second.
For detailed information, please refer to the documentation in the docs/ directory:
- API Reference: Full details on all classes, methods, and functions.
- RTP Timing Support: Guide to RTP timing and synchronization.
- Architecture: Overview of the library's design and structure.
- Installation Guide: Detailed installation instructions.
- Testing Guide: Information on how to run the test suite.
- Security Considerations: Important security information regarding the ka9q-radio protocol.
- Changelog: A log of all changes for each version.
- Release Notes: Release-specific notes and instructions.
See the examples/ directory for complete applications:
- High-Level API:
ensure_channel()handles the complexity of checking existing channels, creating new ones only when necessary, and verifying configurations. - Destination-Aware Channels: Support for unique per-application multicast destinations and deterministic IP generation.
- Stream Sharing: Deterministic SSRC allocation allows multiple independent applications to share
radiodstreams efficiently. discover_example.py- Channel discovery methods (native Python and control utility)tune.py- Interactive channel tuning utility (Python implementation of ka9q-radio's tune)tune_example.py- Programmatic examples of using the tune() methodrtp_recorder_example.py- Complete RTP recorder with timing and state machinetest_timing_fields.py- Verify GPS_TIME/RTP_TIMESNAP timing fieldssimple_am_radio.py- Minimal AM broadcast listenersuperdarn_recorder.py- Ionospheric radar monitoringcodar_oceanography.py- Ocean current radarhf_band_scanner.py- Dynamic frequency scannerwspr_monitor.py- Weak signal propagation reporter
- Broadcast monitoring
- Ham radio operation
- Shortwave listening
- WSPR propagation studies
- SuperDARN ionospheric radar
- CODAR ocean current mapping
- Meteor scatter
- EME (moonbounce)
- FT8/FT4 monitoring
- RTTY/PSK decoding
- DRM digital radio
- HF fax reception
- Downlink reception
- Doppler tracking
- Multi-frequency monitoring
No assumptions! Use for anything SDR-related.
This project is licensed under the MIT License - see the LICENSE file for details.