mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-01-28 01:29:07 +03:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user