diff --git a/esphome/components/uptime/text_sensor/__init__.py b/esphome/components/uptime/text_sensor/__init__.py index 996d983e71..e4a7ac6517 100644 --- a/esphome/components/uptime/text_sensor/__init__.py +++ b/esphome/components/uptime/text_sensor/__init__.py @@ -11,7 +11,7 @@ CONFIG_SCHEMA = text_sensor.text_sensor_schema( UptimeTextSensor, icon=ICON_TIMER, entity_category=ENTITY_CATEGORY_DIAGNOSTIC, -).extend(cv.polling_component_schema("60s")) +).extend(cv.polling_component_schema("30s")) async def to_code(config): diff --git a/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp b/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp index 0fa5e199f3..409af6e4ff 100644 --- a/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +++ b/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp @@ -9,34 +9,51 @@ namespace uptime { static const char *const TAG = "uptime.sensor"; -void UptimeTextSensor::setup() { this->last_ms_ = millis(); } +void UptimeTextSensor::setup() { + this->last_ms_ = millis(); + if (this->last_ms_ < 60 * 1000) + this->last_ms_ = 0; + this->update(); +} void UptimeTextSensor::update() { - const auto now = millis(); + 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. - const uint32_t delta = (now - this->last_ms_) / 1000; - if (delta == 0) - return; - // set last_ms_ to the last second boundary - this->last_ms_ = now - (now % 1000); + uint32_t delta = now - this->last_ms_; + this->last_ms_ = now - delta % 1000; // save remainder for next update + delta /= 1000; this->uptime_ += delta; auto uptime = this->uptime_; - unsigned days = uptime / (24 * 3600); - unsigned seconds = uptime % (24 * 3600); - unsigned hours = seconds / 3600; - seconds %= 3600; - unsigned minutes = seconds / 60; - seconds %= 60; - if (days != 0) { - this->publish_state(str_sprintf("%dd%dh%dm%ds", days, hours, minutes, seconds)); - } else if (hours != 0) { - this->publish_state(str_sprintf("%dh%dm%ds", hours, minutes, seconds)); - } else if (minutes != 0) { - this->publish_state(str_sprintf("%dm%ds", minutes, seconds)); - } else { - this->publish_state(str_sprintf("%ds", seconds)); + unsigned interval = this->get_update_interval() / 1000; + std::string buffer{}; + // display from the largest unit that corresponds to the update interval, drop larger units that are zero. + while (true) { // enable use of break for early exit + unsigned remainder = uptime % 60; + uptime /= 60; + if (interval < 30) { + buffer.insert(0, str_sprintf("%us", remainder)); + if (uptime == 0) + break; + } + remainder = uptime % 60; + uptime /= 60; + if (interval < 1800) { + buffer.insert(0, str_sprintf("%um", remainder)); + if (uptime == 0) + break; + } + remainder = uptime % 24; + uptime /= 24; + if (interval < 12 * 3600) { + buffer.insert(0, str_sprintf("%uh", remainder)); + if (uptime == 0) + break; + } + buffer.insert(0, str_sprintf("%ud", (unsigned) uptime)); + break; } + this->publish_state(buffer); } float UptimeTextSensor::get_setup_priority() const { return setup_priority::HARDWARE; } diff --git a/esphome/components/uptime/text_sensor/uptime_text_sensor.h b/esphome/components/uptime/text_sensor/uptime_text_sensor.h index 4baf1039b6..5719ef38a2 100644 --- a/esphome/components/uptime/text_sensor/uptime_text_sensor.h +++ b/esphome/components/uptime/text_sensor/uptime_text_sensor.h @@ -17,8 +17,8 @@ class UptimeTextSensor : public text_sensor::TextSensor, public PollingComponent float get_setup_priority() const override; protected: - uint64_t uptime_{0}; - uint64_t last_ms_{0}; + uint32_t uptime_{0}; // uptime in seconds, will overflow after 136 years + uint32_t last_ms_{0}; }; } // namespace uptime