[uptime] Add format config for text_sensor (#8304)

This commit is contained in:
Clyde Stubbs 2025-04-17 11:18:08 +10:00 committed by GitHub
parent 248dbd32a5
commit 55e099450c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 88 additions and 14 deletions

View File

@ -1,19 +1,59 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import text_sensor from esphome.components import text_sensor
import esphome.config_validation as cv 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") uptime_ns = cg.esphome_ns.namespace("uptime")
UptimeTextSensor = uptime_ns.class_( UptimeTextSensor = uptime_ns.class_(
"UptimeTextSensor", text_sensor.TextSensor, cg.PollingComponent "UptimeTextSensor", text_sensor.TextSensor, cg.PollingComponent
) )
CONFIG_SCHEMA = text_sensor.text_sensor_schema(
UptimeTextSensor, CONF_SEPARATOR = "separator"
icon=ICON_TIMER, CONF_DAYS = "days"
entity_category=ENTITY_CATEGORY_DIAGNOSTIC, CONF_EXPAND = "expand"
).extend(cv.polling_component_schema("30s"))
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): 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) await cg.register_component(var, config)

View File

@ -16,6 +16,11 @@ void UptimeTextSensor::setup() {
this->update(); 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() { void UptimeTextSensor::update() {
auto now = millis(); auto now = millis();
// get whole seconds since last update. Note that even if the millis count has overflowed between updates, // 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; unsigned remainder = uptime % 60;
uptime /= 60; uptime /= 60;
if (interval < 30) { if (interval < 30) {
buffer.insert(0, str_sprintf("%us", remainder)); this->insert_buffer_(buffer, this->seconds_text_, remainder);
if (uptime == 0) if (!this->expand_ && uptime == 0)
break; break;
} }
remainder = uptime % 60; remainder = uptime % 60;
uptime /= 60; uptime /= 60;
if (interval < 1800) { if (interval < 1800) {
buffer.insert(0, str_sprintf("%um", remainder)); this->insert_buffer_(buffer, this->minutes_text_, remainder);
if (uptime == 0) if (!this->expand_ && uptime == 0)
break; break;
} }
remainder = uptime % 24; remainder = uptime % 24;
uptime /= 24; uptime /= 24;
if (interval < 12 * 3600) { if (interval < 12 * 3600) {
buffer.insert(0, str_sprintf("%uh", remainder)); this->insert_buffer_(buffer, this->hours_text_, remainder);
if (uptime == 0) if (!this->expand_ && uptime == 0)
break; break;
} }
buffer.insert(0, str_sprintf("%ud", (unsigned) uptime)); this->insert_buffer_(buffer, this->days_text_, (unsigned) uptime);
break; break;
} }
this->publish_state(buffer); this->publish_state(buffer);

View File

@ -10,13 +10,32 @@ namespace uptime {
class UptimeTextSensor : public text_sensor::TextSensor, public PollingComponent { class UptimeTextSensor : public text_sensor::TextSensor, public PollingComponent {
public: 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 update() override;
void dump_config() override; void dump_config() override;
void setup() override; void setup() override;
float get_setup_priority() const 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: 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 uptime_{0}; // uptime in seconds, will overflow after 136 years
uint32_t last_ms_{0}; uint32_t last_ms_{0};
}; };

View File

@ -17,3 +17,13 @@ sensor:
text_sensor: text_sensor:
- platform: uptime - platform: uptime
name: Uptime Text 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