Feeding the Mayo Mesh MQTT broker
Flash an observer node that uplinks packets to wss://mqtt.mayomesh.net and powers the live map.
Mayo Mesh runs an MQTT broker at wss://mqtt.mayomesh.net that repeater and observer nodes can uplink packet and status data to. This powers tools like live packet analysers and network dashboards, and is separate from the normal mesh traffic — your node keeps relaying LoRa packets as normal, it just also publishes what it sees over WiFi.
This page covers how to flash MQTT-capable firmware onto a MeshCore repeater/observer and connect it to the Mayo Mesh broker.
This is for repeater/observer nodes only. Companion firmware (your phone-paired node) doesn’t run the MQTT bridge. You’ll need a spare LoRa board with WiFi (e.g. Heltec V3/V4) to dedicate to this.
Preloaded images (easiest option)
We publish ready-to-flash images for Heltec V3 and V4 with the Mayo Mesh broker already baked in — Ireland radio settings and the MQTT connection are preconfigured, so you only need to set WiFi credentials and a device name after flashing.
What’s already set:
- Radio: EU/UK Narrow (869.618 MHz / BW62.5 / SF8) — same as the rest of the Mayo Mesh network
- MQTT connection:
wss://mqtt.mayomesh.net:443(JWT auth, no credentials to enter)
The slot layout differs by board, because Heltec V3 has no PSRAM and can only run 2 active TLS/WSS MQTT connections at once (V4 has PSRAM and can run all 6):
| Slot 1 | Slot 2 | Slot 3 | |
|---|---|---|---|
| V4 | analyzer-us (public) |
analyzer-eu (public) |
mayomesh |
| V3 | disabled | mayomesh |
disabled |
On V3, both public analyzer presets are disabled by default so mayomesh is guaranteed one of the 2 available slots — otherwise it would land in slot 3 behind the two public presets and silently show as (inactive). Re-enable a public preset on V3 with e.g. set mqtt1.preset analyzer-eu, but note doing so may bump mayomesh to inactive since you’d be back at 3 configured slots on a 2-slot board. On V4, tune with set mqtt1.preset none / set mqtt2.preset none as you like — there’s headroom.
Flash it
Put the board into bootloader mode — hold BOOT, press and release RST, then release BOOT (same as in Getting Started) — then with esptool installed (pip install esptool):
esptool.py --chip esp32s3 --port /dev/ttyUSB0 erase_flash
esptool.py --chip esp32s3 --port /dev/ttyUSB0 write_flash 0x0 mayomesh-heltec-v4-mqtt-observer.bin
Swap in the V3 filename and your actual serial port (COMx on Windows) as needed. Each file is a single merged image (bootloader + partition table + app combined), so it flashes in one shot at offset 0x0.
First boot — set your device name, location, Wi-Fi, and admin password
Use the Observer Setup tool — connect over USB, fill in the fields, click Save. It sends the commands below for you over the browser’s Web Serial API (Chrome/Edge only), so there’s nothing to type at a terminal.
Prefer to do it by hand? Connect over serial at 115200 baud and run:
set name MyObserverNode
set lat 53.8000
set lon -9.5000
set wifi.ssid YourWiFiNetwork
set wifi.pwd YourWiFiPassword
reboot
set lat / set lon are optional but worth setting for a fixed observer — they’re what places the node correctly on the map (decimal degrees; find yours on Google Maps by right-clicking your location).
Change the default admin password. These images ship with the fork’s default CLI password (
password) — set your own once connected:password YourNewPassword(the setup tool has a field for this too).
Check it connected with get mqtt.status — see Verify the connection below for details.
Building it yourself
Want a different board, or to customize the build? The bridge firmware comes from a community fork of MeshCore — agessaman/MeshCore, mqtt-bridge-implementation-flex branch — and isn’t part of the official MeshCore web flasher. It adds up to 6 concurrent MQTT connections (“slots”) per device, so a node can uplink to Mayo Mesh’s broker alongside any public MeshCore analyzer services at the same time.
Step 1: Build and flash the firmware
Since this isn’t in the official flasher yet, you’ll need PlatformIO to build it from source:
git clone https://github.com/agessaman/MeshCore.git
cd MeshCore
git checkout mqtt-bridge-implementation-flex
pio run -e heltec_v4_repeater_observer_mqtt -t upload
Pick the build target that matches your board:
| Board | Build target |
|---|---|
| Heltec WiFi LoRa 32 V4 | heltec_v4_repeater_observer_mqtt |
| Heltec WiFi LoRa 32 V3 | Heltec_v3_repeater_observer_mqtt |
| Station G2 | Station_G2_repeater_observer_mqtt |
| LilyGo T-Lora V2.1.1.6 | LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt |
Once flashed, connect over USB serial (or the MeshCore CLI/web app) to configure it.
Step 2: Basic node setup
Set the radio to the EU/UK Narrow preset used across Mayo Mesh (see Getting Started):
set radio 869.618,62.5,8,8
Keep transmit power within the legal limit for the 869 MHz sub-band — see Irish radio settings — and remember antenna gain counts towards it.
Give the node an identifiable name and a location code (any 3-letter code that makes sense to you — it’s used to namespace this device’s MQTT topics, not tied to any specific Mayo Mesh convention):
set name MyObserverNode
set mqtt.iata MAY
Add your WiFi credentials so the node can reach the broker (no quotes needed, spaces are fine):
set wifi.ssid YourWiFiNetwork
set wifi.pwd YourWiFiPassword
Reboot and confirm it came up:
reboot
get wifi.status
Step 3: Point a slot at the Mayo Mesh broker
By default, slots 1 and 2 point at the public analyzer-us / analyzer-eu presets — you can leave those running or disable them (set mqtt1.preset none). Use a free slot (slot 3 in the examples below) for Mayo Mesh:
set mqtt3.preset custom
set mqtt3.server wss://mqtt.mayomesh.net:443
set mqtt3.audience mqtt.mayomesh.net
On non-PSRAM boards (e.g. Heltec V3), only 2 TLS/WSS slots can be active at once. If you leave both public presets enabled and add Mayo Mesh in slot 3, one of the three will silently show as
(inactive)inget mqtt.status— on V3 that’ll be slot 3, meaning Mayo Mesh itself. Disable one of the public presets first (set mqtt1.preset none) to guarantee Mayo Mesh gets a connection.
This uses JWT (Ed25519) authentication — the same scheme as the public analyzer presets — so there’s no username/password to manage. The node signs its own connection using its identity key, keyed to the audience you set above.
Topics follow the default MeshCore pattern, so there’s no need to set mqtt3.topic unless you want a custom layout:
meshcore/{iata}/{device_public_key}/status
meshcore/{iata}/{device_public_key}/packets
meshcore/{iata}/{device_public_key}/raw
Step 4: Verify the connection
get mqtt.status
get mqtt3.diag
get mqtt.status lists each slot’s connection state. If slot 3 isn’t connecting, get mqtt3.diag reports the last error (TLS handshake, socket, or clock/time issue — MQTT auth depends on the node’s clock being correct, so also check get mqtt.ntp.diag if you see certificate/time errors).
What gets published
By default, status messages and packet (RX) messages are enabled; raw messages and TX-packet uplink are off. You can tune this per-node:
set mqtt.packets on|off # decoded packet metadata (RSSI, SNR, type, etc.)
set mqtt.raw on|off # raw packet bytes
set mqtt.rx on|off # uplink received packets
set mqtt.tx on|off|advert # uplink transmitted packets (advert = adverts only)
set mqtt.interval <minutes> # status message interval (default 5)
A packet message looks like:
{
"origin": "MyObserverNode",
"origin_id": "DEVICE_PUBLIC_KEY",
"timestamp": "2026-07-11T12:00:00.000000+00:00",
"type": "PACKET",
"direction": "rx",
"SNR": "12.5",
"RSSI": "-65",
"packet_type": "4",
"raw": "F5930103807E5F1E..."
}
Notes on hardware
- Boards with PSRAM can run all 6 slots at once. Without PSRAM, only 2 TLS/WSS slots can be active simultaneously (each uses ~40 KB of internal heap) — inactive slots show as
(inactive)inget mqtt.status. - WiFi power saving defaults to
none; leave it that way for a fixed observer node, since aggressive power saving can cause missed uplinks.
Resources
- MQTT Implementation doc (agessaman/MeshCore fork) — full CLI reference and build flags
- MeshCore GitHub — upstream firmware
- Getting Started with MeshCore — base radio configuration for Ireland
Note for maintainers: the built-in
mayomeshpreset used by the preloaded images above is a local patch tosrc/helpers/MQTTPresets.h(adds one entry, mirroring how other community networks likechimesh/bostonmesh/nashmeshare defined) plus two new PlatformIO envs (heltec_v4_repeater_observer_mqtt_mayomesh,Heltec_v3_repeater_observer_mqtt_mayomesh) — it hasn’t been pushed to a public fork yet. If you rebuild from a fresh clone of the upstream branch, use thecustombroker steps above instead, or re-apply the same patch.Rebuilding the preloaded images: run
firmware-build/build.shfrom a machine with PlatformIO installed. It clones/updatesagessaman/MeshCoreatmqtt-bridge-implementation-flexintofirmware-build/MeshCore(gitignored — it’s a build cache, not tracked source), appliesfirmware-build/mayomesh-mqtt-preset.patch, builds both boards, and overwrites the two files infirmware/with the fresh output. Run it whenever the upstream branch gets an update worth picking up. If the patch fails to apply (upstream restructuredMQTTPresets.hor the variant.inifiles), the script stops and tells you to re-diff manually — regenerate it withgit diff > firmware-build/mayomesh-mqtt-preset.patchfrom insidefirmware-build/MeshCoreafter re-applying the same three changes by hand.