2#ifdef USE_WEBSERVER_OTA
8#ifdef USE_CAPTIVE_PORTAL
15#elif defined(USE_ESP32) || defined(USE_LIBRETINY)
23static const char *
const TAG =
"web_server.ota";
25class OTARequestHandler :
public AsyncWebHandler {
27 OTARequestHandler(WebServerOTAComponent *parent) : parent_(parent) {}
28 void handleRequest(AsyncWebServerRequest *request)
override;
29 void handleUpload(AsyncWebServerRequest *request,
const String &filename,
size_t index, uint8_t *data,
size_t len,
31 bool canHandle(AsyncWebServerRequest *request)
const override {
33 bool is_ota_request = request->url() ==
"/update" && request->method() == HTTP_POST;
35#if defined(USE_WEBSERVER_OTA_DISABLED) && defined(USE_CAPTIVE_PORTAL)
41#elif defined(USE_WEBSERVER_OTA_DISABLED)
46 return is_ota_request;
51 bool isRequestHandlerTrivial()
const override {
return false; }
54 void report_ota_progress_(AsyncWebServerRequest *request);
55 void schedule_ota_reboot_();
56 void ota_init_(
const char *filename);
60 WebServerOTAComponent *parent_;
61 bool ota_success_{
false};
64 std::unique_ptr<ota::OTABackend> ota_backend_{
nullptr};
67void OTARequestHandler::report_ota_progress_(AsyncWebServerRequest *request) {
69 if (now - this->last_ota_progress_ > 1000) {
70 float percentage = 0.0f;
71 if (request->contentLength() != 0) {
76 percentage = (this->ota_read_length_ * 100.0f) / request->contentLength();
77 ESP_LOGD(TAG,
"OTA in progress: %0.1f%%", percentage);
79 ESP_LOGD(TAG,
"OTA in progress: %u bytes read", this->ota_read_length_);
81#ifdef USE_OTA_STATE_CALLBACK
85 this->last_ota_progress_ = now;
89void OTARequestHandler::schedule_ota_reboot_() {
90 ESP_LOGI(TAG,
"OTA update successful!");
92 ESP_LOGI(TAG,
"Performing OTA reboot now");
97void OTARequestHandler::ota_init_(
const char *filename) {
98 ESP_LOGI(TAG,
"OTA Update Start: %s", filename);
99 this->ota_read_length_ = 0;
100 this->ota_success_ =
false;
103void OTARequestHandler::handleUpload(AsyncWebServerRequest *request,
const String &filename,
size_t index,
104 uint8_t *data,
size_t len,
bool final) {
107 if (index == 0 && !this->ota_backend_) {
109 this->ota_init_(filename.c_str());
111#ifdef USE_OTA_STATE_CALLBACK
119 Update.runAsync(
true);
121#if defined(USE_ESP32) || defined(USE_LIBRETINY)
122 if (Update.isRunning()) {
129 if (!this->ota_backend_) {
130 ESP_LOGE(TAG,
"Failed to create OTA backend");
131#ifdef USE_OTA_STATE_CALLBACK
141 error_code = this->ota_backend_->begin(0);
143 ESP_LOGE(TAG,
"OTA begin failed: %d", error_code);
144 this->ota_backend_.reset();
145#ifdef USE_OTA_STATE_CALLBACK
152 if (!this->ota_backend_) {
158 error_code = this->ota_backend_->write(data,
len);
160 ESP_LOGE(TAG,
"OTA write failed: %d", error_code);
161 this->ota_backend_->abort();
162 this->ota_backend_.reset();
163#ifdef USE_OTA_STATE_CALLBACK
168 this->ota_read_length_ +=
len;
169 this->report_ota_progress_(request);
174 ESP_LOGD(TAG,
"OTA final chunk: index=%zu, len=%zu, total_read=%u, contentLength=%zu", index,
len,
175 this->ota_read_length_, request->contentLength());
180 error_code = this->ota_backend_->end();
182 this->ota_success_ =
true;
183#ifdef USE_OTA_STATE_CALLBACK
187 this->schedule_ota_reboot_();
189 ESP_LOGE(TAG,
"OTA end failed: %d", error_code);
190#ifdef USE_OTA_STATE_CALLBACK
194 this->ota_backend_.reset();
198void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
199 AsyncWebServerResponse *response;
201 const char *msg = this->ota_success_ ?
"Update Successful!" :
"Update Failed!";
202 response = request->beginResponse(200,
"text/plain", msg);
203 response->addHeader(
"Connection",
"close");
204 request->send(response);
210 if (base ==
nullptr) {
211 ESP_LOGE(TAG,
"WebServerBase not found");
218#ifdef USE_OTA_STATE_CALLBACK
virtual void mark_failed()
Mark this component as failed.
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void call_deferred(ota::OTAState state, float progress, uint8_t error)
Call callbacks with deferral to main loop (for thread safety).
StateCallbackManager state_callback_
void dump_config() override
friend class OTARequestHandler
void add_handler(AsyncWebHandler *handler)
CaptivePortal * global_captive_portal
void register_ota_platform(OTAComponent *ota_caller)
std::unique_ptr< ota::OTABackend > make_ota_backend()
@ OTA_RESPONSE_ERROR_UNKNOWN
WebServerBase * global_web_server_base
Providing packet encoding functions for exchanging data with a remote host.
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.