From fe0436166c12eff9672f58d38a9fed64d30504e8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 22:31:04 -1000 Subject: [PATCH] =?UTF-8?q?[core]=20Ensure=20SETUP=E2=86=92LOOP=20transiti?= =?UTF-8?q?on=20before=20main=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Components after the last blocking component in setup only receive one call() (CONSTRUCTION→SETUP) and never get the second call() that would transition them to LOOP state. Explicitly transition all active looping components to LOOP state at the end of setup() so the main loop can call loop() directly without the call() state machine wrapper. --- esphome/core/application.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index f827783503..db1c8a0c0a 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -153,6 +153,14 @@ void Application::setup() { this->setup_wake_loop_threadsafe_(); #endif + // Ensure all active looping components are in LOOP state. + // Components after the last blocking component only got one call() during setup + // (CONSTRUCTION→SETUP) and never received the second call() (SETUP→LOOP). + // The main loop calls loop() directly, bypassing call()'s state machine. + for (uint16_t i = 0; i < this->looping_components_active_end_; i++) { + this->looping_components_[i]->set_component_state_(COMPONENT_STATE_LOOP); + } + this->schedule_dump_config(); } void Application::loop() {