📡 What is this dashboard?
This is a real-time monitoring dashboard for a MeshCore LoRa radio mesh link between Wakefield (WKF) and Sheffield (SHF) in Yorkshire, UK. It connects directly to an MQTT broker over WebSocket and displays live data from both nodes — signal quality, GPS position, packet statistics, and decoded encrypted channel messages.
MeshCore is an open-source, off-grid mesh radio protocol that allows nodes to communicate over LoRa radio without any internet infrastructure. Messages are encrypted with AES-128 and hop across repeaters to extend range.
🔝 Header Bar
| WAKEFIELD ⟵⟶ SHEFFIELD | The animated dashed line shows the active radio link. Dashes flow left when a Sheffield packet is received, right when a Wakefield packet is received. The city labels turn green when that node is online. |
| Session Uptime | How long the browser has been connected to the MQTT broker in this session. Resets on page reload. |
| 🌙 / ☀ Theme button | Toggles between light and dark mode. |
| ? Help button | Opens this help panel. |
| Connection Status | ● Connected — live data flowing. ↻ Reconnecting — broker temporarily unreachable, will retry every 5 seconds. ✕ Disconnected — check MQTT broker availability. |
📦 Node Cards (WKF / SHF)
There are two node cards — one for each end of the link. Each card turns green with a glow when the node is confirmed online. They go amber after 60 seconds without a beacon, and mark offline after 15 minutes of silence.
| WKF // Online / Offline | Current status of the node. Online means a packet has been received recently. |
| Node Name // ID | The node's callsign/name and its unique hex node ID, as broadcast in its ADVERT packets. |
| Beacon: Active / Last: Xs ago | Shows whether the node is actively sending beacon packets. Turns red after 60 seconds without one. |
| Node Reported Signal — RSSI | Received Signal Strength Indicator in dBm. Reported by the remote node itself from the /neighbors packet. Closer to 0 is stronger. Typical good values: −65 dBm or better. Below −95 dBm is very weak. |
| Node Reported Signal — SNR | Signal-to-Noise Ratio in dB. Higher is better. Above 10 dB is excellent. Below 0 dB means the signal is weaker than the noise floor — the node is at the edge of range. |
| Signal Bars | 5-bar visual indicator derived from the RSSI or SNR value. Green = excellent, yellow = fair, red = very weak. |
| Peers | Number of neighbour nodes the gateway can currently hear. |
| Gateway RX Signal — RSSI / SNR | Signal strength as measured at the gateway when it received a raw packet over the air. This is different from Node Reported Signal — it shows how well your Wakefield/Sheffield gateway is hearing the transmitting node, not how well the remote node hears the gateway. |
| Gateway GPS | Latitude/longitude of the gateway node itself, from the /neighbors packet gatewayLat/gatewayLon fields. |
| Neighbour GPS | Latitude/longitude reported by the neighbour node in the /neighbors packet. Shows "No Fix" if the neighbour has no GPS lock (0, 0). |
| Last Seen | Wall-clock time when the most recent packet was received from this node. |
| Last Heard | How long ago the gateway last heard from the neighbour node, calculated from the device uptime timestamps in the packet (not wall-clock time). |
| Node Uptime | How long the remote node has been running since its last reboot, from the /stats packet. |
| Pkts RX / TX | Total packets received and transmitted by the node since boot. |
| Forwarded | Packets this node has relayed on behalf of other nodes in the mesh. A high forwarded count means the node is acting as an active repeater. |
| Free Heap | Available RAM on the node's microcontroller in KB. Low values (below 50 KB) may indicate memory pressure or potential instability. |
📊 Live Packet Monitor
A persistent two-column grid showing the most recent packet of each type received from each node. Cards flash green when updated. WKF is on the left (purple), SHF on the right (amber).
| MESSAGE card | The last message packet received. Shows sender/recipient node IDs (in hex), RSSI, SNR, hop count, message type, and the message text. To=Broadcast means it was sent to all nodes. |
| NEIGHBORS card | The last neighbours report. Shows the gateway name, peer count, the nearest neighbour's name and ID, signal quality, GPS coordinates for both the gateway and the neighbour, and how long ago the neighbour was last heard. |
| STATS card | The last statistics packet. Shows node uptime, RSSI, total packets RX/TX/forwarded/failed, and free heap memory. |
| ADVERT card | The last advertisement (beacon) packet. Shows the node name, hex node ID, gateway, and GPS position. Adverts are broadcast periodically to announce the node's presence on the mesh. |
| RAW card | The last raw encrypted packet. Shows RSSI, SNR, gateway name, hop count, and the raw hex payload. Raw packets are the encrypted over-the-air frames — they may contain channel messages which appear decoded in the Decoded Messages panel below. |
| Hop count | How many repeater nodes the packet passed through before reaching the gateway. "Direct" means 0 hops — the transmitter was heard directly by the gateway. |
| Packet counter (top right) | Total number of MQTT packets received in this session, excluding status packets. |
🔓 Decoded Channel Messages
This panel decrypts and displays channel messages from the raw LoRa packets. Decryption happens entirely in your browser using AES-128 ECB — the encryption keys never leave your device.
| Channel (coloured label) | Green = private channel (secret key required). Purple = hashtag channel (key derived from channel name). Blue = public channel (shared key). |
| From (📻 sender) | The sender's callsign or node name as encoded in the decrypted message payload. |
| Hops | Number of repeater hops the packet took. "Direct" means the sender was in direct radio range of the gateway. |
| Message | The decrypted plain-text message content. |
| Only successful decodes shown | Packets that cannot be decrypted (unknown private channels, hash collisions) are silently dropped and do not appear here. |
🔑 Encryption & Channel Keys
MeshCore uses AES-128 ECB to encrypt channel messages. Each channel has a 16-byte secret key. The dashboard holds ~100 known keys and will attempt to decrypt any GroupText packet it sees.
| Public channel | The default MeshCore channel. Key is publicly known: 8b3387e9c5cdea6ac9e5edbaa115cd72. Anyone can read these messages. |
| Hashtag channels | Channels like #yorkshire, #hamradio, #test. The key is the first 16 bytes of SHA256("#channelname"). Anyone who knows the channel name can join — not truly private. |
| Private channels | Channels with a randomly generated 16-byte secret, such as GB7SR. Only people who have been given the key can decrypt these messages. |
| Channel hash byte | Each packet contains a single byte (first byte of SHA256 of the key) to help receivers identify which key to try. Hash collisions can occur — two different channels may share the same hash byte, causing a decryption attempt that produces garbage. |
| Adding more keys | To decode additional channels, add entries to the CHANNELS array in the dashboard source. Private channel keys must be obtained from the channel owner. |
📻 MeshCore Concepts
| LoRa | Long Range radio modulation used by MeshCore nodes. Operates in the 868 MHz ISM band in the UK/Europe. Typical range: 2–10 km line-of-sight, less in urban areas. |
| MQTT | The messaging protocol used to relay decoded MeshCore packets from the gateway to this dashboard. The gateway publishes packet data to topics like MESHCORE/GB/WKF/.... |
| Repeater / Relay | A MeshCore node that forwards packets it hears to extend the network range. The hop count tells you how many repeaters a packet passed through. |
| ADVERT / Beacon | A periodic broadcast a node sends to announce itself — its name, node ID, and GPS position. Sent every few minutes. The dashboard uses these to update node names and positions. |
| RSSI (dBm) | Received Signal Strength Indicator. −65 dBm = excellent, −75 good, −85 fair, −95 weak, below −100 very weak/unusable. |
| SNR (dB) | Signal-to-Noise Ratio. Above 10 dB = excellent, 5–10 good, 0–5 marginal, below 0 very marginal (LoRa can still decode below 0 dB due to its spread-spectrum nature). |
| Free Heap | The amount of free RAM on the ESP32 microcontroller inside the MeshCore node. Normal is 200–300 KB. Very low values may cause instability. |