MeshCore Change Analysis

From v1.14.1 to v1.15.0

Change report and upgrade recommendations for production devices

Analysis date: April 19, 2026 · Scope: 159 commits, 112 files, ~5030 added / ~947 removed lines · Analysis by Claude Opus 4.7

Executive Summary

159 commits
112 files changed
+5030 lines added
-947 lines removed
11 FIRMWARE_VER_CODE (was 10)
7.6.0 RadioLib (was 7.3.0)
Short Verdict

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.

Table of Contents

  1. Key Functional Changes (all firmware variants)
  2. Companion Radio Protocol Changes (v10 → v11)
  3. Radio Layer and Library Updates
  4. New and Modified CLI Commands
  5. Bug Fixes and Stability Improvements
  6. Per-Device Impact Analysis
  7. Risks and Potential Issues
  8. Recommendation — Upgrade Plan

1. Key Functional Changes

NEW FEATURE Default scope — regional default for flood packets

src/helpers/RegionMap.{h,cpp} · examples/simple_repeater/MyMesh.cpp · examples/companion_radio/MyMesh.cpp

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:

Changes 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:

CLI 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.

NEW FEATURE PAYLOAD_TYPE_GRP_DATA — binary data in group channels

src/MeshCore.h · src/helpers/BaseChatMesh.cpp · src/Packet.h

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:

Maximum 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).

NEW CLI COMMAND get/set dutycycle — easier duty cycle configuration

src/helpers/CommonCLI.cpp · docs/cli_commands.md 0aa0ec1f

Replaces 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.

2. Companion Radio Protocol Changes (v10 → v11)

BREAKING PROTOCOL FIRMWARE_VER_CODE: 10 → 11

examples/companion_radio/MyMesh.cpp · docs/companion_protocol.md d2fdd6fa

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.

New protocol commands

#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

New response codes

#define RESP_CODE_CHANNEL_DATA_RECV     27
#define RESP_CODE_DEFAULT_FLOOD_SCOPE   28

Renamed existing command

- #define CMD_SET_FLOOD_SCOPE           54   // v8+
+ #define CMD_SET_FLOOD_SCOPE_KEY       54   // v8+ (renamed)
Impact on Client Applications

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:

  • New features (send channel data, default scope) will not be available in older clients
  • If a client checks FIRMWARE_VER_CODE and refuses to communicate above a known threshold — you may hit a problem (rare, but possible)
  • Old command constant names in client code (CMD_SET_FLOOD_SCOPE) still work — the rename is cosmetic in the firmware only

Wire format of new command CMD_SEND_CHANNEL_DATA

Byte 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

3. Radio Layer and Library Updates

LIBRARY UPDATE RadioLib 7.3.0 → 7.6.0

platformio.ini · library.json 7829c518

Bumped jgromes/RadioLib from ^7.3.0 to ^7.6.0. Between these versions:

Risk

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.

FIX ElegantOTA / ESPAsyncWebServer

platformio.ini · arch/esp32/AsyncElegantOTA/ 3a9e1086 e6c6282d
- me-no-dev/ESPAsyncWebServer @ ^3.6.0
+ ESP32Async/ESPAsyncWebServer @ 3.10.3

Source repository change (me-no-devESP32Async) with a pinned version. Improves compatibility with SDK 3.x for ESP32-C6.

FIX Default button polarity — active-LOW

src/helpers/ESP32Board.h · variants/xiao_nrf52/XiaoNrf52Board.h · examples/*/UITask.cpp 0a13ac7f

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);
Affects Xiao nRF52. If you have a custom variant with active-HIGH button logic, add -D USER_BTN_PRESSED=HIGH to your platformio.ini before upgrading. For standard builds the change is transparent.

NEW FEATURE RTC RX8130CE support

src/helpers/AutoDiscoverRTCClock.cpp · src/helpers/RTC_RX8130CE.{h,cpp} (new)

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.

4. New and Modified CLI Commands

CLI Command Changes Summary

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

5. Bug Fixes and Stability Improvements

Key Bug Fixes

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

6. Per-Device Impact Analysis

Heltec V4 (repeater) Wait 1–2 weeks

variants/heltec_v4/HeltecV4Board.{h,cpp} · variants/heltec_v4/LoRaFEMControl.{h,cpp} (NEW) · variants/heltec_v4/platformio.ini

The largest change for this device type. A major refactor of radio front-end module (FEM) control:

Risk

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).

Heltec V3 (companion USB/BLE/TCP) After client app verification

variants/heltec_v3/HeltecV3Board.h · examples/companion_radio/*

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:

Key question: Which client application do you use (MeshCore Web, MeshCore App Android/iOS, meshcore-cli, Python MeshCore)? Verify that its version supports protocol v11 before upgrading your companions.

Xiao nRF52 (2 repeaters) One now (pilot)

variants/xiao_nrf52/XiaoNrf52Board.h · variants/xiao_nrf52/platformio.ini

Two changes directly affecting Xiao nRF52:

1. USER_BTN polarity

// 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.

2. OFFLINE_QUEUE_SIZE

// 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.

3. BLE DFU (relevant!)

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.

Recommendation

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.

7. Risks and Potential Issues

Identified Risks

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

8. Recommendation — Upgrade Plan

Strategy: staged rollout

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.

Recommended Schedule

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.

Pre-Upgrade Checklist (per device)

  1. Export full config with get config and save to a file
  2. If using regions: run region and save the list
  3. Check get path_hash_mode and record the value
  4. Build firmware from the new version (for custom builds)
  5. Flash (OTA / USB / DFU)
  6. After boot verify: firmware version (version), get config, neighbor count, RSSI/SNR
  7. For repeaters: watch get stats for the first hour
  8. For Heltec V4: check get manufacturer_name — should return "Heltec V4 OLED" (or TFT)

What to Do if a Regression Appears

  1. Downgrade to v1.14.1 — keep the previous firmware binary handy
  2. If the problem is region-related — restore the config backup
  3. File an issue on GitHub (meshcore-dev/MeshCore/issues) with:
    • Firmware version
    • Device type (variant)
    • Specific behavior (RSSI, logs, screenshot)
    • Comparison with v1.14.1

Summary Table: Per-Device Decision

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
Closing Thoughts

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.