diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index bfe9beb2723..172842ee3d4 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -512,6 +512,13 @@ void PollingComponent::set_update_interval(uint32_t update_interval) { this->upd void __attribute__((noinline, cold)) WarnIfComponentBlockingGuard::warn_blocking(Component *component, uint32_t blocking_time) { + // Clamp underflowed values: if millis() < started_ (e.g. scheduler passes + // a `now` slightly ahead of real millis()), the subtraction wraps to ~4 billion. + // Clamping to uint16_t max lets should_warn_of_blocking() saturate the + // threshold and suppress further warnings. + if (blocking_time > std::numeric_limits::max()) { + blocking_time = std::numeric_limits::max(); + } bool should_warn; if (component != nullptr) { should_warn = component->should_warn_of_blocking(blocking_time); diff --git a/esphome/core/component.h b/esphome/core/component.h index 64f99716272..5fdf23e128a 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -594,17 +594,12 @@ class WarnIfComponentBlockingGuard { // Inlined: the fast path is just millis() + subtract + compare inline uint32_t HOT finish() { uint32_t curr_time = millis(); + uint32_t blocking_time = curr_time - this->started_; #ifdef USE_RUNTIME_STATS this->record_runtime_stats_(); #endif - // Guard against underflow: if curr_time < started_, the subtraction wraps - // to a huge value. This can happen when the scheduler passes a `now` value - // slightly ahead of real millis() (e.g. from execute_item_ return values). - if (curr_time >= this->started_) [[likely]] { - uint32_t blocking_time = curr_time - this->started_; - if (blocking_time > WARN_IF_BLOCKING_OVER_MS) [[unlikely]] { - warn_blocking(this->component_, blocking_time); - } + if (blocking_time > WARN_IF_BLOCKING_OVER_MS) [[unlikely]] { + warn_blocking(this->component_, blocking_time); } return curr_time; }