Skip to content

Add public Meshtastic node layer - #15

Open
Tom-Neverwinter wants to merge 2 commits into
bilawalsidhu:mainfrom
Tom-Neverwinter:issue-6-meshtastic-nodes
Open

Add public Meshtastic node layer#15
Tom-Neverwinter wants to merge 2 commits into
bilawalsidhu:mainfrom
Tom-Neverwinter:issue-6-meshtastic-nodes

Conversation

@Tom-Neverwinter

Copy link
Copy Markdown

Closes #6.

New optional layer showing nodes that opted in to Meshtastic's own public Map Reporting feature — the network's built-in "publish yourself to a public map" mechanism, over MQTT.

Server: meshtasticProxy (vite.config.js) keeps one persistent MQTT connection to mqtt.meshtastic.org (the project's own public broker, published read-only credentials), subscribed only to msh/+/2/map/#. It decodes exclusively unencrypted MapReport packets (portnum 73) via the official @meshtastic/protobufs definitions and never inspects or attempts to decrypt anything else on the wire — encrypted channel packets are dropped without being touched. An in-memory cache (capped 8000 nodes, swept every 15 min, 24h eviction, true LRU) is served as plain JSON from /api/meshtastic/nodes; validated live against the real broker end-to-end.

Client: src/data/meshtasticNodes.js polls that snapshot like any other layer. A node's position_precision (bits retained) is honored rather than flattened into a false-precision pin — meaningful uncertainty renders as a translucent circle, a high-precision report as a plain point. Per-node LIVE/STALE opacity independent of overall layer status.

src/data/meshtasticMapReport.js holds the pure helpers (id formatting, uncertainty radius, freshness bucketing) shared by server and client; src/data/meshtasticDecode.js isolates the protobuf-dependent decode so it never reaches the browser bundle (confirmed via a production build). Registered in main.js + layerState.js, voice/text aliases, attribution in dataCredits.js and DATA_SOURCES.md.

Includes a follow-up commit fixing two bugs a code-review pass found:

  • update() could resolve to false on a transient fetch failure, which manager.js's enable-lifecycle treats as a fatal enable failure and bounces the layer's toggle back off instead of leaving it enabled to report the failure via getStats().
  • The node-cache cap silently dropped brand-new nodes once full instead of evicting the oldest-seen one — fixed to true LRU.

🤖 Generated with Claude Code

Tom-Neverwinter and others added 2 commits August 25, 2026 00:52
New optional layer showing nodes that opted in to Meshtastic's own public
Map Reporting feature — the network's built-in "publish yourself to a
public map" mechanism, over MQTT.

Server: meshtasticProxy (vite.config.js) keeps one persistent MQTT
connection to mqtt.meshtastic.org (the project's own public broker,
published read-only credentials), subscribed only to msh/+/2/map/#. It
decodes exclusively unencrypted MapReport packets (portnum 73) via the
official @meshtastic/protobufs definitions and never inspects or attempts
to decrypt anything else on the wire — encrypted channel packets are
dropped without being touched. An in-memory cache (capped 8000 nodes,
swept every 15 min, 24h eviction) is served as plain JSON from
/api/meshtastic/nodes; validated live against the real broker end-to-end.

Client: src/data/meshtasticNodes.js polls that snapshot like any other
layer. A node's position_precision (bits retained) is honored rather than
flattened into a false-precision pin — meaningful uncertainty renders as a
translucent circle (positionUncertaintyRadiusM, calibrated against
Meshtastic's own published precision reference points), a high-precision
report as a plain point. Per-node LIVE/STALE opacity independent of the
overall layer status.

src/data/meshtasticMapReport.js holds the pure helpers (id formatting,
uncertainty radius, freshness bucketing) shared by server and client;
src/data/meshtasticDecode.js isolates the protobuf-dependent decode so it
never reaches the browser bundle (confirmed via a production build — the
client chunk grew ~4KB, not the hundreds of KB @meshtastic/protobufs would
add). Registered in main.js + layerState.js (token 'n'), voice/text
aliases, attribution in dataCredits.js and DATA_SOURCES.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZFzxaNKiGGkq9V64Y9omb
- meshtasticNodes.js loadNodes(): never resolve `false` from update() —
  manager.js's enable-lifecycle treats that as a fatal enable failure and
  bounces the toggle back off (src/data/manager.js:908-909), which a
  transient fetch failure right after enabling should never do. Also guard
  against a destroy() racing an in-flight fetch (dataSource null-deref).
- vite.config.js meshtasticProxy: the node-cache cap was silently dropping
  brand-new nodes once full instead of evicting the oldest-seen one —
  permanently hiding new mesh participants in a dense region once the
  8000-node cap was reached. Now a proper LRU: delete-then-set on every
  update (a Map's set() on an existing key doesn't reorder it) so the
  first key really is oldest-seen, then evict that on overflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZFzxaNKiGGkq9V64Y9omb
@WolfHarrold

Copy link
Copy Markdown

Closes #6.

New optional layer showing nodes that opted in to Meshtastic's own public Map Reporting feature — the network's built-in "publish yourself to a public map" mechanism, over MQTT.

Server: meshtasticProxy (vite.config.js) keeps one persistent MQTT connection to mqtt.meshtastic.org (the project's own public broker, published read-only credentials), subscribed only to msh/+/2/map/#. It decodes exclusively unencrypted MapReport packets (portnum 73) via the official @meshtastic/protobufs definitions and never inspects or attempts to decrypt anything else on the wire — encrypted channel packets are dropped without being touched. An in-memory cache (capped 8000 nodes, swept every 15 min, 24h eviction, true LRU) is served as plain JSON from /api/meshtastic/nodes; validated live against the real broker end-to-end.

Client: src/data/meshtasticNodes.js polls that snapshot like any other layer. A node's position_precision (bits retained) is honored rather than flattened into a false-precision pin — meaningful uncertainty renders as a translucent circle, a high-precision report as a plain point. Per-node LIVE/STALE opacity independent of overall layer status.

src/data/meshtasticMapReport.js holds the pure helpers (id formatting, uncertainty radius, freshness bucketing) shared by server and client; src/data/meshtasticDecode.js isolates the protobuf-dependent decode so it never reaches the browser bundle (confirmed via a production build). Registered in main.js + layerState.js, voice/text aliases, attribution in dataCredits.js and DATA_SOURCES.md.

Includes a follow-up commit fixing two bugs a code-review pass found:

  • update() could resolve to false on a transient fetch failure, which manager.js's enable-lifecycle treats as a fatal enable failure and bounces the layer's toggle back off instead of leaving it enabled to report the failure via getStats().
  • The node-cache cap silently dropped brand-new nodes once full instead of evicting the oldest-seen one — fixed to true LRU.

🤖 Generated with Claude Code

Yep!

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.

[Feature Request] Meshtastic Public Node Layer

2 participants