Python library and utilities for interacting with the JS8Call-improved API via TCP
Project description
js8call-improved
Jeff Francis gjfrancis@protonmail.com, N0GQ
⚠️ ALPHA SOFTWARE — READ BEFORE USING ⚠️
This library should be considered Alpha quality software. It has not been extensively tested against a running JS8Call-improved instance. APIs may change, functions may behave unexpectedly, and some features may not yet work correctly. Use with caution, especially in any automated or unattended scenario involving actual transmissions.
The library is also subject to change as the JS8Call-improved API itself evolves and improves. Function signatures, return values, and the set of supported commands may all shift in future releases without notice until the API stabilizes. Watch the changelog and pin to a specific version in production code.
Note: This library targets the JS8Call-improved fork. It is not compatible with the original (legacy) JS8Call software. For the original JS8Call, see js8call-legacy.
Installation
pip install js8call-improved
Or from source:
git clone https://github.com/jfrancis42/js8net-improved.git
cd js8net-improved
pip install .
In your Python code, import the library as:
from js8call_improved import *
The Library
js8call-improved is a python3 package for interacting with the JS8Call-improved API. It works exclusively in TCP mode and targets the API extensions introduced in JS8Call-improved (API v2.6+), while also supporting all commands available in the original API (v2.5).
The JS8Call-improved API is a significant improvement over the legacy API, adding remote configuration control, filter management, PTT status, queue depth queries, OS/version introspection, and much more. The underlying protocol is the same JSON-over-TCP transport used by the legacy software.
This library is closely modeled on js8call-legacy to make migration as smooth as possible. See the Differences from js8call-legacy section below for a complete list of changes.
Getting Started
To get started, import the library, then tell it to connect to your JS8Call-improved instance:
from js8call_improved import *
start_net("10.1.1.141", 2242)
Note that the default port is 2242, not 2442. This is the default API port in JS8Call-improved (configurable under Settings → Reporting → API).
At this point, three daemon threads are running: one receives messages from JS8Call-improved and updates internal state; one sends queued commands; one sends keepalive heartbeats every five minutes.
API Reference
Connection
start_net(host, port)
Connect to a JS8Call-improved instance. Default: localhost, port 2242.
Frequency Control
get_freq()
Returns {'dial': hz, 'freq': hz, 'offset': hz}.
set_freq(dial, offset)
Set dial frequency and audio offset, both in Hz.
get_ptt()
New in js8call-improved. Get current PTT state. Returns True if
transmitting, False if not.
set_tune(enabled)
New in js8call-improved. Enable (True) or disable (False) continuous
carrier tune mode for antenna tuning.
tx_halt()
New in js8call-improved. Emergency stop: immediately halt any ongoing transmission.
Station Configuration
get_callsign()
get_grid()
set_grid(grid)
get_info()
set_info(info)
These work identically to their js8call-legacy counterparts.
get_status()
set_status(status_text)
New in js8call-improved. Get or set the station status message.
get_version()
New in js8call-improved. Returns the JS8Call-improved version string.
get_os()
New in js8call-improved. Returns OS information from the running JS8Call-improved instance.
get_spot()
set_spot(enabled)
New in js8call-improved. Get or set the spot-enabled state.
get_config()
New in js8call-improved. Fetch the full station configuration as a dict.
Keys include: AUTO_REPLY, JS8HB, HBACK, MULTI_DECODER, HB_INTERVAL,
HB_TIMER_ACTIVE, MONITOR, TX_ENABLED, SPEED, CAN_HB,
AUTOREPLY_CONFIRMATION, MY_GROUPS, AVOID_ALLCALL.
set_auto_reply(enabled)
set_js8hb(enabled)
set_hback(enabled)
set_multi_decoder(enabled)
New in js8call-improved. Toggle autoreply, JS8 heartbeat networking, heartbeat acknowledgements, and simultaneous multi-decoder on or off.
set_hb_interval(minutes)
set_hb_timer(active)
send_hb()
New in js8call-improved. Control the automated heartbeat: set the interval
in minutes, start/stop the timer, or trigger an immediate API-level heartbeat.
Note: send_hb() triggers JS8Call-improved's built-in heartbeat mechanism and
is distinct from send_heartbeat(), which constructs and queues a heartbeat
message directly.
set_groups(groups)
New in js8call-improved. Replace the list of subscribed groups. Pass a
list of strings, e.g. ["@GROUPONE", "@GROUPTWO"].
set_avoid_allcall(enabled)
New in js8call-improved. Opt out of (True) or back in to (False)
@ALLCALL messages.
Activity Queries
get_call_activity()
Get the list of recently heard callsigns (right panel). Returns a list of
Callstation objects.
get_call_selected()
Return the callsign currently selected in the GUI.
get_band_activity()
Get the band activity list (left panel). Returns a list of Bandstation
objects.
get_free_offsets()
New in js8call-improved. Get available (unoccupied) frequency segments in the passband. Returns a dict with:
FREE: list of{'LOW': hz, 'HIGH': hz, 'WIDTH': hz}segmentsBANDWIDTH: signal bandwidth in Hz for the current speedSPEED: current speed modeLOW,HIGH: usable passband limits in Hz
get_filter()
set_filter(center, width)
set_filter_enabled(enabled)
New in js8call-improved. Get, set, or toggle the bandpass filter. center
and width are in Hz.
Text Buffers
get_rx_text()
get_tx_text()
set_tx_text(text)
These work identically to their js8call-legacy counterparts.
Transmission Queue
get_queue_depth()
New in js8call-improved. Returns the number of messages currently waiting in the transmit queue.
Speed Control
get_speed()
set_speed(speed)
speed_name(speed)
Speed values: 0=Normal, 1=Fast, 2=Turbo, 4=Slow, 8=Ultra.
Change from js8call-legacy: Speed 8 (Ultra/JS8-60) is newly supported.
speed_name() now returns 'Ultra' for speed 8 instead of 'Invalid'.
Window
raise_window()
Bring the JS8Call-improved window to the foreground.
Messaging
send_message(message)
send_directed_message(dest_call, message)
send_inbox_message(dest_call, message)
These work identically to their js8call-legacy counterparts.
send_heartbeat(grid=False)
Construct and queue a heartbeat message over the air. See also send_hb().
send_aprs(dest, message)
send_aprs_grid(grid)
send_sms(phone, message)
send_email(address, message)
send_sota(summit, freq, mode, comment=False)
send_pota(park, freq, mode, comment=False)
These work identically to their js8call-legacy counterparts.
query_snr(dest_call)
query_grid(dest_call)
query_status(dest_call)
query_info(dest_call)
query_hearing(dest_call)
These work identically to their js8call-legacy counterparts.
get_messages()
store_message(callsign, text)
These work identically to their js8call-legacy counterparts.
Connection Health
alive()
Returns True if a valid response was received in the last ~5.5 minutes.
Receiving Messages
Incoming messages that don't map to a query response are placed into rx_queue
(protected by rx_lock). The message types you'll typically see are:
RX.SPOT— spot messageRX.ACTIVITY— partial frame (a fragment of a larger message)RX.DIRECTED— complete reassembled directed messageRX.TEXT— received text buffer updateSTATION.CLOSING— new in js8call-improved: JS8Call-improved is shutting down; theclosingglobal is also set toTrue
Example receive loop:
while True:
if not rx_queue.empty():
with rx_lock:
message = rx_queue.get()
if message['type'] == 'RX.DIRECTED':
print(message['params']['FROM'], '->', message['params']['TO'])
print(message['value'])
elif message['type'] == 'STATION.CLOSING':
print("JS8Call-improved is shutting down.")
time.sleep(0.1)
Differences from js8call-legacy
Users migrating from js8call-legacy should note the following changes:
| Item | js8call-legacy | js8call-improved |
|---|---|---|
| Import | from js8call_legacy import * |
from js8call_improved import * |
| Default port | 2442 |
2242 |
| Speed 8 (Ultra) | Not supported; speed_name(8) returns 'Invalid' |
Supported; speed_name(8) returns 'Ultra' |
send_heartbeat() |
Sends heartbeat over the air | Same behavior; see also new send_hb() |
STATION.CLOSING |
Not handled | Sets closing=True global; queued for user processing |
get_status() / set_status() |
Not available | New functions |
get_version() / get_os() |
Not available | New functions |
get_ptt() / set_tune() / tx_halt() |
Not available | New functions |
get_spot() / set_spot() |
Not available | New functions |
get_config() |
Not available | New function; returns full config dict |
set_auto_reply() / set_js8hb() / set_hback() / set_multi_decoder() |
Not available | New functions |
set_hb_interval() / set_hb_timer() / send_hb() |
Not available | New functions |
set_groups() / set_avoid_allcall() |
Not available | New functions |
get_free_offsets() |
Not available | New function |
get_filter() / set_filter() / set_filter_enabled() |
Not available | New functions |
get_queue_depth() |
Not available | New function |
All other functions (get_callsign(), get_grid(), set_grid(), get_info(),
set_info(), get_freq(), set_freq(), get_call_activity(),
get_band_activity(), get_call_selected(), get_rx_text(), get_tx_text(),
set_tx_text(), get_speed(), set_speed(), raise_window(),
send_message(), send_directed_message(), send_inbox_message(),
send_heartbeat(), send_aprs(), send_aprs_grid(), send_sms(),
send_email(), send_sota(), send_pota(), query_snr(), query_grid(),
query_status(), query_info(), query_hearing(), get_messages(),
store_message(), alive()) are drop-in compatible with js8call-legacy.
Bundled Scripts
| Script | Description |
|---|---|
send_aprs.py |
Send an APRS message to a callsign |
send_email.py |
Send an email via a JS8 gateway |
send_sms.py |
Send an SMS via a JS8 gateway |
send_heartbeat.py |
Send a heartbeat message |
send_message.py |
Send a directed message |
send_pota.py |
Submit a POTA spot |
send_sota.py |
Submit a SOTA spot |
send_grid.py |
Send your grid square to APRS; optionally track via GPSD |
fill_grids.py |
Query stations with missing grid squares |
make_calldb.py |
Build a local callsign database (USA, Canada, Australia) |
stations.py |
Report current station activity |
example.py |
Example code showing basic library usage |
All scripts accept --js8-host and --js8-port (default localhost:2242), or
the environment variables JS8HOST and JS8PORT combined with --env. Speed
arguments now accept 8 for Ultra mode in addition to the legacy values.
For GPS tracking with send_grid.py, install the optional dependency:
pip install gpsd-py3
Credits
- The SVG icons are from Creative Commons and Font Awesome Free.
- Thanks to COAS Book in Las Cruces, NM for being awesome. https://www.coasbooks.com/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file js8call_improved-0.1.0.tar.gz.
File metadata
- Download URL: js8call_improved-0.1.0.tar.gz
- Upload date:
- Size: 21.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef1d8a71d356e17f6655db1fdb18758a282740ab55273058eb60ccd515ba2aea
|
|
| MD5 |
6d61636e57dc26ee6944bbea9b1bac25
|
|
| BLAKE2b-256 |
d74976180a607a670cc09e94f2887f74aa1c2c75659b5653b587b4ddb275f5e6
|
File details
Details for the file js8call_improved-0.1.0-py3-none-any.whl.
File metadata
- Download URL: js8call_improved-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46aa1a5e82111bf28878dcec3dc3cb7b015c27e58a1ae03b0cdef8a2f060ba19
|
|
| MD5 |
70f39f4b6c04e773946b913811857d8b
|
|
| BLAKE2b-256 |
195aab744be604a39e78ab0635e17d4ea06d03a46620fefc571db2e5c28a2c4a
|