ZephCore
CustomA ground-up port of MeshCore from Arduino to the Zephyr RTOS. Replaces the Arduino loop with Zephyr's event-driven primitives so the CPU sleeps between events, while aiming for full protocol compatibility with stock MeshCore firmware and the MeshCore mobile apps.
Reimplementation of MeshCore (Reference)
- Maintainer
- liquidraver ↗
- Status
- Active
- Maturity
- Beta
- Lifecycle
- Active
- Latest version
- 1.16.8-zephcore
- Released
- 2026-07-31
- Runtime
- Zephyr · C++
- Distribution
- Community
- Licensing
- Open source
- License
- MIT
Capabilities
Transports
- ✓ BLE
- ✓ USB serial
- ✓ Native TCP
- ✓ Wi-Fi AP
Operations
- ✕ Web flasher
- ✓ OTA updates
- ✓ BLE DFU
Networking
- ✓ Repeater
- ✓ Room server
- ✓ Observer
- ✓ MQTT
- ✕ KISS modem
Hardware
- ✓ GPS
- ✓ Display
- ✓ Sensors
- ✓ Low-power RX
Protocol
- ✓ MeshCore compatible
- ✓ Raw packet send
- ✓ Raw packet observe
Node role
Features
- Zephyr RTOS event-driven architecture
- CAD-based RX power saving
- Adaptive contention window
- Adaptive Power Control
- DFU / OTA update support
- Listen-only observer (WiFi + MQTT)
- Protocol-compatible with MeshCore apps
Project signals
- GitHub stars
- 129
- Forks
- 31
- Watchers
- 8
- Open issues
- 14
- Contributors
- 14
- Release downloads
- 5,937
- Latest downloads
- 53
- Source available
- Yes
- Releases available
- Yes
- CI builds
- Yes
Releases
from GitHub · updated 2026-07-31v1.16.8-zephcore # Latest Pre-release 5 days ago · 2026-07-31 15:45 UTC
ZephCore 1.16.8-zephcore
[!CAUTION] This is a pre-release. ESP32 light sleep is enabled by default on Heltec repeaters and has not been validated on hardware yet — see the light-sleep section for what to check and how to build it out. It is deliberately not published to the apps.meshamerica.com configurator, which keeps offering v1.16.7; flash this one manually from the assets below if you want to help test it. The nRF based boards should be fine.
[!IMPORTANT]
Before you upgrade
From v1.16.5 / v1.16.6 / v1.16.7 — clean flash, no re-bond, bonds and data survive.
From v1.16.2 / v1.16.3 / v1.16.4 — clean flash, bonds and data survive. If you are on an ESP32-S3 / ESP32-C board and have not yet taken the v1.16.5 update, you still owe the one-time serial reflash: the app moved to flash offset
0x10000in v1.16.5, and a board on the old layout cannot cross that update over WiFi-OTA or the browser flasher — flash the-merged.binonce over USB/serial. Affected boards: Heltec V3 / V4 / V4.3, Station G2, Wireless Tracker / V2, XIAO ESP32-S3 / C3 / C6, LilyGo T-Lora C6, ThinkNode M9. Identity, contacts, channels, prefs, and BLE bonds are preserved. nRF52, classic ESP32 (T-Beam / PICO-D4 / TTGO LoRa32), STM32WL, and native Linux are unaffected.From v1.16.1 or older — flash it; on first boot it clears BLE bonds automatically (identity, contacts, channels, prefs preserved). Re-bond your phone/desktop once.
Coming from Arduino MeshCore — flash it; auto-formats on first boot (new identity, clean storage).
Heltec ESP32 repeaters now light-sleep, and their USB CLI stops answering 10 minutes after boot as a result. Reconnecting your terminal normally resets the node and gives you another 10 minutes; if it doesn't, power-cycle. Details in the light-sleep section below.
One CLI rename:
set/get cad.probe.intervalis nowset/get probe.interval— the same setting, renamed because one measurement now feeds both the noise floor and the CAD probe. Your stored value carries over; only the command name changed.set/get agc.reset.intervalis gone (see below).Take this with a grain of salt — try the formatters if anything anomalous happens with your node.
A power and radio-measurement release. Repeaters no longer wake on a fixed 5 s tick — they sleep until their next real deadline. Every ESP32 build drops to 80 MHz, and Heltec repeaters now light-sleep between packets. The noise-floor sampler and CAD probe were unified into one measurement, the SX126x RSSI/AGC calibration is now band-correct, and the observer role got a batch of fixes for settings that silently never reached the hardware.
Highlights
Repeaters are now deadline-driven — the periodic housekeeping tick is gone
Every repeater woke five times a second-and-a-bit forever: a fixed 5 s "housekeeping" timer that ran the noise-floor sample, the CAD probe, advert timers and the tempradio revert. None of that actually needs a poll — each item is either a deadline or a sampler with its own interval.
The new
mesh/Maintenance.hcontract lets the event loop ask "when does maintenance next have work?" and arm one one-shot wake for exactly that moment. An idle repeater now sleeps until its soonest real deadline instead of on a fixed cadence. A hard ceiling (CONFIG_ZEPHCORE_MAINTENANCE_BACKSTOP_MS, default 60 s) clamps the wake as a safety net against a missed deadline — it should never bind in normal operation.Companions and room servers keep their periodic tick deliberately: the companion block contains genuine pollers (contact-dump progress, BLE advertising watchdog) with no deadline to arm, and the room server is paced by its own 500 ms push timer regardless.
ESP32 power: 80 MHz everywhere, and light sleep on Heltec repeaters
Espressif parts have no equivalent of the nRF52's "idle at microamps in WFI" —
WAITIgates the core clock but le …v1.16.7-zephcore # 11 days ago · 2026-07-25 13:15 UTC
ZephCore 1.16.7-zephcore
[!IMPORTANT]
Before you upgrade
From v1.16.6 / v1.16.5 — clean flash, no re-bond, bonds and data survive.
From v1.16.2 / v1.16.3 / v1.16.4 — clean flash, bonds and data survive. If you are on an ESP32-S3 / ESP32-C board and have not yet taken the v1.16.5 update, you still owe the one-time serial reflash: the app moved to flash offset
0x10000in v1.16.5, and a board on the old layout cannot cross that update over WiFi-OTA or the browser flasher — flash the-merged.binonce over USB/serial. Affected boards: Heltec V3 / V4 / V4.3, Station G2, Wireless Tracker / V2, XIAO ESP32-S3 / C3 / C6, LilyGo T-Lora C6. Identity, contacts, channels, prefs, and BLE bonds are preserved. nRF52, classic ESP32 (T-Beam / PICO-D4 / TTGO LoRa32), STM32WL, and native Linux are unaffected.From v1.16.1 or older — flash it; on first boot it clears BLE bonds automatically (identity, contacts, channels, prefs preserved). Re-bond your phone/desktop once.
Coming from Arduino MeshCore — flash it; auto-formats on first boot (new identity, clean storage).
Take this with a grain of salt — try the formatters if anything anomalous happens with your node.
A stability-and-hardware release. The headline is a whole-node wedge fixed in the GPS power-management path that shipped in v1.16.6, plus RX duty cycle finally working on LR1110 boards and a new safety margin that stops signal-independent duty-cycle packet drops on every radio. Rounded out by joystick-UI fixes and a color-display improvement for the Heltec T114.
Highlights
Fixed: a GPS node could wedge completely on standby (regression in v1.16.6)
v1.16.6 introduced GPS-UART suspend to save power (an armed nRF UARTE receiver costs ~0.5–1 mA even with the GPS module powered down). It had a race that could hang the entire node — no LoRa, no USB, no BLE, CLI answering
-> busy, recoverable only by reboot.The upstream nRF UARTE suspend path spins forever waiting for an
RXTOevent after issuingSTOPRX. In interrupt-driven mode the receiver runs one byte at a time and re-arms from its ISR; if a byte happened to finish in the narrow window where the driver had already disabled theENDRXinterrupt, the receiver was left stopped-and-un-rearmed,STOPRXproduced noRXTO, and the wait never returned — with the main mesh thread stuck inside it. Any nRF board that powers its GPS module down and suspends the port on standby could hit this.Fixed in two independent layers, so neither alone is load-bearing:
ZephyrGPSManagersettles ~5 ms before suspending the GPS UART, letting the last in-flight byte finish and the RX ISR re-arm, so the receiver is armed-and-idle whenSTOPRXfires — the state that reliably yieldsRXTO. Standby happens at most every few minutes, so the cost is negligible.- New patch
0010bounds the driver'sRXTOwait to 4 ms instead of spinning forever. On timeout it falls through to the unconditionalnrf_uarte_disable()that force-stops the receiver anyway — so even if a byte still lands in the race window, the node can never hang.
RX duty cycle now works on LR1110 boards
LR1110 boards (T1000-E, ThinkNode M9, and other LR11xx radios) now get real RX duty-cycle sniff mode instead of sitting in continuous receive — a substantial receive-power saving on battery nodes, the same mechanism SX126x boards have had. This took a significant rework of the LR11xx LoRa driver to land correctly.
New: duty-cycle safety margin stops signal-independent packet drops
set-able viaCONFIG_ZEPHCORE_LORA_DC_MARGIN_PCT(default 15%), shared by every radio (SX126x / LR11xx / LR20xx).The theoretical per-cycle "deaf-time" budget that duty cycle is computed from assumes the sleep clock and the wake transition are exact. They are not: the chip's sleep timer runs on an internal RC oscillator (RC64k on SX126x, RTC on LR11xx) that drifts several …
v1.16.6-zephcore # 13 days ago · 2026-07-23 15:33 UTC
ZephCore 1.16.6-zephcore
[!IMPORTANT]
Before you upgrade
From v1.16.5 — clean flash, no re-bond, bonds and data survive.
From v1.16.2 / v1.16.3 / v1.16.4 — clean flash, bonds and data survive. If you are on an ESP32-S3 / ESP32-C board and have not yet taken the v1.16.5 update, you still owe the one-time serial reflash described there: the app moved to flash offset
0x10000in v1.16.5, and a board on the old layout cannot cross that update over WiFi-OTA or the browser flasher — flash the-merged.binonce over USB/serial. Affected boards: Heltec V3 / V4 / V4.3, Station G2, Wireless Tracker / V2, XIAO ESP32-S3 / C3 / C6, LilyGo T-Lora C6. Identity, contacts, channels, prefs, and BLE bonds are preserved. nRF52, classic ESP32 (T-Beam / PICO-D4 / TTGO LoRa32), STM32WL, and native Linux are unaffected.From v1.16.1 or older — flash it; on first boot it clears BLE bonds automatically (identity, contacts, channels, prefs preserved). Re-bond your phone/desktop once.
Coming from Arduino MeshCore — flash it; auto-formats on first boot (new identity, clean storage).
Take this with a grain of salt — try the formatters if anything anomalous happens with your node.
A maintenance release: an important admin-password fix, a substantial identity-key randomness hardening on ESP32, GPS standby power savings, and the removal of Adaptive Power Control — plus two new boards, muzi works R1 Neo and an experimental first cut at the ThinkNode M9 in dev.
Highlights
2-tap and 5-tap are switched
After a lot of inadvertently sent adverts, the functions of the 2 and 5 clicks were switched, so a double click with the user button now only enables/disables the LEDs and no longer accidentally sends a flood advert.
Fixed: uppercase letters in an admin password were silently lowercased
If you set or changed an admin password on v1.16.5 and can no longer log in, this is why. v1.16.5 introduced case-insensitive CLI keywords by lowercasing the first two words of every command before matching them. That is safe for
get cad— butpassword <value>puts the value in the second word, sopassword MyPasswas stored asmypass, and the password you typed afterwards never matched. (set guest.password <value>has three words and was never affected.)The normalizer has been removed and CLI commands are case-sensitive again, matching upstream Arduino MeshCore. If you are locked out, re-flash and reconfigure, or log in with the all-lowercase form of the password you set.
The one place autocapitalization genuinely hurts — typing commands to the V-Contact from a phone keyboard, which capitalizes the first letter of every line — is handled narrowly instead: only character 0 of a V-Contact chat line is folded. No command takes an argument at position 0, so no value can be touched.
Identity keys are now generated with hardened, hardware-verified randomness
Your node's identity — the Ed25519 keypair that is your node on the mesh — is generated once, on first boot, and kept for life. An investigation into how the randomness behind that key is gathered found that ESP32 boards were generating identities with far less entropy than intended. Two independent problems, both fixed in this release:
- The ESP32 hardware RNG was running unseeded. It only produces true random numbers while the radio (WiFi/BT) is active — and identity generation runs before the radio comes up (on repeaters, the radio never comes up at all). Key generation now feeds the RNG from the chip's ADC noise source for its duration, Espressif's documented method for exactly this pre-radio situation. Verified on hardware: the RNG's output went from a fixed pattern to statistically ideal.
- The timing-jitter backup source measured nothing on ESP32. It sampled the CPU's cycle counter against work …
Device compatibility (35)
| Device | MCU | Radio | Status | Notes |
|---|---|---|---|---|
| RAK WisBlock / WisMesh (RAK 4631) | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Atlavox M1 | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Atlavox Beacon Solar | nrf52840 | Semtech SX1262 | ✓ Supported | |
| RAK WisMesh Repeater Mini | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Yeti Wurks Base Station | nrf52840 | Semtech SX1262 | ✓ Supported | |
| μArt.cz Solar Node Station | nrf52840 | Semtech SX1262 | ✓ Supported | |
| LilyGo T-Echo | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Wio Tracker L1 | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Wio Tracker L1 Pro | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Heltec V3 | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Heltec WSL3 | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Heltec V4 | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Heltec V4 + Expansion Kit (Touch) | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Heltec T114 | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Heltec Wireless Tracker v3 | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| LilyGo T-Beam (SX1262) | esp32 | Semtech SX1262 | ✓ Supported | |
| LilyGo T-LoRa C6 | esp32-c6 | Semtech SX1262 | ✓ Supported | |
| RAK WisMesh 1W Booster (3401 + 13302) | nrf52 | Semtech SX1262 | ✓ Supported | |
| RAK WisMesh Tag | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Seeed Studio SenseCAP Solar Node P1 | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Seeed Studio SenseCAP Solar Node P1-Pro | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Seeed Studio SenseCAP T1000-E | nrf52840 | Semtech LR1110 | ✓ Supported | |
| UnitEng Station G2 | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Elecrow ThinkNode M1 | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Elecrow ThinkNode M3 | nrf52840 | Semtech LR1110 | ✓ Supported | |
| Elecrow ThinkNode M6 | nrf52840 | Semtech SX1262 | ✓ Supported | |
| ProMicro nrf52 (faketec) | nrf52840 | Semtech SX1262 | ✓ Supported | |
| GAT-IoT GAT562 30s | nrf52 | Semtech SX1262 | ✓ Supported | |
| Xiao C3 | esp32-c3 | Semtech SX1262 | ✓ Supported | |
| Xiao C6 | esp32-c6 | Semtech SX1262 | ✓ Supported | |
| Xiao S3 WIO | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Xiao S3 (plain) | esp32-s3 | Semtech SX1262 | ✓ Supported | |
| Xiao nRF52 WIO | nrf52840 | Semtech SX1262 | ✓ Supported | |
| Xiao MG24 + SX1262 | efr32mg24 | Semtech SX1262 | ✓ Supported | |
| Xiao nRF54L15 + SX1262 | nrf54l15 | Semtech SX1262 | ◑ Partial | Early bring-up; not all peripherals wired. |