APRSMon: Build N4MI’s ESP32-S3 AMOLED APRS and Weather Station Monitor

TL;DR: APRSMon by Dan Marshall (N4MI) is an open source amateur radio desk instrument built on the LilyGO T-Encoder Pro (ESP32-S3, 390×390 round AMOLED display, and rotary encoder). Serving as the local situational counterpart to PropMon, APRSMon answers “What is happening in my local operating area right now?” By pairing an on-device rotary interface with a two-container Docker backend, APRSMon connects directly to APRS-IS with a 20-mile radius filter to track active mobile stations (vehicles and handhelds), polls the aprs.fi API for local automated weather stations, and monitors local station telemetry (including N4MI’s home Tempest CWOP node N4MI-13). Featuring five dedicated screens, an ambient storm/wind alert banner, and on-device captive portal Wi-Fi setup, APRSMon delivers neighborhood VHF/APRS awareness straight to the operating bench.


What Is APRSMon?

APRSMon is an open source amateur radio desk instrument built on the LilyGO T-Encoder Pro that displays local APRS mobile station activity, nearby weather station telemetry, and severe environmental alerts on a 390×390 round AMOLED screen using a physical rotary encoder.

APRSMon sitting in the ham shack alongside its sibling instruments, displaying local APRS mobile movement and weather telemetry on a circular AMOLED display.
+-----------------------------------------------------------------------------------------+
|                                  APRSMON SYSTEM TOPOLOGY                                |
+-----------------------------------------------------------------------------------------+

 [ External Networks & APIs ]           [ Local Docker Microservices ]       [ Ham Shack Display ]
 ┌────────────────────────┐              ┌──────────────────────────┐         ┌────────────────────────┐
 │ APRS-IS Global Network │              │ aprsmon_mobile (Port 8077│         │ LilyGO T-Encoder Pro   │
 │ Direct TCP Stream      │ ──TCP:14580► │ - Persistent socket conn │         │ (ESP32-S3 + 8MB PSRAM) │
 └────────────────────────┘ (aprslib)    │ - 20-mile radius filter  │         │                        │
                                         │ - Moving vehicle detector│         │ 390x390 Round AMOLED   │
 ┌────────────────────────┐              │ - Rolling 1-hour count   │         │ (CO5300 Controller)    │
 │ aprs.fi REST API       │              └────────────┬─────────────┘         │                        │
 │ Local Weather Stations │ ──HTTP/REST─┐             │ Flat JSON             │ 5 Rotary Knob Screens: │
 └────────────────────────┘             │             ▼                       │ 1. Overview Dashboard  │
                                        │ ┌──────────────────────────┐        │ 2. Weather Station WX  │
 ┌────────────────────────┐             └►│ aprsmon_server(Port 8078│◄──Wi-Fi─│ 3. Mobile Activity    │
 │ N4MI-13 Home Tempest   │               │ - aprs.fi 10m API poller │        │ 4. Threshold Alerts    │
 │ CWOP / APRS Beacon     │ ──HTTP───────►│ - Unit conversions       │        │ 5. Config & Liveness   │
 └────────────────────────┘               │ - Wind/Rain thresholds   │        │                        │
                                          │ - N4MI-13 watchdog check │        │ Ambient Alert Banner & │
                                          └──────────────────────────┘        │ Captive Wi-Fi Portal   │
                                                                              └────────────────────────┘

The Automatic Packet Reporting System (APRS), created by Bob Bruninga (WB4APR), is one of amateur radio’s most versatile technologies. Operating primarily on 144.390 MHz in North America (and 144.800 MHz in Europe, 144.390 MHz in Malaysia), APRS networks carry position beacons, telemetry, tactical messages, and localized weather observations.

In a typical ham shack, monitoring local APRS traffic requires running specialized desktop client software (such as YAAC, APRIS, or PinPoint APRS), leaving an open web browser pointing at aprs.fi, or staring at a dedicated packet radio terminal.

While these tools are powerful, they demand desktop real estate and user attention. Most hams do not need a full geographic map open while soldering, operating HF CW, or building an antenna. What they need is simple situational awareness: Is the local VHF group out mobile? Did a sudden rain squall hit the local repeater ridge? Has my home weather station stopped beaconing to the network?

Dan Marshall (N4MI) created APRSMon as the second instrument in the N4MI Desktop Instrument Series. APRSMon adopts the identical hardware platform as PropMon (the LilyGO T-Encoder Pro), but pivots from global HF ionospheric propagation to local VHF tactical awareness.


APRSMon vs Traditional APRS Monitoring Solutions

To see how APRSMon fits into the amateur radio shack, let us examine how it contrasts with standard APRS tools:

Monitoring Solution Hardware Form Factor Display Type & Technology Always-On Reliability Focus & Scope of Data Weather Alerts Cognitive Overhead
APRSMon (N4MI) Dedicated Desk Dial (T-Encoder) 390×390 Round AMOLED (CO5300) 100% Always On (Docker Microservices) Hyper-Local 20-Mile Radius & Local WX Wind, Rain, & Watchdog Zero (At-a-Glance)
Web aprs.fi Map (Web Browser) Desktop PC / Tablet PC Monitor / Browser Tab (LCD) Low (Tied to PC / Browser Sleep) Worldwide Map View (Visual Clutter) Raw WX Graphs Only High (Map Nav & Zooming)
Desktop Mapping (YAAC / PinPoint) Primary PC Workstation Large Multi-Monitor App Window Medium (Must Keep App Running) Full Packet Decoding, TNC Messaging Audio Alarms High (Complex Setup)
Radio Screen (Kenwood / Yaesu) APRS HT / Mobile Rig (D710/FT5D) Transceiver Display (Monochrome) High (When Rig Powered) Raw Single-Packet Text Line Station Beacon Lines Low (Single Line Only)
Dedicated TNC Box (Direwolf / Digirig) External Box / Headless Pi No Screen (Terminal) High (TNC Daemon) Packet Forwarding / Digipeat None High (Raw CLI)

While map-based tools like aprs.fi provide exhaustive spatial tracking, APRSMon distills that river of packets into operational essentials. Positioned directly beside your VHF/UHF rig, it serves as an ambient neighborhood compass.


Dual Microservice Architecture: Isolating Socket and REST Lifecycles

APRSMon separates its backend workload into two independent Docker containers running on a home server or NAS.

This architecture addresses a key operational distinction: polling a third-party REST API on a timer requires completely different connection management than maintaining an open, real-time TCP socket to the APRS-IS backbone.

+─────────────────────────────────────────────────────────────────────────────────────────+
|                               APRSMON BACKEND ARCHITECTURE                              |
+─────────────────────────────────────────────────────────────────────────────────────────+

  [ APRS-IS Core Server ]
           │
           │ Persistent TCP Stream (Port 14580, aprslib)
           ▼
  ┌───────────────────────────────────────────────────────────┐
  │ aprsmon_mobile (Container Port 8077)                      │
  │ - Connects via aprslib with filter: r/33.4504/-82.1981/32 │
  │ - Parses incoming position packets in real time           │
  │ - Filters for moving targets (speed > 0 or vehicle symbols)
  │ - Buffers 1-hour active station count & last 3 callsigns  │
  │ - Exposes /api/mobile/recent and /api/mobile/hourly       │
  └─────────────────────────────┬─────────────────────────────┘
                                │ JSON Over LAN
                                ▼
  ┌───────────────────────────────────────────────────────────┐
  │ LilyGO T-Encoder Pro (Firmware UI Engine)                 │
  │ - Polls aprsmon_server and aprsmon_mobile independently   │
  │ - Seamlessly merges weather metrics and mobile positions  │
  │ - Evaluates threshold alerts (gust, rain, silence)        │
  │ - Renders circular AMOLED UI with 10-second idle return   │
  └─────────────────────────────▲─────────────────────────────┘
                                │ JSON Over LAN
                                │
  ┌───────────────────────────────────────────────────────────┐
  │ aprsmon_server (Container Port 8078)                      │
  │ - Periodic cron poller for aprs.fi REST API (10 min timer)│
  │ - Queries 2 fixed local station callsigns (ENMVJD, KC5DDG)│
  │ - Parses temperature, pressure, humidity, wind, and rain  │
  │ - Monitors N4MI-13 CWOP liveness watchdog                 │
  │ - Converts raw metric units to station imperial standards │
  └─────────────────────────────▲─────────────────────────────┘
                                │ HTTPS API Query (10 min)
                                │
  [ aprs.fi Public REST API ] ──┘

1. The Mobile Activity Service (aprsmon_mobile.py)

The mobile activity monitor connects directly to APRS-IS (Automatic Packet Reporting System-Internet Service) on port 14580 using the Python aprslib library:

  • Targeted Geofencing: Instead of listening to the global firehose of thousands of packets per second, it sets a server-side radial filter: r/LAT/LON/32 (a 32 km / 20-mile radius around the home QTH).
  • Moving Target Discrimination: APRS is filled with stationary digipeaters, weather stations, and club beacons. aprsmon_mobile inspects speed metrics and SSID/symbol flags, filtering exclusively for stations that are genuinely moving or mobile.
  • Rolling Analytics: It maintains a thread-safe sliding window tracking how many unique mobile stations were heard in the past 60 minutes, alongside detailed records for the last three heard stations (callsign, speed, bearing, and timestamp).

2. The Weather Ingestion Service (aprsmon_server.py)

The weather service handles scheduled environmental tracking:

  • aprs.fi REST API Compliance: To respect public API rate limits, it polls aprs.fi on a strict 10-minute timer.
  • Dual Station Pairing: Rather than generic zip-code forecasts, it queries two specific, known local weather stations: a primary station and a secondary verification station.
  • Imperial Metric Normalization: It converts raw Unix timestamps to ISO 8601 UTC and parses temperature (F), barometric pressure (inHg), relative humidity (%), wind speed, wind gusts, and 1-hour rainfall.
  • Station Liveness Watchdog: Dan Marshall operates his own on-site WeatherFlow Tempest weather station, beaconed into the Citizen Weather Observer Program (CWOP) and APRS as N4MI-13. The backend continuously tracks the age of N4MI-13‘s beacons. If the station goes silent for more than 45 minutes, it flags a watchdog failure.

Hardware Specifications: LilyGO T-Encoder Pro

Like its sibling PropMon, APRSMon runs on the LilyGO T-Encoder Pro.

+─────────────────────────────────────────────────────────────────────────────────────────+
|                       LILYGO T-ENCODER PRO HARDWARE PROFILE                             |
+─────────────────────────────────────────────────────────────────────────────────────────+

  Microcontroller:    Espressif ESP32-S3 (Xtensa Dual-Core 32-bit LX7 @ 240 MHz)
  Memory:             512 KB SRAM, 16 MB Flash, 8 MB Octal PSRAM (OPI)
  Display Panel:      1.4-inch Round AMOLED Display (True Circular Viewport)
  Resolution:         390 x 390 Pixels (High Pixel Density, Deep Blacks)
  Display Driver:     CO5300 (or legacy SH8601) via QSPI Bus
  Rotary Input:       24-Detent Incremental Rotary Encoder with Push Button
  Wireless:           2.4 GHz Wi-Fi (802.11 b/g/n) and Bluetooth 5.0 LE
  Power Interface:    USB Type-C Connector
  Idle Management:    Automatic 10-Second Return to Overview Screen

The circular AMOLED display is suited for radial gauges and dial instruments. By placing the physical rotary encoder directly around the perimeter of the screen, navigation feels natural: twisting the dial flips between screens, while pressing the center knob triggers secondary actions.


The 5-Screen Interface Tour

APRSMon features five distinct screens, engineered to deliver clear information within a circular 390×390 viewport.

+-----------------------------------------------------------------------+
|                         APRSMON DISPLAY SCREENS                       |
+-----------------------------------------------------------------------+

        [ OVERVIEW ]                     [ WEATHER ]
      ┌──────────────┐                 ┌──────────────┐
      │  LOCAL APRS  │                 │ PRIMARY: WX  │
      │ 78°F   64% RH│                 │ 78.4°F       │
      │ RAIN: 0.14"/h│                 │ 64% RH  29.98│
      │ LAST MOBILE: │                 │ GUST: 18 MPH │
      │   W4XYZ-9    │                 │ (PRESS: SWAP)│
      └──────────────┘                 └──────────────┘

         [ MOBILE ]                      [ ALERTS ]
      ┌──────────────┐                 ┌──────────────┐
      │ MOBILE (1H)  │                 │ ! WIND GUST! │
      │  4 STATIONS  │                 │ PEAK: 42 MPH │
      │ MOST RECENT: │                 │ N4MI-13 OK   │
      │   K4ABC-9    │                 │              │
      │  35 MPH  NE  │                 │ ALL CLEAR    │
      └──────────────┘                 └──────────────┘

                         [ CONFIG ]
                       ┌──────────────┐
                       │ WI-FI: HOME  │
                       │ IP: .1.105   │
                       │ WX AGE: 4m   │
                       │ MOB AGE: 12s │
                       │ N4MI-13: LIVE│
                       └──────────────┘

1. Screen 1: The Overview (The Default State)

APRSMon Overview screen showing temperature, humidity, rain alert, and last mobile callsign
The Overview screen: combines primary station temperature, relative humidity, active rain callouts, and the most recent mobile station heard.

The Overview screen serves as the front door of your local station:

  • Primary Environmental Telemetry: Large, high-visibility temperature and humidity readouts from your primary local weather station.
  • Active Rain Callout: When dry, rain metrics remain hidden to avoid screen clutter. When measurable precipitation occurs, an amber or cyan callout box appears showing rainfall rate (e.g., RAIN: 0.18 in/hr).
  • Most Recent Mobile Station: Displays the callsign of the most recently heard moving mobile station within your 20-mile radius, along with the time elapsed since reception.

2. Screen 2: Dedicated Weather Station Telemetry

APRSMon Weather screen displaying full telemetry from local weather stations
The Weather screen: full meteorological telemetry including temperature, pressure, wind gusts, and instant primary/secondary station swapping.

Rotating the dial one click brings up the Weather screen:

  • Displays comprehensive meteorological observations: temperature, relative humidity, barometric pressure, wind direction, sustained wind speed, and peak wind gusts.
  • Short-Press Station Swap: Pressing the knob instantly toggles between your Primary weather station and your Secondary confirmation station, allowing quick cross-checks during shifting weather patterns.

3. Screen 3: Mobile Activity Feed

APRSMon Mobile Activity screen showing 1-hour active station count and recent mobile stations
The Mobile Activity screen: 1-hour rolling station count, most recent target with road speed, and short-press access to the last 3 heard stations.

Rotating to Screen 3 reveals VHF movement in your community:

  • 1-Hour Rolling Activity Count: Shows how many distinct mobile vehicles, handhelds, or tracking beacons have transited your area over the past hour.
  • Most Recent Heard Target: Detailed callsign, road speed (mph), and heading direction.
  • Short-Press Recent Stations View: Pressing the knob switches the display to a 3-row historical list of the last three distinct stations heard on the air.

4. Screen 4: Threshold Alerts and Station Watchdog

Screen 4 aggregates physical station safety triggers:

  • Wind Gust Alerts: Flags conditions when local wind speeds cross pre-set safety thresholds (e.g., gusts exceeding 35 mph).
  • Rain Rate Alarms: Alerts when convective storm cells trigger extreme precipitation.
  • N4MI-13 Watchdog Status: Confirms whether your home CWOP station is actively beaconing or has gone silent.
  • ALL CLEAR State: When all parameters are within nominal safety envelopes, the screen displays a tranquil green ALL CLEAR banner.

5. Screen 5: Configuration & Backend Liveness

APRSMon Configuration screen showing Wi-Fi IP and backend freshness age
The Configuration screen: connection diagnostics, IP address, data freshness ages, and home station beacon health.

Holding the knob for two seconds from any screen opens the Config screen:

  • Displays current Wi-Fi SSID, RSSI signal strength, and assigned LAN IP address.
  • Shows independent liveness indicators and data freshness ages for both the aprsmon_server and aprsmon_mobile Docker services.
  • Shows the exact beacon timestamp of your personal station (N4MI-13).

Automatic 10-Second Idle Return

If you twist the knob to inspect Weather or Mobile Activity while operating, you do not need to twist it back. An automated 10-second idle timer gently returns the display to the Overview screen, ensuring the instrument always presents its primary dashboard when glanced at later.

Ambient Alert Banner Overlay

Just like PropMon, APRSMon features a global ambient alert system:

  • If a severe wind gust or high rain rate is detected, a high-contrast banner slides across the top third of the display for several seconds, regardless of which screen is active.
  • A persistent warning badge remains in the header until conditions drop back below alert thresholds.

On-Device Wi-Fi Setup via Captive Portal

APRSMon on-device captive portal Wi-Fi setup screen
On-device Wi-Fi Setup: opens an access point for phone onboarding, storing credentials in ESP32 NVS without code modification.

APRSMon incorporates the same on-device captive portal engine as PropMon:

+─────────────────────────────────────────────────────────────────────────────────────────+
|                           CAPTIVE PORTAL ON-BOARDING WORKFLOW                           |
+─────────────────────────────────────────────────────────────────────────────────────────+

  [ LilyGO Dial ]                    [ Network Subsystem ]              [ User Smartphone ]
  ┌──────────────────┐               ┌──────────────────┐               ┌──────────────────┐
  │ Operator holds   │               │ Starts softAP    │               │ Phone connects to│
  │ knob for >3 sec  │ ────────────► │ "APRSMon-Setup"  │ ────────────► │ "APRSMon-Setup"  │
  └──────────────────┘               └──────────────────┘               └────────┬─────────┘
                                                                                 │
                                                                                 ▼
  ┌──────────────────┐               ┌──────────────────┐               ┌──────────────────┐
  │ Reboots and      │               │ Writes SSID &    │               │ Web portal opens;│
  │ joins home Wi-Fi │ ◄──────────── │ Password to NVS  │ ◄──HTTP POST─ │ selects SSID and │
  └──────────────────┘               └──────────────────┘               │ inputs password  │
                                                                        └──────────────────┘

Holding the rotary knob down past the Config screen trigger (~3 seconds total) activates the captive portal:

  1. The device starts an open software Access Point named APRSMon-Setup.
  2. A captive DNS intercept opens the setup page on connecting smartphones.
  3. The user picks their local Wi-Fi SSID from the scanned list and inputs the password.
  4. The credentials are encrypted into ESP32 NVS, and the device restarts directly onto your home network.

Step-by-Step Build and Deployment Guide

Phase 1: Deploying the Docker Backend Services

Unlike PropMon, APRSMon’s firmware and server code reside in the same repository under firmware/ and server/.

Step 1: Deploy aprsmon_server (Weather)

Create a directory on your server and deploy the weather container:

version: "3.8"

services:
  aprsmon-weather:
    build:
      context: https://github.com/N4MI73/n4mi-aprs-monitor.git#main:server
      dockerfile: Dockerfile
    container_name: aprsmon-weather
    restart: unless-stopped
    ports:
      - "8078:8078"
    environment:
      - PORT=8078
      - APRSFI_API_KEY=your_aprsfi_api_key_here # Get from aprs.fi
      - PRIMARY_WX_CALL=ENMVJD                  # Primary weather station
      - SECONDARY_WX_CALL=KC5DDG                # Secondary weather station
      - WATCHDOG_CALL=N4MI-13                   # Personal station callsign

Step 2: Deploy aprsmon_mobile (Mobile Activity)

Create the mobile tracking container configuration:

version: "3.8"

services:
  aprsmon-mobile:
    build:
      context: https://github.com/N4MI73/n4mi-aprs-monitor.git#main:server
      dockerfile: Dockerfile.mobile
    container_name: aprsmon-mobile
    restart: unless-stopped
    ports:
      - "8077:8077"
    environment:
      - PORT=8077
      - APRS_CALLSIGN=YOUR_CALLSIGN             # Your amateur callsign
      - APRS_PASSCODE=YOUR_PASSCODE             # Standard APRS-IS passcode
      - HOME_LAT=33.4504                        # Station latitude
      - HOME_LON=-82.1981                       # Station longitude
      - RADIUS_KM=32                            # 32 km ~= 20 miles

Launch both containers:

docker compose -f docker-compose-weather.yml up -d
docker compose -f docker-compose-mobile.yml up -d

Verify that aprsmon-mobile establishes its connection to APRS-IS:

docker logs -f aprsmon-mobile

You should see: Connected to APRS-IS with filter: r/33.4504/-82.1981/32.


Phase 2: Building and Flashing the Hardware

1. Clone the repository:

git clone https://github.com/N4MI73/n4mi-aprs-monitor.git
cd n4mi-aprs-monitor

2. Open the firmware/ subdirectory in VS Code (do not open the repo root, or PlatformIO will not detect platformio.ini).

3. Open include/config.h and point the firmware to your Docker server’s IP address:

#pragma once

#define WEATHER_HOST "192.168.1.50"
#define WEATHER_PORT 8078
#define WEATHER_PATH "/api/weather"

#define MOBILE_HOST "192.168.1.50"
#define MOBILE_PORT 8077
#define MOBILE_PATH "/api/mobile"

4. Connect your LilyGO T-Encoder Pro to your computer via USB-C.

5. Compile and flash the firmware:

platformio run -t upload

6. Open the serial console:

platformio device monitor -b 115200

7. Use the on-device captive portal to connect the instrument to your home Wi-Fi network.


The N4MI Desktop Instrument Triad

+─────────────────────────────────────────────────────────────────────────────────────────+
|                              THE N4MI DESK INSTRUMENT TRIAD                             |
+─────────────────────────────────────────────────────────────────────────────────────────+

  ┌─────────────────────────┐   ┌─────────────────────────┐   ┌─────────────────────────┐
  │         PROPMON         │   │         APRSMON         │   │         DXMON           │
  │   (Propagation Unit)    │   │      (Activity Tracker) │   │      (DX Hunter)        │
  ├─────────────────────────┤   ├─────────────────────────┤   ├─────────────────────────┤
  │ Round AMOLED / Rotary   │   │ Round AMOLED / Rotary   │   │ 4.3" Capacitive Touch   │
  │ "Can I make the contact?│   │ "What's around me?"     │   │ "Is my target active?"  │
  │ Solar Flux, K-index,    │   │ Local weather, APRS     │   │ Watched DXpeditions,    │
  │ Band Conditions (160-6m)│   │ beacons, mobile count   │   │ Needed DXCC, Azimuth    │
  └────────────┬────────────┘   └─────────────────────────┘   └────────────▲────────────┘
               │                                                           │
               └─────────────── PropMon Propagation API Link ──────────────┘

By completing both PropMon and APRSMon, Dan Marshall established the foundation of his shack instrument philosophy:

  • PropMon looks up into the ionosphere.
  • APRSMon looks out across the local community.
  • DXMon tracks priority target expeditions.

Each unit runs silently, consumes negligible electricity, requires zero operating system maintenance, and presents actionable data at a glance.


Frequently Asked Questions (FAQ)

What hardware platform does APRSMon require?

APRSMon runs on the LilyGO T-Encoder Pro, equipped with an ESP32-S3 microcontroller, 8MB PSRAM, a 390×390 circular AMOLED display, and a 24-detent rotary encoder with a push-button switch.

Why does APRSMon use two separate Docker containers?

APRSMon divides its backend into two microservices because maintaining a continuous TCP socket to APRS-IS has completely different failure modes than polling the aprs.fi REST API on a 10-minute timer. Isolating them prevents a socket reconnection from disrupting weather polling.

How does APRSMon avoid showing stationary digipeaters?

The aprsmon_mobile backend inspects the speed metric and symbol attributes of incoming APRS packets, filtering specifically for stations with speed greater than zero or mobile vehicle symbol designations within its 20-mile radial geofence.

What is the purpose of the 10-second idle timeout?

If you rotate the dial to inspect Weather details or review the Mobile station history, the firmware automatically returns to the primary Overview screen after 10 seconds of inactivity, ensuring the core dashboard is always visible at a glance.

What happens if my home weather station stops beaconing?

APRSMon incorporates an internal watchdog for personal station beacons (like N4MI-13). If no packet is received for 45 minutes, the Config and Alert screens highlight the failure, prompting you to check station power or gateway connectivity.


Sources and Further Reading


73 de 9M2PJU

Post Comment