Skip to main content

An FT8 message logger that tracks, translates, and organizes CQs, QSOs, and Misc. messages from live WSJT-X packets.

Project description

ft8decoder

Ask DeepWiki

ft8decoder is a Python-based tool for decoding, translating, and organizing FT8 digital radio communications in real-time. It listens for UDP packets broadcast by WSJT-X, parses the cryptic messages into human-readable text, sorts them into distinct conversations (QSOs), and provides options to export the captured data into structured JSON files or visualize them on a world map.

This tool is perfect for amateur radio enthusiasts who want to log, understand, and analyze FT8 communications happening on the bands.

Key Features

  • Live Packet Listening: Connects directly to the WSJT-X UDP stream to process radio traffic as it happens.
  • Message Parsing & Translation: Decodes standard FT8 messages, including CQ calls, grid squares, signal reports, and sign-offs, translating them into plain English.
  • Conversation Tracking: Intelligently groups individual transmissions into complete conversations (QSOs) from the initial CQ call to the final "73".
  • Data Exporting: Saves all captured communications, including completed QSOs, unanswered CQs, and miscellaneous messages, into a well-structured JSON file for logging or further analysis.
  • Geographic Visualization: Generates a dynamic HTML map using Folium, plotting the locations of operators (via Maidenhead grid squares) and drawing lines to represent their QSOs.

How It Works

The application is built around two core components:

  1. WsjtxParser: This class is responsible for the low-level networking. It binds to the specified UDP port that WSJT-X uses to broadcast its data. It listens for incoming packets, validates them, and unpacks the binary data into a structured Packet object containing details like SNR, frequency, time delta, and the raw message content.

  2. MessageProcessor: This class handles the logic of understanding the parsed packets. It ingests a stream of Packet objects and organizes them:

    • CQ Calls: Identifies and logs general "CQ" calls.
    • QSO Assembly: When a station responds to a CQ, a new conversation thread is started. The processor tracks each turn of the conversation, from grid square exchange to signal reports and final acknowledgments (RR73, 73).
    • Translation: Each message type is translated into a descriptive sentence (e.g., N5YHF WB7SRC R+05 becomes "WB7SRC says Roger and reports a signal report of +05 to N5YHF.").
    • Grid Square Caching: It caches the grid square of each station heard to resolve their location for mapping, even if they don't repeat it in every transmission.

Installation

Ensure you have Python 3.8+ and a running instance of WSJT-X.

  1. Install from PyPI (recommended):

    pip install ft8decoder
    

    This will install the package and its dependencies (maidenhead and folium).

  2. Install from source:

    git clone https://github.com/ZappatheHackka/ft8decoder.git
    cd ft8decoder
    pip install .
    

    For development, install Poetry and run:

    pip install poetry
    poetry install
    
  3. Configure WSJT-X: In WSJT-X, go to File > Settings > Reporting. Ensure the "UDP Server" is enabled and set to 127.0.0.1:2237, which are the defaults for this tool.

Python API Usage

You can use the core classes directly in your Python code in the following manner:

from ft8decoder import WsjtxParser, MessageProcessor
import time

# Get HOST and PORT from WSJT-X settings
HOST = '127.0.0.1'
PORT = 2237

# Initialize parser with your desired dial frequency
parser = WsjtxParser(dial_frequency=14.074000)

# Initialize processor
processor = MessageProcessor()

# Pass the HOST, PORT, and processor into the parser and begin listening
parser.start_listening(HOST, PORT, processor)

# Start the processor
processor.start()

# Sleep for however long you want to compile data for
time.sleep(180)

# Access the parsed and processed data
print("All captured packets:", processor.master_data)
processor.to_map('map1', all_cqs=True)
processor.to_json(filename="ft8_data")

CLI Usage

The application also includes an easy command-line interface. The primary command is ft8decoder listen.

Basic CLI Usage

To start listening to packets, run the following command. It will listen for 2 minutes (120 seconds) and then print the captured data.

ft8decoder listen

Command-Line Arguments

You can customize the behavior with the following arguments:

  • --host: The host IP to bind to (default: 127.0.0.1).
  • --port: The UDP port to listen on (default: 2237).
  • --dial: Your radio's dial frequency in MHz for accurate frequency calculation (default: 14.074000).
  • --interval: The interval in seconds for processing collected packets (default: 5).
  • --duration: Total listening duration in seconds before the program exits and exports data (default: 120).
  • --export-all <filename>: Export all captured data (QSOs, CQs, Misc.) to a specified JSON file.
  • --export-comms <filename>: Export only conversation data to a JSON file.
  • --export-cqs <filename>: Export only unanswered CQ calls to a JSON file.
  • --export-misc <filename>: Export only miscellaneous messages.
  • --to-map <filename>: Generate an interactive HTML map visualizing the QSOs and CQs.

Example

Listen for 5 minutes, export all data to my_log.json, and create a map named activity_map.html:

ft8decoder listen --duration 300 --export-all my_log.json --to-map activity_map

After running, you will find my_log.json and activity_map.html in your directory.

Sample Output

JSON Data

      "('KF5WCP', 'KT4KB')": [
        {
          "completed": true
        },
        {
          "turn": 1,
          "message": "CQ KT4KB EM94",
          "translated_message": "Station KT4KB is calling for any response from grid EM94.",
          "packet": {
            "snr": 1,
            "delta_time": 0.5,
            "frequency_offset": 831,
            "frequency": 14.074831,
            "band": "20m",
            "message": "CQ KT4KB EM94",
            "schema": 2,
            "program": "WSJT-X",
            "time_captured": "2025-08-08 10:17:56.951461",
            "packet_type": 2
          },
          "type": "CQ Call."
        },
        {
          "turn": 2,
          "message": "KT4KB KF5WCP EM25",
          "translated_message": "KF5WCP sends a grid square location of EM25 to KT4KB.",
          "packet": {
            "snr": -5,
            "delta_time": 0.30000001192092896,
            "frequency_offset": 710,
            "frequency": 14.07471,
            "band": "20m",
            "message": "KT4KB KF5WCP EM25",
            "schema": 2,
            "program": "WSJT-X",
            "time_captured": "2025-08-08 10:18:11.935844",
            "packet_type": 2
          },
          "type": "Grid Square Report"
        },
        {
          "turn": 3,
          "message": "KF5WCP KT4KB -16",
          "translated_message": "KT4KB sends a signal report of -16 to KF5WCP.",
          "packet": {
            "snr": 8,
            "delta_time": 0.5,
            "frequency_offset": 830,
            "frequency": 14.07483,
            "band": "20m",
            "message": "KF5WCP KT4KB -16",
            "schema": 2,
            "program": "WSJT-X",
            "time_captured": "2025-08-08 10:18:26.962332",
            "packet_type": 2
          },
          "type": "Signal Report"
        },
        {
          "turn": 4,
          "message": "KT4KB KF5WCP R-19",
          "translated_message": "KF5WCP says Roger and reports a signal report of -19 to KT4KB.",
          "packet": {
            "snr": 1,
            "delta_time": 0.30000001192092896,
            "frequency_offset": 710,
            "frequency": 14.07471,
            "band": "20m",
            "message": "KT4KB KF5WCP R-19",
            "schema": 2,
            "program": "WSJT-X",
            "time_captured": "2025-08-08 10:18:41.909084",
            "packet_type": 2
          },
          "type": "Signal Report"
        },
        {
          "turn": 5,
          "message": "KF5WCP KT4KB RR73",
          "translated_message": "KT4KB sends a Roger Roger to KF5WCP and says goodbye, concluding the connection.",
          "packet": {
            "snr": 3,
            "delta_time": 0.5,
            "frequency_offset": 831,
            "frequency": 14.074831,
            "band": "20m",
            "message": "KF5WCP KT4KB RR73",
            "schema": 2,
            "program": "WSJT-X",
            "time_captured": "2025-08-08 10:18:56.898584",
            "packet_type": 2
          },
          "type": "RR & Goodbye"
        },
        {
          "turn": 6,
          "message": "KT4KB KF5WCP 73",
          "translated_message": "KF5WCP sends their well wishes to KT4KB, concluding the connection.",
          "packet": {
            "snr": 6,
            "delta_time": 0.30000001192092896,
            "frequency_offset": 711,
            "frequency": 14.074711,
            "band": "20m",
            "message": "KT4KB KF5WCP 73",
            "schema": 2,
            "program": "WSJT-X",
            "time_captured": "2025-08-08 10:19:11.914567",
            "packet_type": 2
          },
          "type": "Goodbye"
        }
      ],

Full JSON file HERE

Folium Map

Sample QSO Map Data

Sample CQ Map Data

Project Structure

  • ft8decoder/: The main source code package.
    • cli.py: Defines the command-line interface using argparse.
    • parser.py: Contains the WsjtxParser for handling UDP packets.
    • processor.py: Contains the MessageProcessor for logic, translation, and data organization.
    • core.py: Core dataclasses for Packet, MessageTurn, and CQ.
  • tests/: Unit tests for the parser and processor logic.
  • setup.py: Package setup and dependency information.
  • all_comms.json: An example JSON output file containing captured data.
  • map.html: An example map generated by the tool.

Documentation

For the fully comprehensive documentation, click HERE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ft8decoder-1.0.0.tar.gz (23.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ft8decoder-1.0.0-py3-none-any.whl (23.5 kB view details)

Uploaded Python 3

File details

Details for the file ft8decoder-1.0.0.tar.gz.

File metadata

  • Download URL: ft8decoder-1.0.0.tar.gz
  • Upload date:
  • Size: 23.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.6

File hashes

Hashes for ft8decoder-1.0.0.tar.gz
Algorithm Hash digest
SHA256 2d19bd4b6e00e7923ca39829cabaef49ab72aaea90ceb43e96651f528f50c03d
MD5 119608e34ba0c39848b1fd92e63d2d8a
BLAKE2b-256 5e70f3cdff8b355b38c495e18db4b88cd3f7713e044b19fe0da6fbac5fc282da

See more details on using hashes here.

File details

Details for the file ft8decoder-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: ft8decoder-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 23.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.6

File hashes

Hashes for ft8decoder-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8de4288146f1f063121b9b55359c0db083e5576daffb8e9efc9131331b6129d0
MD5 567bcdaf87e5a86dbdfcacc637ae47f3
BLAKE2b-256 f77cec13fc3a3a06ed5dbb1aacd34ef4954a52354f7ab97670ad0354ea859bfc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page