feat: APRS local RF integration — display TNC data alongside APRS-IS#845
Conversation
- rig-bridge/aprs-tnc: forward received packets directly to the local
OHC server's /api/aprs/local (fire-and-forget, configurable via
aprs.localForward and aprs.ohcUrl). Disable when using cloud-relay
to avoid duplicate injection on the cloud server.
- rig-bridge/config: add localForward and ohcUrl defaults to aprs
section; bump CONFIG_VERSION to 7.
- server/aprs: expose `source` field on every station in the
GET /api/aprs/stations response; apply RF-wins dedup so internet
updates don't strip the `local-tnc` tag from stations heard over RF;
fix /api/aprs/local to key by ssid (consistent with APRS-IS path);
add GET /api/aprs/tnc-status proxy endpoint.
- useAPRS: add sourceFilter ('all'|'internet'|'rf') state that feeds
into filteredStations; poll /api/aprs/tnc-status every 10s; expose
tncConnected and hasRFStations.
- APRSPanel: add Source selector row (All / Internet / Local RF) with
TNC live indicator dot; show green "RF" badge on locally-heard stations.
- WorldMap: render local-tnc stations in green (#4ade80) to distinguish
them from internet stations (cyan) and watched stations (amber); add
RF label in popup.
- themes.css: add --color-aprs-rf variable across all four themes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@accius please leave that for a while I'm testing this still. It is just for reference to let you know I'm working on it. But you can already let me know if the implementation would suit you also. |
Three bugs when APRS_ENABLED is not set in .env: 1. Station cleanup interval skipped entirely, so RF packets injected via /api/aprs/local would pile up in memory and never be evicted. Fix: remove the APRS_ENABLED guard — cleanup always runs. 2. GET /api/aprs/stations returned enabled:false even when local TNC stations were present. The panel then showed "APRS Not Enabled" and blocked all data. Fix: add tncActive flag (true when any local-tnc station is cached); useAPRS sets aprsEnabled=true when either enabled or tncActive is true. 3. APRSPanel "disabled" message only mentioned APRS_ENABLED=true, making the rig-bridge TNC path invisible to users. Fix: updated message explains both paths (APRS-IS and local RF). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
APRSPanel was entirely missing react-i18next wiring. This commit adds
useTranslation and replaces every hardcoded English string with a t()
call, covering both the strings that pre-existed and the new ones added
in the local RF integration:
New keys (aprsPanel.*) added to en.json:
- disabled.{title,internetBefore,internetAfter,rfBefore,rfAfter,
filterBefore,filterAfter}
- source.{label,all,internet,rf,tncConnected,noRfData}
- groups.{title,description,newGroupPlaceholder,createButton,
callsignPlaceholder,selectGroup,addButton,deleteButton,noCallsigns}
- groupTab.{all,watchlist}
- groupsButton, groupsButtonTitle, mapOn, mapOff
- loading, noStations, noStationsFiltered, quickSearch, rfBadgeTitle
Other locale files will fall back to en.json until translators fill them in.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the 33 aprsPanel.* keys introduced in the previous commit to every non-English locale file: ca, de, es, fr, it, ja, ka, ko, ms, nl, pt, ru, sl, th, zh. Translated strings cover the full panel: disabled-state instructions (both APRS-IS and local RF paths), source selector (All / Internet / Local RF), watchlist group manager, map toggle, station list states, and the RF badge tooltip. Technical terms kept in English across all locales: APRS, APRS-IS, TNC, RF, EmComm, rig-bridge, .env. Locale-appropriate terms used for UI chrome (e.g. EIN/AUS in de, ВКЛ/ВЫКЛ in ru, 開/關 in zh). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@accius from my perspective ready to review now. |
|
Thanks for the solid work on this Jörg — merging as-is since the core functionality is sound, but here are improvements to address in follow-ups: Should fix soon
Nice to have
|
Summary
This PR bridges the gap between local RF APRS data (packets decoded by a TNC connected to rig-bridge) and the existing APRS-IS internet feed, letting operators display both sources side-by-side — or choose one exclusively — without any duplicate handling or source confusion.
What changed
rig-bridge —
aprs-tncpluginPOST /api/aprs/local(fire-and-forget, no retry).rig-bridge/core/config.js:aprs.localForward(defaulttrue) — set tofalsewhen using thecloud-relayplugin to avoid injecting the same packet twice on the cloud instance.aprs.ohcUrl(defaulthttp://localhost:8080) — the base URL of the OHC server to forward to.CONFIG_VERSIONbumped to7; existing configs without these keys are patched in automatically.Server —
server/routes/aprs.jsGET /api/aprs/stations: every station object now carriessource: 'local-tnc' | nullso the frontend can tell RF-heard stations from internet ones. AddedtncActive: truewhen at least onelocal-tncstation is cached — the panel activates from this flag even whenAPRS_ENABLED=false.source: 'local-tnc', a later APRS-IS update for the same SSID will not overwrite that tag. The RF origin is preserved for the lifetime of the station.POST /api/aprs/local: fixed station keying to usessid(consistent with the APRS-IS ingestion path); added the same RF-wins dedup logic here.GET /api/aprs/tnc-status: new endpoint that proxies the rig-bridge TNC status (host/port read fromCONFIG.rigControl). The browser never needs to know the rig-bridge port directly.if (!APRS_ENABLED) returnguard from the 60-second expiry interval. RF-injected stations are now correctly aged out even whenAPRS_ENABLEDis not set.Frontend —
src/hooks/useAPRS.jssourceFilter('all' | 'internet' | 'rf'),tncConnected,hasRFStations./api/aprs/tnc-status.filteredStationsnow applies the source filter first, then the group/watchlist filter.aprsEnabledis nowtruewhen eitherdata.enabled(APRS-IS) ordata.tncActive(local TNC) is set, so the panel opens in RF-only setups withoutAPRS_ENABLED=truein.env.Frontend —
src/components/APRSPanel.jsxAll,🌐 Internet,📡 Local RF. The RF button is greyed out when no RF stations are in cache; shows a pulsing green dot when the TNC is actively connected.source: 'local-tnc'shows a small greenRFchip next to the callsign.APRS_ENABLED=truefor internet spots, and enabling theaprs-tncplugin in rig-bridge for local RF — with no.envchange required.APRSPanelwas previously entirely un-localised. All 33 user-visible strings are now wired throughreact-i18next(t()), with translations provided for all 15 supported locales (see below).Frontend —
src/components/WorldMap.jsxvar(--color-aprs-rf)/#4ade80) on the map, distinct from internet stations (cyan) and watched stations (amber).RFlabel for locally-heard stations.Styles —
src/styles/themes.css--color-aprs-rfadded to all four themes (dark,light,retro,legacy).i18n —
src/lang/en.json: 33 newaprsPanel.*keys added (alphabetically, consistent with existing flat-key convention).ca,de,es,fr,it,ja,ka,ko,ms,nl,pt,ru,sl,th,zh): full translations provided for all 33 keys.APRS,APRS-IS,TNC,RF,EmComm,rig-bridge,.env) kept in English across all locales, which is standard in the ham radio community. Locale-appropriate terms used for UI chrome (EIN/AUSin de,ВКЛ/ВЫКЛin ru,开/关in zh, etc.).Files changed
rig-bridge/core/config.jsaprs.localForward,aprs.ohcUrldefaults;CONFIG_VERSION→ 7rig-bridge/plugins/aprs-tnc.jsserver/routes/aprs.jssource+tncActivein stations response; RF-wins dedup (both paths); cleanup guard removed;ssidkeying fix;/api/aprs/tnc-statusproxysrc/hooks/useAPRS.jssourceFilter,tncConnected,hasRFStations; TNC status poll;aprsEnabledfromtncActivesrc/components/APRSPanel.jsxreact-i18nextwiringsrc/components/WorldMap.jsxsrc/styles/themes.css--color-aprs-rfvariable across all four themessrc/lang/en.jsonaprsPanel.*keyssrc/lang/{ca,de,es,fr,it,ja,ka,ko,ms,nl,pt,ru,sl,th,zh}.jsonBehaviour matrix
APRS_ENABLED=true, no rig-bridgeAPRS_ENABLED=false, rig-bridge TNC activelocal-tnctag wins)Test plan
APRS_ENABLED=true, rig-bridge not running: panel opens, shows internet stations, "Local RF" button is greyed out, no errors in consoleAPRS_ENABLED=false, rig-bridge TNC active with Direwolf: panel opens (no "APRS Not Enabled" screen), RF packets appear with greenRFbadge, map shows green triangleslocal-tncstations shown; "Internet": only non-RF stations; "All": both combinedsource: 'local-tnc'(RF-wins dedup) — verify viaGET /api/aprs/stationsaprs.localForward: falsein rig-bridge config: TNC plugin no longer POSTs to OHC; cloud-relay path unaffectedAPRS_ENABLED=trueand no rig-bridge: no regression in panel behaviour, watchlist groups still workaprsPanel.*key showing rawnpm run buildpasses without new errors or warnings🤖 Generated with Claude Code