From bd58d8af5b87694ac8e9dd116c083c9e8c522cde Mon Sep 17 00:00:00 2001 From: agessaman Date: Tue, 21 Jul 2026 10:32:56 -0700 Subject: [PATCH] feat(mqtt): implement deferred OTA update scheduling in MyMesh Add functionality to schedule deferred OTA updates in the MyMesh class. This includes a new member variable to track the update time and a method to initiate the update process, allowing for a smoother OTA experience by managing timing and state transitions effectively. Cherry-picked from observer-firmware (76f44d7d). Resolved a conflict in loop() where the WITH_WEBCONFIG block occupies the same anchor and shares an identical closing tail; both blocks retained. --- examples/simple_room_server/MyMesh.cpp | 17 +++++++++++++++++ examples/simple_room_server/MyMesh.h | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 1fc1ef88..ada2e2e1 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -1494,6 +1494,23 @@ void MyMesh::loop() { } #endif +#if defined(WITH_MQTT_BRIDGE) && defined(OTA_MANIFEST_BASE) + if (_ota_update_at && millisHasNowPassed(_ota_update_at)) { // deferred `ota update` + _ota_update_at = 0; // clear timer + // The "Beginning update..." reply has now gone out. Free the bridge for heap + // headroom, then flash: otaFromManifest reboots into the new image on success + // (so this never returns); on any abort (already up to date, partition change, + // download error) it returns and we resume the bridge. + Serial.println("OTA: starting update"); + setBridgeState(false); + char ota_reply[160]; + if (!_cli.getBoard()->otaFromManifest(getFirmwareVer(), false, ota_reply)) { + Serial.print("OTA: aborted, resuming bridge - "); Serial.println(ota_reply); + setBridgeState(true); + } + } +#endif + // is pending dirty contacts write needed? if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) { acl.save(_fs, MyMesh::saveFilter); diff --git a/examples/simple_room_server/MyMesh.h b/examples/simple_room_server/MyMesh.h index 74782041..b80b3d02 100644 --- a/examples/simple_room_server/MyMesh.h +++ b/examples/simple_room_server/MyMesh.h @@ -130,6 +130,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks RegionEntry* recv_pkt_region; TransportKey default_scope; unsigned long set_radio_at, revert_radio_at; + unsigned long _ota_update_at = 0; // deferred `ota update` fire time (0 = none scheduled) float pending_freq; float pending_bw; uint8_t pending_sf; @@ -375,6 +376,15 @@ public: #endif } + // Schedule the pull-OTA flash to run from loop() in ~2.5 s, leaving time for the + // "Beginning update..." CLI reply (CLI_REPLY_DELAY_MILLIS = 600 ms) to transmit + // before the flash blocks the loop and reboots. + bool beginDeferredOtaUpdate() override { + _ota_update_at = millis() + 2500; + if (_ota_update_at == 0) _ota_update_at = 1; // 0 means "none" + return true; + } + int getQueueSize() override { return bridge ? bridge->getQueueSize() : 0; }