From f782eac0cf3dca6830ad8583a9ccb19719b42180 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Thu, 2 Oct 2025 11:49:53 +0200 Subject: [PATCH] rename HA dev_i, SRC: do not fetch inactive circuits, long names, HA climated --- src/core/emsdevice.cpp | 7 ++++- src/core/mqtt.cpp | 63 ++++++++++++++++++++++------------------- src/devices/connect.cpp | 59 ++++++++++++++++++++++++-------------- src/devices/connect.h | 2 +- 4 files changed, 78 insertions(+), 53 deletions(-) diff --git a/src/core/emsdevice.cpp b/src/core/emsdevice.cpp index fe6b8de0a..08faa425b 100644 --- a/src/core/emsdevice.cpp +++ b/src/core/emsdevice.cpp @@ -1896,7 +1896,12 @@ void EMSdevice::mqtt_ha_entity_config_create() { create_device_config = false; // only create the main config once count++; } -#ifndef EMSESP_STANDALONE + // SRC thermostats mapped to connect/hs1/... + if (dv.tag >= DeviceValueTAG::TAG_HS1 && !strcmp(dv.short_name, FL_(roomtemp)[0])) { + Mqtt::publish_ha_climate_config(dv.tag, true, false, dv.min, dv.max); + } + + #ifndef EMSESP_STANDALONE // always create minimum one config if (count && (heap_caps_get_free_size(MALLOC_CAP_8BIT) < 65 * 1024)) { // checks free Heap+PSRAM break; diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index 03b579342..f440cb432 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -528,8 +528,8 @@ void Mqtt::ha_status() { strcpy(uniq, "system_status"); } - doc["uniq_id"] = uniq; - doc["obj_id"] = uniq; + doc["uniq_id"] = uniq; + doc["default_entity_id"] = uniq; doc["stat_t"] = Mqtt::base() + "/status"; doc["name"] = "System status"; @@ -827,7 +827,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 object_id which also becomes the Entity ID in HA + // build unique identifier also used as 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 +980,8 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // build the full payload JsonDocument doc; - doc["uniq_id"] = uniq_id; - doc["obj_id"] = uniq_id; // same as unique_id + doc["uniq_id"] = uniq_id; + doc["default_entity_id"] = uniq_id; // same as unique_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 @@ -1235,7 +1235,9 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 } bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, const bool remove, const int16_t min, const uint32_t max) { - uint8_t hc_num = tag; + uint8_t hc_num = tag < DeviceValueTAG::TAG_HS1 ? tag : tag - DeviceValueTAG::TAG_HS1 + 1; + const char * devicename = tag < DeviceValueTAG::TAG_HS1 ? "thermostat" : "connect"; + const char * tagname = tag < DeviceValueTAG::TAG_HS1 ? "hc" : "hs"; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic_t[Mqtt::MQTT_TOPIC_MAX_SIZE]; @@ -1253,21 +1255,21 @@ bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, char min_s[10]; char max_s[10]; - snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::basename().c_str(), hc_num); + snprintf(topic, sizeof(topic), "climate/%s/%s_%s%d/config", Mqtt::basename().c_str(), devicename, tagname, hc_num); if (remove) { return queue_remove_topic(topic); // publish empty payload with retain flag } if (Mqtt::is_nested()) { // nested format - snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.hc%d.mode", hc_num); - snprintf(hc_mode_cond, sizeof(hc_mode_cond), "value_json.hc%d is undefined or %s is undefined", hc_num, hc_mode_s); - snprintf(seltemp_s, sizeof(seltemp_s), "value_json.hc%d.seltemp", hc_num); - snprintf(seltemp_cond, sizeof(seltemp_cond), "value_json.hc%d is defined and %s is defined", hc_num, seltemp_s); + snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.%s%d.mode", tagname, hc_num); + snprintf(hc_mode_cond, sizeof(hc_mode_cond), "value_json.%s%d is undefined or %s is undefined", tagname, hc_num, hc_mode_s); + snprintf(seltemp_s, sizeof(seltemp_s), "value_json.%s%d.seltemp", tagname, hc_num); + snprintf(seltemp_cond, sizeof(seltemp_cond), "value_json.%s%d is defined and %s is defined", tagname, hc_num, seltemp_s); if (has_roomtemp) { - snprintf(currtemp_s, sizeof(currtemp_s), "value_json.hc%d.currtemp", hc_num); - snprintf(currtemp_cond, sizeof(currtemp_cond), "value_json.hc%d is defined and %s is defined", hc_num, currtemp_s); + snprintf(currtemp_s, sizeof(currtemp_s), "value_json.%s%d.currtemp", tagname, hc_num); + snprintf(currtemp_cond, sizeof(currtemp_cond), "value_json.%s%d is defined and %s is defined", tagname, hc_num, currtemp_s); } snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str()); } else { @@ -1281,7 +1283,10 @@ bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, snprintf(currtemp_s, sizeof(currtemp_s), "value_json.currtemp"); snprintf(currtemp_cond, sizeof(currtemp_cond), "%s is defined", currtemp_s); } - snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_HC1 + hc_num - 1).c_str()); + snprintf(topic_t, + sizeof(topic_t), + "~/%s", + Mqtt::tag_to_topic(tag < DeviceValueTAG::TAG_HS1 ? EMSdevice::DeviceType::THERMOSTAT : EMSdevice::DeviceType::CONNECT, tag).c_str()); } snprintf(mode_str_tpl, @@ -1297,28 +1302,28 @@ 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), "Hc%d", hc_num); + snprintf(name_s, sizeof(name_s), "%s%d", tag < DeviceValueTAG::TAG_HS1 ? "Hc" : "Hs", hc_num); if (Mqtt::entity_format() == entityFormat::MULTI_SHORT) { - snprintf(uniq_id_s, sizeof(uniq_id_s), "%s_thermostat_hc%d", Mqtt::basename().c_str(), 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), "thermostat_hc%d", hc_num); // backward compatible with v3.4 + snprintf(uniq_id_s, sizeof(uniq_id_s), "%s%d", devicename, hc_num); // backward compatible with v3.4 } - snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num); - snprintf(mode_cmd_s, sizeof(mode_cmd_s), "~/thermostat/hc%d/mode", hc_num); + snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/%s/%s%d/seltemp", devicename, tagname, hc_num); + snprintf(mode_cmd_s, sizeof(mode_cmd_s), "~/%s/%s%d/mode", devicename, tagname, hc_num); JsonDocument doc; - doc["~"] = Mqtt::base(); - doc["uniq_id"] = uniq_id_s; - doc["obj_id"] = uniq_id_s; // same as uniq_id - doc["name"] = name_s; - doc["mode_stat_t"] = topic_t; - doc["mode_stat_tpl"] = mode_str_tpl; - doc["temp_cmd_t"] = temp_cmd_s; - doc["temp_stat_t"] = topic_t; - doc["temp_stat_tpl"] = (std::string) "{{" + seltemp_s + " if " + seltemp_cond + " else 0}}"; + doc["~"] = Mqtt::base(); + doc["uniq_id"] = uniq_id_s; + doc["default_entity_id"] = uniq_id_s; // same as uniq_id + doc["name"] = name_s; + doc["mode_stat_t"] = topic_t; + doc["mode_stat_tpl"] = mode_str_tpl; + doc["temp_cmd_t"] = temp_cmd_s; + doc["temp_stat_t"] = topic_t; + doc["temp_stat_tpl"] = (std::string) "{{" + seltemp_s + " if " + seltemp_cond + " else 0}}"; if (has_roomtemp) { doc["curr_temp_t"] = topic_t; @@ -1341,7 +1346,7 @@ bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp, modes.add("heat"); modes.add("off"); - add_ha_dev_section(doc.as(), "thermostat", nullptr, nullptr, nullptr, false); // add dev section + add_ha_dev_section(doc.as(), devicename, nullptr, nullptr, nullptr, false); // add dev section add_ha_avail_section(doc.as(), topic_t, false, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); // add availability section return queue_ha(topic, doc.as()); // publish the config payload with retain flag diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp index 79eef43a3..c72aa6954 100644 --- a/src/devices/connect.cpp +++ b/src/devices/connect.cpp @@ -34,11 +34,11 @@ Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, con DeviceValueUOM::DEGREES); // Roomthermostats for (uint8_t i = 0; i < 16; i++) { - register_telegram_type(0x0BDD + i, "Room", false, MAKE_PF_CB(process_roomThermostat)); - register_telegram_type(0x0B3D + i, "Roomname", true, MAKE_PF_CB(process_roomThermostatName)); - register_telegram_type(0x0BB5 + i, "Roomsettings", true, MAKE_PF_CB(process_roomThermostatMode)); - register_telegram_type(0x1230 + i, "Roomparams", true, MAKE_PF_CB(process_roomThermostatParam)); - register_telegram_type(0x1244 + i, "Roomdata", false, MAKE_PF_CB(process_roomThermostatData)); + register_telegram_type(0x0BDD + i, "Room", false, MAKE_PF_CB(process_roomThermostat)); // broadcasted + register_telegram_type(0x0B3D + i, "Roomname", false, MAKE_PF_CB(process_roomThermostatName)); // fetch for active circuits + register_telegram_type(0x0BB5 + i, "Roomsettings", false, MAKE_PF_CB(process_roomThermostatMode)); // fetch for active circuits + register_telegram_type(0x1230 + i, "Roomparams", false, MAKE_PF_CB(process_roomThermostatParam)); // fetch for active circuits + register_telegram_type(0x1244 + i, "Roomdata", false, MAKE_PF_CB(process_roomThermostatData)); // broadcasted } // register_telegram_type(0xDB65, "Roomschedule", true, MAKE_PF_CB(process_roomSchedule)); // 0x2040, broadcast 36 bytes: @@ -84,6 +84,9 @@ std::shared_ptr Connect::room_circuit(const uint8_t num, c room_circuits_.push_back(new_room); // register the device values register_device_values_room(new_room); + toggle_fetch(0x0B3D + num, true); // name + toggle_fetch(0x0BB5 + num, true); // mode + toggle_fetch(0x1230 + num, true); // unknown return new_room; // return back point to new HC object } @@ -115,16 +118,13 @@ void Connect::process_roomThermostatName(std::shared_ptr telegra if (rc == nullptr) { return; } - if (telegram->offset > 1 || telegram->message_length < 3) { - return; - } - std::string s; - for (uint8_t i = 2 - telegram->offset; (i < telegram->message_length) && (telegram->message_data[i] != 0); i += 2) { - s += (char)telegram->message_data[i]; - } - if (s.length()) { - has_update(rc->name_, s.c_str(), s.length() + 1); + + for (uint8_t i = telegram->offset; i < telegram->message_length + telegram->offset && i < 100; i++) { + if ((i > 1) && (i % 2) == 0) { + rc->name_[(i - 2) / 2] = telegram->message_data[i]; + } } + rc->name_[50] = ' \0'; // make sure name is terminated } // settings 0-mode, 1-tempautotemp, 3 - manualtemp, 6,7 - ? @@ -137,10 +137,20 @@ void Connect::process_roomThermostatMode(std::shared_ptr telegra has_update(telegram, rc->mode_, 0); } +// unknown telegrams, needs fetch void Connect::process_roomThermostatParam(std::shared_ptr telegram) { + auto rc = room_circuit(telegram->type_id - 0x1230); + if (rc == nullptr) { + return; + } } +// unknown broadcasted telegrams void Connect::process_roomThermostatData(std::shared_ptr telegram) { + auto rc = room_circuit(telegram->type_id - 0x1244); + if (rc == nullptr) { + return; + } } // Settings: @@ -175,17 +185,22 @@ bool Connect::set_seltemp(const char * value, const int8_t id) { bool Connect::set_name(const char * value, const int8_t id) { auto rc = room_circuit(id - DeviceValueTAG::TAG_HS1); - if (rc == nullptr || value == nullptr || strlen(value) > 12) { + if (rc == nullptr || value == nullptr || strlen(value) > 50) { return false; } - uint8_t data[strlen(value) * 2]; - uint8_t * d = data; - const char * c = value; - while (*c != 0) { - *d++ = 0; - *d++ = *c++; + uint8_t len = strlen(value) * 2 + 2; + uint8_t data[len]; + for (uint8_t i = 0; i < strlen(value) + 1; i++) { // include terminating '\0' + data[2 * i] = 0; + data[2 * i + 1] = value[i]; + } + uint8_t ofs = 0; + while (len > 0) { + uint8_t part = len > 25 ? 25 : len; + write_command(0x0B3D + rc->room(), ofs + 1, &data[ofs], part, 0); + ofs += part; + len -= part; } - write_command(0x0B3D + rc->room(), 1, data, sizeof(data), 0x0B3D + rc->room()); return true; } diff --git a/src/devices/connect.h b/src/devices/connect.h index 877a4b824..3c1b48713 100644 --- a/src/devices/connect.h +++ b/src/devices/connect.h @@ -37,7 +37,7 @@ class Connect : public EMSdevice { int8_t humidity_; uint8_t seltemp_; uint8_t mode_; - char name_[25]; + char name_[51]; int16_t dewtemp_; uint8_t room() {