From 39d18b78a1fe85eaec0ae4409748d28478219224 Mon Sep 17 00:00:00 2001 From: proddy Date: Thu, 18 Dec 2025 21:39:43 +0100 Subject: [PATCH 01/10] formatting --- src/core/emsesp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 5a4722ea5..2b2c5668b 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -646,6 +646,8 @@ void EMSESP::reset_mqtt_ha() { // force the re-creating of the temperature and analog sensor topics (for HA) temperaturesensor_.reload(); analogsensor_.reload(); + + // rebuild MQTT HA config topics for shower, custom entities and scheduler shower_.ha_reset(); webSchedulerService.ha_reset(); webCustomEntityService.ha_reset(); From 99afeb221a3f1990f4861beda05e16807edeb39f Mon Sep 17 00:00:00 2001 From: proddy Date: Thu, 18 Dec 2025 21:40:08 +0100 Subject: [PATCH 02/10] changes to HA --- src/core/mqtt.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index a201fdc54..d4ca0eb5b 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -1448,27 +1448,31 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const char * mo return; } - // create dev section - JsonObject dev_json = doc["dev"].to(); + JsonObject dev_json = doc["dev"].to(); // create dev section - // add ids and name - capitalize first letter of the name + // add ids - capitalize first letter of the name if there is one JsonArray ids = dev_json["ids"].to(); // ids, it is an array with a single element if (name != nullptr) { - // for ids, replace all spaces with - + // for ids, replace all spaces with - and add to the basename 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()); // no name, assign it to the main EMS-ESP device in HA } - // create the model, manufacturer and version + // create the name, model, manufacturer and version if (create_model) { + if (name != nullptr) { + auto cap_name = strdup(name); + Helpers::CharToUpperUTF8(cap_name); // capitalize first letter + dev_json["name"] = Mqtt::basename() + " " + cap_name; + free(cap_name); + } else { + dev_json["name"] = Mqtt::basename(); + } + + // add mf, mdl, sw and via_device dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP"; if (model != nullptr) { dev_json["mdl"] = model; From 0eddbac150e426c8497a6c22543fd2117c87723c Mon Sep 17 00:00:00 2001 From: proddy Date: Thu, 18 Dec 2025 21:40:41 +0100 Subject: [PATCH 03/10] remove force in HA MQTT --- src/web/WebCustomEntityService.cpp | 21 +++++++-------------- src/web/WebCustomEntityService.h | 6 +++--- src/web/WebSchedulerService.cpp | 23 ++++++++--------------- src/web/WebSchedulerService.h | 6 +++--- 4 files changed, 21 insertions(+), 35 deletions(-) diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index d04d40fff..9f6fce797 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -378,19 +378,12 @@ void WebCustomEntityService::publish_single(CustomEntityItem & entity) { } // publish to Mqtt -void WebCustomEntityService::publish(const bool force) { - if (force) { - ha_registered_ = false; - } - - if (!Mqtt::enabled()) { +void WebCustomEntityService::publish() { + if (!Mqtt::enabled() || customEntityItems_->empty()) { return; } - if (customEntityItems_->empty()) { - return; - } - if (Mqtt::publish_single() && force) { + if (Mqtt::publish_single()) { for (CustomEntityItem & entityItem : *customEntityItems_) { publish_single(entityItem); } @@ -398,7 +391,7 @@ void WebCustomEntityService::publish(const bool force) { JsonDocument doc; JsonObject output = doc.to(); - bool ha_created = ha_registered_; + bool ha_created = ha_configdone_; for (CustomEntityItem & entityItem : *customEntityItems_) { if (entityItem.hide) { @@ -406,7 +399,7 @@ void WebCustomEntityService::publish(const bool force) { } render_value(output, entityItem); // create HA config - if (Mqtt::ha_enabled() && !ha_registered_) { + if (!ha_configdone_) { JsonDocument config; config["~"] = Mqtt::base(); @@ -464,7 +457,6 @@ void WebCustomEntityService::publish(const bool force) { config["def_ent_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, "EMS-ESP", EMSESP_APP_VERSION, !ha_created); Mqtt::add_ha_avty_section(config.as(), stat_t, val_cond); @@ -472,7 +464,8 @@ void WebCustomEntityService::publish(const bool force) { } } - ha_registered_ = ha_created; + ha_configdone_ = ha_created; + if (output.size() > 0) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; snprintf(topic, sizeof(topic), "%s_data", F_(custom)); diff --git a/src/web/WebCustomEntityService.h b/src/web/WebCustomEntityService.h index d6149d31e..517d19c88 100644 --- a/src/web/WebCustomEntityService.h +++ b/src/web/WebCustomEntityService.h @@ -58,7 +58,7 @@ class WebCustomEntityService : public StatefulService { void begin(); void publish_single(CustomEntityItem & entity); - void publish(const bool force = false); + void publish(); bool command_setvalue(const char * value, const int8_t id, const char * name); bool get_value_info(JsonObject output, const char * cmd); void get_value_json(JsonObject output, CustomEntityItem const & entity); @@ -70,7 +70,7 @@ class WebCustomEntityService : public StatefulService { uint8_t count_entities(); void ha_reset() { - ha_registered_ = false; + ha_configdone_ = false; } #if defined(EMSESP_TEST) @@ -85,7 +85,7 @@ class WebCustomEntityService : public StatefulService { std::list> * customEntityItems_; // pointer to the list of entity items - bool ha_registered_ = false; + bool ha_configdone_ = false; }; } // namespace emsesp diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index b72b60556..fcc313bbe 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -106,7 +106,8 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu } } - EMSESP::webSchedulerService.publish(true); + EMSESP::webSchedulerService.ha_reset(); + EMSESP::webSchedulerService.publish(); return StateUpdateResult::CHANGED; } @@ -215,20 +216,12 @@ void WebSchedulerService::publish_single(const char * name, const bool state) { } // publish to Mqtt -void WebSchedulerService::publish(const bool force) { - if (force) { - ha_registered_ = false; - } - - if (!Mqtt::enabled()) { +void WebSchedulerService::publish() { + if (!Mqtt::enabled() || scheduleItems_->empty()) { return; } - if (scheduleItems_->empty()) { - return; - } - - if (Mqtt::publish_single() && force) { + if (Mqtt::publish_single()) { for (const ScheduleItem & scheduleItem : *scheduleItems_) { publish_single(scheduleItem.name, scheduleItem.active); } @@ -236,13 +229,13 @@ void WebSchedulerService::publish(const bool force) { JsonDocument doc; JsonObject output = doc.to(); - bool ha_created = ha_registered_; + bool ha_created = ha_configdone_; for (const ScheduleItem & scheduleItem : *scheduleItems_) { if (scheduleItem.name[0] != '\0' && !output[scheduleItem.name].is()) { Mqtt::add_value_bool(output, (const char *)scheduleItem.name, scheduleItem.active); // create HA config - if (Mqtt::ha_enabled() && !ha_registered_) { + if (!ha_configdone_) { JsonDocument config; config["~"] = Mqtt::base(); @@ -284,7 +277,7 @@ void WebSchedulerService::publish(const bool force) { } } - ha_registered_ = ha_created; + ha_configdone_ = ha_created; if (!doc.isNull()) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; diff --git a/src/web/WebSchedulerService.h b/src/web/WebSchedulerService.h index 4a485e35d..25b561bcc 100644 --- a/src/web/WebSchedulerService.h +++ b/src/web/WebSchedulerService.h @@ -78,12 +78,12 @@ class WebSchedulerService : public StatefulService { void begin(); void loop(); void publish_single(const char * name, const bool state); - void publish(const bool force = false); + void publish(); bool command_setvalue(const char * value, const int8_t id, const char * name); bool get_value_info(JsonObject output, const char * cmd); void get_value_json(JsonObject output, const ScheduleItem & scheduleItem); void ha_reset() { - ha_registered_ = false; + ha_configdone_ = false; } uint8_t count_entities(bool cmd_only = false); bool onChange(const char * cmd); @@ -106,7 +106,7 @@ class WebSchedulerService : public StatefulService { HttpEndpoint _httpEndpoint; FSPersistence _fsPersistence; - bool ha_registered_ = false; + bool ha_configdone_ = false; std::list> * scheduleItems_; // pointer to the list of schedule events std::list> cmd_changed_; // pointer to commands in list that are triggered by change From 11d41099157ec69a75826bc883595d5bf8ead1d0 Mon Sep 17 00:00:00 2001 From: proddy Date: Thu, 18 Dec 2025 21:40:53 +0100 Subject: [PATCH 04/10] package update --- interface/package.json | 2 +- interface/pnpm-lock.yaml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/interface/package.json b/interface/package.json index d458f87d5..c2841fec4 100644 --- a/interface/package.json +++ b/interface/package.json @@ -65,7 +65,7 @@ "typescript-eslint": "^8.50.0", "vite": "^7.3.0", "vite-plugin-imagemin": "^0.6.1", - "vite-tsconfig-paths": "^6.0.2" + "vite-tsconfig-paths": "^6.0.3" }, "packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402" } diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index d66e262a2..1e2b41d03 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -127,8 +127,8 @@ importers: specifier: ^0.6.1 version: 0.6.1(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) vite-tsconfig-paths: - specifier: ^6.0.2 - version: 6.0.2(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) + specifier: ^6.0.3 + version: 6.0.3(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) packages: @@ -1027,8 +1027,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.9: - resolution: {integrity: sha512-V8fbOCSeOFvlDj7LLChUcqbZrdKD9RU/VR260piF1790vT0mfLSwGc/Qzxv3IqiTukOpNtItePa0HBpMAj7MDg==} + baseline-browser-mapping@2.9.10: + resolution: {integrity: sha512-2VIKvDx8Z1a9rTB2eCkdPE5nSe28XnA+qivGnWHoB40hMMt/h1hSz0960Zqsn6ZyxWXUie0EBdElKv8may20AA==} hasBin: true bin-build@3.0.0: @@ -2988,8 +2988,8 @@ packages: peerDependencies: vite: 5.x || 6.x || 7.x - vite-tsconfig-paths@6.0.2: - resolution: {integrity: sha512-c06LOO8fWB5RuEPpEIHXU9t7Dt4DoiPIljnKws9UygIaQo6PoFKawTftz5/QVcO+6pOs/HHWycnq4UrZkWVYnQ==} + vite-tsconfig-paths@6.0.3: + resolution: {integrity: sha512-7bL7FPX/DSviaZGYUKowWF1AiDVWjMjxNbE8lyaVGDezkedWqfGhlnQ4BZXre0ZN5P4kAgIJfAlgFDVyjrCIyg==} peerDependencies: vite: '*' peerDependenciesMeta: @@ -3958,7 +3958,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.9.9: {} + baseline-browser-mapping@2.9.10: {} bin-build@3.0.0: dependencies: @@ -4015,7 +4015,7 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.9 + baseline-browser-mapping: 2.9.10 caniuse-lite: 1.0.30001760 electron-to-chromium: 1.5.267 node-releases: 2.0.27 @@ -6002,7 +6002,7 @@ snapshots: stack-trace: 1.0.0-pre2 vite: 7.3.0(@types/node@25.0.3)(terser@5.44.1) - vite-tsconfig-paths@6.0.2(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)): + vite-tsconfig-paths@6.0.3(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)): dependencies: debug: 4.4.3 globrex: 0.1.2 From 778fe43012fa576c6d910a4f1971eb76a8f9e9c0 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 19 Dec 2025 08:54:30 +0100 Subject: [PATCH 05/10] package update --- interface/package.json | 2 +- interface/pnpm-lock.yaml | 8 ++++---- mock-api/package.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/package.json b/interface/package.json index c2841fec4..b32094173 100644 --- a/interface/package.json +++ b/interface/package.json @@ -67,5 +67,5 @@ "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^6.0.3" }, - "packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402" + "packageManager": "pnpm@10.26.1+sha512.664074abc367d2c9324fdc18037097ce0a8f126034160f709928e9e9f95d98714347044e5c3164d65bd5da6c59c6be362b107546292a8eecb7999196e5ce58fa" } diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 1e2b41d03..e46dd8a79 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -1117,8 +1117,8 @@ packages: resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} engines: {node: '>=0.10.0'} - caniuse-lite@1.0.30001760: - resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + caniuse-lite@1.0.30001761: + resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} caw@2.0.1: resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==} @@ -4016,7 +4016,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.10 - caniuse-lite: 1.0.30001760 + caniuse-lite: 1.0.30001761 electron-to-chromium: 1.5.267 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -4075,7 +4075,7 @@ snapshots: camelcase@2.1.1: {} - caniuse-lite@1.0.30001760: {} + caniuse-lite@1.0.30001761: {} caw@2.0.1: dependencies: diff --git a/mock-api/package.json b/mock-api/package.json index c2f11def4..c281edffa 100644 --- a/mock-api/package.json +++ b/mock-api/package.json @@ -15,5 +15,5 @@ "itty-router": "^5.0.22", "prettier": "^3.7.4" }, - "packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402" + "packageManager": "pnpm@10.26.1+sha512.664074abc367d2c9324fdc18037097ce0a8f126034160f709928e9e9f95d98714347044e5c3164d65bd5da6c59c6be362b107546292a8eecb7999196e5ce58fa" } From 179351cb6bfca606dc10faf492c506aae0a7d344 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 19 Dec 2025 08:54:59 +0100 Subject: [PATCH 06/10] add back force, fix for non-HA --- src/web/WebSchedulerService.cpp | 12 ++++++++---- src/web/WebSchedulerService.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index fcc313bbe..c8af8f825 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -216,12 +216,16 @@ void WebSchedulerService::publish_single(const char * name, const bool state) { } // publish to Mqtt -void WebSchedulerService::publish() { +void WebSchedulerService::publish(const bool force) { + if (force) { + ha_configdone_ = false; + } + if (!Mqtt::enabled() || scheduleItems_->empty()) { return; } - if (Mqtt::publish_single()) { + if (Mqtt::publish_single() && force) { for (const ScheduleItem & scheduleItem : *scheduleItems_) { publish_single(scheduleItem.name, scheduleItem.active); } @@ -235,7 +239,7 @@ void WebSchedulerService::publish() { Mqtt::add_value_bool(output, (const char *)scheduleItem.name, scheduleItem.active); // create HA config - if (!ha_configdone_) { + if (Mqtt::ha_enabled() && !ha_configdone_) { JsonDocument config; config["~"] = Mqtt::base(); @@ -269,7 +273,7 @@ void WebSchedulerService::publish() { config["cmd_t"] = command_topic; Mqtt::add_ha_bool(config.as()); - Mqtt::add_ha_dev_section(config.as(), F_(scheduler), nullptr, "EMS-ESP", EMSESP_APP_VERSION, !ha_created); + Mqtt::add_ha_dev_section(config.as(), F_(scheduler), !ha_created); Mqtt::add_ha_avty_section(config.as(), stat_t, val_cond); ha_created |= Mqtt::queue_ha(topic, config.as()); diff --git a/src/web/WebSchedulerService.h b/src/web/WebSchedulerService.h index 25b561bcc..511e66ef8 100644 --- a/src/web/WebSchedulerService.h +++ b/src/web/WebSchedulerService.h @@ -78,7 +78,7 @@ class WebSchedulerService : public StatefulService { void begin(); void loop(); void publish_single(const char * name, const bool state); - void publish(); + void publish(const bool force = false); bool command_setvalue(const char * value, const int8_t id, const char * name); bool get_value_info(JsonObject output, const char * cmd); void get_value_json(JsonObject output, const ScheduleItem & scheduleItem); From ecc6e9286a8a855820f5bb68242b99ed981cd44c Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 19 Dec 2025 08:55:33 +0100 Subject: [PATCH 07/10] tidy up add_ha_dev_section --- src/core/analogsensor.cpp | 2 +- src/core/mqtt.cpp | 18 ++++++++---------- src/core/mqtt.h | 7 ++++++- src/core/shower.cpp | 4 ++-- src/core/temperaturesensor.cpp | 2 +- src/web/WebCustomEntityService.cpp | 2 +- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index e6718626b..0723f1419 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -804,7 +804,7 @@ void AnalogSensor::publish_values(const bool force) { config["def_ent_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s; // dev section with model is only created on the 1st sensor - Mqtt::add_ha_dev_section(config.as(), "Analog Sensors", nullptr, "EMS-ESP", EMSESP_APP_VERSION, !ha_dev_created); + Mqtt::add_ha_dev_section(config.as(), "Analog Sensors", !ha_dev_created); Mqtt::add_ha_avty_section(config.as(), stat_t, val_cond); sensor.ha_registered = Mqtt::queue_ha(topic, config.as()); diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index d4ca0eb5b..f5400cc3e 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -1106,14 +1106,14 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // add origin JsonObject origin_json = doc["o"].to(); origin_json["name"] = "EMS-ESP"; - origin_json["sw"] = EMSESP_APP_VERSION; + origin_json["sw"] = "v" + std::string(EMSESP_APP_VERSION); origin_json["url"] = "https://emsesp.org"; // add dev section if (device_type == EMSdevice::DeviceType::SYSTEM) { - add_ha_dev_section(doc.as(), nullptr, nullptr, nullptr, nullptr, false); + add_ha_dev_section(doc.as()); } else { - add_ha_dev_section(doc.as(), EMSdevice::device_type_2_device_name(device_type), model, brand, version, create_device_config); + add_ha_dev_section(doc.as(), EMSdevice::device_type_2_device_name(device_type), create_device_config, model, brand, version); } return queue_ha(topic, doc.as()); @@ -1414,8 +1414,8 @@ bool Mqtt::publish_ha_climate_config(const DeviceValue & dv, const bool has_room doc["ic"] = icon; } - add_ha_dev_section(doc.as(), devicename, nullptr, nullptr, nullptr, false); // add dev section - add_ha_avty_section(doc.as(), topic_t, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); // add availability section + add_ha_dev_section(doc.as(), devicename); + add_ha_avty_section(doc.as(), topic_t, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); return queue_ha(topic, doc.as()); // publish the config payload with retain flag } @@ -1442,7 +1442,7 @@ std::string Mqtt::tag_to_topic(uint8_t device_type, int8_t tag) { // 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 char * version, const bool create_model) { +void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool create_model, const char * model, const char * brand, const char * version) { // only works for HA if (discovery_type() != discoveryType::HOMEASSISTANT) { return; @@ -1472,14 +1472,12 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const char * mo dev_json["name"] = Mqtt::basename(); } - // add mf, mdl, sw and via_device + // add mf (manufacturer/brand), mdl (model), sw (software version) and via_device dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP"; if (model != nullptr) { dev_json["mdl"] = model; } - if (version != nullptr) { - dev_json["sw"] = version; - } + dev_json["sw"] = version != nullptr ? version : "v" + std::string(EMSESP_APP_VERSION); dev_json["via_device"] = Mqtt::basename(); } } diff --git a/src/core/mqtt.h b/src/core/mqtt.h index b55000407..e51e16fac 100644 --- a/src/core/mqtt.h +++ b/src/core/mqtt.h @@ -259,7 +259,12 @@ class Mqtt { 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 char * version, const bool create_model); + static void add_ha_dev_section(JsonObject doc, + const char * name = nullptr, + const bool create_model = false, + const char * model = nullptr, + const char * brand = nullptr, + const char * version = nullptr); static void add_ha_avty_section(JsonObject doc, const char * state_t = nullptr, const char * cond1 = nullptr, diff --git a/src/core/shower.cpp b/src/core/shower.cpp index 18ef444f5..ee9d3fc1a 100644 --- a/src/core/shower.cpp +++ b/src/core/shower.cpp @@ -210,7 +210,7 @@ void Shower::create_ha_discovery() { doc["stat_t"] = "~/shower_active"; Mqtt::add_ha_bool(doc.as()); - Mqtt::add_ha_dev_section(doc.as(), "Shower Sensors", nullptr, nullptr, nullptr, false); + Mqtt::add_ha_dev_section(doc.as(), "Shower Sensors", true); Mqtt::add_ha_avty_section(doc.as()); // no conditions snprintf(topic, sizeof(topic), "binary_sensor/%s/shower_active/config", Mqtt::basename().c_str()); @@ -239,7 +239,7 @@ void Shower::create_ha_discovery() { doc["dev_cla"] = "duration"; // doc["ent_cat"] = "diagnostic"; - Mqtt::add_ha_dev_section(doc.as(), "Shower Sensors", nullptr, "EMS-ESP", EMSESP_APP_VERSION, true); + Mqtt::add_ha_dev_section(doc.as(), "Shower Sensors"); Mqtt::add_ha_avty_section(doc.as(), "~/shower_data", "value_json.duration is defined"); snprintf(topic, sizeof(topic), "sensor/%s/shower_duration/config", Mqtt::basename().c_str()); diff --git a/src/core/temperaturesensor.cpp b/src/core/temperaturesensor.cpp index d58cfe442..c3820d3e6 100644 --- a/src/core/temperaturesensor.cpp +++ b/src/core/temperaturesensor.cpp @@ -545,7 +545,7 @@ void TemperatureSensor::publish_values(const bool force) { config["name"] = (const char *)sensor.name(); // dev section with model is only created on the 1st sensor - Mqtt::add_ha_dev_section(config.as(), "Temperature Sensors", nullptr, "EMS-ESP", EMSESP_APP_VERSION, !ha_dev_created); + Mqtt::add_ha_dev_section(config.as(), "Temperature Sensors", !ha_dev_created); Mqtt::add_ha_avty_section(config.as(), stat_t, val_cond); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index 9f6fce797..ab74f0a0d 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -457,7 +457,7 @@ void WebCustomEntityService::publish() { config["def_ent_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, "EMS-ESP", EMSESP_APP_VERSION, !ha_created); + Mqtt::add_ha_dev_section(config.as(), "Custom Entities", !ha_created); Mqtt::add_ha_avty_section(config.as(), stat_t, val_cond); ha_created |= Mqtt::queue_ha(topic, config.as()); From e6beb010758a6f04aca8523b54819576cfcaccc1 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 19 Dec 2025 16:35:29 +0100 Subject: [PATCH 08/10] package update --- interface/pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index e46dd8a79..1d28dc7cc 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -1027,8 +1027,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.10: - resolution: {integrity: sha512-2VIKvDx8Z1a9rTB2eCkdPE5nSe28XnA+qivGnWHoB40hMMt/h1hSz0960Zqsn6ZyxWXUie0EBdElKv8may20AA==} + baseline-browser-mapping@2.9.11: + resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} hasBin: true bin-build@3.0.0: @@ -3958,7 +3958,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.9.10: {} + baseline-browser-mapping@2.9.11: {} bin-build@3.0.0: dependencies: @@ -4015,7 +4015,7 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.10 + baseline-browser-mapping: 2.9.11 caniuse-lite: 1.0.30001761 electron-to-chromium: 1.5.267 node-releases: 2.0.27 From 48b261317dcefb1dc8563a559813463ef5c033a9 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 19 Dec 2025 16:35:40 +0100 Subject: [PATCH 09/10] 3.7.3-dev.39 --- src/emsesp_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emsesp_version.h b/src/emsesp_version.h index e3ec4e341..6de79fa7e 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.3-dev.38" +#define EMSESP_APP_VERSION "3.7.3-dev.39" From eec373e2ae29f3bf07279f08066e9954e1f244e0 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 19 Dec 2025 16:35:55 +0100 Subject: [PATCH 10/10] publish ha only if ha is enabled --- src/web/WebCustomEntityService.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index ab74f0a0d..482b021b3 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -383,12 +383,6 @@ void WebCustomEntityService::publish() { return; } - if (Mqtt::publish_single()) { - for (CustomEntityItem & entityItem : *customEntityItems_) { - publish_single(entityItem); - } - } - JsonDocument doc; JsonObject output = doc.to(); bool ha_created = ha_configdone_; @@ -399,7 +393,7 @@ void WebCustomEntityService::publish() { } render_value(output, entityItem); // create HA config - if (!ha_configdone_) { + if (Mqtt::ha_enabled() && !ha_configdone_) { JsonDocument config; config["~"] = Mqtt::base();