diff --git a/esphome/components/uptime/text_sensor/__init__.py b/esphome/components/uptime/text_sensor/__init__.py index e4a7ac6517..6b91b526c0 100644 --- a/esphome/components/uptime/text_sensor/__init__.py +++ b/esphome/components/uptime/text_sensor/__init__.py @@ -1,19 +1,59 @@ import esphome.codegen as cg from esphome.components import text_sensor import esphome.config_validation as cv -from esphome.const import ENTITY_CATEGORY_DIAGNOSTIC, ICON_TIMER +from esphome.const import ( + CONF_FORMAT, + CONF_HOURS, + CONF_ID, + CONF_MINUTES, + CONF_SECONDS, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_TIMER, +) uptime_ns = cg.esphome_ns.namespace("uptime") UptimeTextSensor = uptime_ns.class_( "UptimeTextSensor", text_sensor.TextSensor, cg.PollingComponent ) -CONFIG_SCHEMA = text_sensor.text_sensor_schema( - UptimeTextSensor, - icon=ICON_TIMER, - entity_category=ENTITY_CATEGORY_DIAGNOSTIC, -).extend(cv.polling_component_schema("30s")) + +CONF_SEPARATOR = "separator" +CONF_DAYS = "days" +CONF_EXPAND = "expand" + +CONFIG_SCHEMA = ( + text_sensor.text_sensor_schema( + UptimeTextSensor, + icon=ICON_TIMER, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ) + .extend( + { + cv.Optional(CONF_FORMAT, default={}): cv.Schema( + { + cv.Optional(CONF_DAYS, default="d"): cv.string_strict, + cv.Optional(CONF_HOURS, default="h"): cv.string_strict, + cv.Optional(CONF_MINUTES, default="m"): cv.string_strict, + cv.Optional(CONF_SECONDS, default="s"): cv.string_strict, + cv.Optional(CONF_SEPARATOR, default=""): cv.string_strict, + cv.Optional(CONF_EXPAND, default=False): cv.boolean, + } + ) + } + ) + .extend(cv.polling_component_schema("30s")) +) async def to_code(config): - var = await text_sensor.new_text_sensor(config) + format = config[CONF_FORMAT] + var = cg.new_Pvariable( + config[CONF_ID], + format[CONF_DAYS], + format[CONF_HOURS], + format[CONF_MINUTES], + format[CONF_SECONDS], + format[CONF_SEPARATOR], + format[CONF_EXPAND], + ) + await text_sensor.register_text_sensor(var, config) await cg.register_component(var, config) diff --git a/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp b/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp index 409af6e4ff..94585379fe 100644 --- a/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +++ b/esphome/components/uptime/text_sensor/uptime_text_sensor.cpp @@ -16,6 +16,11 @@ void UptimeTextSensor::setup() { this->update(); } +void UptimeTextSensor::insert_buffer_(std::string &buffer, const char *key, unsigned value) const { + buffer.insert(0, this->separator_); + buffer.insert(0, str_sprintf("%u%s", value, key)); +} + void UptimeTextSensor::update() { auto now = millis(); // get whole seconds since last update. Note that even if the millis count has overflowed between updates, @@ -32,25 +37,25 @@ void UptimeTextSensor::update() { unsigned remainder = uptime % 60; uptime /= 60; if (interval < 30) { - buffer.insert(0, str_sprintf("%us", remainder)); - if (uptime == 0) + this->insert_buffer_(buffer, this->seconds_text_, remainder); + if (!this->expand_ && uptime == 0) break; } remainder = uptime % 60; uptime /= 60; if (interval < 1800) { - buffer.insert(0, str_sprintf("%um", remainder)); - if (uptime == 0) + this->insert_buffer_(buffer, this->minutes_text_, remainder); + if (!this->expand_ && uptime == 0) break; } remainder = uptime % 24; uptime /= 24; if (interval < 12 * 3600) { - buffer.insert(0, str_sprintf("%uh", remainder)); - if (uptime == 0) + this->insert_buffer_(buffer, this->hours_text_, remainder); + if (!this->expand_ && uptime == 0) break; } - buffer.insert(0, str_sprintf("%ud", (unsigned) uptime)); + this->insert_buffer_(buffer, this->days_text_, (unsigned) uptime); break; } this->publish_state(buffer); diff --git a/esphome/components/uptime/text_sensor/uptime_text_sensor.h b/esphome/components/uptime/text_sensor/uptime_text_sensor.h index 5719ef38a2..8dd058998c 100644 --- a/esphome/components/uptime/text_sensor/uptime_text_sensor.h +++ b/esphome/components/uptime/text_sensor/uptime_text_sensor.h @@ -10,13 +10,32 @@ namespace uptime { class UptimeTextSensor : public text_sensor::TextSensor, public PollingComponent { public: + UptimeTextSensor(const char *days_text, const char *hours_text, const char *minutes_text, const char *seconds_text, + const char *separator, bool expand) + : days_text_(days_text), + hours_text_(hours_text), + minutes_text_(minutes_text), + seconds_text_(seconds_text), + separator_(separator), + expand_(expand) {} void update() override; void dump_config() override; void setup() override; float get_setup_priority() const override; + void set_days(const char *days_text) { this->days_text_ = days_text; } + void set_hours(const char *hours_text) { this->hours_text_ = hours_text; } + void set_minutes(const char *minutes_text) { this->minutes_text_ = minutes_text; } + void set_seconds(const char *seconds_text) { this->seconds_text_ = seconds_text; } protected: + void insert_buffer_(std::string &buffer, const char *key, unsigned value) const; + const char *days_text_; + const char *hours_text_; + const char *minutes_text_; + 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}; }; diff --git a/tests/components/uptime/common.yaml b/tests/components/uptime/common.yaml index d78ef8eca9..86b764e7ff 100644 --- a/tests/components/uptime/common.yaml +++ b/tests/components/uptime/common.yaml @@ -17,3 +17,13 @@ sensor: text_sensor: - platform: uptime name: Uptime Text + - platform: uptime + name: Uptime Text With Separator + format: + separator: "-" + expand: true + days: "Days" + hours: "H" + minutes: "M" + seconds: "S" + update_interval: 10s