mirror of
https://github.com/yellowcooln/meshcore-mqtt-live-map.git
synced 2026-04-20 23:23:36 +00:00
11 KiB
11 KiB
Repository Guidelines
Current version: 1.8.4 (see VERSIONS.md).
Project Structure & Module Organization
backend/app.pywires FastAPI routes, MQTT lifecycle, and websocket broadcast flow.backend/config.pycentralizes env configuration.backend/state.pyholds shared in-memory state + dataclasses.backend/decoder.pycontains payload parsing, multibyte MeshCore decoding, and route helpers.backend/los.pycontains LOS math + elevation fetch helpers.backend/history.pyhandles 24h route history persistence/cleanup.backend/static/index.htmlis the HTML shell + template placeholders.backend/static/styles.cssholds all UI styles.backend/static/app.jsholds all client-side map logic.backend/static/sw.jsis the PWA service worker.backend/requirements.txtandbackend/Dockerfiledefine Python and Node dependencies.docker-compose.yamlruns the service asmeshmap-live.data/stores persisted state (state.json), route history (route_history.jsonl), role overrides (device_roles.json), and optional neighbor overrides (neighbor_overrides.json)..envholds dev runtime settings;.env.examplemirrors template defaults.VERSION.txttracks the current version (now1.8.4); append changes inVERSIONS.md.
Build, Test, and Development Commands
docker compose up -d --buildrebuilds and restarts the backend (preferred workflow).docker compose logs -f meshmap-livefollows server logs for MQTT activity.curl -s http://localhost:8080/snapshotchecks current device state.curl -s http://localhost:8080/statsshows ingest/route counters.curl -s http://localhost:8080/debug/lastinspects recent decoded packets.
Coding Style & Naming Conventions
- Python in
backend/*.pyuses 2-space indentation; keep it consistent. - The project enforces an 80-character column limit for Python code to maintain readability.
- Formatting is handled by
yapfusing the config inbackend/.style.yapf.- To format code manually:
yapf --in-place --recursive --style backend/.style.yapf backend/
- To format code manually:
- HTML/CSS/JS in
backend/static/index.htmluses 2 spaces as well. - Use lowercase, underscore-separated names for Python variables/functions.
- Prefer small helper functions for parsing/normalization; keep logging concise.
Testing Guidelines
- Run automated tests with
pip install -r requirements-dev.txt && pytest -q. - Validate runtime behavior manually with
/snapshot,/stats, and/debug/last.
Commit & Pull Request Guidelines
- No git history is available in this workspace, so there is no established commit convention.
- If you add git later, use short, imperative commit messages and describe behavioral changes in PRs.
Configuration & Operations
- Most behavior is controlled by
.env(MQTT host, TLS, topics, TTLs, map start lat/lon/zoom, MQTT online window, default map layer). - Current dev defaults:
DEVICE_TTL_HOURS=96,PATH_TTL_SECONDS=172800,MQTT_ONLINE_SECONDS=600,ROUTE_TTL_SECONDS=60,TRAIL_LEN=0,DISTANCE_UNITS=mi. - Node size default is
NODE_MARKER_RADIUS(pixels); users can override via the HUD slider. - History link size default is
HISTORY_LINK_SCALE; users can override via the History panel slider. - Map radius filter:
MAP_RADIUS_KM=0disables filtering;.env.exampleuses241.4km (150mi). Applies to nodes, trails, routes, and history edges. MAP_RADIUS_SHOW=truedraws a debug circle centered onMAP_START_LAT/LON.- Set
TRAIL_LEN=0to disable trails entirely; the HUD trail hint is removed when trails are off. - Coverage button only appears when
COVERAGE_API_URLis set. QR_CODE_BUTTON_ENABLED=trueadds aGenerate QR Codebutton to node popups that opens a theme-aware MeshCore-compatible contact QR modal; default is off.- Geographic filtering defaults to radius mode; polygon mode is optional via
MAP_BOUNDARY_MODE=polygonandMAP_BOUNDARY_FILE. - Standalone boundary builder:
tools/map-boundary-builder.htmloutputs the JSON consumed byMAP_BOUNDARY_FILE; hosted copy: https://yellowcooln.com/map-boundary-builder/. - Radar country-bounds controls:
WEATHER_RADAR_COUNTRY_BOUNDS_ENABLEDandWEATHER_RADAR_COUNTRY_LOOKUP_URL.WEATHER_RADAR_COUNTRY_LOOKUP_URLdefaults to/weather/radar/country-boundsand is an HTTP route path, not a filesystem directory. - Weather wind controls:
WEATHER_WIND_ENABLED,WEATHER_WIND_API_URL,WEATHER_WIND_GRID_SIZE,WEATHER_WIND_REFRESH_SECONDS. - LOS curvature controls:
LOS_CURVATURE_ENABLEDandLOS_CURVATURE_FACTOR. When unset, LOS curvature defaults totruewith factor1.333333. DEVICE_COORDS_FILEpoints to optional coordinate overrides (default/data/device_coords.json).NEIGHBOR_OVERRIDES_FILEcan point at a JSON map/list of neighbor pairs to resolve hash collisions.- Auto-neighbor overrides are controlled by:
AUTO_NEIGHBOR_OVERRIDES_ENABLED,AUTO_NEIGHBOR_OVERRIDES_FILE,AUTO_NEIGHBOR_ACTIVE_DAYS,AUTO_NEIGHBOR_MIN_EDGE_COUNT, andAUTO_NEIGHBOR_REFRESH_SECONDS. - Optional custom HUD link appears when
CUSTOM_LINK_URLis set. - Update banner uses
GIT_CHECK_ENABLED(compare local vs upstream) withGIT_CHECK_PATHpointing at a git repo. GIT_CHECK_FETCHcontrols whether the server fetches before comparing;GIT_CHECK_INTERVAL_SECONDSsets the recheck interval.- Route history modes default to
pathviaROUTE_HISTORY_ALLOWED_MODES. ROUTE_PATH_MAX_LENcaps oversized path-hash lists (prevents bogus long routes).ROUTE_ALLOW_AMBIGUOUS_ONE_BYTE_FALLBACK=truerestores pre-v1.7.0closest/time-based fallback for colliding 1-byte route prefixes; default is conservativefalse.- Persisted state in
data/state.jsonis loaded on startup; edit with care. - After editing
backend/*.pyorbackend/static/*, rebuild withdocker compose up -d --build. - History tool visibility is not persisted; it always loads off unless
history=onis in the URL.
Feature Notes
- MQTT supports WSS/TLS or TCP; the official
@michaelhart/meshcore-decoderruns via a Node helper for advert/location parsing, 1/2/3-byte path decoding, and conservative MQTT role extraction. - Routes are rendered as trace/message/advert lines with TTL cleanup; 0,0 coords (including stringy zeros) are filtered from trails/routes.
- Route IDs are observer-aware (
message_hash:receiver_id) so multi-observer receptions do not overwrite each other. - Dev route debug: in non-prod mode (
PROD_MODE=false), clicking a route line logs hop-by-hop details to the browser console (distance, hashes, origin/receiver, timestamps). - Turnstile protection only activates when
PROD_MODE=trueand requiresTURNSTILE_ENABLED,TURNSTILE_SITE_KEY, andTURNSTILE_SECRET_KEY. - Turnstile browser auth (
meshmap_auth/?auth=) is used for map + WebSocket sessions; protected API routes still requirePROD_TOKEN. - Discord/social embeds can be allowlisted under Turnstile via
TURNSTILE_BOT_BYPASSandTURNSTILE_BOT_ALLOWLIST. - Route hash collisions prefer known neighbors (and optional overrides); long path lists are skipped via
ROUTE_PATH_MAX_LEN. - Route collisions fall back to closest-hop selection and drop hops beyond
ROUTE_MAX_HOP_DISTANCE. ROUTE_INFRA_ONLYrestricts route lines to repeaters/rooms (companions still show as markers).- Heatmap shows recent traffic points (TTL controlled).
- LOS uses
/los/elevationsfor client-side realtime updates (with/losfallback). - LOS uses Earth-curvature-aware obstruction checks by default in both the frontend realtime path and the backend
/losfallback. - LOS UI includes peak markers, a relay suggestion marker, elevation profile hover, and map-line hover sync.
- LOS legend items (clear/blocked/peaks/relay) are hidden until the LOS tool is active.
- Mobile LOS supports long-press on nodes (Shift+click on desktop); endpoints can be dragged or click-selected and moved via map click.
- MQTT online status is derived from
/status+/internalTTL windows;/packetsis tracked as feed activity. - Devices that remain MQTT-online keep their last known coordinates on the map until MQTT presence expires, even if fresh location packets stop.
MQTT_ONLINE_FORCE_NAMES(comma-separated device names) forces selected nodes to always appear MQTT online.- Service worker fetches navigations with
no-storeto avoid stale UI/env toggles (e.g., radius debug ring). - Node search + labels toggle (persisted in localStorage) and a GitHub link in the HUD.
- Hide-nodes toggle hides markers, trails, heat, routes, and history layers.
- Heat toggle hides the heatmap; it defaults on and the button turns green when heat is off.
- History line weight was reduced for a lighter map overlay.
- HUD logo uses
SITE_ICON; if missing/invalid it falls back to a small "Map" badge to keep the toggle usable. - Route styling now keys off payload type: 2/5 = Message (blue), 8/9 = Trace (orange), 4 = Advert (green).
- 24h route history persists to
data/route_history.jsonl, renders as a volume heatline, and defaults off (History tool panel). - History tool opens a right-side panel with a 5-step heat filter slider: All, Blue, Yellow, Yellow+Red, Red; legend swatch hides unless active.
- History panel can be dismissed with the X button while leaving history lines visible (History tool brings it back).
- History records route modes from
ROUTE_HISTORY_ALLOWED_MODES(default:path). - Propagation render stays visible until a new render; origin changes only mark it dirty.
- Propagation now has an adjustable TX antenna gain (dBi) control, and Rx AGL defaults to 1m.
- Preview image endpoint renders in-bounds device dots for shared links.
- Peers tool opens a right-side panel showing incoming/outgoing neighbors (counts + %) based on rolling peer-history buckets; selecting a node draws peer lines on the map.
- Peer-history buckets are also updated from route
point_idswhen a hop cannot be drawn as a visible segment, so peer counts still reflect real adjacency for non-drawable hops. - Peers tool ignores nodes listed in
MQTT_ONLINE_FORCE_NAMES(used for observer listeners). - Units toggle (km/mi) is stored in localStorage and defaults to
DISTANCE_UNITS. - PWA support is enabled via
/manifest.webmanifest+/sw.jsso mobile browsers can install the app. - Clicking the logo toggles the left HUD panel while LOS/Propagation panels remain open.
- Node popups do not auto-pan; dragging the map won’t snap back to keep a popup in view.
- Node popups let users click the short key under the node name to copy the full public key, and can optionally show a MeshCore-compatible contact QR modal for that node with the node name plus a clickable truncated key that still copies the full public key.
- MQTT disconnect handler tolerates extra Paho args so the loop doesn’t crash; reconnects resume ingest.
- Share button copies a URL with
lat,lon,zoom,layer,history,heat,coverage,weather,labels,nodes,legend,menu,units, andhistory_filterparams. - Weather state is not persisted in localStorage; it defaults off unless
weather=onis in the URL. - URL params override localStorage on load (
history=onis the only way to load History open). - Node size slider persists in localStorage (
meshmapNodeRadius) and can be reset by clearing site data. - MeshMapper coverage viewport sync reuses cached rectangles instead of rebuilding all visible squares on every pan/zoom, which keeps the Coverage layer responsive on busy maps.