From 41a2ba6e5dd0eaed5b261c259b6f958402b99859 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 9 Jun 2025 16:07:26 +0200 Subject: [PATCH] fixes #2579 --- src/core/analogsensor.cpp | 7 +- src/core/emsdevice.cpp | 6 +- src/core/mqtt.cpp | 168 ++++++++++++++--------------- src/core/mqtt.h | 26 ++--- src/core/shower.cpp | 9 +- src/core/temperaturesensor.cpp | 3 +- src/web/WebCustomEntityService.cpp | 23 ++-- src/web/WebSchedulerService.cpp | 5 +- 8 files changed, 128 insertions(+), 119 deletions(-) diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index ff3d7baf8..c3344d598 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -631,7 +631,7 @@ void AnalogSensor::publish_values(const bool force) { snprintf(topic, sizeof(topic), "switch/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::base().c_str(), F_(analogsensor), sensor.name().c_str()); config["cmd_t"] = command_topic; - Mqtt::add_ha_bool(config); + Mqtt::add_ha_bool(config.as()); } else if (sensor.type() == AnalogType::DIGITAL_OUT) { // DAC snprintf(topic, sizeof(topic), "number/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::base().c_str(), F_(analogsensor), sensor.name().c_str()); @@ -665,7 +665,7 @@ void AnalogSensor::publish_values(const bool force) { // config["step"] = sensor.factor(); } else if (sensor.type() == AnalogType::DIGITAL_IN) { snprintf(topic, sizeof(topic), "binary_sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); - Mqtt::add_ha_bool(config); + Mqtt::add_ha_bool(config.as()); } else { snprintf(topic, sizeof(topic), "sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); config["stat_cla"] = "measurement"; @@ -680,7 +680,8 @@ void AnalogSensor::publish_values(const bool force) { } } - Mqtt::add_ha_sections_to_doc("analog", stat_t, config, !is_ha_device_created, val_cond); + Mqtt::add_ha_dev_section(config.as(), "Analog Sensors", nullptr, nullptr, false); + Mqtt::add_ha_avail_section(config.as(), stat_t, !is_ha_device_created, val_cond); sensor.ha_registered = Mqtt::queue_ha(topic, config.as()); } diff --git a/src/core/emsdevice.cpp b/src/core/emsdevice.cpp index bfd8f6fa9..57f3ef4b8 100644 --- a/src/core/emsdevice.cpp +++ b/src/core/emsdevice.cpp @@ -1221,7 +1221,7 @@ void EMSdevice::setCustomizationEntity(const std::string & entity_id) { if (Mqtt::ha_enabled() && (has_custom_name || ((current_mask ^ new_mask) & (DeviceValueState::DV_READONLY >> 4)))) { // remove ha config on change of dv_readonly flag dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED); - Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true) + Mqtt::publish_ha_sensor_config_dv(dv, "", "", true); // delete topic (remove = true) } // always write the mask @@ -1673,7 +1673,7 @@ void EMSdevice::get_value_json(JsonObject json, DeviceValue & dv) { } // add uom, state class and device class - Mqtt::add_ha_uom(json, dv.type, dv.uom, dv.short_name, false); // no icon + Mqtt::add_ha_classes(json, device_type(), dv.type, dv.uom, dv.short_name, false); // no icon json["readable"] = dv.type != DeviceValueType::CMD && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE); json["writeable"] = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY); @@ -1886,7 +1886,7 @@ void EMSdevice::mqtt_ha_entity_config_create() { if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && dv.has_state(DeviceValueState::DV_ACTIVE) && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) { // create_device_config is only done once for the EMS device. It can added to any entity, so we take the first - if (Mqtt::publish_ha_sensor_config(dv, name().c_str(), brand_to_char(), false, create_device_config)) { + if (Mqtt::publish_ha_sensor_config_dv(dv, name().c_str(), brand_to_char(), false, create_device_config)) { dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); create_device_config = false; // only create the main config once count++; diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index 4df7d1638..7b2e4701c 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -744,39 +744,17 @@ bool Mqtt::queue_ha(const char * topic, const JsonObjectConst payload) { return queue_publish_message(Mqtt::discovery_prefix() + topic, payload_text, true); // with retain true } -// create's a ha sensor config topic from a device value object +// create's a ha sensor config topic from a device value object (dev) +// adds ids, name, mf, mdl, via_device // and also takes a flag (create_device_config) used to also create the main HA device config. This is only needed for one entity -bool Mqtt::publish_ha_sensor_config(DeviceValue & dv, const char * model, const char * brand, const bool remove, const bool create_device_config) { - JsonDocument dev_json; - - // always create the ids (discovery identifiers) - // with the name always - // and the manufacturer and model if we're creating the device config for the first entity - JsonArray ids = dev_json["ids"].to(); - char ha_device[40]; - auto device_type_name = EMSdevice::device_type_2_device_name(dv.device_type); - snprintf(ha_device, sizeof(ha_device), "%s-%s", Mqtt::basename().c_str(), device_type_name); - ids.add(ha_device); - - auto cap_name = strdup(device_type_name); - Helpers::CharToUpperUTF8(cap_name); // capitalize first letter - dev_json["name"] = Mqtt::basename() + " " + cap_name; - free(cap_name); - - // create only once per category - if (create_device_config) { - dev_json["mf"] = brand; - dev_json["mdl"] = model; - dev_json["via_device"] = Mqtt::basename(); - } - +bool Mqtt::publish_ha_sensor_config_dv(DeviceValue & dv, const char * model, const char * brand, const bool remove, const bool create_device_config) { // calculate the min and max int16_t dv_set_min; uint32_t dv_set_max; (void)dv.get_min_max(dv_set_min, dv_set_max); // determine if we're creating the command topics which we use special HA configs - // unless the entity has been marked as read-only and so it'll default to using the sensor/ type + // if the entity has been marked as read-only it'll be created as a binary_sensor or sensor // or we're dealing with Energy sensors that must have "diagnostic" as an entity category (e.g. negheat & nrgww) bool has_cmd = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY) && (dv.uom != DeviceValueUOM::KWH); @@ -794,20 +772,14 @@ bool Mqtt::publish_ha_sensor_config(DeviceValue & dv, const char * model, const dv_set_min, dv_set_max, dv.numeric_operator, - dev_json.as()); + model, + brand, + create_device_config); } -// publish HA sensor for System using the heartbeat tag +// publish HA sensor specific for System using the heartbeat tag bool Mqtt::publish_system_ha_sensor_config(uint8_t type, const char * name, const char * entity, const uint8_t uom) { - JsonDocument doc; - JsonObject dev_json = doc["dev"].to(); - - dev_json["name"] = Mqtt::basename(); - JsonArray ids = dev_json["ids"].to(); - ids.add(Mqtt::basename()); - - return publish_ha_sensor_config( - type, DeviceValueTAG::TAG_DEVICE_DATA, name, name, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, nullptr, 0, 0, 0, 0, dev_json); + return publish_ha_sensor_config(type, DeviceValueTAG::TAG_DEVICE_DATA, name, name, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, nullptr, 0, 0, 0, 0); } // MQTT discovery configs @@ -827,7 +799,9 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev const int16_t dv_set_min, const uint32_t dv_set_max, const int8_t num_op, - const JsonObjectConst dev_json) { + const char * const model, + const char * const brand, + const bool create_device_config) { // ignore if name (fullname) is empty if (!fullname || !en_name) { return false; @@ -984,8 +958,10 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev } // if at this point we don't have a topic created yet, create a default sensor one. We always need a topic. + bool is_sensor = false; if (!strnlen(topic, sizeof(topic))) { snprintf(topic, sizeof(topic), (type == DeviceValueType::BOOL) ? "binary_sensor/%s" : "sensor/%s", config_topic); // binary sensor (for booleans) + is_sensor = true; } // if we're asking to remove this topic, send an empty payload and exit @@ -995,7 +971,7 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev return queue_remove_topic(topic); } - // build the payload + // build the full payload JsonDocument doc; doc["uniq_id"] = uniq_id; doc["obj_id"] = uniq_id; // same as unique_id @@ -1065,8 +1041,8 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev free(F_name); // very important! doc["name"] = ha_name; - // not needed for commands - if (type != DeviceValueType::CMD) { + // add state_topic and it's value_template. This is not needed for commands, only sensors + if (type != DeviceValueType::CMD || is_sensor) { // state topic, except for commands char stat_t[MQTT_TOPIC_MAX_SIZE]; @@ -1095,7 +1071,7 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // applies to both Binary Sensor (read only) and a Switch (for a command) // has no unit of measure or icon, and must be true/false (not on/off or 1/0) if (type == DeviceValueType::BOOL) { - add_ha_bool(doc); + add_ha_bool(doc.as()); strlcpy(sample_val, "false", sizeof(sample_val)); // default is "false" } @@ -1105,7 +1081,7 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // adds availability, dev, ids to the config section to HA Discovery config // except for commands - add_ha_sections_to_doc(nullptr, stat_t, doc, false, val_cond); // no name, since the "dev" has already been added + add_ha_avail_section(doc.as(), stat_t, false, val_cond); } else { // Domoticz doesn't support value templates, so we just use the value directly // Also omit the uom and other state classes @@ -1116,18 +1092,24 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // Add the state class, device class and an optional icon based on the uom // first set the catagory for System entities // https://github.com/emsesp/EMS-ESP32/discussions/1459#discussioncomment-7694873 - if (device_type == EMSdevice::DeviceType::SYSTEM) { - doc["ent_cat"] = "diagnostic"; // instead of config - } - add_ha_uom(doc.as(), type, uom, entity); + add_ha_classes(doc.as(), device_type, type, uom, entity); - doc["dev"] = dev_json; + // add dev section + if (device_type == EMSdevice::DeviceType::SYSTEM) { + add_ha_dev_section(doc.as(), nullptr, nullptr, nullptr, false); + } else { + add_ha_dev_section(doc.as(), EMSdevice::device_type_2_device_name(device_type), model, brand, create_device_config); + } return queue_ha(topic, doc.as()); } // Add the uom, state class, device class and an optional icon based on the uom -void Mqtt::add_ha_uom(JsonObject doc, const uint8_t type, const uint8_t uom, const char * entity, bool is_discovery) { +void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity, bool is_discovery) { + if (device_type == EMSdevice::DeviceType::SYSTEM) { + doc["ent_cat"] = "diagnostic"; // instead of 'config' + } + // for HA discovery we use different namings const char * dc_ha = is_discovery ? "dev_cla" : "device_class"; // device class const char * sc_ha = is_discovery ? "stat_cla" : "state_class"; // state class @@ -1145,8 +1127,7 @@ void Mqtt::add_ha_uom(JsonObject doc, const uint8_t type, const uint8_t uom, con } else if (uom != DeviceValueUOM::NONE) { doc[uom_ha] = EMSdevice::uom_to_string(uom); // use default } else if (discovery_type() != discoveryType::HOMEASSISTANT) { - // Domoticz use " " for a no-uom - doc[uom_ha] = " "; + doc[uom_ha] = " "; // Domoticz uses " " for a no-uom } } @@ -1353,8 +1334,8 @@ bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, modes.add("heat"); modes.add("off"); - // device name must be different to the entity name, take the ids value we just created - add_ha_sections_to_doc("thermostat", topic_t, doc, false, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); + add_ha_dev_section(doc.as(), "thermostat", nullptr, nullptr, false); // add dev section + add_ha_avail_section(doc.as(), topic_t, false, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); // add availability section return queue_ha(topic, doc.as()); // publish the config payload with retain flag } @@ -1378,34 +1359,52 @@ std::string Mqtt::tag_to_topic(uint8_t device_type, int8_t tag) { } } -// adds availability, dev, ids to the config section to HA Discovery config -void Mqtt::add_ha_sections_to_doc(const char * name, - const char * state_t, - JsonDocument & config, - const bool is_first, - const char * cond1, - const char * cond2, - const char * negcond) { - // only for HA +// add devs section to an existing doc, only for HA +// under devs node it will create ids and name and optional mf, mdl, via_device +// name could be EMSdevice::device_type_2_device_name(dv.device_type)); +void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const char * model, const char * brand, const bool create_model) { + // only works for HA if (discovery_type() != discoveryType::HOMEASSISTANT) { return; } - // adds dev section to HA Discovery config + // create dev section + JsonObject dev_json = doc["dev"].to(); + + // add ids and name - with capitalize first letter + JsonArray ids = dev_json["ids"].to(); // ids, it is an array with a single element if (name != nullptr) { - JsonObject dev = config["dev"].to(); - char * cap_name = strdup(name); - cap_name[0] = toupper(name[0]); // capitalize first letter - dev["name"] = std::string(Mqtt::basename()) + " " + cap_name; - // if it's the first in the category, attach the group to the main HA device - if (is_first) { - dev["mf"] = "EMS-ESP"; - dev["mdl"] = cap_name; - dev["via_device"] = Mqtt::basename(); - } - JsonArray ids = dev["ids"].to(); - ids.add(Mqtt::basename() + "-" + Helpers::toLower(name)); + // for ids, replace all spaces with - + std::string lower_name_str(name); + std::replace(lower_name_str.begin(), lower_name_str.end(), ' ', '-'); + ids.add(Mqtt::basename() + "-" + Helpers::toLower(lower_name_str)); + + auto cap_name = strdup(name); + Helpers::CharToUpperUTF8(cap_name); // capitalize first letter + dev_json["name"] = Mqtt::basename() + " " + cap_name; free(cap_name); + } else { + ids.add(Mqtt::basename()); + dev_json["name"] = Mqtt::basename(); + } + + // this is used to only create it once when entities are dynamically added + if (create_model) { + dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP"; + if (model != nullptr) { + dev_json["mdl"] = model; + } + dev_json["via_device"] = Mqtt::basename(); + } +} + +// adds sections for HA Discovery to an existing JSON doc +// adds dev section with ids, name, mf, mdl, via_device +// adds optional availability section +void Mqtt::add_ha_avail_section(JsonObject doc, const char * state_t, const bool is_first, const char * cond1, const char * cond2, const char * negcond) { + // only works for HA + if (discovery_type() != discoveryType::HOMEASSISTANT) { + return; } // skip availability section if no conditions set @@ -1414,7 +1413,7 @@ void Mqtt::add_ha_sections_to_doc(const char * name, } // adds "availability" section to HA Discovery config - JsonArray avty = config["avty"].to(); + JsonArray avty = doc["avty"].to(); JsonDocument avty_json; // make local copy of state, as the pointer will get de-referenced @@ -1451,22 +1450,23 @@ void Mqtt::add_ha_sections_to_doc(const char * name, avty.add(avty_json); // returns 0 if no mem } - config["avty_mode"] = "all"; + doc["avty_mode"] = "all"; } -void Mqtt::add_ha_bool(JsonDocument & config) { +// adds the pl_on and pl_off sections to the doc +void Mqtt::add_ha_bool(JsonObject doc) { const char * pl_on = "pl_on"; const char * pl_off = "pl_off"; if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { - config[pl_on] = true; - config[pl_off] = false; + doc[pl_on] = true; + doc[pl_off] = false; } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { - config[pl_on] = 1; - config[pl_off] = 0; + doc[pl_on] = 1; + doc[pl_off] = 0; } else { char result[12]; - config[pl_on] = Helpers::render_boolean(result, true); - config[pl_off] = Helpers::render_boolean(result, false); + doc[pl_on] = Helpers::render_boolean(result, true); + doc[pl_off] = Helpers::render_boolean(result, false); } } diff --git a/src/core/mqtt.h b/src/core/mqtt.h index b45118b67..9d936a802 100644 --- a/src/core/mqtt.h +++ b/src/core/mqtt.h @@ -85,7 +85,7 @@ class Mqtt { static bool queue_ha(const char * topic, const JsonObjectConst payload); static bool queue_remove_topic(const char * topic); - static bool publish_ha_sensor_config(DeviceValue & dv, const char * model, const char * brand, const bool remove, const bool create_device_config = false); + static bool publish_ha_sensor_config_dv(DeviceValue & dv, const char * model, const char * brand, const bool remove, const bool create_device_config = false); static bool publish_ha_sensor_config(uint8_t type, int8_t tag, const char * const fullname, @@ -100,7 +100,9 @@ class Mqtt { const int16_t dv_set_min, const uint32_t dv_set_max, const int8_t num_op, - const JsonObjectConst dev_json); + const char * const model = nullptr, + const char * const brand = nullptr, + const bool create_device_config = false); static bool publish_system_ha_sensor_config(uint8_t type, const char * name, const char * entity, const uint8_t uom); static bool publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, const bool remove = false, const int16_t min = 5, const uint32_t max = 30); @@ -243,16 +245,16 @@ class Mqtt { static std::string tag_to_topic(uint8_t device_type, int8_t tag); - static void add_ha_uom(JsonObject doc, const uint8_t type, const uint8_t uom, const char * entity = nullptr, bool is_discovery = true); - - static void add_ha_sections_to_doc(const char * name, - const char * state_t, - JsonDocument & config, - const bool is_first = false, - const char * cond1 = nullptr, - const char * cond2 = nullptr, - const char * negcond = nullptr); - static void add_ha_bool(JsonDocument & config); + static void + add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity = nullptr, bool is_discovery = true); + static void add_ha_dev_section(JsonObject doc, const char * name, const char * model, const char * brand, const bool create_model); + static void add_ha_avail_section(JsonObject doc, + const char * state_t, + const bool is_first, + const char * cond1 = nullptr, + const char * cond2 = nullptr, + const char * negcond = nullptr); + static void add_ha_bool(JsonObject doc); private: static uuid::log::Logger logger_; diff --git a/src/core/shower.cpp b/src/core/shower.cpp index d7529e807..912a6b786 100644 --- a/src/core/shower.cpp +++ b/src/core/shower.cpp @@ -211,9 +211,9 @@ void Shower::create_ha_discovery() { snprintf(stat_t, sizeof(stat_t), "%s/shower_active", Mqtt::base().c_str()); doc["stat_t"] = stat_t; - Mqtt::add_ha_bool(doc); - - Mqtt::add_ha_sections_to_doc("shower", stat_t, doc, true); // create first dev & ids, no conditions + Mqtt::add_ha_bool(doc.as()); + Mqtt::add_ha_dev_section(doc.as(), "Shower Sensor", nullptr, nullptr, false); + Mqtt::add_ha_avail_section(doc.as(), stat_t, true); // no conditions snprintf(topic, sizeof(topic), "binary_sensor/%s/shower_active/config", Mqtt::basename().c_str()); ha_configdone_ = Mqtt::queue_ha(topic, doc.as()); // publish the config payload with retain flag @@ -243,7 +243,8 @@ void Shower::create_ha_discovery() { doc["dev_cla"] = "duration"; // doc["ent_cat"] = "diagnostic"; - Mqtt::add_ha_sections_to_doc("shower", stat_t, doc, false, "value_json.duration is defined"); + Mqtt::add_ha_dev_section(doc.as(), "Shower Sensor", nullptr, nullptr, false); + Mqtt::add_ha_avail_section(doc.as(), stat_t, false, "value_json.duration is defined"); snprintf(topic, sizeof(topic), "sensor/%s/shower_duration/config", Mqtt::basename().c_str()); Mqtt::queue_ha(topic, doc.as()); // publish the config payload with retain flag diff --git a/src/core/temperaturesensor.cpp b/src/core/temperaturesensor.cpp index 02769cdc8..305639786 100644 --- a/src/core/temperaturesensor.cpp +++ b/src/core/temperaturesensor.cpp @@ -520,7 +520,8 @@ void TemperatureSensor::publish_values(const bool force) { } } - Mqtt::add_ha_sections_to_doc("temperature", stat_t, config, !is_ha_device_created, val_cond); + Mqtt::add_ha_dev_section(config.as(), "Temperature Sensors", nullptr, nullptr, false); + Mqtt::add_ha_avail_section(config.as(), stat_t, !is_ha_device_created, val_cond); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; snprintf(topic, sizeof(topic), "sensor/%s/%s_%s/config", Mqtt::basename().c_str(), F_(temperaturesensor), sensor.id().c_str()); diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index 2b1e4f20c..2bd4ed86e 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -326,15 +326,14 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) // build the json for specific entity void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem & entity) { - output["name"] = entity.name; - output["fullname"] = entity.name; - output["storage"] = entity.ram ? "ram" : "ems"; - output["type"] = entity.value_type == DeviceValueType::BOOL ? "boolean" : entity.value_type == DeviceValueType::STRING ? "string" : F_(number); - // add uom state class and device class - Mqtt::add_ha_uom(output, entity.value_type, entity.uom, nullptr, false); + output["name"] = entity.name; + output["fullname"] = entity.name; + output["storage"] = entity.ram ? "ram" : "ems"; + output["type"] = entity.value_type == DeviceValueType::BOOL ? "boolean" : entity.value_type == DeviceValueType::STRING ? "string" : F_(number); output["readable"] = true; output["writeable"] = entity.writeable; output["visible"] = true; + if (entity.ram == 0) { output["device_id"] = Helpers::hextoa(entity.device_id); output["type_id"] = Helpers::hextoa(entity.type_id); @@ -345,6 +344,10 @@ void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem output["bytes"] = (uint8_t)entity.factor; } } + + // add uom state class and device class + Mqtt::add_ha_classes(output, EMSdevice::DeviceType::SYSTEM, entity.value_type, entity.uom, nullptr, false); + render_value(output, entity, true); // create the "value" field } @@ -445,12 +448,12 @@ void WebCustomEntityService::publish(const bool force) { if (entityItem.value_type == DeviceValueType::BOOL) { // applies to both Binary Sensor (read only) and a Switch (for a command) - Mqtt::add_ha_bool(config); + Mqtt::add_ha_bool(config.as()); } - Mqtt::add_ha_uom(config.as(), entityItem.value_type, entityItem.uom); // add uom - - Mqtt::add_ha_sections_to_doc(F_(custom), stat_t, config, !ha_created, val_cond); + Mqtt::add_ha_classes(config.as(), EMSdevice::DeviceType::SYSTEM, entityItem.value_type, entityItem.uom); + Mqtt::add_ha_dev_section(config.as(), "Custom Entities", nullptr, nullptr, false); + Mqtt::add_ha_avail_section(config.as(), stat_t, !ha_created, val_cond); ha_created |= Mqtt::queue_ha(topic, config.as()); } diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 3807b3503..ef519cc31 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -287,8 +287,9 @@ void WebSchedulerService::publish(const bool force) { snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::base().c_str(), F_(scheduler), scheduleItem.name.c_str()); config["cmd_t"] = command_topic; - Mqtt::add_ha_bool(config); - Mqtt::add_ha_sections_to_doc(F_(scheduler), stat_t, config, !ha_created, val_cond); + Mqtt::add_ha_bool(config.as()); + Mqtt::add_ha_dev_section(config.as(), F_(scheduler), nullptr, nullptr, false); + Mqtt::add_ha_avail_section(config.as(), stat_t, !ha_created, val_cond); ha_created |= Mqtt::queue_ha(topic, config.as()); }