Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
hpanther
2020-11-14 22:54:53 +01:00
66 changed files with 2648 additions and 1854 deletions

View File

@@ -74,11 +74,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
// create the config topics for Home Assistant MQTT Discovery
// for each of the main elements
void Boiler::register_mqtt_ha_config(bool force) {
if ((mqtt_ha_config_ && !force)) {
return;
}
void Boiler::register_mqtt_ha_config() {
if (!Mqtt::connected()) {
return;
}
@@ -141,8 +137,17 @@ void Boiler::register_mqtt_ha_config(bool force) {
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(burnWorkMin), this->device_type(), "burnWorkMin", F_(min), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(heatWorkMin), this->device_type(), "heatWorkMin", F_(min), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(UBAuptime), this->device_type(), "UBAuptime", F_(min), nullptr);
mqtt_ha_config_ = true; // done
}
// ww
// create the config topics for Home Assistant MQTT Discovery
// for each of the ww elements
void Boiler::register_mqtt_ha_config_ww() {
if (!Mqtt::connected()) {
return;
}
// ww
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWSelTemp), this->device_type(), "wWSelTemp", F_(degrees), F_(iconcruise));
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWSetTemp), this->device_type(), "wWSetTemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWDisinfectionTemp), this->device_type(), "wWDisinfectionTemp", F_(degrees), F_(icontemperature));
@@ -170,14 +175,15 @@ void Boiler::register_mqtt_ha_config(bool force) {
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWStarts), this->device_type(), "wWStarts", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, F_(mqtt_suffix_ww), F_(wWWorkM), this->device_type(), "wWWorkM", F_(min), nullptr);
mqtt_ha_config_ = true; // done
mqtt_ha_config_ww_ = true; // done
}
// send stuff to the Web UI
void Boiler::device_info_web(JsonArray & root) {
// fetch the values into a JSON document
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
JsonObject json = doc.to<JsonObject>();
// DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json = doc.to<JsonObject>();
if (!export_values_main(json)) {
return; // empty
}
@@ -618,19 +624,29 @@ bool Boiler::export_values_main(JsonObject & json) {
void Boiler::publish_values(JsonObject & json, bool force) {
// handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force);
if (force) {
mqtt_ha_config_ = false;
mqtt_ha_config_ww_ = false;
}
// register ww in next cycle if both unregistered
if (!mqtt_ha_config_) {
register_mqtt_ha_config();
return;
} else if (!mqtt_ha_config_ww_) {
register_mqtt_ha_config_ww();
return;
}
}
DynamicJsonDocument doc_main(EMSESP_MAX_JSON_SIZE_LARGE);
JsonObject json_main = doc_main.to<JsonObject>();
if (export_values_main(json_main)) {
Mqtt::publish(F("boiler_data"), doc_main.as<JsonObject>());
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json_data = doc.to<JsonObject>();
if (export_values_main(json_data)) {
Mqtt::publish(F("boiler_data"), json_data);
}
json_data.clear();
DynamicJsonDocument doc_ww(EMSESP_MAX_JSON_SIZE_LARGE);
JsonObject json_ww = doc_ww.to<JsonObject>();
if (export_values_ww(json_ww)) {
Mqtt::publish(F("boiler_data_ww"), doc_ww.as<JsonObject>());
if (export_values_ww(json_data)) {
Mqtt::publish(F("boiler_data_ww"), json_data);
}
// send out heating and tapwater status
@@ -651,13 +667,14 @@ void Boiler::show_values(uuid::console::Shell & shell) {
EMSdevice::show_values(shell); // for showing the header
// fetch the values into a JSON document
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
JsonObject json = doc.to<JsonObject>();
// DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json = doc.to<JsonObject>();
if (!export_values_main(json)) {
return; // empty
}
export_values_ww(json); // append ww values
doc.shrinkToFit();
// doc.shrinkToFit();
print_value_json(shell, F("heatingActive"), nullptr, F_(heatingActive), nullptr, json);
print_value_json(shell, F("tapwaterActive"), nullptr, F_(tapwaterActive), nullptr, json);

View File

@@ -47,13 +47,15 @@ class Boiler : public EMSdevice {
private:
static uuid::log::Logger logger_;
void register_mqtt_ha_config(bool force);
void register_mqtt_ha_config();
void register_mqtt_ha_config_ww();
void check_active();
bool export_values_main(JsonObject & doc);
bool export_values_ww(JsonObject & doc);
bool changed_ = false;
bool mqtt_ha_config_ = false; // HA MQTT Discovery
bool changed_ = false;
bool mqtt_ha_config_ = false; // HA MQTT Discovery
bool mqtt_ha_config_ww_ = false; // HA MQTT Discovery
static constexpr uint8_t EMS_TYPE_UBAParameterWW = 0x33;
static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D;

View File

@@ -49,8 +49,8 @@ bool Heatpump::export_values(JsonObject & json) {
void Heatpump::device_info_web(JsonArray & root) {
// fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
JsonObject json = doc.to<JsonObject>();
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>();
if (!export_values(json)) {
return; // empty
}
@@ -64,8 +64,8 @@ void Heatpump::show_values(uuid::console::Shell & shell) {
EMSdevice::show_values(shell); // always call this to show header
// fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
JsonObject json = doc.to<JsonObject>();
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>();
if (!export_values(json)) {
return; // empty
}
@@ -78,27 +78,26 @@ void Heatpump::show_values(uuid::console::Shell & shell) {
void Heatpump::publish_values(JsonObject & json, bool force) {
// handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force);
if (!mqtt_ha_config_ || force) {
register_mqtt_ha_config();
return;
}
}
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
JsonObject json_data = doc.to<JsonObject>();
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json_data = doc.to<JsonObject>();
if (export_values(json_data)) {
Mqtt::publish(F("heatpump_data"), doc.as<JsonObject>());
}
}
void Heatpump::register_mqtt_ha_config(bool force) {
if ((mqtt_ha_config_ && !force)) {
return;
}
void Heatpump::register_mqtt_ha_config() {
if (!Mqtt::connected()) {
return;
}
// Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["name"] = F_(EMSESP);
doc["uniq_id"] = F_(heatpump);
doc["ic"] = F_(iconheatpump);

View File

@@ -45,7 +45,7 @@ class Heatpump : public EMSdevice {
private:
static uuid::log::Logger logger_;
void register_mqtt_ha_config(bool force);
void register_mqtt_ha_config();
uint8_t airHumidity_ = EMS_VALUE_UINT_NOTSET;
uint8_t dewTemperature_ = EMS_VALUE_UINT_NOTSET;

View File

@@ -62,7 +62,7 @@ void Mixer::device_info_web(JsonArray & root) {
}
// fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>();
if (!export_values_format(Mqtt::Format::SINGLE, json)) {
return; // empty
@@ -101,7 +101,7 @@ void Mixer::show_values(uuid::console::Shell & shell) {
}
// fetch the values into a JSON document
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>();
if (!export_values_format(Mqtt::Format::SINGLE, json)) {
return; // empty
@@ -128,13 +128,16 @@ void Mixer::show_values(uuid::console::Shell & shell) {
void Mixer::publish_values(JsonObject & json, bool force) {
// handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force);
if (!mqtt_ha_config_ || force) {
register_mqtt_ha_config();
return;
}
}
if (Mqtt::mqtt_format() == Mqtt::Format::SINGLE) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
JsonObject json = doc.to<JsonObject>();
if (export_values_format(Mqtt::mqtt_format(), json)) {
JsonObject json_data = doc.to<JsonObject>();
if (export_values_format(Mqtt::mqtt_format(), json_data)) {
char topic[30];
if (type() == Type::HC) {
snprintf_P(topic, 30, PSTR("mixer_data_hc%d"), hc_);
@@ -150,18 +153,13 @@ void Mixer::publish_values(JsonObject & json, bool force) {
}
// publish config topic for HA MQTT Discovery
void Mixer::register_mqtt_ha_config(bool force) {
if ((mqtt_ha_config_ && !force)) {
return;
}
void Mixer::register_mqtt_ha_config() {
if (!Mqtt::connected()) {
return;
}
// if we don't have valid values for this HC don't add it ever again
if (!Helpers::hasValue(status_)) {
mqtt_ha_config_ = true;
if (!Helpers::hasValue(pumpStatus_)) {
return;
}
@@ -194,7 +192,7 @@ void Mixer::register_mqtt_ha_config(bool force) {
std::string topic(100, '\0');
if (this->type() == Type::HC) {
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/mixer_hc%d/config"), hc_);
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/ems-esp/mixer_hc%d/config"), hc_);
Mqtt::publish_retain(topic, doc.as<JsonObject>(), true); // publish the config payload with retain flag
char hc_name[10];
snprintf_P(hc_name, sizeof(hc_name), PSTR("hc%d"), hc_);
@@ -204,7 +202,7 @@ void Mixer::register_mqtt_ha_config(bool force) {
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(valveStatus), this->device_type(), "valveStatus", nullptr, nullptr);
} else {
// WWC
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/mixer_wwc%d/config"), hc_);
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/ems-esp/mixer_wwc%d/config"), hc_);
Mqtt::publish_retain(topic, doc.as<JsonObject>(), true); // publish the config payload with retain flag
char wwc_name[10];
snprintf_P(wwc_name, sizeof(wwc_name), PSTR("wwc%d"), hc_);

View File

@@ -46,7 +46,7 @@ class Mixer : public EMSdevice {
static uuid::log::Logger logger_;
bool export_values_format(uint8_t mqtt_format, JsonObject & doc);
void register_mqtt_ha_config(bool force);
void register_mqtt_ha_config();
void process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram);
void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram);

View File

@@ -49,6 +49,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_telegram_type(0x036A, F("SM100Status2"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100Status2(t); });
register_telegram_type(0x0380, F("SM100CollectorConfig"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100CollectorConfig(t); });
register_telegram_type(0x038E, F("SM100Energy"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Energy(t); });
register_telegram_type(0x0391, F("SM100Time"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Time(t); });
register_mqtt_cmd(F("SM100Tank1MaxTemp"), [&](const char * value, const int8_t id) { return set_SM100Tank1MaxTemp(value, id); });
}
@@ -83,6 +84,7 @@ void Solar::device_info_web(JsonArray & root) {
print_value_json(root, F("energyLastHour"), nullptr, F_(energyLastHour), F_(wh), json);
print_value_json(root, F("energyToday"), nullptr, F_(energyToday), F_(wh), json);
print_value_json(root, F("energyTotal"), nullptr, F_(energyTotal), F_(kwh), json);
print_value_json(root, F("pumpWorkMin"), nullptr, F_(pumpWorkMin), F_(min), json);
if (Helpers::hasValue(pumpWorkMin_)) {
JsonObject dataElement = root.createNestedObject();
@@ -118,6 +120,7 @@ void Solar::show_values(uuid::console::Shell & shell) {
print_value_json(shell, F("energyLastHour"), nullptr, F_(energyLastHour), F_(wh), json);
print_value_json(shell, F("energyToday"), nullptr, F_(energyToday), F_(wh), json);
print_value_json(shell, F("energyTotal"), nullptr, F_(energyTotal), F_(kwh), json);
print_value_json(shell, F("pumpWorkMin"), nullptr, F_(pumpWorkMin), F_(min), json);
if (Helpers::hasValue(pumpWorkMin_)) {
shell.printfln(F(" %s: %d days %d hours %d minutes"),
@@ -132,7 +135,10 @@ void Solar::show_values(uuid::console::Shell & shell) {
void Solar::publish_values(JsonObject & json, bool force) {
// handle HA first
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
register_mqtt_ha_config(force);
if ((!mqtt_ha_config_ || force)) {
register_mqtt_ha_config();
return;
}
}
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
@@ -147,17 +153,13 @@ void Solar::publish_values(JsonObject & json, bool force) {
}
// publish config topic for HA MQTT Discovery
void Solar::register_mqtt_ha_config(bool force) {
if ((mqtt_ha_config_ && !force)) {
return;
}
void Solar::register_mqtt_ha_config() {
if (!Mqtt::connected()) {
return;
}
// Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["name"] = F_(EMSESP);
doc["uniq_id"] = F_(solar);
doc["ic"] = F_(iconthermostat);
@@ -183,10 +185,10 @@ void Solar::register_mqtt_ha_config(bool force) {
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(heatExchangerTemp), this->device_type(), "heatExchangerTemp", F_(degrees), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(solarPumpModulation), this->device_type(), "solarPumpModulation", F_(percent), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(cylinderPumpModulation), this->device_type(), "cylinderPumpModulation", F_(percent), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(pumpWorkMin), this->device_type(), "pumpWorkMin", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(energyLastHour), this->device_type(), "energyLastHour", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(energyToday), this->device_type(), "energyToday", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(energyTotal), this->device_type(), "energyTotal", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(pumpWorkMin), this->device_type(), "pumpWorkMin", F_(min), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(energyLastHour), this->device_type(), "energyLastHour", F_(wh), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(energyToday), this->device_type(), "energyToday", F_(wh), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(energyTotal), this->device_type(), "energyTotal", F_(kwh), nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(solarPump), this->device_type(), "solarPump", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(valveStatus), this->device_type(), "valveStatus", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(tankHeated), this->device_type(), "tankHeated", nullptr, nullptr);
@@ -450,6 +452,13 @@ void Solar::process_SM100Energy(std::shared_ptr<const Telegram> telegram) {
changed_ |= telegram->read_value(energyTotal_, 8); // total / 10 in kWh
}
/*
* SM100Time - type 0x0391 EMS+ for pump working time
*/
void Solar::process_SM100Time(std::shared_ptr<const Telegram> telegram) {
changed_ |= telegram->read_value(pumpWorkMin_, 1, 3);
}
/*
* Junkers ISM1 Solar Module - type 0x0103 EMS+ for energy readings
* e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0

View File

@@ -44,7 +44,7 @@ class Solar : public EMSdevice {
private:
static uuid::log::Logger logger_;
void register_mqtt_ha_config(bool force);
void register_mqtt_ha_config();
int16_t collectorTemp_ = EMS_VALUE_SHORT_NOTSET; // TS1: Temperature sensor for collector array 1
int16_t tankBottomTemp_ = EMS_VALUE_SHORT_NOTSET; // TS2: Temperature sensor 1 cylinder, bottom (solar thermal system)
@@ -106,6 +106,7 @@ class Solar : public EMSdevice {
void process_SM100Status2(std::shared_ptr<const Telegram> telegram);
void process_SM100CollectorConfig(std::shared_ptr<const Telegram> telegram);
void process_SM100Energy(std::shared_ptr<const Telegram> telegram);
void process_SM100Time(std::shared_ptr<const Telegram> telegram);
void process_SM100wwTemperature(std::shared_ptr<const Telegram> telegram);
void process_SM100wwStatus(std::shared_ptr<const Telegram> telegram);

View File

@@ -114,10 +114,12 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8};
set_typeids = {0x02B9, 0x02BA, 0x02BB, 0x02BC};
summer_typeids = {0x02AF, 0x02B0, 0x02B1, 0x02B2};
curve_typeids = {0x029B, 0x029C, 0x029D, 0x029E};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Monitor(t); });
register_telegram_type(set_typeids[i], F("RC300Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Set(t); });
register_telegram_type(summer_typeids[i], F("RC300Summer"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Summer(t); });
register_telegram_type(curve_typeids[i], F("RC300Curves"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Curve(t); });
}
register_telegram_type(0x2F5, F("RC300WWmode"), true, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode(t); });
register_telegram_type(0x31B, F("RC300WWtemp"), true, [&](std::shared_ptr<const Telegram> t) { process_RC300WWtemp(t); });
@@ -171,12 +173,15 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
for (uint8_t i = 0; i < summer_typeids.size(); i++) {
EMSESP::send_read_request(summer_typeids[i], device_id);
}
} // namespace emsesp
for (uint8_t i = 0; i < curve_typeids.size(); i++) {
EMSESP::send_read_request(curve_typeids[i], device_id);
}
}
// prepare data for Web UI
void Thermostat::device_info_web(JsonArray & root) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc_main;
JsonObject json_main = doc_main.to<JsonObject>();
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc_main;
JsonObject json_main = doc_main.to<JsonObject>();
if (export_values_main(json_main)) {
print_value_json(root, F("time"), nullptr, F_(time), nullptr, json_main);
print_value_json(root, F("errorcode"), nullptr, F_(error), nullptr, json_main);
@@ -194,6 +199,7 @@ void Thermostat::device_info_web(JsonArray & root) {
print_value_json(root, F("wwmode"), nullptr, F_(wwmode), nullptr, json_main);
print_value_json(root, F("wwtemp"), nullptr, F_(wwtemp), nullptr, json_main);
print_value_json(root, F("wwtemplow"), nullptr, F_(wwtemplow), nullptr, json_main);
print_value_json(root, F("wwextra1"), nullptr, F_(wwextra1), nullptr, json_main);
print_value_json(root, F("wwcircmode"), nullptr, F_(wwcircmode), nullptr, json_main);
}
@@ -226,6 +232,8 @@ void Thermostat::device_info_web(JsonArray & root) {
print_value_json(root, F("designtemp"), FPSTR(prefix_str), F_(designtemp), F_(degrees), json);
print_value_json(root, F("roominfluence"), FPSTR(prefix_str), F_(roominfluence), F_(degrees), json);
print_value_json(root, F("flowtempoffset"), FPSTR(prefix_str), F_(flowtempoffset), F_(degrees), json);
print_value_json(root, F("minflowtemp"), FPSTR(prefix_str), F_(minflowtemp), F_(degrees), json);
print_value_json(root, F("maxflowtemp"), FPSTR(prefix_str), F_(maxflowtemp), F_(degrees), json);
print_value_json(root, F("summertemp"), FPSTR(prefix_str), F_(summertemp), F_(degrees), json);
print_value_json(root, F("summermode"), FPSTR(prefix_str), F_(summermode), F_(degrees), json);
print_value_json(root, F("mode"), FPSTR(prefix_str), F_(mode), nullptr, json);
@@ -278,6 +286,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
print_value_json(shell, F("wwmode"), nullptr, F_(wwmode), nullptr, json_main);
print_value_json(shell, F("wwtemp"), nullptr, F_(wwtemp), nullptr, json_main);
print_value_json(shell, F("wwtemplow"), nullptr, F_(wwtemplow), nullptr, json_main);
print_value_json(shell, F("wwextra1"), nullptr, F_(wwextra1), nullptr, json_main);
print_value_json(shell, F("wwcircmode"), nullptr, F_(wwcircmode), nullptr, json_main);
}
@@ -310,6 +319,8 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
print_value_json(shell, F("designtemp"), F_(2spaces), F_(designtemp), F_(degrees), json);
print_value_json(shell, F("roominfluence"), F_(2spaces), F_(roominfluence), F_(degrees), json);
print_value_json(shell, F("flowtempoffset"), F_(2spaces), F_(flowtempoffset), F_(degrees), json);
print_value_json(shell, F("minflowtemp"), F_(2spaces), F_(minflowtemp), F_(degrees), json);
print_value_json(shell, F("maxflowtemp"), F_(2spaces), F_(maxflowtemp), F_(degrees), json);
print_value_json(shell, F("summertemp"), F_(2spaces), F_(summertemp), F_(degrees), json);
print_value_json(shell, F("summermode"), F_(2spaces), F_(summermode), F_(degrees), json);
print_value_json(shell, F("mode"), F_(2spaces), F_(mode), nullptr, json);
@@ -325,10 +336,16 @@ void Thermostat::publish_values(JsonObject & json, bool force) {
if (EMSESP::actual_master_thermostat() != this->device_id()) {
return;
}
// see if we have already registered this with HA MQTT Discovery, if not send the config
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
if (!ha_config(force)) {
return;
}
}
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
JsonObject json_data = doc.to<JsonObject>();
bool has_data = false;
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
JsonObject json_data = doc.to<JsonObject>();
bool has_data = false;
// if MQTT is in single mode send out the main data to the thermostat_data topic
has_data |= export_values_main(json_data);
@@ -343,10 +360,6 @@ void Thermostat::publish_values(JsonObject & json, bool force) {
// if we're in HA or CUSTOM, send out the complete topic with all the data
if (Mqtt::mqtt_format() != Mqtt::Format::SINGLE && has_data) {
// see if we have already registered this with HA MQTT Discovery, if not send the config
if (Mqtt::mqtt_format() == Mqtt::Format::HA) {
ha_config(force);
}
Mqtt::publish(F("thermostat_data"), json_data);
}
}
@@ -473,6 +486,16 @@ bool Thermostat::export_values_main(JsonObject & rootThermostat) {
rootThermostat["wwtemplow"] = wwTempLow_;
}
// Warm water extra1
if (Helpers::hasValue(wwExtra1_)) {
rootThermostat["wwextra1"] = wwExtra1_;
}
// Warm water extra2
if (Helpers::hasValue(wwExtra2_)) {
rootThermostat["wwextra2"] = wwExtra2_;
}
// Warm Water circulation mode
if (Helpers::hasValue(wwCircMode_)) {
char s[7];
@@ -600,6 +623,16 @@ bool Thermostat::export_values_hc(uint8_t mqtt_format, JsonObject & rootThermost
dataThermostat["flowtempoffset"] = hc->flowtempoffset;
}
// Min Flow temperature offset
if (Helpers::hasValue(hc->minflowtemp)) {
dataThermostat["minflowtemp"] = hc->minflowtemp;
}
// Max Flow temperature offset
if (Helpers::hasValue(hc->maxflowtemp)) {
dataThermostat["maxflowtemp"] = hc->maxflowtemp;
}
// Summer temperature
if (Helpers::hasValue(hc->summertemp)) {
dataThermostat["summertemp"] = hc->summertemp;
@@ -654,23 +687,32 @@ bool Thermostat::export_values_hc(uint8_t mqtt_format, JsonObject & rootThermost
}
// set up HA MQTT Discovery
void Thermostat::ha_config(bool force) {
bool Thermostat::ha_config(bool force) {
if (!Mqtt::connected()) {
return;
return false;
}
if (force) {
for (const auto & hc : heating_circuits_) {
hc->ha_registered(false);
}
ha_registered(false);
}
if (force || !ha_registered()) {
if (!ha_registered()) {
register_mqtt_ha_config();
ha_registered(true);
return false;
}
// check to see which heating circuits need publishing
for (const auto & hc : heating_circuits_) {
if (force || (hc->is_active() && !hc->ha_registered())) {
if (hc->is_active() && !hc->ha_registered()) {
register_mqtt_ha_config(hc->hc_num());
hc->ha_registered(true);
return false;
}
}
return true;
}
// returns the heating circuit object based on the hc number
@@ -679,13 +721,15 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(const ui
// if hc_num is 0 then return the first existing hc in the list
if (hc_num == AUTO_HEATING_CIRCUIT) {
for (const auto & heating_circuit : heating_circuits_) {
return heating_circuit;
if (heating_circuit->is_active()) {
return heating_circuit;
}
}
}
// otherwise find a match
for (const auto & heating_circuit : heating_circuits_) {
if (heating_circuit->hc_num() == hc_num) {
if ((heating_circuit->hc_num() == hc_num) && heating_circuit->is_active()) {
return heating_circuit;
}
}
@@ -773,10 +817,10 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
return heating_circuits_.back(); // even after sorting, this should still point back to the newly created HC
}
// publish config topic for HA MQTT Discovery
// publish config topic for HA MQTT Discovery for main thermostat values
// homeassistant/climate/ems-esp/thermostat/config
void Thermostat::register_mqtt_ha_config() {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["uniq_id"] = F("thermostat");
doc["ic"] = F("mdi:home-thermometer-outline");
@@ -808,6 +852,7 @@ void Thermostat::register_mqtt_ha_config() {
if (model == EMS_DEVICE_FLAG_RC300 || model == EMS_DEVICE_FLAG_RC100) {
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(dampedtemp), this->device_type(), "dampedtemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(building), this->device_type(), "building", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(minexttemp), this->device_type(), "minexttemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(floordry), this->device_type(), "floordry", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(floordrytemp), this->device_type(), "floordrytemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(wwmode), this->device_type(), "wwmode", nullptr, nullptr);
@@ -826,18 +871,18 @@ void Thermostat::register_mqtt_ha_config() {
}
}
// publish config topic for HA MQTT Discovery
// publish config topic for HA MQTT Discovery for each of the heating circuit
// e.g. homeassistant/climate/ems-esp/thermostat_hc1/config
void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
char str1[40];
char str1[20];
snprintf_P(str1, sizeof(str1), PSTR("Thermostat hc%d"), hc_num);
char str2[40];
char str2[20];
snprintf_P(str2, sizeof(str2), PSTR("thermostat_hc%d"), hc_num);
char str3[40];
char str3[25];
snprintf_P(str3, sizeof(str3), PSTR("~/%s"), str2);
doc["mode_cmd_t"] = str3;
doc["temp_cmd_t"] = str3;
@@ -909,7 +954,7 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
// for each of the heating circuits
std::string topic2(100, '\0');
snprintf_P(&topic2[0], topic2.capacity() + 1, PSTR("thermostat_hc%d"), hc_num);
register_mqtt_topic(topic2, [=](const char * m) { return thermostat_ha_cmd(m, hc_num); });
register_mqtt_topic(topic2, [&](const char * m) { return thermostat_ha_cmd(m, hc_num); });
char hc_name[10]; // hc{1-4}
strlcpy(hc_name, "hc", 10);
@@ -918,6 +963,9 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(mode), this->device_type(), "mode", nullptr, nullptr);
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(seltemp), this->device_type(), "seltemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(currtemp), this->device_type(), "currtemp", F_(degrees), F_(icontemperature));
uint8_t model = this->model();
switch (model) {
case EMS_DEVICE_FLAG_RC100:
@@ -927,6 +975,12 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(manualtemp), this->device_type(), "manualtemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(comforttemp), this->device_type(), "comforttemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(summertemp), this->device_type(), "summertemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(designtemp), this->device_type(), "designtemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(offsettemp), this->device_type(), "offsettemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(minflowtemp), this->device_type(), "minflowtemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(maxflowtemp), this->device_type(), "maxflowtemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(roominfluence), this->device_type(), "roominfluence", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(nofrosttemp), this->device_type(), "nofrosttemp", F_(degrees), F_(icontemperature));
break;
case EMS_DEVICE_FLAG_RC20_2:
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(daytemp), this->device_type(), "daytemp", F_(degrees), F_(icontemperature));
@@ -944,6 +998,8 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(summertemp), this->device_type(), "summertemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(nofrosttemp), this->device_type(), "nofrosttemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(roominfluence), this->device_type(), "roominfluence", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(minflowtemp), this->device_type(), "minflowtemp", F_(degrees), F_(icontemperature));
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(maxflowtemp), this->device_type(), "maxflowtemp", F_(degrees), F_(icontemperature));
break;
case EMS_DEVICE_FLAG_JUNKERS:
Mqtt::register_mqtt_ha_sensor(hc_name, nullptr, F_(modetype), this->device_type(), "modetype", nullptr, nullptr);
@@ -1094,6 +1150,15 @@ std::string Thermostat::mode_tostring(uint8_t mode) {
case HeatingCircuit::Mode::DESIGN:
return read_flash_string(F("design"));
break;
case HeatingCircuit::Mode::MINFLOW:
return read_flash_string(F("minflow"));
break;
case HeatingCircuit::Mode::MAXFLOW:
return read_flash_string(F("maxflow"));
break;
case HeatingCircuit::Mode::ROOMINFLUENCE:
return read_flash_string(F("roominfluence"));
break;
default:
case HeatingCircuit::Mode::UNKNOWN:
return read_flash_string(F("unknown"));
@@ -1268,8 +1333,28 @@ void Thermostat::process_RC300Set(std::shared_ptr<const Telegram> telegram) {
// types 0x2AF ff
void Thermostat::process_RC300Summer(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
changed_ |= telegram->read_value(hc->roominfluence, 0);
changed_ |= telegram->read_value(hc->offsettemp, 2);
changed_ |= telegram->read_value(hc->summertemp, 6);
changed_ |= telegram->read_value(hc->summer_setmode, 7);
if (hc->heatingtype < 3) {
changed_ |= telegram->read_value(hc->designtemp, 4);
} else {
changed_ |= telegram->read_value(hc->designtemp, 5);
}
changed_ |= telegram->read_value(hc->minflowtemp, 8);
}
// types 0x29B ff
void Thermostat::process_RC300Curve(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
changed_ |= telegram->read_value(hc->heatingtype, 1); // 1=radiator, 2=convector, 3=floor
changed_ |= telegram->read_value(hc->nofrosttemp, 6);
if (hc->heatingtype < 3) {
changed_ |= telegram->read_value(hc->maxflowtemp, 8);
} else {
changed_ |= telegram->read_value(hc->maxflowtemp, 7);
}
}
// types 0x31B (and 0x31C?)
@@ -1306,6 +1391,7 @@ void Thermostat::process_RC300OutdoorTemp(std::shared_ptr<const Telegram> telegr
// 0x240 RC300 parameter
void Thermostat::process_RC300Settings(std::shared_ptr<const Telegram> telegram) {
changed_ |= telegram->read_value(ibaBuildingType_, 9); // 1=light, 2=medium, 3=heavy
changed_ |= telegram->read_value(ibaMinExtTemperature_, 10);
}
// 0x267 RC300 floordrying
@@ -1370,10 +1456,13 @@ void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
changed_ |= telegram->read_value(hc->summertemp, 22); // is * 1
changed_ |= telegram->read_value(hc->nofrosttemp, 23); // is * 1
changed_ |= telegram->read_value(hc->flowtempoffset, 24); // is * 1, only in mixed circuits
changed_ |= telegram->read_value(hc->minflowtemp, 16);
if (hc->heatingtype == 3) {
changed_ |= telegram->read_value(hc->designtemp, 36); // is * 1
changed_ |= telegram->read_value(hc->designtemp, 36); // is * 1
changed_ |= telegram->read_value(hc->maxflowtemp, 35); // is * 1
} else {
changed_ |= telegram->read_value(hc->designtemp, 17); // is * 1
changed_ |= telegram->read_value(hc->designtemp, 17); // is * 1
changed_ |= telegram->read_value(hc->maxflowtemp, 15); // is * 1
}
}
@@ -1564,24 +1653,6 @@ bool Thermostat::set_control(const char * value, const int8_t id) {
return true;
}
// Set roominfluence
bool Thermostat::set_roominfluence(const char * value, const int8_t id) {
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) {
LOG_WARNING(F("Set roominfluence: Heating Circuit %d not found or activated"), hc_num);
return false;
}
int t = 0;
if (!Helpers::value2number(value, t)) {
LOG_WARNING(F("Set roominfluence: Invalid value"));
return false;
}
LOG_INFO(F("Setting roominfluence to %d"), t);
write_command(set_typeids[hc->hc_num() - 1], 4, t, set_typeids[hc->hc_num() - 1]);
return true;
}
// sets the thermostat ww working mode, where mode is a string, ems and ems+
bool Thermostat::set_wwmode(const char * value, const int8_t id) {
uint8_t set = 0xFF;
@@ -1627,6 +1698,19 @@ bool Thermostat::set_wwtemplow(const char * value, const int8_t id) {
return true;
}
// Set ww onetime RC300, ems+
bool Thermostat::set_wwonetime(const char * value, const int8_t id) {
bool b = false;
if (!Helpers::value2bool(value, b)) {
LOG_WARNING(F("Set warm water onetime: Invalid value"));
return false;
}
char s[7];
LOG_INFO(F("Setting warm water onetime to %s"), Helpers::render_boolean(s, b));
write_command(0x02F5, 11, b ? 0xFF : 0x00, 0x031D);
return true;
}
// sets the thermostat ww circulation working mode, where mode is a string
bool Thermostat::set_wwcircmode(const char * value, const int8_t id) {
@@ -1957,6 +2041,15 @@ bool Thermostat::set_temperature(const float temperature, const std::string & mo
if (mode_tostring(HeatingCircuit::Mode::DESIGN) == mode) {
return set_temperature(temperature, HeatingCircuit::Mode::DESIGN, hc_num);
}
if (mode_tostring(HeatingCircuit::Mode::MINFLOW) == mode) {
return set_temperature(temperature, HeatingCircuit::Mode::MINFLOW, hc_num);
}
if (mode_tostring(HeatingCircuit::Mode::MAXFLOW) == mode) {
return set_temperature(temperature, HeatingCircuit::Mode::MAXFLOW, hc_num);
}
if (mode_tostring(HeatingCircuit::Mode::ROOMINFLUENCE) == mode) {
return set_temperature(temperature, HeatingCircuit::Mode::ROOMINFLUENCE, hc_num);
}
LOG_WARNING(F("Set temperature: Invalid mode"));
return false;
@@ -2005,6 +2098,49 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
case HeatingCircuit::Mode::ECO:
offset = 0x04; // eco offset
break;
case HeatingCircuit::Mode::OFFSET:
offset = 2;
set_typeid = summer_typeids[hc->hc_num() - 1];
validate_typeid = set_typeid;
break;
case HeatingCircuit::Mode::DESIGN:
set_typeid = summer_typeids[hc->hc_num() - 1];
validate_typeid = set_typeid;
if (hc->heatingtype == 3) {
offset = 5;
} else {
offset = 4;
}
factor = 1;
break;
case HeatingCircuit::Mode::MINFLOW:
set_typeid = summer_typeids[hc->hc_num() - 1];
validate_typeid = set_typeid;
offset = 8;
factor = 1;
break;
case HeatingCircuit::Mode::MAXFLOW:
set_typeid = curve_typeids[hc->hc_num() - 1];
validate_typeid = set_typeid;
if (hc->heatingtype == 3) {
offset = 7;
} else {
offset = 8;
}
factor = 1;
break;
case HeatingCircuit::Mode::NOFROST:
set_typeid = curve_typeids[hc->hc_num() - 1];
validate_typeid = set_typeid;
offset = 6;
factor = 1;
break;
case HeatingCircuit::Mode::ROOMINFLUENCE:
set_typeid = summer_typeids[hc->hc_num() - 1];
validate_typeid = set_typeid;
offset = 0;
factor = 1;
break;
default:
case HeatingCircuit::Mode::AUTO:
uint8_t mode_ = hc->get_mode(this->flags());
@@ -2067,6 +2203,22 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
offset = EMS_OFFSET_RC35Set_temp_nofrost;
factor = 1;
break;
case HeatingCircuit::Mode::ROOMINFLUENCE:
offset = 4;
factor = 1;
break;
case HeatingCircuit::Mode::MINFLOW:
offset = 16;
factor = 1;
break;
case HeatingCircuit::Mode::MAXFLOW:
if (hc->heatingtype == 3) {
offset = 35;
} else {
offset = 15;
}
factor = 1;
break;
default:
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
validate_typeid = monitor_typeids[hc->hc_num() - 1]; //get setpoint roomtemp back
@@ -2226,6 +2378,18 @@ bool Thermostat::set_flowtempoffset(const char * value, const int8_t id) {
return set_temperature_value(value, id, HeatingCircuit::Mode::FLOWOFFSET);
}
bool Thermostat::set_maxflowtemp(const char * value, const int8_t id) {
return set_temperature_value(value, id, HeatingCircuit::Mode::MAXFLOW);
}
bool Thermostat::set_minflowtemp(const char * value, const int8_t id) {
return set_temperature_value(value, id, HeatingCircuit::Mode::MINFLOW);
}
bool Thermostat::set_roominfluence(const char * value, const int8_t id) {
return set_temperature_value(value, id, HeatingCircuit::Mode::ROOMINFLUENCE);
}
// API commands for MQTT and Console
void Thermostat::add_commands() {
// if this thermostat doesn't support write, don't add the commands
@@ -2250,7 +2414,15 @@ void Thermostat::add_commands() {
register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { return set_wwmode(value, id); });
register_mqtt_cmd(F("wwtemp"), [&](const char * value, const int8_t id) { return set_wwtemp(value, id); });
register_mqtt_cmd(F("wwtemplow"), [&](const char * value, const int8_t id) { return set_wwtemplow(value, id); });
register_mqtt_cmd(F("wwonetime"), [&](const char * value, const int8_t id) { return set_wwonetime(value, id); });
register_mqtt_cmd(F("building"), [&](const char * value, const int8_t id) { return set_building(value, id); });
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); });
register_mqtt_cmd(F("designtemp"), [&](const char * value, const int8_t id) { return set_designtemp(value, id); });
register_mqtt_cmd(F("offsettemp"), [&](const char * value, const int8_t id) { return set_offsettemp(value, id); });
register_mqtt_cmd(F("minflowtemp"), [&](const char * value, const int8_t id) { return set_minflowtemp(value, id); });
register_mqtt_cmd(F("maxflowtemp"), [&](const char * value, const int8_t id) { return set_maxflowtemp(value, id); });
register_mqtt_cmd(F("minexttemp"), [&](const char * value, const int8_t id) { return set_minexttemp(value, id); });
register_mqtt_cmd(F("roominfluence"), [&](const char * value, const int8_t id) { return set_roominfluence(value, id); });
break;
case EMS_DEVICE_FLAG_RC20_2:
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); });
@@ -2280,6 +2452,8 @@ void Thermostat::add_commands() {
register_mqtt_cmd(F("wwcircmode"), [&](const char * value, const int8_t id) { return set_wwcircmode(value, id); });
register_mqtt_cmd(F("roominfluence"), [&](const char * value, const int8_t id) { return set_roominfluence(value, id); });
register_mqtt_cmd(F("flowtempoffset"), [&](const char * value, const int8_t id) { return set_flowtempoffset(value, id); });
register_mqtt_cmd(F("minflowtemp"), [&](const char * value, const int8_t id) { return set_minflowtemp(value, id); });
register_mqtt_cmd(F("maxflowtemp"), [&](const char * value, const int8_t id) { return set_maxflowtemp(value, id); });
break;
case EMS_DEVICE_FLAG_JUNKERS:
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); });
@@ -2291,5 +2465,4 @@ void Thermostat::add_commands() {
}
}
} // namespace emsesp

View File

@@ -58,13 +58,15 @@ class Thermostat : public EMSdevice {
uint8_t heatingtype = EMS_VALUE_UINT_NOTSET; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
uint8_t targetflowtemp = EMS_VALUE_UINT_NOTSET;
uint8_t summertemp = EMS_VALUE_UINT_NOTSET;
uint8_t nofrosttemp = EMS_VALUE_UINT_NOTSET;
int8_t nofrosttemp = EMS_VALUE_INT_NOTSET; // signed -20°C to +10°C
uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heating curve design temp at MinExtTemp
int8_t offsettemp = EMS_VALUE_INT_NOTSET; // heating curve offest temp at roomtemp signed!
uint8_t manualtemp = EMS_VALUE_UINT_NOTSET;
uint8_t summer_setmode = EMS_VALUE_UINT_NOTSET;
uint8_t roominfluence = EMS_VALUE_UINT_NOTSET;
uint8_t flowtempoffset = EMS_VALUE_UINT_NOTSET;
uint8_t minflowtemp = EMS_VALUE_UINT_NOTSET;
uint8_t maxflowtemp = EMS_VALUE_UINT_NOTSET;
uint8_t hc_num() const {
return hc_num_;
@@ -86,7 +88,7 @@ class Thermostat : public EMSdevice {
uint8_t get_mode(uint8_t flags) const;
uint8_t get_mode_type(uint8_t flags) const;
enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN, SUMMER, FLOWOFFSET };
enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN, SUMMER, FLOWOFFSET, MINFLOW, MAXFLOW, ROOMINFLUENCE };
// for sorting based on hc number
friend inline bool operator<(const std::shared_ptr<HeatingCircuit> & lhs, const std::shared_ptr<HeatingCircuit> & rhs) {
@@ -131,6 +133,7 @@ class Thermostat : public EMSdevice {
std::vector<uint16_t> set_typeids;
std::vector<uint16_t> timer_typeids;
std::vector<uint16_t> summer_typeids;
std::vector<uint16_t> curve_typeids;
std::string datetime_; // date and time stamp
std::string errorCode_; // code from 0xA2 as string i.e. "A22(816)"
@@ -245,7 +248,7 @@ class Thermostat : public EMSdevice {
void register_mqtt_ha_config();
void register_mqtt_ha_config(uint8_t hc_num);
void ha_config(bool force = false);
bool ha_config(bool force = false);
bool thermostat_ha_cmd(const char * message, uint8_t hc_num);
void process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram);
@@ -273,6 +276,7 @@ class Thermostat : public EMSdevice {
void process_RC300OutdoorTemp(std::shared_ptr<const Telegram> telegram);
void process_RC300Settings(std::shared_ptr<const Telegram> telegram);
void process_RC300Floordry(std::shared_ptr<const Telegram> telegram);
void process_RC300Curve(std::shared_ptr<const Telegram> telegram);
void process_JunkersMonitor(std::shared_ptr<const Telegram> telegram);
void process_JunkersSet(std::shared_ptr<const Telegram> telegram);
void process_JunkersSet2(std::shared_ptr<const Telegram> telegram);
@@ -308,11 +312,14 @@ class Thermostat : public EMSdevice {
bool set_remotetemp(const char * value, const int8_t id);
bool set_roominfluence(const char * value, const int8_t id);
bool set_flowtempoffset(const char * value, const int8_t id);
bool set_minflowtemp(const char * value, const int8_t id);
bool set_maxflowtemp(const char * value, const int8_t id);
// set functions - these don't use the id/hc, the parameters are ignored
bool set_wwmode(const char * value, const int8_t id);
bool set_wwtemp(const char * value, const int8_t id);
bool set_wwtemplow(const char * value, const int8_t id);
bool set_wwonetime(const char * value, const int8_t id);
bool set_wwcircmode(const char * value, const int8_t id);
bool set_datetime(const char * value, const int8_t id);
bool set_minexttemp(const char * value, const int8_t id);