Add OTA support to ESP-IDF webserver

This commit is contained in:
J. Nick Koston 2025-06-29 10:38:53 -05:00
parent 7efbd62730
commit c366d555e9
No known key found for this signature in database
6 changed files with 25 additions and 7 deletions

View File

@ -261,6 +261,8 @@ async def to_code(config):
cg.add(var.set_css_url(config[CONF_CSS_URL])) cg.add(var.set_css_url(config[CONF_CSS_URL]))
cg.add(var.set_js_url(config[CONF_JS_URL])) cg.add(var.set_js_url(config[CONF_JS_URL]))
cg.add(var.set_allow_ota(config[CONF_OTA])) cg.add(var.set_allow_ota(config[CONF_OTA]))
if config[CONF_OTA]:
cg.add_define("USE_WEBSERVER_OTA")
cg.add(var.set_expose_log(config[CONF_LOG])) cg.add(var.set_expose_log(config[CONF_LOG]))
if config[CONF_ENABLE_PRIVATE_NETWORK_ACCESS]: if config[CONF_ENABLE_PRIVATE_NETWORK_ACCESS]:
cg.add_define("USE_WEBSERVER_PRIVATE_NETWORK_ACCESS") cg.add_define("USE_WEBSERVER_PRIVATE_NETWORK_ACCESS")

View File

@ -14,7 +14,7 @@
#endif #endif
#endif #endif
#ifdef USE_ESP_IDF #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
#include "esphome/components/ota/ota_backend.h" #include "esphome/components/ota/ota_backend.h"
#endif #endif
@ -98,7 +98,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
} }
#endif #endif
#ifdef USE_ESP_IDF #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
// ESP-IDF implementation // ESP-IDF implementation
if (index == 0) { if (index == 0) {
ESP_LOGI(TAG, "OTA Update Start: %s", filename.c_str()); ESP_LOGI(TAG, "OTA Update Start: %s", filename.c_str());
@ -173,7 +173,7 @@ void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
response->addHeader("Connection", "close"); response->addHeader("Connection", "close");
request->send(response); request->send(response);
#endif #endif
#ifdef USE_ESP_IDF #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
AsyncWebServerResponse *response; AsyncWebServerResponse *response;
if (this->ota_started_ && this->ota_backend_) { if (this->ota_started_ && this->ota_backend_) {
response = request->beginResponse(200, "text/plain", "Update Successful!"); response = request->beginResponse(200, "text/plain", "Update Successful!");
@ -186,7 +186,7 @@ void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
} }
void WebServerBase::add_ota_handler() { void WebServerBase::add_ota_handler() {
#if defined(USE_ARDUINO) || defined(USE_ESP_IDF) #if defined(USE_ARDUINO) || (defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA))
this->add_handler(new OTARequestHandler(this)); // NOLINT this->add_handler(new OTARequestHandler(this)); // NOLINT
#endif #endif
} }

View File

@ -142,7 +142,7 @@ class OTARequestHandler : public AsyncWebHandler {
uint32_t last_ota_progress_{0}; uint32_t last_ota_progress_{0};
uint32_t ota_read_length_{0}; uint32_t ota_read_length_{0};
WebServerBase *parent_; WebServerBase *parent_;
#ifdef USE_ESP_IDF #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
std::unique_ptr<ota::OTABackend> ota_backend_; std::unique_ptr<ota::OTABackend> ota_backend_;
bool ota_started_{false}; bool ota_started_{false};
#endif #endif

View File

@ -1,4 +1,5 @@
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
#ifdef USE_WEBSERVER_OTA
#include "multipart_parser.h" #include "multipart_parser.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
@ -223,4 +224,5 @@ size_t MultipartParser::find_pattern(const uint8_t *pattern, size_t pattern_len,
} // namespace web_server_idf } // namespace web_server_idf
} // namespace esphome } // namespace esphome
#endif #endif // USE_WEBSERVER_OTA
#endif // USE_ESP_IDF

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
#ifdef USE_WEBSERVER_OTA
#include <string> #include <string>
#include <vector> #include <vector>
@ -64,4 +65,5 @@ class MultipartParser {
} // namespace web_server_idf } // namespace web_server_idf
} // namespace esphome } // namespace esphome
#endif #endif // USE_WEBSERVER_OTA
#endif // USE_ESP_IDF

View File

@ -8,7 +8,9 @@
#include "esp_tls_crypto.h" #include "esp_tls_crypto.h"
#include "utils.h" #include "utils.h"
#ifdef USE_WEBSERVER_OTA
#include "multipart_parser.h" #include "multipart_parser.h"
#endif
#include "web_server_idf.h" #include "web_server_idf.h"
@ -74,6 +76,7 @@ esp_err_t AsyncWebServer::request_post_handler(httpd_req_t *r) {
ESP_LOGVV(TAG, "Enter AsyncWebServer::request_post_handler. uri=%s", r->uri); ESP_LOGVV(TAG, "Enter AsyncWebServer::request_post_handler. uri=%s", r->uri);
auto content_type = request_get_header(r, "Content-Type"); auto content_type = request_get_header(r, "Content-Type");
#ifdef USE_WEBSERVER_OTA
// Check if this is a multipart form data request (for OTA updates) // Check if this is a multipart form data request (for OTA updates)
bool is_multipart = false; bool is_multipart = false;
std::string boundary; std::string boundary;
@ -92,6 +95,13 @@ esp_err_t AsyncWebServer::request_post_handler(httpd_req_t *r) {
return AsyncWebServer::request_handler(r); return AsyncWebServer::request_handler(r);
} }
} }
#else
if (content_type.has_value() && content_type.value() != "application/x-www-form-urlencoded") {
ESP_LOGW(TAG, "Only application/x-www-form-urlencoded supported for POST request");
// fallback to get handler to support backward compatibility
return AsyncWebServer::request_handler(r);
}
#endif
if (!request_has_header(r, "Content-Length")) { if (!request_has_header(r, "Content-Length")) {
ESP_LOGW(TAG, "Content length is requred for post: %s", r->uri); ESP_LOGW(TAG, "Content length is requred for post: %s", r->uri);
@ -99,6 +109,7 @@ esp_err_t AsyncWebServer::request_post_handler(httpd_req_t *r) {
return ESP_OK; return ESP_OK;
} }
#ifdef USE_WEBSERVER_OTA
// Handle multipart form data // Handle multipart form data
if (is_multipart && !boundary.empty()) { if (is_multipart && !boundary.empty()) {
// Create request object // Create request object
@ -167,6 +178,7 @@ esp_err_t AsyncWebServer::request_post_handler(httpd_req_t *r) {
found_handler->handleRequest(&req); found_handler->handleRequest(&req);
return ESP_OK; return ESP_OK;
} }
#endif // USE_WEBSERVER_OTA
// Handle regular form data // Handle regular form data
if (r->content_len > HTTPD_MAX_REQ_HDR_LEN) { if (r->content_len > HTTPD_MAX_REQ_HDR_LEN) {