From f1bb1830173f39bc3a8ff557d69e1ed407c41210 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 23 Sep 2022 21:54:13 +0200 Subject: [PATCH] ha config to basename, analog/dallas allow single/nested with ha --- src/analogsensor.cpp | 95 +++++++++++++++++++++++--------------------- src/dallassensor.cpp | 14 ++++--- src/mqtt.cpp | 58 ++++++++++++++------------- src/mqtt.h | 7 +++- 4 files changed, 93 insertions(+), 81 deletions(-) diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index e75d75d88..74f0e7392 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -26,9 +26,11 @@ uuid::log::Logger AnalogSensor::logger_{F_(analogsensor), uuid::log::Facility::D void AnalogSensor::start() { reload(); // fetch the list of sensors from our customization service - if (analog_enabled_) { - analogSetAttenuation(ADC_2_5db); // for all channels 1.5V + if (!analog_enabled_) { + return; } + analogSetAttenuation(ADC_2_5db); // for all channels 1.5V + LOG_INFO(F("Starting Analog sensor service")); @@ -354,7 +356,7 @@ void AnalogSensor::remove_ha_topic(const uint8_t gpio) const { LOG_DEBUG(F("Removing HA config for analog sensor GPIO %d"), gpio); #endif char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), gpio); + snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::basename().c_str(), gpio); Mqtt::publish_ha(topic); } @@ -376,8 +378,7 @@ void AnalogSensor::publish_values(const bool force) { for (auto & sensor : sensors_) { if (sensor.type() != AnalogType::NOTUSED) { - if (Mqtt::is_nested() || Mqtt::ha_enabled()) { - // nested + if (Mqtt::is_nested()) { char s[10]; JsonObject dataSensor = doc.createNestedObject(Helpers::smallitoa(s, sensor.gpio())); dataSensor["name"] = sensor.name(); @@ -395,51 +396,53 @@ void AnalogSensor::publish_values(const bool force) { dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0 break; } - - // create HA config - if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) { - LOG_DEBUG(F("Recreating HA config for analog sensor GPIO %d"), sensor.gpio()); - - StaticJsonDocument config; - - char stat_t[50]; - snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str()); - config["stat_t"] = stat_t; - - char str[50]; - snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.gpio()); - config["val_tpl"] = str; - - snprintf(str, sizeof(str), "analog_sensor_%s", sensor.name().c_str()); - config["object_id"] = str; - - snprintf(str, sizeof(str), "%s", sensor.name().c_str()); - config["name"] = str; - - snprintf(str, sizeof(str), "analogsensor_%d", sensor.gpio()); - config["uniq_id"] = str; - - if (sensor.uom() != DeviceValueUOM::NONE) { - config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom()); - } - - JsonObject dev = config.createNestedObject("dev"); - JsonArray ids = dev.createNestedArray("ids"); - ids.add("ems-esp"); - - char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), sensor.gpio()); - - Mqtt::publish_ha(topic, config.as()); - - sensor.ha_registered = true; - } - - } else { // not nested doc[sensor.name()] = sensor.value(); } + + // create HA config + if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) { + LOG_DEBUG(F("Recreating HA config for analog sensor GPIO %d"), sensor.gpio()); + + StaticJsonDocument config; + + char stat_t[50]; + snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str()); + config["stat_t"] = stat_t; + + char str[50]; + if (Mqtt::is_nested()) { + snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.gpio()); + } else { + snprintf(str, sizeof(str), "{{value_json['%s']}", sensor.name().c_str()); + } + config["val_tpl"] = str; + + snprintf(str, sizeof(str), "%s_analog_sensor_%s", Mqtt::basename().c_str(), sensor.name().c_str()); + config["object_id"] = str; + + snprintf(str, sizeof(str), "%s", sensor.name().c_str()); + config["name"] = str; + + snprintf(str, sizeof(str), "analogsensor_%d", sensor.gpio()); + config["uniq_id"] = str; + + if (sensor.uom() != DeviceValueUOM::NONE) { + config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom()); + } + + JsonObject dev = config.createNestedObject("dev"); + JsonArray ids = dev.createNestedArray("ids"); + ids.add("ems-esp"); + + char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::basename().c_str(), sensor.gpio()); + + Mqtt::publish_ha(topic, config.as()); + + sensor.ha_registered = true; + } } } diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index 030ad5474..2c18d6b36 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -447,7 +447,7 @@ void DallasSensor::remove_ha_topic(const std::string & id) { std::string sensorid = id; std::replace(sensorid.begin(), sensorid.end(), '-', '_'); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "sensor/%s/dallassensor_%s/config", Mqtt::base().c_str(), sensorid.c_str()); + snprintf(topic, sizeof(topic), "sensor/%s/dallassensor_%s/config", Mqtt::basename().c_str(), sensorid.c_str()); Mqtt::publish_ha(topic); } @@ -469,7 +469,7 @@ void DallasSensor::publish_values(const bool force) { for (auto & sensor : sensors_) { bool has_value = Helpers::hasValue(sensor.temperature_c); - if (Mqtt::is_nested() || Mqtt::ha_enabled()) { + if (Mqtt::is_nested()) { JsonObject dataSensor = doc.createNestedObject(sensor.id()); dataSensor["name"] = sensor.name(); if (has_value) { @@ -495,10 +495,14 @@ void DallasSensor::publish_values(const bool force) { config["unit_of_meas"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); char str[50]; - snprintf(str, sizeof(str), "{{value_json['%s'].temp}}", sensor.id().c_str()); + if (Mqtt::is_nested()) { + snprintf(str, sizeof(str), "{{value_json['%s'].temp}}", sensor.id().c_str()); + } else { + snprintf(str, sizeof(str), "{{value_json['%s']}}", sensor.name().c_str()); + } config["val_tpl"] = str; - snprintf(str, sizeof(str), "temperature_sensor_%s", sensor.name().c_str()); + snprintf(str, sizeof(str), "%s_temperature_sensor_%s", Mqtt::basename().c_str(), sensor.name().c_str()); config["object_id"] = str; snprintf(str, sizeof(str), "%s", sensor.name().c_str()); @@ -516,7 +520,7 @@ void DallasSensor::publish_values(const bool force) { std::string sensorid = sensor.id(); std::replace(sensorid.begin(), sensorid.end(), '-', '_'); - snprintf(topic, sizeof(topic), "sensor/%s/dallassensor_%s/config", Mqtt::base().c_str(), sensorid.c_str()); + snprintf(topic, sizeof(topic), "sensor/%s/dallassensor_%s/config", Mqtt::basename().c_str(), sensorid.c_str()); Mqtt::publish_ha(topic, config.as()); diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 898fd1cce..f7c07b8bd 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -26,8 +26,8 @@ namespace emsesp { AsyncMqttClient * Mqtt::mqttClient_; // static parameters we make global -std::string Mqtt::system_hostname_; // copy from System::hostname() std::string Mqtt::mqtt_base_; +std::string Mqtt::mqtt_basename_; uint8_t Mqtt::mqtt_qos_; bool Mqtt::mqtt_retain_; uint32_t Mqtt::publish_time_boiler_; @@ -213,7 +213,7 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) { // prefix base, only if it's not a discovery topic if (content->topic.compare(0, discovery_prefix().size(), discovery_prefix()) == 0) { - snprintf(topic, sizeof(topic), "%s/%s", Mqtt::base().c_str(), content->topic.c_str()); + snprintf(topic, sizeof(topic), "%s/%s", mqtt_base_.c_str(), content->topic.c_str()); } else { snprintf(topic, sizeof(topic), "%s", content->topic.c_str()); } @@ -422,8 +422,9 @@ void Mqtt::load_settings() { publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000; }); - // get a local copy of the system hostname - system_hostname_ = EMSESP::system_.hostname(); + // create basename from base + mqtt_basename_ = mqtt_base_; + std::replace(mqtt_basename_.begin(), mqtt_basename_.end(), '/', '_'); } void Mqtt::start() { @@ -580,13 +581,13 @@ void Mqtt::on_connect() { publish(F_(info), doc.as()); // topic called "info" if (ha_enabled_) { - LOG_INFO(F("start removing topics %s/+/%s/#"), discovery_prefix_.c_str(), system_hostname_.c_str()); - queue_unsubscribe_message(discovery_prefix_ + "/climate/" + system_hostname_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/sensor/" + system_hostname_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/binary_sensor/" + system_hostname_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/number/" + system_hostname_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/select/" + system_hostname_ + "/#"); - queue_unsubscribe_message(discovery_prefix_ + "/switch/" + system_hostname_ + "/#"); + LOG_INFO(F("start removing topics %s/+/%s/#"), discovery_prefix_.c_str(), mqtt_basename_.c_str()); + queue_unsubscribe_message(discovery_prefix_ + "/climate/" + mqtt_basename_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/sensor/" + mqtt_basename_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/binary_sensor/" + mqtt_basename_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/number/" + mqtt_basename_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/select/" + mqtt_basename_ + "/#"); + queue_unsubscribe_message(discovery_prefix_ + "/switch/" + mqtt_basename_ + "/#"); EMSESP::reset_mqtt_ha(); // re-create all HA devices if there are any ha_status(); // create the EMS-ESP device in HA, which is MQTT retained ha_climate_reset(true); @@ -595,12 +596,12 @@ void Mqtt::on_connect() { // In line 272 they are removed. If HA is enabled the subscriptions are removed. // As described in the doc (https://emsesp.github.io/docs/#/Troubleshooting?id=home-assistant): // disable HA, wait 5 minutes (to allow the broker to send all), than reenable HA again. - queue_subscribe_message(discovery_prefix_ + "/climate/" + system_hostname_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/sensor/" + system_hostname_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/binary_sensor/" + system_hostname_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/number/" + system_hostname_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/select/" + system_hostname_ + "/#"); - queue_subscribe_message(discovery_prefix_ + "/switch/" + system_hostname_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/climate/" + mqtt_basename_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/sensor/" + mqtt_basename_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/binary_sensor/" + mqtt_basename_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/number/" + mqtt_basename_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/select/" + mqtt_basename_ + "/#"); + queue_subscribe_message(discovery_prefix_ + "/switch/" + mqtt_basename_ + "/#"); } // send initial MQTT messages for some of our services @@ -649,7 +650,7 @@ void Mqtt::ha_status() { ids.add("ems-esp"); char topic[MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "sensor/%s/system/config", system_hostname_.c_str()); + snprintf(topic, sizeof(topic), "sensor/%s/system/config", mqtt_basename_.c_str()); Mqtt::publish_ha(topic, doc.as()); // publish the config payload with retain flag // create the sensors - must match the MQTT payload keys @@ -1017,28 +1018,28 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, case DeviceValueType::ULONG: // number - https://www.home-assistant.io/integrations/number.mqtt // https://developers.home-assistant.io/docs/core/entity/number - snprintf(topic, sizeof(topic), "number/%s/%s/config", system_hostname_.c_str(), uniq); + snprintf(topic, sizeof(topic), "number/%s/%s/config", mqtt_basename_.c_str(), uniq); break; case DeviceValueType::BOOL: // switch - https://www.home-assistant.io/integrations/switch.mqtt - snprintf(topic, sizeof(topic), "switch/%s/%s/config", system_hostname_.c_str(), uniq); + snprintf(topic, sizeof(topic), "switch/%s/%s/config", mqtt_basename_.c_str(), uniq); break; case DeviceValueType::ENUM: // select - https://www.home-assistant.io/integrations/select.mqtt - snprintf(topic, sizeof(topic), "select/%s/%s/config", system_hostname_.c_str(), uniq); + snprintf(topic, sizeof(topic), "select/%s/%s/config", mqtt_basename_.c_str(), uniq); break; default: // plain old sensor - snprintf(topic, sizeof(topic), "sensor/%s/%s/config", system_hostname_.c_str(), uniq); + snprintf(topic, sizeof(topic), "sensor/%s/%s/config", mqtt_basename_.c_str(), uniq); break; } } else { // plain old read only device entity if (type == DeviceValueType::BOOL) { - snprintf(topic, sizeof(topic), "binary_sensor/%s/%s/config", system_hostname_.c_str(), uniq); // binary sensor + snprintf(topic, sizeof(topic), "binary_sensor/%s/%s/config", mqtt_basename_.c_str(), uniq); // binary sensor } else { use_ha_sensor = true; - snprintf(topic, sizeof(topic), "sensor/%s/%s/config", system_hostname_.c_str(), uniq); // normal HA sensor, not a boolean one + snprintf(topic, sizeof(topic), "sensor/%s/%s/config", mqtt_basename_.c_str(), uniq); // normal HA sensor, not a boolean one } } @@ -1126,9 +1127,10 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // entity id is generated from the name, see https://www.home-assistant.io/docs/mqtt/discovery/#use-object_id-to-influence-the-entity-id // so we override it to make it unique using entity_id // See https://github.com/emsesp/EMS-ESP32/issues/596 - // "__ " + // "__ " + // with basename a single instance with "/" replaced by "_" char object_id[130]; - snprintf(object_id, sizeof(object_id), "%s_%s_%s", system_hostname_.c_str(), device_name, ha_name); + snprintf(object_id, sizeof(object_id), "%s_%s_%s", mqtt_basename_.c_str(), device_name, ha_name); doc["object_id"] = object_id; // value template @@ -1265,7 +1267,7 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove char min_s[10]; char max_s[10]; - snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::base().c_str(), hc_num); + snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", mqtt_basename_.c_str(), hc_num); if (remove) { publish_ha(topic); // publish empty payload with retain flag return; @@ -1305,7 +1307,7 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove StaticJsonDocument doc; - doc["~"] = base(); + doc["~"] = mqtt_base_; doc["object_id"] = id_s; doc["name"] = name_s; doc["uniq_id"] = uniq_id_s; diff --git a/src/mqtt.h b/src/mqtt.h index 6d107cb89..ac463586b 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -142,6 +142,10 @@ class Mqtt { return mqtt_base_; } + static std::string basename() { + return mqtt_basename_; + } + // returns the discovery MQTT topic prefix and adds a / static std::string discovery_prefix() { if (discovery_prefix_.empty()) { @@ -286,9 +290,8 @@ class Mqtt { static bool ha_climate_reset_; // settings, copied over - static std::string system_hostname_; - static std::string mqtt_base_; + static std::string mqtt_basename_; static uint8_t mqtt_qos_; static bool mqtt_retain_; static uint32_t publish_time_;