#759 use b ase in HA unique_id and object_id

This commit is contained in:
Proddy
2022-11-29 21:15:46 +01:00
parent 4103bad8de
commit 5b5dc6a8cc
3 changed files with 43 additions and 53 deletions

View File

@@ -454,13 +454,11 @@ void AnalogSensor::publish_values(const bool force) {
// snprintf(str, sizeof(str), "%s_analog_sensor_%s", Mqtt::basename().c_str(), sensor.name().c_str()); // snprintf(str, sizeof(str), "%s_analog_sensor_%s", Mqtt::basename().c_str(), sensor.name().c_str());
snprintf(str, sizeof(str), "analog_sensor_%d", sensor.gpio()); snprintf(str, sizeof(str), "analog_sensor_%d", sensor.gpio());
config["object_id"] = str; config["object_id"] = str;
config["uniq_id"] = str; // same as object_id
snprintf(str, sizeof(str), "%s", sensor.name().c_str()); snprintf(str, sizeof(str), "%s", sensor.name().c_str());
config["name"] = str; config["name"] = str;
snprintf(str, sizeof(str), "analogsensor_%d", sensor.gpio());
config["uniq_id"] = str;
if (sensor.uom() != DeviceValueUOM::NONE) { if (sensor.uom() != DeviceValueUOM::NONE) {
config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom()); config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom());
} }

View File

@@ -521,15 +521,14 @@ void DallasSensor::publish_values(const bool force) {
// snprintf(str, sizeof(str), "%s_temperature_sensor_%s", Mqtt::basename().c_str(), sensor.id().c_str()); // snprintf(str, sizeof(str), "%s_temperature_sensor_%s", Mqtt::basename().c_str(), sensor.id().c_str());
snprintf(str, sizeof(str), "temperature_sensor_%s", sensor.id().c_str()); snprintf(str, sizeof(str), "temperature_sensor_%s", sensor.id().c_str());
config["object_id"] = str; config["object_id"] = str;
config["uniq_id"] = str; // same as object_id
snprintf(str, sizeof(str), "%s", sensor.name().c_str()); snprintf(str, sizeof(str), "%s", sensor.name().c_str());
config["name"] = str; config["name"] = str;
snprintf(str, sizeof(str), "dallasensor_%s", sensor.id().c_str());
config["uniq_id"] = str; config["uniq_id"] = str;
JsonObject dev = config.createNestedObject("dev");
JsonObject dev = config.createNestedObject("dev"); JsonArray ids = dev.createNestedArray("ids");
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp"); ids.add("ems-esp");
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];

View File

@@ -591,12 +591,12 @@ void Mqtt::on_connect() {
void Mqtt::ha_status() { void Mqtt::ha_status() {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["uniq_id"] = "ems-esp-system"; doc["uniq_id"] = "ems-esp-system";
doc["~"] = mqtt_base_; // default ems-esp doc["object_id"] = "ems_esp_status";
doc["~"] = mqtt_base_; // default ems-esp
// doc["avty_t"] = "~/status"; // commented out, as it causes errors in HA sometimes // doc["avty_t"] = "~/status"; // commented out, as it causes errors in HA sometimes
// doc["json_attr_t"] = "~/heartbeat"; // store also as HA attributes // doc["json_attr_t"] = "~/heartbeat"; // store also as HA attributes
doc["stat_t"] = "~/status"; doc["stat_t"] = "~/status";
doc["object_id"] = "ems_esp_status";
doc["name"] = "EMS-ESP status"; doc["name"] = "EMS-ESP status";
doc["payload_on"] = "online"; doc["payload_on"] = "online";
doc["payload_off"] = "offline"; doc["payload_off"] = "offline";
@@ -950,21 +950,29 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
return; return;
} }
// create the device name // create the device name
auto device_name = EMSdevice::device_type_2_device_name(device_type); auto device_name = EMSdevice::device_type_2_device_name(device_type);
// create entity by add the hc/wwc tag if present, separating with a . // create entity by add the hc/wwc tag if present, separating with a .
char new_entity[50]; char entity_with_tag[50];
if (tag >= DeviceValueTAG::TAG_HC1) { if (tag >= DeviceValueTAG::TAG_HC1) {
snprintf(new_entity, sizeof(new_entity), "%s.%s", EMSdevice::tag_to_mqtt(tag).c_str(), entity); snprintf(entity_with_tag, sizeof(entity_with_tag), "%s.%s", EMSdevice::tag_to_mqtt(tag).c_str(), entity);
} else { } else {
snprintf(new_entity, sizeof(new_entity), "%s", entity); snprintf(entity_with_tag, sizeof(entity_with_tag), "%s", entity);
} }
// build unique identifier which will be used in the topic, replacing all . with _ as not to break HA // build unique identifier which will be used in the topic, also used as object_id
char uniq[101]; char uniq_id[70];
snprintf(uniq, sizeof(uniq), "%s_%s", device_name, new_entity); snprintf(uniq_id, sizeof(uniq_id), "%s_%s_%s", mqtt_basename_.c_str(), device_name, entity_with_tag);
Helpers::replace_char(uniq, '.', '_'); Helpers::replace_char(uniq_id, '.', '_'); // replacing all . with _ as not to break HA
// build a config topic that will be prefix onto a HA type (e.g. number, switch)
// e.g. homeassistant/number/ems-esp/thermostat_hc1_manualtemp
char config_topic[70];
snprintf(config_topic, sizeof(config_topic), "%s/%s_%s/config", mqtt_basename_.c_str(), device_name, entity_with_tag);
Helpers::replace_char(config_topic, '.', '_'); // replacing all . with _ as not to break HA
bool set_ha_classes = false; // set to true if we want to set the state class and device class bool set_ha_classes = false; // set to true if we want to set the state class and device class
@@ -981,19 +989,19 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
case DeviceValueType::ULONG: case DeviceValueType::ULONG:
// number - https://www.home-assistant.io/integrations/number.mqtt // number - https://www.home-assistant.io/integrations/number.mqtt
// https://developers.home-assistant.io/docs/core/entity/number // https://developers.home-assistant.io/docs/core/entity/number
snprintf(topic, sizeof(topic), "number/%s/%s/config", mqtt_basename_.c_str(), uniq); snprintf(topic, sizeof(topic), "number/%s", config_topic);
break; break;
case DeviceValueType::BOOL: case DeviceValueType::BOOL:
// switch - https://www.home-assistant.io/integrations/switch.mqtt // switch - https://www.home-assistant.io/integrations/switch.mqtt
snprintf(topic, sizeof(topic), "switch/%s/%s/config", mqtt_basename_.c_str(), uniq); snprintf(topic, sizeof(topic), "switch/%s", config_topic);
break; break;
case DeviceValueType::ENUM: case DeviceValueType::ENUM:
// select - https://www.home-assistant.io/integrations/select.mqtt // select - https://www.home-assistant.io/integrations/select.mqtt
snprintf(topic, sizeof(topic), "select/%s/%s/config", mqtt_basename_.c_str(), uniq); snprintf(topic, sizeof(topic), "select/%s", config_topic);
break; break;
default: default:
// plain old sensor // plain old sensor
snprintf(topic, sizeof(topic), "sensor/%s/%s/config", mqtt_basename_.c_str(), uniq); snprintf(topic, sizeof(topic), "sensor/%s", config_topic);
break; break;
} }
} else { } else {
@@ -1001,26 +1009,25 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
set_ha_classes = true; set_ha_classes = true;
// plain old read only device entity // plain old read only device entity
if (type == DeviceValueType::BOOL) { if (type == DeviceValueType::BOOL) {
snprintf(topic, sizeof(topic), "binary_sensor/%s/%s/config", mqtt_basename_.c_str(), uniq); // binary sensor (for booleans) snprintf(topic, sizeof(topic), "binary_sensor/%s", config_topic); // binary sensor (for booleans)
} else { } else {
snprintf(topic, sizeof(topic), "sensor/%s/%s/config", mqtt_basename_.c_str(), uniq); // normal HA sensor snprintf(topic, sizeof(topic), "sensor/%s", config_topic); // normal HA sensor
} }
} }
// if we're asking to remove this topic, send an empty payload and exit // if we're asking to remove this topic, send an empty payload and exit
// https://github.com/emsesp/EMS-ESP32/issues/196 // https://github.com/emsesp/EMS-ESP32/issues/196
if (remove) { if (remove) {
LOG_DEBUG("Removing HA config for %s", uniq); LOG_DEBUG("Removing HA config for %s", uniq_id);
publish_ha(topic); publish_ha(topic);
return; return;
} }
bool have_tag = !EMSdevice::tag_to_string(tag).empty();
// build the payload // build the payload
DynamicJsonDocument doc(EMSESP_JSON_SIZE_HA_CONFIG); DynamicJsonDocument doc(EMSESP_JSON_SIZE_HA_CONFIG);
doc["~"] = mqtt_base_; doc["~"] = mqtt_base_;
doc["uniq_id"] = uniq; doc["uniq_id"] = uniq_id;
doc["object_id"] = uniq_id; // same as unique_id
const char * ic_ha = "ic"; // icon - only set this if there is no device class const char * ic_ha = "ic"; // icon - only set this if there is no device class
const char * sc_ha = "state_class"; // state class const char * sc_ha = "state_class"; // state class
@@ -1031,8 +1038,8 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// note: there is no way to handle strings in HA so datetimes (e.g. set_datetime, set_holiday, set_wwswitchtime etc) are excluded // note: there is no way to handle strings in HA so datetimes (e.g. set_datetime, set_holiday, set_wwswitchtime etc) are excluded
if (has_cmd) { if (has_cmd) {
// command topic back to EMS-ESP // command topic back to EMS-ESP
char command_topic[105]; char command_topic[MQTT_TOPIC_MAX_SIZE];
snprintf(command_topic, sizeof(command_topic), "~/%s", uniq); snprintf(command_topic, sizeof(command_topic), "~/%s", uniq_id);
Helpers::replace_char(command_topic, '_', '/'); Helpers::replace_char(command_topic, '_', '/');
doc["command_topic"] = command_topic; doc["command_topic"] = command_topic;
@@ -1082,31 +1089,19 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
char ha_name[70]; char ha_name[70];
char * F_name = strdup(fullname); char * F_name = strdup(fullname);
F_name[0] = toupper(F_name[0]); // capitalize first letter F_name[0] = toupper(F_name[0]); // capitalize first letter
if (have_tag) { if (EMSdevice::tag_to_string(tag).empty()) {
snprintf(ha_name, sizeof(ha_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), F_name);
} else {
snprintf(ha_name, sizeof(ha_name), "%s", F_name); snprintf(ha_name, sizeof(ha_name), "%s", F_name);
}
free(F_name);
doc["name"] = ha_name;
// 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
// keep it compatible to v3.4, use english fullname, no prefix (basename prefix commented out)
char object_id[130];
if (have_tag) {
snprintf(object_id, sizeof(object_id), "%s_%s_%s", device_name, EMSdevice::tag_to_string(tag, false).c_str(), en_name);
} else { } else {
snprintf(object_id, sizeof(object_id), "%s_%s", device_name, en_name); snprintf(ha_name, sizeof(ha_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), F_name);
} }
doc["object_id"] = object_id; free(F_name); // very important!
doc["name"] = ha_name;
// value template // value template
// if its nested mqtt format then use the appended entity name, otherwise take the original // if its nested mqtt format then use the appended entity name, otherwise take the original
char val_tpl[75]; char val_tpl[75];
if (is_nested()) { if (is_nested()) {
snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", new_entity); snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", entity_with_tag);
} else { } else {
snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", entity); snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", entity);
} }
@@ -1230,8 +1225,7 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
char currtemp_s[30]; char currtemp_s[30];
char mode_str_tpl[400]; char mode_str_tpl[400];
char name_s[10]; char name_s[10];
char id_s[20]; char uniq_id_s[60];
char uniq_id_s[30];
char temp_cmd_s[30]; char temp_cmd_s[30];
char mode_cmd_s[30]; char mode_cmd_s[30];
char min_s[10]; char min_s[10];
@@ -1269,18 +1263,17 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
hc_mode_s, hc_mode_s,
hc_mode_s); hc_mode_s);
snprintf(id_s, sizeof(id_s), "thermostat_hc%d", hc_num);
snprintf(name_s, sizeof(name_s), "Hc%d", hc_num); snprintf(name_s, sizeof(name_s), "Hc%d", hc_num);
snprintf(uniq_id_s, sizeof(uniq_id_s), "thermostat_hc%d", hc_num); snprintf(uniq_id_s, sizeof(uniq_id_s), "%s_thermostat_hc%d", mqtt_basename_.c_str(), hc_num); // add basename
snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num); snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num);
snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num); snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num);
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["~"] = mqtt_base_; doc["~"] = mqtt_base_;
doc["object_id"] = id_s;
doc["name"] = name_s;
doc["uniq_id"] = uniq_id_s; doc["uniq_id"] = uniq_id_s;
doc["object_id"] = uniq_id_s; // same as uniq_id
doc["name"] = name_s;
doc["mode_stat_t"] = topic_t; doc["mode_stat_t"] = topic_t;
doc["mode_stat_tpl"] = mode_str_tpl; doc["mode_stat_tpl"] = mode_str_tpl;
doc["temp_cmd_t"] = temp_cmd_s; doc["temp_cmd_t"] = temp_cmd_s;