fix(firmware): raise the httpd stack for OTA image validation - #1831
Open
clonea1 wants to merge 3 commits into
Open
fix(firmware): raise the httpd stack for OTA image validation#1831clonea1 wants to merge 3 commits into
clonea1 wants to merge 3 commits into
Conversation
Changing any node setting meant a USB cable and physical access. On a fleet mounted on walls and ceilings that is the difference between a five-second change and taking a board down. Adds an authenticated HTTP config endpoint on each node. Settings are typed and range-checked at the boundary, persisted to NVS, and applied without a reflash. Includes LED mode and brightness: the status LED is bright enough to be unwelcome in a bedroom, and that is a configuration question, not a reflash. TRIAL AND REVERT. A setting that breaks connectivity would otherwise brick a node remotely -- change the WiFi password and the node is simply gone. So a change that could sever the uplink is applied on trial: the old values are banked, the node reboots, and the change is confirmed only once the node reassociates and gets an address. If it does not within the deadline, the node restores the banked values and comes back on the old settings. Verified on hardware with a deliberately wrong password: recovered on its own in 60.5 s. The reply to a trial push is sent before the reboot rather than after it, so the caller learns the trial was accepted instead of seeing a dropped connection and having to guess. Mutating requests require a pre-shared key checked in constant time, and the endpoint FAILS CLOSED when no key is provisioned. The key is read from a file path given at build time with no default, so no personal path is baked into a published tree. Co-Authored-By: claude-flow <ruv@ruv.net>
Config changes already self-heal: a node given credentials it cannot associate
with banks the old ones, reboots, and restores them. Firmware had no such
protection -- a bad image meant a boot loop and a USB cable, which for nodes
mounted around a house is the difference between a mistake and an afternoon.
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE makes a freshly-OTA'd image boot as
PENDING_VERIFY; if it reboots without confirming, the bootloader reverts.
WHEN to confirm is the whole design. Confirming in app_main() would make the
mechanism decorative, since any image that starts would qualify. The failure
that actually costs someone a ladder is a node that cannot be REACHED, and
unreachable means no WiFi -- so the criterion is: obtained an IP, then stayed
up for a 60 s soak. The soak also catches an image that associates and then
crashes, which confirming on IP alone would miss. It shares the
IP_EVENT_STA_GOT_IP hook with the config trial: both mechanisms key off the
same evidence that the node can still talk.
Deliberately conservative -- a reboot for any other reason inside the soak
rolls back a good image. That errs toward a node that works over a node that
is new.
A silent revert is nearly useless operationally: a node that reappears on its
old firmware looks identical to one whose update never arrived. So the boot
check also detects an already-reverted slot and reports the failed partition,
its version and the reset reason, in the log, in NVS so a late poller still
sees it, and on /ota/status as `last_rollback` alongside `pending_verify`.
MEASURED on node 3 (esp32c6), not inferred:
happy path -- OTA'd a good image, it booted PENDING_VERIFY, got an IP,
soaked, confirmed; a subsequent reboot stayed on ota_1, which only happens
if confirmation actually occurred.
failure path -- OTA'd an image built to abort() 15 s after boot, inside the
soak window:
ota_update: OTA update successful! Rebooting to partition 'ota_0'...
ota_update: new image on trial (ota_0): must reach the network and
survive 60 s or the bootloader reverts
main: Got IP: <node-ip>
ota_update: image on trial reached the network; confirming in 60 s
abort() was called at PC 0x4201ec43 on core 0
ota_update: FIRMWARE ROLLBACK: ota_0 image 0.8.8 was aborted;
recovered via panic
main: Got IP: <node-ip>
and /ota/status then returns
"last_rollback": "ota_0 image 0.8.8 was aborted; recovered via panic"
The node recovered with no USB intervention. The panic used to produce the bad
image was a throwaway and is not in this commit.
Co-Authored-By: claude-flow <ruv@ruv.net>
Adopted from upstream PR ruvnet#1594 (Juan Kuscevic, open since 2026-08-11). The OTA upload handler runs esp_ota_end() -> esp_image_verify() on the httpd task's own stack, and HTTPD_DEFAULT_CONFIG allocates 4 KB. That overflows at the very end of an upload: the transfer completes, validation panics, and the node reboots into the old image. The symptom reads as 'the update did not take' rather than as a crash, which makes it hard to attribute. 12 KB costs one page of RAM. Co-Authored-By: claude-flow <ruv@ruv.net> (cherry picked from commit cbfecfdb4b20dd37b40ab7d43f87504cad39024e)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adopted from upstream PR #1594 (Juan Kuscevic, open since 2026-08-11).
The OTA upload handler runs esp_ota_end() -> esp_image_verify() on the httpd
task's own stack, and HTTPD_DEFAULT_CONFIG allocates 4 KB. That overflows at
the very end of an upload: the transfer completes, validation panics, and the
node reboots into the old image. The symptom reads as 'the update did not
take' rather than as a crash, which makes it hard to attribute.
12 KB costs one page of RAM.
Stacked on #1827 (
remote-config) — this branch carries that commit too, so review only the last two here, or merge #1827 first and this shrinks.Rebased onto current
main; one additive conflict inmain/CMakeLists.txt(maingainedthermal.c, this addsconfig_api.c) resolved by keeping both. Firmware builds clean for esp32c6 on ESP-IDF v5.4.