Skip to content

richcannings/ft8bot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ft8bot

Autonomous FT8 amateur radio contact bot. Interfaces with WSJTX via its UDP API to make contacts without operator intervention — search and pounce, call CQ, or let the bot decide.

Status: Active development. Core S&P and CQ calling work. Band switching and AI integration coming next.

How It Works

ft8bot connects to a running WSJTX instance over UDP. It monitors decoded FT8 signals, selects stations to work, and lets WSJTX handle the full QSO exchange via its auto-sequencer. The bot reads your callsign and grid locator directly from WSJTX — no duplicate configuration needed.

FT8 Bot  <--UDP-->  WSJTX  <--CAT/Audio-->  Radio

Prerequisites

  • WSJTX 3.0+ installed and configured with your radio
  • Python 3.9+
  • A valid amateur radio license
  • WSJTX must have "Accept UDP requests" enabled (Settings > Reporting)

Setup

git clone https://github.com/richcannings/ft8bot.git
cd ft8bot
python3 -m venv venv
source venv/bin/activate
pip install -e .

Quick Start

Make sure WSJTX is running and decoding. Then:

# Monitor mode — watch decodes, no transmitting
python -m ft8bot

# Bot mode — fully autonomous, strategy chosen automatically
python -m ft8bot --bot

The bot reads your callsign and grid from WSJTX automatically.

Usage

python -m ft8bot [CALL] [options]

Options

Option Default Description
CALL (from WSJTX) Your callsign. Optional — read from WSJTX if omitted.
--grid GRID (from WSJTX) Your Maidenhead grid locator. Optional — read from WSJTX if omitted.
--bot off Enable bot mode (autonomous operation). Without this flag, the bot only monitors.
--strategy {both,sp,cq} both Operating strategy (see below).
--min-snr N -20 Minimum SNR (dB) to attempt a contact. Stations weaker than this are ignored.
--max-retries N 5 Max TX attempts per QSO step before giving up.
--cq-threshold N 3 In both mode: switch to CQ when fewer than N answerable CQs per cycle.
--cq-max-cycles N 10 In both mode: switch back to S&P after N CQ cycles with no response.
--import-adif PATH Import an existing ADIF log for duplicate checking.
--dupe-check MODE callsign+band Duplicate check: callsign, callsign+band, or callsign+band+mode.
--host ADDR 127.0.0.1 WSJTX UDP address.
--port PORT 2237 WSJTX UDP port.
--debug off Enable debug logging.

Strategies

Strategy Description
both Use both S&P and CQ. Start in search & pounce, switch to CQ when the band is quiet, switch back when CQ gets no responses. Best for unattended operation.
sp Search & pounce only. Answer other stations' CQs, never call CQ yourself.
cq CQ only. Call CQ and work anyone who responds, never answer other stations' CQs. The bot picks the best TX frequency slot automatically.

Examples

Just watch what's on the air

python -m ft8bot

Monitor mode. Prints every FT8 decode with SNR, frequency offset, and message. No transmitting. Good for checking band conditions.

Fully autonomous — let the bot decide everything

python -m ft8bot --bot

Both strategy (default). Answers CQs when available, calls CQ when the band is quiet, switches between them based on activity. Reads callsign and grid from WSJTX.

Search and pounce only

python -m ft8bot --bot --strategy sp

Only answers other stations' CQs. Never calls CQ. Good for busy bands where there are plenty of stations to work.

Call CQ only

python -m ft8bot --bot --strategy cq

Calls CQ and works anyone who responds. The bot automatically picks the best TX frequency offset (least-occupied 50 Hz slot in 300-2700 Hz range).

Picky — only work strong signals

python -m ft8bot --bot --min-snr -10

Ignores anything weaker than -10 dB. Higher completion rate, fewer wasted TX cycles.

Import your existing log to avoid duplicates

python -m ft8bot --bot --import-adif ~/logs/my_logbook.adi

Loads your existing ADIF log at startup. The bot won't call anyone you've already worked on the same band.

Quick retries for contest conditions

python -m ft8bot --bot --max-retries 3

Give up after 3 TX attempts instead of the default 5. Moves on faster when stations don't respond.

Full debug output

python -m ft8bot --bot --debug

Shows all state machine transitions, heartbeats, strategy switches, and protocol messages. Useful for troubleshooting.

The everything command

python -m ft8bot --bot --strategy both --min-snr -15 --max-retries 5 --import-adif ~/logs/wsjtx_log.adi --dupe-check callsign+band --debug

What the Bot Does

Search & Pounce (S&P)

  1. Watches each 15-second FT8 decode cycle for CQ calls
  2. Filters out duplicates (already worked on this band) and weak signals (below min SNR)
  3. Picks the strongest remaining station
  4. Sends a Reply to WSJTX, which starts the auto-sequencer
  5. WSJTX handles the full exchange (grid, report, R+report, RR73) autonomously
  6. Logs the completed QSO to SQLite and ADIF on QSOLogged

Calling CQ

  1. Analyzes recent decode audio offsets to find the least-occupied frequency slot
  2. Configures WSJTX TX offset and clears the DX Call field
  3. User enables TX in WSJTX (one-time) — WSJTX handles CQ and all exchanges
  4. After each QSO, WSJTX automatically returns to calling CQ

Smart Behaviors

  • Lost detection: If the station you're calling responds to someone else, the bot immediately moves on
  • Stuck exchange detection: If a station keeps repeating their report (not hearing your R+report), the TX counter still climbs and the bot will time out
  • Callsign sync: Reads your callsign and grid from WSJTX at runtime — always in sync, no configuration drift
  • HaltTx on failure: When a QSO times out, the bot immediately halts TX so WSJTX stops transmitting

WSJTX Setup

  1. Settings > Reporting: Enable UDP server (default port 2237)
  2. Settings > Reporting: Check "Accept UDP requests" (required for the bot to control WSJTX)
  3. File > Configurations: Create named profiles for each band (e.g., "FT8-20m" at 14.074 MHz) — needed for future band switching
  4. Recommended: enable auto-logging so completed QSOs are logged without clicking OK

Project Structure

src/ft8bot/
├── main.py                  # Entry point, bot orchestrator
├── protocol/                # WSJTX UDP protocol layer
│   ├── messages.py          # Message dataclasses (16 types)
│   ├── decoder.py           # Binary -> Python
│   ├── encoder.py           # Python -> binary
│   └── wsjtx.py             # Async UDP client
├── ft8/                     # FT8 logic
│   ├── decode.py            # Message text parser
│   ├── qso.py               # QSO state machine
│   ├── frequency.py         # TX offset analysis (best-slot)
│   └── strategy.py          # S&P / CQ / both mode switching
├── log/                     # Contact logging
│   └── contact_log.py       # SQLite + ADIF
├── selector/                # Contact selection (future)
├── bands/                   # Band management (future)
└── ui/                      # Terminal dashboard (future)

Tests

source venv/bin/activate
python -m pytest tests/ -v

111 tests covering the protocol layer, FT8 parser, QSO tracker, TX offset analysis, and strategy manager.

Documentation

Roadmap

  • WSJTX UDP protocol (all 16 message types)
  • FT8 message parser
  • QSO state machine (S&P + CQ caller exchanges)
  • Contact log with ADIF import/export and duplicate detection
  • Search & pounce (automatic CQ answering)
  • CQ calling with best-slot TX offset selection
  • Strategy manager (auto-switch between S&P and CQ)
  • Band switching via WSJTX configurations
  • Online propagation data (NOAA, PSKReporter)
  • Goal system (DX, WAS, VUCC, grids)
  • AI-assisted contact selection (Ollama / Anthropic)
  • Desktop GUI (PySide6, cross-platform)

License

Apache 2.0

Disclaimer

The operator is legally responsible for all transmissions made by their station, including those initiated by this software. Ensure you hold a valid amateur radio license and comply with all applicable regulations.

About

Autonomous FT8 contact bot using WSJTX

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages