diff --git a/interface/package.json b/interface/package.json index d087b3b5e..332ff89f4 100644 --- a/interface/package.json +++ b/interface/package.json @@ -38,7 +38,7 @@ "react": "^19.2.0", "react-dom": "^19.2.0", "react-icons": "^5.5.0", - "react-router": "^7.9.3", + "react-router": "^7.9.4", "react-toastify": "^11.0.5", "typesafe-i18n": "^5.26.2", "typescript": "^5.9.3" diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 6a30175db..d2303c938 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -57,8 +57,8 @@ importers: specifier: ^5.5.0 version: 5.5.0(react@19.2.0) react-router: - specifier: ^7.9.3 - version: 7.9.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^7.9.4 + version: 7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react-toastify: specifier: ^11.0.5 version: 11.0.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -1014,8 +1014,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.13: - resolution: {integrity: sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==} + baseline-browser-mapping@2.8.14: + resolution: {integrity: sha512-GM9c0cWWR8Ga7//Ves/9KRgTS8nLausCkP3CGiFLrnwA2CDUluXgaQqvrULoR2Ujrd/mz/lkX87F5BHFsNr5sQ==} hasBin: true bin-build@3.0.0: @@ -2505,8 +2505,8 @@ packages: react-is@19.2.0: resolution: {integrity: sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==} - react-router@7.9.3: - resolution: {integrity: sha512-4o2iWCFIwhI/eYAIL43+cjORXYn/aRQPgtFRRZb3VzoyQ5Uej0Bmqj7437L97N9NJW4wnicSwLOLS+yCXfAPgg==} + react-router@7.9.4: + resolution: {integrity: sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -3936,7 +3936,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.8.13: {} + baseline-browser-mapping@2.8.14: {} bin-build@3.0.0: dependencies: @@ -3993,7 +3993,7 @@ snapshots: browserslist@4.26.3: dependencies: - baseline-browser-mapping: 2.8.13 + baseline-browser-mapping: 2.8.14 caniuse-lite: 1.0.30001749 electron-to-chromium: 1.5.233 node-releases: 2.0.23 @@ -5498,7 +5498,7 @@ snapshots: react-is@19.2.0: {} - react-router@7.9.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + react-router@7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: cookie: 1.0.2 react: 19.2.0 diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index 2e3ff3dfe..a1a39b6a7 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -700,8 +700,7 @@ void AnalogSensor::publish_values(const bool force) { snprintf(uniq_s, sizeof(uniq_s), "%s_%02d", F_(analogsensor), sensor.gpio()); } - config["obj_id"] = uniq_s; - config["uniq_id"] = uniq_s; // same as object_id + config["uniq_id"] = uniq_s; char name[50]; snprintf(name, sizeof(name), "%s", sensor.name().c_str()); @@ -772,6 +771,10 @@ void AnalogSensor::publish_values(const bool force) { } } + // add default_entity_id + std::string topic_str(topic); + doc["default_entity_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s; + Mqtt::add_ha_dev_section(config.as(), "Analog Sensors", nullptr, nullptr, nullptr, false); Mqtt::add_ha_avail_section(config.as(), stat_t, !is_ha_device_created, val_cond); diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index 272426cc4..37e25a22b 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -529,15 +529,14 @@ void Mqtt::ha_status() { } doc["uniq_id"] = uniq; - doc["default_entity_id"] = uniq; - - doc["stat_t"] = Mqtt::base() + "/status"; - doc["name"] = "System status"; - doc["pl_on"] = "online"; - doc["pl_off"] = "offline"; - doc["stat_cla"] = "measurement"; - doc["dev_cla"] = "connectivity"; - doc["ent_cat"] = "diagnostic"; + doc["default_entity_id"] = (std::string) "binary_sensor." + uniq; + doc["stat_t"] = Mqtt::base() + "/status"; + doc["name"] = "System status"; + doc["pl_on"] = "online"; + doc["pl_off"] = "offline"; + doc["stat_cla"] = "measurement"; + doc["dev_cla"] = "connectivity"; + doc["ent_cat"] = "diagnostic"; // doc["avty_t"] = "~/status"; // commented out, as it causes errors in HA sometimes // doc["json_attr_t"] = "~/heartbeat"; // store also as HA attributes @@ -827,7 +826,7 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev snprintf(entity_with_tag, sizeof(entity_with_tag), "%s", entity); } - // build unique identifier also used as default_entity_id which also becomes the Entity ID in HA + // build unique identifier also used to build the default_entity_id which also becomes the Entity ID in HA char uniq_id[80]; // list of boiler entities that need conversion for 3.6 compatibility, add ww suffix @@ -980,8 +979,12 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // build the full payload JsonDocument doc; - doc["uniq_id"] = uniq_id; - doc["default_entity_id"] = uniq_id; // same as unique_id + doc["uniq_id"] = uniq_id; + + // set the entity_id. This is breaking change in HA 2025.10.0 - see https://github.com/home-assistant/core/pull/151775 + // extract the string from topic up to the / using std::string + std::string topic_str(topic); + doc["default_entity_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_id; char sample_val[30] = "0"; // sample, correct(!) entity value, used only to prevent warning/error in HA if real value is not published yet @@ -1302,12 +1305,12 @@ bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, hc_mode_s, Helpers::translated_word(FL_(off))); - snprintf(name_s, sizeof(name_s), "%s%d", tag < DeviceValueTAG::TAG_HS1 ? "Hc" : "Hs", hc_num); + snprintf(name_s, sizeof(name_s), "%s%d", tagname, hc_num); if (Mqtt::entity_format() == entityFormat::MULTI_SHORT) { - snprintf(uniq_id_s, sizeof(uniq_id_s), "%s_%s%s%d", Mqtt::basename().c_str(), devicename, tagname, hc_num); // add basename + snprintf(uniq_id_s, sizeof(uniq_id_s), "%s_%s_%s%d", Mqtt::basename().c_str(), devicename, tagname, hc_num); // add basename } else { - snprintf(uniq_id_s, sizeof(uniq_id_s), "%s%d", devicename, hc_num); // backward compatible with v3.4 + snprintf(uniq_id_s, sizeof(uniq_id_s), "%s_%s%d", devicename, tagname, hc_num); // backward compatible with v3.4 } snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/%s/%s%d/seltemp", devicename, tagname, hc_num); @@ -1317,7 +1320,7 @@ bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, doc["~"] = Mqtt::base(); doc["uniq_id"] = uniq_id_s; - doc["default_entity_id"] = uniq_id_s; // same as uniq_id + doc["default_entity_id"] = (std::string) "climate." + uniq_id_s; doc["name"] = name_s; doc["mode_stat_t"] = topic_t; doc["mode_stat_tpl"] = mode_str_tpl; diff --git a/src/core/shower.cpp b/src/core/shower.cpp index 78e9651bf..3946171f3 100644 --- a/src/core/shower.cpp +++ b/src/core/shower.cpp @@ -205,8 +205,8 @@ void Shower::create_ha_discovery() { } else { snprintf(str, sizeof(str), "shower_active"); // v3.4 compatible } - doc["uniq_id"] = str; - doc["obj_id"] = str; + doc["uniq_id"] = str; + doc["default_entity_id"] = (std::string) "binary_sensor." + str; snprintf(stat_t, sizeof(stat_t), "%s/shower_active", Mqtt::base().c_str()); doc["stat_t"] = stat_t; @@ -223,8 +223,8 @@ void Shower::create_ha_discovery() { snprintf(str, sizeof(str), "%s_shower_duration", Mqtt::basename().c_str()); - doc["uniq_id"] = str; - doc["object_id"] = str; + doc["uniq_id"] = str; + doc["default_entity_id"] = (std::string) "sensor." + str; snprintf(stat_t, sizeof(stat_t), "%s/shower_data", Mqtt::base().c_str()); doc["stat_t"] = stat_t; @@ -258,7 +258,6 @@ void Shower::create_ha_discovery() { snprintf(str, sizeof(str), "%s_shower_timestamp", Mqtt::basename().c_str()); doc["uniq_id"] = str; - doc["object_id"] = str; snprintf(stat_t, sizeof(stat_t), "%s/shower_data", Mqtt::base().c_str()); doc["stat_t"] = stat_t; diff --git a/src/core/temperaturesensor.cpp b/src/core/temperaturesensor.cpp index a8ede463e..8e17ef4f4 100644 --- a/src/core/temperaturesensor.cpp +++ b/src/core/temperaturesensor.cpp @@ -531,8 +531,8 @@ void TemperatureSensor::publish_values(const bool force) { snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(temperaturesensor), sensor.id().c_str()); } - config["obj_id"] = uniq_s; - config["uniq_id"] = uniq_s; // same as object_id/obj_id + config["uniq_id"] = uniq_s; + config["default_entity_id"] = (std::string) "sensor." + uniq_s; char name[50]; snprintf(name, sizeof(name), "%s", sensor.name().c_str()); diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index 0a7676164..8311ce2c5 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -429,8 +429,7 @@ void WebCustomEntityService::publish(const bool force) { char uniq_s[70]; snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(custom), entityItem.name.c_str()); - config["obj_id"] = uniq_s; - config["uniq_id"] = uniq_s; // same as object_id + config["uniq_id"] = uniq_s; config["name"] = entityItem.name.c_str(); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; @@ -461,6 +460,10 @@ void WebCustomEntityService::publish(const bool force) { Mqtt::add_ha_bool(config.as()); } + // add default_entity_id + std::string topic_str(topic); + config["default_entity_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s; + 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, nullptr, false); Mqtt::add_ha_avail_section(config.as(), stat_t, !ha_created, val_cond); diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index a1dc97cd5..73813042e 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -282,9 +282,9 @@ void WebSchedulerService::publish(const bool force) { char uniq_s[70]; snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(scheduler), scheduleItem.name.c_str()); - config["obj_id"] = uniq_s; - config["uniq_id"] = uniq_s; // same as object_id - config["name"] = scheduleItem.name.c_str(); + config["uniq_id"] = uniq_s; + config["name"] = scheduleItem.name.c_str(); + config["default_entity_id"] = (std::string) "switch." + uniq_s; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];