Skip to main content

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} segments
  • BANDWIDTH: signal bandwidth in Hz for the current speed
  • SPEED: current speed mode
  • LOW, 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 message
  • RX.ACTIVITY — partial frame (a fragment of a larger message)
  • RX.DIRECTED — complete reassembled directed message
  • RX.TEXT — received text buffer update
  • STATION.CLOSING — new in js8call-improved: JS8Call-improved is shutting down; the closing global is also set to True

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/

Metadata

Release files for js8call-improved 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for js8call-improved 0.1.0
File Size Uploaded Provenance Actions
js8call_improved-0.1.0.tar.gz 21.5 kB Without provenance Details for js8call_improved-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for js8call-improved 0.1.0
File Interpreter ABI Platform Actions
js8call_improved-0.1.0-py3-none-any.whl Python 3 none any Details for js8call_improved-0.1.0-py3-none-any.whl

Total release size: 51.8 kB

Release files / js8call_improved-0.1.0.tar.gz

Download URL js8call_improved-0.1.0.tar.gz
Size 21.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ef1d8a71d356e17f6655db1fdb18758a282740ab55273058eb60ccd515ba2aea
BLAKE2b-256 checksum
How to use checksums
d74976180a607a670cc09e94f2887f74aa1c2c75659b5653b587b4ddb275f5e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release files / js8call_improved-0.1.0-py3-none-any.whl

Download URL js8call_improved-0.1.0-py3-none-any.whl
Size 30.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
46aa1a5e82111bf28878dcec3dc3cb7b015c27e58a1ae03b0cdef8a2f060ba19
BLAKE2b-256 checksum
How to use checksums
195aab744be604a39e78ab0635e17d4ea06d03a46620fefc571db2e5c28a2c4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Security for js8call-improved 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page