Skip to content

PAARA-org/PAARAbot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PAARAbot

PAARAbot is a Discord bot written in GoLang (https://golang.org) using the DiscordGo library (https://github.com/bwmarrin/discordgo).

On startup, the bot reads from a list of ham callsigns (Club members, or Discord server members), and then periodically retrieves the list of active SOTA and POTA spots. If it finds any spots for the tracked callsigns, it will post a Discord message containing the Call Sign, Park or Peak, Frequency and Mode.

Install

You have two options:

  1. Get the GitHub built binaries for your platform from the releases page (https://github.com/PAARA-org/PAARAbot/releases).
  2. Clone the Git repository and build the binary yourself
    • git clone git@github.com:PAARA-org/PAARAbot.git
    • cd PAARAbot
    • ./build.sh

Usage

Sample usage:

$ ./PAARAbot \
  -hamfile=paara_members.txt \
  -csvURL="https://docs.google.com/spreadsheets/d/e/.../pub?output=csv" \
  -refreshInterval=12h \
  -sotacsv=sota_pota.csv \
  -postThrottleTime=4.5h \
  -spotCheckInterval=3m \
  -dbPath=/var/lib/paarabot/spots.db \
  -token=abc \
  -potaChannelID=xxx \
  -sotaChannelID=yyy

The paara_members.txt file or the -csvURL flag (or both) must be provided to load callsigns. The sota_pota.csv file is optional.

-token, -potaChannelID and -sotaChannelID

These three values are mandatory to allow the bot to connect to Discord and post messages.

To generate a token, you need to visit https://discord.com/developers/applications and create a new application. For more information, please check this Medium article, or search how to generate a discord bot token on <Google.com>.

The -potaChannelID and -sotaChannelID can be set to different values, or to the same value. Our Club's (<paara.org>) Discord server had initially posted them separately in either the #pota or #sota channel, but we later converged into one channel named #spots.

If you want to use a single channel, use the same channelID for both variables.

-hamfile

This flag sets the filename containing the list of interesting ham call signs.

The format of the file is very simple: one call sign per line. The parser will ignore any empty or commented lines (starting with # or //).

An example file is provided in examples/callsigns_sample.txt:

# This is a sample file containing callsigns that must match this format:
# * the commented files are ignored
# * one callsign per line
#
KN6YUH
AK6EU

-csvURL

This flag allows fetching callsigns from a remote CSV file, such as a published Google Sheet shared with anyone with the link (this is to avoid having to set up authentication). The bot expects the callsigns to be in the first column and will skip the first row (header).

If a Google Sheet URL in "edit" mode is provided, the bot will automatically attempt to convert it to an "export" URL in CSV format.

-refreshInterval

This flag determines how often the bot will re-fetch the callsigns from the -csvURL. The default is 8 hours.

-spotCheckInterval

This flag controls the interval for checking the POTA and SOTA for new spots. The default is 2 minutes, and I'd recommend not setting is to something shorter than this, to avoid getting blocked for refreshing the page too often.

-postThrottleTime

This flag controls how often the same combination of CallSign and POTA/SOTA entity will cause a new message to be posted to Discord.

It's highly recommended to not reduce this flag to less than 1 hour, as that could cause doubling the posts.

-dbPath

Path to the SQLite file used to persist the per-callsign spot cache. Defaults to paarabot.db in the current working directory. Pass an empty string (-dbPath="") to run with an in-memory cache only.

The file is created automatically on first start, so no manual setup is needed. The schema is reconciled on every start: if a future bot release adds or removes a column from the spots table, the existing file is migrated in place via ALTER TABLE rather than being recreated, so cached history is preserved across upgrades.

The store is tuned for SD-card-backed deployments (the bot runs on an old Raspberry Pi for the PAARA club): WAL journaling, synchronous=NORMAL, an in-memory temp store, and a single writer connection — the goal is to minimize write amplification and fsync calls so the SD card lasts longer.

The bot also writes two sidecar files next to the DB (*.db-wal and *.db-shm) — these are normal SQLite WAL files and should not be deleted while the bot is running.

-help

% ./PAARAbot --helpshort
flag provided but not defined: -helpshort
Usage of ./PAARAbot:
  -csvURL string
    	URL to a CSV file containing ham callsigns (e.g. Google Sheet export link).
  -dbPath string
		Path to the SQLite file used to persist the spot cache. Set to empty to disable persistence. (default "paarabot.db")
  -hamfile string
    	File containing the list of ham callsigns to check for activations.
  -postThrottleTime duration
    	How often to re-post the same spot. (default 4h0m0s)
  -potaChannelID string
    	POTA channel ID from Discord.
  -refreshInterval duration
    	How often to refresh the callsigns from the CSV URL. (default 8h0m0s)
  -sotaChannelID string
    	SOTA channel ID from Discord.
  -sotacsv string
    	CSV file containing mapping from peak to park.
  -spotCheckInterval duration
    	How often to check for new spots (default 2m0s)
  -token string
    	Discord bot token
  -version
    	Display application build information and exit.

QRT Handling

When a tracked activator's spot is marked QRT (either via the SOTA QRT type or by the substring QRT appearing in the comments of a POTA or SOTA spot), the bot posts a Discord message immediately, bypassing the -postThrottleTime rate limit so the going-off-air notice isn't held up.

Once an activation has been observed in QRT, the bot latches that status: later spots whose comments no longer say QRT will not trigger another out-of-band post. Without this latch, a real activation that has both a manual "Qrt" spot and automated Reverse Beacon Network (RBN) re-spots in flight was perceived as a constant QRT↔NORMAL flip — every poll looked like a status transition and bypassed the throttle, flooding the channel.

The normal rate limit still applies. After -postThrottleTime elapses, the next spot for that activation is allowed through the regular path with whatever QRT status its current comment dictates, so the posted message simply drops the QRT suffix once the activator stops sending it — the message stream naturally moves out of QRT without the bot having to fire a dedicated "no longer QRT" announcement.

SOTA activations in POTA parks

This is a feature requested by Gabriel AJ6X on 06/17/2025. When a SOTA activation is detected by the bot, it will check whether the peak is located in a POTA location and, if true, will post an additional message in the #pota Discord channel.

The mapping from PEAK to PARK is done by parsing this CSV: https://raw.githubusercontent.com/aj6x/sota/refs/heads/main/data/sota_pota.csv

You will need to fetch a copy of this CSV file locally and point the bot at it using the -sotacsv flag.

When a SOTA peak is mapped to a POTA park, the SOTA cache entry's location is annotated with the mapped park id — e.g. W6/NC-353 (Burdell Mountain - 1580ft, within US-3527). This keeps the SOTA spot (which the activator may have self-spotted only on SOTA) visible in the per-callsign recent-spots view while making the SOTA↔POTA relationship explicit, without trying to collapse the two sources into one entry.

User Interactions

Users can interact with the bot directly in the Discord channels configured for POTA or SOTA spots.

Retrieve Recent Spots

If you want to check the recent activity of a specific callsign (even if it's not currently active), you can mention the bot followed by the callsign.

Usage: @PAARAbot <CALLSIGN>

Example: @PAARAbot K6STR

Behavior:

  1. The bot checks its local cache for the last 10 distinct spotting events for that callsign. Re-spots of the same activation (same source, location, frequency, mode, and QRT status) are collapsed into a single entry whose timestamp is bumped to the latest observation, regardless of whether the duplicates are adjacent in time — so a steady activation that's polled every few minutes by multiple POTA spotters and SOTA spotters doesn't double the cache each cycle. A meaningful change in any of the key fields (moving to a new frequency, going QRT) creates a separate entry. Same-key spots more than an hour apart are also kept as separate runs, so an activator who comes back to the same configuration later in the day still appears as a fresh row.
  2. If the cache is empty (e.g. the bot restarted or the user hasn't been active recently), it will automatically fetch the latest spot lists from POTA and SOTA to find any recent activity. The same dedup is applied to the fresh results.
  3. It will reply with the 10 most recent entries in chronological order (newest first), including the source (POTA/SOTA), time, location, frequency, and mode.

Credits

This is a Discord bot initially based on the example provided at https://medium.com/@mssandeepkamath/building-a-simple-discord-bot-using-go-12bfca31ad5d.

About

PAARAbot is an application that tracks a list of call signs for POTA or SOTA activations and posts a message on Discord with the activation details. Originally developed by KN6YUH for the Palo Alto Amateur Radio Association Discord server.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors