Skip to content

Feed Meshtastic GPS into observer-location fallback chain - #248

Closed
Poid-ZA wants to merge 5 commits into
smittix:mainfrom
Poid-ZA:feat/meshtastic-gps-observer-location
Closed

Poid-ZA wants to merge 5 commits into
smittix:mainfrom
Poid-ZA:feat/meshtastic-gps-observer-location

Conversation

@Poid-ZA

@Poid-ZA Poid-ZA commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds an external-position fallback slot to utils/gps.py (set_external_position/get_external_position), consulted by get_current_position() only when no gpsd client has a live fix — gpsd remains authoritative whenever present.
  • utils/meshtastic.py forwards the local node's own POSITION_APP reports into that slot (_is_local_node guards against any mesh peer's position ever being mistaken for the observer's own location).
  • Result: a Meshtastic-attached GPS (e.g. Heltec T114) automatically feeds INTERCEPT's existing observer-location chain (_get_observer_location(): gpsd -> external -> config -> hardcoded default) used by ADS-B range rings and other location-aware features — no separate gpsd-speaking receiver required.

Stacked on #247 — this branch is built on top of feat/cot-export so the two features don't collide in the same POSITION_APP handling block. Please land #247 first; this PR's diff will settle down to just the GPS-forwarding commit once that happens.

Test plan

  • pytest tests/test_gps.py tests/test_meshtastic.py tests/test_cot.py tests/test_system.py tests/test_bt_locate.py — 91 passed
  • New tests/test_gps.py covers: no source available, external-only, gpsd-priority-over-external, external-fallback-when-gpsd-client-has-no-fix
  • New TestMeshtasticOwnNodeGpsFeedsObserverLocation in tests/test_meshtastic.py covers own-node forwarding and confirms peer-node positions are never forwarded
  • Deployed and verified importable on both the on-box server checkout and the Pi (192.168.200.28, the actual Heltec-T114-equipped device)

🤖 Generated with Claude Code

Closes smittix#179. Publishes decoded ADS-B, AIS, and APRS position events as
CoT XML to a configured UDP/TCP destination (defaults to the ATAK SA
multicast group 239.2.3.1:6969, or point it at a TAK Server), following
the same optional/env-gated export pattern already used by the MQTT
export (utils/mqtt.py): disabled by default, no external dependency,
hooked into the shared event pipeline so all three modes get it for
free.

New env vars: INTERCEPT_COT_HOST (unset = disabled), INTERCEPT_COT_PORT,
INTERCEPT_COT_PROTO, INTERCEPT_COT_STALE_SECONDS.
Meshtastic was the only mode not wired into the shared event pipeline
(no alerts, recording, MQTT, or now CoT). This hooks POSITION_APP
packet handling into utils.event_pipeline.process_event(), the same
call already made for ADS-B/AIS/APRS, and adds a "meshtastic" entry to
cot.py's mode map (CoT type a-f-G-U-C, uid MESH-<node id>).

Position updates from mesh nodes now flow through the same
alerts/recording/MQTT/CoT infrastructure as every other mode, so a
Meshtastic node with GPS (e.g. the Heltec T114) shows up on
ATAK/WinTAK alongside tracked aircraft/vessels/APRS stations when CoT
export is enabled.
The Heltec T114 attached to the Pi's Meshtastic node reports its own
position via POSITION_APP packets. Forward that position into
utils/gps.py's external-position slot so _get_observer_location()
(gpsd -> external -> config -> hardcoded default) picks it up
automatically for ADS-B range rings and any other observer-location
consumer, without requiring a separate gpsd-speaking GPS receiver.

Only the local node's own position is ever forwarded (_is_local_node
guards against any mesh peer's position corrupting the observer
location); gpsd remains authoritative whenever a real fix is present.
InterceptTime's global timezone preference only offered UTC, browser-local,
or US zones -- no way to select SAST, and it defaulted to US/Eastern. Added
Africa/Johannesburg (labelled SAST) as a selectable option and made it the
default, since this deployment and its primary user are South Africa-based.

Also fixed two clocks that bypassed InterceptTime entirely and hardcoded raw
UTC display regardless of user preference:
- map-utils.js's per-map HUD clock (top-right overlay)
- gps.js's GPS-fix timestamp readouts (sidebar + visuals panel)

Both now show the user's configured local time (SAST by default) with UTC
appended for reference, rather than UTC-only. templates/layout/base.html's
header clock (currently unused by any route, but defensively) was updated
the same way for consistency.
…popups

Surfaces Position.sats_in_view (already sent by the device, previously
unparsed) alongside the existing lat/lon/altitude fields: MeshNode and
NodeInfo gain a sats_in_view field, populated from both the live
POSITION_APP packet handler and the nodeDB interface-sync path. Frontend
shows it as a SATS stat in the local-node status strip and a Sats: line
in each node's map popup.
@smittix

smittix commented Sep 23, 2026

Copy link
Copy Markdown
Owner

Thanks for this — and for splitting it up afterwards, which is what makes it easy to act on.

This branch is the stacked version of work that now exists as three focused PRs. Comparing them:

PR Commits
#247 59530b3 CoT export, 6901c0c Meshtastic positions in CoT
#250 SAST timezone
#251 a401c56 observer-location fallback, 1049e8d satellite count

This PR carries all five of those commits, and its 15 changed files are exactly the union of the other three — nothing here is missing from them. #251's commits are the same content as this branch's 92673c0/ec29269, rebased onto main.

So I'm closing this one as superseded, and reviewing #247, #250 and #251 individually — each is far easier to assess on its own merits than the stack is. Review notes are going on each of them now.

Nothing is lost by this; if you think something in here isn't covered by the other three, say so and I'll reopen.

@smittix smittix closed this Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants