MeshMonitor 4.11.0 is the general-availability release of the 4.11 line (consolidating v4.11.0-rc1 and v4.11.0-rc2). The headline is the MeshCore virtual node — connect the MeshCore mobile app to a MeshMonitor-managed MeshCore device over WiFi, the MeshCore counterpart to the existing Meshtastic Virtual Node Server. MeshCore also gains name-aware contact forwarding-path editing, role-based map icons, and a node-type map filter. Across both protocols, the map picks up a per-node Hide from Map toggle, and Node Details gets a 15m–7d telemetry time-range selector. This release also wires up newer AirQualityMetrics fields and lands a broad set of correctness fixes — most notably a replay guard that stops powered-off nodes from appearing "recently heard" via replayed/retained MQTT frames, a NodeInfo position-precision guard, RE2 hardening of user-supplied regexes, and per-source scoping fixes for traceroute history and neighbor-info display. Under the hood, server.ts was substantially decomposed into focused route modules and the test suite migrated onto a shared createTestDb helper. Upgrading is drop-in — no manual migration or configuration changes required.
✨ Features
- MeshCore virtual node — connect the MeshCore app over WiFi (#3540, #3535) — expose a managed MeshCore device as a virtual node the MeshCore app connects to over TCP/WiFi (default port
5000, per-source enablement, admin commands blocked by default, private-key export always blocked). - MeshCore: define a contact's forwarding path by repeater name (#3550) — first-class, name-aware path editor, on by default.
- MeshCore node-type icons + map filtering (#3563, #3546) — role-based markers (repeater / room server / sensor / companion) and a Node Types filter with legend.
- Per-node "Hide from Map" toggle (#3565, #3549) — suppress a node's map marker everywhere while keeping it visible in lists, DMs, and the packet monitor.
- Node list export — CSV / HTML (#3537, #3499) — export the Nodes view (respecting current filters/sort) for mesh upgrade planning.
- Telemetry time-range selector in Node Details (#3530) — 15m–7d range buttons on the Node Details graphs, persisted and shared with Device Info.
- Position-history map: a marker at every fix, points-only mode, hover tooltip (#3495, #3492).
- Newer AirQualityMetrics fields wired up (#3517, #3507) —
particles_40um,pm40_standard, formaldehyde trio, and PM-sensor extras now graphed. - Native OIDC group → role mapping (#3489, #3485) — map IdP groups to admin/login via
OIDC_GROUPS_CLAIM/OIDC_ADMIN_GROUPS/OIDC_ALLOWED_GROUPS. - UI tweaks + map unification pass (#3561, #3557) — "Messages" → "Node Details" nav, clickable map-popup source rows, unified tile/legend/GeoJSON toggles, and more.
🐛 Bug Fixes
- Offline nodes kept appearing "recently heard" from replayed packets (#3569) — new replay guard ignores stale
lastHeardrefreshes from retained/replayed MQTT frames. - NodeInfo could overwrite high-precision positions with lower-precision ones (#3516, #3513) — precision-downgrade guard added.
- User-supplied regexes hardened against ReDoS (#3544) — all user/admin regexes now compiled with RE2 (resolves 4 CodeQL alerts).
- Traceroute History mixed in rows from every source (#3566) — history now scoped to the active source.
- Map "Show Neighbor Info" disagreed with the Map Analysis Neighbors view (#3560) — freshness filters aligned.
- Per-node position override ignored on the multi-source dashboard map (#3559, #3551).
- SaveBar only saved the active section (#3558, #3552) — grouped sections now save together via "Save All".
- MeshCore DM contact list nearly empty while node/map view was full (#3554) — in-memory contacts seeded from the durable DB rows on connect.
- MeshCore node list intermittently collapsed to a single node (#3539).
- Link previews failed to load on MeshCore / first page visited (#3541) — switched to a static api import so previews resolve under
BASE_URL. - MeshCore
upsertNodeoverwrote stored data with nulls (#3510, #3504). - Node upsert could clobber learned name/MAC/hwModel with blanks (#3512, #3505).
- Serial telemetry ingest unified onto the shared digit-aware normalizer (#3514, #3506).
- Traffic Management / Status Message firmware gating corrected (#3493, #3491).
- Auto-ping ACKs misattributed / duplicate sends (#3522).
- Battery-alert monitored-node selection stuck with stale IDs (#3487, #3486).
- Docker entrypoint integrity check for a 0-byte server bundle (#3543, #3542).
- System-backup download hardened — async existence check +
headersSentguards (#3529, #3524). - Mobile map Features panel blocked the sidebar Connect button (#3536, #3532).
- Unified Packet Monitor headers aligned with columns (#3567).
📚 Documentation
- New MeshCore Virtual Node guide alongside the Meshtastic one (config, default port 5000, admin-command safety, app setup, troubleshooting); CHANGELOG finalized for 4.11.0; refreshed README/index/CLAUDE references.
- SSO docs corrected and expanded (#3489) — documented
DISABLE_LOCAL_AUTHand added a Group → Role Mapping section. - Security pages restored to the public site (#3534) — Duplicate-Keys and Low-Entropy-Keys advisories.
🔧 Refactoring & Internal
server.tsdecomposed into focused route modules — health/cleanup/maintenance/themes/purge, mesh-request/telemetry/connection/device/status, channels, device & system, scripts/data-exchange/server-info, backup + notification, traceroutes/route-segments/neighbor-info/ignored-nodes/announce (#3509, #3519, #3523, #3525, #3526, #3527, #3528).- Test suite migrated onto a shared
createTestDbhelper and config/module-type registry centralized (#3497, #3498, #3500, #3511, #3520). - Telemetry pipeline unified onto
buildCanonicalMetrics(#3518); dead unguarded channel upsert path removed (#3508).
📦 Dependencies & CI
- Dependabot updates: azure/setup-helm, actions/setup-python, wait-on-check-action, typescript-eslint, lucide-react, archiver types, and the dev/prod dependency groups (#3466–#3476).
- CI: pinned the Claude Action model (#3488); translations update from Hosted Weblate (#3438).
📋 Issues Resolved
Closes #3535, #3546, #3549, #3499, #3530, #3492/#3494, #3507, #3485, #3557, #3556, #3555, #3553, #3552, #3551, #3542, #3533, #3532, #3524, #3515, #3513, #3506, #3505, #3504, #3503, #3491, #3486, #3480, #3477, #3464.
⬆️ Upgrade Notes
Drop-in upgrade — no manual migration or config changes. Schema migrations (through 092_add_hide_from_map_to_nodes) run automatically on first boot. The MeshCore virtual node and MeshCore name-aware path editing are opt-in / gated by existing permissions.
Full changelog: v4.10.4...v4.11.0
🚀 MeshMonitor v4.11.0
📦 Installation
Docker (recommended):
docker run -d \
--name meshmonitor \
-p 8080:3001 \
-v meshmonitor-data:/data \
ghcr.io/Yeraze/meshmonitor:4.11.0🧪 Testing
✅ All tests passed
✅ TypeScript checks passed
✅ Docker images built for linux/amd64, linux/arm64, linux/arm/v7
📋 Changes
See commit history for detailed changes.