diff --git a/esphome/components/web_server_base/web_server_base.cpp b/esphome/components/web_server_base/web_server_base.cpp index 1db6dc43e8..9bbeb7b605 100644 --- a/esphome/components/web_server_base/web_server_base.cpp +++ b/esphome/components/web_server_base/web_server_base.cpp @@ -119,8 +119,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin // ESP-IDF implementation if (index == 0) { this->ota_init_(filename.c_str()); - this->ota_started_ = false; - this->ota_success_ = false; + this->ota_state_ = OTAState::IDLE; // Create OTA backend auto backend = ota::make_ota_backend(); @@ -129,15 +128,16 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin auto result = backend->begin(0); if (result != ota::OTA_RESPONSE_OK) { ESP_LOGE(TAG, "OTA begin failed: %d", result); + this->ota_state_ = OTAState::FAILED; return; } // Store the backend pointer this->ota_backend_ = backend.release(); - this->ota_started_ = true; + this->ota_state_ = OTAState::STARTED; } - if (!this->ota_started_ || !this->ota_backend_) { + if (this->ota_state_ != OTAState::STARTED && this->ota_state_ != OTAState::IN_PROGRESS) { // Begin failed or was aborted return; } @@ -145,6 +145,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin // Write data if (len > 0) { auto *backend = static_cast(this->ota_backend_); + this->ota_state_ = OTAState::IN_PROGRESS; auto result = backend->write(data, len); if (result != ota::OTA_RESPONSE_OK) { @@ -152,8 +153,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin backend->abort(); delete backend; this->ota_backend_ = nullptr; - this->ota_started_ = false; - this->ota_success_ = false; + this->ota_state_ = OTAState::FAILED; return; } @@ -165,15 +165,14 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin auto *backend = static_cast(this->ota_backend_); auto result = backend->end(); if (result == ota::OTA_RESPONSE_OK) { - this->ota_success_ = true; + this->ota_state_ = OTAState::SUCCESS; this->schedule_ota_reboot_(); } else { ESP_LOGE(TAG, "OTA end failed: %d", result); - this->ota_success_ = false; + this->ota_state_ = OTAState::FAILED; } delete backend; this->ota_backend_ = nullptr; - this->ota_started_ = false; } #endif // USE_ESP_IDF #endif // USE_WEBSERVER_OTA @@ -195,7 +194,7 @@ void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) { #ifdef USE_ESP_IDF // For ESP-IDF, we use direct send() instead of beginResponse() // to ensure the response is sent immediately before the reboot. - request->send(200, "text/plain", this->ota_success_ ? "Update Successful!" : "Update Failed!"); + request->send(200, "text/plain", this->ota_state_ == OTAState::SUCCESS ? "Update Successful!" : "Update Failed!"); return; #endif // USE_ESP_IDF response->addHeader("Connection", "close"); diff --git a/esphome/components/web_server_base/web_server_base.h b/esphome/components/web_server_base/web_server_base.h index d6be110582..ac319ca4f7 100644 --- a/esphome/components/web_server_base/web_server_base.h +++ b/esphome/components/web_server_base/web_server_base.h @@ -130,8 +130,7 @@ class OTARequestHandler : public AsyncWebHandler { OTARequestHandler(WebServerBase *parent) : parent_(parent) { #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) this->ota_backend_ = nullptr; - this->ota_started_ = false; - this->ota_success_ = false; + this->ota_state_ = OTAState::IDLE; #endif } void handleRequest(AsyncWebServerRequest *request) override; @@ -157,9 +156,17 @@ class OTARequestHandler : public AsyncWebHandler { private: #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) + // OTA state machine + enum class OTAState : uint8_t{ + IDLE = 0, // No OTA in progress + STARTED, // OTA begin() succeeded + IN_PROGRESS, // Writing data + SUCCESS, // OTA end() succeeded + FAILED // OTA failed at any stage + }; + void *ota_backend_{nullptr}; - bool ota_started_{false}; - bool ota_success_{false}; + OTAState ota_state_{OTAState::IDLE}; #endif };