Change report and upgrade recommendations for production devices
Version 1.15.0 is a major functional update — it introduces the concept of "default scope" (regions), a new payload type PAYLOAD_TYPE_GRP_DATA for binary data in group channels, a new get/set dutycycle command, and a companion protocol version bump (v10 → v11).
The recommended approach is a staged rollout (not all at once) — start with one Xiao nRF as a pilot, then the Heltec V4 (after verifying stability), and finally Heltec V3 companions (after confirming client apps support protocol v11).
Note: this release was published on 19.04.2026 — the same day as this analysis. It is a fresh release; it is worth monitoring early user reports before a mass rollout.
A new concept of a "default scope" has been introduced — a region whose transport key is automatically applied to all flood packets sent by the device, unless a different scope is explicitly specified.
Changes in RegionMap:
default_id field to the persistent region file header (alongside existing home_id)getDefaultRegion() / setDefaultRegion() methodsgetTransportKeysFor(region, dest, max_num) — refactored common key-loading logicisWildcard() to RegionEntryChanges in the repeater (simple_repeater/MyMesh.cpp):
// New method: sendFloodReply - replies preserve the scope of the incoming request
void MyMesh::sendFloodReply(mesh::Packet* packet, unsigned long delay_millis, uint8_t path_hash_size) {
if (recv_pkt_region && !recv_pkt_region->isWildcard()) {
TransportKey scope;
if (region_map.getTransportKeysFor(*recv_pkt_region, &scope, 1) > 0) {
sendFloodScoped(scope, packet, delay_millis, path_hash_size);
} else {
sendFlood(packet, delay_millis, path_hash_size); // send un-scoped
}
} else {
sendFlood(packet, delay_millis, path_hash_size); // send un-scoped
}
}
All places where the repeater called sendFlood() for replies (login, group-key, ACK, CLI reply, anon req) have been replaced with sendFloodReply(). Result: if a request arrived in a specific regional scope, the reply is sent back in that same scope rather than as an un-scoped flood.
Changes in companion_radio:
NodePrefs: default_scope_name[31] and default_scope_key[16]CMD_SET_DEFAULT_FLOOD_SCOPE (63), CMD_GET_DEFAULT_FLOOD_SCOPE (64)sendFloodScoped() (for ContactInfo and GroupChannel) now fall back to default_scope when the current send_scope is emptyCLI changes:
region default // show current default
region default <name> // set default (auto-creates region if needed)
region default null // clear default
region put <name> [parent] // NEW: allow-flood by default
region * commands have been refactored from MyMesh.cpp (repeater, room-server) into a shared CommonCLI.cpp. The sensor variant has only minimal wiring, without full default-scope support.
A new payload type allows sending arbitrary binary data (not text) inside group channels — with its own "namespace" for developer and community applications.
// src/MeshCore.h
#define MAX_PACKET_PAYLOAD 184
#define MAX_GROUP_DATA_LENGTH (MAX_PACKET_PAYLOAD - CIPHER_BLOCK_SIZE - 3)
Payload format:
Bytes 0-1: data_type (16-bit little-endian)
Byte 2: data_len (binary length)
Bytes 3+: binary payload data
Type assignments:
0x0000 — not allowed0xFFFF (DATA_TYPE_DEV) — developer-use namespaceMaximum payload length on the companion side: 163 bytes (MAX_FRAME_SIZE - 9). Larger payloads are rejected with PACKET_ERROR.
New companion protocol command:
#define CMD_SEND_CHANNEL_DATA 62
#define RESP_CODE_CHANNEL_DATA_RECV 27
Validation in BaseChatMesh::onGroupDataRecv(): added guards against short/malformed packets (checking len < 5 for GRP_TXT, len < 3 for GRP_DATA, and verifying data_len > available_len).
get/set dutycycle — easier duty cycle configurationReplaces the less intuitive set af (airtime factor) command with a percentage-based value that is much easier to reason about.
| Command | Meaning | af equivalent |
|---|---|---|
set dutycycle 100 |
No duty cycle limit | af = 0 |
set dutycycle 50 |
50% (default) | af = 1 |
set dutycycle 10 |
10% (EU requirements) | af = 9 |
set dutycycle 1 |
1% (strictest EU limit) | af = 99 |
Internally the value is translated to af — stored preferences are not broken. The old set af command is marked as deprecated but still functional.
The companion protocol version has been bumped from 10 to 11. This means that client applications (MeshCore Web, meshcore-cli, Android/iOS, Python libraries) need to be updated to fully use the new features.
#define CMD_SEND_CHANNEL_DATA 62 // binary datagram in channel
#define CMD_SET_DEFAULT_FLOOD_SCOPE 63 // set default region scope
#define CMD_GET_DEFAULT_FLOOD_SCOPE 64 // get default region scope
#define RESP_CODE_CHANNEL_DATA_RECV 27
#define RESP_CODE_DEFAULT_FLOOD_SCOPE 28
- #define CMD_SET_FLOOD_SCOPE 54 // v8+
+ #define CMD_SET_FLOOD_SCOPE_KEY 54 // v8+ (renamed)
Older client application versions (MeshCore Web, Android, meshcore-cli) will continue to work with firmware 1.15.0 — the new commands are extensions, not replacements. However:
FIRMWARE_VER_CODE and refuses to communicate above a known threshold — you may hit a problem (rare, but possible)CMD_SET_FLOOD_SCOPE) still work — the rename is cosmetic in the firmware onlyCMD_SEND_CHANNEL_DATAByte 0: 0x3E (CMD_SEND_CHANNEL_DATA)
Bytes 1-2: Data Type (16-bit little-endian)
Byte 3: Channel Index (0-7)
Bytes 4+: Binary payload (max 163 bytes)
Response: PACKET_OK (0x00) or PACKET_ERROR
Bumped jgromes/RadioLib from ^7.3.0 to ^7.6.0. Between these versions:
RadioLib updates are generally safe, but may subtly alter radio timing/power parameters. No commits indicate regressions, but it is advisable to monitor RSSI/SNR after upgrading.
- me-no-dev/ESPAsyncWebServer @ ^3.6.0
+ ESP32Async/ESPAsyncWebServer @ 3.10.3
Source repository change (me-no-dev → ESP32Async) with a pinned version. Improves compatibility with SDK 3.x for ESP32-C6.
Unified USER_BTN polarity to active-LOW (default). Nearly all LoRa boards use a boot button that pulls to ground when pressed.
// variants/xiao_nrf52/XiaoNrf52Board.h
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
// Change in powerOff()
while (digitalRead(PIN_USER_BTN) == LOW);
while (digitalRead(PIN_USER_BTN) == USER_BTN_PRESSED);
-D USER_BTN_PRESSED=HIGH to your platformio.ini before upgrading. For standard builds the change is transparent.
Added support for the RTC RX8130CE chip (I2C address 0x32) — used in newer GAT562 watches. Auto-detected via I2C probe. Does not affect standard Heltec or Xiao boards.
| Command | Status | Description |
|---|---|---|
region default <name|null> |
NEW | Sets the default regional scope for flood packets. Auto-creates the region if it doesn't exist. |
region put <name> [parent] |
CHANGED | Now defaults to allow-flood (previously required explicit allowf flag). |
get/set dutycycle |
NEW | Set duty cycle as a percentage (1–100). More intuitive than af. |
get/set af |
DEPRECATED | Still functional, but marked deprecated in documentation. |
discover.neighbors |
NEW | Zero-hop neighbor discovery. sendNodeDiscoverReq() moved to the public API. |
neighbor.remove (space) |
NEW | Empty prefix (space) removes all neighbors at once. |
set agc.reset.interval 0 |
NEW | Value 0 disables AGC reset entirely. |
get/set radio.rxgain |
DEFAULT CHANGED | New installs default to on (was off in some variants). Now officially documented. |
| GPS status output | FORMAT | New format: on, {active|deactivated}, {fix|no fix}, {N} sats |
| Commit | Type | Description |
|---|---|---|
| 49b37d56 | BOUNDS | Minor bounds fix in RegionMap.cpp (landed the day before release) |
| 74139288 | OFF-BY-ONE | Off-by-one in memcmp — comparison length corrected |
| df1e12de | REPEATER | sendFloodReply() rule change — replies now preserve incoming scope |
| cfe4b0b9 | BLE | Bleuart service stays registered first — fixes Android GATT cache issue for already-paired devices (nRF52 only) |
| b898e7a0 | BLE DFU | DFU added to main BLE stack — paired clients see DFU without switching to OTA mode (nRF52 only) |
| f8dbdce6 | GPS | Companion radio — "GPS enabled" preference now applied at boot (was ignored previously) |
| 285fc685 | RADIO | Allow lower LoRa frequencies |
| 8056344b | WAVESHARE | Fix RX sensitivity on Waveshare RP2040 (added SX126X_RXEN=17) |
| 2325973f | GPS | applyGPSPrefs() called in one place (outside UITask) — more consistent behavior |
| BaseChatMesh | VALIDATION | Added group payload length validation — short/malformed packets are now dropped instead of causing a crash |
The largest change for this device type. A major refactor of radio front-end module (FEM) control:
LoRaFEMControl class supporting two FEM chip types:
GC1109_PA — original Heltec V4KCT8103L_PA — newer Heltec V4.3platformio.ini:
-D P_LORA_GC1109_PA_EN=2
-D P_LORA_GC1109_PA_TX_EN=46
-D P_LORA_KCT8103L_PA_CSD=2
-D P_LORA_KCT8103L_PA_CTX=5
getManufacturerName() now returns:
"Heltec V4 OLED" / "Heltec V4 TFT" (original FEM)"Heltec V4.3 OLED" / "Heltec V4.3 TFT" (new FEM)OFFLINE_QUEUE_SIZE=256 for WiFi variants (was default ~16)onBeforeTransmit() / onAfterTransmit() to use loRaFEMControl.setTxModeEnable() / setRxModeEnable()This refactor touches the critical RF path (PA/LNA control). A regression could cause hardware damage or a drastic drop in range. Commit 49b37d56 ("minor bounds fix") landed the day before the release, suggesting last-minute changes to this code.
Note: if you have local modifications to variants/heltec_v4/platformio.ini, verify that your changes are compatible with the new pin naming scheme (P_LORA_GC1109_PA_EN instead of P_LORA_PA_EN).
Changes to the board support itself are minimal:
// variants/heltec_v3/HeltecV3Board.h
#ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER 5.42
#endif
// Was hardcoded 5.42 - now overridable
This change is transparent — the default value remains 5.42. It allows ADC calibration overrides for other board variants, but has no impact on standard builds.
What affects you:
Two changes directly affecting Xiao nRF52:
// variants/xiao_nrf52/XiaoNrf52Board.h
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
// In powerOff():
while (digitalRead(PIN_USER_BTN) == LOW); // v1.14.1
while (digitalRead(PIN_USER_BTN) == USER_BTN_PRESSED); // v1.15.0
Default behavior remains active-LOW — no functional change for standard builds.
// variants/xiao_nrf52/platformio.ini (companion_usb env)
+ -D OFFLINE_QUEUE_SIZE=256
Larger offline queue for USB companion — fewer messages lost when the client disconnects. Does not apply to repeater builds.
Commit b898e7a0 adds DFU to the main BLE stack on nRF52. Commit cfe4b0b9 fixes Android GATT cache issues — previously paired devices sometimes required "forget and re-pair" after a firmware update. This is a real stability improvement for your Xiao nRF52 units.
Changes on Xiao nRF52 are low-risk and bring real benefits (BLE stability, offline queue). This makes it the ideal pilot candidate — upgrade one repeater, leave the other on v1.14.1 for 7–14 days, and observe its behavior in the network.
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Release freshness — published 19.04.2026, last-minute fix the day before | medium | undetected regressions | Monitor GitHub issues for 7–14 days; wait for 1.15.1 before upgrading critical devices |
| Companion protocol v10 → v11 | low | older apps may not expose new features | Verify your client app version before upgrading companions |
| Heltec V4 FEM refactor — critical RF path | medium | range loss / TX errors | Do not upgrade your main repeater first; verify range after upgrade |
RegionMap format change — added default_id |
low | backup incompatibility | Theoretically backward-compatible, but back up config before upgrading |
region put default changed to allow-flood |
low | unexpected region behavior | Check existing regions with the region command after upgrading |
| RadioLib 7.3 → 7.6 | low | changed timing parameters | Monitor RSSI/SNR after upgrading |
| Xiao nRF BLE DFU in main stack | low | larger BLE attack surface | DFU requires pairing with MITM protection — secure by default |
Local modifications to variants/heltec_v4/platformio.ini |
high | merge conflict / incorrect build | Review your local changes, back them up, and re-apply on top of the new base |
Release 1.15.0 is not a security-critical update — none of the commits contain an explicitly flagged security vulnerability. The changes are primarily new features (default scope, GRP_DATA, dutycycle) and consolidations (BLE DFU, CLI refactor). There is no urgent need to upgrade "tomorrow".
That said, the upgrade is worthwhile — BLE fixes for nRF52, group payload validation, updated RadioLib, and radio.rxgain=on by default are real improvements.
| Phase | Device | Timing | Rationale |
|---|---|---|---|
| 0 | Backup — export config from all devices | Now | Guard against RegionMap / region config incompatibility |
| 1 | 1× Xiao nRF repeater (pilot) | In 3–5 days (22–24.04.2026) | Lowest-risk upgrade. BLE improvements + offline queue. Verifies that 1.15.0 is stable in your network. |
| 2 | Observation — monitor the pilot | 7–14 days | Check: range, retransmission count, interoperability with v1.14.1 repeaters. Watch GitHub issues. |
| 3 | Heltec V4 (repeater) | ~2 weeks out (early May 2026) | Allows time for a potential 1.15.1 patch. Re-apply local platformio.ini changes on the new base. |
| 4 | 2nd Xiao nRF repeater | After phase 3 | Maintain redundancy — do not upgrade both Xiao units at the same time |
| 5 | Heltec V3 companions (USB, BLE, TCP) | After phase 4 | Verify client app v11 support first. Companions can be upgraded independently of repeaters. |
get config and save to a fileregion and save the listget path_hash_mode and record the valueversion), get config, neighbor count, RSSI/SNRget stats for the first hourget manufacturer_name — should return "Heltec V4 OLED" (or TFT)| Device | Recommendation | Primary Reason | Primary Risk |
|---|---|---|---|
| 1× Xiao nRF repeater (pilot) | Upgrade in 3–5 days | BLE stability + offline queue + low risk — ideal test candidate | Minimal — board-specific changes are small |
| Heltec V4 repeater | Wait 1–2 weeks | Major FEM refactor — watch issues and wait for 1.15.1 | Range loss if PA/LNA control regresses |
| 2nd Xiao nRF repeater | After pilot confirmation | Maintain redundancy — do not upgrade both at once | Risk exposure if pilot reveals a problem |
| Heltec V3 companions (×N) | After client app update | Full benefit only when client app supports v11 | Old apps will still work, but new features unavailable |
Release 1.15.0 is a solid, feature-rich update — not a revolution, but a meaningful expansion of network capabilities (default scope, binary group data). For a typical deployment there is no urgent need to upgrade immediately — v1.14.1 is stable and remains packet-level compatible with v1.15.0 nodes on the mesh.
A "one device at a time, with observation" approach is sensible here — it minimises risk and lets you build confidence with the new version at a comfortable pace.