From 7409c7286fa4bcd205274e01e600b4bba91e3514 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 24 May 2026 21:34:49 +0200 Subject: [PATCH] https://github.com/emsesp/EMS-ESP32/issues/3089 --- src/core/emsdevicevalue.cpp | 10 +++++---- src/core/emsdevicevalue.h | 3 ++- src/core/locale_common.h | 2 ++ src/core/mqtt.cpp | 42 ++++++++++++++++++++++++++++--------- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/core/emsdevicevalue.cpp b/src/core/emsdevicevalue.cpp index ea5db353e..8db02d339 100644 --- a/src/core/emsdevicevalue.cpp +++ b/src/core/emsdevicevalue.cpp @@ -110,10 +110,12 @@ DeviceValue::DeviceValue(uint8_t device_type, const char * DeviceValue::DeviceValueUOM_s[] = { F_(uom_blank), // 0 - F_(uom_degrees), F_(uom_degrees), F_(uom_percent), F_(uom_lmin), F_(uom_kwh), F_(uom_wh), FL_(hours)[0], FL_(minutes)[0], - F_(uom_ua), F_(uom_bar), F_(uom_kw), F_(uom_w), F_(uom_kb), FL_(seconds)[0], F_(uom_dbm), F_(uom_fahrenheit), - F_(uom_mv), F_(uom_sqm), F_(uom_m3), F_(uom_l), F_(uom_kmin), F_(uom_k), F_(uom_volts), F_(uom_mbar), - F_(uom_lh), F_(uom_ctkwh), F_(uom_hz), F_(uom_blank) + F_(uom_degrees), F_(uom_degrees), F_(uom_percent), F_(uom_lmin), F_(uom_kwh), F_(uom_wh), FL_(hours)[0], FL_(minutes)[0], F_(uom_ua), + F_(uom_bar), F_(uom_kw), F_(uom_w), F_(uom_kb), FL_(seconds)[0], F_(uom_dbm), F_(uom_fahrenheit), F_(uom_mv), F_(uom_sqm), + F_(uom_m3), F_(uom_l), F_(uom_kmin), F_(uom_k), F_(uom_volts), F_(uom_mbar), F_(uom_lh), F_(uom_ctkwh), F_(uom_hz), + F_(uom_blank), // connectivity + F_(uom_blank), // timestamp + F_(uom_blank) // blank }; diff --git a/src/core/emsdevicevalue.h b/src/core/emsdevicevalue.h index c2a5b12db..764273269 100644 --- a/src/core/emsdevicevalue.h +++ b/src/core/emsdevicevalue.h @@ -77,7 +77,8 @@ class DeviceValue { LH, // 25 - l/h - volume flow rate CTKWH, // 26 - ct/kWh - monetary HERTZ, // 27 - Hz - frequency - CONNECTIVITY // 28 - used in HA - connectivity + CONNECTIVITY, // 28 - used in HA - connectivity + TIMESTAMP, // 29 - used in HA - timestamp }; // TAG mapping - maps to DeviceValueTAG_s in emsdevicevalue.cpp diff --git a/src/core/locale_common.h b/src/core/locale_common.h index 31106bdfa..725081ce4 100644 --- a/src/core/locale_common.h +++ b/src/core/locale_common.h @@ -268,6 +268,8 @@ MAKE_WORD_CUSTOM(uom_l, "l") MAKE_WORD_CUSTOM(uom_kmin, "K*min") MAKE_WORD_CUSTOM(uom_k, "K") MAKE_WORD_CUSTOM(uom_volts, "V") +MAKE_WORD_CUSTOM(uom_connectivity, "connectivity") +MAKE_WORD_CUSTOM(uom_timestamp, "timestamp") MAKE_WORD_CUSTOM(uom_mbar, "mbar") MAKE_WORD_CUSTOM(uom_lh, "l/h") MAKE_WORD_CUSTOM(uom_ctkwh, "ct/kWh") diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index 9477571c3..c177fa9b6 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -567,8 +567,6 @@ void Mqtt::ha_status() { #endif publish_system_ha_sensor_config(DeviceValueType::STRING, "EMS Bus", "bus_status", DeviceValueUOM::NONE); - publish_system_ha_sensor_config(DeviceValueType::STRING, "Uptime", "uptime", DeviceValueUOM::NONE); - publish_system_ha_sensor_config(DeviceValueType::INT8, "Uptime (sec)", "uptime_sec", DeviceValueUOM::SECONDS); publish_system_ha_sensor_config(DeviceValueType::INT8, "Free memory", "freemem", DeviceValueUOM::KB); publish_system_ha_sensor_config(DeviceValueType::INT8, "Max alloc", "max_alloc", DeviceValueUOM::KB); publish_system_ha_sensor_config(DeviceValueType::INT8, "MQTT fails", "mqttfails", DeviceValueUOM::NONE); @@ -585,8 +583,10 @@ void Mqtt::ha_status() { if (!EMSESP::network_.ethernet_connected()) { publish_system_ha_sensor_config(DeviceValueType::INT16, "WiFi reconnects", "wifireconnects", DeviceValueUOM::NONE); } - // This one comes from the info MQTT topic - and handled in the publish_ha_sensor_config function + + // These come from the info MQTT topic - and handled in the publish_ha_sensor_config function publish_system_ha_sensor_config(DeviceValueType::STRING, "Version", "version", DeviceValueUOM::NONE); + publish_system_ha_sensor_config(DeviceValueType::STRING, "Uptime", "bootTime", DeviceValueUOM::TIMESTAMP); } // add sub or pub task to the queue. @@ -1065,11 +1065,17 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev char stat_t[MQTT_TOPIC_MAX_SIZE]; // This is where we determine which MQTT topic to pull the data from - // There is one exception for DeviceType::SYSTEM, which uses the heartbeat topic, and when fetching the version we want to take this from the info topic instead - if ((device_type == EMSdevice::DeviceType::SYSTEM) && (strncmp(entity, "version", 7) == 0)) { - snprintf(stat_t, sizeof(stat_t), "~/%s", F_(info)); - } else { - snprintf(stat_t, sizeof(stat_t), "~/%s", tag_to_topic(device_type, tag).c_str()); + // There are exceptions for DeviceType::SYSTEM, which uses the heartbeat topic + // and when fetching the version we want to take this from the info topic instead + if (device_type == EMSdevice::DeviceType::SYSTEM) { + // handle the exceptions + if (strncmp(entity, "version", 7) == 0) { + snprintf(stat_t, sizeof(stat_t), "~/%s", F_(info)); + } else if (strncmp(entity, "bootTime", 8) == 0) { + snprintf(stat_t, sizeof(stat_t), "~/%s", F_(info)); + } else { + snprintf(stat_t, sizeof(stat_t), "~/%s", tag_to_topic(device_type, tag).c_str()); + } } doc["stat_t"] = stat_t; @@ -1095,7 +1101,14 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // don't bother with value template conditions if using Domoticz which doesn't fully support MQTT Discovery if (discovery_type() == discoveryType::HOMEASSISTANT) { - doc["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + " else " + sample_val + "}}"; + if (uom == DeviceValueUOM::TIMESTAMP) { + // special case for timestamp, using "value_template": "{{ (value_json.bootTime | as_datetime).isoformat() }}", + char val_tpl[100]; + snprintf(val_tpl, sizeof(val_tpl), "{{ (value_json.%s | as_datetime).isoformat() }}", entity); + doc["val_tpl"] = val_tpl; + } else { + doc["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + " else " + sample_val + "}}"; + } add_ha_avty_section(doc.as(), stat_t, val_cond); // adds availability section } else { // Domoticz doesn't support value templates, so we just use the value directly @@ -1166,8 +1179,13 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 doc[uom_ha] = "L/h"; } else if (uom == DeviceValueUOM::L) { doc[uom_ha] = "L"; + } else if (uom == DeviceValueUOM::TIMESTAMP) { + // do nothing } else if (uom != DeviceValueUOM::NONE) { - doc[uom_ha] = EMSdevice::uom_to_string(uom); // use default + auto uom_str = EMSdevice::uom_to_string(uom); + if (strlen(uom_str)) { + doc[uom_ha] = uom_str; + } } else if (discovery_type() != discoveryType::HOMEASSISTANT) { doc[uom_ha] = " "; // Domoticz uses " " for a no-uom } @@ -1259,6 +1277,10 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "connectivity"; break; + case DeviceValueUOM::TIMESTAMP: + doc[sc_ha] = sc_ha_measurement; + doc[dc_ha] = "timestamp"; + break; case DeviceValueUOM::MV: case DeviceValueUOM::VOLTS: doc[sc_ha] = sc_ha_measurement;