mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'ota_base_extract' into integration
This commit is contained in:
		| @@ -327,6 +327,7 @@ esphome/components/opentherm/* @olegtarasov | |||||||
| esphome/components/openthread/* @mrene | esphome/components/openthread/* @mrene | ||||||
| esphome/components/opt3001/* @ccutrer | esphome/components/opt3001/* @ccutrer | ||||||
| esphome/components/ota/* @esphome/core | esphome/components/ota/* @esphome/core | ||||||
|  | esphome/components/ota_base/* @esphome/core | ||||||
| esphome/components/output/* @esphome/core | esphome/components/output/* @esphome/core | ||||||
| esphome/components/packet_transport/* @clydebarrow | esphome/components/packet_transport/* @clydebarrow | ||||||
| esphome/components/pca6416a/* @Mat931 | esphome/components/pca6416a/* @Mat931 | ||||||
|   | |||||||
| @@ -15,8 +15,7 @@ namespace adc { | |||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| // clang-format off | // clang-format off | ||||||
| #if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 7)) || \ | #if (ESP_IDF_VERSION_MAJOR == 5 && \ | ||||||
|     (ESP_IDF_VERSION_MAJOR == 5 && \ |  | ||||||
|      ((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \ |      ((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \ | ||||||
|       (ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \ |       (ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \ | ||||||
|       (ESP_IDF_VERSION_MINOR >= 2)) \ |       (ESP_IDF_VERSION_MINOR >= 2)) \ | ||||||
| @@ -100,11 +99,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage | |||||||
|   adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; |   adc1_channel_t channel1_{ADC1_CHANNEL_MAX}; | ||||||
|   adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; |   adc2_channel_t channel2_{ADC2_CHANNEL_MAX}; | ||||||
|   bool autorange_{false}; |   bool autorange_{false}; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {}; |   esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {}; | ||||||
| #else |  | ||||||
|   esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {}; |  | ||||||
| #endif  // ESP_IDF_VERSION_MAJOR |  | ||||||
| #endif  // USE_ESP32 | #endif  // USE_ESP32 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -411,8 +411,8 @@ def _esp_idf_check_versions(value): | |||||||
|         version = cv.Version.parse(cv.version_number(value[CONF_VERSION])) |         version = cv.Version.parse(cv.version_number(value[CONF_VERSION])) | ||||||
|         source = value.get(CONF_SOURCE, None) |         source = value.get(CONF_SOURCE, None) | ||||||
|  |  | ||||||
|     if version < cv.Version(4, 0, 0): |     if version < cv.Version(5, 0, 0): | ||||||
|         raise cv.Invalid("Only ESP-IDF 4.0+ is supported.") |         raise cv.Invalid("Only ESP-IDF 5.0+ is supported.") | ||||||
|  |  | ||||||
|     # flag this for later *before* we set value[CONF_PLATFORM_VERSION] below |     # flag this for later *before* we set value[CONF_PLATFORM_VERSION] below | ||||||
|     has_platform_ver = CONF_PLATFORM_VERSION in value |     has_platform_ver = CONF_PLATFORM_VERSION in value | ||||||
| @@ -422,20 +422,15 @@ def _esp_idf_check_versions(value): | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     if ( |     if ( | ||||||
|         (is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION])) |         is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION]) | ||||||
|         and version.major >= 5 |     ) and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X: | ||||||
|         and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X |  | ||||||
|     ): |  | ||||||
|         raise cv.Invalid( |         raise cv.Invalid( | ||||||
|             f"ESP-IDF {str(version)} not supported by platformio/espressif32" |             f"ESP-IDF {str(version)} not supported by platformio/espressif32" | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|     if ( |     if ( | ||||||
|         version.major < 5 |         version in SUPPORTED_PLATFORMIO_ESP_IDF_5X | ||||||
|         or ( |         and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X | ||||||
|             version in SUPPORTED_PLATFORMIO_ESP_IDF_5X |  | ||||||
|             and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X |  | ||||||
|         ) |  | ||||||
|     ) and not has_platform_ver: |     ) and not has_platform_ver: | ||||||
|         raise cv.Invalid( |         raise cv.Invalid( | ||||||
|             f"ESP-IDF {value[CONF_VERSION]} may be supported by platformio/espressif32; please specify '{CONF_PLATFORM_VERSION}'" |             f"ESP-IDF {value[CONF_VERSION]} may be supported by platformio/espressif32; please specify '{CONF_PLATFORM_VERSION}'" | ||||||
| @@ -801,14 +796,9 @@ async def to_code(config): | |||||||
|  |  | ||||||
|         if advanced.get(CONF_IGNORE_EFUSE_MAC_CRC): |         if advanced.get(CONF_IGNORE_EFUSE_MAC_CRC): | ||||||
|             add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) |             add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) | ||||||
|             if (framework_ver.major, framework_ver.minor) >= (4, 4): |             add_idf_sdkconfig_option( | ||||||
|                 add_idf_sdkconfig_option( |                 "CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False | ||||||
|                     "CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False |             ) | ||||||
|                 ) |  | ||||||
|             else: |  | ||||||
|                 add_idf_sdkconfig_option( |  | ||||||
|                     "CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE", False |  | ||||||
|                 ) |  | ||||||
|         if advanced.get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): |         if advanced.get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): | ||||||
|             _LOGGER.warning( |             _LOGGER.warning( | ||||||
|                 "Using experimental features in ESP-IDF may result in unexpected failures." |                 "Using experimental features in ESP-IDF may result in unexpected failures." | ||||||
|   | |||||||
| @@ -56,11 +56,7 @@ void arch_init() { | |||||||
| void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); } | void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); } | ||||||
|  |  | ||||||
| uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } | uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); } | uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); } | ||||||
| #else |  | ||||||
| uint32_t arch_get_cpu_cycle_count() { return cpu_hal_get_cycle_count(); } |  | ||||||
| #endif |  | ||||||
| uint32_t arch_get_cpu_freq_hz() { | uint32_t arch_get_cpu_freq_hz() { | ||||||
|   uint32_t freq = 0; |   uint32_t freq = 0; | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP_IDF | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ from esphome.const import ( | |||||||
|     CONF_ON_BLE_SERVICE_DATA_ADVERTISE, |     CONF_ON_BLE_SERVICE_DATA_ADVERTISE, | ||||||
|     CONF_SERVICE_UUID, |     CONF_SERVICE_UUID, | ||||||
|     CONF_TRIGGER_ID, |     CONF_TRIGGER_ID, | ||||||
|     KEY_CORE, |  | ||||||
|     KEY_FRAMEWORK_VERSION, |  | ||||||
| ) | ) | ||||||
| from esphome.core import CORE | from esphome.core import CORE | ||||||
|  |  | ||||||
| @@ -323,10 +321,7 @@ async def to_code(config): | |||||||
|         # https://github.com/espressif/esp-idf/issues/2503 |         # https://github.com/espressif/esp-idf/issues/2503 | ||||||
|         # Match arduino CONFIG_BTU_TASK_STACK_SIZE |         # Match arduino CONFIG_BTU_TASK_STACK_SIZE | ||||||
|         # https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866 |         # https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866 | ||||||
|         if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(4, 4, 6): |         add_idf_sdkconfig_option("CONFIG_BT_BTU_TASK_STACK_SIZE", 8192) | ||||||
|             add_idf_sdkconfig_option("CONFIG_BT_BTU_TASK_STACK_SIZE", 8192) |  | ||||||
|         else: |  | ||||||
|             add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192) |  | ||||||
|         add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9) |         add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9) | ||||||
|         add_idf_sdkconfig_option( |         add_idf_sdkconfig_option( | ||||||
|             "CONFIG_BTDM_CTRL_BLE_MAX_CONN", config[CONF_MAX_CONNECTIONS] |             "CONFIG_BTDM_CTRL_BLE_MAX_CONN", config[CONF_MAX_CONNECTIONS] | ||||||
| @@ -335,8 +330,7 @@ async def to_code(config): | |||||||
|         # max notifications in 5.x, setting CONFIG_BT_ACL_CONNECTIONS |         # max notifications in 5.x, setting CONFIG_BT_ACL_CONNECTIONS | ||||||
|         # is enough in 4.x |         # is enough in 4.x | ||||||
|         # https://github.com/esphome/issues/issues/6808 |         # https://github.com/esphome/issues/issues/6808 | ||||||
|         if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(5, 0, 0): |         add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9) | ||||||
|             add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9) |  | ||||||
|  |  | ||||||
|     cg.add_define("USE_OTA_STATE_CALLBACK")  # To be notified when an OTA update starts |     cg.add_define("USE_OTA_STATE_CALLBACK")  # To be notified when an OTA update starts | ||||||
|     cg.add_define("USE_ESP32_BLE_CLIENT") |     cg.add_define("USE_ESP32_BLE_CLIENT") | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ | |||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
|  |  | ||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
| #include "esphome/components/ota/ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE | #ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE | ||||||
| @@ -61,9 +61,9 @@ void ESP32BLETracker::setup() { | |||||||
|   global_esp32_ble_tracker = this; |   global_esp32_ble_tracker = this; | ||||||
|  |  | ||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
|   ota::get_global_ota_callback()->add_on_state_callback( |   ota_base::get_global_ota_callback()->add_on_state_callback( | ||||||
|       [this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) { |       [this](ota_base::OTAState state, float progress, uint8_t error, ota_base::OTAComponent *comp) { | ||||||
|         if (state == ota::OTA_STARTED) { |         if (state == ota_base::OTA_STARTED) { | ||||||
|           this->stop_scan(); |           this->stop_scan(); | ||||||
|           for (auto *client : this->clients_) { |           for (auto *client : this->clients_) { | ||||||
|             client->disconnect(); |             client->disconnect(); | ||||||
|   | |||||||
| @@ -1,7 +1,8 @@ | |||||||
| import logging | import logging | ||||||
|  |  | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code | from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code | ||||||
|  | from esphome.components.ota_base import OTAComponent | ||||||
| from esphome.config_helpers import merge_config | from esphome.config_helpers import merge_config | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|   | |||||||
| @@ -2,12 +2,12 @@ | |||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
| #include "esphome/components/md5/md5.h" | #include "esphome/components/md5/md5.h" | ||||||
| #include "esphome/components/network/util.h" | #include "esphome/components/network/util.h" | ||||||
| #include "esphome/components/ota/ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h"  // For OTAComponent and callbacks | ||||||
| #include "esphome/components/ota/ota_backend_arduino_esp32.h" | #include "esphome/components/ota_base/ota_backend_arduino_esp32.h" | ||||||
| #include "esphome/components/ota/ota_backend_arduino_esp8266.h" | #include "esphome/components/ota_base/ota_backend_arduino_esp8266.h" | ||||||
| #include "esphome/components/ota/ota_backend_arduino_libretiny.h" | #include "esphome/components/ota_base/ota_backend_arduino_libretiny.h" | ||||||
| #include "esphome/components/ota/ota_backend_arduino_rp2040.h" | #include "esphome/components/ota_base/ota_backend_arduino_rp2040.h" | ||||||
| #include "esphome/components/ota/ota_backend_esp_idf.h" | #include "esphome/components/ota_base/ota_backend_esp_idf.h" | ||||||
| #include "esphome/core/application.h" | #include "esphome/core/application.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| @@ -23,7 +23,7 @@ static constexpr u_int16_t OTA_BLOCK_SIZE = 8192; | |||||||
|  |  | ||||||
| void ESPHomeOTAComponent::setup() { | void ESPHomeOTAComponent::setup() { | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|   ota::register_ota_platform(this); |   ota_base::register_ota_platform(this); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   this->server_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0);  // monitored for incoming connections |   this->server_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0);  // monitored for incoming connections | ||||||
| @@ -94,7 +94,7 @@ void ESPHomeOTAComponent::loop() { | |||||||
| static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01; | static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01; | ||||||
|  |  | ||||||
| void ESPHomeOTAComponent::handle_() { | void ESPHomeOTAComponent::handle_() { | ||||||
|   ota::OTAResponseTypes error_code = ota::OTA_RESPONSE_ERROR_UNKNOWN; |   ota_base::OTAResponseTypes error_code = ota_base::OTA_RESPONSE_ERROR_UNKNOWN; | ||||||
|   bool update_started = false; |   bool update_started = false; | ||||||
|   size_t total = 0; |   size_t total = 0; | ||||||
|   uint32_t last_progress = 0; |   uint32_t last_progress = 0; | ||||||
| @@ -102,7 +102,7 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   char *sbuf = reinterpret_cast<char *>(buf); |   char *sbuf = reinterpret_cast<char *>(buf); | ||||||
|   size_t ota_size; |   size_t ota_size; | ||||||
|   uint8_t ota_features; |   uint8_t ota_features; | ||||||
|   std::unique_ptr<ota::OTABackend> backend; |   std::unique_ptr<ota_base::OTABackend> backend; | ||||||
|   (void) ota_features; |   (void) ota_features; | ||||||
| #if USE_OTA_VERSION == 2 | #if USE_OTA_VERSION == 2 | ||||||
|   size_t size_acknowledged = 0; |   size_t size_acknowledged = 0; | ||||||
| @@ -129,7 +129,7 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   ESP_LOGD(TAG, "Starting update from %s", this->client_->getpeername().c_str()); |   ESP_LOGD(TAG, "Starting update from %s", this->client_->getpeername().c_str()); | ||||||
|   this->status_set_warning(); |   this->status_set_warning(); | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|   this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0); |   this->state_callback_.call(ota_base::OTA_STARTED, 0.0f, 0); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   if (!this->readall_(buf, 5)) { |   if (!this->readall_(buf, 5)) { | ||||||
| @@ -140,16 +140,16 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) { |   if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) { | ||||||
|     ESP_LOGW(TAG, "Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3], |     ESP_LOGW(TAG, "Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3], | ||||||
|              buf[4]); |              buf[4]); | ||||||
|     error_code = ota::OTA_RESPONSE_ERROR_MAGIC; |     error_code = ota_base::OTA_RESPONSE_ERROR_MAGIC; | ||||||
|     goto error;  // NOLINT(cppcoreguidelines-avoid-goto) |     goto error;  // NOLINT(cppcoreguidelines-avoid-goto) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Send OK and version - 2 bytes |   // Send OK and version - 2 bytes | ||||||
|   buf[0] = ota::OTA_RESPONSE_OK; |   buf[0] = ota_base::OTA_RESPONSE_OK; | ||||||
|   buf[1] = USE_OTA_VERSION; |   buf[1] = USE_OTA_VERSION; | ||||||
|   this->writeall_(buf, 2); |   this->writeall_(buf, 2); | ||||||
|  |  | ||||||
|   backend = ota::make_ota_backend(); |   backend = ota_base::make_ota_backend(); | ||||||
|  |  | ||||||
|   // Read features - 1 byte |   // Read features - 1 byte | ||||||
|   if (!this->readall_(buf, 1)) { |   if (!this->readall_(buf, 1)) { | ||||||
| @@ -160,16 +160,16 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   ESP_LOGV(TAG, "Features: 0x%02X", ota_features); |   ESP_LOGV(TAG, "Features: 0x%02X", ota_features); | ||||||
|  |  | ||||||
|   // Acknowledge header - 1 byte |   // Acknowledge header - 1 byte | ||||||
|   buf[0] = ota::OTA_RESPONSE_HEADER_OK; |   buf[0] = ota_base::OTA_RESPONSE_HEADER_OK; | ||||||
|   if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) { |   if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) { | ||||||
|     buf[0] = ota::OTA_RESPONSE_SUPPORTS_COMPRESSION; |     buf[0] = ota_base::OTA_RESPONSE_SUPPORTS_COMPRESSION; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   this->writeall_(buf, 1); |   this->writeall_(buf, 1); | ||||||
|  |  | ||||||
| #ifdef USE_OTA_PASSWORD | #ifdef USE_OTA_PASSWORD | ||||||
|   if (!this->password_.empty()) { |   if (!this->password_.empty()) { | ||||||
|     buf[0] = ota::OTA_RESPONSE_REQUEST_AUTH; |     buf[0] = ota_base::OTA_RESPONSE_REQUEST_AUTH; | ||||||
|     this->writeall_(buf, 1); |     this->writeall_(buf, 1); | ||||||
|     md5::MD5Digest md5{}; |     md5::MD5Digest md5{}; | ||||||
|     md5.init(); |     md5.init(); | ||||||
| @@ -220,14 +220,14 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|  |  | ||||||
|     if (!matches) { |     if (!matches) { | ||||||
|       ESP_LOGW(TAG, "Auth failed! Passwords do not match"); |       ESP_LOGW(TAG, "Auth failed! Passwords do not match"); | ||||||
|       error_code = ota::OTA_RESPONSE_ERROR_AUTH_INVALID; |       error_code = ota_base::OTA_RESPONSE_ERROR_AUTH_INVALID; | ||||||
|       goto error;  // NOLINT(cppcoreguidelines-avoid-goto) |       goto error;  // NOLINT(cppcoreguidelines-avoid-goto) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| #endif  // USE_OTA_PASSWORD | #endif  // USE_OTA_PASSWORD | ||||||
|  |  | ||||||
|   // Acknowledge auth OK - 1 byte |   // Acknowledge auth OK - 1 byte | ||||||
|   buf[0] = ota::OTA_RESPONSE_AUTH_OK; |   buf[0] = ota_base::OTA_RESPONSE_AUTH_OK; | ||||||
|   this->writeall_(buf, 1); |   this->writeall_(buf, 1); | ||||||
|  |  | ||||||
|   // Read size, 4 bytes MSB first |   // Read size, 4 bytes MSB first | ||||||
| @@ -243,12 +243,12 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   ESP_LOGV(TAG, "Size is %u bytes", ota_size); |   ESP_LOGV(TAG, "Size is %u bytes", ota_size); | ||||||
|  |  | ||||||
|   error_code = backend->begin(ota_size); |   error_code = backend->begin(ota_size); | ||||||
|   if (error_code != ota::OTA_RESPONSE_OK) |   if (error_code != ota_base::OTA_RESPONSE_OK) | ||||||
|     goto error;  // NOLINT(cppcoreguidelines-avoid-goto) |     goto error;  // NOLINT(cppcoreguidelines-avoid-goto) | ||||||
|   update_started = true; |   update_started = true; | ||||||
|  |  | ||||||
|   // Acknowledge prepare OK - 1 byte |   // Acknowledge prepare OK - 1 byte | ||||||
|   buf[0] = ota::OTA_RESPONSE_UPDATE_PREPARE_OK; |   buf[0] = ota_base::OTA_RESPONSE_UPDATE_PREPARE_OK; | ||||||
|   this->writeall_(buf, 1); |   this->writeall_(buf, 1); | ||||||
|  |  | ||||||
|   // Read binary MD5, 32 bytes |   // Read binary MD5, 32 bytes | ||||||
| @@ -261,7 +261,7 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   backend->set_update_md5(sbuf); |   backend->set_update_md5(sbuf); | ||||||
|  |  | ||||||
|   // Acknowledge MD5 OK - 1 byte |   // Acknowledge MD5 OK - 1 byte | ||||||
|   buf[0] = ota::OTA_RESPONSE_BIN_MD5_OK; |   buf[0] = ota_base::OTA_RESPONSE_BIN_MD5_OK; | ||||||
|   this->writeall_(buf, 1); |   this->writeall_(buf, 1); | ||||||
|  |  | ||||||
|   while (total < ota_size) { |   while (total < ota_size) { | ||||||
| @@ -285,14 +285,14 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     error_code = backend->write(buf, read); |     error_code = backend->write(buf, read); | ||||||
|     if (error_code != ota::OTA_RESPONSE_OK) { |     if (error_code != ota_base::OTA_RESPONSE_OK) { | ||||||
|       ESP_LOGW(TAG, "Error writing binary data to flash!, error_code: %d", error_code); |       ESP_LOGW(TAG, "Error writing binary data to flash!, error_code: %d", error_code); | ||||||
|       goto error;  // NOLINT(cppcoreguidelines-avoid-goto) |       goto error;  // NOLINT(cppcoreguidelines-avoid-goto) | ||||||
|     } |     } | ||||||
|     total += read; |     total += read; | ||||||
| #if USE_OTA_VERSION == 2 | #if USE_OTA_VERSION == 2 | ||||||
|     while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) { |     while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) { | ||||||
|       buf[0] = ota::OTA_RESPONSE_CHUNK_OK; |       buf[0] = ota_base::OTA_RESPONSE_CHUNK_OK; | ||||||
|       this->writeall_(buf, 1); |       this->writeall_(buf, 1); | ||||||
|       size_acknowledged += OTA_BLOCK_SIZE; |       size_acknowledged += OTA_BLOCK_SIZE; | ||||||
|     } |     } | ||||||
| @@ -304,7 +304,7 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|       float percentage = (total * 100.0f) / ota_size; |       float percentage = (total * 100.0f) / ota_size; | ||||||
|       ESP_LOGD(TAG, "Progress: %0.1f%%", percentage); |       ESP_LOGD(TAG, "Progress: %0.1f%%", percentage); | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|       this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0); |       this->state_callback_.call(ota_base::OTA_IN_PROGRESS, percentage, 0); | ||||||
| #endif | #endif | ||||||
|       // feed watchdog and give other tasks a chance to run |       // feed watchdog and give other tasks a chance to run | ||||||
|       App.feed_wdt(); |       App.feed_wdt(); | ||||||
| @@ -313,21 +313,21 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Acknowledge receive OK - 1 byte |   // Acknowledge receive OK - 1 byte | ||||||
|   buf[0] = ota::OTA_RESPONSE_RECEIVE_OK; |   buf[0] = ota_base::OTA_RESPONSE_RECEIVE_OK; | ||||||
|   this->writeall_(buf, 1); |   this->writeall_(buf, 1); | ||||||
|  |  | ||||||
|   error_code = backend->end(); |   error_code = backend->end(); | ||||||
|   if (error_code != ota::OTA_RESPONSE_OK) { |   if (error_code != ota_base::OTA_RESPONSE_OK) { | ||||||
|     ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code); |     ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code); | ||||||
|     goto error;  // NOLINT(cppcoreguidelines-avoid-goto) |     goto error;  // NOLINT(cppcoreguidelines-avoid-goto) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Acknowledge Update end OK - 1 byte |   // Acknowledge Update end OK - 1 byte | ||||||
|   buf[0] = ota::OTA_RESPONSE_UPDATE_END_OK; |   buf[0] = ota_base::OTA_RESPONSE_UPDATE_END_OK; | ||||||
|   this->writeall_(buf, 1); |   this->writeall_(buf, 1); | ||||||
|  |  | ||||||
|   // Read ACK |   // Read ACK | ||||||
|   if (!this->readall_(buf, 1) || buf[0] != ota::OTA_RESPONSE_OK) { |   if (!this->readall_(buf, 1) || buf[0] != ota_base::OTA_RESPONSE_OK) { | ||||||
|     ESP_LOGW(TAG, "Reading back acknowledgement failed"); |     ESP_LOGW(TAG, "Reading back acknowledgement failed"); | ||||||
|     // do not go to error, this is not fatal |     // do not go to error, this is not fatal | ||||||
|   } |   } | ||||||
| @@ -338,7 +338,7 @@ void ESPHomeOTAComponent::handle_() { | |||||||
|   ESP_LOGI(TAG, "Update complete"); |   ESP_LOGI(TAG, "Update complete"); | ||||||
|   this->status_clear_warning(); |   this->status_clear_warning(); | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|   this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, 0); |   this->state_callback_.call(ota_base::OTA_COMPLETED, 100.0f, 0); | ||||||
| #endif | #endif | ||||||
|   delay(100);  // NOLINT |   delay(100);  // NOLINT | ||||||
|   App.safe_reboot(); |   App.safe_reboot(); | ||||||
| @@ -355,7 +355,7 @@ error: | |||||||
|  |  | ||||||
|   this->status_momentary_error("onerror", 5000); |   this->status_momentary_error("onerror", 5000); | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|   this->state_callback_.call(ota::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code)); |   this->state_callback_.call(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code)); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,13 +4,13 @@ | |||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
| #include "esphome/components/ota/ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h" | ||||||
| #include "esphome/components/socket/socket.h" | #include "esphome/components/socket/socket.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|  |  | ||||||
| /// ESPHomeOTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA. | /// ESPHomeOTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA. | ||||||
| class ESPHomeOTAComponent : public ota::OTAComponent { | class ESPHomeOTAComponent : public ota_base::OTAComponent { | ||||||
|  public: |  public: | ||||||
| #ifdef USE_OTA_PASSWORD | #ifdef USE_OTA_PASSWORD | ||||||
|   void set_auth_password(const std::string &password) { password_ = password; } |   void set_auth_password(const std::string &password) { password_ = password; } | ||||||
|   | |||||||
| @@ -19,11 +19,7 @@ | |||||||
| #include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||||
| #include "esp_log.h" | #include "esp_log.h" | ||||||
| #include "esp_eth.h" | #include "esp_eth.h" | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| #include "esp_eth_phy_802_3.h" | #include "esp_eth_phy_802_3.h" | ||||||
| #else |  | ||||||
| #include "eth_phy_regs_struct.h" |  | ||||||
| #endif |  | ||||||
| #include "freertos/FreeRTOS.h" | #include "freertos/FreeRTOS.h" | ||||||
| #include "freertos/task.h" | #include "freertos/task.h" | ||||||
| #include "driver/gpio.h" | #include "driver/gpio.h" | ||||||
| @@ -174,11 +170,7 @@ static esp_err_t jl1101_reset_hw(esp_eth_phy_t *phy) { | |||||||
|   return ESP_OK; |   return ESP_OK; | ||||||
| } | } | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| static esp_err_t jl1101_negotiate(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *nego_state) { | static esp_err_t jl1101_negotiate(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *nego_state) { | ||||||
| #else |  | ||||||
| static esp_err_t jl1101_negotiate(esp_eth_phy_t *phy) { |  | ||||||
| #endif |  | ||||||
|   phy_jl1101_t *jl1101 = __containerof(phy, phy_jl1101_t, parent); |   phy_jl1101_t *jl1101 = __containerof(phy, phy_jl1101_t, parent); | ||||||
|   esp_eth_mediator_t *eth = jl1101->eth; |   esp_eth_mediator_t *eth = jl1101->eth; | ||||||
|   /* in case any link status has changed, let's assume we're in link down status */ |   /* in case any link status has changed, let's assume we're in link down status */ | ||||||
| @@ -293,11 +285,7 @@ static esp_err_t jl1101_init(esp_eth_phy_t *phy) { | |||||||
|   esp_eth_mediator_t *eth = jl1101->eth; |   esp_eth_mediator_t *eth = jl1101->eth; | ||||||
|   // Detect PHY address |   // Detect PHY address | ||||||
|   if (jl1101->addr == ESP_ETH_PHY_ADDR_AUTO) { |   if (jl1101->addr == ESP_ETH_PHY_ADDR_AUTO) { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|     PHY_CHECK(esp_eth_phy_802_3_detect_phy_addr(eth, &jl1101->addr) == ESP_OK, "Detect PHY address failed", err); |     PHY_CHECK(esp_eth_phy_802_3_detect_phy_addr(eth, &jl1101->addr) == ESP_OK, "Detect PHY address failed", err); | ||||||
| #else |  | ||||||
|     PHY_CHECK(esp_eth_detect_phy_addr(eth, &jl1101->addr) == ESP_OK, "Detect PHY address failed", err); |  | ||||||
| #endif |  | ||||||
|   } |   } | ||||||
|   /* Power on Ethernet PHY */ |   /* Power on Ethernet PHY */ | ||||||
|   PHY_CHECK(jl1101_pwrctl(phy, true) == ESP_OK, "power control failed", err); |   PHY_CHECK(jl1101_pwrctl(phy, true) == ESP_OK, "power control failed", err); | ||||||
| @@ -336,11 +324,7 @@ esp_eth_phy_t *esp_eth_phy_new_jl1101(const eth_phy_config_t *config) { | |||||||
|   jl1101->parent.init = jl1101_init; |   jl1101->parent.init = jl1101_init; | ||||||
|   jl1101->parent.deinit = jl1101_deinit; |   jl1101->parent.deinit = jl1101_deinit; | ||||||
|   jl1101->parent.set_mediator = jl1101_set_mediator; |   jl1101->parent.set_mediator = jl1101_set_mediator; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   jl1101->parent.autonego_ctrl = jl1101_negotiate; |   jl1101->parent.autonego_ctrl = jl1101_negotiate; | ||||||
| #else |  | ||||||
|   jl1101->parent.negotiate = jl1101_negotiate; |  | ||||||
| #endif |  | ||||||
|   jl1101->parent.get_link = jl1101_get_link; |   jl1101->parent.get_link = jl1101_get_link; | ||||||
|   jl1101->parent.pwrctl = jl1101_pwrctl; |   jl1101->parent.pwrctl = jl1101_pwrctl; | ||||||
|   jl1101->parent.get_addr = jl1101_get_addr; |   jl1101->parent.get_addr = jl1101_get_addr; | ||||||
|   | |||||||
| @@ -122,25 +122,12 @@ void EthernetComponent::setup() { | |||||||
|       .post_cb = nullptr, |       .post_cb = nullptr, | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| #if CONFIG_ETH_SPI_ETHERNET_W5500 | #if CONFIG_ETH_SPI_ETHERNET_W5500 | ||||||
|   eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg); |   eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg); | ||||||
| #endif | #endif | ||||||
| #if CONFIG_ETH_SPI_ETHERNET_DM9051 | #if CONFIG_ETH_SPI_ETHERNET_DM9051 | ||||||
|   eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(host, &devcfg); |   eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(host, &devcfg); | ||||||
| #endif | #endif | ||||||
| #else |  | ||||||
|   spi_device_handle_t spi_handle = nullptr; |  | ||||||
|   err = spi_bus_add_device(host, &devcfg, &spi_handle); |  | ||||||
|   ESPHL_ERROR_CHECK(err, "SPI bus add device error"); |  | ||||||
|  |  | ||||||
| #if CONFIG_ETH_SPI_ETHERNET_W5500 |  | ||||||
|   eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); |  | ||||||
| #endif |  | ||||||
| #if CONFIG_ETH_SPI_ETHERNET_DM9051 |  | ||||||
|   eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); |  | ||||||
| #endif |  | ||||||
| #endif  // ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|  |  | ||||||
| #if CONFIG_ETH_SPI_ETHERNET_W5500 | #if CONFIG_ETH_SPI_ETHERNET_W5500 | ||||||
|   w5500_config.int_gpio_num = this->interrupt_pin_; |   w5500_config.int_gpio_num = this->interrupt_pin_; | ||||||
| @@ -211,11 +198,7 @@ void EthernetComponent::setup() { | |||||||
|     } |     } | ||||||
|     case ETHERNET_TYPE_KSZ8081: |     case ETHERNET_TYPE_KSZ8081: | ||||||
|     case ETHERNET_TYPE_KSZ8081RNA: { |     case ETHERNET_TYPE_KSZ8081RNA: { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|       this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config); |       this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config); | ||||||
| #else |  | ||||||
|       this->phy_ = esp_eth_phy_new_ksz8081(&phy_config); |  | ||||||
| #endif |  | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| from esphome import automation | from esphome import automation | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code | from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import CONF_ID, CONF_PASSWORD, CONF_URL, CONF_USERNAME | from esphome.const import CONF_ID, CONF_PASSWORD, CONF_URL, CONF_USERNAME | ||||||
| from esphome.core import coroutine_with_priority | from esphome.core import coroutine_with_priority | ||||||
| @@ -15,6 +15,9 @@ DEPENDENCIES = ["network", "http_request"] | |||||||
| CONF_MD5 = "md5" | CONF_MD5 = "md5" | ||||||
| CONF_MD5_URL = "md5_url" | CONF_MD5_URL = "md5_url" | ||||||
|  |  | ||||||
|  | ota_base_ns = cg.esphome_ns.namespace("ota_base") | ||||||
|  | OTAComponent = ota_base_ns.class_("OTAComponent", cg.Component) | ||||||
|  |  | ||||||
| OtaHttpRequestComponent = http_request_ns.class_( | OtaHttpRequestComponent = http_request_ns.class_( | ||||||
|     "OtaHttpRequestComponent", OTAComponent |     "OtaHttpRequestComponent", OTAComponent | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -6,11 +6,11 @@ | |||||||
|  |  | ||||||
| #include "esphome/components/md5/md5.h" | #include "esphome/components/md5/md5.h" | ||||||
| #include "esphome/components/watchdog/watchdog.h" | #include "esphome/components/watchdog/watchdog.h" | ||||||
| #include "esphome/components/ota/ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h" | ||||||
| #include "esphome/components/ota/ota_backend_arduino_esp32.h" | #include "esphome/components/ota_base/ota_backend_arduino_esp32.h" | ||||||
| #include "esphome/components/ota/ota_backend_arduino_esp8266.h" | #include "esphome/components/ota_base/ota_backend_arduino_esp8266.h" | ||||||
| #include "esphome/components/ota/ota_backend_arduino_rp2040.h" | #include "esphome/components/ota_base/ota_backend_arduino_rp2040.h" | ||||||
| #include "esphome/components/ota/ota_backend_esp_idf.h" | #include "esphome/components/ota_base/ota_backend_esp_idf.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace http_request { | namespace http_request { | ||||||
| @@ -19,7 +19,7 @@ static const char *const TAG = "http_request.ota"; | |||||||
|  |  | ||||||
| void OtaHttpRequestComponent::setup() { | void OtaHttpRequestComponent::setup() { | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|   ota::register_ota_platform(this); |   ota_base::register_ota_platform(this); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -50,15 +50,15 @@ void OtaHttpRequestComponent::flash() { | |||||||
|  |  | ||||||
|   ESP_LOGI(TAG, "Starting update"); |   ESP_LOGI(TAG, "Starting update"); | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|   this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0); |   this->state_callback_.call(ota_base::OTA_STARTED, 0.0f, 0); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   auto ota_status = this->do_ota_(); |   auto ota_status = this->do_ota_(); | ||||||
|  |  | ||||||
|   switch (ota_status) { |   switch (ota_status) { | ||||||
|     case ota::OTA_RESPONSE_OK: |     case ota_base::OTA_RESPONSE_OK: | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|       this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, ota_status); |       this->state_callback_.call(ota_base::OTA_COMPLETED, 100.0f, ota_status); | ||||||
| #endif | #endif | ||||||
|       delay(10); |       delay(10); | ||||||
|       App.safe_reboot(); |       App.safe_reboot(); | ||||||
| @@ -66,7 +66,7 @@ void OtaHttpRequestComponent::flash() { | |||||||
|  |  | ||||||
|     default: |     default: | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|       this->state_callback_.call(ota::OTA_ERROR, 0.0f, ota_status); |       this->state_callback_.call(ota_base::OTA_ERROR, 0.0f, ota_status); | ||||||
| #endif | #endif | ||||||
|       this->md5_computed_.clear();  // will be reset at next attempt |       this->md5_computed_.clear();  // will be reset at next attempt | ||||||
|       this->md5_expected_.clear();  // will be reset at next attempt |       this->md5_expected_.clear();  // will be reset at next attempt | ||||||
| @@ -74,7 +74,7 @@ void OtaHttpRequestComponent::flash() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void OtaHttpRequestComponent::cleanup_(std::unique_ptr<ota::OTABackend> backend, | void OtaHttpRequestComponent::cleanup_(std::unique_ptr<ota_base::OTABackend> backend, | ||||||
|                                        const std::shared_ptr<HttpContainer> &container) { |                                        const std::shared_ptr<HttpContainer> &container) { | ||||||
|   if (this->update_started_) { |   if (this->update_started_) { | ||||||
|     ESP_LOGV(TAG, "Aborting OTA backend"); |     ESP_LOGV(TAG, "Aborting OTA backend"); | ||||||
| @@ -115,9 +115,9 @@ uint8_t OtaHttpRequestComponent::do_ota_() { | |||||||
|   ESP_LOGV(TAG, "MD5Digest initialized"); |   ESP_LOGV(TAG, "MD5Digest initialized"); | ||||||
|  |  | ||||||
|   ESP_LOGV(TAG, "OTA backend begin"); |   ESP_LOGV(TAG, "OTA backend begin"); | ||||||
|   auto backend = ota::make_ota_backend(); |   auto backend = ota_base::make_ota_backend(); | ||||||
|   auto error_code = backend->begin(container->content_length); |   auto error_code = backend->begin(container->content_length); | ||||||
|   if (error_code != ota::OTA_RESPONSE_OK) { |   if (error_code != ota_base::OTA_RESPONSE_OK) { | ||||||
|     ESP_LOGW(TAG, "backend->begin error: %d", error_code); |     ESP_LOGW(TAG, "backend->begin error: %d", error_code); | ||||||
|     this->cleanup_(std::move(backend), container); |     this->cleanup_(std::move(backend), container); | ||||||
|     return error_code; |     return error_code; | ||||||
| @@ -144,7 +144,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() { | |||||||
|       // write bytes to OTA backend |       // write bytes to OTA backend | ||||||
|       this->update_started_ = true; |       this->update_started_ = true; | ||||||
|       error_code = backend->write(buf, bufsize); |       error_code = backend->write(buf, bufsize); | ||||||
|       if (error_code != ota::OTA_RESPONSE_OK) { |       if (error_code != ota_base::OTA_RESPONSE_OK) { | ||||||
|         // error code explanation available at |         // error code explanation available at | ||||||
|         // https://github.com/esphome/esphome/blob/dev/esphome/components/ota/ota_backend.h |         // https://github.com/esphome/esphome/blob/dev/esphome/components/ota/ota_backend.h | ||||||
|         ESP_LOGE(TAG, "Error code (%02X) writing binary data to flash at offset %d and size %d", error_code, |         ESP_LOGE(TAG, "Error code (%02X) writing binary data to flash at offset %d and size %d", error_code, | ||||||
| @@ -160,7 +160,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() { | |||||||
|       float percentage = container->get_bytes_read() * 100.0f / container->content_length; |       float percentage = container->get_bytes_read() * 100.0f / container->content_length; | ||||||
|       ESP_LOGD(TAG, "Progress: %0.1f%%", percentage); |       ESP_LOGD(TAG, "Progress: %0.1f%%", percentage); | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|       this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0); |       this->state_callback_.call(ota_base::OTA_IN_PROGRESS, percentage, 0); | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
|   }  // while |   }  // while | ||||||
| @@ -174,7 +174,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() { | |||||||
|   if (strncmp(this->md5_computed_.c_str(), this->md5_expected_.c_str(), MD5_SIZE) != 0) { |   if (strncmp(this->md5_computed_.c_str(), this->md5_expected_.c_str(), MD5_SIZE) != 0) { | ||||||
|     ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->md5_computed_.c_str()); |     ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->md5_computed_.c_str()); | ||||||
|     this->cleanup_(std::move(backend), container); |     this->cleanup_(std::move(backend), container); | ||||||
|     return ota::OTA_RESPONSE_ERROR_MD5_MISMATCH; |     return ota_base::OTA_RESPONSE_ERROR_MD5_MISMATCH; | ||||||
|   } else { |   } else { | ||||||
|     backend->set_update_md5(md5_receive_str.get()); |     backend->set_update_md5(md5_receive_str.get()); | ||||||
|   } |   } | ||||||
| @@ -187,14 +187,14 @@ uint8_t OtaHttpRequestComponent::do_ota_() { | |||||||
|   delay(100);  // NOLINT |   delay(100);  // NOLINT | ||||||
|  |  | ||||||
|   error_code = backend->end(); |   error_code = backend->end(); | ||||||
|   if (error_code != ota::OTA_RESPONSE_OK) { |   if (error_code != ota_base::OTA_RESPONSE_OK) { | ||||||
|     ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code); |     ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code); | ||||||
|     this->cleanup_(std::move(backend), container); |     this->cleanup_(std::move(backend), container); | ||||||
|     return error_code; |     return error_code; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   ESP_LOGI(TAG, "Update complete"); |   ESP_LOGI(TAG, "Update complete"); | ||||||
|   return ota::OTA_RESPONSE_OK; |   return ota_base::OTA_RESPONSE_OK; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::string OtaHttpRequestComponent::get_url_with_auth_(const std::string &url) { | std::string OtaHttpRequestComponent::get_url_with_auth_(const std::string &url) { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "esphome/components/ota/ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/defines.h" | #include "esphome/core/defines.h" | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| @@ -22,7 +22,7 @@ enum OtaHttpRequestError : uint8_t { | |||||||
|   OTA_CONNECTION_ERROR = 0x12, |   OTA_CONNECTION_ERROR = 0x12, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class OtaHttpRequestComponent : public ota::OTAComponent, public Parented<HttpRequestComponent> { | class OtaHttpRequestComponent : public ota_base::OTAComponent, public Parented<HttpRequestComponent> { | ||||||
|  public: |  public: | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
| @@ -40,7 +40,7 @@ class OtaHttpRequestComponent : public ota::OTAComponent, public Parented<HttpRe | |||||||
|   void flash(); |   void flash(); | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void cleanup_(std::unique_ptr<ota::OTABackend> backend, const std::shared_ptr<HttpContainer> &container); |   void cleanup_(std::unique_ptr<ota_base::OTABackend> backend, const std::shared_ptr<HttpContainer> &container); | ||||||
|   uint8_t do_ota_(); |   uint8_t do_ota_(); | ||||||
|   std::string get_url_with_auth_(const std::string &url); |   std::string get_url_with_auth_(const std::string &url); | ||||||
|   bool http_get_md5_(); |   bool http_get_md5_(); | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/components/json/json_util.h" | #include "esphome/components/json/json_util.h" | ||||||
| #include "esphome/components/network/util.h" | #include "esphome/components/network/util.h" | ||||||
|  | #include "esphome/components/ota_base/ota_backend.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace http_request { | namespace http_request { | ||||||
| @@ -21,13 +22,13 @@ static const char *const TAG = "http_request.update"; | |||||||
| static const size_t MAX_READ_SIZE = 256; | static const size_t MAX_READ_SIZE = 256; | ||||||
|  |  | ||||||
| void HttpRequestUpdate::setup() { | void HttpRequestUpdate::setup() { | ||||||
|   this->ota_parent_->add_on_state_callback([this](ota::OTAState state, float progress, uint8_t err) { |   this->ota_parent_->add_on_state_callback([this](ota_base::OTAState state, float progress, uint8_t err) { | ||||||
|     if (state == ota::OTAState::OTA_IN_PROGRESS) { |     if (state == ota_base::OTAState::OTA_IN_PROGRESS) { | ||||||
|       this->state_ = update::UPDATE_STATE_INSTALLING; |       this->state_ = update::UPDATE_STATE_INSTALLING; | ||||||
|       this->update_info_.has_progress = true; |       this->update_info_.has_progress = true; | ||||||
|       this->update_info_.progress = progress; |       this->update_info_.progress = progress; | ||||||
|       this->publish_state(); |       this->publish_state(); | ||||||
|     } else if (state == ota::OTAState::OTA_ABORT || state == ota::OTAState::OTA_ERROR) { |     } else if (state == ota_base::OTAState::OTA_ABORT || state == ota_base::OTAState::OTA_ERROR) { | ||||||
|       this->state_ = update::UPDATE_STATE_AVAILABLE; |       this->state_ = update::UPDATE_STATE_AVAILABLE; | ||||||
|       this->status_set_error("Failed to install firmware"); |       this->status_set_error("Failed to install firmware"); | ||||||
|       this->publish_state(); |       this->publish_state(); | ||||||
|   | |||||||
| @@ -9,14 +9,7 @@ from esphome.components.esp32.const import ( | |||||||
|     VARIANT_ESP32S3, |     VARIANT_ESP32S3, | ||||||
| ) | ) | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import CONF_BITS_PER_SAMPLE, CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE | ||||||
|     CONF_BITS_PER_SAMPLE, |  | ||||||
|     CONF_CHANNEL, |  | ||||||
|     CONF_ID, |  | ||||||
|     CONF_SAMPLE_RATE, |  | ||||||
|     KEY_CORE, |  | ||||||
|     KEY_FRAMEWORK_VERSION, |  | ||||||
| ) |  | ||||||
| from esphome.core import CORE | from esphome.core import CORE | ||||||
| from esphome.cpp_generator import MockObjClass | from esphome.cpp_generator import MockObjClass | ||||||
| import esphome.final_validate as fv | import esphome.final_validate as fv | ||||||
| @@ -250,8 +243,7 @@ def _final_validate(_): | |||||||
|  |  | ||||||
|  |  | ||||||
| def use_legacy(): | def use_legacy(): | ||||||
|     framework_version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] |     if CORE.using_esp_idf: | ||||||
|     if CORE.using_esp_idf and framework_version >= cv.Version(5, 0, 0): |  | ||||||
|         if not _use_legacy_driver: |         if not _use_legacy_driver: | ||||||
|             return False |             return False | ||||||
|     return True |     return True | ||||||
|   | |||||||
| @@ -9,15 +9,11 @@ namespace i2s_audio { | |||||||
|  |  | ||||||
| static const char *const TAG = "i2s_audio"; | static const char *const TAG = "i2s_audio"; | ||||||
|  |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| static const uint8_t I2S_NUM_MAX = SOC_I2S_NUM;  // because IDF 5+ took this away :( |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| void I2SAudioComponent::setup() { | void I2SAudioComponent::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Running setup"); |   ESP_LOGCONFIG(TAG, "Running setup"); | ||||||
|  |  | ||||||
|   static i2s_port_t next_port_num = I2S_NUM_0; |   static i2s_port_t next_port_num = I2S_NUM_0; | ||||||
|   if (next_port_num >= I2S_NUM_MAX) { |   if (next_port_num >= SOC_I2S_NUM) { | ||||||
|     ESP_LOGE(TAG, "Too many components"); |     ESP_LOGE(TAG, "Too many components"); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   | |||||||
| @@ -59,11 +59,7 @@ optional<uint8_t> ImprovSerialComponent::read_byte_() { | |||||||
|       break; |       break; | ||||||
| #if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC) | #if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC) | ||||||
|     case logger::UART_SELECTION_USB_CDC: |     case logger::UART_SELECTION_USB_CDC: | ||||||
| #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) |  | ||||||
|       if (esp_usb_console_available_for_read()) { |       if (esp_usb_console_available_for_read()) { | ||||||
| #else |  | ||||||
|       if (esp_usb_console_read_available()) { |  | ||||||
| #endif |  | ||||||
|         esp_usb_console_read_buf((char *) &data, 1); |         esp_usb_console_read_buf((char *) &data, 1); | ||||||
|         byte = data; |         byte = data; | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -10,11 +10,7 @@ uint8_t temprature_sens_read(); | |||||||
| #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ | #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ | ||||||
|     defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \ |     defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \ | ||||||
|     defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4) |     defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4) | ||||||
| #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) |  | ||||||
| #include "driver/temp_sensor.h" |  | ||||||
| #else |  | ||||||
| #include "driver/temperature_sensor.h" | #include "driver/temperature_sensor.h" | ||||||
| #endif  // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) |  | ||||||
| #endif  // USE_ESP32_VARIANT | #endif  // USE_ESP32_VARIANT | ||||||
| #endif  // USE_ESP32 | #endif  // USE_ESP32 | ||||||
| #ifdef USE_RP2040 | #ifdef USE_RP2040 | ||||||
| @@ -31,12 +27,11 @@ namespace internal_temperature { | |||||||
|  |  | ||||||
| static const char *const TAG = "internal_temperature"; | static const char *const TAG = "internal_temperature"; | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \ | #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ | ||||||
|     (defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ |     defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ | ||||||
|      defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ |     defined(USE_ESP32_VARIANT_ESP32P4) | ||||||
|      defined(USE_ESP32_VARIANT_ESP32P4)) |  | ||||||
| static temperature_sensor_handle_t tsensNew = NULL; | static temperature_sensor_handle_t tsensNew = NULL; | ||||||
| #endif  // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && USE_ESP32_VARIANT | #endif  // USE_ESP32_VARIANT | ||||||
| #endif  // USE_ESP32 | #endif  // USE_ESP32 | ||||||
|  |  | ||||||
| void InternalTemperatureSensor::update() { | void InternalTemperatureSensor::update() { | ||||||
| @@ -51,24 +46,11 @@ void InternalTemperatureSensor::update() { | |||||||
| #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ | #elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \ | ||||||
|     defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \ |     defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \ | ||||||
|     defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4) |     defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4) | ||||||
| #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) |  | ||||||
|   temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT(); |  | ||||||
|   temp_sensor_set_config(tsens); |  | ||||||
|   temp_sensor_start(); |  | ||||||
| #if defined(USE_ESP32_VARIANT_ESP32S3) && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 3)) |  | ||||||
| #error \ |  | ||||||
|     "ESP32-S3 internal temperature sensor requires ESP IDF V4.4.3 or higher. See https://github.com/esphome/issues/issues/4271" |  | ||||||
| #endif |  | ||||||
|   esp_err_t result = temp_sensor_read_celsius(&temperature); |  | ||||||
|   temp_sensor_stop(); |  | ||||||
|   success = (result == ESP_OK); |  | ||||||
| #else |  | ||||||
|   esp_err_t result = temperature_sensor_get_celsius(tsensNew, &temperature); |   esp_err_t result = temperature_sensor_get_celsius(tsensNew, &temperature); | ||||||
|   success = (result == ESP_OK); |   success = (result == ESP_OK); | ||||||
|   if (!success) { |   if (!success) { | ||||||
|     ESP_LOGE(TAG, "Reading failed (%d)", result); |     ESP_LOGE(TAG, "Reading failed (%d)", result); | ||||||
|   } |   } | ||||||
| #endif  // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) |  | ||||||
| #endif  // USE_ESP32_VARIANT | #endif  // USE_ESP32_VARIANT | ||||||
| #endif  // USE_ESP32 | #endif  // USE_ESP32 | ||||||
| #ifdef USE_RP2040 | #ifdef USE_RP2040 | ||||||
| @@ -99,10 +81,9 @@ void InternalTemperatureSensor::update() { | |||||||
|  |  | ||||||
| void InternalTemperatureSensor::setup() { | void InternalTemperatureSensor::setup() { | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \ | #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ | ||||||
|     (defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \ |     defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ | ||||||
|      defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \ |     defined(USE_ESP32_VARIANT_ESP32P4) | ||||||
|      defined(USE_ESP32_VARIANT_ESP32P4)) |  | ||||||
|   ESP_LOGCONFIG(TAG, "Running setup"); |   ESP_LOGCONFIG(TAG, "Running setup"); | ||||||
|  |  | ||||||
|   temperature_sensor_config_t tsens_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80); |   temperature_sensor_config_t tsens_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80); | ||||||
| @@ -120,7 +101,7 @@ void InternalTemperatureSensor::setup() { | |||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| #endif  // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && USE_ESP32_VARIANT | #endif  // USE_ESP32_VARIANT | ||||||
| #endif  // USE_ESP32 | #endif  // USE_ESP32 | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,46 +1,21 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| from esphome.components import sensor | from esphome.components import sensor | ||||||
| from esphome.components.esp32 import get_esp32_variant |  | ||||||
| from esphome.components.esp32.const import VARIANT_ESP32S3 |  | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     DEVICE_CLASS_TEMPERATURE, |     DEVICE_CLASS_TEMPERATURE, | ||||||
|     ENTITY_CATEGORY_DIAGNOSTIC, |     ENTITY_CATEGORY_DIAGNOSTIC, | ||||||
|     KEY_CORE, |  | ||||||
|     KEY_FRAMEWORK_VERSION, |  | ||||||
|     PLATFORM_BK72XX, |     PLATFORM_BK72XX, | ||||||
|     PLATFORM_ESP32, |     PLATFORM_ESP32, | ||||||
|     PLATFORM_RP2040, |     PLATFORM_RP2040, | ||||||
|     STATE_CLASS_MEASUREMENT, |     STATE_CLASS_MEASUREMENT, | ||||||
|     UNIT_CELSIUS, |     UNIT_CELSIUS, | ||||||
| ) | ) | ||||||
| from esphome.core import CORE |  | ||||||
|  |  | ||||||
| internal_temperature_ns = cg.esphome_ns.namespace("internal_temperature") | internal_temperature_ns = cg.esphome_ns.namespace("internal_temperature") | ||||||
| InternalTemperatureSensor = internal_temperature_ns.class_( | InternalTemperatureSensor = internal_temperature_ns.class_( | ||||||
|     "InternalTemperatureSensor", sensor.Sensor, cg.PollingComponent |     "InternalTemperatureSensor", sensor.Sensor, cg.PollingComponent | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_config(config): |  | ||||||
|     if CORE.is_esp32: |  | ||||||
|         variant = get_esp32_variant() |  | ||||||
|         if variant == VARIANT_ESP32S3: |  | ||||||
|             if CORE.using_arduino and CORE.data[KEY_CORE][ |  | ||||||
|                 KEY_FRAMEWORK_VERSION |  | ||||||
|             ] < cv.Version(2, 0, 6): |  | ||||||
|                 raise cv.Invalid( |  | ||||||
|                     "ESP32-S3 Internal Temperature Sensor requires framework version 2.0.6 or higher. See <https://github.com/esphome/issues/issues/4271>." |  | ||||||
|                 ) |  | ||||||
|             if CORE.using_esp_idf and CORE.data[KEY_CORE][ |  | ||||||
|                 KEY_FRAMEWORK_VERSION |  | ||||||
|             ] < cv.Version(4, 4, 3): |  | ||||||
|                 raise cv.Invalid( |  | ||||||
|                     "ESP32-S3 Internal Temperature Sensor requires framework version 4.4.3 or higher. See <https://github.com/esphome/issues/issues/4271>." |  | ||||||
|                 ) |  | ||||||
|     return config |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     sensor.sensor_schema( |     sensor.sensor_schema( | ||||||
|         InternalTemperatureSensor, |         InternalTemperatureSensor, | ||||||
| @@ -51,7 +26,6 @@ CONFIG_SCHEMA = cv.All( | |||||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, |         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, | ||||||
|     ).extend(cv.polling_component_schema("60s")), |     ).extend(cv.polling_component_schema("60s")), | ||||||
|     cv.only_on([PLATFORM_ESP32, PLATFORM_RP2040, PLATFORM_BK72XX]), |     cv.only_on([PLATFORM_ESP32, PLATFORM_RP2040, PLATFORM_BK72XX]), | ||||||
|     validate_config, |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -83,9 +83,7 @@ void init_uart(uart_port_t uart_num, uint32_t baud_rate, int tx_buffer_size) { | |||||||
|   uart_config.parity = UART_PARITY_DISABLE; |   uart_config.parity = UART_PARITY_DISABLE; | ||||||
|   uart_config.stop_bits = UART_STOP_BITS_1; |   uart_config.stop_bits = UART_STOP_BITS_1; | ||||||
|   uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; |   uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; | ||||||
| #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) |  | ||||||
|   uart_config.source_clk = UART_SCLK_DEFAULT; |   uart_config.source_clk = UART_SCLK_DEFAULT; | ||||||
| #endif |  | ||||||
|   uart_param_config(uart_num, &uart_config); |   uart_param_config(uart_num, &uart_config); | ||||||
|   const int uart_buffer_size = tx_buffer_size; |   const int uart_buffer_size = tx_buffer_size; | ||||||
|   // Install UART driver using an event queue here |   // Install UART driver using an event queue here | ||||||
|   | |||||||
| @@ -8,8 +8,6 @@ from esphome.const import ( | |||||||
|     CONF_PROTOCOL, |     CONF_PROTOCOL, | ||||||
|     CONF_SERVICE, |     CONF_SERVICE, | ||||||
|     CONF_SERVICES, |     CONF_SERVICES, | ||||||
|     KEY_CORE, |  | ||||||
|     KEY_FRAMEWORK_VERSION, |  | ||||||
| ) | ) | ||||||
| from esphome.core import CORE, coroutine_with_priority | from esphome.core import CORE, coroutine_with_priority | ||||||
|  |  | ||||||
| @@ -85,9 +83,7 @@ async def to_code(config): | |||||||
|         elif CORE.is_rp2040: |         elif CORE.is_rp2040: | ||||||
|             cg.add_library("LEAmDNS", None) |             cg.add_library("LEAmDNS", None) | ||||||
|  |  | ||||||
|     if CORE.using_esp_idf and CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version( |     if CORE.using_esp_idf: | ||||||
|         5, 0, 0 |  | ||||||
|     ): |  | ||||||
|         add_idf_component(name="espressif/mdns", ref="1.8.2") |         add_idf_component(name="espressif/mdns", ref="1.8.2") | ||||||
|  |  | ||||||
|     cg.add_define("USE_MDNS") |     cg.add_define("USE_MDNS") | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| #include "esphome/components/audio/audio_transfer_buffer.h" | #include "esphome/components/audio/audio_transfer_buffer.h" | ||||||
|  |  | ||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
| #include "esphome/components/ota/ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| @@ -121,11 +121,11 @@ void MicroWakeWord::setup() { | |||||||
|   }); |   }); | ||||||
|  |  | ||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
|   ota::get_global_ota_callback()->add_on_state_callback( |   ota_base::get_global_ota_callback()->add_on_state_callback( | ||||||
|       [this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) { |       [this](ota_base::OTAState state, float progress, uint8_t error, ota_base::OTAComponent *comp) { | ||||||
|         if (state == ota::OTA_STARTED) { |         if (state == ota_base::OTA_STARTED) { | ||||||
|           this->suspend_task_(); |           this->suspend_task_(); | ||||||
|         } else if (state == ota::OTA_ERROR) { |         } else if (state == ota_base::OTA_ERROR) { | ||||||
|           this->resume_task_(); |           this->resume_task_(); | ||||||
|         } |         } | ||||||
|       }); |       }); | ||||||
|   | |||||||
| @@ -14,49 +14,6 @@ namespace mqtt { | |||||||
| static const char *const TAG = "mqtt.idf"; | static const char *const TAG = "mqtt.idf"; | ||||||
|  |  | ||||||
| bool MQTTBackendESP32::initialize_() { | bool MQTTBackendESP32::initialize_() { | ||||||
| #if ESP_IDF_VERSION_MAJOR < 5 |  | ||||||
|   mqtt_cfg_.user_context = (void *) this; |  | ||||||
|   mqtt_cfg_.buffer_size = MQTT_BUFFER_SIZE; |  | ||||||
|  |  | ||||||
|   mqtt_cfg_.host = this->host_.c_str(); |  | ||||||
|   mqtt_cfg_.port = this->port_; |  | ||||||
|   mqtt_cfg_.keepalive = this->keep_alive_; |  | ||||||
|   mqtt_cfg_.disable_clean_session = !this->clean_session_; |  | ||||||
|  |  | ||||||
|   if (!this->username_.empty()) { |  | ||||||
|     mqtt_cfg_.username = this->username_.c_str(); |  | ||||||
|     if (!this->password_.empty()) { |  | ||||||
|       mqtt_cfg_.password = this->password_.c_str(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (!this->lwt_topic_.empty()) { |  | ||||||
|     mqtt_cfg_.lwt_topic = this->lwt_topic_.c_str(); |  | ||||||
|     this->mqtt_cfg_.lwt_qos = this->lwt_qos_; |  | ||||||
|     this->mqtt_cfg_.lwt_retain = this->lwt_retain_; |  | ||||||
|  |  | ||||||
|     if (!this->lwt_message_.empty()) { |  | ||||||
|       mqtt_cfg_.lwt_msg = this->lwt_message_.c_str(); |  | ||||||
|       mqtt_cfg_.lwt_msg_len = this->lwt_message_.size(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (!this->client_id_.empty()) { |  | ||||||
|     mqtt_cfg_.client_id = this->client_id_.c_str(); |  | ||||||
|   } |  | ||||||
|   if (ca_certificate_.has_value()) { |  | ||||||
|     mqtt_cfg_.cert_pem = ca_certificate_.value().c_str(); |  | ||||||
|     mqtt_cfg_.skip_cert_common_name_check = skip_cert_cn_check_; |  | ||||||
|     mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_SSL; |  | ||||||
|  |  | ||||||
|     if (this->cl_certificate_.has_value() && this->cl_key_.has_value()) { |  | ||||||
|       mqtt_cfg_.client_cert_pem = this->cl_certificate_.value().c_str(); |  | ||||||
|       mqtt_cfg_.client_key_pem = this->cl_key_.value().c_str(); |  | ||||||
|     } |  | ||||||
|   } else { |  | ||||||
|     mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_TCP; |  | ||||||
|   } |  | ||||||
| #else |  | ||||||
|   mqtt_cfg_.broker.address.hostname = this->host_.c_str(); |   mqtt_cfg_.broker.address.hostname = this->host_.c_str(); | ||||||
|   mqtt_cfg_.broker.address.port = this->port_; |   mqtt_cfg_.broker.address.port = this->port_; | ||||||
|   mqtt_cfg_.session.keepalive = this->keep_alive_; |   mqtt_cfg_.session.keepalive = this->keep_alive_; | ||||||
| @@ -95,7 +52,7 @@ bool MQTTBackendESP32::initialize_() { | |||||||
|   } else { |   } else { | ||||||
|     mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_TCP; |     mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_TCP; | ||||||
|   } |   } | ||||||
| #endif |  | ||||||
|   auto *mqtt_client = esp_mqtt_client_init(&mqtt_cfg_); |   auto *mqtt_client = esp_mqtt_client_init(&mqtt_cfg_); | ||||||
|   if (mqtt_client) { |   if (mqtt_client) { | ||||||
|     handler_.reset(mqtt_client); |     handler_.reset(mqtt_client); | ||||||
|   | |||||||
| @@ -272,18 +272,13 @@ bool OpenTherm::init_esp32_timer_() { | |||||||
|   this->timer_idx_ = timer_idx; |   this->timer_idx_ = timer_idx; | ||||||
|  |  | ||||||
|   timer_config_t const config = { |   timer_config_t const config = { | ||||||
|     .alarm_en = TIMER_ALARM_EN, |       .alarm_en = TIMER_ALARM_EN, | ||||||
|     .counter_en = TIMER_PAUSE, |       .counter_en = TIMER_PAUSE, | ||||||
|     .intr_type = TIMER_INTR_LEVEL, |       .intr_type = TIMER_INTR_LEVEL, | ||||||
|     .counter_dir = TIMER_COUNT_UP, |       .counter_dir = TIMER_COUNT_UP, | ||||||
|     .auto_reload = TIMER_AUTORELOAD_EN, |       .auto_reload = TIMER_AUTORELOAD_EN, | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |       .clk_src = TIMER_SRC_CLK_DEFAULT, | ||||||
|     .clk_src = TIMER_SRC_CLK_DEFAULT, |       .divider = 80, | ||||||
| #endif |  | ||||||
|     .divider = 80, |  | ||||||
| #if defined(SOC_TIMER_GROUP_SUPPORT_XTAL) && ESP_IDF_VERSION_MAJOR < 5 |  | ||||||
|     .clk_src = TIMER_SRC_CLK_APB |  | ||||||
| #endif |  | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   esp_err_t result; |   esp_err_t result; | ||||||
|   | |||||||
| @@ -8,10 +8,12 @@ from esphome.const import ( | |||||||
|     CONF_PLATFORM, |     CONF_PLATFORM, | ||||||
|     CONF_TRIGGER_ID, |     CONF_TRIGGER_ID, | ||||||
| ) | ) | ||||||
| from esphome.core import CORE, coroutine_with_priority | from esphome.core import coroutine_with_priority | ||||||
|  |  | ||||||
|  | from ..ota_base import OTAState | ||||||
|  |  | ||||||
| CODEOWNERS = ["@esphome/core"] | CODEOWNERS = ["@esphome/core"] | ||||||
| AUTO_LOAD = ["md5", "safe_mode"] | AUTO_LOAD = ["safe_mode", "ota_base"] | ||||||
|  |  | ||||||
| IS_PLATFORM_COMPONENT = True | IS_PLATFORM_COMPONENT = True | ||||||
|  |  | ||||||
| @@ -23,8 +25,6 @@ CONF_ON_STATE_CHANGE = "on_state_change" | |||||||
|  |  | ||||||
|  |  | ||||||
| ota_ns = cg.esphome_ns.namespace("ota") | ota_ns = cg.esphome_ns.namespace("ota") | ||||||
| OTAComponent = ota_ns.class_("OTAComponent", cg.Component) |  | ||||||
| OTAState = ota_ns.enum("OTAState") |  | ||||||
| OTAAbortTrigger = ota_ns.class_("OTAAbortTrigger", automation.Trigger.template()) | OTAAbortTrigger = ota_ns.class_("OTAAbortTrigger", automation.Trigger.template()) | ||||||
| OTAEndTrigger = ota_ns.class_("OTAEndTrigger", automation.Trigger.template()) | OTAEndTrigger = ota_ns.class_("OTAEndTrigger", automation.Trigger.template()) | ||||||
| OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template()) | OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template()) | ||||||
| @@ -84,12 +84,6 @@ BASE_OTA_SCHEMA = cv.Schema( | |||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     cg.add_define("USE_OTA") |     cg.add_define("USE_OTA") | ||||||
|  |  | ||||||
|     if CORE.is_esp32 and CORE.using_arduino: |  | ||||||
|         cg.add_library("Update", None) |  | ||||||
|  |  | ||||||
|     if CORE.is_rp2040 and CORE.using_arduino: |  | ||||||
|         cg.add_library("Updater", None) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def ota_to_code(var, config): | async def ota_to_code(var, config): | ||||||
|     await cg.past_safe_mode() |     await cg.past_safe_mode() | ||||||
|   | |||||||
| @@ -1,12 +1,16 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
| #include "ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h" | ||||||
|  |  | ||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota { | ||||||
|  |  | ||||||
|  | // Import types from ota_base for the automation triggers | ||||||
|  | using ota_base::OTAComponent; | ||||||
|  | using ota_base::OTAState; | ||||||
|  |  | ||||||
| class OTAStateChangeTrigger : public Trigger<OTAState> { | class OTAStateChangeTrigger : public Trigger<OTAState> { | ||||||
|  public: |  public: | ||||||
|   explicit OTAStateChangeTrigger(OTAComponent *parent) { |   explicit OTAStateChangeTrigger(OTAComponent *parent) { | ||||||
| @@ -22,7 +26,7 @@ class OTAStartTrigger : public Trigger<> { | |||||||
|  public: |  public: | ||||||
|   explicit OTAStartTrigger(OTAComponent *parent) { |   explicit OTAStartTrigger(OTAComponent *parent) { | ||||||
|     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { |     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { | ||||||
|       if (state == OTA_STARTED && !parent->is_failed()) { |       if (state == ota_base::OTA_STARTED && !parent->is_failed()) { | ||||||
|         trigger(); |         trigger(); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @@ -33,7 +37,7 @@ class OTAProgressTrigger : public Trigger<float> { | |||||||
|  public: |  public: | ||||||
|   explicit OTAProgressTrigger(OTAComponent *parent) { |   explicit OTAProgressTrigger(OTAComponent *parent) { | ||||||
|     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { |     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { | ||||||
|       if (state == OTA_IN_PROGRESS && !parent->is_failed()) { |       if (state == ota_base::OTA_IN_PROGRESS && !parent->is_failed()) { | ||||||
|         trigger(progress); |         trigger(progress); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @@ -44,7 +48,7 @@ class OTAEndTrigger : public Trigger<> { | |||||||
|  public: |  public: | ||||||
|   explicit OTAEndTrigger(OTAComponent *parent) { |   explicit OTAEndTrigger(OTAComponent *parent) { | ||||||
|     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { |     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { | ||||||
|       if (state == OTA_COMPLETED && !parent->is_failed()) { |       if (state == ota_base::OTA_COMPLETED && !parent->is_failed()) { | ||||||
|         trigger(); |         trigger(); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @@ -55,7 +59,7 @@ class OTAAbortTrigger : public Trigger<> { | |||||||
|  public: |  public: | ||||||
|   explicit OTAAbortTrigger(OTAComponent *parent) { |   explicit OTAAbortTrigger(OTAComponent *parent) { | ||||||
|     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { |     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { | ||||||
|       if (state == OTA_ABORT && !parent->is_failed()) { |       if (state == ota_base::OTA_ABORT && !parent->is_failed()) { | ||||||
|         trigger(); |         trigger(); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @@ -66,7 +70,7 @@ class OTAErrorTrigger : public Trigger<uint8_t> { | |||||||
|  public: |  public: | ||||||
|   explicit OTAErrorTrigger(OTAComponent *parent) { |   explicit OTAErrorTrigger(OTAComponent *parent) { | ||||||
|     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { |     parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) { | ||||||
|       if (state == OTA_ERROR && !parent->is_failed()) { |       if (state == ota_base::OTA_ERROR && !parent->is_failed()) { | ||||||
|         trigger(error); |         trigger(error); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								esphome/components/ota_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/ota_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.core import CORE, coroutine_with_priority | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@esphome/core"] | ||||||
|  | AUTO_LOAD = ["md5"] | ||||||
|  |  | ||||||
|  | ota_base_ns = cg.esphome_ns.namespace("ota_base") | ||||||
|  | OTAComponent = ota_base_ns.class_("OTAComponent", cg.Component) | ||||||
|  | OTAState = ota_base_ns.enum("OTAState") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @coroutine_with_priority(52.0) | ||||||
|  | async def to_code(config): | ||||||
|  |     # Note: USE_OTA_STATE_CALLBACK is not defined here | ||||||
|  |     # Components that need OTA callbacks (like esp32_ble_tracker, speaker, etc.) | ||||||
|  |     # define USE_OTA_STATE_CALLBACK themselves in their own __init__.py files | ||||||
|  |     # This ensures the callback functionality is only compiled when actually needed | ||||||
|  |  | ||||||
|  |     if CORE.is_esp32 and CORE.using_arduino: | ||||||
|  |         cg.add_library("Update", None) | ||||||
|  |  | ||||||
|  |     if CORE.is_rp2040 and CORE.using_arduino: | ||||||
|  |         cg.add_library("Updater", None) | ||||||
| @@ -1,7 +1,9 @@ | |||||||
| #include "ota_backend.h" | #include "ota_backend.h" | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
|  | 
 | ||||||
|  | // The make_ota_backend() implementation is provided by each platform-specific backend
 | ||||||
| 
 | 
 | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
| OTAGlobalCallback *global_ota_callback{nullptr};  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | OTAGlobalCallback *global_ota_callback{nullptr};  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | ||||||
| @@ -16,5 +18,5 @@ OTAGlobalCallback *get_global_ota_callback() { | |||||||
| void register_ota_platform(OTAComponent *ota_caller) { get_global_ota_callback()->register_ota(ota_caller); } | void register_ota_platform(OTAComponent *ota_caller) { get_global_ota_callback()->register_ota(ota_caller); } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| @@ -9,7 +9,7 @@ | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| enum OTAResponseTypes { | enum OTAResponseTypes { | ||||||
|   OTA_RESPONSE_OK = 0x00, |   OTA_RESPONSE_OK = 0x00, | ||||||
| @@ -59,15 +59,38 @@ class OTABackend { | |||||||
|   virtual bool supports_compression() = 0; |   virtual bool supports_compression() = 0; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | std::unique_ptr<OTABackend> make_ota_backend(); | ||||||
|  | 
 | ||||||
| class OTAComponent : public Component { | class OTAComponent : public Component { | ||||||
| #ifdef USE_OTA_STATE_CALLBACK | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  public: |  public: | ||||||
|   void add_on_state_callback(std::function<void(ota::OTAState, float, uint8_t)> &&callback) { |   void add_on_state_callback(std::function<void(OTAState, float, uint8_t)> &&callback) { | ||||||
|     this->state_callback_.add(std::move(callback)); |     this->state_callback_.add(std::move(callback)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  protected: |  protected: | ||||||
|   CallbackManager<void(ota::OTAState, float, uint8_t)> state_callback_{}; |   /** Extended callback manager with deferred call support.
 | ||||||
|  |    * | ||||||
|  |    * This adds a call_deferred() method for thread-safe execution from other tasks. | ||||||
|  |    */ | ||||||
|  |   class StateCallbackManager : public CallbackManager<void(OTAState, float, uint8_t)> { | ||||||
|  |    public: | ||||||
|  |     StateCallbackManager(OTAComponent *component) : component_(component) {} | ||||||
|  | 
 | ||||||
|  |     /** Call callbacks with deferral to main loop (for thread safety).
 | ||||||
|  |      * | ||||||
|  |      * This should be used by OTA implementations that run in separate tasks | ||||||
|  |      * (like web_server OTA) to ensure callbacks execute in the main loop. | ||||||
|  |      */ | ||||||
|  |     void call_deferred(OTAState state, float progress, uint8_t error) { | ||||||
|  |       component_->defer([this, state, progress, error]() { this->call(state, progress, error); }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |    private: | ||||||
|  |     OTAComponent *component_; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   StateCallbackManager state_callback_{this}; | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @@ -89,8 +112,12 @@ class OTAGlobalCallback { | |||||||
| 
 | 
 | ||||||
| OTAGlobalCallback *get_global_ota_callback(); | OTAGlobalCallback *get_global_ota_callback(); | ||||||
| void register_ota_platform(OTAComponent *ota_caller); | void register_ota_platform(OTAComponent *ota_caller); | ||||||
| #endif |  | ||||||
| std::unique_ptr<ota::OTABackend> make_ota_backend(); |  | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | // OTA implementations should use:
 | ||||||
|  | // - state_callback_.call() when already in main loop (e.g., esphome OTA)
 | ||||||
|  | // - state_callback_.call_deferred() when in separate task (e.g., web_server OTA)
 | ||||||
|  | // This ensures proper callback execution in all contexts.
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| @@ -8,13 +8,18 @@ | |||||||
| #include <Update.h> | #include <Update.h> | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| static const char *const TAG = "ota.arduino_esp32"; | static const char *const TAG = "ota.arduino_esp32"; | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP32OTABackend>(); } | std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoESP32OTABackend>(); } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { | OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { | ||||||
|  |   // Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA
 | ||||||
|  |   // where the exact firmware size is unknown due to multipart encoding
 | ||||||
|  |   if (image_size == 0) { | ||||||
|  |     image_size = UPDATE_SIZE_UNKNOWN; | ||||||
|  |   } | ||||||
|   bool ret = Update.begin(image_size, U_FLASH); |   bool ret = Update.begin(image_size, U_FLASH); | ||||||
|   if (ret) { |   if (ret) { | ||||||
|     return OTA_RESPONSE_OK; |     return OTA_RESPONSE_OK; | ||||||
| @@ -29,7 +34,10 @@ OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { | |||||||
|   return OTA_RESPONSE_ERROR_UNKNOWN; |   return OTA_RESPONSE_ERROR_UNKNOWN; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } | void ArduinoESP32OTABackend::set_update_md5(const char *md5) { | ||||||
|  |   Update.setMD5(md5); | ||||||
|  |   this->md5_set_ = true; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { | OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { | ||||||
|   size_t written = Update.write(data, len); |   size_t written = Update.write(data, len); | ||||||
| @@ -44,7 +52,9 @@ OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoESP32OTABackend::end() { | OTAResponseTypes ArduinoESP32OTABackend::end() { | ||||||
|   if (Update.end()) { |   // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
 | ||||||
|  |   // This matches the behavior of the old web_server OTA implementation
 | ||||||
|  |   if (Update.end(!this->md5_set_)) { | ||||||
|     return OTA_RESPONSE_OK; |     return OTA_RESPONSE_OK; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @@ -56,7 +66,7 @@ OTAResponseTypes ArduinoESP32OTABackend::end() { | |||||||
| 
 | 
 | ||||||
| void ArduinoESP32OTABackend::abort() { Update.abort(); } | void ArduinoESP32OTABackend::abort() { Update.abort(); } | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif  // USE_ESP32_FRAMEWORK_ARDUINO
 | #endif  // USE_ESP32_FRAMEWORK_ARDUINO
 | ||||||
| @@ -6,7 +6,7 @@ | |||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| class ArduinoESP32OTABackend : public OTABackend { | class ArduinoESP32OTABackend : public OTABackend { | ||||||
|  public: |  public: | ||||||
| @@ -16,9 +16,12 @@ class ArduinoESP32OTABackend : public OTABackend { | |||||||
|   OTAResponseTypes end() override; |   OTAResponseTypes end() override; | ||||||
|   void abort() override; |   void abort() override; | ||||||
|   bool supports_compression() override { return false; } |   bool supports_compression() override { return false; } | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   bool md5_set_{false}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif  // USE_ESP32_FRAMEWORK_ARDUINO
 | #endif  // USE_ESP32_FRAMEWORK_ARDUINO
 | ||||||
| @@ -10,13 +10,18 @@ | |||||||
| #include <Updater.h> | #include <Updater.h> | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| static const char *const TAG = "ota.arduino_esp8266"; | static const char *const TAG = "ota.arduino_esp8266"; | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP8266OTABackend>(); } | std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoESP8266OTABackend>(); } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { | OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { | ||||||
|  |   // Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space
 | ||||||
|  |   if (image_size == 0) { | ||||||
|  |     // NOLINTNEXTLINE(readability-static-accessed-through-instance)
 | ||||||
|  |     image_size = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; | ||||||
|  |   } | ||||||
|   bool ret = Update.begin(image_size, U_FLASH); |   bool ret = Update.begin(image_size, U_FLASH); | ||||||
|   if (ret) { |   if (ret) { | ||||||
|     esp8266::preferences_prevent_write(true); |     esp8266::preferences_prevent_write(true); | ||||||
| @@ -38,7 +43,10 @@ OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { | |||||||
|   return OTA_RESPONSE_ERROR_UNKNOWN; |   return OTA_RESPONSE_ERROR_UNKNOWN; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } | void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { | ||||||
|  |   Update.setMD5(md5); | ||||||
|  |   this->md5_set_ = true; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { | OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { | ||||||
|   size_t written = Update.write(data, len); |   size_t written = Update.write(data, len); | ||||||
| @@ -53,13 +61,19 @@ OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoESP8266OTABackend::end() { | OTAResponseTypes ArduinoESP8266OTABackend::end() { | ||||||
|   if (Update.end()) { |   // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
 | ||||||
|  |   // This matches the behavior of the old web_server OTA implementation
 | ||||||
|  |   bool success = Update.end(!this->md5_set_); | ||||||
|  | 
 | ||||||
|  |   // On ESP8266, Update.end() might return false even with error code 0
 | ||||||
|  |   // Check the actual error code to determine success
 | ||||||
|  |   uint8_t error = Update.getError(); | ||||||
|  | 
 | ||||||
|  |   if (success || error == UPDATE_ERROR_OK) { | ||||||
|     return OTA_RESPONSE_OK; |     return OTA_RESPONSE_OK; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   uint8_t error = Update.getError(); |  | ||||||
|   ESP_LOGE(TAG, "End error: %d", error); |   ESP_LOGE(TAG, "End error: %d", error); | ||||||
| 
 |  | ||||||
|   return OTA_RESPONSE_ERROR_UPDATE_END; |   return OTA_RESPONSE_ERROR_UPDATE_END; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -68,7 +82,7 @@ void ArduinoESP8266OTABackend::abort() { | |||||||
|   esp8266::preferences_prevent_write(false); |   esp8266::preferences_prevent_write(false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
| @@ -7,7 +7,7 @@ | |||||||
| #include "esphome/core/macros.h" | #include "esphome/core/macros.h" | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| class ArduinoESP8266OTABackend : public OTABackend { | class ArduinoESP8266OTABackend : public OTABackend { | ||||||
|  public: |  public: | ||||||
| @@ -21,9 +21,12 @@ class ArduinoESP8266OTABackend : public OTABackend { | |||||||
| #else | #else | ||||||
|   bool supports_compression() override { return false; } |   bool supports_compression() override { return false; } | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   bool md5_set_{false}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
| @@ -8,13 +8,18 @@ | |||||||
| #include <Update.h> | #include <Update.h> | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| static const char *const TAG = "ota.arduino_libretiny"; | static const char *const TAG = "ota.arduino_libretiny"; | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoLibreTinyOTABackend>(); } | std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoLibreTinyOTABackend>(); } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { | OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { | ||||||
|  |   // Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA
 | ||||||
|  |   // where the exact firmware size is unknown due to multipart encoding
 | ||||||
|  |   if (image_size == 0) { | ||||||
|  |     image_size = UPDATE_SIZE_UNKNOWN; | ||||||
|  |   } | ||||||
|   bool ret = Update.begin(image_size, U_FLASH); |   bool ret = Update.begin(image_size, U_FLASH); | ||||||
|   if (ret) { |   if (ret) { | ||||||
|     return OTA_RESPONSE_OK; |     return OTA_RESPONSE_OK; | ||||||
| @@ -29,7 +34,10 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { | |||||||
|   return OTA_RESPONSE_ERROR_UNKNOWN; |   return OTA_RESPONSE_ERROR_UNKNOWN; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } | void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { | ||||||
|  |   Update.setMD5(md5); | ||||||
|  |   this->md5_set_ = true; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { | OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { | ||||||
|   size_t written = Update.write(data, len); |   size_t written = Update.write(data, len); | ||||||
| @@ -44,7 +52,9 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoLibreTinyOTABackend::end() { | OTAResponseTypes ArduinoLibreTinyOTABackend::end() { | ||||||
|   if (Update.end()) { |   // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
 | ||||||
|  |   // This matches the behavior of the old web_server OTA implementation
 | ||||||
|  |   if (Update.end(!this->md5_set_)) { | ||||||
|     return OTA_RESPONSE_OK; |     return OTA_RESPONSE_OK; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @@ -56,7 +66,7 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::end() { | |||||||
| 
 | 
 | ||||||
| void ArduinoLibreTinyOTABackend::abort() { Update.abort(); } | void ArduinoLibreTinyOTABackend::abort() { Update.abort(); } | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif  // USE_LIBRETINY
 | #endif  // USE_LIBRETINY
 | ||||||
| @@ -5,7 +5,7 @@ | |||||||
| #include "esphome/core/defines.h" | #include "esphome/core/defines.h" | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| class ArduinoLibreTinyOTABackend : public OTABackend { | class ArduinoLibreTinyOTABackend : public OTABackend { | ||||||
|  public: |  public: | ||||||
| @@ -15,9 +15,12 @@ class ArduinoLibreTinyOTABackend : public OTABackend { | |||||||
|   OTAResponseTypes end() override; |   OTAResponseTypes end() override; | ||||||
|   void abort() override; |   void abort() override; | ||||||
|   bool supports_compression() override { return false; } |   bool supports_compression() override { return false; } | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   bool md5_set_{false}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif  // USE_LIBRETINY
 | #endif  // USE_LIBRETINY
 | ||||||
| @@ -10,13 +10,24 @@ | |||||||
| #include <Updater.h> | #include <Updater.h> | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| static const char *const TAG = "ota.arduino_rp2040"; | static const char *const TAG = "ota.arduino_rp2040"; | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoRP2040OTABackend>(); } | std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoRP2040OTABackend>(); } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { | OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { | ||||||
|  |   // Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space
 | ||||||
|  |   if (image_size == 0) { | ||||||
|  |     // Similar to ESP8266, calculate available space from flash layout
 | ||||||
|  |     extern uint8_t _FS_start; | ||||||
|  |     extern uint8_t _FS_end; | ||||||
|  |     // Calculate the size of the filesystem area which will be used for OTA
 | ||||||
|  |     size_t fs_size = &_FS_end - &_FS_start; | ||||||
|  |     // Reserve some space for filesystem overhead
 | ||||||
|  |     image_size = (fs_size - 0x1000) & 0xFFFFF000; | ||||||
|  |     ESP_LOGD(TAG, "OTA size unknown, using filesystem size: %u bytes", image_size); | ||||||
|  |   } | ||||||
|   bool ret = Update.begin(image_size, U_FLASH); |   bool ret = Update.begin(image_size, U_FLASH); | ||||||
|   if (ret) { |   if (ret) { | ||||||
|     rp2040::preferences_prevent_write(true); |     rp2040::preferences_prevent_write(true); | ||||||
| @@ -38,7 +49,10 @@ OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { | |||||||
|   return OTA_RESPONSE_ERROR_UNKNOWN; |   return OTA_RESPONSE_ERROR_UNKNOWN; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } | void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { | ||||||
|  |   Update.setMD5(md5); | ||||||
|  |   this->md5_set_ = true; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) { | OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) { | ||||||
|   size_t written = Update.write(data, len); |   size_t written = Update.write(data, len); | ||||||
| @@ -53,7 +67,9 @@ OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes ArduinoRP2040OTABackend::end() { | OTAResponseTypes ArduinoRP2040OTABackend::end() { | ||||||
|   if (Update.end()) { |   // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
 | ||||||
|  |   // This matches the behavior of the old web_server OTA implementation
 | ||||||
|  |   if (Update.end(!this->md5_set_)) { | ||||||
|     return OTA_RESPONSE_OK; |     return OTA_RESPONSE_OK; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @@ -68,7 +84,7 @@ void ArduinoRP2040OTABackend::abort() { | |||||||
|   rp2040::preferences_prevent_write(false); |   rp2040::preferences_prevent_write(false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif  // USE_RP2040
 | #endif  // USE_RP2040
 | ||||||
| @@ -7,7 +7,7 @@ | |||||||
| #include "esphome/core/macros.h" | #include "esphome/core/macros.h" | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| class ArduinoRP2040OTABackend : public OTABackend { | class ArduinoRP2040OTABackend : public OTABackend { | ||||||
|  public: |  public: | ||||||
| @@ -17,9 +17,12 @@ class ArduinoRP2040OTABackend : public OTABackend { | |||||||
|   OTAResponseTypes end() override; |   OTAResponseTypes end() override; | ||||||
|   void abort() override; |   void abort() override; | ||||||
|   bool supports_compression() override { return false; } |   bool supports_compression() override { return false; } | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   bool md5_set_{false}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif  // USE_RP2040
 | #endif  // USE_RP2040
 | ||||||
| @@ -6,15 +6,12 @@ | |||||||
| 
 | 
 | ||||||
| #include <esp_ota_ops.h> | #include <esp_ota_ops.h> | ||||||
| #include <esp_task_wdt.h> | #include <esp_task_wdt.h> | ||||||
| 
 |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| #include <spi_flash_mmap.h> | #include <spi_flash_mmap.h> | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::IDFOTABackend>(); } | std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<IDFOTABackend>(); } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes IDFOTABackend::begin(size_t image_size) { | OTAResponseTypes IDFOTABackend::begin(size_t image_size) { | ||||||
|   this->partition_ = esp_ota_get_next_update_partition(nullptr); |   this->partition_ = esp_ota_get_next_update_partition(nullptr); | ||||||
| @@ -24,7 +21,6 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { | |||||||
| 
 | 
 | ||||||
| #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 | #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 | ||||||
|   // The following function takes longer than the 5 seconds timeout of WDT
 |   // The following function takes longer than the 5 seconds timeout of WDT
 | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   esp_task_wdt_config_t wdtc; |   esp_task_wdt_config_t wdtc; | ||||||
|   wdtc.idle_core_mask = 0; |   wdtc.idle_core_mask = 0; | ||||||
| #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 | #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 | ||||||
| @@ -36,21 +32,14 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { | |||||||
|   wdtc.timeout_ms = 15000; |   wdtc.timeout_ms = 15000; | ||||||
|   wdtc.trigger_panic = false; |   wdtc.trigger_panic = false; | ||||||
|   esp_task_wdt_reconfigure(&wdtc); |   esp_task_wdt_reconfigure(&wdtc); | ||||||
| #else |  | ||||||
|   esp_task_wdt_init(15, false); |  | ||||||
| #endif |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|   esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_); |   esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_); | ||||||
| 
 | 
 | ||||||
| #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 | #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 | ||||||
|   // Set the WDT back to the configured timeout
 |   // Set the WDT back to the configured timeout
 | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; |   wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; | ||||||
|   esp_task_wdt_reconfigure(&wdtc); |   esp_task_wdt_reconfigure(&wdtc); | ||||||
| #else |  | ||||||
|   esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); |  | ||||||
| #endif |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|   if (err != ESP_OK) { |   if (err != ESP_OK) { | ||||||
| @@ -67,7 +56,10 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { | |||||||
|   return OTA_RESPONSE_OK; |   return OTA_RESPONSE_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void IDFOTABackend::set_update_md5(const char *expected_md5) { memcpy(this->expected_bin_md5_, expected_md5, 32); } | void IDFOTABackend::set_update_md5(const char *expected_md5) { | ||||||
|  |   memcpy(this->expected_bin_md5_, expected_md5, 32); | ||||||
|  |   this->md5_set_ = true; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) { | OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) { | ||||||
|   esp_err_t err = esp_ota_write(this->update_handle_, data, len); |   esp_err_t err = esp_ota_write(this->update_handle_, data, len); | ||||||
| @@ -84,10 +76,12 @@ OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| OTAResponseTypes IDFOTABackend::end() { | OTAResponseTypes IDFOTABackend::end() { | ||||||
|   this->md5_.calculate(); |   if (this->md5_set_) { | ||||||
|   if (!this->md5_.equals_hex(this->expected_bin_md5_)) { |     this->md5_.calculate(); | ||||||
|     this->abort(); |     if (!this->md5_.equals_hex(this->expected_bin_md5_)) { | ||||||
|     return OTA_RESPONSE_ERROR_MD5_MISMATCH; |       this->abort(); | ||||||
|  |       return OTA_RESPONSE_ERROR_MD5_MISMATCH; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   esp_err_t err = esp_ota_end(this->update_handle_); |   esp_err_t err = esp_ota_end(this->update_handle_); | ||||||
|   this->update_handle_ = 0; |   this->update_handle_ = 0; | ||||||
| @@ -111,6 +105,6 @@ void IDFOTABackend::abort() { | |||||||
|   this->update_handle_ = 0; |   this->update_handle_ = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| #endif | #endif | ||||||
| @@ -8,7 +8,7 @@ | |||||||
| #include <esp_ota_ops.h> | #include <esp_ota_ops.h> | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ota { | namespace ota_base { | ||||||
| 
 | 
 | ||||||
| class IDFOTABackend : public OTABackend { | class IDFOTABackend : public OTABackend { | ||||||
|  public: |  public: | ||||||
| @@ -24,8 +24,9 @@ class IDFOTABackend : public OTABackend { | |||||||
|   const esp_partition_t *partition_; |   const esp_partition_t *partition_; | ||||||
|   md5::MD5Digest md5_{}; |   md5::MD5Digest md5_{}; | ||||||
|   char expected_bin_md5_[32]; |   char expected_bin_md5_[32]; | ||||||
|  |   bool md5_set_{false}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace ota
 | }  // namespace ota_base
 | ||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| #endif | #endif | ||||||
| @@ -2,9 +2,7 @@ | |||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| #include "psram.h" | #include "psram.h" | ||||||
| #include <esp_idf_version.h> | #include <esp_idf_version.h> | ||||||
| #if defined(USE_ESP_IDF) && ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
| #include <esp_psram.h> | #include <esp_psram.h> | ||||||
| #endif  // USE_ESP_IDF |  | ||||||
|  |  | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
| @@ -16,7 +14,6 @@ static const char *const TAG = "psram"; | |||||||
|  |  | ||||||
| void PsramComponent::dump_config() { | void PsramComponent::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "PSRAM:"); |   ESP_LOGCONFIG(TAG, "PSRAM:"); | ||||||
| #if defined(USE_ESP_IDF) && ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   bool available = esp_psram_is_initialized(); |   bool available = esp_psram_is_initialized(); | ||||||
|  |  | ||||||
|   ESP_LOGCONFIG(TAG, "  Available: %s", YESNO(available)); |   ESP_LOGCONFIG(TAG, "  Available: %s", YESNO(available)); | ||||||
| @@ -26,23 +23,6 @@ void PsramComponent::dump_config() { | |||||||
|     ESP_LOGCONFIG(TAG, "  ECC enabled: YES"); |     ESP_LOGCONFIG(TAG, "  ECC enabled: YES"); | ||||||
| #endif | #endif | ||||||
|   } |   } | ||||||
| #else |  | ||||||
|   // Technically this can be false if the PSRAM is full, but heap_caps_get_total_size() isn't always available, and it's |  | ||||||
|   // very unlikely for the PSRAM to be full. |  | ||||||
|   bool available = heap_caps_get_free_size(MALLOC_CAP_SPIRAM) > 0; |  | ||||||
|   ESP_LOGCONFIG(TAG, "  Available: %s", YESNO(available)); |  | ||||||
|  |  | ||||||
|   if (available) { |  | ||||||
|     const size_t psram_total_size_bytes = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); |  | ||||||
|     const float psram_total_size_kb = psram_total_size_bytes / 1024.0f; |  | ||||||
|  |  | ||||||
|     if (abs(std::round(psram_total_size_kb) - psram_total_size_kb) < 0.05f) { |  | ||||||
|       ESP_LOGCONFIG(TAG, "  Size: %.0f KB", psram_total_size_kb); |  | ||||||
|     } else { |  | ||||||
|       ESP_LOGCONFIG(TAG, "  Size: %zu bytes", psram_total_size_bytes); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| #endif  // USE_ESP_IDF |  | ||||||
| } | } | ||||||
|  |  | ||||||
| }  // namespace psram | }  // namespace psram | ||||||
|   | |||||||
| @@ -146,11 +146,7 @@ void PVVXDisplay::sync_time_() { | |||||||
|   } |   } | ||||||
|   time.recalc_timestamp_utc(true);  // calculate timestamp of local time |   time.recalc_timestamp_utc(true);  // calculate timestamp of local time | ||||||
|   uint8_t blk[5] = {}; |   uint8_t blk[5] = {}; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   ESP_LOGD(TAG, "[%s] Sync time with timestamp %" PRIu64 ".", this->parent_->address_str().c_str(), time.timestamp); |   ESP_LOGD(TAG, "[%s] Sync time with timestamp %" PRIu64 ".", this->parent_->address_str().c_str(), time.timestamp); | ||||||
| #else |  | ||||||
|   ESP_LOGD(TAG, "[%s] Sync time with timestamp %lu.", this->parent_->address_str().c_str(), time.timestamp); |  | ||||||
| #endif |  | ||||||
|   blk[0] = 0x23; |   blk[0] = 0x23; | ||||||
|   blk[1] = time.timestamp & 0xff; |   blk[1] = time.timestamp & 0xff; | ||||||
|   blk[2] = (time.timestamp >> 8) & 0xff; |   blk[2] = (time.timestamp >> 8) & 0xff; | ||||||
|   | |||||||
| @@ -10,10 +10,8 @@ void RpiDpiRgb::setup() { | |||||||
|   this->reset_display_(); |   this->reset_display_(); | ||||||
|   esp_lcd_rgb_panel_config_t config{}; |   esp_lcd_rgb_panel_config_t config{}; | ||||||
|   config.flags.fb_in_psram = 1; |   config.flags.fb_in_psram = 1; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   config.bounce_buffer_size_px = this->width_ * 10; |   config.bounce_buffer_size_px = this->width_ * 10; | ||||||
|   config.num_fbs = 1; |   config.num_fbs = 1; | ||||||
| #endif  // ESP_IDF_VERSION_MAJOR |  | ||||||
|   config.timings.h_res = this->width_; |   config.timings.h_res = this->width_; | ||||||
|   config.timings.v_res = this->height_; |   config.timings.v_res = this->height_; | ||||||
|   config.timings.hsync_pulse_width = this->hsync_pulse_width_; |   config.timings.hsync_pulse_width = this->hsync_pulse_width_; | ||||||
| @@ -47,10 +45,8 @@ void RpiDpiRgb::setup() { | |||||||
|   ESP_LOGCONFIG(TAG, "RPI_DPI_RGB setup complete"); |   ESP_LOGCONFIG(TAG, "RPI_DPI_RGB setup complete"); | ||||||
| } | } | ||||||
| void RpiDpiRgb::loop() { | void RpiDpiRgb::loop() { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   if (this->handle_ != nullptr) |   if (this->handle_ != nullptr) | ||||||
|     esp_lcd_rgb_panel_restart(this->handle_); |     esp_lcd_rgb_panel_restart(this->handle_); | ||||||
| #endif  // ESP_IDF_VERSION_MAJOR |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, | void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/components/audio/audio.h" | #include "esphome/components/audio/audio.h" | ||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
| #include "esphome/components/ota/ota_backend.h" | #include "esphome/components/ota_base/ota_backend.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| @@ -67,16 +67,16 @@ void SpeakerMediaPlayer::setup() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
| #ifdef USE_OTA | #ifdef USE_OTA | ||||||
|   ota::get_global_ota_callback()->add_on_state_callback( |   ota_base::get_global_ota_callback()->add_on_state_callback( | ||||||
|       [this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) { |       [this](ota_base::OTAState state, float progress, uint8_t error, ota_base::OTAComponent *comp) { | ||||||
|         if (state == ota::OTA_STARTED) { |         if (state == ota_base::OTA_STARTED) { | ||||||
|           if (this->media_pipeline_ != nullptr) { |           if (this->media_pipeline_ != nullptr) { | ||||||
|             this->media_pipeline_->suspend_tasks(); |             this->media_pipeline_->suspend_tasks(); | ||||||
|           } |           } | ||||||
|           if (this->announcement_pipeline_ != nullptr) { |           if (this->announcement_pipeline_ != nullptr) { | ||||||
|             this->announcement_pipeline_->suspend_tasks(); |             this->announcement_pipeline_->suspend_tasks(); | ||||||
|           } |           } | ||||||
|         } else if (state == ota::OTA_ERROR) { |         } else if (state == ota_base::OTA_ERROR) { | ||||||
|           if (this->media_pipeline_ != nullptr) { |           if (this->media_pipeline_ != nullptr) { | ||||||
|             this->media_pipeline_->resume_tasks(); |             this->media_pipeline_->resume_tasks(); | ||||||
|           } |           } | ||||||
|   | |||||||
| @@ -12,10 +12,8 @@ void ST7701S::setup() { | |||||||
|  |  | ||||||
|   esp_lcd_rgb_panel_config_t config{}; |   esp_lcd_rgb_panel_config_t config{}; | ||||||
|   config.flags.fb_in_psram = 1; |   config.flags.fb_in_psram = 1; | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   config.bounce_buffer_size_px = this->width_ * 10; |   config.bounce_buffer_size_px = this->width_ * 10; | ||||||
|   config.num_fbs = 1; |   config.num_fbs = 1; | ||||||
| #endif  // ESP_IDF_VERSION_MAJOR |  | ||||||
|   config.timings.h_res = this->width_; |   config.timings.h_res = this->width_; | ||||||
|   config.timings.v_res = this->height_; |   config.timings.v_res = this->height_; | ||||||
|   config.timings.hsync_pulse_width = this->hsync_pulse_width_; |   config.timings.hsync_pulse_width = this->hsync_pulse_width_; | ||||||
| @@ -48,10 +46,8 @@ void ST7701S::setup() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void ST7701S::loop() { | void ST7701S::loop() { | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   if (this->handle_ != nullptr) |   if (this->handle_ != nullptr) | ||||||
|     esp_lcd_rgb_panel_restart(this->handle_); |     esp_lcd_rgb_panel_restart(this->handle_); | ||||||
| #endif  // ESP_IDF_VERSION_MAJOR |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void ST7701S::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, | void ST7701S::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, | ||||||
|   | |||||||
| @@ -48,11 +48,7 @@ uart_config_t IDFUARTComponent::get_config_() { | |||||||
|   uart_config.parity = parity; |   uart_config.parity = parity; | ||||||
|   uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2; |   uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2; | ||||||
|   uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; |   uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; | ||||||
| #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) |  | ||||||
|   uart_config.source_clk = UART_SCLK_DEFAULT; |   uart_config.source_clk = UART_SCLK_DEFAULT; | ||||||
| #else |  | ||||||
|   uart_config.source_clk = UART_SCLK_APB; |  | ||||||
| #endif |  | ||||||
|   uart_config.rx_flow_ctrl_thresh = 122; |   uart_config.rx_flow_ctrl_thresh = 122; | ||||||
|  |  | ||||||
|   return uart_config; |   return uart_config; | ||||||
|   | |||||||
| @@ -38,16 +38,12 @@ WatchdogManager::~WatchdogManager() { | |||||||
| void WatchdogManager::set_timeout_(uint32_t timeout_ms) { | void WatchdogManager::set_timeout_(uint32_t timeout_ms) { | ||||||
|   ESP_LOGV(TAG, "Adjusting WDT to %" PRIu32 "ms", timeout_ms); |   ESP_LOGV(TAG, "Adjusting WDT to %" PRIu32 "ms", timeout_ms); | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|   esp_task_wdt_config_t wdt_config = { |   esp_task_wdt_config_t wdt_config = { | ||||||
|       .timeout_ms = timeout_ms, |       .timeout_ms = timeout_ms, | ||||||
|       .idle_core_mask = (1 << SOC_CPU_CORES_NUM) - 1, |       .idle_core_mask = (1 << SOC_CPU_CORES_NUM) - 1, | ||||||
|       .trigger_panic = true, |       .trigger_panic = true, | ||||||
|   }; |   }; | ||||||
|   esp_task_wdt_reconfigure(&wdt_config); |   esp_task_wdt_reconfigure(&wdt_config); | ||||||
| #else |  | ||||||
|   esp_task_wdt_init(timeout_ms / 1000, true); |  | ||||||
| #endif  // ESP_IDF_VERSION_MAJOR |  | ||||||
| #endif  // USE_ESP32 | #endif  // USE_ESP32 | ||||||
|  |  | ||||||
| #ifdef USE_RP2040 | #ifdef USE_RP2040 | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ from esphome.const import ( | |||||||
| from esphome.core import CORE, coroutine_with_priority | from esphome.core import CORE, coroutine_with_priority | ||||||
| import esphome.final_validate as fv | import esphome.final_validate as fv | ||||||
|  |  | ||||||
| AUTO_LOAD = ["json", "web_server_base"] | AUTO_LOAD = ["json", "web_server_base", "ota_base"] | ||||||
|  |  | ||||||
| CONF_SORTING_GROUP_ID = "sorting_group_id" | CONF_SORTING_GROUP_ID = "sorting_group_id" | ||||||
| CONF_SORTING_GROUPS = "sorting_groups" | CONF_SORTING_GROUPS = "sorting_groups" | ||||||
| @@ -274,7 +274,7 @@ async def to_code(config): | |||||||
|     cg.add(var.set_allow_ota(config[CONF_OTA])) |     cg.add(var.set_allow_ota(config[CONF_OTA])) | ||||||
|     if config[CONF_OTA]: |     if config[CONF_OTA]: | ||||||
|         # Define USE_WEBSERVER_OTA based only on web_server OTA config |         # Define USE_WEBSERVER_OTA based only on web_server OTA config | ||||||
|         # This allows web server OTA to work without loading the OTA component |         # Web server OTA now uses ota_base backend for consistency | ||||||
|         cg.add_define("USE_WEBSERVER_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]: | ||||||
|   | |||||||
| @@ -4,19 +4,16 @@ | |||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO | #ifdef USE_WEBSERVER_OTA | ||||||
| #include <StreamString.h> | #include "esphome/components/ota_base/ota_backend.h" | ||||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) |  | ||||||
| #include <Update.h> |  | ||||||
| #endif |  | ||||||
| #ifdef USE_ESP8266 |  | ||||||
| #include <Updater.h> |  | ||||||
| #endif |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) | #ifdef USE_ARDUINO | ||||||
| #include <esp_ota_ops.h> | #ifdef USE_ESP8266 | ||||||
| #include <esp_task_wdt.h> | #include <Updater.h> | ||||||
|  | #elif defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||||
|  | #include <Update.h> | ||||||
|  | #endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| @@ -24,104 +21,6 @@ namespace web_server_base { | |||||||
|  |  | ||||||
| static const char *const TAG = "web_server_base"; | static const char *const TAG = "web_server_base"; | ||||||
|  |  | ||||||
| #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) |  | ||||||
| // Minimal OTA backend implementation for web server |  | ||||||
| // This allows OTA updates via web server without requiring the OTA component |  | ||||||
| // TODO: In the future, this should be refactored into a common ota_base component |  | ||||||
| // that both web_server and ota components can depend on, avoiding code duplication |  | ||||||
| // while keeping the components independent. This would allow both ESP-IDF and Arduino |  | ||||||
| // implementations to share the base OTA functionality without requiring the full OTA component. |  | ||||||
| // The IDFWebServerOTABackend class is intentionally designed with the same interface |  | ||||||
| // as OTABackend to make it easy to swap to using OTABackend when the ota component |  | ||||||
| // is split into ota and ota_base in the future. |  | ||||||
| class IDFWebServerOTABackend { |  | ||||||
|  public: |  | ||||||
|   bool begin() { |  | ||||||
|     this->partition_ = esp_ota_get_next_update_partition(nullptr); |  | ||||||
|     if (this->partition_ == nullptr) { |  | ||||||
|       ESP_LOGE(TAG, "No OTA partition available"); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 |  | ||||||
|     // The following function takes longer than the default timeout of WDT due to flash erase |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|     esp_task_wdt_config_t wdtc; |  | ||||||
|     wdtc.idle_core_mask = 0; |  | ||||||
| #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 |  | ||||||
|     wdtc.idle_core_mask |= (1 << 0); |  | ||||||
| #endif |  | ||||||
| #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 |  | ||||||
|     wdtc.idle_core_mask |= (1 << 1); |  | ||||||
| #endif |  | ||||||
|     wdtc.timeout_ms = 15000; |  | ||||||
|     wdtc.trigger_panic = false; |  | ||||||
|     esp_task_wdt_reconfigure(&wdtc); |  | ||||||
| #else |  | ||||||
|     esp_task_wdt_init(15, false); |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     esp_err_t err = esp_ota_begin(this->partition_, 0, &this->update_handle_); |  | ||||||
|  |  | ||||||
| #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15 |  | ||||||
|     // Set the WDT back to the configured timeout |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 5 |  | ||||||
|     wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000; |  | ||||||
|     esp_task_wdt_reconfigure(&wdtc); |  | ||||||
| #else |  | ||||||
|     esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     if (err != ESP_OK) { |  | ||||||
|       esp_ota_abort(this->update_handle_); |  | ||||||
|       this->update_handle_ = 0; |  | ||||||
|       ESP_LOGE(TAG, "esp_ota_begin failed: %s", esp_err_to_name(err)); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   bool write(uint8_t *data, size_t len) { |  | ||||||
|     esp_err_t err = esp_ota_write(this->update_handle_, data, len); |  | ||||||
|     if (err != ESP_OK) { |  | ||||||
|       ESP_LOGE(TAG, "esp_ota_write failed: %s", esp_err_to_name(err)); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   bool end() { |  | ||||||
|     esp_err_t err = esp_ota_end(this->update_handle_); |  | ||||||
|     this->update_handle_ = 0; |  | ||||||
|     if (err != ESP_OK) { |  | ||||||
|       ESP_LOGE(TAG, "esp_ota_end failed: %s", esp_err_to_name(err)); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     err = esp_ota_set_boot_partition(this->partition_); |  | ||||||
|     if (err != ESP_OK) { |  | ||||||
|       ESP_LOGE(TAG, "esp_ota_set_boot_partition failed: %s", esp_err_to_name(err)); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void abort() { |  | ||||||
|     if (this->update_handle_ != 0) { |  | ||||||
|       esp_ota_abort(this->update_handle_); |  | ||||||
|       this->update_handle_ = 0; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  private: |  | ||||||
|   esp_ota_handle_t update_handle_{0}; |  | ||||||
|   const esp_partition_t *partition_{nullptr}; |  | ||||||
| }; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| void WebServerBase::add_handler(AsyncWebHandler *handler) { | void WebServerBase::add_handler(AsyncWebHandler *handler) { | ||||||
|   // remove all handlers |   // remove all handlers | ||||||
|  |  | ||||||
| @@ -138,12 +37,21 @@ void WebServerBase::add_handler(AsyncWebHandler *handler) { | |||||||
| void OTARequestHandler::report_ota_progress_(AsyncWebServerRequest *request) { | void OTARequestHandler::report_ota_progress_(AsyncWebServerRequest *request) { | ||||||
|   const uint32_t now = millis(); |   const uint32_t now = millis(); | ||||||
|   if (now - this->last_ota_progress_ > 1000) { |   if (now - this->last_ota_progress_ > 1000) { | ||||||
|  |     float percentage = 0.0f; | ||||||
|     if (request->contentLength() != 0) { |     if (request->contentLength() != 0) { | ||||||
|       float percentage = (this->ota_read_length_ * 100.0f) / request->contentLength(); |       // Note: Using contentLength() for progress calculation is technically wrong as it includes | ||||||
|  |       // multipart headers/boundaries, but it's only off by a small amount and we don't have | ||||||
|  |       // access to the actual firmware size until the upload is complete. This is intentional | ||||||
|  |       // as it still gives the user a reasonable progress indication. | ||||||
|  |       percentage = (this->ota_read_length_ * 100.0f) / request->contentLength(); | ||||||
|       ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage); |       ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage); | ||||||
|     } else { |     } else { | ||||||
|       ESP_LOGD(TAG, "OTA in progress: %u bytes read", this->ota_read_length_); |       ESP_LOGD(TAG, "OTA in progress: %u bytes read", this->ota_read_length_); | ||||||
|     } |     } | ||||||
|  | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  |     // Report progress - use call_deferred since we're in web server task | ||||||
|  |     this->parent_->state_callback_.call_deferred(ota_base::OTA_IN_PROGRESS, percentage, 0); | ||||||
|  | #endif | ||||||
|     this->last_ota_progress_ = now; |     this->last_ota_progress_ = now; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -159,87 +67,72 @@ void OTARequestHandler::schedule_ota_reboot_() { | |||||||
| void OTARequestHandler::ota_init_(const char *filename) { | void OTARequestHandler::ota_init_(const char *filename) { | ||||||
|   ESP_LOGI(TAG, "OTA Update Start: %s", filename); |   ESP_LOGI(TAG, "OTA Update Start: %s", filename); | ||||||
|   this->ota_read_length_ = 0; |   this->ota_read_length_ = 0; | ||||||
| } |   this->ota_success_ = false; | ||||||
|  |  | ||||||
| void report_ota_error() { |  | ||||||
| #ifdef USE_ARDUINO |  | ||||||
|   StreamString ss; |  | ||||||
|   Update.printError(ss); |  | ||||||
|   ESP_LOGW(TAG, "OTA Update failed! Error: %s", ss.c_str()); |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, | void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, | ||||||
|                                      uint8_t *data, size_t len, bool final) { |                                      uint8_t *data, size_t len, bool final) { | ||||||
| #ifdef USE_ARDUINO |   ota_base::OTAResponseTypes error_code = ota_base::OTA_RESPONSE_OK; | ||||||
|   bool success; |  | ||||||
|   if (index == 0) { |   if (index == 0 && !this->ota_backend_) { | ||||||
|  |     // Initialize OTA on first call | ||||||
|     this->ota_init_(filename.c_str()); |     this->ota_init_(filename.c_str()); | ||||||
|  |  | ||||||
|  | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  |     // Notify OTA started - use call_deferred since we're in web server task | ||||||
|  |     this->parent_->state_callback_.call_deferred(ota_base::OTA_STARTED, 0.0f, 0); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     // Platform-specific pre-initialization | ||||||
|  | #ifdef USE_ARDUINO | ||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
|     Update.runAsync(true); |     Update.runAsync(true); | ||||||
|     // NOLINTNEXTLINE(readability-static-accessed-through-instance) |  | ||||||
|     success = Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000); |  | ||||||
| #endif | #endif | ||||||
| #if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY) | #if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY) | ||||||
|     if (Update.isRunning()) { |     if (Update.isRunning()) { | ||||||
|       Update.abort(); |       Update.abort(); | ||||||
|     } |     } | ||||||
|     success = Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH); |  | ||||||
| #endif | #endif | ||||||
|     if (!success) { |  | ||||||
|       report_ota_error(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|   } else if (Update.hasError()) { |  | ||||||
|     // don't spam logs with errors if something failed at start |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   success = Update.write(data, len) == len; |  | ||||||
|   if (!success) { |  | ||||||
|     report_ota_error(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   this->ota_read_length_ += len; |  | ||||||
|   this->report_ota_progress_(request); |  | ||||||
|  |  | ||||||
|   if (final) { |  | ||||||
|     if (Update.end(true)) { |  | ||||||
|       this->schedule_ota_reboot_(); |  | ||||||
|     } else { |  | ||||||
|       report_ota_error(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| #endif  // USE_ARDUINO | #endif  // USE_ARDUINO | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF |     this->ota_backend_ = ota_base::make_ota_backend(); | ||||||
|   // ESP-IDF implementation |     if (!this->ota_backend_) { | ||||||
|   if (index == 0 && !this->ota_backend_) { |       ESP_LOGE(TAG, "Failed to create OTA backend"); | ||||||
|     // Initialize OTA on first call | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|     this->ota_init_(filename.c_str()); |       this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f, | ||||||
|     this->ota_success_ = false; |                                                    static_cast<uint8_t>(ota_base::OTA_RESPONSE_ERROR_UNKNOWN)); | ||||||
|  | #endif | ||||||
|     auto *backend = new IDFWebServerOTABackend(); |       return; | ||||||
|     if (!backend->begin()) { |     } | ||||||
|       ESP_LOGE(TAG, "OTA begin failed"); |  | ||||||
|       delete backend; |     // Web server OTA uses multipart uploads where the actual firmware size | ||||||
|  |     // is unknown (contentLength includes multipart overhead) | ||||||
|  |     // Pass 0 to indicate unknown size | ||||||
|  |     error_code = this->ota_backend_->begin(0); | ||||||
|  |     if (error_code != ota_base::OTA_RESPONSE_OK) { | ||||||
|  |       ESP_LOGE(TAG, "OTA begin failed: %d", error_code); | ||||||
|  |       this->ota_backend_.reset(); | ||||||
|  | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  |       this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code)); | ||||||
|  | #endif | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     this->ota_backend_ = backend; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   auto *backend = static_cast<IDFWebServerOTABackend *>(this->ota_backend_); |   if (!this->ota_backend_) { | ||||||
|   if (!backend) { |  | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Process data |   // Process data | ||||||
|   if (len > 0) { |   if (len > 0) { | ||||||
|     if (!backend->write(data, len)) { |     error_code = this->ota_backend_->write(data, len); | ||||||
|       ESP_LOGE(TAG, "OTA write failed"); |     if (error_code != ota_base::OTA_RESPONSE_OK) { | ||||||
|       backend->abort(); |       ESP_LOGE(TAG, "OTA write failed: %d", error_code); | ||||||
|       delete backend; |       this->ota_backend_->abort(); | ||||||
|       this->ota_backend_ = nullptr; |       this->ota_backend_.reset(); | ||||||
|  | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  |       this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code)); | ||||||
|  | #endif | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     this->ota_read_length_ += len; |     this->ota_read_length_ += len; | ||||||
| @@ -248,40 +141,45 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin | |||||||
|  |  | ||||||
|   // Finalize |   // Finalize | ||||||
|   if (final) { |   if (final) { | ||||||
|     this->ota_success_ = backend->end(); |     ESP_LOGD(TAG, "OTA final chunk: index=%u, len=%u, total_read=%u, contentLength=%u", index, len, | ||||||
|     if (this->ota_success_) { |              this->ota_read_length_, request->contentLength()); | ||||||
|  |  | ||||||
|  |     // For Arduino framework, the Update library tracks expected size from firmware header | ||||||
|  |     // If we haven't received enough data, calling end() will fail | ||||||
|  |     // This can happen if the upload is interrupted or the client disconnects | ||||||
|  |     error_code = this->ota_backend_->end(); | ||||||
|  |     if (error_code == ota_base::OTA_RESPONSE_OK) { | ||||||
|  |       this->ota_success_ = true; | ||||||
|  | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  |       // Report completion before reboot - use call_deferred since we're in web server task | ||||||
|  |       this->parent_->state_callback_.call_deferred(ota_base::OTA_COMPLETED, 100.0f, 0); | ||||||
|  | #endif | ||||||
|       this->schedule_ota_reboot_(); |       this->schedule_ota_reboot_(); | ||||||
|     } else { |     } else { | ||||||
|       ESP_LOGE(TAG, "OTA end failed"); |       ESP_LOGE(TAG, "OTA end failed: %d", error_code); | ||||||
|  | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  |       this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code)); | ||||||
|  | #endif | ||||||
|     } |     } | ||||||
|     delete backend; |     this->ota_backend_.reset(); | ||||||
|     this->ota_backend_ = nullptr; |  | ||||||
|   } |   } | ||||||
| #endif  // USE_ESP_IDF |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) { | void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) { | ||||||
|   AsyncWebServerResponse *response; |   AsyncWebServerResponse *response; | ||||||
| #ifdef USE_ARDUINO |   // Use the ota_success_ flag to determine the actual result | ||||||
|   if (!Update.hasError()) { |   const char *msg = this->ota_success_ ? "Update Successful!" : "Update Failed!"; | ||||||
|     response = request->beginResponse(200, "text/plain", "Update Successful!"); |   response = request->beginResponse(200, "text/plain", msg); | ||||||
|   } else { |  | ||||||
|     StreamString ss; |  | ||||||
|     ss.print("Update Failed: "); |  | ||||||
|     Update.printError(ss); |  | ||||||
|     response = request->beginResponse(200, "text/plain", ss); |  | ||||||
|   } |  | ||||||
| #endif  // USE_ARDUINO |  | ||||||
| #ifdef USE_ESP_IDF |  | ||||||
|   // Send response based on the OTA result |  | ||||||
|   response = request->beginResponse(200, "text/plain", this->ota_success_ ? "Update Successful!" : "Update Failed!"); |  | ||||||
| #endif  // USE_ESP_IDF |  | ||||||
|   response->addHeader("Connection", "close"); |   response->addHeader("Connection", "close"); | ||||||
|   request->send(response); |   request->send(response); | ||||||
| } | } | ||||||
|  |  | ||||||
| void WebServerBase::add_ota_handler() { | void WebServerBase::add_ota_handler() { | ||||||
|   this->add_handler(new OTARequestHandler(this));  // NOLINT |   this->add_handler(new OTARequestHandler(this));  // NOLINT | ||||||
|  | #ifdef USE_OTA_STATE_CALLBACK | ||||||
|  |   // Register with global OTA callback system | ||||||
|  |   ota_base::register_ota_platform(this); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,6 +14,10 @@ | |||||||
| #include "esphome/components/web_server_idf/web_server_idf.h" | #include "esphome/components/web_server_idf/web_server_idf.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_WEBSERVER_OTA | ||||||
|  | #include "esphome/components/ota_base/ota_backend.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace web_server_base { | namespace web_server_base { | ||||||
|  |  | ||||||
| @@ -79,7 +83,11 @@ class AuthMiddlewareHandler : public MiddlewareHandler { | |||||||
|  |  | ||||||
| }  // namespace internal | }  // namespace internal | ||||||
|  |  | ||||||
|  | #ifdef USE_WEBSERVER_OTA | ||||||
|  | class WebServerBase : public ota_base::OTAComponent { | ||||||
|  | #else | ||||||
| class WebServerBase : public Component { | class WebServerBase : public Component { | ||||||
|  | #endif | ||||||
|  public: |  public: | ||||||
|   void init() { |   void init() { | ||||||
|     if (this->initialized_) { |     if (this->initialized_) { | ||||||
| @@ -151,12 +159,10 @@ 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_; | ||||||
|  |   bool ota_success_{false}; | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
| #ifdef USE_ESP_IDF |   std::unique_ptr<ota_base::OTABackend> ota_backend_{nullptr}; | ||||||
|   void *ota_backend_{nullptr}; |  | ||||||
|   bool ota_success_{false}; |  | ||||||
| #endif |  | ||||||
| }; | }; | ||||||
| #endif  // USE_WEBSERVER_OTA | #endif  // USE_WEBSERVER_OTA | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,14 +6,7 @@ import esphome.codegen as cg | |||||||
| from esphome.components import time | from esphome.components import time | ||||||
| from esphome.components.esp32 import CORE, add_idf_sdkconfig_option | from esphome.components.esp32 import CORE, add_idf_sdkconfig_option | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import CONF_ADDRESS, CONF_ID, CONF_REBOOT_TIMEOUT, CONF_TIME_ID | ||||||
|     CONF_ADDRESS, |  | ||||||
|     CONF_ID, |  | ||||||
|     CONF_REBOOT_TIMEOUT, |  | ||||||
|     CONF_TIME_ID, |  | ||||||
|     KEY_CORE, |  | ||||||
|     KEY_FRAMEWORK_VERSION, |  | ||||||
| ) |  | ||||||
| from esphome.core import TimePeriod | from esphome.core import TimePeriod | ||||||
|  |  | ||||||
| CONF_NETMASK = "netmask" | CONF_NETMASK = "netmask" | ||||||
| @@ -125,9 +118,7 @@ async def to_code(config): | |||||||
|  |  | ||||||
|     # Workaround for crash on IDF 5+ |     # Workaround for crash on IDF 5+ | ||||||
|     # See https://github.com/trombik/esp_wireguard/issues/33#issuecomment-1568503651 |     # See https://github.com/trombik/esp_wireguard/issues/33#issuecomment-1568503651 | ||||||
|     if CORE.using_esp_idf and CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version( |     if CORE.using_esp_idf: | ||||||
|         5, 0, 0 |  | ||||||
|     ): |  | ||||||
|         add_idf_sdkconfig_option("CONFIG_LWIP_PPP_SUPPORT", True) |         add_idf_sdkconfig_option("CONFIG_LWIP_PPP_SUPPORT", True) | ||||||
|  |  | ||||||
|     # This flag is added here because the esp_wireguard library statically |     # This flag is added here because the esp_wireguard library statically | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								tests/components/ota_base/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/components/ota_base/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | # Test that ota_base compiles correctly as a dependency | ||||||
|  | # This component is typically auto-loaded by other components | ||||||
|  |  | ||||||
|  | wifi: | ||||||
|  |   ssid: MySSID | ||||||
|  |   password: password1 | ||||||
|  |  | ||||||
|  | ota: | ||||||
|  |   - platform: esphome | ||||||
|  |     password: "test1234" | ||||||
							
								
								
									
										1
									
								
								tests/components/ota_base/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/ota_base/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <<: !include common.yaml | ||||||
		Reference in New Issue
	
	Block a user