Skip to content

fix(ota): defer remote actions during updates - #145

Merged
ODevStudio merged 4 commits into
mainfrom
audit/pr-017-defer-ota-remote-actions
Aug 13, 2026
Merged

fix(ota): defer remote actions during updates#145
ODevStudio merged 4 commits into
mainfrom
audit/pr-017-defer-ota-remote-actions

Conversation

@ODevStudio

@ODevStudio ODevStudio commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Defer ordinary remote actions, including client-requested resets, while OTA owns the device lifecycle.
  • Give OTA completion its own scheduled-reset bit and timestamp.
  • Serialize ElegantOTA start with the complete main-loop remote action batch.
  • Restore extracted actions without overriding newer replacement-group intent.
  • Make rapid remote sleep/wake replacement honor the latest requested state.

Root Cause

processWsPendingCmds() could execute remote actions while OTA was active. Client reset and OTA completion initially shared one pending bit, an extracted batch could escape when ElegantOTA started concurrently, and callback-owned soft-sleep state could make a later wake lose to an earlier pending sleep.

A flag recheck under wsPendingMux was insufficient. ElegantOTA could start immediately after the recheck but before hardware dispatch. Restoring the old batch with |= also resurrected older display, low-power, sleep, or timer commands over newer pending replacements.

Implementation

  • OTA completion uses WSP_OTA_RESET, pendingOtaResetAt, and remoteQueueOtaResetAt(); ordinary resets retain WSP_RESET.
  • processWsPendingCmds() and onOTAStart() share otaDispatchMutex. The dispatcher holds it across the complete extracted batch, so OTA start either waits for in-flight hardware work or publishes active OTA before the dispatcher rechecks.
  • When OTA wins, restoration drops an extracted replacement group if that group already has newer pending intent. Unrelated extracted actions remain queued.
  • A pull-OTA start requeues an extracted power-off action instead of executing or losing it after OTA becomes active.
  • BLE and WebSocket sleep callbacks queue intent; the main loop publishes applied soft-sleep state beside the rail transition.

Safety / Reliability Impact

Client resets cannot interrupt an active flash write. Display, rail, timer, sample, gyro, duplicate-update, and power actions remain queued during OTA. The lifecycle mutex is a normal task mutex, not a critical section, so interrupts remain enabled during hardware dispatch.

Compatibility

No BLE, USB, WebSocket, manifest, storage, or OTA packet format changes. Remote actions received during a cancelled or failed update remain queued and run afterward; successful OTA completion still reboots through the main loop. Native, grinder, custom, and hardware targets were intentionally not run locally.

Regression Coverage

tools/test_ota_reboot_routing_contract.py now covers ordinary-reset deferral, combined extraction/OTA-start/newer-command restoration for every replacement group, lifecycle-lock placement, rapid sleep/wake replacement, and pull-OTA power-action preservation. tools/test_soft_sleep_ads_wake.py verifies both remote transports use main-loop sleep transitions.

Verification

  • python tools/test_ota_reboot_routing_contract.py
  • python tools/test_soft_sleep_ads_wake.py
  • python tools/test_pull_ota_contract.py
  • python tools/test_ota_input_isolation_contract.py
  • python tools/test_ota_rollback_contract.py
  • python tools/test_charging_wake_contract.py
  • python tools/test_ble_subscription_contract.py
  • python tools/test_ai_docs_contract.py
  • pio run -e esp32s3 with an isolated PLATFORMIO_CORE_DIR
  • git diff --check

All passed. The ESP32-S3 build retains only the existing volatile-increment warnings in src/wifi_setup.cpp.

Hardware Verification

Not run. No physical concurrent remote-command traffic, OTA upload, flash write, cancellation, failure, or reboot was exercised.

Related Work

PR #141 isolates USB and physical-button input during OTA. PRs #142 and #144 restore soft-sleep hardware for pull and asynchronous OTA entry. PR #143 defers remote wake state publication until main-loop recovery.

@ODevStudio
ODevStudio force-pushed the audit/pr-017-defer-ota-remote-actions branch from 63bf149 to 3427df9 Compare August 13, 2026 13:49
@ODevStudio
ODevStudio force-pushed the audit/pr-017-defer-ota-remote-actions branch from eff76b0 to bff8810 Compare August 13, 2026 14:36
@ODevStudio
ODevStudio marked this pull request as ready for review August 13, 2026 14:53
@ODevStudio
ODevStudio merged commit 9a4e9c5 into main Aug 13, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant