A Python library for the JF8Call WebSocket API. Full asyncio coverage with typed dataclasses, a synchronous wrapper for scripts, and a complete event system. Drive a JF8Call instance — send messages, tune frequencies, read configuration, stream decoded traffic — from any Python application.
Requires Python 3.10+ and websockets 11+.
JF8Call must be running with the WebSocket API enabled (default: ws://localhost:2102).
Async (recommended)
Sync (for scripts)
Status & Configuration
get_status()
Returns a typed Status dataclass
get_config()
Returns a typed Config dataclass (superset of Status)
set_config(**kwargs)
Update any subset of config fields by name; returns updated Config
Radio (Hamlib)
get_radio()
Returns RadioStatus
connect_radio(rig_model, port, baud, ptt_type, …)
Configure and connect a Hamlib rig
disconnect_radio()
Disconnect the rig
set_frequency(khz)
Tune to frequency in kHz; triggers ATU if auto_atu is set
tune()
Issue ATU tune command (CAT only, no RF)
Transmit
send(text, submode=None)
Queue a message; returns TX queue depth
send_and_wait(text, timeout=120)
Send and block until TX completes
send_heartbeat()
Transmit a heartbeat
send_snr_query(callsign)
Query SNR from another station
get_tx_queue() / clear_tx_queue()
Inspect or clear the pending TX queue
wait_for_tx(timeout=120)
Block until a tx.finished event is received
Messages & Spectrum
get_messages(offset, limit)
Returns list[DecodedMessage]
clear_messages()
Clear the message log
get_spectrum()
Returns Spectrum with .peak_hz() and .slice(lo, hi)
Register handlers with decorators or direct calls. Handlers may be plain functions
or coroutines. The wildcard event "*" receives everything.
| Event | Convenience method | Argument type |
|---|---|---|
| message.decoded | on_message | DecodedMessage |
| message.frame | on_frame | FrameUpdate |
| status | on_status | Status |
| spectrum | on_spectrum | Spectrum |
| tx.started / tx.finished | on_tx_started / on_tx_finished | None |
| radio.connected | on_radio_connected | dict |
| config.changed | on_config_changed | dict |
message.frame fires for each incoming partial GFSK8 frame,
letting you display in-progress multi-frame messages before they complete.
Single-frame messages go directly to message.decoded.
| File | Description |
|---|---|
| 01_basic_status.py | Status, config, audio devices, recent messages |
| 02_receive_messages.py | Stream decoded messages with filters |
| 03_send_message.py | Send directed messages and wait for TX |
| 04_frame_assembly.py | Real-time multi-frame GFSK8 assembly display |
| 05_radio_control.py | Frequency changes, ATU tuning, rig connect |
| 06_config_management.py | Read/write all config fields |
| 07_spectrum_monitor.py | ASCII waterfall from live spectrum events |
| 08_sync_usage.py | All of the above using the sync wrapper |
| 09_chat.py | Interactive two-way terminal chat |
Run any example with --help for options,
and --host to point at a remote JF8Call instance.
js8net is the companion library for the original JS8Call application, using its TCP-based API. jf8net targets JF8Call and its purpose-built WebSocket API — a cleaner, fully documented protocol designed for automation from the start.
If you're running JS8Call, use js8net. If you're running JF8Call, use jf8net. The two APIs are not interchangeable, but the concepts map closely.