diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 748c8f2237..873f342277 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -71,8 +71,11 @@ void Application::setup() { do { uint8_t new_app_state = STATUS_LED_WARNING; - this->scheduler.call(millis()); - this->feed_wdt(); + uint32_t now = millis(); + + // Process pending loop enables to handle GPIO interrupts during setup + this->before_loop_tasks_(now); + for (uint32_t j = 0; j <= i; j++) { // Update loop_component_start_time_ right before calling each component this->loop_component_start_time_ = millis(); @@ -81,6 +84,8 @@ void Application::setup() { this->app_state_ |= new_app_state; this->feed_wdt(); } + + this->after_loop_tasks_(); this->app_state_ = new_app_state; yield(); } while (!component->can_proceed()); @@ -100,27 +105,7 @@ void Application::loop() { // Get the initial loop time at the start uint32_t last_op_end_time = millis(); - this->scheduler.call(last_op_end_time); - - // Feed WDT with time - this->feed_wdt(last_op_end_time); - - // Process any pending enable_loop requests from ISRs - // This must be done before marking in_loop_ = true to avoid race conditions - if (this->has_pending_enable_loop_requests_) { - // Clear flag BEFORE processing to avoid race condition - // If ISR sets it during processing, we'll catch it next loop iteration - // This is safe because: - // 1. Each component has its own pending_enable_loop_ flag that we check - // 2. If we can't process a component (wrong state), enable_pending_loops_() - // will set this flag back to true - // 3. Any new ISR requests during processing will set the flag again - this->has_pending_enable_loop_requests_ = false; - this->enable_pending_loops_(); - } - - // Mark that we're in the loop for safe reentrant modifications - this->in_loop_ = true; + this->before_loop_tasks_(last_op_end_time); for (this->current_loop_index_ = 0; this->current_loop_index_ < this->looping_components_active_end_; this->current_loop_index_++) { @@ -141,7 +126,7 @@ void Application::loop() { this->feed_wdt(last_op_end_time); } - this->in_loop_ = false; + this->after_loop_tasks_(); this->app_state_ = new_app_state; #ifdef USE_RUNTIME_STATS @@ -411,6 +396,36 @@ void Application::enable_pending_loops_() { } } +void Application::before_loop_tasks_(uint32_t loop_start_time) { + // Process scheduled tasks + this->scheduler.call(loop_start_time); + + // Feed the watchdog timer + this->feed_wdt(loop_start_time); + + // Process any pending enable_loop requests from ISRs + // This must be done before marking in_loop_ = true to avoid race conditions + if (this->has_pending_enable_loop_requests_) { + // Clear flag BEFORE processing to avoid race condition + // If ISR sets it during processing, we'll catch it next loop iteration + // This is safe because: + // 1. Each component has its own pending_enable_loop_ flag that we check + // 2. If we can't process a component (wrong state), enable_pending_loops_() + // will set this flag back to true + // 3. Any new ISR requests during processing will set the flag again + this->has_pending_enable_loop_requests_ = false; + this->enable_pending_loops_(); + } + + // Mark that we're in the loop for safe reentrant modifications + this->in_loop_ = true; +} + +void Application::after_loop_tasks_() { + // Clear the in_loop_ flag to indicate we're done processing components + this->in_loop_ = false; +} + #ifdef USE_SOCKET_SELECT_SUPPORT bool Application::register_socket_fd(int fd) { // WARNING: This function is NOT thread-safe and must only be called from the main loop diff --git a/esphome/core/application.h b/esphome/core/application.h index 75b9769ca3..a83789837f 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -512,6 +512,8 @@ class Application { void enable_component_loop_(Component *component); void enable_pending_loops_(); void activate_looping_component_(uint16_t index); + void before_loop_tasks_(uint32_t loop_start_time); + void after_loop_tasks_(); void feed_wdt_arch_();