Skip to content

nasticmc/meshcore-mqtt-live-map

 
 

Repository files navigation

Mesh Live Map

Version: 1.3.6 (see VERSIONS.md)

Live MeshCore traffic map that renders nodes, routes, and activity in real time on a Leaflet map. The backend subscribes to MQTT over WebSockets+TLS or TCP, decodes MeshCore packets with @michaelhart/meshcore-decoder, and streams updates to the browser via WebSockets.

Live example sites:

Live map preview

Live map preview

Features

  • Live node markers with roles (Repeater, Companion, Room Server, Unknown)
  • MQTT online indicator (green outline + popup status)
  • Animated route/trace lines
  • Dev route inspection: click a route line in dev (PROD_MODE=false) to log hop-by-hop details in the browser console (PR #14, credit: https://github.com/sefator)
  • Heat map for the last 10 minutes of message activity (includes adverts)
  • Persistent device state and optional trails (disable with TRAIL_LEN=0)
  • 24-hour route history tool with volume-based coloring, click-to-view packet details, a heat-band slider, and a link-size slider
  • History panel can be dismissed with an X without hiding history lines (re-open via History tool)
  • Peers tool showing incoming/outgoing neighbors with on-map lines (blue = incoming, purple = outgoing)
  • Coverage layer from a coverage map API (button hidden when not configured)
  • Update available banner (git local vs upstream) with dismiss
  • UI controls: legend toggle, dark map, topo map, units toggle (km/mi), labels toggle, hide nodes, heat toggle
  • Share button that copies a URL with current view + settings
  • URL parameters to open the map at a specific view (center, zoom, toggles)
  • Node search by name or public key
  • Adjustable node size slider (defaults from env, saves locally)
  • LOS tool with elevation profile + peak markers, hover sync, and realtime draggable endpoints (Shift+click or long‑press nodes)
  • Embeddable metadata (Open Graph/Twitter tags) driven by env vars
  • Preview image renders in-bounds device dots for shared links
  • Route pruning via neighbor-aware closest-hop selection + max hop distance (configurable)
  • Route lines are derived from decoded packet paths only (no MQTT observer/receiver fallback)
  • First-hop collision fix prefers the closest repeater/room to the sender (Issue #11)
  • Propagation panel lives on the right and keeps the last render until you generate a new one (click an origin marker to remove it)
  • Propagation tool supports adjustable TX antenna gain (dBi), and now defaults Rx AGL to 1m
  • Installable PWA (manifest + service worker) for Add to Home Screen
  • Click the logo to hide/show the left HUD panel while tools stay open
  • New nodes filter button shows only nodes first seen in the last 24 hours (configurable via NEW_NODE_FILTER_ENABLED)

Project Structure

  • backend/app.py: FastAPI server wiring, MQTT lifecycle, WS broadcast
  • backend/config.py: environment configuration
  • backend/state.py: shared in-memory state + dataclasses
  • backend/decoder.py: payload parsing + meshcore-decoder integration
  • backend/los.py: LOS math + elevation helpers
  • backend/history.py: route history persistence + pruning
  • backend/static/index.html: HTML shell + template placeholders
  • backend/static/styles.css: UI styles
  • backend/static/app.js: map logic + UI controls
  • backend/static/sw.js: PWA service worker
  • docker-compose.yaml: runtime configuration (reads from .env)
  • data/: runtime state (created at first run)

Quick Start

  1. Clone the repo and enter it:
git clone https://github.com/yellowcooln/meshcore-mqtt-live-map
cd meshcore-mqtt-live-map
  1. Copy env template:
cp .env.example .env
  1. Edit .env with your MQTT broker and site metadata.
    • See howto.md for a step-by-step guide to setting up the MQTT server and this live map.
  2. Build and run:
docker compose up -d --build
  1. Open: http://localhost:8080/ (or your WEB_PORT)

Configuration (.env)

Debugging:

  • DEBUG_PAYLOAD (verbose decode logs)
  • DEBUG_PAYLOAD_MAX / PAYLOAD_PREVIEW_MAX (log truncation limits)
  • DEBUG_LAST_MAX / DEBUG_STATUS_MAX (debug endpoint entry caps)

Storage + server:

  • STATE_DIR (persisted state path)
  • STATE_FILE (full state file path override)
  • DEVICE_ROLES_FILE (optional role override JSON file)
  • DEVICE_COORDS_FILE (optional coordinate override JSON file; default /data/device_coords.json)
  • NEIGHBOR_OVERRIDES_FILE (optional JSON mapping for neighbor overrides)
  • STATE_SAVE_INTERVAL (seconds between state saves)
  • WEB_PORT (host port for the web UI)
  • PROD_MODE (true to require a token for API + WS)
  • PROD_TOKEN (required token; send via ?token= or Authorization: Bearer)

Turnstile protection (prod-only):

  • TURNSTILE_ENABLED (requires PROD_MODE=true)
  • TURNSTILE_SITE_KEY
  • TURNSTILE_SECRET_KEY
  • TURNSTILE_API_URL
  • TURNSTILE_TOKEN_TTL_SECONDS
  • TURNSTILE_BOT_BYPASS (allowlist embed bots like Discord)
  • TURNSTILE_BOT_ALLOWLIST (comma-separated user-agent tokens; default: discordbot,twitterbot,slackbot,facebookexternalhit,linkedinbot,telegrambot,whatsapp,skypeuripreview,redditbot)

Site metadata (page title + embeds):

  • SITE_TITLE
  • SITE_DESCRIPTION
  • SITE_OG_IMAGE (optional; leave blank to omit embed image)
  • SITE_URL (public URL)
  • SITE_ICON
  • SITE_FEED_NOTE
  • CUSTOM_LINK_URL (optional extra HUD link; hidden when blank)
  • DISTANCE_UNITS (km or mi, default display units)
  • NODE_MARKER_RADIUS (default node marker size in pixels)

MQTT:

  • MQTT_HOST
  • MQTT_PORT
  • MQTT_USERNAME
  • MQTT_PASSWORD
  • MQTT_TRANSPORT (tcp or websockets)
  • MQTT_WS_PATH (usually / or /mqtt)
  • MQTT_TLS (true)
  • MQTT_TLS_INSECURE (allow invalid TLS certs)
  • MQTT_CA_CERT (custom CA bundle path)
  • MQTT_CLIENT_ID (optional client id override)
  • MQTT_TOPIC (e.g. meshcore/# or meshcore/#,other/topic/+ for multiple topics)

Coverage layer:

  • COVERAGE_API_URL (URL to coverage map API; button hidden when blank)

Node filter:

  • NEW_NODE_FILTER_ENABLED (true/false; shows a "New nodes" button that filters to nodes first seen in the last 24h; default true, button hidden when false)

Device + route tuning:

  • DEVICE_TTL_HOURS (advert/device stale window; default 96)
  • PATH_TTL_SECONDS (path stale window; default 172800)
  • TRAIL_LEN (points per device trail; 0 disables trails)
  • ROUTE_TTL_SECONDS
  • ROUTE_PATH_MAX_LEN (skip oversized path-hash lists)
  • ROUTE_PAYLOAD_TYPES (packet types used for live routes)
  • ROUTE_MAX_HOP_DISTANCE (km; prunes unrealistic hops)
  • ROUTE_INFRA_ONLY (true = only repeaters/rooms in route lines)
  • MESSAGE_ORIGIN_TTL_SECONDS

History overlay:

  • ROUTE_HISTORY_ENABLED
  • ROUTE_HISTORY_HOURS
  • ROUTE_HISTORY_MAX_SEGMENTS
  • ROUTE_HISTORY_COMPACT_INTERVAL
  • ROUTE_HISTORY_FILE
  • ROUTE_HISTORY_PAYLOAD_TYPES
  • ROUTE_HISTORY_ALLOWED_MODES (comma-separated route modes; default path)
  • HISTORY_LINK_SCALE (default history line weight multiplier)

Heat + online status:

  • HEAT_TTL_SECONDS
  • MQTT_ONLINE_SECONDS (online window for status ring)
  • MQTT_ONLINE_TOPIC_SUFFIXES (comma-separated topics that count as “online”)
  • MQTT_SEEN_BROADCAST_MIN_SECONDS
  • MQTT_ONLINE_FORCE_NAMES (comma-separated names to force as MQTT online; also excluded from peers)

Update checks:

  • GIT_CHECK_ENABLED (show update banner if repo is behind)
  • GIT_CHECK_FETCH (fetch before comparing)
  • GIT_CHECK_PATH (path to git repo in the container)
  • GIT_CHECK_INTERVAL_SECONDS (defaults to 43200 = 12h)

Map + LOS:

  • MAP_START_LAT / MAP_START_LON / MAP_START_ZOOM (default map view)
  • MAP_DEFAULT_LAYER (light, dark, or topo; localStorage overrides)
  • MAP_RADIUS_KM (0 disables radius filtering; .env.example uses 241.4 km ≈ 150mi)
  • MAP_RADIUS_SHOW (true draws the radius debug circle)
  • LOS_ELEVATION_URL (elevation API for LOS tool)
  • LOS_ELEVATION_PROXY_URL (server proxy for client-side LOS elevation fetches)
  • LOS_SAMPLE_MIN / LOS_SAMPLE_MAX / LOS_SAMPLE_STEP_METERS
  • ELEVATION_CACHE_TTL (seconds)
  • LOS_PEAKS_MAX (max peaks shown on LOS profile)

Decoder helpers:

  • DECODE_WITH_NODE (toggle meshcore-decoder usage)
  • NODE_DECODE_TIMEOUT_SECONDS
  • DIRECT_COORDS_MODE (topic or payload)
  • DIRECT_COORDS_TOPIC_REGEX (topic matcher for direct coords)
  • DIRECT_COORDS_ALLOW_ZERO (allow 0,0 coords if true)

Common Commands

  • Rebuild/restart: docker compose up -d --build
  • Logs: docker compose logs -f meshmap-live
  • Snapshot: curl -s http://localhost:8080/snapshot
  • Stats: curl -s http://localhost:8080/stats

Production Token

Enable protection by setting:

PROD_MODE=true
PROD_TOKEN=<random-string>

Turnstile protection is also gated by PROD_MODE=true. If PROD_MODE=false, Turnstile stays off even when TURNSTILE_ENABLED=true. When Turnstile is enabled, browser sessions can authenticate the map + WebSocket with a Turnstile auth token (meshmap_auth cookie or ?auth= on /ws), but protected API routes (/snapshot, /api/nodes, /peers/{id}) still require PROD_TOKEN. Ensure PROD_MODE/PROD_TOKEN are set in .env (docker-compose passes them through).

Generate a token:

openssl rand -hex 32

Use it:

  • HTTP: http://host:8080/snapshot?token=YOUR_TOKEN
  • WS: ws://host:8080/ws?token=YOUR_TOKEN
  • Or send Authorization: Bearer YOUR_TOKEN

Notes

  • The map can only draw routes for hops that appear in your MQTT feed.
  • To see full paths, the feed must include Path/Trace packets (payload types 8/9).
  • Runtime state is persisted to data/state.json.
  • MQTT disconnects are handled; the client will reconnect when the broker returns.
  • Live route IDs are observer-aware (message_hash:receiver_id) so the same message seen by multiple MQTT observers does not overwrite active lines.
  • Line-of-sight tool: click LOS tool and pick two points, or Shift+click two nodes to measure LOS between them. Drag endpoints or select A/B then click the map to move that point.
  • On mobile, long‑press a node to select it for LOS.
  • LOS elevations are fetched via /los/elevations and LOS/relay math runs client-side (with /los fallback).
  • History tool always loads off (use the button or history=on in the URL).
  • Peers tool uses route history segments; forced MQTT listeners are excluded from peer lists.
  • URL params override stored settings: lat, lon/lng/long, zoom, layer, history, heat, labels, nodes, legend, menu, units, history_filter.
  • Dark map also darkens node popups for readability.
  • Route styling uses payload type: 2/5 = Message (blue), 8/9 = Trace (orange), 4 = Advert (green).
  • Turnstile browser auth (meshmap_auth/?auth=) is for map + WS session flow; protected API endpoints still require PROD_TOKEN.
  • If hop hashes collide, the backend prefers known neighbors (or overrides) before picking the closest hop and pruning beyond ROUTE_MAX_HOP_DISTANCE.
  • Device pruning can use both stale windows together (DEVICE_TTL_HOURS and PATH_TTL_SECONDS).
  • Coordinates at 0,0 (including string values) are filtered from devices, trails, and routes.
  • With Turnstile enabled, common embed bots (Discord, Slack, etc.) can be allowlisted via TURNSTILE_BOT_BYPASS and TURNSTILE_BOT_ALLOWLIST.

API

The backend exposes a nodes API for external tools (e.g. MeshBuddy):

  • GET /api/nodes?token=YOUR_TOKEN
    • Default response: {"data":[...], "nodes":[...]}
    • Optional: format=nested returns {"data":{"nodes":[...]}}
    • updated_since applies delta filtering automatically
    • Optional: mode=full (or all/snapshot) forces full-list response

Example:

https://your-host/api/nodes?token=YOUR_TOKEN
https://your-host/api/nodes?token=YOUR_TOKEN&updated_since=2025-01-01T12:00:00Z
https://your-host/api/nodes?token=YOUR_TOKEN&format=nested
https://your-host/api/nodes?token=YOUR_TOKEN&mode=full

Each node includes: public_key, name, device_role (1/2/3), last_seen (ISO), timestamp (epoch), and location with latitude/longitude.

Peer summary:

  • GET /peers/{device_id}?token=YOUR_TOKEN
    • Returns incoming/outgoing neighbors with counts/percentages from route history.

License

GPL-3.0.


This project was vibe-coded with Codex—please expect rough edges and the occasional bug.

Star History

Star History Chart

About

Live Map of Meshcore MQTT feed

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • JavaScript 48.2%
  • Python 39.8%
  • HTML 6.6%
  • CSS 5.3%
  • Dockerfile 0.1%