1
0
mirror of https://github.com/craigerl/aprsd.git synced 2026-01-05 07:48:41 -05:00

Reworked README and documentation

This commit is contained in:
Walter Boring 2025-12-10 14:57:12 -05:00
parent 23ad059707
commit 5ece2a10ef
19 changed files with 4021 additions and 831 deletions

1571
ChangeLog.rst Normal file

File diff suppressed because it is too large Load Diff

View File

@ -36,14 +36,10 @@
17. [Development](#development)
18. [Release](#release)
19. [Building your own APRSD plugins](#building-your-own-aprsd-plugins)
20. [Overview](#overview)
21. [Docker Container](#docker-container)
22. [Building](#building)
23. [Official Build](#official-build)
24. [Development Build](#development-build)
25. [Running the container](#running-the-container)
26. [Activity](#activity)
27. [Star History](#star-history)
20. [Docker Container](#docker-container)
21. [Running the container](#running-the-container)
22. [Activity](#activity)
23. [Star History](#star-history)
---
@ -392,53 +388,11 @@ To do release to pypi:
#### Building your own APRSD plugins
APRSD plugins are the mechanism by which APRSD can respond to APRS
Messages. The plugins are loaded at server startup and can also be
loaded at listen startup. When a packet is received by APRSD, it is
passed to each of the plugins in the order they were registered in the
config file. The plugins can then decide what to do with the packet.
When a plugin is called, it is passed a APRSD Packet object. The plugin
can then do something with the packet and return a reply message if
desired. If a plugin does not want to reply to the packet, it can just
return None. When a plugin does return a reply message, APRSD will send
the reply message to the appropriate destination.
For example, when a \'ping\' message is received, the PingPlugin will
return a reply message of \'pong\'. When APRSD receives the \'pong\'
message, it will be sent back to the original caller of the ping
message.
APRSD plugins are simply python packages that can be installed from
pypi.org. They are installed into the aprsd virtualenv and can be
imported by APRSD at runtime. The plugins are registered in the config
file and loaded at startup of the aprsd server command or the aprsd
listen command.
#### Overview
You can build your own plugins by following the instructions in the
[Building your own APRSD plugins](#building-your-own-aprsd-plugins)
section.
Plugins are called by APRSD when packe
For information on building your own APRSD plugins, see the [Plugin Development documentation](https://aprsd.readthedocs.io/en/latest/plugin.html).
### Docker Container
### Building
There are 2 versions of the container Dockerfile that can be used. The
main Dockerfile, which is for building the official release container
based off of the uv/pip install version of aprsd and the Dockerfile-dev,
which is used for building a container based off of a git branch of the
repo.
### Official Build
`docker build -t hemna6969/aprsd:latest .`
### Development Build
`docker build -t hemna6969/aprsd:latest -f Dockerfile-dev .`
For information on building Docker containers (official and development builds), see the [Docker Container documentation](https://aprsd.readthedocs.io/en/latest/readme.html#docker-container).
### Running the container

View File

@ -180,20 +180,19 @@ def load_entry_points(group):
def calculate_initial_compass_bearing(point_a, point_b):
"""
Calculates the bearing between two points.
The formulae used is the following:
"""Calculates the bearing between two points.
The formulae used is the following::
θ = atan2(sin(Δlong).cos(lat2),
cos(lat1).sin(lat2) sin(lat1).cos(lat2).cos(Δlong))
:Parameters:
- `pointA: The tuple representing the latitude/longitude for the
:param point_a: The tuple representing the latitude/longitude for the
first point. Latitude and longitude must be in decimal degrees
- `pointB: The tuple representing the latitude/longitude for the
:param point_b: The tuple representing the latitude/longitude for the
second point. Latitude and longitude must be in decimal degrees
:Returns:
The bearing in degrees
:Returns Type:
float
:returns: The bearing in degrees
:rtype: float
"""
if (type(point_a) != tuple) or (type(point_b) != tuple): # noqa: E721
raise TypeError('Only tuples are supported as arguments')

View File

@ -136,7 +136,8 @@ def no_trace(f):
Use this decorator on methods that should not be wrapped with trace_method
by the TraceWrapperMetaclass.
Example:
Example::
class MyClass(metaclass=TraceWrapperMetaclass):
def traced_method(self):
pass # This will be wrapped

View File

@ -0,0 +1,21 @@
aprsd.client.drivers.lib package
================================
Submodules
----------
aprsd.client.drivers.lib.aprslib module
---------------------------------------
.. automodule:: aprsd.client.drivers.lib.aprslib
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: aprsd.client.drivers.lib
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,6 +1,14 @@
aprsd.client.drivers package
============================
Subpackages
-----------
.. toctree::
:maxdepth: 4
aprsd.client.drivers.lib
Submodules
----------
@ -20,10 +28,34 @@ aprsd.client.drivers.fake module
:undoc-members:
:show-inheritance:
aprsd.client.drivers.kiss module
--------------------------------
aprsd.client.drivers.kiss\_common module
----------------------------------------
.. automodule:: aprsd.client.drivers.kiss
.. automodule:: aprsd.client.drivers.kiss_common
:members:
:undoc-members:
:show-inheritance:
aprsd.client.drivers.registry module
------------------------------------
.. automodule:: aprsd.client.drivers.registry
:members:
:undoc-members:
:show-inheritance:
aprsd.client.drivers.serialkiss module
--------------------------------------
.. automodule:: aprsd.client.drivers.serialkiss
:members:
:undoc-members:
:show-inheritance:
aprsd.client.drivers.tcpkiss module
-----------------------------------
.. automodule:: aprsd.client.drivers.tcpkiss
:members:
:undoc-members:
:show-inheritance:

View File

@ -12,42 +12,10 @@ Subpackages
Submodules
----------
aprsd.client.aprsis module
aprsd.client.client module
--------------------------
.. automodule:: aprsd.client.aprsis
:members:
:undoc-members:
:show-inheritance:
aprsd.client.base module
------------------------
.. automodule:: aprsd.client.base
:members:
:undoc-members:
:show-inheritance:
aprsd.client.factory module
---------------------------
.. automodule:: aprsd.client.factory
:members:
:undoc-members:
:show-inheritance:
aprsd.client.fake module
------------------------
.. automodule:: aprsd.client.fake
:members:
:undoc-members:
:show-inheritance:
aprsd.client.kiss module
------------------------
.. automodule:: aprsd.client.kiss
.. automodule:: aprsd.client.client
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,29 @@
aprsd.packets.filters package
=============================
Submodules
----------
aprsd.packets.filters.dupe\_filter module
-----------------------------------------
.. automodule:: aprsd.packets.filters.dupe_filter
:members:
:undoc-members:
:show-inheritance:
aprsd.packets.filters.packet\_type module
-----------------------------------------
.. automodule:: aprsd.packets.filters.packet_type
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: aprsd.packets.filters
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,6 +1,14 @@
aprsd.packets package
=====================
Subpackages
-----------
.. toctree::
:maxdepth: 4
aprsd.packets.filters
Submodules
----------
@ -20,6 +28,14 @@ aprsd.packets.core module
:undoc-members:
:show-inheritance:
aprsd.packets.filter module
---------------------------
.. automodule:: aprsd.packets.filter
:members:
:undoc-members:
:show-inheritance:
aprsd.packets.log module
------------------------

View File

@ -36,6 +36,14 @@ aprsd.threads.rx module
:undoc-members:
:show-inheritance:
aprsd.threads.service module
----------------------------
.. automodule:: aprsd.threads.service
:members:
:undoc-members:
:show-inheritance:
aprsd.threads.stats module
--------------------------

View File

@ -44,6 +44,14 @@ aprsd.utils.objectstore module
:undoc-members:
:show-inheritance:
aprsd.utils.package module
--------------------------
.. automodule:: aprsd.utils.package
:members:
:undoc-members:
:show-inheritance:
aprsd.utils.ring\_buffer module
-------------------------------

346
docs/builtin_plugins.rst Normal file
View File

@ -0,0 +1,346 @@
Built-in APRSD Plugins
======================
APRSD comes with several built-in plugins that provide various functionality out of the box.
These plugins are automatically available when you install APRSD and can be enabled or disabled
through the configuration file.
Message Command Plugins
------------------------
These plugins respond to APRS messages sent to your APRSD callsign.
PingPlugin
~~~~~~~~~~
**Command:** ``ping``, ``p``, or ``p `` (p followed by space)
**Description:** Responds with "Pong!" and the current time.
**Usage:** Send a message containing "ping" to your APRSD callsign.
**Example:**
::
You: ping
APRSD: Pong! 14:30:05
**Configuration:** No configuration required.
**Plugin Path:** ``aprsd.plugins.ping.PingPlugin``
FortunePlugin
~~~~~~~~~~~~~
**Command:** ``fortune``, ``f``, or ``f `` (f followed by space)
**Description:** Returns a random fortune cookie message using the system's ``fortune`` command.
**Usage:** Send a message containing "fortune" to your APRSD callsign.
**Requirements:** Requires the ``fortune`` command to be installed on the system. The plugin
will automatically search common installation paths and disable itself if not found.
**Example:**
::
You: fortune
APRSD: A journey of a thousand miles begins with a single step.
**Configuration:** No configuration required.
**Plugin Path:** ``aprsd.plugins.fortune.FortunePlugin``
TimePlugin
~~~~~~~~~~
**Command:** ``time``, ``t``, or ``t `` (t followed by space)
**Description:** Returns the current local time of the APRSD server in a human-readable format
with timezone information.
**Usage:** Send a message containing "time" to your APRSD callsign.
**Example:**
::
You: time
APRSD: half past two (14:30 PDT)
**Configuration:** No configuration required. Uses the system's local timezone.
**Plugin Path:** ``aprsd.plugins.time.TimePlugin``
TimeOWMPlugin
~~~~~~~~~~~~~
**Command:** ``time``, ``t``, or ``t `` (t followed by space)
**Description:** Returns the current time based on the GPS beacon location of the calling
callsign (or optionally a specified callsign). Uses OpenWeatherMap API to determine the
timezone for the location.
**Usage:**
::
You: time
APRSD: quarter to three (14:45 EST)
You: time WB4BOR
APRSD: half past two (14:30 PDT)
**Requirements:**
- Requires an ``aprs_fi.apiKey`` configuration option
- Requires an ``owm_weather_plugin.apiKey`` configuration option
**Configuration:**
- ``aprs_fi.apiKey`` - API key from aprs.fi account
- ``owm_weather_plugin.apiKey`` - OpenWeatherMap API key
**Plugin Path:** ``aprsd.plugins.time.TimeOWMPlugin``
VersionPlugin
~~~~~~~~~~~~~
**Command:** ``version``, ``v``, or ``v `` (v followed by space)
**Description:** Returns the APRSD version number and server uptime.
**Usage:** Send a message containing "version" to your APRSD callsign.
**Example:**
::
You: version
APRSD: APRSD ver:4.2.4 uptime:2 days, 5:30:15
**Configuration:** No configuration required.
**Plugin Path:** ``aprsd.plugins.version.VersionPlugin``
USWeatherPlugin
~~~~~~~~~~~~~~~
**Command:** ``weather``, ``w``, or ``W`` (w or W at start of message)
**Description:** Provides weather information for locations within the United States only.
Uses the forecast.weather.gov API to fetch weather data based on the GPS beacon location
of the calling callsign (or optionally a specified callsign).
**Usage:**
::
You: weather
APRSD: 72F(68F/75F) Partly cloudy. Tonight, Clear.
You: weather WB4BOR
APRSD: 65F(60F/70F) Sunny. Tonight, Partly cloudy.
**Requirements:** Requires an ``aprs_fi.apiKey`` configuration option.
**Configuration:**
- ``aprs_fi.apiKey`` - API key from aprs.fi account
**Note:** This plugin does not require an API key for the weather service itself, only
for aprs.fi to get the GPS location.
**Plugin Path:** ``aprsd.plugins.weather.USWeatherPlugin``
USMetarPlugin
~~~~~~~~~~~~~
**Command:** ``metar``, ``m``, ``M``, or ``m `` (m or M at start of message)
**Description:** Provides METAR (Meteorological Aerodrome Report) weather reports for
stations within the United States only. Uses the forecast.weather.gov API.
**Usage:**
::
You: metar
APRSD: KORD 101451Z 28010KT 10SM FEW250 22/12 A3001
You: metar KORD
APRSD: KORD 101451Z 28010KT 10SM FEW250 22/12 A3001
**Requirements:** Requires an ``aprs_fi.apiKey`` configuration option (when querying
by callsign location).
**Configuration:**
- ``aprs_fi.apiKey`` - API key from aprs.fi account
**Note:** When specifying a station identifier directly (e.g., "metar KORD"), the
aprs.fi API key is not required.
**Plugin Path:** ``aprsd.plugins.weather.USMetarPlugin``
OWMWeatherPlugin
~~~~~~~~~~~~~~~~
**Command:** ``weather``, ``w``, or ``W`` (w or W at start of message)
**Description:** Provides weather information using the OpenWeatherMap API. Works worldwide
and provides current weather conditions including temperature, dew point, wind speed and
direction, and humidity.
**Usage:**
::
You: weather
APRSD: clear sky 72.1F/65.2F Wind 5@270 45%
You: weather WB4BOR
APRSD: partly cloudy 68.5F/62.1F Wind 8@180G12 52%
**Requirements:**
- Requires an ``aprs_fi.apiKey`` configuration option
- Requires an ``owm_weather_plugin.apiKey`` configuration option
**Configuration:**
- ``aprs_fi.apiKey`` - API key from aprs.fi account
- ``owm_weather_plugin.apiKey`` - OpenWeatherMap API key (get one at https://home.openweathermap.org/api_keys)
- ``units`` - Set to "imperial" or "metric" (default: "imperial")
**Plugin Path:** ``aprsd.plugins.weather.OWMWeatherPlugin``
AVWXWeatherPlugin
~~~~~~~~~~~~~~~~~
**Command:** ``metar``, ``m``, ``m `` (m at start of message)
**Description:** Provides METAR weather reports using the AVWX API service. Fetches METAR
data from the nearest weather station to the GPS beacon location of the calling callsign
(or optionally a specified callsign).
**Usage:**
::
You: metar
APRSD: KORD 101451Z 28010KT 10SM FEW250 22/12 A3001 RMK AO2 SLP168 T02220122
You: metar WB4BOR
APRSD: KSFO 101500Z 25015KT 10SM FEW030 18/14 A2998 RMK AO2
**Requirements:**
- Requires an ``aprs_fi.apiKey`` configuration option
- Requires an ``avwx_plugin.apiKey`` configuration option
- Requires an ``avwx_plugin.base_url`` configuration option
**Configuration:**
- ``aprs_fi.apiKey`` - API key from aprs.fi account
- ``avwx_plugin.apiKey`` - API key for AVWX service
- ``avwx_plugin.base_url`` - Base URL for AVWX API (default: https://avwx.rest)
**Note:** AVWX is an open-source project. You can use the hosted service at https://avwx.rest/
or host your own instance. See the plugin code comments for instructions on running your
own AVWX API server.
**Plugin Path:** ``aprsd.plugins.weather.AVWXWeatherPlugin``
HelpPlugin
~~~~~~~~~~
**Command:** ``help``, ``h``, or ``H`` (h or H at start of message)
**Description:** Provides help information about available plugins. Can list all available
plugins or provide specific help for a named plugin.
**Usage:**
::
You: help
APRSD: Send APRS MSG of 'help' or 'help <plugin>'
plugins: fortune ping time version weather
You: help weather
APRSD: openweathermap: Send ^[wW] to get weather from your location
openweathermap: Send ^[wW] <callsign> to get weather from <callsign>
**Configuration:** Can be disabled by setting ``load_help_plugin = false`` in the configuration.
**Plugin Path:** ``aprsd.plugin.HelpPlugin``
WatchList Plugins
-----------------
These plugins monitor APRS traffic and can send notifications based on watch list criteria.
NotifySeenPlugin
~~~~~~~~~~~~~~~~
**Type:** WatchList Plugin
**Description:** Monitors callsigns in the watch list and sends a notification message when
a callsign that hasn't been seen recently (based on the configured age limit) appears on
the APRS network.
**How it works:**
- Tracks callsigns configured in the watch list
- Monitors all incoming APRS packets
- When a callsign in the watch list is seen and hasn't been seen recently (exceeds
the age limit), sends a notification message to the configured alert callsign
**Configuration:**
- ``watch_list.enabled`` - Must be set to ``true``
- ``watch_list.callsigns`` - List of callsigns to watch for
- ``watch_list.alert_callsign`` - Callsign to send notifications to
- ``watch_list.alert_time_seconds`` - Time threshold in seconds (default: 3600)
**Example Notification:**
::
APRSD -> WB4BOR: KM6LYW was just seen by type:'BeaconPacket'
**Plugin Path:** ``aprsd.plugins.notify.NotifySeenPlugin``
Enabling Built-in Plugins
--------------------------
Built-in plugins are enabled through the ``enabled_plugins`` configuration option in your
APRSD configuration file. List the full Python path to each plugin class you want to enable.
**Example Configuration:**
::
[DEFAULT]
enabled_plugins = aprsd.plugins.fortune.FortunePlugin,aprsd.plugins.ping.PingPlugin,aprsd.plugins.time.TimePlugin,aprsd.plugins.weather.OWMWeatherPlugin,aprsd.plugins.version.VersionPlugin,aprsd.plugins.notify.NotifySeenPlugin
**Note:** The HelpPlugin is enabled by default and does not need to be listed in
``enabled_plugins``. It can be disabled by setting ``load_help_plugin = false``.
**Note:** Some plugins may require additional configuration (API keys, etc.) and will
automatically disable themselves if required configuration is missing.
**Note:** Weather plugins (USWeatherPlugin, OWMWeatherPlugin, AVWXWeatherPlugin) all use
the same command pattern (``w`` or ``W`` at the start). Only one should be enabled at a time
to avoid conflicts. Similarly, METAR plugins (USMetarPlugin, AVWXWeatherPlugin) use the
same pattern (``m`` or ``M`` at the start).
Listing Available Plugins
--------------------------
You can see all available built-in plugins, along with their descriptions and command patterns,
by running:
.. code-block:: shell
aprsd list-plugins
This command will show:
- Built-in plugins included with APRSD
- Available plugins on PyPI that can be installed
- Currently installed third-party plugins
.. include:: links.rst

File diff suppressed because it is too large Load Diff

View File

@ -36,14 +36,14 @@ Sample config file
#
# Callsign to use for messages sent by APRSD (string value)
#callsign = <None>
#callsign = NOCALL
# Enable saving of watch list, packet tracker between restarts.
# (boolean value)
#enable_save = true
# Save location for packet tracking files. (string value)
#save_location = ~/.config/aprsd
#save_location = /Users/I530566/.config/aprsd/
# Enable code tracing (boolean value)
#trace_enabled = false
@ -51,34 +51,89 @@ Sample config file
# Units for display, imperial or metric (string value)
#units = imperial
# The wait period in seconds per Ack packet being sent.1 means 1 ack
# packet per second allowed.2 means 1 pack packet every 2 seconds
# allowed (integer value)
#ack_rate_limit_period = 1
# Wait period in seconds per non AckPacket being sent.2 means 1 packet
# every 2 seconds allowed.5 means 1 pack packet every 5 seconds
# allowed (integer value)
#msg_rate_limit_period = 2
# The number of seconds before a packet is not considered a duplicate.
# (integer value)
#packet_dupe_timeout = 300
# Enable sending of a GPS Beacon packet to locate this service.
# Requires latitude and longitude to be set. (boolean value)
#enable_beacon = false
# The number of seconds between beacon packets. (integer value)
#beacon_interval = 1800
# The symbol to use for the GPS Beacon packet. See:
# http://www.aprs.net/vm/DOS/SYMBOLS.HTM (string value)
#beacon_symbol = /
# Latitude for the GPS Beacon button. If not set, the button will not
# be enabled. (string value)
#latitude = <None>
# Longitude for the GPS Beacon button. If not set, the button will
# not be enabled. (string value)
#longitude = <None>
# When logging packets 'compact' will use a single line formatted for
# each packet.'multiline' will use multiple lines for each packet and
# is the traditional format.both will log both compact and multiline.
# (string value)
# Possible values:
# compact - <No description provided>
# multiline - <No description provided>
# both - <No description provided>
#log_packet_format = compact
# The number of times to send a non ack packet before giving up.
# (integer value)
#default_packet_send_count = 3
# The number of times to send an ack packet in response to recieving a
# packet. (integer value)
#default_ack_send_count = 3
# The maximum number of packets to store in the packet list. (integer
# value)
#packet_list_maxlen = 100
# The maximum number of packets to send in the stats dict for admin
# ui. -1 means no max. (integer value)
#packet_list_stats_maxlen = 20
# Enable the Callsign seen list tracking feature. This allows aprsd
# to keep track of callsigns that have been seen and when they were
# last seen. (boolean value)
#enable_seen_list = true
# Set this to False, to disable logging of packets to the log file.
# (boolean value)
#enable_packet_logging = true
# Set this to False to disable the help plugin. (boolean value)
#load_help_plugin = true
# Set this to False, to disable sending of ack packets. This will
# entirely stopAPRSD from sending ack packets. (boolean value)
#enable_sending_ack_packets = true
# Set this to True, if APRSD is running on a Digipi.This is useful for
# changing the behavior of APRSD to work with Digipi. (boolean value)
#is_digipi = false
# Comma separated list of enabled plugins for APRSD.To enable
# installed external plugins add them here.The full python path to the
# class name must be used (list value)
#enabled_plugins = aprsd.plugins.email.EmailPlugin,aprsd.plugins.fortune.FortunePlugin,aprsd.plugins.location.LocationPlugin,aprsd.plugins.ping.PingPlugin,aprsd.plugins.query.QueryPlugin,aprsd.plugins.time.TimePlugin,aprsd.plugins.weather.OWMWeatherPlugin,aprsd.plugins.version.VersionPlugin
[admin]
#
# From aprsd.conf
#
# Enable the Admin Web Interface (boolean value)
#web_enabled = false
# The ip address to listen on (IP address value)
#web_ip = 0.0.0.0
# The port to listen on (port value)
# Minimum value: 0
# Maximum value: 65535
#web_port = 8001
# The admin user for the admin web interface (string value)
#user = admin
# Admin interface password (string value)
#password = <None>
#enabled_plugins = aprsd.plugins.fortune.FortunePlugin,aprsd.plugins.location.LocationPlugin,aprsd.plugins.ping.PingPlugin,aprsd.plugins.time.TimePlugin,aprsd.plugins.weather.OWMWeatherPlugin,aprsd.plugins.version.VersionPlugin,aprsd.plugins.notify.NotifySeenPlugin
[aprs_fi]
@ -109,7 +164,7 @@ Sample config file
# https://apps.magicbug.co.uk/passcode (string value)
#password = <None>
# The APRS-IS hostname (hostname value)
# The APRS-IS hostname (host address value)
#host = noam.aprs2.net
# APRS-IS port (port value)
@ -118,21 +173,35 @@ Sample config file
#port = 14580
[aprsd_weewx_plugin]
[aprs_registry]
#
# From aprsd_weewx_plugin.conf
# From aprsd.conf
#
# Latitude of the station you want to report as (floating point value)
#latitude = <None>
# Longitude of the station you want to report as (floating point
# Enable sending aprs registry information. This will let the APRS
# registry know about your service and it's uptime. No personal
# information is sent, just the callsign, uptime and description. The
# service callsign is the callsign set in [DEFAULT] section. (boolean
# value)
#longitude = <None>
#enabled = false
# How long (in seconds) in between weather reports (integer value)
#report_interval = 60
# Description of the service to send to the APRS registry. This is
# what will show up in the APRS registry.If not set, the description
# will be the same as the callsign. (string value)
#description = <None>
# The APRS registry domain name to send the information to. (string
# value)
#registry_url = https://aprs.hemna.com/api/v1/registry
# The website for your APRS service to send to the APRS registry.
# (string value)
#service_website = <None>
# The frequency in seconds to send the APRS registry information.
# (integer value)
#frequency_seconds = 3600
[avwx_plugin]
@ -152,62 +221,15 @@ Sample config file
#base_url = https://avwx.rest
[email_plugin]
[fake_client]
#
# From aprsd.conf
#
# (Required) Callsign to validate for doing email commands.Only this
# callsign can check email. This is also where the email notifications
# for new emails will be sent. (string value)
#callsign = <None>
# Enable the Email plugin? (boolean value)
# Enable fake client connection. (boolean value)
#enabled = false
# Enable the Email plugin Debugging? (boolean value)
#debug = false
# Login username/email for IMAP server (string value)
#imap_login = <None>
# Login password for IMAP server (string value)
#imap_password = <None>
# Hostname/IP of the IMAP server (hostname value)
#imap_host = <None>
# Port to use for IMAP server (port value)
# Minimum value: 0
# Maximum value: 65535
#imap_port = 993
# Use SSL for connection to IMAP Server (boolean value)
#imap_use_ssl = true
# Login username/email for SMTP server (string value)
#smtp_login = <None>
# Login password for SMTP server (string value)
#smtp_password = <None>
# Hostname/IP of the SMTP server (hostname value)
#smtp_host = <None>
# Port to use for SMTP server (port value)
# Minimum value: 0
# Maximum value: 65535
#smtp_port = 465
# Use SSL for connection to SMTP Server (boolean value)
#smtp_use_ssl = true
# List of email shortcuts for checking/sending email For Exmaple:
# wb=walt@walt.com,cl=cl@cl.com
# Means use 'wb' to send an email to walt@walt.com (list value)
#email_shortcuts = <None>
[kiss_serial]
@ -224,6 +246,9 @@ Sample config file
# The Serial device baud rate for communication (integer value)
#baudrate = 9600
# The APRS path to use for wide area coverage. (list value)
#path = WIDE1-1,WIDE2-1
[kiss_tcp]
@ -234,7 +259,7 @@ Sample config file
# Enable Serial KISS interface connection. (boolean value)
#enabled = false
# The KISS TCP Host to connect to. (hostname value)
# The KISS TCP Host to connect to. (host address value)
#host = <None>
# The KISS TCP/IP network port (port value)
@ -242,6 +267,9 @@ Sample config file
# Maximum value: 65535
#port = 8001
# The APRS path to use for wide area coverage. (list value)
#path = WIDE1-1,WIDE2-1
[logging]
@ -249,17 +277,26 @@ Sample config file
# From aprsd.conf
#
# Date format for log entries (string value)
#date_format = %m/%d/%Y %I:%M:%S %p
# Enable Rich logging (boolean value)
#rich_logging = true
# File to log to (string value)
#logfile = <None>
# Log file format, unless rich_logging enabled. (string value)
#logformat = [%(asctime)s] [%(threadName)-20.20s] [%(levelname)-5.5s] %(message)s - [%(pathname)s:%(lineno)d]
#logformat = <green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <yellow>{thread.name: <18}</yellow> | <level>{level: <8}</level> | <level>{message}</level> | <cyan>{name}</cyan>:<cyan>{function:}</cyan>:<magenta>{line:}</magenta>
# Log level for logging of events. (string value)
# Possible values:
# CRITICAL - <No description provided>
# ERROR - <No description provided>
# WARNING - <No description provided>
# INFO - <No description provided>
# DEBUG - <No description provided>
#log_level = INFO
# Enable ANSI color codes in logging (boolean value)
#enable_color = true
# Enable logging to the console/stdout. (boolean value)
#enable_console_stdout = true
[owm_weather_plugin]
@ -275,39 +312,6 @@ Sample config file
#apiKey = <None>
[query_plugin]
#
# From aprsd.conf
#
# The Ham callsign to allow access to the query plugin from RF.
# (string value)
#callsign = <None>
[rpc_settings]
#
# From aprsd.conf
#
# Enable RPC calls (boolean value)
#enabled = true
# The ip address to listen on (string value)
#ip = localhost
# The port to listen on (port value)
# Minimum value: 0
# Maximum value: 65535
#port = 18861
# Magic word to authenticate requests between client/server (string
# value)
#magic_word = CHANGEME!!!
[watch_list]
#

234
docs/extension.rst Normal file
View File

@ -0,0 +1,234 @@
APRSD Extension Development
============================
APRSD extensions are more comprehensive than plugins and can add new functionality
to the APRSD daemon beyond simple command plugins. Extensions can include:
* New command-line commands
* Configuration options
* Background threads
* Statistics collectors
* Custom packet processors
* And more
Creating an Extension Project
-------------------------------
The recommended way to create a new APRSD extension project is to use the
`cookiecutter-aprsd-extension`_ template. This template provides a complete project
structure with all the necessary files, testing infrastructure, and documentation setup.
Installation
~~~~~~~~~~~~
First, install cookiecutter if you haven't already::
pip install cookiecutter
Creating a New Extension Project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run cookiecutter with the APRSD extension template::
cookiecutter gh:hemna/cookiecutter-aprsd-extension
Cookiecutter will prompt you for several pieces of information:
* **extension_name**: The name of your extension (e.g., ``aprsd-my-extension``)
* **extension_module_name**: The Python module name (e.g., ``aprsd_my_extension``)
* **author_name**: Your name or organization name
* **author_email**: Your email address
* **description**: A brief description of your extension
* **version**: Initial version (default: ``0.1.0``)
Project Structure
~~~~~~~~~~~~~~~~~
The cookiecutter template creates a complete project structure including:
* **Test automation** with Tox
* **Linting** with pre-commit and Flake8
* **Continuous integration** with GitHub Actions
* **Documentation** with Sphinx and Read the Docs
* **Automated uploads** to PyPI and TestPyPI
* **Automated dependency updates** with Dependabot
* **Code formatting** with Gray
* **Testing** with pytest
* **Code coverage** with Coverage.py
* **Coverage reporting** with Codecov
The generated project follows Python packaging best practices and includes:
* Proper ``setup.py`` and ``pyproject.toml`` configuration
* Entry point registration for APRSD extension discovery (``aprsd.extension``)
* Configuration entry points for oslo.config (``oslo.config.opts``)
* Test suite structure
* Documentation templates
* CI/CD pipeline configuration
Extension Registration
~~~~~~~~~~~~~~~~~~~~~~
Extensions are registered using Python entry points in your ``pyproject.toml`` or
``setup.py`` file. The entry point group is ``aprsd.extension``::
[project.entry-points."aprsd.extension"]
"my_extension" = "aprsd_my_extension.extension"
Configuration Options
~~~~~~~~~~~~~~~~~~~~~
Extensions can add their own configuration options using oslo.config. Register
your configuration options using the ``oslo.config.opts`` entry point::
[project.entry-points."oslo.config.opts"]
"aprsd_my_extension.conf" = "aprsd_my_extension.conf.opts:list_opts"
Example Extension Structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~
A typical extension project structure looks like this::
aprsd-my-extension/
├── aprsd_my_extension/
│ ├── __init__.py
│ ├── extension.py # Main extension entry point
│ ├── cmds/ # Command-line commands
│ │ ├── __init__.py
│ │ └── show.py
│ ├── conf/ # Configuration options
│ │ ├── __init__.py
│ │ ├── opts.py
│ │ └── main.py
│ ├── threads/ # Background threads
│ │ ├── __init__.py
│ │ └── MyThread.py
│ └── stats.py # Statistics collectors
├── tests/
├── docs/
├── pyproject.toml
├── setup.py
└── README.md
Example Extension: WebChat
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The `aprsd-webchat-extension`_ is a real-world example of an APRSD extension that
adds a web-based chat interface to APRSD. Let's examine how it's structured:
Entry Point Registration
^^^^^^^^^^^^^^^^^^^^^^^^^
In ``pyproject.toml``, the extension registers itself::
[project.entry-points."aprsd.extension"]
"webchat" = "aprsd_webchat_extension.extension"
[project.entry-points."oslo.config.opts"]
"aprsd_webchat_extension.conf" = "aprsd_webchat_extension.conf.opts:list_opts"
Extension Entry Point
^^^^^^^^^^^^^^^^^^^^^^
The ``extension.py`` file imports the command module to register it::
from aprsd_webchat_extension.cmds import webchat # noqa: F401
This import causes the command to be registered with APRSD's CLI system.
Command Implementation
^^^^^^^^^^^^^^^^^^^^^^
The webchat extension adds a new command ``aprsd webchat`` that starts a Flask-based
web server. The command is implemented in ``cmds/webchat.py`` and uses Click for
command-line interface::
import click
from aprsd.main import cli
@cli.command()
@click.option('--host', default='0.0.0.0', help='Host to bind to')
@click.option('--port', default=8080, help='Port to bind to')
def webchat(host, port):
"""Start the webchat interface."""
# Implementation here
pass
Configuration Options
^^^^^^^^^^^^^^^^^^^^^
The extension adds configuration options through ``conf/opts.py``::
from oslo_config import cfg
webchat_group = cfg.OptGroup(name='webchat',
title='WebChat Options')
webchat_opts = [
cfg.StrOpt('host',
default='0.0.0.0',
help='WebChat server host'),
cfg.IntOpt('port',
default=8080,
help='WebChat server port'),
]
def list_opts():
return [
(webchat_group, webchat_opts),
]
The configuration can then be used in the extension code::
from oslo_config import cfg
CONF = cfg.CONF
host = CONF.webchat.host
port = CONF.webchat.port
Project Structure
^^^^^^^^^^^^^^^^^
The webchat extension has the following structure::
aprsd-webchat-extension/
├── aprsd_webchat_extension/
│ ├── __init__.py
│ ├── extension.py # Entry point that imports commands
│ ├── cmds/
│ │ ├── __init__.py
│ │ └── webchat.py # Command implementation
│ ├── conf/
│ │ ├── __init__.py
│ │ ├── opts.py # Configuration option definitions
│ │ └── main.py # Configuration group definitions
│ ├── web/ # Web assets (HTML, CSS, JS)
│ │ └── chat/
│ │ ├── static/
│ │ └── templates/
│ └── utils.py # Utility functions
├── tests/
├── docs/
├── pyproject.toml
└── README.md
Usage
^^^^^
Once installed, users can run the webchat command::
$ aprsd webchat --loglevel DEBUG
This demonstrates how extensions can add new functionality beyond simple plugins,
including web interfaces, background services, and complex integrations.
For more information about the cookiecutter template, visit the
`cookiecutter-aprsd-extension repository`_.
For the complete source code of the webchat extension, see the
`aprsd-webchat-extension repository`_.
.. _cookiecutter-aprsd-extension: https://github.com/hemna/cookiecutter-aprsd-extension
.. _cookiecutter-aprsd-extension repository: https://github.com/hemna/cookiecutter-aprsd-extension
.. _aprsd-webchat-extension: https://github.com/hemna/aprsd-webchat-extension
.. _aprsd-webchat-extension repository: https://github.com/hemna/aprsd-webchat-extension

View File

@ -17,7 +17,10 @@
install
configure
server
listen
builtin_plugins
plugin
extension
apidoc/modules.rst

138
docs/listen.rst Normal file
View File

@ -0,0 +1,138 @@
APRSD listen
============
Running the APRSD listen command
---------------------------------
The ``aprsd listen`` command allows you to listen to packets on the APRS-IS Network based on a FILTER.
This is useful for monitoring specific APRS traffic without running the full server.
Once APRSD is :doc:`installed <install>` and :doc:`configured <configure>`, the listen command can be started by running:
.. code-block:: shell
aprsd listen [FILTER]
The FILTER parameter is optional and follows the APRS-IS filter format. For example, ``m/300`` filters for
messages within 300 miles of your configured location.
Example usage
-------------
.. code-block:: shell
aprsd listen --loglevel DEBUG m/300
2025-12-10 14:32:33.813 | MainThread | INFO | Python version: 3.10.14 (main, Aug 14 2024, 05:14:46) [Clang 18.1.8 ] | aprsd.cmds.listen:listen:224
2025-12-10 14:32:33.813 | MainThread | INFO | APRSD Listen Started version: 4.2.5.dev8+g9c0695794 | aprsd.cmds.listen:listen:225
2025-12-10 14:32:33.841 | MainThread | DEBUG | ******************************************************************************** | oslo_config.cfg:log_opt_values:2804
2025-12-10 14:32:33.841 | MainThread | DEBUG | Configuration options gathered from: | oslo_config.cfg:log_opt_values:2805
2025-12-10 14:32:33.841 | MainThread | DEBUG | command line args: [] | oslo_config.cfg:log_opt_values:2806
2025-12-10 14:32:33.841 | MainThread | DEBUG | config files: ['/Users/I530566/.config/aprsd/aprsd.conf'] | oslo_config.cfg:log_opt_values:2807
2025-12-10 14:32:33.841 | MainThread | DEBUG | ================================================================================ | oslo_config.cfg:log_opt_values:2809
2025-12-10 14:32:33.841 | MainThread | DEBUG | ack_rate_limit_period = 1 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | beacon_interval = 60 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | beacon_symbol = / | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | callsign = WB4BOR-1 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | config_dir = [] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | config_file = ['/Users/I530566/.config/aprsd/aprsd.conf'] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | config_source = [] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | default_ack_send_count = 3 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | default_packet_send_count = 3 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | enable_beacon = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | enable_packet_logging = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.841 | MainThread | DEBUG | enable_save = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | enable_seen_list = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | enable_sending_ack_packets = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | enabled_plugins = ['aprsd.plugins.weather.AVWXWeatherPlugin'] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | is_digipi = False | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | latitude = 37.3443862 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | load_help_plugin = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | log_packet_format = compact | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | longitude = -78.850000 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | msg_rate_limit_period = 2 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | packet_dupe_timeout = 300 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | packet_list_maxlen = 5000 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | packet_list_stats_maxlen = 20 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | save_location = /Users/I530566/.config/aprsd/ | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | shell_completion = None | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | trace_enabled = False | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | units = imperial | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:32:33.842 | MainThread | DEBUG | logging.enable_color = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | logging.enable_console_stdout = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | logging.log_level = INFO | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | logging.logfile = /tmp/aprsd.log | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | logging.logformat = <green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <yellow>{thread.name: <18}</yellow> | <level>{level: <8}</level> | <level>{message}</level> | <cyan>{name}</cyan>:<cyan>{function:}</cyan>:<magenta>{line:}</magenta> | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | watch_list.alert_callsign = WB4BOR-1 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | watch_list.alert_time_seconds = 3600 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | watch_list.callsigns = ['APPOMX', 'REPEAT', 'KM6LYW', 'WB4BOR', 'M0IAX', 'VE3SCN', 'WA4RTS-5', 'KC9BUH', 'W4SOU-7', 'KD9KAF-7', 'NN4RB-9', 'KN4MLN-9', 'KK4WZS-8', 'K2VIZ-1', 'KE3XE-9', 'WB2UTI-9', 'KO4ARL-7', 'LMS6CAE42', 'WDJ6895', 'PHISVR', 'F1BIS-9', 'M7APR-9', 'Y09INA-5', 'M0PLT-7', 'M0GLJ-14', 'MW6JUY-10', 'M0XZS', 'M0HPP-8', 'ON2BBW-8'] | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | watch_list.enabled = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | watch_list.packet_keep_count = 10 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | aprs_registry.description = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | aprs_registry.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.842 | MainThread | DEBUG | aprs_registry.frequency_seconds = 3600 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_registry.registry_url = https://aprs.hemna.com/api/v1/registry | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_registry.service_website = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_network.enabled = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_network.host = 155.138.131.1 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_network.login = WB4BOR-1 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_network.password = **** | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_network.port = 14580 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_serial.baudrate = 9600 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_serial.device = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_serial.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_serial.path = ['WIDE1-1', 'WIDE2-1'] | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_tcp.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_tcp.host = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_tcp.path = ['WIDE1-1', 'WIDE2-1'] | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | kiss_tcp.port = 8001 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | fake_client.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | aprs_fi.apiKey = 152327.lds79D1bgvlbd | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | owm_weather_plugin.apiKey = e26b403324563f24a290fa1d06459bae | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | avwx_plugin.apiKey = Foo | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | avwx_plugin.base_url = https://avwx.rest | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:32:33.843 | MainThread | DEBUG | ******************************************************************************** | oslo_config.cfg:log_opt_values:2828
2025-12-10 14:32:33.843 | MainThread | DEBUG | Loading saved MsgTrack object. | aprsd.cmds.listen:listen:232
2025-12-10 14:32:33.843 | MainThread | INFO | Creating aprslib client(155.138.131.1:14580) and logging in WB4BOR-1. try #1 | aprsd.client.drivers.aprsis:setup_connection:103
2025-12-10 14:32:33.843 | MainThread | INFO | Attempting connection to 155.138.131.1:14580 | aprsd.client.drivers.lib.aprslib:_connect:69
2025-12-10 14:32:33.869 | MainThread | INFO | Connected to ('155.138.131.1', 14580) | aprsd.client.drivers.lib.aprslib:_connect:78
2025-12-10 14:32:33.900 | MainThread | DEBUG | Banner: # aprsc 2.1.19-g730c5c0 | aprsd.client.drivers.lib.aprslib:_connect:96
2025-12-10 14:32:33.900 | MainThread | DEBUG | Sending login information | aprsd.client.drivers.lib.aprslib:_send_login:180
2025-12-10 14:32:33.924 | MainThread | DEBUG | Server: '# logresp WB4BOR-1 verified, server T2CAEAST' | aprsd.client.drivers.lib.aprslib:_send_login:190
2025-12-10 14:32:33.924 | MainThread | INFO | Login successful | aprsd.client.drivers.lib.aprslib:_send_login:212
2025-12-10 14:32:33.924 | MainThread | INFO | Connected to T2CAEAST | aprsd.client.drivers.lib.aprslib:_send_login:214
2025-12-10 14:32:33.924 | MainThread | INFO | Creating client connection | aprsd.cmds.listen:listen:242
2025-12-10 14:32:33.924 | MainThread | INFO | <aprsd.client.client.APRSDClient object at 0x10bd9bfa0> | aprsd.cmds.listen:listen:244
2025-12-10 14:32:33.924 | MainThread | DEBUG | Filter messages on aprsis server by '('m/300',)' | aprsd.cmds.listen:listen:252
2025-12-10 14:32:33.924 | MainThread | INFO | Setting filter to: ('m/300',) | aprslib.inet:set_filter:83
2025-12-10 14:32:33.925 | MainThread | INFO | No packet filtering enabled. | aprsd.cmds.listen:listen:268
2025-12-10 14:32:33.925 | MainThread | WARNING | Not Loading any plugins use --load-plugins to load what's defined in the config file. | aprsd.cmds.listen:listen:282
2025-12-10 14:32:33.925 | StatsStore | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:32:33.925 | MainThread | DEBUG | Start APRSDRxThread | aprsd.cmds.listen:listen:294
2025-12-10 14:32:33.926 | RX_PKT | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:32:33.926 | MainThread | DEBUG | Create APRSDListenProcessThread | aprsd.cmds.listen:listen:298
2025-12-10 14:32:33.926 | MainThread | DEBUG | Start APRSDListenProcessThread | aprsd.cmds.listen:listen:306
2025-12-10 14:32:33.926 | ListenProcThread | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:32:33.926 | KeepAlive | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:32:33.926 | MainThread | DEBUG | keepalive Join | aprsd.cmds.listen:listen:313
2025-12-10 14:32:34.927 | RX_PKT | DEBUG | Server: # filter m/300 active | aprsd.client.drivers.lib.aprslib:consumer:255
2025-12-10 14:32:34.942 | RX_PKT | INFO | RX(1)↓ MicEPacket:None WX4EMC-1 →WIDE1-1→WIDE2-2→qAR→W4VA-13→ S8QQ8S : Lat:38.197 Lon:-77.561 101 mbits : Northeast@91.78miles | aprsd.packets.log:log:170
2025-12-10 14:32:34.965 | RX_PKT | INFO | RX(2)↓ BeaconPacket:None W4MUP-10 →TCPIP*→qAS→W4MUP→ APMI06 : Lat:36.208 Lon:-80.269 Igate and Digi U=13.3V : Southwest@111.08miles | aprsd.packets.log:log:170
2025-12-10 14:32:35.996 | RX_PKT | INFO | RX(3)↓ WeatherPacket:None W4MLN-1 →TCPIP*→qAC→T2CAEAST→ APN000 : Temp 009F Humidity 49% Wind 007MPH@261 Pressure 999.7mb Rain 0.01in/24hr : West-Southwest@157.78miles | aprsd.packets.log:log:170
2025-12-10 14:32:37.669 | RX_PKT | INFO | RX(4)↓ BeaconPacket:None W4GER →TCPIP*→qAC→T2SYDNEY→ APOSB4 : Lat:38.735 Lon:-77.279 SharkRF openSPOT4 : Northeast@128.60miles | aprsd.packets.log:log:170
2025-12-10 14:32:37.943 | RX_PKT | INFO | RX(5)↓ BeaconPacket:None NM5ER-10 →TCPIP*→qAC→T2SYDNEY→ APLRG1 : Lat:36.440 Lon:-81.140 LoRa APRS : West-Southwest@141.12miles | aprsd.packets.log:log:170
The listen command connects to the APRS-IS network and displays packets matching the specified filter.
In the example above, packets within 300 miles are displayed, showing various packet types including MicEPacket,
BeaconPacket, and WeatherPacket.
Key differences from the server command
----------------------------------------
Unlike the ``aprsd server`` command, the listen command:
- Does not load plugins by default (use ``--load-plugins`` to enable them)
- Does not respond to messages
- Is designed for monitoring and logging APRS traffic
- Supports APRS-IS filter syntax for targeted packet monitoring
.. include:: links.rst

View File

@ -1,6 +1,63 @@
APRSD Command Plugin Development
================================
Creating a Plugin Project
-------------------------
The recommended way to create a new APRSD plugin project is to use the `cookiecutter-aprsd-plugin`_ template. This template provides a complete project structure with all the necessary files, testing infrastructure, and documentation setup.
Installation
~~~~~~~~~~~~
First, install cookiecutter if you haven't already::
pip install cookiecutter
Creating a New Plugin Project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run cookiecutter with the APRSD plugin template::
cookiecutter gh:hemna/cookiecutter-aprsd-plugin
Cookiecutter will prompt you for several pieces of information:
* **plugin_name**: The name of your plugin (e.g., ``aprsd-my-plugin``)
* **plugin_module_name**: The Python module name (e.g., ``aprsd_my_plugin``)
* **author_name**: Your name or organization name
* **author_email**: Your email address
* **description**: A brief description of your plugin
* **version**: Initial version (default: ``0.1.0``)
Project Structure
~~~~~~~~~~~~~~~~~
The cookiecutter template creates a complete project structure including:
* **Test automation** with Tox
* **Linting** with pre-commit and Flake8
* **Continuous integration** with GitHub Actions
* **Documentation** with Sphinx and Read the Docs
* **Automated uploads** to PyPI and TestPyPI
* **Automated dependency updates** with Dependabot
* **Code formatting** with Gray
* **Testing** with pytest
* **Code coverage** with Coverage.py
* **Coverage reporting** with Codecov
The generated project follows Python packaging best practices and includes:
* Proper ``setup.py`` and ``pyproject.toml`` configuration
* Entry point registration for APRSD plugin discovery
* Test suite structure
* Documentation templates
* CI/CD pipeline configuration
For more information about the cookiecutter template, visit the `cookiecutter-aprsd-plugin repository`_.
.. _cookiecutter-aprsd-plugin: https://github.com/hemna/cookiecutter-aprsd-plugin
.. _cookiecutter-aprsd-plugin repository: https://github.com/hemna/cookiecutter-aprsd-plugin
APRSDPluginBase
------------------------

View File

@ -14,40 +14,151 @@ running.
The server will start several threads to deal handle incoming messages, outgoing
messages, checking and sending email.
How APRSD processes messages
-----------------------------
When APRSD receives an APRS message packet, it follows a structured processing flow:
1. **Packet Reception**: The ``RX_PKT`` thread receives packets from the APRS-IS network
and places them into a packet queue.
2. **Packet Processing**: The ``ProcessPKT`` thread processes packets from the queue.
It determines if the packet is:
- An ACK packet destined for APRSD (handled separately)
- A Reject packet (handled separately)
- A MessagePacket destined for APRSD's callsign
- Other packet types (beacons, weather, etc.)
3. **Message Routing**: When a MessagePacket is received that is addressed to APRSD's
callsign, the packet is sent to the ``process_our_message_packet`` method.
4. **Plugin Processing**: The message packet is passed to the PluginManager, which:
- Iterates through all registered plugins in the order they were configured
- For each plugin, checks if the message matches the plugin's regex pattern
- If a match is found, calls the plugin's ``process()`` method with the packet
- Collects any reply messages returned by the plugins
5. **Response Handling**: Any reply messages returned by plugins are sent back to the
original sender via the APRS-IS network. Plugins can return:
- A string message (converted to a MessagePacket)
- A Packet object (sent as-is)
- A list of messages (multiple replies)
- ``NULL_MESSAGE`` (indicates the plugin processed the message but has no reply)
6. **ACK Handling**: After processing, if the message had a message ID, APRSD
automatically sends an ACK packet to acknowledge receipt.
This plugin-based architecture allows APRSD to be extended with custom functionality
without modifying the core codebase. Each plugin can independently process messages
and respond as needed. See the :doc:`plugin <plugin>` documentation for information
on creating your own plugins.
.. code-block:: shell
[MainThread ] [INFO ] APRSD Started version: 1.5.1
[MainThread ] [INFO ] Checking IMAP configuration
[MainThread ] [INFO ] Checking SMTP configuration
[MainThread ] [DEBUG] Connect to SMTP host SSL smtp.gmail.com:465 with user 'test@hemna.com'
[MainThread ] [DEBUG] Connected to smtp host SSL smtp.gmail.com:465
[MainThread ] [DEBUG] Logged into SMTP server SSL smtp.gmail.com:465
[MainThread ] [INFO ] Validating 2 Email shortcuts. This can take up to 10 seconds per shortcut
[MainThread ] [ERROR] 'craiglamparter@somedomain.org' is an invalid email address. Removing shortcut
[MainThread ] [INFO ] Available shortcuts: {'wb': 'waboring@hemna.com'}
[MainThread ] [INFO ] Loading Core APRSD Command Plugins
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.email.EmailPlugin'(1.0) '^-.*'
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.fortune.FortunePlugin'(1.0) '^[fF]'
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.location.LocationPlugin'(1.0) '^[lL]'
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.ping.PingPlugin'(1.0) '^[pP]'
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.query.QueryPlugin'(1.0) '^\?.*'
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.time.TimePlugin'(1.0) '^[tT]'
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.weather.WeatherPlugin'(1.0) '^[wW]'
[MainThread ] [INFO ] Registering Command plugin 'aprsd.plugins.version.VersionPlugin'(1.0) '^[vV]'
[MainThread ] [INFO ] Skipping Custom Plugins directory.
[MainThread ] [INFO ] Completed Plugin Loading.
[MainThread ] [DEBUG] Loading saved MsgTrack object.
[RX_MSG ] [INFO ] Starting
[TX_MSG ] [INFO ] Starting
[MainThread ] [DEBUG] KeepAlive Tracker(0): {}
[RX_MSG ] [INFO ] Creating aprslib client
[RX_MSG ] [INFO ] Attempting connection to noam.aprs2.net:14580
[RX_MSG ] [INFO ] Connected to ('198.50.198.139', 14580)
[RX_MSG ] [DEBUG] Banner: # aprsc 2.1.8-gf8824e8
[RX_MSG ] [INFO ] Sending login information
[RX_MSG ] [DEBUG] Server: # logresp KM6XXX-14 verified, server T2VAN
[RX_MSG ] [INFO ] Login successful
[RX_MSG ] [DEBUG] Logging in to APRS-IS with user 'KM6XXX-14'
aprsd server --loglevel DEBUG
2025-12-10 14:30:05.146 | MainThread | INFO | Python version: 3.10.14 (main, Aug 14 2024, 05:14:46) [Clang 18.1.8 ] | aprsd.cmds.server:server:43
2025-12-10 14:30:05.147 | MainThread | INFO | APRSD Started version: 4.2.5.dev8+g9c0695794 | aprsd.cmds.server:server:44
2025-12-10 14:30:05.147 | MainThread | INFO | APRSD is up to date | aprsd.cmds.server:server:49
2025-12-10 14:30:05.167 | MainThread | INFO | Creating aprslib client(155.138.131.1:14580) and logging in WB4BOR-1. try #1 | aprsd.client.drivers.aprsis:setup_connection:103
2025-12-10 14:30:05.167 | MainThread | INFO | Attempting connection to 155.138.131.1:14580 | aprsd.client.drivers.lib.aprslib:_connect:69
2025-12-10 14:30:05.193 | MainThread | INFO | Connected to ('155.138.131.1', 14580) | aprsd.client.drivers.lib.aprslib:_connect:78
2025-12-10 14:30:05.232 | MainThread | DEBUG | Banner: # aprsc 2.1.19-g730c5c0 | aprsd.client.drivers.lib.aprslib:_connect:96
2025-12-10 14:30:05.232 | MainThread | DEBUG | Sending login information | aprsd.client.drivers.lib.aprslib:_send_login:180
2025-12-10 14:30:05.256 | MainThread | DEBUG | Server: '# logresp WB4BOR-1 verified, server T2CAEAST' | aprsd.client.drivers.lib.aprslib:_send_login:190
2025-12-10 14:30:05.256 | MainThread | INFO | Login successful | aprsd.client.drivers.lib.aprslib:_send_login:212
2025-12-10 14:30:05.256 | MainThread | INFO | Connected to T2CAEAST | aprsd.client.drivers.lib.aprslib:_send_login:214
2025-12-10 14:30:05.256 | MainThread | INFO | Creating client connection | aprsd.cmds.server:server:62
2025-12-10 14:30:05.256 | MainThread | INFO | <aprsd.client.client.APRSDClient object at 0x1096ac460> | aprsd.cmds.server:server:64
2025-12-10 14:30:05.256 | MainThread | INFO | Loading Plugin Manager and registering plugins | aprsd.cmds.server:server:78
2025-12-10 14:30:05.257 | MainThread | INFO | Loading APRSD Plugins | aprsd.plugin:setup_plugins:493
2025-12-10 14:30:05.257 | MainThread | INFO | Registering Regex plugin 'aprsd.plugins.weather.AVWXWeatherPlugin'(4.2.5.dev8+g9c0695794) -- ^([m]|[m]|[m]\s|metar) | aprsd.plugin:_load_plugin:452
2025-12-10 14:30:05.257 | MainThread | INFO | Completed Plugin Loading. | aprsd.plugin:setup_plugins:513
2025-12-10 14:30:05.257 | MainThread | DEBUG | ******************************************************************************** | oslo_config.cfg:log_opt_values:2804
2025-12-10 14:30:05.257 | MainThread | DEBUG | Configuration options gathered from: | oslo_config.cfg:log_opt_values:2805
2025-12-10 14:30:05.257 | MainThread | DEBUG | command line args: [] | oslo_config.cfg:log_opt_values:2806
2025-12-10 14:30:05.257 | MainThread | DEBUG | config files: ['/Users/I530566/.config/aprsd/aprsd.conf'] | oslo_config.cfg:log_opt_values:2807
2025-12-10 14:30:05.257 | MainThread | DEBUG | ================================================================================ | oslo_config.cfg:log_opt_values:2809
2025-12-10 14:30:05.257 | MainThread | DEBUG | ack_rate_limit_period = 1 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | beacon_interval = 60 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | beacon_symbol = / | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | callsign = WB4BOR-1 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | config_dir = [] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | config_file = ['/Users/I530566/.config/aprsd/aprsd.conf'] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | config_source = [] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | default_ack_send_count = 3 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | default_packet_send_count = 3 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | enable_beacon = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | enable_packet_logging = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | enable_save = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | enable_seen_list = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | enable_sending_ack_packets = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | enabled_plugins = ['aprsd.plugins.weather.AVWXWeatherPlugin'] | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | is_digipi = False | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | latitude = 37.3443862 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | load_help_plugin = True | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | log_packet_format = compact | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | longitude = -78.850000 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | msg_rate_limit_period = 2 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.258 | MainThread | DEBUG | packet_dupe_timeout = 300 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.259 | MainThread | DEBUG | packet_list_maxlen = 5000 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.259 | MainThread | DEBUG | packet_list_stats_maxlen = 20 | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.259 | MainThread | DEBUG | save_location = /Users/I530566/.config/aprsd/ | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.259 | MainThread | DEBUG | shell_completion = None | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.259 | MainThread | DEBUG | trace_enabled = False | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.259 | MainThread | DEBUG | units = imperial | oslo_config.cfg:log_opt_values:2817
2025-12-10 14:30:05.259 | MainThread | DEBUG | logging.enable_color = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | logging.enable_console_stdout = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | logging.log_level = INFO | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | logging.logfile = /tmp/aprsd.log | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | logging.logformat = <green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <yellow>{thread.name: <18}</yellow> | <level>{level: <8}</level> | <level>{message}</level> | <cyan>{name}</cyan>:<cyan>{function:}</cyan>:<magenta>{line:}</magenta> | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | watch_list.alert_callsign = WB4BOR-1 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | watch_list.alert_time_seconds = 3600 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | watch_list.callsigns = ['APPOMX', 'REPEAT', 'KM6LYW', 'WB4BOR', 'M0IAX', 'VE3SCN', 'WA4RTS-5', 'KC9BUH', 'W4SOU-7', 'KD9KAF-7', 'NN4RB-9', 'KN4MLN-9', 'KK4WZS-8', 'K2VIZ-1', 'KE3XE-9', 'WB2UTI-9', 'KO4ARL-7', 'LMS6CAE42', 'WDJ6895', 'PHISVR', 'F1BIS-9', 'M7APR-9', 'Y09INA-5', 'M0PLT-7', 'M0GLJ-14', 'MW6JUY-10', 'M0XZS', 'M0HPP-8', 'ON2BBW-8'] | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | watch_list.enabled = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | watch_list.packet_keep_count = 10 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | aprs_registry.description = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | aprs_registry.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | aprs_registry.frequency_seconds = 3600 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | aprs_registry.registry_url = https://aprs.hemna.com/api/v1/registry | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | aprs_registry.service_website = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.259 | MainThread | DEBUG | aprs_network.enabled = True | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | aprs_network.host = 155.138.131.1 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | aprs_network.login = WB4BOR-1 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | aprs_network.password = **** | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | aprs_network.port = 14580 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_serial.baudrate = 9600 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_serial.device = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_serial.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_serial.path = ['WIDE1-1', 'WIDE2-1'] | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_tcp.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_tcp.host = None | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_tcp.path = ['WIDE1-1', 'WIDE2-1'] | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | kiss_tcp.port = 8001 | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | fake_client.enabled = False | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | aprs_fi.apiKey = 152327.lds79D1bgvlbd | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | owm_weather_plugin.apiKey = e26b403324563f24a290fa1d06459bae | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | avwx_plugin.apiKey = Foo | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | avwx_plugin.base_url = https://avwx.rest | oslo_config.cfg:log_opt_values:2824
2025-12-10 14:30:05.260 | MainThread | DEBUG | ******************************************************************************** | oslo_config.cfg:log_opt_values:2828
2025-12-10 14:30:05.260 | MainThread | INFO | Message Plugins enabled and running: | aprsd.cmds.server:server:86
2025-12-10 14:30:05.260 | MainThread | INFO | <aprsd.plugins.weather.AVWXWeatherPlugin object at 0x109a74c40> | aprsd.cmds.server:server:88
2025-12-10 14:30:05.260 | MainThread | INFO | <aprsd.plugin.HelpPlugin object at 0x109a74ac0> | aprsd.cmds.server:server:88
2025-12-10 14:30:05.260 | MainThread | INFO | Watchlist Plugins enabled and running: | aprsd.cmds.server:server:89
2025-12-10 14:30:05.260 | MainThread | DEBUG | Loading saved packet tracking data. | aprsd.cmds.server:server:103
2025-12-10 14:30:05.261 | MainThread | DEBUG | PacketList::No save file found. | aprsd.utils.objectstore:load:113
2025-12-10 14:30:05.261 | MainThread | DEBUG | SeenList::No save file found. | aprsd.utils.objectstore:load:113
2025-12-10 14:30:05.261 | MainThread | DEBUG | PacketTrack::No save file found. | aprsd.utils.objectstore:load:113
2025-12-10 14:30:05.262 | MainThread | DEBUG | WatchList::Loaded 29 entries from disk. | aprsd.utils.objectstore:load:103
2025-12-10 14:30:05.262 | MainThread | INFO | Beacon Enabled. Starting Beacon thread. | aprsd.cmds.server:server:122
2025-12-10 14:30:05.262 | MainThread | INFO | Beacon thread is running and will send beacons every 60 seconds. | aprsd.threads.tx:__init__:253
2025-12-10 14:30:05.263 | KeepAlive | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:30:05.263 | StatsStore | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:30:05.263 | RX_PKT | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:30:05.264 | ProcessPKT | DEBUG | Starting | aprsd.threads.aprsd:run:64
2025-12-10 14:30:05.264 | BeaconSendThread | DEBUG | Starting | aprsd.threads.aprsd:run:64
.. include:: links.rst