Offband Mesh
ForkA MeshCore fork for cross-role firmware enhancements and optimization. Active roles include companion/observer with WiFi+MQTT observation publishing, NimBLE migration, web UI, and repeater with MQTT-to-Mosquitto bridging, burst-WiFi telemetry, heap and power tuning.
Fork of MeshCore (Reference)
- Maintainer
- OffbandMesh ↗
- Status
- Active
- Maturity
- Beta
- Lifecycle
- Active
- Latest version
- 1.3.0
- Released
- 2026-08-06
- Runtime
- Arduino · C++
- Distribution
- Community
- Licensing
- Open source
- License
- MIT
Capabilities
Transports
- ✓ BLE
- ✓ USB serial
- ✓ Native TCP
- ✓ Wi-Fi AP
Operations
- ✕ Web flasher
- ✓ OTA updates
Networking
- ✓ Repeater
- ✕ Room server
- ✓ Observer
- ✓ MQTT
- ✕ KISS modem
Hardware
- ✓ GPS
- ✓ Display
- ✕ Sensors
- ✕ Low-power RX
Protocol
- ✓ MeshCore compatible
Node role
Features
- Companion/observer with WiFi+MQTT observation publishing
- NimBLE migration (off Bluedroid)
- CrashLog / boot-survival diagnostics
- MQTT-to-Mosquitto bridging (repeater)
- Burst-WiFi telemetry
- Heap and power optimization for ESP32-S3
- Web UI
Project signals
- GitHub stars
- 9
- Forks
- 1
- Watchers
- 1
- Open issues
- 159
- Contributors
- 174
- Release downloads
- 332
- Latest downloads
- 31
- Source available
- Yes
- Releases available
- Yes
- CI builds
- Yes
Releases
from GitHub · updated 2026-08-06v1.3.0 # Latest 2 days ago · 2026-08-06 08:16 UTC
Offband v1.3.0 — the field-diagnostics release
This release is about seeing what a node is doing in the field — especially a headless repeater on a roof or a solar node you can't easily reach with a cable. It adds a full crash/observability stack (persistent crash logs, live log capture and off-device forwarding, a runtime watchdog, and a way to drive a node remotely), plus a batch of user-facing quality-of-life controls (turn the LEDs and screen off, choose which notifications you get, map button presses). Under the hood it also lands the shared multi-broker MQTT engine the next release builds on.
Most of this is additive — existing nodes keep working. The one thing to know up front: the biggest under-the-hood piece (repeater multi-broker) is foundation only this release — see Known limitations before you rely on it.
What's in it
Field diagnostics — find out why a node misbehaves
- caplog — the node tees its own log into a small in-memory ring. Levels:
boot/error/debug/packet(packet = every LoRa RX/TX). How you read it depends on the role (see the matrix below): Companion nodes download it to the companion app over BLE; Repeater nodes on WiFi-telemetry builds stream it live off-device to a syslog receiver you run; Room Server / Sensor dump it over serial. - Live forward (Repeater, WiFi-telemetry builds) exists because the in-memory ring is wiped on reboot — a crash destroys exactly the evidence you want. Arm a forward window and the lines land on your receiver as they happen, surviving the reboot.
- CrashLog — a persistent record of the last crash (reason + context) that now survives a reboot on every role, including nRF52. It re-dumps if you connect a serial console a moment too late.
- Watchdog — both ESP32 and nRF52 now auto-recover a hung main loop and report why they reset, so a wedged node reboots itself instead of going dark.
- Command surface (
offband-cmd) — queue a command to a node, check the queue, and pull the result from your workstation over HTTP — no SSH, no serial cable.
Turn off the light show (user-controllable indicators)
- New
led on|off|statusanddisplay auto|always-on|always-offcontrols, over the CLI or the companion app. Persisted across reboots. Good for battery, dark bedrooms, and stealth deployments.
Headless device control
- Notification scope — choose ALL / SELF / NONE so a headless node isn't chattering on every channel message.
- Button-action matrix — map button presses to actions, with reliable edge-capture (no more dropped fast presses) on the T1000-E.
Under the hood
- Repeater multi-broker engine — the shared MQTT broker pool + TLS rotation scheduler now runs on the repeater, with a measured heap-safe concurrency ceiling. (Foundation — see limitations.)
- Per-message RSSI is now populated in the v3 message frames; role-agnostic config dispatch; a pile of flash-tooling robustness fixes.
Which features apply to which role
Feature Companion Repeater Room Server Sensor caplog capture (log ring) ● ● ● ● caplog read-out app (BLE) live syslog forward serial serial CrashLog (persistent, survives reboot) ● ● ● ● Runtime watchdog (auto-recover hangs) ● ● — ● Command surface ( offband-cmd)— ● — — Indicators — turn LED / display off ● (app) ● (CLI) ● (CLI) ● (CLI) Notification scope (ALL/SELF/NONE) ● — — — Button-action matrix ● (T1000-E) — — — ● = in this release · — = not this role. Companion is driven through the app; Repeater through the command surface / CLI; Room Server & Sensor are serial/CLI only for now (no app download, no live forward). Observer is a WiFi build of the companion/repeater and inherits that role's row.
How to use it
- **Pull a log from a node (a …
- caplog — the node tees its own log into a small in-memory ring. Levels:
v1.2.0 # 18 days ago · 2026-07-21 06:48 UTC
Adds MeshSmith Photon‑1W support (both MCU flavors) on the MeshCore 1.16.0 base, and receive-sensitivity recovery on Heltec V4 (external FEM LNA control, which stock MeshCore leaves bypassed), plus the ESP32‑C6 I2C‑scan boot‑hang fix found bench‑validating it, a NimBLE build fix, and flashing‑docs corrections.
Added
- MeshSmith Photon‑1W support — ESP32‑C6 + nRF52 (#193, #194) — vendors MeshSmith's MIT Photon
variants (
meshsmith_photon_esp32c6,meshsmith_photon_nrf52; Seeed XIAO ESP32‑C6 / XIAO nRF52840 + Ebyte E22‑900M30S 1W radio) and wires all roles into CI + the release pipeline. ESP32‑C6 needed minimal MeshCore‑consistent base edits (antenna‑switch virtuals, protected_gps_serial, NimBLE dep); nRF52 needed none. The ESP32‑C6 companion + repeater are bench‑verified on hardware; the nRF52 variant is not yet bench‑verified — review findings tracked as bench checkpoints on #193/#194. - External FEM LNA control on Heltec V4 companions (#298). MeshCore leaves the Heltec V4
front-end module's LNA bypassed at boot, so V4 companions ran with degraded receive
sensitivity. Offband now enables it at companion boot from a persisted
radio_fem_rxgainpreference (default on), on the boards whose FEM exposes an independent LNA line (heltec_v4,heltec_tracker_v2,heltec_t096). A new companion-API command (0xC3, SET/GET) plus a capability bit lets the client show a user toggle, gated on the runtime-detected FEM chip.FIRMWARE_VER_CODE15 -> 16. Verified end-to-end on a KCT8103L (V4.3) board. - Model string names the detected FEM part (#327) — reads
Heltec V4 OLED (KCT8103L)or(GC1109), so a V4.3 (independent LNA control) is distinguishable from a V4.2 in the app.
Fixed
- Photon‑1W ESP32‑C6 hung at boot, dead on the mesh (#294). The C6 variant declares its I2C bus,
but
EnvironmentSensorManager::begin()ran the blind I2C scan regardless; on the C6 the scan wedges the I2C peripheral (hangs at addr0x0d) and never returns, sosetup()never reachedloop(). The scan is now skipped on boards that setENV_SKIP_I2C_SENSOR_SCAN(guard vendored verbatim from MeshSmith's fork); every other board is unchanged. - CLI accepted garbage after a valid key (#299).
get radio foobarreturned the radio settings, andset radio 910.525,62.5,7,5,junksilently applied the first four values and dropped the rest. Keys now require a whole-token match; extraset radioparameters are rejected. - 64 ESP32 BLE companion environments could not build (#199, #90). The NimBLE dependency was
declared per-variant with no shared source, and the greedy source filter pulled the BLE
interface into non-BLE (
usb/wifi) builds too. Factored into a shared config; restores boards silently absent from prior releases, includingHeltec_v2_companion_radio_usbandXiao_C3_companion_radio_usb. A CI invariant now guards every ESP32 env. (The #89 fix below is the first, single-env instance of this class.) - FEM auto-detect source comment corrected (#318, #321). The Heltec V4 FEM type is set by a
board strap, not chip-internal pulls as the code claimed; documented against schematics + the
GC1109 datasheet. A boot detection probe is available behind
-D FEM_DEBUG_PROBE(off by default). pio-flashidentified devices by USB port-path, not identity (#336, #323). Boards were misidentified after any USB port or device swap, and a no-discriminator registry entry wildcard-matched its whole chip family. Now keys on the device-unique USB serial and refuses ambiguous matches; hardware-verified across colliding same-VID:PID boards. Bench tooling, not shipped firmware.pio-flashbootstrap parses the ESP32-C6/H2 base MAC and anchors its MAC regexes (#290, #292). Bench tooling.Xiao_S3_WIO_companion_radio_usbbuild (#89) — excludeSerialBLEInterface.cppfrom the USB companion env (it has no BLE), resolving the `NimBLEDe …
- MeshSmith Photon‑1W support — ESP32‑C6 + nRF52 (#193, #194) — vendors MeshSmith's MIT Photon
variants (
v1.1.2 # 1 month ago · 2026-07-03 00:31 UTC
Companion GPS auto-baud + on-demand GPS status, plus the wedge/time fixes found while validating it on real hardware, and a safer first-flash default — a fresh Observer no longer auto-publishes to a preset MQTT broker. Still on the MeshCore 1.16.0 base.
Added
- GPS auto-baud detection — the companion now detects the GPS modem's baud rate at runtime (probing 115200 then 9600, validating by a checksum-good NMEA sentence), so one image reads either a standard 9600 module or a 115200 one with no rebuild. It re-probes on a GPS enable and keeps trying if a modem is slow to start at boot. (#216, #233)
- On-demand GPS status to the app (
0xC1) — the client can query live GPS state (enabled / detected / fix / baud / lat / lon / alt / sats / time) instead of only seeing position at connect. (#216) - On-device build identity — an optional build tag shows on the app device-info field and the OLED splash, so a specific build is identifiable without a serial console. (#222)
Changed
- Fresh flashes no longer auto-publish to OKIMesh CoreScope. A newly-flashed Observer previously seeded the CoreScope (Dayton) broker enabled, so a device flashed anywhere in the world immediately fed MQTT to OKIMesh CoreScope tagged as a Dayton node. On a fresh flash every broker now ships disabled — the operator opts in per slot. (#262)
- Default region is now
XYZ(a non-geographic placeholder) instead ofHAO(Dayton), so an out-of-region device stops mislabeling itself until the operator sets its region viamqtt iata. Fresh / NVS-erased devices only; existing devices keep their stored config. (#262)
Fixed
- GPS at high baud could wedge BLE. An unbounded GPS read loop let a fast modem (e.g. 115200, multi-constellation) monopolize the main loop and starve BLE — the app would slog or stall. GPS ingestion is now bounded per loop. (#231)
- GPS time showed garbage before the date was acquired. A position fix can arrive
before the calendar date; the device now reports
time=0("acquiring") until a real date is parsed, instead of a wrapped-garbage timestamp. (#232)
Internal
- Build/governance tooling + GPS design & diagnostic records — no firmware-behavior change. (#214, #217–#219)
Which file do I download?
File What it is When to use it *-merged.bin(ESP32 — Heltec V3/V4, XIAO)Full image — bootloader + partition table + app in one, flashed at 0x0after a chip erase. Self-contained, works on a blank chip.First install / clean setup. In a web flasher this is the "Full Firmware" option. *.bin(ESP32)App only — flashed at the app offset ( 0x10000); the bootloader must already be on the chip.Updating an existing node — OTA / "Update Only." Keeps the device identity + WiFi/MQTT config. *.uf2(nRF52 — RAK, T-Echo, XIAO nRF52)Complete self-contained image. First install and updates — double-tap reset, then drag-drop onto the USB drive. (nRF52 has no merged/app split.) ⚠️ ESP32: the app-only
*.binwill not boot if flashed at0x0— use*-merged.binfor a fresh install. A full erase / "Full Firmware" wipes the device's identity + saved config, so use it only for a first install or recovery, never a routine update.What's Changed
- fix(#239): round CLI frequency output to 3 decimals (ftoa3) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/240
- docs(#244): block-user firmware<->app architectural contract by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/245
- feat(#241): Block/Ignore Users — firmware half (BlockStore + 0xC2 sync + DM-drop) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/247
- chore: sync pre-commit to canonical (§0.6) + pin DW_PROJECT=Crosswire by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/249
- fix(#251): pio-flash ESP32-S3 USB-Serial/JTA …
Device compatibility (3)
| Device | MCU | Radio | Status | Notes |
|---|---|---|---|---|
| Heltec V4 | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Heltec V3 | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Xiao S3 WIO | esp32-s3 | Semtech SX1262 | ✓ Supported |