From 5ab5d747bc4a80ab11cec10a77fc168f41053064 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 3 Oct 2020 14:19:45 +0200 Subject: [PATCH] render and parse multible text parameters, add thermostat wwmode, some watning messages --- src/devices/boiler.cpp | 51 ++++-- src/devices/thermostat.cpp | 331 ++++++++++++++++++------------------- src/devices/thermostat.h | 10 +- src/helpers.cpp | 35 +++- src/helpers.h | 4 + 5 files changed, 244 insertions(+), 187 deletions(-) diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 08044775f..44d0acee8 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -800,6 +800,7 @@ void Boiler::process_UBAMaintenanceData(std::shared_ptr telegram bool Boiler::set_warmwater_temp(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler warm water temperature: Invalid value")); return false; } @@ -807,8 +808,8 @@ bool Boiler::set_warmwater_temp(const char * value, const int8_t id) { if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) { write_command(EMS_TYPE_UBAParameterWWPlus, 6, v, EMS_TYPE_UBAParameterWWPlus); } else { - write_command(EMS_TYPE_UBAParameterWW, 2, v, EMS_TYPE_UBAParameterWW); - write_command(EMS_TYPE_UBAFlags, 3, v, EMS_TYPE_UBAParameterWW); // for i9000, see #397 + write_command(EMS_TYPE_UBAParameterWW, 2, v, EMS_TYPE_UBAParameterWW); // read seltemp back + write_command(EMS_TYPE_UBAFlags, 3, v, 0x34); // for i9000, see #397, read setTemp } return true; @@ -818,6 +819,7 @@ bool Boiler::set_warmwater_temp(const char * value, const int8_t id) { bool Boiler::set_flow_temp(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler flow temperature: Invalid value")); return false; } @@ -831,6 +833,7 @@ bool Boiler::set_flow_temp(const char * value, const int8_t id) { bool Boiler::set_heating_activated(const char * value, const int8_t id) { bool v = false; if (!Helpers::value2bool(value, v)) { + LOG_WARNING(F("Set boiler heating: Invalid value")); return false; } @@ -848,6 +851,7 @@ bool Boiler::set_heating_activated(const char * value, const int8_t id) { bool Boiler::set_heating_temp(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler heating temperature: Invalid value")); return false; } @@ -865,6 +869,7 @@ bool Boiler::set_heating_temp(const char * value, const int8_t id) { bool Boiler::set_min_power(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler min power: Invalid value")); return false; } @@ -882,6 +887,7 @@ bool Boiler::set_min_power(const char * value, const int8_t id) { bool Boiler::set_max_power(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler max power: Invalid value")); return false; } @@ -899,6 +905,7 @@ bool Boiler::set_max_power(const char * value, const int8_t id) { bool Boiler::set_hyst_on(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler hysteresis: Invalid value")); return false; } @@ -916,6 +923,7 @@ bool Boiler::set_hyst_on(const char * value, const int8_t id) { bool Boiler::set_hyst_off(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler hysteresis: Invalid value")); return false; } @@ -933,6 +941,7 @@ bool Boiler::set_hyst_off(const char * value, const int8_t id) { bool Boiler::set_burn_period(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set burner min. period: Invalid value")); return false; } @@ -950,21 +959,25 @@ bool Boiler::set_burn_period(const char * value, const int8_t id) { bool Boiler::set_pump_delay(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set boiler pump delay: Invalid value")); return false; } if (get_toggle_fetch(EMS_TYPE_UBAParameters)) { LOG_INFO(F("Setting boiler pump delay to %d min"), v); write_command(EMS_TYPE_UBAParameters, 8, v, EMS_TYPE_UBAParameters); + return true; } - return true; + return false; } // note some boilers do not have this setting, than it's done by thermostat // on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3) 1=hot, 2=eco, 3=intelligent bool Boiler::set_warmwater_mode(const char * value, const int8_t id) { - if (value == nullptr) { + uint8_t set; + if (!Helpers::value2enum(value, set, {"hot","eco","intelligent"})) { + LOG_WARNING(F("Set boiler warm water mode: Invalid value")); return false; } @@ -972,14 +985,12 @@ bool Boiler::set_warmwater_mode(const char * value, const int8_t id) { return false; } - uint8_t set; - if (strcmp(value, "hot") == 0) { + if (set == 0) { LOG_INFO(F("Setting boiler warm water to Hot")); - set = 0x00; - } else if (strcmp(value, "eco") == 0) { + } else if (set == 1) { LOG_INFO(F("Setting boiler warm water to Eco")); set = 0xD8; - } else if (strcmp(value, "intelligent") == 0) { + } else if (set == 2) { LOG_INFO(F("Setting boiler warm water to Intelligent")); set = 0xEC; } else { @@ -994,10 +1005,11 @@ bool Boiler::set_warmwater_mode(const char * value, const int8_t id) { bool Boiler::set_warmwater_activated(const char * value, const int8_t id) { bool v = false; if (!Helpers::value2bool(value, v)) { + LOG_WARNING(F("Set boiler warm water active: Invalid value")); return false; } - LOG_INFO(F("Setting boiler warm water %s"), v ? "on" : "off"); + LOG_INFO(F("Setting boiler warm water active %s"), v ? "on" : "off"); // https://github.com/proddy/EMS-ESP/issues/268 uint8_t n; @@ -1021,10 +1033,11 @@ bool Boiler::set_warmwater_activated(const char * value, const int8_t id) { bool Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) { bool v = false; if (!Helpers::value2bool(value, v)) { + LOG_WARNING(F("Set warm tap water: Invalid value")); return false; } - LOG_INFO(F("Setting tap warm tap water %s"), v ? "on" : "off"); + LOG_INFO(F("Setting warm tap water %s"), v ? "on" : "off"); uint8_t message_data[EMS_MAX_TELEGRAM_MESSAGE_LENGTH]; for (uint8_t i = 0; i < sizeof(message_data); i++) { message_data[i] = 0x00; @@ -1055,10 +1068,11 @@ bool Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) { bool Boiler::set_warmwater_onetime(const char * value, const int8_t id) { bool v = false; if (!Helpers::value2bool(value, v)) { + LOG_WARNING(F("Set warm water OneTime loading: Invalid value")); return false; } - LOG_INFO(F("Setting boiler warm water OneTime loading %s"), v ? "on" : "off"); + LOG_INFO(F("Setting warm water OneTime loading %s"), v ? "on" : "off"); if (get_toggle_fetch(EMS_TYPE_UBAParameterWWPlus)) { write_command(EMS_TYPE_UBAFlags, 0, (v ? 0x22 : 0x02), 0xE9); // not sure if this is in flags } else { @@ -1073,10 +1087,11 @@ bool Boiler::set_warmwater_onetime(const char * value, const int8_t id) { bool Boiler::set_warmwater_circulation(const char * value, const int8_t id) { bool v = false; if (!Helpers::value2bool(value, v)) { + LOG_WARNING(F("Set warm water circulation: Invalid value")); return false; } - LOG_INFO(F("Setting boiler warm water circulation %s"), v ? "on" : "off"); + LOG_INFO(F("Setting warm water circulation %s"), v ? "on" : "off"); if (get_toggle_fetch(EMS_TYPE_UBAParameterWWPlus)) { write_command(EMS_TYPE_UBAFlags, 1, (v ? 0x22 : 0x02), 0xE9); // not sure if this is in flags } else { @@ -1090,10 +1105,11 @@ bool Boiler::set_warmwater_circulation(const char * value, const int8_t id) { bool Boiler::set_warmwater_circulation_pump(const char * value, const int8_t id) { bool v = false; if (!Helpers::value2bool(value, v)) { + LOG_WARNING(F("Set warm water circulation pump: Invalid value")); return false; } - LOG_INFO(F("Setting boiler warm water circulation %s"), v ? "on" : "off"); + LOG_INFO(F("Setting warm water circulation pump %s"), v ? "on" : "off"); if (get_toggle_fetch(EMS_TYPE_UBAParameterWWPlus)) { write_command(EMS_TYPE_UBAParameterWWPlus, 10, v ? 0x01 : 0x00, EMS_TYPE_UBAParameterWWPlus); @@ -1109,14 +1125,17 @@ bool Boiler::set_warmwater_circulation_pump(const char * value, const int8_t id) bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id) { int v = 0; if (!Helpers::value2number(value, v)) { + LOG_WARNING(F("Set warm water circulation mode: Invalid value")); return false; } if (get_toggle_fetch(EMS_TYPE_UBAParameterWW)) { if (v < 7) { - LOG_INFO(F("Setting circulation mode %dx3min"), v); + LOG_INFO(F("Setting warm water circulation mode %dx3min"), v); + } else if (v == 7) { + LOG_INFO(F("Setting warm water circulation mode continous")); } else { - LOG_INFO(F("Setting circulation mode continous")); + return false; } write_command(EMS_TYPE_UBAParameterWW, 6, v, EMS_TYPE_UBAParameterWW); } diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index e53fd4f81..e04a99834 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -118,8 +118,10 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i register_telegram_type(set_typeids[i], F("RC300Set"), false, [&](std::shared_ptr t) { process_RC300Set(t); }); register_telegram_type(summer_typeids[i], F("RC300Summer"), false, [&](std::shared_ptr t) { process_RC300Summer(t); }); } - register_telegram_type(0x31D, F("RC300WWmode"), false, [&](std::shared_ptr t) { process_RC300WWmode(t); }); - register_telegram_type(0x31E, F("RC300WWmode"), false, [&](std::shared_ptr t) { process_RC300WWmode(t); }); + register_telegram_type(0x2F5, F("RC300WWmode"), false, [&](std::shared_ptr t) { process_RC300WWmode(t); }); + register_telegram_type(0x31B, F("RC300WWtemp"), false, [&](std::shared_ptr t) { process_RC300WWtemp(t); }); + register_telegram_type(0x31D, F("RC300WWmode2"), false, [&](std::shared_ptr t) { process_RC300WWmode2(t); }); + register_telegram_type(0x31E, F("RC300WWmode2"), false, [&](std::shared_ptr t) { process_RC300WWmode2(t); }); // JUNKERS/HT3 } else if (model == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { @@ -263,12 +265,15 @@ void Thermostat::publish_values() { bool Thermostat::export_values(uint8_t mqtt_format, JsonObject & rootThermostat) { uint8_t flags = this->model(); JsonObject dataThermostat; + bool has_data = false; + if (datetime_.size()) { + rootThermostat["time"] = datetime_.c_str(); + has_data = true; + } // add external temp and other stuff specific to the RC30 and RC35 if (flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) { - if (datetime_.size()) { - rootThermostat["time"] = datetime_.c_str(); - } + has_data = true; if (Helpers::hasValue(dampedoutdoortemp_)) { rootThermostat["dampedtemp"] = dampedoutdoortemp_; } @@ -285,41 +290,44 @@ bool Thermostat::export_values(uint8_t mqtt_format, JsonObject & rootThermostat) rootThermostat["minexttemp"] = (float)ibaMinExtTemperature_; // min ext temp for heating curve, in deg. } if (Helpers::hasValue(ibaBuildingType_)) { - if (ibaBuildingType_ == 0) { - rootThermostat["building"] = "light"; - } else if (ibaBuildingType_ == 1) { - rootThermostat["building"] = "medium"; - } else if (ibaBuildingType_ == 2) { - rootThermostat["building"] = "heavy"; - } + char s[10]; + rootThermostat["building"] = Helpers::render_enum(s, {"light","medium","heavy"}, ibaBuildingType_); } - if (Helpers::hasValue(wwMode_)) { - if (wwMode_ == 2) { - rootThermostat["wwmode"] = "auto"; - } else { - char s[7]; - rootThermostat["wwmode"] = Helpers::render_boolean(s, (wwMode_ == 1)); - } + } + if (Helpers::hasValue(wwMode_)) { + char s[10]; + if (flags == EMS_DEVICE_FLAG_RC300 || flags == EMS_DEVICE_FLAG_RC100) { + rootThermostat["wwmode"] = Helpers::render_enum(s, {"off","low","high","auto","own_prog"}, wwMode_); + } else { + rootThermostat["wwmode"] = Helpers::render_enum(s, {"off","on","auto"}, wwMode_); } + has_data = true; + } - if (Helpers::hasValue(wwCircMode_)) { - if (wwCircMode_ == 2) { - rootThermostat["wwcircmode"] = "auto"; - } else { - char s[7]; - rootThermostat["wwcircmode"] = Helpers::render_boolean(s, (wwCircMode_ == 1)); - } - } + if (Helpers::hasValue(wwCircMode_)) { + char s[7]; + rootThermostat["wwcircmode"] = Helpers::render_enum(s, {"off","on","auto"}, wwCircMode_); + has_data = true; + } - // send this specific data using the thermostat_data topic - if (mqtt_format != Mqtt::Format::NESTED) { - Mqtt::publish(F("thermostat_data"), rootThermostat); - rootThermostat.clear(); // clear object - } + if (Helpers::hasValue(wwTemp_)) { + rootThermostat["wwtemp"] = wwTemp_; + has_data = true; + } + + if (Helpers::hasValue(wwTempLow_)) { + rootThermostat["wwtemplow"] = wwTempLow_; + has_data = true; + } + + // send this specific data using the thermostat_data topic + if (mqtt_format != Mqtt::Format::NESTED) { + Mqtt::publish(F("thermostat_data"), rootThermostat); + rootThermostat.clear(); // clear object + has_data = false; } // go through all the heating circuits - bool has_data = false; for (const auto & hc : heating_circuits_) { if (hc->is_active()) { has_data = true; @@ -408,12 +416,8 @@ bool Thermostat::export_values(uint8_t mqtt_format, JsonObject & rootThermostat) } if (Helpers::hasValue(hc->summer_setmode)) { - if (hc->summer_setmode == 1) { - dataThermostat["summermode"] = "auto"; - } else { - char s[7]; - dataThermostat["summermode"] = Helpers::render_boolean(s, (hc->summer_setmode == 0)); - } + char s[7]; + dataThermostat["summermode"] = Helpers::render_enum(s, {"off","auto","on"}, hc->summer_setmode); } // mode - always force showing this when in HA so not to break HA's climate component @@ -794,19 +798,25 @@ void Thermostat::show_values(uuid::console::Shell & shell) { } if (Helpers::hasValue(wwMode_)) { - if (wwMode_ == 2) { - print_value(shell, 2, F("Warm Water mode"), F("auto")); + char s[11]; + if ((flags == EMS_DEVICE_FLAG_RC300) || (flags == EMS_DEVICE_FLAG_RC100)) { + print_value(shell, 2, F("Warm Water mode"), Helpers::render_enum(s, {"off","low","high","auto","own prog."}, wwMode_)); } else { - print_value(shell, 2, F("Warm Water mode"), wwMode_, nullptr, EMS_VALUE_BOOL); + print_value(shell, 2, F("Warm Water mode"), Helpers::render_enum(s, {"off","on","auto"}, wwMode_)); } } + if (Helpers::hasValue(wwTemp_)) { + print_value(shell, 2, F("Warm Water temperatur"), wwTemp_, F_(degrees)); + } + + if (Helpers::hasValue(wwTempLow_)) { + print_value(shell, 2, F("Warm Water lower temperatur"), wwTempLow_, F_(degrees)); + } + if (Helpers::hasValue(wwCircMode_)) { - if (wwCircMode_ == 2) { - print_value(shell, 2, F("Warm Water circulation mode"), F("auto")); - } else { - print_value(shell, 2, F("Warm Water circulation mode"), wwCircMode_, nullptr, EMS_VALUE_BOOL); - } + char s[7]; + print_value(shell, 2, F("Warm Water circulation mode"), Helpers::render_enum(s, {"off","on","auto"}, wwCircMode_)); } if (flags == EMS_DEVICE_FLAG_RC35) { @@ -840,15 +850,8 @@ void Thermostat::show_values(uuid::console::Shell & shell) { } if (Helpers::hasValue(ibaLanguage_)) { - if (ibaLanguage_ == 0) { - shell.printfln(F(" Language: German")); - } else if (ibaLanguage_ == 1) { - shell.printfln(F(" Language: Dutch")); - } else if (ibaLanguage_ == 2) { - shell.printfln(F(" Language: French")); - } else if (ibaLanguage_ == 3) { - shell.printfln(F(" Language: Italian")); - } + char s[10]; + print_value(shell, 2, F("Language"), Helpers::render_enum(s, {"German","Dutch","French","Italian"}, ibaLanguage_)); } } @@ -862,13 +865,8 @@ void Thermostat::show_values(uuid::console::Shell & shell) { } if (Helpers::hasValue(ibaBuildingType_)) { - if (ibaBuildingType_ == 0) { - shell.printfln(F(" Building: light")); - } else if (ibaBuildingType_ == 1) { - shell.printfln(F(" Building: medium")); - } else if (ibaBuildingType_ == 2) { - shell.printfln(F(" Building: heavy")); - } + char s[10]; + print_value(shell, 2, F("Building"), Helpers::render_enum(s, {"light","medium","heavy"}, ibaBuildingType_)); } } @@ -946,12 +944,8 @@ void Thermostat::show_values(uuid::console::Shell & shell) { print_value(shell, 4, F("Summer temperature"), hc->summertemp, F_(degrees)); } if (Helpers::hasValue(hc->summer_setmode)) { - if (hc->summer_setmode == 1) { - print_value(shell, 4, F("Summer mode"), F("auto")); - } else { - char s[7]; - print_value(shell, 4, F("Summer mode"), Helpers::render_boolean(s, (hc->summer_setmode == 0))); - } + char s[7]; + print_value(shell, 4, F("Summer mode"), Helpers::render_enum(s, {"off","auto","on"}, hc->summer_setmode)); } if (Helpers::hasValue(hc->targetflowtemp)) { print_value(shell, 4, F("Target flow temperature"), hc->targetflowtemp, F_(degrees)); @@ -1129,11 +1123,25 @@ void Thermostat::process_RC300Summer(std::shared_ptr telegram) { changed_ |= telegram->read_value(hc->summer_setmode, 7); } -// types 0x31D and 0x31E +// types 0x31B (and 0x31C?) +void Thermostat::process_RC300WWtemp(std::shared_ptr telegram) { + changed_ |= telegram->read_value(wwTemp_, 0); + changed_ |= telegram->read_value(wwTempLow_, 1); +} + +// type 02F5 void Thermostat::process_RC300WWmode(std::shared_ptr telegram) { + changed_ |=telegram->read_value(wwMode_, 2); // 0=off, 1=low, 2=high, 3=auto, 4=own prog +} + +// types 0x31D and 0x31E +void Thermostat::process_RC300WWmode2(std::shared_ptr telegram) { // 0x31D for WW system 1, 0x31E for WW system 2 - wwSystem_ = telegram->type_id - 0x31D + 1; - changed_ |= telegram->read_value(wwExtra_, 0); // 0=no, 1=yes + if (telegram->type_id == 0x031D) { + changed_ |= telegram->read_value(wwExtra1_, 0); // 0=no, 1=yes + } else { + changed_ |= telegram->read_value(wwExtra2_, 0); // 0=no, 1=yes + } // pos 1 = holiday mode // pos 2 = current status of DHW setpoint // pos 3 = current status of DHW circulation pump @@ -1239,6 +1247,7 @@ void Thermostat::process_RCTime(std::shared_ptr telegram) { bool Thermostat::set_minexttemp(const char * value, const int8_t id) { int mt = 0; if (!Helpers::value2number(value, mt)) { + LOG_WARNING(F("Set min external temperature: Invalid value")); return false; } @@ -1252,6 +1261,7 @@ bool Thermostat::set_minexttemp(const char * value, const int8_t id) { bool Thermostat::set_clockoffset(const char * value, const int8_t id) { int co = 0; if (!Helpers::value2number(value, co)) { + LOG_WARNING(F("Set clock offset: Invalid value")); return false; } @@ -1265,6 +1275,7 @@ bool Thermostat::set_clockoffset(const char * value, const int8_t id) { bool Thermostat::set_calinttemp(const char * value, const int8_t id) { int ct = 0; if (!Helpers::value2number(value, ct)) { + LOG_WARNING(F("Cal internal temperature: Invalid value")); return false; } @@ -1278,6 +1289,7 @@ bool Thermostat::set_calinttemp(const char * value, const int8_t id) { bool Thermostat::set_display(const char * value, const int8_t id) { int ds = 0; if (!Helpers::value2number(value, ds)) { + LOG_WARNING(F("Set display: Invalid value")); return false; } @@ -1290,6 +1302,7 @@ bool Thermostat::set_display(const char * value, const int8_t id) { bool Thermostat::set_remotetemp(const char * value, const int8_t id) { float f = 0; if (!Helpers::value2float(value, f)) { + LOG_WARNING(F("Set remote temperature: Invalid value")); return false; } @@ -1306,32 +1319,23 @@ bool Thermostat::set_remotetemp(const char * value, const int8_t id) { // 0xA5 - Set the building settings bool Thermostat::set_building(const char * value, const int8_t id) { - std::string bd(20, '\0'); - if (!Helpers::value2string(value, bd)) { + uint8_t bd = 0; + if (!Helpers::value2enum(value, bd, {"light","medium","heavy"})) { + LOG_WARNING(F("Set building: Invalid value")); return false; } - uint8_t bg = 0; - if (bd == "light") { - bg = 0; - } else if (bd == "medium") { - bg = 1; - } else if (bd == "heavy") { - bg = 2; - } else { - return false; // invalid - } - - LOG_INFO(F("Setting building to %d"), bg); - write_command(EMS_TYPE_IBASettings, 6, bg, EMS_TYPE_IBASettings); + LOG_INFO(F("Setting building to %s"), value); + write_command(EMS_TYPE_IBASettings, 6, bd, EMS_TYPE_IBASettings); return true; } // 0xA5 Set the language settings bool Thermostat::set_language(const char * value, const int8_t id) { - int lg = 0; - if (!Helpers::value2number(value, lg)) { + uint8_t lg = 0; + if (!Helpers::value2enum(value, lg, {"german","dutch","french","italian"})) { + LOG_WARNING(F("Set language: Invalid value")); return false; } @@ -1345,19 +1349,13 @@ bool Thermostat::set_language(const char * value, const int8_t id) { bool Thermostat::set_control(const char * value, const int8_t id) { int ctrl = 0; if (!Helpers::value2number(value, ctrl)) { + LOG_WARNING(F("Set control: Invalid value")); return false; } - uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; - - std::shared_ptr hc = heating_circuit(hc_num); - if (hc == nullptr) { - LOG_WARNING(F("Set control: Heating Circuit %d not found or activated"), hc_num); - return false; - } - - if (ctrl > 2) { - LOG_WARNING(F("Set control: Invalid control mode: %d"), ctrl); + uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; + std::shared_ptr hc = heating_circuit(hc_num); + if (hc == nullptr || ctrl > 2) { return false; } @@ -1367,55 +1365,61 @@ bool Thermostat::set_control(const char * value, const int8_t id) { return true; } -// sets the thermostat ww working mode, where mode is a string +// 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) { - std::string v(10, '\0'); - if (!Helpers::value2string(value, v)) { - return false; - } - - uint8_t set = 0xFF; // some dummy value - if (v == "off" || v == "0" || v == "false") { - set = 0; - } else if (v == "on" || v == "1" || v == "true") { - set = 1; - } else if (v == "auto" || v == "2") { - set = 2; - } - - if (set != 0xFF) { - LOG_INFO(F("Setting thermostat warm water mode to %s"), v.c_str()); - write_command(EMS_TYPE_wwSettings, 2, set, EMS_TYPE_wwSettings); + uint8_t set = 0xFF; + if ((this->model() == EMS_DEVICE_FLAG_RC300) || (this->model() == EMS_DEVICE_FLAG_RC100)) { + if (!Helpers::value2enum(value, set, {"off","low","high","auto","own"})) { + LOG_WARNING(F("Set warm water mode: Invalid mode")); + return false; + } + LOG_INFO(F("Setting warm water mode to %s"), value); + write_command(0x02F5, 2, set, 0x02F5); } else { - LOG_WARNING(F("Set thermostat warm water mode: Invalid mode: %s"), v.c_str()); + if (!Helpers::value2enum(value, set, {"off","on","auto"})) { + LOG_WARNING(F("Set warm water mode: Invalid mode")); + return false; + } + LOG_INFO(F("Setting warm water mode to %s"), value); + write_command(EMS_TYPE_wwSettings, 2, set, EMS_TYPE_wwSettings); } - 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) { - std::string v(10, '\0'); - if (!Helpers::value2string(value, v)) { +// Set wwhigh temperature, ems+ +bool Thermostat::set_wwtemp(const char * value, const int8_t id) { + int t = 0; + if (!Helpers::value2number(value, t)) { + LOG_WARNING(F("Set warm water high temperature: Invalid value")); return false; } + LOG_INFO(F("Setting warm water high temperature to %d"), t); + write_command(0x031B, 0, t, 0x031B); + return true; +} - uint8_t set = 0xFF; // some dummy value - if (v == "off" || v == "0" || v == "false") { - set = 0; - } else if (v == "on" || v == "1" || v == "true") { - set = 1; - } else if (v == "auto" || v == "2") { - set = 2; +// Set ww low temperature, ems+ +bool Thermostat::set_wwtemplow(const char * value, const int8_t id) { + int t = 0; + if (!Helpers::value2number(value, t)) { + LOG_WARNING(F("Set warm water low temperature: Invalid value")); + return false; } + LOG_INFO(F("Setting warm water low temperature to %d"), t); + write_command(0x031B, 1, t, 0x031B); + return true; +} - if (set != 0xFF) { - LOG_INFO(F("Setting thermostat warm water circulation mode to %s"), v.c_str()); - write_command(EMS_TYPE_wwSettings, 3, set, EMS_TYPE_wwSettings); - } else { - LOG_WARNING(F("Set thermostat warm water circulation mode: Invalid mode: %s"), v.c_str()); + +// sets the thermostat ww circulation working mode, where mode is a string +bool Thermostat::set_wwcircmode(const char * value, const int8_t id) { + uint8_t set = 0xFF; + if (!Helpers::value2enum(value, set, {"off","on","auto"})) { + LOG_WARNING(F("Set warm water circulation mode: Invalid mode")); + return false; } - + LOG_INFO(F("Setting warm water circulation mode to %s"), value); + write_command(EMS_TYPE_wwSettings, 3, set, EMS_TYPE_wwSettings); return true; } @@ -1423,11 +1427,11 @@ bool Thermostat::set_wwcircmode(const char * value, const int8_t id) { bool Thermostat::set_holiday(const char * value, const int8_t id) { std::string hd(30, '\0'); if (!Helpers::value2string(value, hd)) { + LOG_WARNING(F("Set holiday: Invalid value")); return false; } - uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; - - std::shared_ptr hc = heating_circuit(hc_num); + uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; + std::shared_ptr hc = heating_circuit(hc_num); if (hc == nullptr) { LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->device_id()); return false; @@ -1451,11 +1455,12 @@ bool Thermostat::set_holiday(const char * value, const int8_t id) { bool Thermostat::set_pause(const char * value, const int8_t id) { int hrs = 0; if (!Helpers::value2number(value, hrs)) { + LOG_WARNING(F("Set pause: Invalid value")); return false; } - uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; - std::shared_ptr hc = heating_circuit(hc_num); + uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; + std::shared_ptr hc = heating_circuit(hc_num); if (hc == nullptr) { LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->device_id()); return false; @@ -1471,6 +1476,7 @@ bool Thermostat::set_pause(const char * value, const int8_t id) { bool Thermostat::set_party(const char * value, const int8_t id) { int hrs = 0; if (!Helpers::value2number(value, hrs)) { + LOG_WARNING(F("Set party: Invalid value")); return false; } uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; @@ -1492,6 +1498,7 @@ bool Thermostat::set_party(const char * value, const int8_t id) { bool Thermostat::set_datetime(const char * value, const int8_t id) { std::string dt(30, '\0'); if (!Helpers::value2string(value, dt)) { + LOG_WARNING(F("Set date: Invalid value")); return false; } @@ -1537,6 +1544,7 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) { bool Thermostat::set_mode(const char * value, const int8_t id) { std::string mode(10, '\0'); if (!Helpers::value2string(value, mode)) { + LOG_WARNING(F("Set mode: Invalid mode")); return false; } @@ -1572,6 +1580,7 @@ bool Thermostat::set_mode(const char * value, const int8_t id) { return set_mode_n(HeatingCircuit::Mode::COMFORT, hc_num); } + LOG_WARNING(F("Set mode: Invalid mode %s"), value); return false; } @@ -1669,6 +1678,7 @@ bool Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) { return true; } +// sets the thermostat summermode for RC300 bool Thermostat::set_summermode(const char * value, const int8_t id) { uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; std::shared_ptr hc = heating_circuit(hc_num); @@ -1676,26 +1686,12 @@ bool Thermostat::set_summermode(const char * value, const int8_t id) { LOG_WARNING(F("Setting summer mode: Heating Circuit %d not found or activated"), hc_num); return false; } - std::string v(10, '\0'); - if (!Helpers::value2string(value, v)) { - LOG_WARNING(F("Setting summer mode: Invalid value")); - return false; - } - - uint8_t set = 0xFF; // some dummy value - if (v == "on" || v == "1" || v == "true") { - LOG_INFO(F("Setting summer mode to always on for heating circuit %d"), hc->hc_num()); - set = 0; - } else if (v == "auto" || v == "2") { - LOG_INFO(F("Setting summer mode to auto for heating circuit %d"), hc->hc_num()); - set = 1; - } else if (v == "off" || v == "0" || v == "false") { - LOG_INFO(F("Setting summer mode to always off for heating circuit %d"), hc->hc_num()); - set = 2; - } else { - LOG_WARNING(F("Setting summer mode: Invalid value %s"), v.c_str()); + uint8_t set = 0xFF; + if (!Helpers::value2enum(value, set, {"off","auto","on"})) { + LOG_WARNING(F("Setting summer mode: Invalid mode")); return false; } + LOG_INFO(F("Setting summer mode to %s for heating circuit %d"), value, hc->hc_num()); write_command(summer_typeids[hc->hc_num() - 1], 7, set, summer_typeids[hc->hc_num() - 1]); return true; } @@ -1740,7 +1736,7 @@ bool Thermostat::set_temperature(const float temperature, const std::string & mo return set_temperature(temperature, HeatingCircuit::Mode::DESIGN, hc_num); } - LOG_WARNING(F("Invalid mode %s."), mode.c_str()); + LOG_WARNING(F("Set temperature: Invalid mode")); return false; } @@ -1933,6 +1929,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co return true; } + LOG_WARNING(F("Set temperature: Invalid value")); return false; } @@ -1942,6 +1939,7 @@ bool Thermostat::set_temperature_value(const char * value, const int8_t id, cons if (Helpers::value2float(value, f)) { return set_temperature(f, mode, hc_num); } else { + LOG_WARNING(F("Set temperature: Invalid value")); return false; } } @@ -2008,13 +2006,8 @@ void Thermostat::add_commands() { // common to all thermostats register_mqtt_cmd(F("temp"), [&](const char * value, const int8_t id) { return set_temp(value, id); }); - register_mqtt_cmd(F("mode"), [=](const char * value, const int8_t id) { - if (!set_mode(value, id)) { - LOG_WARNING(F("Invalid mode %s. Cannot set"), value); - return false; - } - return true; - }); + register_mqtt_cmd(F("mode"), [&](const char * value, const int8_t id) { return set_mode(value, id); }); + register_mqtt_cmd(F("datetime"), [&](const char * value, const int8_t id) { return set_datetime(value, id); }); uint8_t model = this->model(); switch (model) { @@ -2025,6 +2018,9 @@ void Thermostat::add_commands() { register_mqtt_cmd(F("comforttemp"), [&](const char * value, const int8_t id) { return set_comforttemp(value, id); }); register_mqtt_cmd(F("summermode"), [&](const char * value, const int8_t id) { return set_summermode(value, id); }); register_mqtt_cmd(F("summertemp"), [&](const char * value, const int8_t id) { return set_summertemp(value, id); }); + 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); }); break; case EMS_DEVICE_FLAG_RC20_2: register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); }); @@ -2039,7 +2035,6 @@ void Thermostat::add_commands() { register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { return set_daytemp(value, id); }); register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); }); register_mqtt_cmd(F("remotetemp"), [&](const char * value, const int8_t id) { return set_remotetemp(value, id); }); - register_mqtt_cmd(F("datetime"), [&](const char * value, const int8_t id) { return set_datetime(value, id); }); register_mqtt_cmd(F("minexttemp"), [&](const char * value, const int8_t id) { return set_minexttemp(value, id); }); register_mqtt_cmd(F("calinttemp"), [&](const char * value, const int8_t id) { return set_calinttemp(value, id); }); register_mqtt_cmd(F("building"), [&](const char * value, const int8_t id) { return set_building(value, id); }); diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 2dd3c170f..bc6039b62 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -137,10 +137,12 @@ class Thermostat : public EMSdevice { uint16_t tempsensor1_ = EMS_VALUE_USHORT_NOTSET; uint16_t tempsensor2_ = EMS_VALUE_USHORT_NOTSET; - uint8_t wwSystem_ = EMS_VALUE_UINT_NOTSET; - uint8_t wwExtra_ = EMS_VALUE_UINT_NOTSET; + uint8_t wwExtra1_ = EMS_VALUE_UINT_NOTSET; // wwExtra active for wwSystem 1 + uint8_t wwExtra2_ = EMS_VALUE_UINT_NOTSET; uint8_t wwMode_ = EMS_VALUE_UINT_NOTSET; uint8_t wwCircMode_ = EMS_VALUE_UINT_NOTSET; + uint8_t wwTemp_ = EMS_VALUE_UINT_NOTSET; + uint8_t wwTempLow_ = EMS_VALUE_UINT_NOTSET; std::vector> heating_circuits_; // each thermostat can have multiple heating circuits @@ -245,6 +247,8 @@ class Thermostat : public EMSdevice { void process_RC300Set(std::shared_ptr telegram); void process_RC300Summer(std::shared_ptr telegram); void process_RC300WWmode(std::shared_ptr telegram); + void process_RC300WWmode2(std::shared_ptr telegram); + void process_RC300WWtemp(std::shared_ptr telegram); void process_JunkersMonitor(std::shared_ptr telegram); void process_JunkersSet(std::shared_ptr telegram); void process_JunkersSet2(std::shared_ptr telegram); @@ -281,6 +285,8 @@ class Thermostat : public EMSdevice { // 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_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); diff --git a/src/helpers.cpp b/src/helpers.cpp index 1eb195b84..ac1ed1a1a 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -134,6 +134,24 @@ char * Helpers::render_boolean(char * result, bool value) { return result; } +// depending on format render a number or a string +char * Helpers::render_enum(char * result, const std::vector value, const int8_t no) { + if (bool_format() == BOOL_FORMAT_ONOFF) { + strcpy(result, value[no].c_str()); + } else if (bool_format() == BOOL_FORMAT_TRUEFALSE) { + if (no == 0 && value[0] == "off") { + strlcpy(result, "false", 7); + } else if (no == 1 && value[1] == "on") { + strlcpy(result, "true", 6); + } else { + strcpy(result, value[no].c_str()); + } + } else { + itoa(result, no); + } + return result; +} + // render for native char strings char * Helpers::render_value(char * result, const char * value, uint8_t format) { strcpy(result, value); @@ -402,7 +420,7 @@ std::string Helpers::toLower(std::string const & s) { return lc; } -// checks if we can convert a chat string to an int value +// checks if we can convert a char string to a lowercase string bool Helpers::value2string(const char * v, std::string & value) { if ((v == nullptr) || (strlen(v) == 0)) { value = {}; @@ -434,4 +452,19 @@ bool Helpers::value2bool(const char * v, bool & value) { return false; // not a bool } +// checks to see if a string is member of a vector and return the index, also allow true/false for on/off +bool Helpers::value2enum(const char * v, uint8_t & value, const std::vector strs) { + if ((v == nullptr) || (strlen(v) == 0)) { + return false; + } + std::string str = toLower(v); + for (value = 0; value < strs.size(); value++) { + if ((strs[value] == "off" && str == "false") || (strs[value] == "on" && str == "true") || (str == strs[value]) || (v[0] == '0' + value)) { + return true; + } + } + return false; +} + + } // namespace emsesp diff --git a/src/helpers.h b/src/helpers.h index 034ddbe36..b94c5b449 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -43,6 +43,7 @@ class Helpers { static char * render_value(char * result, const char * value, uint8_t format); static char * render_boolean(char * result, bool value); + static char * render_enum(char * result, const std::vector value, const int8_t no); static char * smallitoa(char * result, const uint8_t value); static char * smallitoa(char * result, const uint16_t value); @@ -77,6 +78,9 @@ class Helpers { static bool value2bool(const char * v, bool & value); static bool value2string(const char * v, std::string & value); + static bool value2enum(const char * v, uint8_t & value, const std::vector strs); + + private: static uint8_t bool_format_; };