mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
@@ -333,8 +333,6 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
|||||||
auto new_hc = std::make_shared<Thermostat::HeatingCircuit>(hc_num, model());
|
auto new_hc = std::make_shared<Thermostat::HeatingCircuit>(hc_num, model());
|
||||||
heating_circuits_.push_back(new_hc);
|
heating_circuits_.push_back(new_hc);
|
||||||
|
|
||||||
new_hc->ha_climate_created(false); // set flag saying we're ready to create the MQTT Discovery Climate topic for this hc
|
|
||||||
|
|
||||||
// sort based on hc number so there's a nice order when displaying
|
// sort based on hc number so there's a nice order when displaying
|
||||||
// TODO temporarily commented out the HC sorting until I'm 100% sure the return object still references the newly created object
|
// TODO temporarily commented out the HC sorting until I'm 100% sure the return object still references the newly created object
|
||||||
// not sure if new_hc and heating_circuits_.back() will still reference the new HC after its sorted - to check!
|
// not sure if new_hc and heating_circuits_.back() will still reference the new HC after its sorted - to check!
|
||||||
@@ -371,121 +369,13 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
|||||||
return new_hc; // return back point to new HC object
|
return new_hc; // return back point to new HC object
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish config topic for HA MQTT Discovery for a heating circuit
|
// add the HVAC/Climate HA component for the HC
|
||||||
// e.g. homeassistant/climate/ems-esp/thermostat_hc1/config
|
void Thermostat::add_ha_climate(std::shared_ptr<HeatingCircuit> hc) {
|
||||||
void Thermostat::publish_ha_config_hc(std::shared_ptr<Thermostat::HeatingCircuit> hc) {
|
if (!Mqtt::ha_enabled()) {
|
||||||
uint8_t hc_num = hc->hc_num();
|
hc->climate = EMS_VALUE_UINT_NOTSET;
|
||||||
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
return;
|
||||||
|
|
||||||
char topic_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
|
||||||
char hc_mode_s[30];
|
|
||||||
char seltemp_s[30];
|
|
||||||
char currtemp_s[30];
|
|
||||||
char mode_str_tpl[400];
|
|
||||||
char name_s[30];
|
|
||||||
char uniq_id_s[30];
|
|
||||||
char temp_cmd_s[30];
|
|
||||||
char mode_cmd_s[30];
|
|
||||||
char min_s[10];
|
|
||||||
char max_s[10];
|
|
||||||
|
|
||||||
// https://github.com/emsesp/EMS-ESP32/issues/325#issuecomment-1022249093
|
|
||||||
// before you had to have a seltemp and roomtemp for the HA to work, now its optional
|
|
||||||
bool have_current_room_temp = Helpers::hasValue(hc->roomTemp);
|
|
||||||
|
|
||||||
if (Mqtt::is_nested()) {
|
|
||||||
// nested format
|
|
||||||
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.hc%d.mode", hc_num);
|
|
||||||
snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.hc%d.seltemp}}", hc_num);
|
|
||||||
if (have_current_room_temp) {
|
|
||||||
snprintf(currtemp_s, sizeof(currtemp_s), "{{value_json.hc%d.currtemp}}", hc_num);
|
|
||||||
}
|
}
|
||||||
snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str());
|
hc->climate = Helpers::hasValue(hc->roomTemp) ? 1 : Helpers::hasValue(hc->selTemp) ? 0 : EMS_VALUE_UINT_NOTSET;
|
||||||
} else {
|
|
||||||
// single format
|
|
||||||
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.mode");
|
|
||||||
snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.seltemp}}");
|
|
||||||
if (have_current_room_temp) {
|
|
||||||
snprintf(currtemp_s, sizeof(currtemp_s), "{{value_json.currtemp}}");
|
|
||||||
}
|
|
||||||
snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_HC1 + hc_num - 1).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(mode_str_tpl,
|
|
||||||
sizeof(mode_str_tpl),
|
|
||||||
"{%%if %s=='manual'%%}heat{%%elif %s=='day'%%}heat{%%elif %s=='night'%%}off{%%elif %s=='off'%%}off{%%else%%}auto{%%endif%%}",
|
|
||||||
hc_mode_s,
|
|
||||||
hc_mode_s,
|
|
||||||
hc_mode_s,
|
|
||||||
hc_mode_s);
|
|
||||||
|
|
||||||
snprintf(name_s, sizeof(name_s), "Thermostat hc%d", hc_num);
|
|
||||||
snprintf(uniq_id_s, sizeof(uniq_id_s), "thermostat_hc%d", hc_num);
|
|
||||||
snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num);
|
|
||||||
snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num);
|
|
||||||
|
|
||||||
doc["~"] = Mqtt::base();
|
|
||||||
doc["name"] = name_s;
|
|
||||||
doc["uniq_id"] = uniq_id_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"] = seltemp_s;
|
|
||||||
doc["mode_cmd_t"] = mode_cmd_s;
|
|
||||||
|
|
||||||
if (have_current_room_temp) {
|
|
||||||
doc["curr_temp_t"] = topic_t;
|
|
||||||
doc["curr_temp_tpl"] = currtemp_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc["min_temp"] = Helpers::render_value(min_s, 5, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
|
|
||||||
doc["max_temp"] = Helpers::render_value(max_s, 30, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
|
|
||||||
doc["temp_step"] = "0.5";
|
|
||||||
|
|
||||||
// the HA climate component only responds to auto, heat and off
|
|
||||||
JsonArray modes = doc.createNestedArray("modes");
|
|
||||||
|
|
||||||
if (model() != EMSdevice::EMS_DEVICE_FLAG_RC10) {
|
|
||||||
modes.add("auto");
|
|
||||||
}
|
|
||||||
|
|
||||||
modes.add("heat");
|
|
||||||
modes.add("off");
|
|
||||||
|
|
||||||
JsonObject dev = doc.createNestedObject("dev");
|
|
||||||
JsonArray ids = dev.createNestedArray("ids");
|
|
||||||
ids.add("ems-esp-thermostat");
|
|
||||||
|
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
|
||||||
snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::base().c_str(), hc_num);
|
|
||||||
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
|
||||||
}
|
|
||||||
|
|
||||||
// for HA specifically when receiving over MQTT in the thermostat topic
|
|
||||||
// e.g. thermostat_hc1
|
|
||||||
// it could be either a 'mode' or a float value for a temperature. we try brute force both and see which one works.
|
|
||||||
// return true if it parses the message correctly
|
|
||||||
bool Thermostat::thermostat_ha_cmd(const char * message, uint8_t hc_num) {
|
|
||||||
// check if it's json. We know the message isn't empty
|
|
||||||
if (message[0] == '{') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for mode first, which is a string
|
|
||||||
if (message[0] >= 'A') {
|
|
||||||
if (set_mode(message, hc_num)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((message[0] >= '0' && message[0] <= '9') || message[0] == '-') {
|
|
||||||
// otherwise handle as a numerical temperature value and set the setpoint temp
|
|
||||||
float f = strtof((char *)message, 0);
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodes the thermostat mode for the heating circuit based on the thermostat type
|
// decodes the thermostat mode for the heating circuit based on the thermostat type
|
||||||
@@ -669,27 +559,6 @@ void Thermostat::process_RC10Monitor(std::shared_ptr<const Telegram> telegram) {
|
|||||||
add_ha_climate(hc);
|
add_ha_climate(hc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the HVAC/Climate HA component for the HC
|
|
||||||
void Thermostat::add_ha_climate(std::shared_ptr<HeatingCircuit> hc) {
|
|
||||||
if (!Mqtt::ha_enabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// note, this doesn't account for whether any of the device values have been excluded
|
|
||||||
if (hc->ha_climate_created()) {
|
|
||||||
// see if we've lost the selTemp (roomTemp/currTemp is optional and checked in the publish_ha_config_hc() function)
|
|
||||||
if (!Helpers::hasValue(hc->selTemp)) {
|
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
|
||||||
snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::base().c_str(), hc->hc_num());
|
|
||||||
Mqtt::publish_ha(topic);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// create the climate component, only once
|
|
||||||
publish_ha_config_hc(hc);
|
|
||||||
hc->ha_climate_created(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// type 0xB0 - for reading the mode from the RC10 thermostat (0x17)
|
// type 0xB0 - for reading the mode from the RC10 thermostat (0x17)
|
||||||
// Data: 00 FF 00 1C 20 08 01
|
// Data: 00 FF 00 1C 20 08 01
|
||||||
void Thermostat::process_RC10Set(std::shared_ptr<const Telegram> telegram) {
|
void Thermostat::process_RC10Set(std::shared_ptr<const Telegram> telegram) {
|
||||||
@@ -817,8 +686,6 @@ void Thermostat::process_RC20Set_2(std::shared_ptr<const Telegram> telegram) {
|
|||||||
has_update(telegram, hc->minflowtemp, 15);
|
has_update(telegram, hc->minflowtemp, 15);
|
||||||
has_update(telegram, hc->maxflowtemp, 16);
|
has_update(telegram, hc->maxflowtemp, 16);
|
||||||
has_update(telegram, hc->summertemp, 17);
|
has_update(telegram, hc->summertemp, 17);
|
||||||
|
|
||||||
add_ha_climate(hc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xAF - for reading the roomtemperature from the RC20/ES72 thermostat (0x18, 0x19, ..)
|
// 0xAF - for reading the roomtemperature from the RC20/ES72 thermostat (0x18, 0x19, ..)
|
||||||
@@ -827,8 +694,7 @@ void Thermostat::process_RC20Remote(std::shared_ptr<const Telegram> telegram) {
|
|||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
has_update(telegram, hc->roomTemp, 0);
|
has_update(telegram, hc->remotetemp, 0);
|
||||||
add_ha_climate(hc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type 0x0165, ff
|
// type 0x0165, ff
|
||||||
@@ -844,8 +710,6 @@ void Thermostat::process_JunkersSet(std::shared_ptr<const Telegram> telegram) {
|
|||||||
has_update(telegram, hc->control, 1); // remote: 0-off, 1-FB10, 2-FB100
|
has_update(telegram, hc->control, 1); // remote: 0-off, 1-FB10, 2-FB100
|
||||||
has_enumupdate(telegram, hc->program, 13, 1); // 1-6: 1 = A, 2 = B,...
|
has_enumupdate(telegram, hc->program, 13, 1); // 1-6: 1 = A, 2 = B,...
|
||||||
has_enumupdate(telegram, hc->mode, 14, 1); // 0 = nofrost, 1 = eco, 2 = heat, 3 = auto
|
has_enumupdate(telegram, hc->mode, 14, 1); // 0 = nofrost, 1 = eco, 2 = heat, 3 = auto
|
||||||
|
|
||||||
add_ha_climate(hc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type 0x0179, ff
|
// type 0x0179, ff
|
||||||
@@ -860,8 +724,6 @@ void Thermostat::process_JunkersSet2(std::shared_ptr<const Telegram> telegram) {
|
|||||||
has_update(telegram, hc->nofrosttemp, 5); // is * 2
|
has_update(telegram, hc->nofrosttemp, 5); // is * 2
|
||||||
has_enumupdate(telegram, hc->program, 10, 1); // 1-6: 1 = A, 2 = B,...
|
has_enumupdate(telegram, hc->program, 10, 1); // 1-6: 1 = A, 2 = B,...
|
||||||
has_enumupdate(telegram, hc->mode, 4, 1); // 0 = nofrost, 1 = eco, 2 = heat, 3 = auto
|
has_enumupdate(telegram, hc->mode, 4, 1); // 0 = nofrost, 1 = eco, 2 = heat, 3 = auto
|
||||||
|
|
||||||
add_ha_climate(hc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type 0x123 - FR10/FR110 Junkers as remote
|
// type 0x123 - FR10/FR110 Junkers as remote
|
||||||
@@ -870,8 +732,7 @@ void Thermostat::process_JunkersRemoteMonitor(std::shared_ptr<const Telegram> te
|
|||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
has_update(telegram, hc->roomTemp, 0); // roomTemp from remote
|
has_update(telegram, hc->remotetemp, 0); // roomTemp from remote
|
||||||
add_ha_climate(hc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type 0xA3 - for external temp settings from the the RC* thermostats (e.g. RC35)
|
// type 0xA3 - for external temp settings from the the RC* thermostats (e.g. RC35)
|
||||||
@@ -892,6 +753,7 @@ void Thermostat::process_RC20Monitor(std::shared_ptr<const Telegram> telegram) {
|
|||||||
|
|
||||||
has_update(telegram, hc->selTemp, 1, 1); // is * 2, force as single byte
|
has_update(telegram, hc->selTemp, 1, 1); // is * 2, force as single byte
|
||||||
has_update(telegram, hc->roomTemp, 2); // is * 10
|
has_update(telegram, hc->roomTemp, 2); // is * 10
|
||||||
|
|
||||||
add_ha_climate(hc);
|
add_ha_climate(hc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,6 +766,7 @@ void Thermostat::process_EasyMonitor(std::shared_ptr<const Telegram> telegram) {
|
|||||||
|
|
||||||
has_update(telegram, hc->roomTemp, 8); // is * 100
|
has_update(telegram, hc->roomTemp, 8); // is * 100
|
||||||
has_update(telegram, hc->selTemp, 10); // is * 100
|
has_update(telegram, hc->selTemp, 10); // is * 100
|
||||||
|
|
||||||
add_ha_climate(hc);
|
add_ha_climate(hc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,8 +1056,6 @@ void Thermostat::process_RC30Set(std::shared_ptr<const Telegram> telegram) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
has_update(telegram, hc->mode, 23);
|
has_update(telegram, hc->mode, 23);
|
||||||
|
|
||||||
add_ha_climate(hc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes
|
// type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes
|
||||||
@@ -1216,15 +1077,7 @@ void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
has_update(telegram, hc->selTemp, 2, 1); // is * 2, force to single byte, is 0 in summermode
|
has_update(telegram, hc->selTemp, 2, 1); // is * 2, force to single byte, is 0 in summermode
|
||||||
int16_t roomTemp = hc->roomTemp;
|
|
||||||
has_update(telegram, hc->roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler
|
has_update(telegram, hc->roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler
|
||||||
// publish zero if there was a roomtemp, but now is missing
|
|
||||||
if (Helpers::hasValue(roomTemp) && !Helpers::hasValue(hc->roomTemp)) {
|
|
||||||
roomTemp = hc->roomTemp;
|
|
||||||
hc->roomTemp = 0;
|
|
||||||
has_update(hc->roomTemp);
|
|
||||||
hc->roomTemp = roomTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
has_bitupdate(telegram, hc->modetype, 1, 1);
|
has_bitupdate(telegram, hc->modetype, 1, 1);
|
||||||
has_bitupdate(telegram, hc->summermode, 1, 0);
|
has_bitupdate(telegram, hc->summermode, 1, 0);
|
||||||
@@ -1273,8 +1126,6 @@ void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
|
|||||||
has_update(telegram, hc->designtemp, 17); // is * 1
|
has_update(telegram, hc->designtemp, 17); // is * 1
|
||||||
has_update(telegram, hc->maxflowtemp, 15); // is * 1
|
has_update(telegram, hc->maxflowtemp, 15); // is * 1
|
||||||
}
|
}
|
||||||
|
|
||||||
add_ha_climate(hc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type 0x3F (HC1), 0x49 (HC2), 0x53 (HC3), 0x5D (HC4) - timer setting
|
// type 0x3F (HC1), 0x49 (HC2), 0x53 (HC3), 0x5D (HC4) - timer setting
|
||||||
@@ -1512,7 +1363,7 @@ bool Thermostat::set_remotetemp(const char * value, const int8_t id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Roomctrl::set_remotetemp(hc->hc(), hc->remotetemp);
|
Roomctrl::set_remotetemp(hc->hc(), hc->remotetemp);
|
||||||
// has_update(hc->remotetemp);
|
has_update(hc->remotetemp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3357,6 +3208,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
|
|||||||
if (device_id() != EMSESP::actual_master_thermostat()) {
|
if (device_id() != EMSESP::actual_master_thermostat()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
register_device_value(tag, &hc->climate, DeviceValueType::ENUM, FL_(enum_climate), FL_(climate), DeviceValueUOM::NONE);
|
||||||
|
|
||||||
switch (model) {
|
switch (model) {
|
||||||
case EMS_DEVICE_FLAG_RC10:
|
case EMS_DEVICE_FLAG_RC10:
|
||||||
@@ -3423,6 +3275,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
|
|||||||
tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype));
|
tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype));
|
||||||
register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp));
|
register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp));
|
||||||
register_device_value(tag, &hc->summermode, DeviceValueType::ENUM, FL_(enum_summer), FL_(summermode), DeviceValueUOM::NONE);
|
register_device_value(tag, &hc->summermode, DeviceValueType::ENUM, FL_(enum_summer), FL_(summermode), DeviceValueUOM::NONE);
|
||||||
|
register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES);
|
||||||
break;
|
break;
|
||||||
case EMS_DEVICE_FLAG_RC25:
|
case EMS_DEVICE_FLAG_RC25:
|
||||||
register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode3), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode));
|
register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode3), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode));
|
||||||
@@ -3488,6 +3341,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
|
|||||||
register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(div2), FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp));
|
register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(div2), FL_(nofrosttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nofrosttemp));
|
||||||
register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_j_control), FL_(control), DeviceValueUOM::NONE, MAKE_CF_CB(set_control));
|
register_device_value(tag, &hc->control, DeviceValueType::ENUM, FL_(enum_j_control), FL_(control), DeviceValueUOM::NONE, MAKE_CF_CB(set_control));
|
||||||
register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode4), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program));
|
register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode4), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program));
|
||||||
|
register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class Thermostat : public EMSdevice {
|
|||||||
char vacation[26];
|
char vacation[26];
|
||||||
char switchtime1[16];
|
char switchtime1[16];
|
||||||
char switchtime2[16];
|
char switchtime2[16];
|
||||||
|
uint8_t climate;
|
||||||
|
|
||||||
// RC 10
|
// RC 10
|
||||||
uint8_t reducehours; // night reduce duration
|
uint8_t reducehours; // night reduce duration
|
||||||
@@ -96,14 +97,6 @@ class Thermostat : public EMSdevice {
|
|||||||
return Helpers::hasValue(selTemp);
|
return Helpers::hasValue(selTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ha_climate_created() {
|
|
||||||
return ha_climate_created_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ha_climate_created(bool ha_climate_created) {
|
|
||||||
ha_climate_created_ = ha_climate_created;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t get_mode() const;
|
uint8_t get_mode() const;
|
||||||
uint8_t get_mode_type() const;
|
uint8_t get_mode_type() const;
|
||||||
|
|
||||||
@@ -142,7 +135,6 @@ class Thermostat : public EMSdevice {
|
|||||||
private:
|
private:
|
||||||
uint8_t hc_num_; // heating circuit number 1..10
|
uint8_t hc_num_; // heating circuit number 1..10
|
||||||
uint8_t model_; // the model type
|
uint8_t model_; // the model type
|
||||||
bool ha_climate_created_; // if we need to create the HA climate control
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string mode_tostring(uint8_t mode);
|
static std::string mode_tostring(uint8_t mode);
|
||||||
@@ -298,10 +290,8 @@ class Thermostat : public EMSdevice {
|
|||||||
std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(std::shared_ptr<const Telegram> telegram);
|
std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(std::shared_ptr<const Telegram> telegram);
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(const uint8_t hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(const uint8_t hc_num);
|
||||||
|
|
||||||
void publish_ha_config_hc(std::shared_ptr<Thermostat::HeatingCircuit> hc);
|
|
||||||
void register_device_values_hc(std::shared_ptr<Thermostat::HeatingCircuit> hc);
|
void register_device_values_hc(std::shared_ptr<Thermostat::HeatingCircuit> hc);
|
||||||
|
|
||||||
bool thermostat_ha_cmd(const char * message, uint8_t hc_num);
|
|
||||||
void add_ha_climate(std::shared_ptr<HeatingCircuit> hc);
|
void add_ha_climate(std::shared_ptr<HeatingCircuit> hc);
|
||||||
|
|
||||||
void process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram);
|
void process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|||||||
@@ -1233,6 +1233,9 @@ void EMSdevice::mqtt_ha_entity_config_remove() {
|
|||||||
&& ((!dv.has_state(DeviceValueState::DV_VISIBLE)) || (!dv.has_state(DeviceValueState::DV_ACTIVE)))) {
|
&& ((!dv.has_state(DeviceValueState::DV_VISIBLE)) || (!dv.has_state(DeviceValueState::DV_ACTIVE)))) {
|
||||||
Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true)
|
Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true)
|
||||||
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
|
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
|
||||||
|
if (dv.short_name == FL_(climate)[0]) {
|
||||||
|
Mqtt::publish_ha_climate_config(dv.tag, false, true); // delete topic (remove = true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1243,9 +1246,19 @@ void EMSdevice::mqtt_ha_entity_config_create() {
|
|||||||
bool create_device_config = !ha_config_done(); // do we need to create the main Discovery device config with this entity?
|
bool create_device_config = !ha_config_done(); // do we need to create the main Discovery device config with this entity?
|
||||||
|
|
||||||
// check the state of each of the device values
|
// check the state of each of the device values
|
||||||
|
// create climate if roomtemp is visible
|
||||||
// create the discovery topic if if hasn't already been created, not a command (like reset) and is active and visible
|
// create the discovery topic if if hasn't already been created, not a command (like reset) and is active and visible
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
if ((!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && dv.type != DeviceValueType::CMD) && dv.has_state(DeviceValueState::DV_ACTIVE)
|
if ((dv.short_name == FL_(climate)[0]) && dv.has_state(DeviceValueState::DV_VISIBLE) && dv.has_state(DeviceValueState::DV_ACTIVE)) {
|
||||||
|
if (*(int8_t *)(dv.value_p) == 1 && (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) || dv.has_state(DeviceValueState::DV_HA_CLIMATE_NO_RT))) {
|
||||||
|
dv.remove_state(DeviceValueState::DV_HA_CLIMATE_NO_RT);
|
||||||
|
Mqtt::publish_ha_climate_config(dv.tag, true);
|
||||||
|
} else if (*(int8_t *)(dv.value_p) == 0 && (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) || !dv.has_state(DeviceValueState::DV_HA_CLIMATE_NO_RT))) {
|
||||||
|
dv.add_state(DeviceValueState::DV_HA_CLIMATE_NO_RT);
|
||||||
|
Mqtt::publish_ha_climate_config(dv.tag, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && (dv.type != DeviceValueType::CMD) && dv.has_state(DeviceValueState::DV_ACTIVE)
|
||||||
&& dv.has_state(DeviceValueState::DV_VISIBLE)) {
|
&& dv.has_state(DeviceValueState::DV_VISIBLE)) {
|
||||||
// create_device_config is only done once for the EMS device. It can added to any entity, so we take the first
|
// create_device_config is only done once for the EMS device. It can added to any entity, so we take the first
|
||||||
Mqtt::publish_ha_sensor_config(dv, name(), brand_to_string(), false, create_device_config);
|
Mqtt::publish_ha_sensor_config(dv, name(), brand_to_string(), false, create_device_config);
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ class DeviceValue {
|
|||||||
DV_DEFAULT = 0, // 0 - does not yet have a value
|
DV_DEFAULT = 0, // 0 - does not yet have a value
|
||||||
DV_ACTIVE = (1 << 0), // 1 - has a validated real value
|
DV_ACTIVE = (1 << 0), // 1 - has a validated real value
|
||||||
DV_VISIBLE = (1 << 1), // 2 - shown on web, console and on MQTT payload. Otherwise hidden
|
DV_VISIBLE = (1 << 1), // 2 - shown on web, console and on MQTT payload. Otherwise hidden
|
||||||
DV_HA_CONFIG_CREATED = (1 << 2) // 4 - set if the HA config topic has been created
|
DV_HA_CONFIG_CREATED = (1 << 2), // 4 - set if the HA config topic has been created
|
||||||
|
DV_HA_CLIMATE_NO_RT = (1 << 3) // 8 - climate created without roomTemp
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t device_type; // EMSdevice::DeviceType
|
uint8_t device_type; // EMSdevice::DeviceType
|
||||||
|
|||||||
@@ -387,6 +387,7 @@ MAKE_PSTR_LIST(enum_progMode3, F("Familie"), F("Morgends"), F("Abends"), F("Vorm
|
|||||||
MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f"))
|
MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f"))
|
||||||
|
|
||||||
MAKE_PSTR_LIST(enum_switchmode, F_(off), F_(eco), F_(comfort), F_(heat))
|
MAKE_PSTR_LIST(enum_switchmode, F_(off), F_(eco), F_(comfort), F_(heat))
|
||||||
|
MAKE_PSTR_LIST(enum_climate, F("Solltemperature"), F("Raumtemperatur"))
|
||||||
|
|
||||||
// solar list
|
// solar list
|
||||||
MAKE_PSTR_LIST(enum_solarmode, F_(constant), F("pwm"), F("analog"))
|
MAKE_PSTR_LIST(enum_solarmode, F_(constant), F("pwm"), F("analog"))
|
||||||
@@ -581,6 +582,7 @@ MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("Kreis 2 Extra"))
|
|||||||
MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating"))
|
MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating"))
|
||||||
MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time"))
|
MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time"))
|
||||||
// thermostat hc
|
// thermostat hc
|
||||||
|
MAKE_PSTR_LIST(climate, F("climate"), F("Klima Anzeige"))
|
||||||
MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("Sollwert Raumtemperatur"))
|
MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("Sollwert Raumtemperatur"))
|
||||||
MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("aktuelle Raumtemperatur"))
|
MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("aktuelle Raumtemperatur"))
|
||||||
MAKE_PSTR_LIST(mode, F("mode"), F("modus"))
|
MAKE_PSTR_LIST(mode, F("mode"), F("modus"))
|
||||||
|
|||||||
@@ -387,6 +387,7 @@ MAKE_PSTR_LIST(enum_progMode3, F("family"), F("morning"), F("evening"), F("am"),
|
|||||||
MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f"))
|
MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f"))
|
||||||
|
|
||||||
MAKE_PSTR_LIST(enum_switchmode, F_(off), F_(eco), F_(comfort), F_(heat))
|
MAKE_PSTR_LIST(enum_switchmode, F_(off), F_(eco), F_(comfort), F_(heat))
|
||||||
|
MAKE_PSTR_LIST(enum_climate, F("selTemp"), F("roomTemp"))
|
||||||
|
|
||||||
// solar list
|
// solar list
|
||||||
MAKE_PSTR_LIST(enum_solarmode, F_(constant), F("pwm"), F("analog"))
|
MAKE_PSTR_LIST(enum_solarmode, F_(constant), F("pwm"), F("analog"))
|
||||||
@@ -582,6 +583,7 @@ MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra"))
|
|||||||
MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating"))
|
MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating"))
|
||||||
MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time"))
|
MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time"))
|
||||||
// thermostat hc
|
// thermostat hc
|
||||||
|
MAKE_PSTR_LIST(climate, F("climate"), F("climate entity"))
|
||||||
MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature"))
|
MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature"))
|
||||||
MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("current room temperature"))
|
MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("current room temperature"))
|
||||||
MAKE_PSTR_LIST(mode, F("mode"), F("mode"))
|
MAKE_PSTR_LIST(mode, F("mode"), F("mode"))
|
||||||
|
|||||||
90
src/mqtt.cpp
90
src/mqtt.cpp
@@ -49,6 +49,7 @@ std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
|
|||||||
uint32_t Mqtt::mqtt_publish_fails_ = 0;
|
uint32_t Mqtt::mqtt_publish_fails_ = 0;
|
||||||
bool Mqtt::connecting_ = false;
|
bool Mqtt::connecting_ = false;
|
||||||
bool Mqtt::initialized_ = false;
|
bool Mqtt::initialized_ = false;
|
||||||
|
bool Mqtt::ha_climate_reset_ = false;
|
||||||
uint8_t Mqtt::connectcount_ = 0;
|
uint8_t Mqtt::connectcount_ = 0;
|
||||||
uint32_t Mqtt::mqtt_message_id_ = 0;
|
uint32_t Mqtt::mqtt_message_id_ = 0;
|
||||||
char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer
|
char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer
|
||||||
@@ -581,6 +582,7 @@ void Mqtt::on_connect() {
|
|||||||
queue_unsubscribe_message(discovery_prefix_ + "/switch/" + mqtt_base_ + "/#");
|
queue_unsubscribe_message(discovery_prefix_ + "/switch/" + mqtt_base_ + "/#");
|
||||||
EMSESP::reset_mqtt_ha(); // re-create all HA devices if there are any
|
EMSESP::reset_mqtt_ha(); // re-create all HA devices if there are any
|
||||||
ha_status(); // create the EMS-ESP device in HA, which is MQTT retained
|
ha_status(); // create the EMS-ESP device in HA, which is MQTT retained
|
||||||
|
ha_climate_reset(true);
|
||||||
} else {
|
} else {
|
||||||
queue_subscribe_message(discovery_prefix_ + "/climate/" + mqtt_base_ + "/#");
|
queue_subscribe_message(discovery_prefix_ + "/climate/" + mqtt_base_ + "/#");
|
||||||
queue_subscribe_message(discovery_prefix_ + "/sensor/" + mqtt_base_ + "/#");
|
queue_subscribe_message(discovery_prefix_ + "/sensor/" + mqtt_base_ + "/#");
|
||||||
@@ -1220,6 +1222,94 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
|
|||||||
publish_ha(topic, doc.as<JsonObject>());
|
publish_ha(topic, doc.as<JsonObject>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove) {
|
||||||
|
uint8_t hc_num = tag - DeviceValueTAG::TAG_HC1 + 1;
|
||||||
|
|
||||||
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
|
char topic_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
|
char hc_mode_s[30];
|
||||||
|
char seltemp_s[30];
|
||||||
|
char currtemp_s[30];
|
||||||
|
char mode_str_tpl[400];
|
||||||
|
char name_s[30];
|
||||||
|
char uniq_id_s[30];
|
||||||
|
char temp_cmd_s[30];
|
||||||
|
char mode_cmd_s[30];
|
||||||
|
char min_s[10];
|
||||||
|
char max_s[10];
|
||||||
|
|
||||||
|
snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::base().c_str(), hc_num);
|
||||||
|
if (remove) {
|
||||||
|
publish_ha(topic); // publish empty payload with retain flag
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Mqtt::is_nested()) {
|
||||||
|
// nested format
|
||||||
|
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.hc%d.mode", hc_num);
|
||||||
|
snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.hc%d.seltemp}}", hc_num);
|
||||||
|
if (has_roomtemp) {
|
||||||
|
snprintf(currtemp_s, sizeof(currtemp_s), "{{value_json.hc%d.currtemp}}", hc_num);
|
||||||
|
}
|
||||||
|
snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str());
|
||||||
|
} else {
|
||||||
|
// single format
|
||||||
|
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.mode");
|
||||||
|
snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.seltemp}}");
|
||||||
|
if (has_roomtemp) {
|
||||||
|
snprintf(currtemp_s, sizeof(currtemp_s), "{{value_json.currtemp}}");
|
||||||
|
}
|
||||||
|
snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_HC1 + hc_num - 1).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(mode_str_tpl,
|
||||||
|
sizeof(mode_str_tpl),
|
||||||
|
"{%%if %s=='manual'%%}heat{%%elif %s=='day'%%}heat{%%elif %s=='night'%%}off{%%elif %s=='off'%%}off{%%else%%}auto{%%endif%%}",
|
||||||
|
hc_mode_s,
|
||||||
|
hc_mode_s,
|
||||||
|
hc_mode_s,
|
||||||
|
hc_mode_s);
|
||||||
|
|
||||||
|
snprintf(name_s, sizeof(name_s), "Thermostat hc%d", hc_num);
|
||||||
|
snprintf(uniq_id_s, sizeof(uniq_id_s), "thermostat_hc%d", hc_num);
|
||||||
|
snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num);
|
||||||
|
snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num);
|
||||||
|
|
||||||
|
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
||||||
|
|
||||||
|
doc["~"] = base();
|
||||||
|
doc["name"] = name_s;
|
||||||
|
doc["uniq_id"] = uniq_id_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"] = seltemp_s;
|
||||||
|
doc["mode_cmd_t"] = mode_cmd_s;
|
||||||
|
|
||||||
|
if (has_roomtemp) {
|
||||||
|
doc["curr_temp_t"] = topic_t;
|
||||||
|
doc["curr_temp_tpl"] = currtemp_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
doc["min_temp"] = Helpers::render_value(min_s, 5, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
|
||||||
|
doc["max_temp"] = Helpers::render_value(max_s, 30, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
|
||||||
|
doc["temp_step"] = "0.5";
|
||||||
|
|
||||||
|
// the HA climate component only responds to auto, heat and off
|
||||||
|
JsonArray modes = doc.createNestedArray("modes");
|
||||||
|
|
||||||
|
modes.add("auto");
|
||||||
|
modes.add("heat");
|
||||||
|
modes.add("off");
|
||||||
|
|
||||||
|
JsonObject dev = doc.createNestedObject("dev");
|
||||||
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
|
ids.add("ems-esp-thermostat");
|
||||||
|
|
||||||
|
publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
}
|
||||||
|
|
||||||
// based on the device and tag, create the MQTT topic name (without the basename)
|
// based on the device and tag, create the MQTT topic name (without the basename)
|
||||||
// differs based on whether MQTT nested is enabled
|
// differs based on whether MQTT nested is enabled
|
||||||
// tag = EMSdevice::DeviceValueTAG
|
// tag = EMSdevice::DeviceValueTAG
|
||||||
|
|||||||
10
src/mqtt.h
10
src/mqtt.h
@@ -107,6 +107,7 @@ class Mqtt {
|
|||||||
const JsonObject & dev_json);
|
const JsonObject & dev_json);
|
||||||
|
|
||||||
static void publish_system_ha_sensor_config(uint8_t type, const __FlashStringHelper * name, const __FlashStringHelper * entity, const uint8_t uom);
|
static void publish_system_ha_sensor_config(uint8_t type, const __FlashStringHelper * name, const __FlashStringHelper * entity, const uint8_t uom);
|
||||||
|
static void publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove = false);
|
||||||
|
|
||||||
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
|
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
|
||||||
static void show_mqtt(uuid::console::Shell & shell);
|
static void show_mqtt(uuid::console::Shell & shell);
|
||||||
@@ -191,6 +192,14 @@ class Mqtt {
|
|||||||
ha_enabled_ = ha_enabled;
|
ha_enabled_ = ha_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ha_climate_reset() {
|
||||||
|
return ha_climate_reset_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ha_climate_reset(bool reset) {
|
||||||
|
ha_climate_reset_ = reset;;
|
||||||
|
}
|
||||||
|
|
||||||
static bool send_response() {
|
static bool send_response() {
|
||||||
return send_response_;
|
return send_response_;
|
||||||
}
|
}
|
||||||
@@ -276,6 +285,7 @@ class Mqtt {
|
|||||||
static bool initialized_;
|
static bool initialized_;
|
||||||
static uint32_t mqtt_publish_fails_;
|
static uint32_t mqtt_publish_fails_;
|
||||||
static uint8_t connectcount_;
|
static uint8_t connectcount_;
|
||||||
|
static bool ha_climate_reset_;
|
||||||
|
|
||||||
// settings, copied over
|
// settings, copied over
|
||||||
static std::string mqtt_base_;
|
static std::string mqtt_base_;
|
||||||
|
|||||||
Reference in New Issue
Block a user