rename HA dev_i, SRC: do not fetch inactive circuits, long names, HA climated

This commit is contained in:
MichaelDvP
2025-10-02 11:49:53 +02:00
parent d88513d789
commit f782eac0cf
4 changed files with 78 additions and 53 deletions

View File

@@ -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;

View File

@@ -529,7 +529,7 @@ void Mqtt::ha_status() {
}
doc["uniq_id"] = uniq;
doc["obj_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
@@ -981,7 +981,7 @@ 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["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,22 +1302,22 @@ 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["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;
@@ -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<JsonObject>(), "thermostat", nullptr, nullptr, nullptr, false); // add dev section
add_ha_dev_section(doc.as<JsonObject>(), devicename, nullptr, nullptr, nullptr, false); // add dev section
add_ha_avail_section(doc.as<JsonObject>(), topic_t, false, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); // add availability section
return queue_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag

View File

@@ -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::RoomCircuit> 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<const Telegram> telegra
if (rc == nullptr) {
return;
}
if (telegram->offset > 1 || telegram->message_length < 3) {
return;
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];
}
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);
}
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<const Telegram> telegra
has_update(telegram, rc->mode_, 0);
}
// unknown telegrams, needs fetch
void Connect::process_roomThermostatParam(std::shared_ptr<const Telegram> telegram) {
auto rc = room_circuit(telegram->type_id - 0x1230);
if (rc == nullptr) {
return;
}
}
// unknown broadcasted telegrams
void Connect::process_roomThermostatData(std::shared_ptr<const Telegram> 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;
}

View File

@@ -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() {