fix(admin): don't disable BLE on config paths that never reboot (#11651)

Three places took BLE down and left nothing to bring it back. The nRF52
auto-re-advertise bug masked them by restoring advertising ~1s later; with
that fixed (#11650) the outage is real, lasting until the next PowerFSM
transition - up to screen_on_secs, 10 minutes on a default client.

- restore_preferences passed 1000 to reboot(), which takes seconds, arming
  the reset ~16.7 minutes out instead of the intended ~1s. With BLE disabled
  for a pending reboot the node was unreachable for that whole window. Use
  DEFAULT_REBOOT_SECONDS and disable before arming, matching the factory and
  nodedb reset paths.
- mesh_beacon sets shouldReboot=false but was not in the list that spares a
  variant from the blanket disable, unlike statusmessage. Add it.
- MQTT and Serial disable BLE inside their own case, bypassing the
  transaction check above them. Inside an edit transaction saveChanges()
  defers the reboot, so BLE went down with no restore - reachable today by
  importing a device profile containing either module config.

Build: heltec-mesh-node-t096. Tests: test_module_config 3/3.
This commit is contained in:
Ben Meadors authored and GitHub committed 2026-08-31 19:38:35 +00:00
1 parent b8faaaf54b
commit 47db0e3020
1 file changed
+14 -8
+14 -8
View File
@@ -653,8 +653,8 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
SEGMENT_DEVICESTATE | SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_CHANNELS)) {
myReply = allocErrorResponse(meshtastic_Routing_Error_NONE, &mp);
LOG_DEBUG("Rebooting after preferences restore");
reboot(1000);
disableBluetooth();
reboot(DEFAULT_REBOOT_SECONDS);
} else {
myReply = allocErrorResponse(meshtastic_Routing_Error_BAD_REQUEST, &mp);
}
@@ -1233,10 +1233,12 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c, bool fromOthers)
bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
{
bool shouldReboot = true;
// If we are in an open transaction or configuring MQTT or Serial (which have validation), defer disabling Bluetooth
// Otherwise, disable Bluetooth to prevent the phone from interfering with the config
if (!hasOpenEditTransaction && !IS_ONE_OF(c.which_payload_variant, meshtastic_ModuleConfig_mqtt_tag,
meshtastic_ModuleConfig_serial_tag, meshtastic_ModuleConfig_statusmessage_tag)) {
// Skip the variants that must not lose BLE here: MQTT and Serial validate first and disable it
// themselves, and statusmessage/mesh_beacon never reboot, so a disable would strand BLE until the
// next PowerFSM transition. Everything else reboots, so take BLE down before the phone interferes.
if (!hasOpenEditTransaction &&
!IS_ONE_OF(c.which_payload_variant, meshtastic_ModuleConfig_mqtt_tag, meshtastic_ModuleConfig_serial_tag,
meshtastic_ModuleConfig_statusmessage_tag, meshtastic_ModuleConfig_mesh_beacon_tag)) {
disableBluetooth();
}
@@ -1250,8 +1252,10 @@ bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
if (!MQTT::isValidConfig(c.payload_variant.mqtt)) {
return false;
}
// Disable Bluetooth to prevent interference during MQTT configuration
disableBluetooth();
// Disable Bluetooth to prevent interference during MQTT configuration, except inside an edit
// transaction: saveChanges() defers the reboot there, so nothing would bring BLE back.
if (!hasOpenEditTransaction)
disableBluetooth();
moduleConfig.has_mqtt = true;
{
char prevPass[sizeof(moduleConfig.mqtt.password)];
@@ -1269,7 +1273,9 @@ bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
LOG_ERROR("Invalid serial config");
return false;
}
disableBluetooth(); // Disable Bluetooth to prevent interference during Serial configuration
// Same transaction caveat as MQTT above: a deferred reboot would leave BLE down with no restore.
if (!hasOpenEditTransaction)
disableBluetooth(); // Disable Bluetooth to prevent interference during Serial configuration
moduleConfig.has_serial = true;
moduleConfig.serial = c.payload_variant.serial;
break;