diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 2249b9158..b9f9cd22f 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -5,7 +5,7 @@ ## **IMPORTANT! BREAKING CHANGES** - When upgrading to v3.5 for the first time from v3.4 on a BBQKees Gateway board you will need to use the [EMS-EPS Flasher](https://github.com/emsesp/EMS-ESP-Flasher/releases) to correctly re-partition the flash. Make sure you backup the settings and customizations from the WebUI (System->Upload/Download) and restore after the upgrade. -- Since 3.5.0b11 we have added support for multiple EMS-ESPs [#759] and also renamed the HA Entity IDs. For example what was previously `sensor.boiler_actual_boiler_temperature` is now using the shortname form `sensor.boiler_boiltemp` as opposed to the English description. Unfortunately this does means any HA dashboards, automation scripts and integrations (e.g. Grafana) need to be adjusted accordingly. +- Since 3.5.0b11 we have added support for multiple EMS-ESPs [#759] as an optional setting in MQTT. When this is enabled, which is now the default, all MQTT Discovery Entity IDs will include the base name and the shortname of the EMS-ESP device entity. For example what was previously `sensor.boiler_actual_boiler_temperature` will become `sensor.ems-esp_boiler_boiltemp`. If you still want to use the old format and retain the history and script compatibility in Home Assistant then set this back to the old format. ## Added diff --git a/interface/src/framework/mqtt/MqttSettingsForm.tsx b/interface/src/framework/mqtt/MqttSettingsForm.tsx index 85f468771..ef78c8436 100644 --- a/interface/src/framework/mqtt/MqttSettingsForm.tsx +++ b/interface/src/framework/mqtt/MqttSettingsForm.tsx @@ -245,8 +245,8 @@ const MqttSettingsForm: FC = () => { margin="normal" select > - {LL.MQTT_ENTITY_FORMAT_0()} - {LL.MQTT_ENTITY_FORMAT_1()} + {LL.MQTT_ENTITY_FORMAT_0()} + {LL.MQTT_ENTITY_FORMAT_1()} diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index f480b9c51..5ee053fca 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -250,7 +250,7 @@ const de: Translation = { MQTT_QUEUE: 'MQTT Queue', DEFAULT: 'Standard', MQTT_ENTITY_FORMAT: 'Entity ID format', - MQTT_ENTITY_FORMAT_0: 'Single instance, long name', + MQTT_ENTITY_FORMAT_0: 'Single instance, long name (depreciated)', MQTT_ENTITY_FORMAT_1: 'Multiple instances, short name', MQTT_CLEAN_SESSION: 'Setze `Clean Session`', MQTT_RETAIN_FLAG: 'Setze `Retain flag` immer', diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index e76450b70..95f386a5f 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -249,7 +249,7 @@ const en: Translation = { MQTT_QUEUE: 'MQTT Queue', DEFAULT: 'Default', MQTT_ENTITY_FORMAT: 'Entity ID format', - MQTT_ENTITY_FORMAT_0: 'Single instance, long name', + MQTT_ENTITY_FORMAT_0: 'Single instance, long name (depreciated)', MQTT_ENTITY_FORMAT_1: 'Multiple instances, short name', MQTT_CLEAN_SESSION: 'Set Clean Session', MQTT_RETAIN_FLAG: 'Always set Retain flag', diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 659c96359..8665ddb2a 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -249,7 +249,7 @@ const fr: Translation = { MQTT_QUEUE: 'Queue MQTT', DEFAULT: 'Défaut', MQTT_ENTITY_FORMAT: 'Entity ID format', - MQTT_ENTITY_FORMAT_0: 'Single instance, long name', + MQTT_ENTITY_FORMAT_0: 'Single instance, long name (depreciated)', MQTT_ENTITY_FORMAT_1: 'Multiple instances, short name', MQTT_CLEAN_SESSION: 'Flag Clean Session', MQTT_RETAIN_FLAG: 'Toujours activer le Retain Flag', diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index dc250c99b..41cfe4bae 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -249,7 +249,7 @@ const nl: Translation = { MQTT_QUEUE: 'MQTT Queue', DEFAULT: 'Default', MQTT_ENTITY_FORMAT: 'Entity ID format', - MQTT_ENTITY_FORMAT_0: 'Single instance, long name', + MQTT_ENTITY_FORMAT_0: 'Single instance, long name (depreciated)', MQTT_ENTITY_FORMAT_1: 'Multiple instances, short name', MQTT_CLEAN_SESSION: 'Clean Session aan', MQTT_RETAIN_FLAG: 'Retain flag aan', diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index b9e7db89c..2eaf3e2fd 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -249,7 +249,7 @@ const no: Translation = { MQTT_QUEUE: 'MQTT Queue', DEFAULT: 'Standard', MQTT_ENTITY_FORMAT: 'Entity ID format', - MQTT_ENTITY_FORMAT_0: 'Single instance, long name', + MQTT_ENTITY_FORMAT_0: 'Single instance, long name (depreciated)', MQTT_ENTITY_FORMAT_1: 'Multiple instances, short name', MQTT_CLEAN_SESSION: 'Benytt Clean Session', MQTT_RETAIN_FLAG: 'Alltid sett Retain flag', diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index ed542e798..8e023ed85 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -249,7 +249,7 @@ const pl: BaseTranslation = { MQTT_QUEUE: 'Kolejka MQTT', DEFAULT: '{{Pozostałe|Domyślna|}}', MQTT_ENTITY_FORMAT: 'Entity ID format', - MQTT_ENTITY_FORMAT_0: 'Single instance, long name', + MQTT_ENTITY_FORMAT_0: 'Single instance, long name (depreciated)', MQTT_ENTITY_FORMAT_1: 'Multiple instances, short name', MQTT_CLEAN_SESSION: 'Ustawiaj flagę "Clean session"', MQTT_RETAIN_FLAG: 'Ustawiaj flagę "Retain"', diff --git a/interface/src/i18n/se/index.ts b/interface/src/i18n/se/index.ts index 99e33eebc..74a2898c2 100644 --- a/interface/src/i18n/se/index.ts +++ b/interface/src/i18n/se/index.ts @@ -249,7 +249,7 @@ const se: Translation = { MQTT_QUEUE: 'MQTT Queue', DEFAULT: 'Standard', MQTT_ENTITY_FORMAT: 'Entity ID format', - MQTT_ENTITY_FORMAT_0: 'Single instance, long name', + MQTT_ENTITY_FORMAT_0: 'Single instance, long name (depreciated)', MQTT_ENTITY_FORMAT_1: 'Multiple instances, short name', MQTT_CLEAN_SESSION: 'Använd "Clean Session"-flaggan', MQTT_RETAIN_FLAG: 'Använd "Always Retain"-flaggan', diff --git a/lib/framework/MqttSettingsService.cpp b/lib/framework/MqttSettingsService.cpp index aa6198706..a52af34f6 100644 --- a/lib/framework/MqttSettingsService.cpp +++ b/lib/framework/MqttSettingsService.cpp @@ -223,6 +223,10 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting changed = true; } + if (newSettings.multiple_instances != settings.multiple_instances) { + changed = true; + } + // if both settings are stored from older version, HA has priority if (newSettings.ha_enabled && newSettings.publish_single) { newSettings.publish_single = false; @@ -258,44 +262,38 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting if (newSettings.publish_time_boiler != settings.publish_time_boiler) { emsesp::EMSESP::mqtt_.set_publish_time_boiler(newSettings.publish_time_boiler); - changed = true; } if (newSettings.publish_time_thermostat != settings.publish_time_thermostat) { emsesp::EMSESP::mqtt_.set_publish_time_thermostat(newSettings.publish_time_thermostat); - changed = true; } if (newSettings.publish_time_solar != settings.publish_time_solar) { emsesp::EMSESP::mqtt_.set_publish_time_solar(newSettings.publish_time_solar); - changed = true; } if (newSettings.publish_time_mixer != settings.publish_time_mixer) { emsesp::EMSESP::mqtt_.set_publish_time_mixer(newSettings.publish_time_mixer); - changed = true; } if (newSettings.publish_time_other != settings.publish_time_other) { emsesp::EMSESP::mqtt_.set_publish_time_other(newSettings.publish_time_other); - changed = true; } if (newSettings.publish_time_sensor != settings.publish_time_sensor) { emsesp::EMSESP::mqtt_.set_publish_time_sensor(newSettings.publish_time_sensor); - changed = true; } if (newSettings.publish_time_heartbeat != settings.publish_time_heartbeat) { emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat); - changed = true; } + // save the new settings + settings = newSettings; + if (changed) { emsesp::EMSESP::mqtt_.reset_mqtt(); } - settings = newSettings; - return StateUpdateResult::CHANGED; } diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index ffb02bb7c..da7c350f3 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -451,14 +451,15 @@ void AnalogSensor::publish_values(const bool force) { } config["val_tpl"] = str; + char uniq_s[70]; if (Mqtt::multiple_instances()) { - snprintf(str, sizeof(str), "%s_analogsensor_%d", Mqtt::basename().c_str(), sensor.gpio()); + snprintf(uniq_s, sizeof(uniq_s), "%s_analogsensor_%d", Mqtt::basename().c_str(), sensor.gpio()); } else { - snprintf(str, sizeof(str), "analogsensor_%d", sensor.gpio()); + snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%d", sensor.gpio()); } - config["object_id"] = str; - config["uniq_id"] = str; // same as object_id + config["object_id"] = uniq_s; + config["uniq_id"] = uniq_s; // same as object_id snprintf(str, sizeof(str), "%s", sensor.name().c_str()); config["name"] = str; diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index d58f22d7c..59607909b 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -518,14 +518,15 @@ void DallasSensor::publish_values(const bool force) { } config["val_tpl"] = str; + char uniq_s[70]; if (Mqtt::multiple_instances()) { - snprintf(str, sizeof(str), "%s_dallassensor_%s", Mqtt::basename().c_str(), sensor.id().c_str()); + snprintf(uniq_s, sizeof(uniq_s), "%s_dallassensor_%s", Mqtt::basename().c_str(), sensor.id().c_str()); } else { - snprintf(str, sizeof(str), "dallassensor_%s", sensor.id().c_str()); + snprintf(uniq_s, sizeof(uniq_s), "dallassensor_%s", sensor.id().c_str()); } - config["object_id"] = str; - config["uniq_id"] = str; // same as object_id + config["object_id"] = uniq_s; + config["uniq_id"] = uniq_s; // same as object_id snprintf(str, sizeof(str), "%s", sensor.name().c_str()); config["name"] = str; diff --git a/src/emsdevicevalue.cpp b/src/emsdevicevalue.cpp index 20e4d463a..c3d2cc0fe 100644 --- a/src/emsdevicevalue.cpp +++ b/src/emsdevicevalue.cpp @@ -105,10 +105,9 @@ DeviceValue::DeviceValue(uint8_t device_type, // must be an int of 4 bytes, 32bit aligned const char * DeviceValue::DeviceValueUOM_s[] = { - 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_blank) // connectivity + 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_blank) }; diff --git a/src/helpers.cpp b/src/helpers.cpp index 6865f9081..5b4cad590 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -678,6 +678,10 @@ std::string Helpers::toUpper(std::string const & s) { // replace char in char string void Helpers::replace_char(char * str, char find, char replace) { + if (str == nullptr) { + return; + } + int i = 0; while (str[i] != '\0') { diff --git a/src/locale_common.h b/src/locale_common.h index fdc4b59fa..9c4879147 100644 --- a/src/locale_common.h +++ b/src/locale_common.h @@ -224,7 +224,7 @@ MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww") MAKE_PSTR(tag_device_data_ww_mqtt, "") // Home Assistant - this is special and has no translations -MAKE_PSTR_LIST(climate, "HA climate config creation") +MAKE_PSTR_LIST(climate, "") // syslog MAKE_PSTR_LIST(list_syslog_level, "off", "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", "trace", "all") diff --git a/src/mqtt.cpp b/src/mqtt.cpp index d279fc931..2b36aba8d 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -974,7 +974,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev const int16_t dv_set_max, const JsonObject & dev_json) { // ignore if name (fullname) is empty - if (!fullname) { + if (!fullname || !en_name) { return; } @@ -990,13 +990,28 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev } // build unique identifier which will be used in the topic, also used as object_id + // and becomes the Entity ID in HA char uniq_id[70]; if (Mqtt::multiple_instances()) { // prefix base name to each uniq_id and use the shortname snprintf(uniq_id, sizeof(uniq_id), "%s_%s_%s", mqtt_basename_.c_str(), device_name, entity_with_tag); } else { // old v3.4 style - snprintf(uniq_id, sizeof(uniq_id), "%s_%s", device_name, en_name); + // if there is no en_name take the shortname + if (en_name == nullptr || strlen(en_name) == 0) { + strlcpy(uniq_id, entity, sizeof(uniq_id)); + } else { + // old v3.4 style + // take en_name and replace all spaces and lowercase it + char uniq_s[40]; + strlcpy(uniq_s, en_name, sizeof(uniq_s)); + Helpers::replace_char(uniq_s, ' ', '_'); + if (EMSdevice::tag_to_string(tag).empty()) { + snprintf(uniq_id, sizeof(uniq_id), "%s_%s", device_name, Helpers::toLower(uniq_s).c_str()); + } else { + snprintf(uniq_id, sizeof(uniq_id), "%s_%s_%s", device_name, EMSdevice::tag_to_string(tag).c_str(), Helpers::toLower(uniq_s).c_str()); + } + } } // build a config topic that will be prefix onto a HA type (e.g. number, switch) diff --git a/src/shower.cpp b/src/shower.cpp index fa43a6f05..61c5f9ab6 100644 --- a/src/shower.cpp +++ b/src/shower.cpp @@ -155,7 +155,11 @@ void Shower::set_shower_state(bool state, bool force) { doc["name"] = "Shower Active"; char str[70]; - snprintf(str, sizeof(str), "%s_shower_active", Mqtt::basename().c_str()); + if (Mqtt::multiple_instances()) { + snprintf(str, sizeof(str), "%s_shower_active", Mqtt::basename().c_str()); + } else { + snprintf(str, sizeof(str), "shower_active"); // v3.4 compatible + } doc["uniq_id"] = str; doc["object_id"] = str; diff --git a/src/system.cpp b/src/system.cpp index 5275a2a1a..b7e23086d 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1059,11 +1059,11 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp JsonObject node; // System - node = output.createNestedObject("System Info"); - node["version"] = EMSESP_APP_VERSION; - node["platform"] = EMSESP_PLATFORM; - node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); - // node["uptime (seconds)"] = uuid::get_uptime_sec(); + node = output.createNestedObject("System Info"); + node["version"] = EMSESP_APP_VERSION; + node["platform"] = EMSESP_PLATFORM; + node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); + node["uptime (seconds)"] = uuid::get_uptime_sec(); #ifndef EMSESP_STANDALONE node["free mem"] = ESP.getFreeHeap() / 1024; // kilobytes node["max alloc"] = ESP.getMaxAllocHeap() / 1024; // kilobytes diff --git a/src/test/test.h b/src/test/test.h index e8d7a287e..5abd892bc 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -30,12 +30,12 @@ namespace emsesp { // #define EMSESP_DEBUG_DEFAULT "solar" // #define EMSESP_DEBUG_DEFAULT "mixer" // #define EMSESP_DEBUG_DEFAULT "web" -#define EMSESP_DEBUG_DEFAULT "mqtt" +// #define EMSESP_DEBUG_DEFAULT "mqtt" // #define EMSESP_DEBUG_DEFAULT "general" // #define EMSESP_DEBUG_DEFAULT "boiler" // #define EMSESP_DEBUG_DEFAULT "mqtt2" // #define EMSESP_DEBUG_DEFAULT "mqtt_nested" -// #define EMSESP_DEBUG_DEFAULT "ha" +#define EMSESP_DEBUG_DEFAULT "ha" // #define EMSESP_DEBUG_DEFAULT "masked" // #define EMSESP_DEBUG_DEFAULT "board_profile" // #define EMSESP_DEBUG_DEFAULT "shower_alert"