From 4dcaea15a3079381d4095050613b72be4b66db73 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 14 Apr 2026 21:54:48 -1000 Subject: [PATCH 1/2] missed some sites --- esphome/core/application.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 1c73230705..6c7670ceaa 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -78,7 +78,7 @@ void Application::setup() { Component *component = this->components_[i]; // Update loop_component_start_time_ before calling each component during setup - this->loop_component_start_time_ = millis(); + this->loop_component_start_time_ = MillisInternal::get(); component->call(); this->scheduler.process_to_add(); this->feed_wdt(); @@ -91,14 +91,14 @@ void Application::setup() { this->app_state_ |= STATUS_LED_WARNING; do { - uint32_t now = millis(); + uint32_t now = MillisInternal::get(); // 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(); + this->loop_component_start_time_ = MillisInternal::get(); this->components_[j]->call(); this->feed_wdt(); } @@ -212,7 +212,7 @@ void Application::process_dump_config_() { void Application::feed_wdt() { // Cold entry: callers without a millis() timestamp in hand. Fetches the // time and takes the same rate-limit path as feed_wdt_with_time(). - uint32_t now = millis(); + uint32_t now = MillisInternal::get(); if (now - this->last_wdt_feed_ > WDT_FEED_INTERVAL_MS) { this->feed_wdt_slow_(now); } @@ -274,7 +274,7 @@ void Application::run_powerdown_hooks() { } void Application::teardown_components(uint32_t timeout_ms) { - uint32_t start_time = millis(); + uint32_t start_time = MillisInternal::get(); // Use a StaticVector instead of std::vector to avoid heap allocation // since we know the actual size at compile time @@ -353,7 +353,7 @@ void Application::teardown_components(uint32_t timeout_ms) { } // Update time for next iteration - now = millis(); + now = MillisInternal::get(); } if (pending_count > 0) { @@ -396,7 +396,7 @@ void Application::disable_component_loop_(Component *component) { // This prevents integer underflow in timing calculations by ensuring // the swapped component starts with a fresh timing reference, avoiding // errors caused by stale or wrapped timing values. - this->loop_component_start_time_ = millis(); + this->loop_component_start_time_ = MillisInternal::get(); } } return; From 6a6d9bb80876f6445ae877a0d1a24235758d1943 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 14 Apr 2026 21:58:22 -1000 Subject: [PATCH 2/2] cleanup --- esphome/core/scheduler.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/esphome/core/scheduler.h b/esphome/core/scheduler.h index 0372e06066..432a488a38 100644 --- a/esphome/core/scheduler.h +++ b/esphome/core/scheduler.h @@ -284,12 +284,14 @@ class Scheduler { bool cancel_retry_(Component *component, NameType name_type, const char *static_name, uint32_t hash_or_id); // Extend a 32-bit millis() value to 64-bit. Use when the caller already has a fresh now. - // On platforms with native 64-bit time (ESP32), ignores now and uses millis_64() directly. - // This means the Scheduler uses the esp_timer clock (via millis_64()) for all scheduling, - // even though the caller's 32-bit now came from xTaskGetTickCount (via millis()). Safe - // because scheduling only compares millis_64 against millis_64 — never against millis(). - // On other platforms (ESP8266), extends now to 64-bit using rollover tracking, so both - // millis() and scheduling use the same clock. + // On platforms with native 64-bit time (ESP32, Host, Zephyr, RP2040 — see + // USE_NATIVE_64BIT_TIME in defines.h), ignores now and uses millis_64() directly, so the + // Scheduler always works in 64-bit time regardless of what the caller's 32-bit now came + // from. On ESP32 specifically, millis() comes from xTaskGetTickCount while millis_64() + // comes from esp_timer — two different clocks — but that is safe because scheduling + // compares millis_64 values against millis_64 only, never against millis(). + // On platforms without native 64-bit time (e.g. ESP8266), extends now to 64-bit using + // rollover tracking, so both millis() and scheduling use the same underlying clock. uint64_t ESPHOME_ALWAYS_INLINE millis_64_from_(uint32_t now) { #ifdef USE_NATIVE_64BIT_TIME (void) now;