A real-time web dashboard for MeshCore LoRa mesh repeaters.
pyMC Console gives you full visibility into your mesh network — packet flow, topology, signal quality, RF metrics, and radio configuration — through a single browser tab. It layers on top of pyMC_Repeater without modifying it.
- Raspberry Pi (3, 4, 5, or Zero 2 W)
- LoRa radio module (SX1262 or SX1276)
- Raspberry Pi OS (Bookworm recommended)
git clone https://github.com/dmduran12/pymc_console-dist.git pymc_console
cd pymc_console
sudo bash manage.sh installDuring installation you'll be prompted to select a pyMC_Repeater branch — choose dev (the default). The dev branch has the latest features and is the recommended target.
The installer handles everything:
- System dependencies (Python, pip, SPI tools)
- Clones and installs pyMC_Repeater + pyMC_core
- Deploys the Console web dashboard
- Configures and starts the systemd service
Once complete, open http://<your-pi-ip>:8000 in a browser.
cd pymc_console
sudo bash manage.sh upgradeChoose Console only (updates just the dashboard) or Full Stack (updates Console + pyMC_Repeater + pyMC_core). Console-only upgrades are safe and fast — your repeater config is untouched.
cd pymc_console
sudo bash manage.shSelect Uninstall from the menu. Removes all installed files, config, logs, and the systemd service.
┌─────────────────────────────────────────────────────────────┐
│ pyMC Console │
│ (this repo — web dashboard UI) │
│ │
│ • React SPA served on port 8000 │
│ • Real-time packets, topology, stats, radio config │
│ • manage.sh installer handles everything │
└─────────────────────┬───────────────────────────────────────┘
│ uses API from
┌─────────────────────▼───────────────────────────────────────┐
│ pyMC_Repeater │
│ (RightUp's repeater daemon) │
│ │
│ • Python daemon running the LoRa repeater │
│ • REST API + WebSocket on port 8000 │
│ • Packet forwarding, logging, radio control │
└─────────────────────┬───────────────────────────────────────┘
│ built on
┌─────────────────────▼───────────────────────────────────────┐
│ pyMC_core │
│ (RightUp's protocol library) │
│ │
│ • Low-level MeshCore protocol implementation │
│ • Radio drivers (SX1262, SX1276) │
│ • Packet encoding/decoding │
└─────────────────────────────────────────────────────────────┘
Key points:
- Console does not replace Repeater — they work together
manage.shinstalls both Repeater and Console side-by-side- You can upgrade Console independently without touching Repeater
Reconstructs your network's structure from packet paths using a Viterbi HMM decoder — resolving prefix collisions with physics-based RF constraints and real-world observation evidence.
- One-click Deep Analysis from up to 14 days of packet history
- Viterbi HMM decoding — resolves 2-char prefix collisions using geographic distance and LoRa range constraints
- Ghost node discovery — detects unknown repeaters when no known candidate fits
- 7-phase topology pipeline — directional edges, betweenness centrality, mobile detection, TX delay recommendations, path health scoring
- 3D terrain — AWS Terrarium elevation with hillshading; markers and edges drape onto the landscape
- Wardriving overlay — H3 hexagonal coverage tiles with SNR-based coloring
- Edge confidence — line thickness scales with observation count; color indicates certainty
Polar chart placing all contacts at their actual compass bearing and distance from your node.
- Zero-hop neighbors colored by SNR (green → yellow → orange → red)
- Multi-hop contacts at 33% opacity to distinguish direct RF from relayed
- Hover tooltips with full signal metrics (RSSI, SNR, distance, last seen)
Comprehensive RF metrics and network composition analysis.
- Airtime utilization — RX/TX stacked area charts with peak and mean metrics
- Packet type distribution — treemap of ADVERT, TXT_MSG, ACK, TRACE, etc.
- Network composition — repeater / companion / room server breakdown
- Noise floor heatmap — interference patterns over time
- Disambiguation health — Viterbi confidence metrics and ghost node stats
- TX delay recommendations — slot-based timing optimization per node role
Click any packet to visualize its route through the mesh with hop-by-hop confidence.
- Confidence coloring — Green (100%), Yellow (50–99%), Orange (25–49%), Red (<25%), Gray (ghost)
- Interactive map showing resolved path with intermediate hops
- Signal details — RSSI, SNR, and timing per packet
- Byte-level breakdown — header fields, payload structure, raw hex
Two polished color schemes and a built-in CLI for direct repeater interaction.
- Breeze Dark / Breeze Light — KDE Breeze-inspired themes with full design token system
- Terminal — interactive CLI mapped to API endpoints (get/set radio, ping, diagnostics)
- Packet capture —
start cap/end cap/export capfor timed diagnostic snapshots - Live logs — streaming from repeater with DEBUG/INFO toggle
| Page | Route | What it does |
|---|---|---|
| Dashboard | / |
Live packet counters, sparkline trends, LBT widgets, recent packets |
| Packets | /packets |
Searchable packet history with detail modal, path visualization, byte breakdown |
| Contacts | /contacts |
MapLibre GL map with topology edges, ghost nodes, terrain, wardriving overlay |
| Statistics | /statistics |
µPlot charts — airtime, packet types, noise floor, signal scatter, network composition |
| Mesh Graph | /meshgraph |
GPU-accelerated force-directed graph (Cosmograph) |
| System | /system |
CPU, memory, disk, temperature, processes, network I/O |
| Logs | /logs |
Live log stream with level filtering |
| Terminal | /terminal |
Interactive CLI — MeshCore commands, ping, diagnostics, captures |
| Configuration | /configuration |
Radio settings, TX delays, transport keys, identity, theme, stealth location |
sudo bash manage.sh┌────────────────────────────────────────────────┐
│ pyMC Console │
│ Status: Running │
├────────────────────────────────────────────────┤
│ install Fresh installation │
│ upgrade Upgrade existing │
│ uninstall Remove everything │
│ status Show versions │
│ logs View live logs │
│ exit Exit │
└────────────────────────────────────────────────┘
- Install — Full Stack or Console-only
- Upgrade — Console-only (fast, safe) or Full Stack (Console + Repeater + Core)
- Uninstall — Removes everything (installation, config, logs, service)
- Status — Installed versions of Core, Repeater, Console
- Logs — Live journal output from the repeater
Radio and GPIO settings are managed by upstream pyMC_Repeater:
cd ~/pyMC_Repeater && sudo ./manage.shOr edit the config directly:
# /etc/pymc_repeater/config.yaml
radio:
frequency: 927875000 # Hz
spreading_factor: 7 # SF7–SF12
bandwidth: 62500 # Hz
tx_power: 28 # dBm
coding_rate: 6 # 4/5, 4/6, 4/7, 4/8You can also change radio settings live from the Configuration page in the dashboard — no SSH required.
Some LoRa modules need specific DIO pin settings. These are independent — enabling one does not affect the other:
- DIO3 (TCXO) — set
use_dio3_tcxo: trueif your module has a temperature-compensated oscillator on DIO3 - DIO2 (RF Switch) — set
use_dio2_rf: trueif your module uses DIO2 for TX/RX antenna switching
radio:
use_dio3_tcxo: true
use_dio2_rf: true # dev branch onlysudo systemctl status pymc-repeater # Check status
sudo systemctl restart pymc-repeater # Restart
sudo journalctl -u pymc-repeater -f # Live logsAfter installation:
~/pymc_console/ ← This repo (cloned by you)
~/pyMC_Repeater/ ← Repeater daemon (cloned by manage.sh)
/opt/pymc_repeater/ ← Installed repeater
/opt/pymc_console/web/html/ ← Installed dashboard
/etc/pymc_repeater/config.yaml ← Radio + repeater configuration
/var/log/pymc_repeater/ ← Log files
- Raspberry Pi 3, 4, 5
- Raspberry Pi Zero 2 W
- Any SBC with SPI and GPIO (untested but likely works)
- Waveshare SX1262 HAT
- Ebyte E22 modules
- LILYGO T3S3 (via USB serial)
- Heltec LoRa 32
LoRa module connects via SPI with GPIO pins for reset, busy, and DIO1. Pin mapping is configured during installation via pyMC_Repeater's manage.sh.
- Is the service running?
sudo systemctl status pymc-repeater
- Is port 8000 responding?
curl -s http://localhost:8000/api/stats | head -c 100 - Check for errors:
sudo journalctl -u pymc-repeater -n 50
Usually caused by a version mismatch between Console and Repeater.
cd pymc_console
sudo bash manage.sh upgradeSelect Full pyMC Stack to update everything to compatible versions.
-
SPI enabled?
ls /dev/spidev*If no devices listed, enable SPI via
raspi-config→ Interface Options → SPI. -
GPIO correct? Run pyMC_Repeater's manage.sh → Configure GPIO and verify pin assignments match your wiring.
-
Frequency match? Confirm your radio frequency matches the rest of your mesh network.
-
Check the logs:
sudo journalctl -u pymc-repeater -n 100 | grep -i "error\|fail\|radio"
# Check for config syntax errors
python3 -c "import yaml; yaml.safe_load(open('/etc/pymc_repeater/config.yaml'))"
# Check for Python dependency issues
pip3 show pymc-repeater pymc-coreNon-fatal warning. The installer fetches presets from an API; if unavailable, it falls back to common defaults. Installation continues normally.
- The dashboard requires authentication. If you see the login page, use the credentials you set during pyMC_Repeater installation.
- If you're on a fresh install, allow 30–60 seconds for the repeater to initialize and begin receiving packets.
- Check that WebSocket is connecting: open browser DevTools → Network → WS. You should see an active
/ws/packetsconnection.
Hard-refresh your browser (Cmd+Shift+R / Ctrl+Shift+R) to clear the cached SPA bundle. Vite hashes filenames, but the browser may still cache index.html.
MeshCore packets contain 2-character hex prefixes representing the route through the mesh:
Path: ["FA", "79", "24", "19"]
Origin → Hop1 → Hop2 → Local
Multiple nodes can share the same 2-char prefix (1-in-256 collision). The system uses a Viterbi HMM decoder to find the most probable sequence of actual nodes:
- States — all candidate nodes matching each prefix, plus a "ghost" state for unknowns
- Priors — recency-weighted (recently-seen nodes are more likely)
- Transitions — physics-based costs using geographic distance and LoRa range constraints
- Key principle — when edge observations have ≥80% confidence, real-world evidence overrides physics
Before Viterbi decoding, candidates are scored using four-factor analysis:
- Position (15%) — typical path positions for this prefix
- Co-occurrence (15%) — which prefixes appear adjacent
- Geographic (35%) — distance to dual-hop anchor points
- Recency (35%) — exponential decay
e^(-hours/12)
When no known candidate is geographically plausible, the decoder selects a "ghost" state. These are clustered and classified into four tiers:
- Confirmed — very high observation count, consistent neighbors, plausible location
- Likely — strong evidence, probably a real undiscovered repeater
- Possible — moderate evidence, worth investigating
- Noise — low evidence, likely path artifacts
Ghost clusters include RF-constrained location estimates, temporal consistency analysis, and collision detection against known nodes.
- Directional edge tracking — forward/reverse counts, symmetry ratio
- Path sequence registry — all observed paths, canonical detection
- Flood vs direct classification — per-edge routing type
- Edge betweenness centrality — backbone identification
- Mobile repeater detection — path volatility analysis
- TX delay recommendations — slot-based timing optimization
- Path health scoring — combined health, weakest link, latency
The frontend includes a complete TypeScript port of the MeshCore protocol — binary packet parsing, header bit-field extraction, per-type payload decoders, channel key derivation, and GRP_TXT decryption (SHA-256, AES-ECB, pure JS — no native dependencies).
If you already have pyMC_Repeater running and just want the dashboard, see INSTALL.md for manual tar.gz installation without manage.sh.
MIT — See LICENSE
Built on the work of:
- RightUp — Creator of pyMC_Repeater, pymc_core, and the MeshCore Python ecosystem
- pyMC_Repeater — Core repeater daemon
- pymc_core — Protocol library
- MeshCore — The MeshCore project and community
- d40cht/meshcore-connectivity-analysis — Viterbi HMM approach for path disambiguation
- meshcore-bot — Recency scoring and dual-hop anchor disambiguation




