ZephCore v1.16.4-zephyr
Important
Before you upgrade
Updating from v1.16.2 or v1.16.3 — clean flash, no re-bond required, bonds and data survive.
Updating from v1.16.1 or older — flash the firmware; on first boot it detects the old installation and clears the BLE bond storage automatically. Your identity, contacts, channels, and prefs are preserved. You will need to re-bond your phone/desktop once.
Coming from Arduino MeshCore — flash the firmware; it detects the incompatible filesystem on first boot and formats automatically (new identity, clean storage). No formatter tool required.
Take this with a grain of salt though — try the formatters if anything anomalous happens with your node.
The headline of this release is Mesh Time Sync: an optional, off-by-default feature that lets a node fix its own clock from the mesh — no GPS, no phone. Alongside it: two new board ports, a color-TFT UI pass, a flash-wear fix on GPS nodes, and a batch of multi-byte-path-hash bug fixes.
Highlights
New: Mesh Time Sync — self-correcting clocks from the mesh (simulated from EmpireMesh live data)
Your node can now listen to the timestamps inside other nodes' signed adverts and, if its own clock is clearly wrong, gently correct itself. No GPS and no phone required. It works on every role (repeater, room server, observer, companion).
Why it matters: a node with a wrong clock shows garbage "last heard" times, and after a reboot without a time sync its own adverts can be silently ignored by every node that already knows it. On the live mesh today, almost half of all repeaters are more than an hour off — this fixes that whole class of problem automatically.
It is OFF by default. Nothing changes unless you enable it.
set meshtimesync on— enable (USB serial CLI or remote admin on repeaters/room servers/observers; on companions toggle themeshtimesynccustom variable from the app, or use the same command over the USB text CLI).get meshtimesync— live view, even while the feature is off: how many trustworthy senders it sees, how many agree, and what correction it would make. Worth watching this dry-run for a day before (and after) you enable.
Guardrails, in short: any clock set protects the node for 7 days — a GPS fix and a manual time/clock sync use the exact same 7-day suppression window, so a GPS-synced node is left alone just like a manually-set one (a live GPS re-arms it on every fix); it steps at most ±1 h at a time and at most once per 6 h; it does nothing without a quorum (default 6) of tenured, agreeing senders; and room servers/companions never step backward.
Full documentation — how to switch it on, the honest limitations, and the recovery recipe — is in MESHTIMESYNC.md. Design details (consensus algorithm, security model, why the limits are what they are) are in ARCHITECTURE.md §4.9.
New boards
- Heltec Mesh Node T096 (nRF52840) — SX1262 + KCT8103L PA/FEM, UC6580 GNSS, ST7735S 160×80 color TFT, button, LED, battery ADC.
- Seeed LoRa-E5 mini (STM32WLE5JC) — integrated sub-GHz radio (SX1262-class). No BLE/USB: runs as a companion + CLI over USART1 (serial companion transport).
- TTGO LoRa32 (ESP32 PICO-D4, SX1276) — added as the SX127x reference board (loramac-node backend), USB-UART CLI.
- LilyGo T-Impulse Plus (nRF52840) — LoRa wristband: SX1262 (S62F module, embedded 32 MHz TCXO, GPIO antenna switch), u-blox MIA-M10Q GNSS, SSD1315 128×64 OLED, TTP223 touch button, haptic vibration motor, ZD25WQ32C 4 MB QSPI flash, battery ADC. Companion + repeater. Ported from LilyGo's official sources and builds clean; on-device bring-up pending (see the board README for the hardware-verify checklist).
- Heltec Wireless Tracker V2 (ESP32-S3) — SX1262, ST7735R 160×80 color TFT, UC6580 GNSS. Build-verified across companion, repeater, room server, and observer roles.
Color TFT UI
The single-button and joystick UIs gained color and reworked screens for TFT boards (Heltec T114 ST7789V, T096 ST7735S, Wireless Tracker ST7735R). Color rendering is now gated to TFT panels only, so monochrome OLED/e-paper boards are unaffected. Also fixed: set tx (ADC/TX power) not sticking on the color-screen build.
Fixed: GPS nodes were hammering flash
ZephyrGPSManager was writing to flash on GPS activity, adding needless flash wear on tracker/companion nodes. Those writes are gone — GPS state is kept in RAM and only the intended, rate-limited persistence remains.
Other fixes and improvements
- Fixed: multi-byte path-hash mode bugs. Several paths mishandled the packed path-hash byte (top 2 bits encode hash size, bottom 6 the hop count) when
path.hash.modewas 1 or 2:- Path-discovery responses were wrongly rejected at 2/3-byte hash sizes.
- The joystick UI path editor encoded/decoded paths at a fixed 1-byte hash size instead of the mesh's actual size.
- The companion direct-send retry timeout scaled off the raw packed byte, inflating the timeout by up to ~17× on multi-byte-hash paths.
- Fixed: companion send-retry bug (direct message timeout math, per above).
- Fixed: region scope leaking onto direct-request replies (repeaters & room servers). When a repeater or room server answered a direct request, its flood reply could inherit the transport region of the last flood packet it happened to hear, instead of being sent un-scoped — so replies could go out under the wrong scope. The region is now resolved per received packet and cleared for direct packets. (Ported from upstream PR #2874.)
- Fixed: region table save silently reporting success. Writing the region map to flash always returned "success" even when a write failed (e.g. full filesystem); it now reports the actual write result.
- Fixed: ThinkNode M6 GPS & regulator handling.
- Fixed: Heltec V4 battery reading.
- Fixed: Wio Tracker L1 Grove sensor (I2C) port.
- ESP32: drop the serial/USB transport cleanly on reboot so the port releases instead of hanging.
- Live radio values now auto-refresh on-screen (non-EPD boards). Repeater/UI screens repaint automatically when a live radio value actually changes (frequency, SF, bandwidth, CR, TX power, noise floor, APC state, RX/TX activity) instead of waiting for a manual refresh. E-paper panels are deliberately left out of the auto-repaint so they don't flash on every value change (only real UI events repaint them).
- Platform: Zephyr advanced past v4.4.1 (to the
v4.4-branchtip, heading toward v4.4.2). The most relevant thing this pulls in is an upstream BLE host use-after-free fix: when a phone or desktop disconnected in the middle of a transfer, a deferred ATT "sent" callback could dereference already-freed memory and fault. All companions (nRF52, ESP32-S3, MG24) inherit the fix. - Native Linux target documented — ZephCore also runs as a native Linux process on SBCs (Femtofox / Luckfox Pico Mini, Raspberry Pi + RAK6421 HAT) with a real SX1262 on SPI/GPIO and the app connecting over TCP. See LINUX_NATIVE.md.
- README / ARCHITECTURE / CLI docs updated (RX duty cycle description,
backoff.multiplierdefault, GPS duty knobs, board tables, meshtimesync commands).
Recommended upgrade checklist
- From v1.16.2 / v1.16.3: just flash — bonds and data survive intact.
- From v1.16.1 or older: just flash — firmware self-migrates on first boot; re-bond your phone/computer once.
- From Official MeshCore: just flash — firmware auto-formats on first boot, start fresh.
- Anything odd or suspicious? Format first.