From cafa275579f99ae78a2b89a22206ecfe83e109d4 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:47:21 -0500 Subject: [PATCH 1/6] [esp32_hosted] Fix build and bump IDF component version to 2.7.0 (#12282) Co-authored-by: Claude --- esphome/components/esp32_hosted/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32_hosted/__init__.py b/esphome/components/esp32_hosted/__init__.py index fde75517eb..9c9d1d4bb4 100644 --- a/esphome/components/esp32_hosted/__init__.py +++ b/esphome/components/esp32_hosted/__init__.py @@ -93,9 +93,9 @@ async def to_code(config): framework_ver: cv.Version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] os.environ["ESP_IDF_VERSION"] = f"{framework_ver.major}.{framework_ver.minor}" if framework_ver >= cv.Version(5, 5, 0): - esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="1.1.5") + esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="1.2.2") esp32.add_idf_component(name="espressif/eppp_link", ref="1.1.3") - esp32.add_idf_component(name="espressif/esp_hosted", ref="2.6.1") + esp32.add_idf_component(name="espressif/esp_hosted", ref="2.7.0") else: esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="0.13.0") esp32.add_idf_component(name="espressif/eppp_link", ref="0.2.0") From 0da157ab98a7472475d8f5d05009c6ae18bd175f Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Thu, 4 Dec 2025 16:14:30 -0500 Subject: [PATCH 2/6] [tests] Bump esp32_hosted in the test code (#12289) Co-authored-by: Claude --- esphome/idf_component.yml | 4 ++-- tests/components/esp32/test.esp32-p4-idf.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/idf_component.yml b/esphome/idf_component.yml index b27b6b8ed1..9bb5967248 100644 --- a/esphome/idf_component.yml +++ b/esphome/idf_component.yml @@ -6,7 +6,7 @@ dependencies: espressif/mdns: version: 1.9.1 espressif/esp_wifi_remote: - version: 1.1.5 + version: 1.2.2 rules: - if: "target in [esp32h2, esp32p4]" espressif/eppp_link: @@ -14,7 +14,7 @@ dependencies: rules: - if: "target in [esp32h2, esp32p4]" espressif/esp_hosted: - version: 2.6.1 + version: 2.7.0 rules: - if: "target in [esp32h2, esp32p4]" zorxx/multipart-parser: diff --git a/tests/components/esp32/test.esp32-p4-idf.yaml b/tests/components/esp32/test.esp32-p4-idf.yaml index 1c243ef459..00a4ceec27 100644 --- a/tests/components/esp32/test.esp32-p4-idf.yaml +++ b/tests/components/esp32/test.esp32-p4-idf.yaml @@ -7,7 +7,7 @@ esp32: components: - espressif/mdns^1.8.2 - name: espressif/esp_hosted - ref: 2.6.6 + ref: 2.7.0 advanced: enable_idf_experimental_features: yes From 4db77488157b5b64f280cadad4cd114853a0f40f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 21:53:36 +0000 Subject: [PATCH 3/6] Bump ruff from 0.14.7 to 0.14.8 (#12286) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 412a678d02..49b87866f1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.14.7 + rev: v0.14.8 hooks: # Run the linter. - id: ruff diff --git a/requirements_test.txt b/requirements_test.txt index 9d55d23272..16ac131517 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==4.0.4 flake8==7.3.0 # also change in .pre-commit-config.yaml when updating -ruff==0.14.7 # also change in .pre-commit-config.yaml when updating +ruff==0.14.8 # also change in .pre-commit-config.yaml when updating pyupgrade==3.21.2 # also change in .pre-commit-config.yaml when updating pre-commit From 2b54f96d67d3080890df8d09107de52587f97ce4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 4 Dec 2025 16:58:09 -0600 Subject: [PATCH 4/6] [api] Use loop-based reboot timeout check to avoid scheduler heap churn --- esphome/components/api/api_server.cpp | 33 ++++++++++++--------------- esphome/components/api/api_server.h | 2 +- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 4168761c74..897cf8c41f 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -52,11 +52,6 @@ void APIServer::setup() { #endif #endif - // Schedule reboot if no clients connect within timeout - if (this->reboot_timeout_ != 0) { - this->schedule_reboot_timeout_(); - } - this->socket_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0); // monitored for incoming connections if (this->socket_ == nullptr) { ESP_LOGW(TAG, "Could not create socket"); @@ -112,16 +107,6 @@ void APIServer::setup() { #endif } -void APIServer::schedule_reboot_timeout_() { - this->status_set_warning(); - this->set_timeout("api_reboot", this->reboot_timeout_, []() { - if (!global_api_server->is_connected()) { - ESP_LOGE(TAG, "No clients; rebooting"); - App.reboot(); - } - }); -} - void APIServer::loop() { // Accept new clients only if the socket exists and has incoming connections if (this->socket_ && this->socket_->ready()) { @@ -147,15 +132,24 @@ void APIServer::loop() { this->clients_.emplace_back(conn); conn->start(); - // Clear warning status and cancel reboot when first client connects + // First client connected - clear warning and update timestamp if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) { this->status_clear_warning(); - this->cancel_timeout("api_reboot"); + this->last_connected_ = App.get_loop_component_start_time(); } } } if (this->clients_.empty()) { + // Check reboot timeout - done in loop to avoid scheduler heap churn + // (cancelled scheduler items sit in heap memory until their scheduled time) + if (this->reboot_timeout_ != 0) { + const uint32_t now = App.get_loop_component_start_time(); + if (now - this->last_connected_ > this->reboot_timeout_) { + ESP_LOGE(TAG, "No client connected; rebooting"); + App.reboot(); + } + } return; } @@ -194,9 +188,10 @@ void APIServer::loop() { } this->clients_.pop_back(); - // Schedule reboot when last client disconnects + // Last client disconnected - set warning and start tracking for reboot timeout if (this->clients_.empty() && this->reboot_timeout_ != 0) { - this->schedule_reboot_timeout_(); + this->status_set_warning(); + this->last_connected_ = App.get_loop_component_start_time(); } // Don't increment client_index since we need to process the swapped element } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 3089bb1d35..eb495afde7 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -202,7 +202,6 @@ class APIServer : public Component, #endif protected: - void schedule_reboot_timeout_(); #ifdef USE_API_NOISE bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg, const psk_t &active_psk, bool make_active); @@ -218,6 +217,7 @@ class APIServer : public Component, // 4-byte aligned types uint32_t reboot_timeout_{300000}; + uint32_t last_connected_{0}; // Vectors and strings (12 bytes each on 32-bit) std::vector> clients_; From d950d3868d2d07a7643c7bcc59e518f446970956 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 4 Dec 2025 17:01:38 -0600 Subject: [PATCH 5/6] fix --- esphome/components/api/api_server.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 897cf8c41f..9106e7aefa 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -105,6 +105,9 @@ void APIServer::setup() { camera::Camera::instance()->add_listener(this); } #endif + + // Initialize last_connected_ for reboot timeout tracking + this->last_connected_ = millis(); } void APIServer::loop() { From 5f2afe4b820c4effe09a3a95e1e22a81b83b534c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 4 Dec 2025 17:04:44 -0600 Subject: [PATCH 6/6] tweak --- esphome/components/api/api_server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 9106e7aefa..1cd85a1a52 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -107,7 +107,7 @@ void APIServer::setup() { #endif // Initialize last_connected_ for reboot timeout tracking - this->last_connected_ = millis(); + this->last_connected_ = App.get_loop_component_start_time(); } void APIServer::loop() { @@ -149,7 +149,7 @@ void APIServer::loop() { if (this->reboot_timeout_ != 0) { const uint32_t now = App.get_loop_component_start_time(); if (now - this->last_connected_ > this->reboot_timeout_) { - ESP_LOGE(TAG, "No client connected; rebooting"); + ESP_LOGE(TAG, "No clients; rebooting"); App.reboot(); } }