diff --git a/esphome/components/uptime/sensor/uptime_seconds_sensor.cpp b/esphome/components/uptime/sensor/uptime_seconds_sensor.cpp index 54260d7e80..20e8ed8fda 100644 --- a/esphome/components/uptime/sensor/uptime_seconds_sensor.cpp +++ b/esphome/components/uptime/sensor/uptime_seconds_sensor.cpp @@ -1,30 +1,16 @@ #include "uptime_seconds_sensor.h" -#include "esphome/core/hal.h" -#include "esphome/core/helpers.h" +#include "esphome/core/application.h" #include "esphome/core/log.h" -namespace esphome { -namespace uptime { +namespace esphome::uptime { static const char *const TAG = "uptime.sensor"; void UptimeSecondsSensor::update() { - const uint32_t ms = millis(); - const uint64_t ms_mask = (1ULL << 32) - 1ULL; - const uint32_t last_ms = this->uptime_ & ms_mask; - if (ms < last_ms) { - this->uptime_ += ms_mask + 1ULL; - ESP_LOGD(TAG, "Detected roll-over \xf0\x9f\xa6\x84"); - } - this->uptime_ &= ~ms_mask; - this->uptime_ |= ms; - - // Do separate second and milliseconds conversion to avoid floating point division errors - // Probably some IEEE standard already guarantees this division can be done without loss - // of precision in a single division, but let's do it like this to be sure. - const uint64_t seconds_int = this->uptime_ / 1000ULL; - const float seconds = float(seconds_int) + (this->uptime_ % 1000ULL) / 1000.0f; + const uint64_t uptime = App.scheduler.millis_64(); + const uint64_t seconds_int = uptime / 1000ULL; + const float seconds = float(seconds_int) + (uptime % 1000ULL) / 1000.0f; this->publish_state(seconds); } float UptimeSecondsSensor::get_setup_priority() const { return setup_priority::HARDWARE; } @@ -33,5 +19,4 @@ void UptimeSecondsSensor::dump_config() { ESP_LOGCONFIG(TAG, " Type: Seconds"); } -} // namespace uptime -} // namespace esphome +} // namespace esphome::uptime diff --git a/esphome/components/uptime/sensor/uptime_seconds_sensor.h b/esphome/components/uptime/sensor/uptime_seconds_sensor.h index 210195052f..1b80a4480a 100644 --- a/esphome/components/uptime/sensor/uptime_seconds_sensor.h +++ b/esphome/components/uptime/sensor/uptime_seconds_sensor.h @@ -3,8 +3,7 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/core/component.h" -namespace esphome { -namespace uptime { +namespace esphome::uptime { class UptimeSecondsSensor : public sensor::Sensor, public PollingComponent { public: @@ -12,10 +11,6 @@ class UptimeSecondsSensor : public sensor::Sensor, public PollingComponent { void dump_config() override; float get_setup_priority() const override; - - protected: - uint64_t uptime_{0}; }; -} // namespace uptime -} // namespace esphome +} // namespace esphome::uptime diff --git a/esphome/components/uptime/sensor/uptime_timestamp_sensor.cpp b/esphome/components/uptime/sensor/uptime_timestamp_sensor.cpp index 69033be11c..4e0f06be1c 100644 --- a/esphome/components/uptime/sensor/uptime_timestamp_sensor.cpp +++ b/esphome/components/uptime/sensor/uptime_timestamp_sensor.cpp @@ -6,8 +6,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -namespace esphome { -namespace uptime { +namespace esphome::uptime { static const char *const TAG = "uptime.sensor"; @@ -33,7 +32,6 @@ void UptimeTimestampSensor::dump_config() { ESP_LOGCONFIG(TAG, " Type: Timestamp"); } -} // namespace uptime -} // namespace esphome +} // namespace esphome::uptime #endif // USE_TIME diff --git a/esphome/components/uptime/sensor/uptime_timestamp_sensor.h b/esphome/components/uptime/sensor/uptime_timestamp_sensor.h index f38b5d53b4..912c0b7655 100644 --- a/esphome/components/uptime/sensor/uptime_timestamp_sensor.h +++ b/esphome/components/uptime/sensor/uptime_timestamp_sensor.h @@ -8,8 +8,7 @@ #include "esphome/components/time/real_time_clock.h" #include "esphome/core/component.h" -namespace esphome { -namespace uptime { +namespace esphome::uptime { class UptimeTimestampSensor : public sensor::Sensor, public Component { public: @@ -24,7 +23,6 @@ class UptimeTimestampSensor : public sensor::Sensor, public Component { time::RealTimeClock *time_; }; -} // namespace uptime -} // namespace esphome +} // namespace esphome::uptime #endif // USE_TIME diff --git a/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp b/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp index acd3980a1a..88ae53fbfc 100644 --- a/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +++ b/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp @@ -1,11 +1,10 @@ #include "uptime_text_sensor.h" -#include "esphome/core/hal.h" +#include "esphome/core/application.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -namespace esphome { -namespace uptime { +namespace esphome::uptime { static const char *const TAG = "uptime.sensor"; @@ -17,22 +16,10 @@ static void append_unit(char *buf, size_t buf_size, size_t &pos, const char *sep pos = buf_append_printf(buf, buf_size, pos, "%u%s", value, label); } -void UptimeTextSensor::setup() { - this->last_ms_ = millis(); - if (this->last_ms_ < 60 * 1000) - this->last_ms_ = 0; - this->update(); -} +void UptimeTextSensor::setup() { this->update(); } void UptimeTextSensor::update() { - auto now = millis(); - // get whole seconds since last update. Note that even if the millis count has overflowed between updates, - // the difference will still be correct due to the way twos-complement arithmetic works. - uint32_t delta = now - this->last_ms_; - this->last_ms_ = now - delta % 1000; // save remainder for next update - delta /= 1000; - this->uptime_ += delta; - uint32_t uptime = this->uptime_; + uint32_t uptime = static_cast(App.scheduler.millis_64() / 1000); unsigned interval = this->get_update_interval() / 1000; // Calculate all time units @@ -89,5 +76,4 @@ void UptimeTextSensor::update() { float UptimeTextSensor::get_setup_priority() const { return setup_priority::HARDWARE; } void UptimeTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Uptime Text Sensor", this); } -} // namespace uptime -} // namespace esphome +} // namespace esphome::uptime diff --git a/esphome/components/uptime/text_sensor/uptime_text_sensor.h b/esphome/components/uptime/text_sensor/uptime_text_sensor.h index 947d9c91e9..a97ba332bb 100644 --- a/esphome/components/uptime/text_sensor/uptime_text_sensor.h +++ b/esphome/components/uptime/text_sensor/uptime_text_sensor.h @@ -5,8 +5,7 @@ #include "esphome/components/text_sensor/text_sensor.h" #include "esphome/core/component.h" -namespace esphome { -namespace uptime { +namespace esphome::uptime { class UptimeTextSensor : public text_sensor::TextSensor, public PollingComponent { public: @@ -35,9 +34,6 @@ class UptimeTextSensor : public text_sensor::TextSensor, public PollingComponent const char *seconds_text_; const char *separator_; bool expand_{}; - uint32_t uptime_{0}; // uptime in seconds, will overflow after 136 years - uint32_t last_ms_{0}; }; -} // namespace uptime -} // namespace esphome +} // namespace esphome::uptime diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index 3294f689e8..e82efcc520 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -675,6 +675,8 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, NameType name_type return total_cancelled > 0; } +uint64_t Scheduler::millis_64() { return this->millis_64_(millis()); } + uint64_t Scheduler::millis_64_(uint32_t now) { // THREAD SAFETY NOTE: // This function has three implementations, based on the precompiler flags diff --git a/esphome/core/scheduler.h b/esphome/core/scheduler.h index 394178a831..afe11aaca6 100644 --- a/esphome/core/scheduler.h +++ b/esphome/core/scheduler.h @@ -116,6 +116,9 @@ class Scheduler { ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0") bool cancel_retry(Component *component, uint32_t id); + /// Get 64-bit millisecond timestamp (handles 32-bit millis() rollover) + uint64_t millis_64(); + // Calculate when the next scheduled item should run // @param now Fresh timestamp from millis() - must not be stale/cached // Returns the time in milliseconds until the next scheduled item, or nullopt if no items