Offband Mesh · Releases
from GitHub · updated 2026-06-2110 releases
v1.0.0 # 3 days ago · 2026-06-18 00:46 UTC
First production-stable Offband release — companion, observer, and repeater roles all working and hardware-verified. Built on the MeshCore 1.16.0 base.
Base
- MeshCore 1.16.0 base-update (#126) — the fork is rebased onto upstream MeshCore 1.16.0, smoke-verified across all three active roles (Companion, Observer, Repeater) on Heltec V3/V4 + RAK3401.
Added
- RAK3401 (WisMesh 1W) GPS (#104) — the RAK12500 (u-blox ZOE-M8Q) I²C GPS now works in Slot D. Companion and repeater acquire a position fix. (Position only; the I²C path does not sync the clock.)
- Display always-on toggle (#141) —
display always onkeeps a USB/mains-powered observer's screen lit;display normalrestores the 15 s timeout. Persists across reboots, applies immediately. Heltec V3, V4 OLED, V4 TFT observers. - Display rotation (0/180) (#148) —
display rotate 0/180/display flipover the_syschannel; persists, applies immediately. Verified on the OLED observers (Heltec V3, V4 OLED). Displays without a verified rotation driver (the V4 TFT) reportrotation not supported on this displayrather than silently no-op'ing; TFT rotation is tracked separately.
Known issues
- Heltec V4 observer GPS position unverified (#149) — an attached UART GPS doesn't yet surface a position on the V4 observer (reads 0,0). Observer time (NTP/SNTP) and all other function are unaffected; GPS only adds the device's own map-position dot.
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
- epic(#126): MeshCore 1.16.0 base-update (integration) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/134
Full Changelog: https://github.com/OffbandMesh/meshcore-firmware/compare/offband-v0.18.1...offband-v1.0.0
v0.19.0-rc1 # Pre-release 5 days ago · 2026-06-16 04:06 UTC
Display
_sysenhancements (RC1 — for testing)Two new observer/companion display controls over the
_syschannel:- Display always-on (#141) —
display always onkeeps the screen lit;display normalrestores the 15 s blank. (Verified: V3/V4 OLED + V4 TFT.) - Display rotation 0/180 (#148) —
display rotate 0/display rotate 180/display flipflip the screen for upside-down mounting. (Verified: V3/V4 OLED.)
⚠️ TFT 180° rotation is UNVERIFIED — this is the thing to test. On the Heltec V4 TFT (
heltec_v4_tft_companion_observer_wifi),display rotate 180uses a best-guess MADCTL combo (flipScreenVertically). Please confirm it gives a clean 180° flip (upside-down but readable), not a mirror or garbled image.display rotate 0should return to normal;display flipshould toggle. Report back — it's a one-line fix if the combo is wrong.TFT flash:
heltec_v4_tft_companion_observer_wifi-v0.19.0-rc1-14bc32d-merged.bin(full image — web-flasher "Full Firmware" for a fresh install), or the.bin(app-only) to update an existing node and keep its identity/config.
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.Full Changelog: https://github.com/OffbandMesh/meshcore-firmware/compare/offband-v0.18.1...offband-v0.19.0-rc1
- Display always-on (#141) —
v0.18.1 # 6 days ago · 2026-06-15 03:08 UTC
Fixed
- WiFi password confirmation wording —
set wifi.pwdnow replieswifi.pwd set (N chars entered)instead ofwifi.pwd set (length=N), which was being misread as a 17-character maximum. The reply reports the length of what was entered (never the secret PSK); it is not a cap. WiFi passwords accept the full WPA2 range (8–63 chars).
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(observer): wifi.pwd confirmation wording (0.18.1) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/139
Full Changelog: https://github.com/OffbandMesh/meshcore-firmware/compare/offband-v0.18.0...offband-v0.18.1
- WiFi password confirmation wording —
v0.18.0 # 6 days ago · 2026-06-15 02:56 UTC
Added
- Heltec V4 TFT observer build (
heltec_v4_tft_companion_observer_wifi) — the observer role on the TFT (ST7789) display variant, switched to the NimBLE stack the observer requires. Added to the CI build matrix and the release env set so it always builds and ships.
Changed
- Firmware download clarity — a "Which file?" table in the README and a static
footer appended to every GitHub Release, explaining
-merged.bin(first install) vs.bin(update) vs.uf2(nRF52).
Fixed
pio-flashdevice matching —find_in_registryprefers an exact DeviceID-instance match over a class-only label, so a registered chip is no longer shadowed by a same-class device with null discriminators (fixes nRF52/ESP32 mislabels where two boards share a VID:PID).
Internal
- Wire a gitignored
HARDWARE.local.md(symlink to the LoRa hardware inventory) plus a CLAUDE.md "read before any hardware work" pointer.
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
- docs(#127): MeshCore 1.16.0 base-update merge plan by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/133
- feat: Heltec V4 TFT observer build (always-build) + flash docs & tooling by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/138
Full Changelog: https://github.com/OffbandMesh/meshcore-firmware/compare/offband-v0.17.0...offband-v0.18.0
- Heltec V4 TFT observer build (
v0.18.0-rc1 # Pre-release 7 days ago · 2026-06-14 22:46 UTC
(No CHANGELOG entry for v0.18.0-rc1.)
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
- docs(#127): MeshCore 1.16.0 base-update merge plan by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/133
- feat: Heltec V4 TFT observer build (always-build) + flash docs & tooling by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/138
Full Changelog: https://github.com/OffbandMesh/meshcore-firmware/compare/offband-v0.17.0...offband-v0.18.0-rc1
v0.17.0 # 7 days ago · 2026-06-14 07:31 UTC
First release under OffbandMesh/meshcore-firmware. Bundles the 0.16.0 observer work below (which landed on
firmware-basebut was never separately tagged) with the Crosswire→Offband rebrand and the OffbandMesh org cutover. (Version pending owner confirmation; the tag is hardware-gated per VERSIONING.md.)Changed
- Rebranded the fork from Crosswire to Offband (GitHub org
OffbandMesh): the C++ namespace, build macros, embedded identity blob, version prefix (offband-v*), MQTT / flash-audit identity fields (offband_*), brand strings (serial banner,versioncommand, OLED splash, Home Assistant manufacturer), and the WiFi setup-AP SSID (Offband-Observer-). Historicalcrosswire-v*release tags are preserved; the_sysPSK domain separator and the MeshCore interop topic namespace are intentionally unchanged. (#100) - Repo / board / working-dir cutover to OffbandMesh — repo
OffbandMesh/meshcore-firmware, OffbandMesh org Projects board, and the preflight / CLAUDE.md / label-sync workflow re-pointed; removed the stale upstreamCNAME. (#107, #111)
Docs
- Finished the rebrand reference cleanup across docs + code comments. (#113, #114)
- Release-readiness pass: README getting-started + multi-role positioning, the
docs index surfaces the observer guides, and observer
_sysCLI reference corrections. (#117)
What's Changed
- feat: observer MQTT connectivity (crosswire-v0.15.0) — #53 #48 #63 #68 by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/72
- docs: fix README license link (LICENSE.txt -> license.txt) — #73 by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/74
- docs: 2026-06-10 observer-MQTT session handoff — #75 by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/76
- chore: relocate to C:/Dev/Crosswire — canonical hook sync + AM repin by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/78
- docs(#79): correct stale active-agents line in CLAUDE.md by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/80
- Observer: time arbiter (#69) + position in /status (#31) + _sys CLI grammar (#45) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/91
- Observer follow-ups: arbiter decouple + held-state (#87) + /status radio from runtime prefs (#88) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/92
- docs: README/CHANGELOG 0.16.0 (#93) + observer instructions (#94) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/99
- #95: observer MQTT broker pre-config + per-device auth by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/105
- #98: mqtt view + mqtt clear (broker config inspection) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/106
- Offband rebrand: Crosswire -> Offband (code + docs) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/108
- chore(#107): finish OffbandMesh local cutover (preflight, CLAUDE.md, board #1) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/109
- chore(#111): remove stale upstream CNAME (docs.meshcore.nz) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/112
- docs(#113): finish rebrand — Strycher/Crosswire refs + CLAUDE.md PROJECT_PAT note by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/115
- chore(#114): update stale Strycher/Crosswire# refs in code comments -> #N by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/116
- epic(#117): Offband release-readiness — docs, observer reference, CHANGELOG prep by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/125
Full Changelog: https://github.com/OffbandMesh/meshcore-firmware/compare/crosswire-v0.14.0...offband-v0.17.0
- Rebranded the fork from Crosswire to Offband (GitHub org
v0.17.0-rc1 # Pre-release 7 days ago · 2026-06-14 07:15 UTC
(No CHANGELOG entry for v0.17.0-rc1.)
What's Changed
- feat: observer MQTT connectivity (crosswire-v0.15.0) — #53 #48 #63 #68 by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/72
- docs: fix README license link (LICENSE.txt -> license.txt) — #73 by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/74
- docs: 2026-06-10 observer-MQTT session handoff — #75 by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/76
- chore: relocate to C:/Dev/Crosswire — canonical hook sync + AM repin by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/78
- docs(#79): correct stale active-agents line in CLAUDE.md by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/80
- Observer: time arbiter (#69) + position in /status (#31) + _sys CLI grammar (#45) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/91
- Observer follow-ups: arbiter decouple + held-state (#87) + /status radio from runtime prefs (#88) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/92
- docs: README/CHANGELOG 0.16.0 (#93) + observer instructions (#94) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/99
- #95: observer MQTT broker pre-config + per-device auth by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/105
- #98: mqtt view + mqtt clear (broker config inspection) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/106
- Offband rebrand: Crosswire -> Offband (code + docs) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/108
- chore(#107): finish OffbandMesh local cutover (preflight, CLAUDE.md, board #1) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/109
- chore(#111): remove stale upstream CNAME (docs.meshcore.nz) by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/112
- docs(#113): finish rebrand — Strycher/Crosswire refs + CLAUDE.md PROJECT_PAT note by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/115
- chore(#114): update stale Strycher/Crosswire# refs in code comments -> #N by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/116
- epic(#117): Offband release-readiness — docs, observer reference, CHANGELOG prep by @Strycher in https://github.com/OffbandMesh/meshcore-firmware/pull/125
Full Changelog: https://github.com/OffbandMesh/meshcore-firmware/compare/crosswire-v0.14.0...offband-v0.17.0-rc1
v0.14.0 # 10 days ago · 2026-06-10 23:45 UTC
Added
- CI release pipeline (epic #14): dev-channel firmware artifacts on every
firmware-basepush / PR (ci.yml), and arelease.ymlworkflow that builds the curated community board set fromcrosswire-v*tags and publishes a GitHub Release (pre-release for-rc*, "Latest" for stable). Curated env set in.github/release-envs.txt(72 envs;heltec_v4_repeater_telemetrygated on #20). Design of record:docs/architecture/2026-06-06-ci-release-pipeline.md. (#15, #16, #17)
Changed
- Reconciled inherited CI workflows: removed 7 dead/superseded
(
pr-build-check,auto-promote,github-pages, the three upstream-tagbuild-*-firmwares,branch-cleanup); keptbuild-safeboot-firmwares+sync-labels-to-board. (#18)
What's Changed
- fix(#27): pio-flash firmware_dir -> repo root + --firmware-dir override by @Strycher in https://github.com/Strycher/Crosswire/pull/28
- pio-flash artifact-flash: flash CI release artifacts through the identity gate (#29, #34) by @Strycher in https://github.com/Strycher/Crosswire/pull/35
- fix(#33): OLED splash carries pre-release identifier (v0.14.0-rc1, not v0.14.0+0) by @Strycher in https://github.com/Strycher/Crosswire/pull/37
- chore(#38): gitignore pycache/ by @Strycher in https://github.com/Strycher/Crosswire/pull/40
- feat(#42): strip observer companion to minima + delete dead ring buffer by @Strycher in https://github.com/Strycher/Crosswire/pull/50
- docs: pin Crosswire project identity (Citadel + Agent Mail keys) (#55) by @Strycher in https://github.com/Strycher/Crosswire/pull/56
- docs(#32): position-to-map pipeline architecture draft by @Strycher in https://github.com/Strycher/Crosswire/pull/57
- docs: MeshCore 1.16.0 base-update impact assessment (spike #54) by @Strycher in https://github.com/Strycher/Crosswire/pull/58
- chore(#59): port /work + session-state.py compaction-recovery hook into Crosswire by @Strycher in https://github.com/Strycher/Crosswire/pull/60
- docs(#61): correct CLAUDE.md build/flash + migration-status after meshcore-firmware retire by @Strycher in https://github.com/Strycher/Crosswire/pull/62
Full Changelog: https://github.com/Strycher/Crosswire/compare/crosswire-v0.14.0-rc1...crosswire-v0.14.0
- CI release pipeline (epic #14): dev-channel firmware artifacts on every
v0.15.0 # 10 days ago · 2026-06-10 23:43 UTC
Observer MQTT connectivity -- hardware-validated against three brokers (CoreScope / W8OOF tcp-anon, eastme.sh wss/jwt, LetsMesh-US wss/jwt).
Added
- Owner broker registry: seed the default 6-slot broker set with an
iata=HAOdefault; per-broker GTS Root R4 + ISRG Root X2 CA certificates added and mapped, registry cert-names corrected. (#48) - Per-broker JWT identity claims
jwt_owner/jwt_email(set mqtt.broker.<N>.jwt_owner|jwt_email), surfaced inmqtt status. (#63) - Multi-frame
mqtt statusover the BLE_syschannel: the per-slot broker table spans multiple frames instead of truncating. (#48)
Fixed
- BLE
_syscommand channel no longer hangs whenset mqtt.broker.*runs. The blockingesp_mqttlifecycle ops (connect / destroy) moved offloopTaskto a dedicatedmqtt_workertask with a per-broker lock and a per-slot reconcile flag. (#53) - wss/JWT broker authentication: send the MQTT CONNECT username
v1_<UPPERCASE pubkey>(was a null username) so eastme.sh / LetsMesh accept the connection -- the broker verifies the token'spublicKeyclaim against it and rejects a null username (CONNACK rc=5) even with an otherwise-valid token. (#68)
What's Changed
- fix(#27): pio-flash firmware_dir -> repo root + --firmware-dir override by @Strycher in https://github.com/Strycher/Crosswire/pull/28
- pio-flash artifact-flash: flash CI release artifacts through the identity gate (#29, #34) by @Strycher in https://github.com/Strycher/Crosswire/pull/35
- fix(#33): OLED splash carries pre-release identifier (v0.14.0-rc1, not v0.14.0+0) by @Strycher in https://github.com/Strycher/Crosswire/pull/37
- chore(#38): gitignore pycache/ by @Strycher in https://github.com/Strycher/Crosswire/pull/40
- feat(#42): strip observer companion to minima + delete dead ring buffer by @Strycher in https://github.com/Strycher/Crosswire/pull/50
- docs: pin Crosswire project identity (Citadel + Agent Mail keys) (#55) by @Strycher in https://github.com/Strycher/Crosswire/pull/56
- docs(#32): position-to-map pipeline architecture draft by @Strycher in https://github.com/Strycher/Crosswire/pull/57
- docs: MeshCore 1.16.0 base-update impact assessment (spike #54) by @Strycher in https://github.com/Strycher/Crosswire/pull/58
- chore(#59): port /work + session-state.py compaction-recovery hook into Crosswire by @Strycher in https://github.com/Strycher/Crosswire/pull/60
- docs(#61): correct CLAUDE.md build/flash + migration-status after meshcore-firmware retire by @Strycher in https://github.com/Strycher/Crosswire/pull/62
- feat: observer MQTT connectivity (crosswire-v0.15.0) — #53 #48 #63 #68 by @Strycher in https://github.com/Strycher/Crosswire/pull/72
Full Changelog: https://github.com/Strycher/Crosswire/compare/crosswire-v0.14.0-rc1...crosswire-v0.15.0
- Owner broker registry: seed the default 6-slot broker set with an
v0.14.0-rc1 # Pre-release 14 days ago · 2026-06-07 21:22 UTC
(No CHANGELOG entry for v0.14.0-rc1.)
What's Changed
- docs: adopt versioning + CHANGELOG + release-channel discipline (#11) by @Strycher in https://github.com/Strycher/Crosswire/pull/12
- chore: roll CHANGELOG to v0.13.2 + fix em-dashes to ASCII (#11) by @Strycher in https://github.com/Strycher/Crosswire/pull/13
- epic(#14): CI release pipeline -- dev artifacts + crosswire-v* releases by @Strycher in https://github.com/Strycher/Crosswire/pull/24
- docs(#25): roll CHANGELOG to [0.14.0] (CI release pipeline) by @Strycher in https://github.com/Strycher/Crosswire/pull/26
New Contributors
- @Strycher made their first contribution in https://github.com/Strycher/Crosswire/pull/12
Full Changelog: https://github.com/Strycher/Crosswire/commits/crosswire-v0.14.0-rc1