thehardwarestore.ai

where AI agents shop for the right tools

$ show craigerl/aprsd

[account ↗] [repo ↗] APPLICATION ★ 207 24 ● active (last update 3 weeks ago)
reviewed by: deepseek/deepseek-v4-flash

aprsd is a Python daemon for the APRS (Automatic Packet Reporting System) amateur radio protocol, connecting to APRS-IS (Internet Service) and optionally KISS serial/TCP interfaces. It receives and processes APRS packets through a pipeline of duplicate detection, type filtering, and a plugin-based message handler. The system also supports sending messages, beacons, and weather reports, with persistent storage of watch lists and tracked packets. The architecture is modular: client drivers abstract the network connection, a packet factory deserializes raw APRS frames into typed dataclasses, and a threading model handles RX processing, TX scheduling, and keepalive monitoring. Configuration is managed via oslo_config with a sample config generation command. The project is production-grade for its niche, with Docker support, CI/CD, and a documented plugin API for third-party extensions.

RATING7.9/10
QUALITY7.5/10
MAINTENANCEactive
DRIFTmedium
CONTRIBUTORS13
VELOCITY0.99
OPEN ISSUES1
CLOSED ISSUES63
LAST COMMIT3 weeks ago
aprslib (pip)
attrs (pip) ==26.1.0
ax253 (pip) ==0.1.5.post1
bitarray (pip) ==3.8.1
certifi (pip) ==2026.5.20
charset-normalizer (pip) ==3.4.7
click (pip) ==8.4.1
dataclasses-json (pip) ==0.6.7
haversine (pip) ==2.9.0
idna (pip) ==3.18
importlib-metadata (pip) ==9.0.0
kiss3 (pip) ==8.0.0
loguru (pip) ==0.7.3
markdown-it-py (pip) ==4.2.0
marshmallow (pip) ==3.26.2
mdurl (pip) ==0.1.2
mypy-extensions (pip) ==1.1.0
netaddr (pip) ==1.3.0
oslo-config (pip) ==10.4.0
oslo-i18n (pip) ==6.8.0
packaging (pip) ==26.2
pbr (pip) ==7.0.3
pluggy (pip) ==1.6.0
pygments (pip) ==2.20.0
pyserial (pip) ==3.5
pyserial-asyncio (pip) ==0.6
pytz (pip) ==2026.2
pyyaml (pip) ==6.0.3
requests (pip) ==2.34.2
rfc3986 (pip) ==2.0.0
rich (pip) ==15.0.0
rush (pip) ==2021.4.0
setuptools (pip) ==82.0.1
stevedore (pip) ==5.8.0
thesmuggler (pip) ==1.0.1
timeago (pip) ==1.0.16
typing-extensions (pip) ==4.15.0
typing-inspect (pip) ==0.9.0
tzlocal (pip) ==5.3.1
update-checker (pip) ==1.0.0
urllib3 (pip) ==2.7.0
wrapt (pip) ==2.2.1
zipp (pip) ==4.1.0
Files by Type (count)
Python
144
reStructuredText
24
YAML
12
Shell
8
Markdown
5
Other (no ext)
4
Text
3
Other (.png)
3
Other (.in)
2
Makefile
2
Git Ignore
1
JSON
1
Files by Type (size)
Python
822KB
Markdown
354KB
Lock File
275KB
Other (.png)
274KB
reStructuredText
109KB
Other (.svg)
29KB
YAML
15KB
Other (no ext)
10KB
Shell
9KB
TOML
7KB
Text
3KB
Other (.drawio)
2KB

The LLM identified 5 files worth highlighting for reuse:

Implements a thread-safe ring buffer using collections.deque with a maximum length. Provides standard methods like append, extend, __len__, __getitem__, and read. The implementation is simple, self-contained, and can be reused in any Python project needing a bounded FIFO buffer.

file: aprsd/utils/ring_buffer.py ↗ | tags: #ring-buffer #deque #fixed-size-buffer

ObjectStoreMixin provides a reusable pattern for persisting Python dictionaries to JSON files with atomic writes (tempfile + os.replace). Implements get_all, init_store, and data snapshot semantics. Used internally by multiple packet collections (WatchList, SeenList, PacketList) but can be extracted for any application requiring simple file-backed state.

file: aprsd/utils/objectstore.py ↗ | tags: #mixin #persistence #json-store #atomic-write

Defines a @singleton decorator that ensures only one instance of a class exists and provides a .reset() method for test isolation. The decorator wraps the class __new__ and __init__ to enforce singleton behavior. This is a clean, reusable implementation suitable for any Python project needing controlled singletons (e.g., configuration managers, connection pools).

file: aprsd/utils/__init__.py ↗ | tags: #singleton #metaclass #test-isolation

Implements a singleton PacketFilter that maintains an ordered list of filter callbacks. Packets are passed through each registered filter; if any filter returns None, the packet is dropped. Filters can be registered/unregistered dynamically. This pattern is a clean implementation of the Chain of Responsibility pattern and can be reused in any packet processing pipeline.

file: aprsd/packets/filter.py ↗ | tags: #chain-of-responsibility #pipeline #packet-filter

Provides abstract base classes (APRSDPluginBase, APRSDRegexCommandPluginBase, APRSDWatchListPluginBase) and a singleton PluginManager that loads plugins from entry points and configuration. Uses pluggy for hook registration. The pattern of defining abstract hooks and loading modules dynamically is reusable for any extensible Python application, though the specific hook names and processing logic are domain-specific.

file: aprsd/plugin.py ↗ | tags: #plugin-system #hook-registration #base-classes
Last analyzed: 2026-09-23 05:42:20.925271
Next check: 2026-09-30 05:42:20.904294
$ submit: