diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 58444c916..9ecf8780c 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -1028,6 +1028,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; } @@ -1035,8 +1036,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; @@ -1046,6 +1047,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; } @@ -1059,6 +1061,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; } @@ -1076,6 +1079,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; } @@ -1093,6 +1097,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; } @@ -1110,6 +1115,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; } @@ -1127,6 +1133,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; } @@ -1144,6 +1151,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; } @@ -1161,6 +1169,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; } @@ -1178,21 +1187,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; } @@ -1200,14 +1213,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 { @@ -1222,10 +1233,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; @@ -1249,10 +1261,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; @@ -1283,10 +1296,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 { @@ -1301,10 +1315,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 { @@ -1318,10 +1333,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); @@ -1337,14 +1353,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 6a1dc2bf7..4cd4a75a9 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) { @@ -326,6 +328,72 @@ void Thermostat::publish_values() { // creates JSON doc from values // returns false if empty +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) { + has_data = true; + if (Helpers::hasValue(dampedoutdoortemp_)) { + rootThermostat["dampedtemp"] = dampedoutdoortemp_; + } + if (Helpers::hasValue(tempsensor1_)) { + rootThermostat["inttemp1"] = (float)tempsensor1_ / 10; + } + if (Helpers::hasValue(tempsensor2_)) { + rootThermostat["inttemp2"] = (float)tempsensor2_ / 10; + } + if (Helpers::hasValue(ibaCalIntTemperature_)) { + rootThermostat["intoffset"] = (float)ibaCalIntTemperature_ / 2; + } + if (Helpers::hasValue(ibaMinExtTemperature_)) { + rootThermostat["minexttemp"] = (float)ibaMinExtTemperature_; // min ext temp for heating curve, in deg. + } + if (Helpers::hasValue(ibaBuildingType_)) { + char s[10]; + rootThermostat["building"] = Helpers::render_enum(s, {"light","medium","heavy"}, ibaBuildingType_); + } + } + 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_)) { + char s[7]; + rootThermostat["wwcircmode"] = Helpers::render_enum(s, {"off","on","auto"}, wwCircMode_); + has_data = true; + } + + 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; + + +======= bool Thermostat::export_values_main(JsonObject & rootThermostat) { // Clock time if (datetime_.size()) { @@ -440,7 +508,6 @@ bool Thermostat::export_values_hc(uint8_t mqtt_format, JsonObject & rootThermost JsonObject dataThermostat; // go through all the heating circuits - bool has_data = false; for (const auto & hc : heating_circuits_) { if (hc->is_active()) { has_data = true; @@ -545,12 +612,8 @@ bool Thermostat::export_values_hc(uint8_t mqtt_format, JsonObject & rootThermost // Summer mode 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 @@ -958,6 +1021,179 @@ std::string Thermostat::mode_tostring(uint8_t mode) { } } +// display all thermostat values into the shell console +void Thermostat::show_values(uuid::console::Shell & shell) { + EMSdevice::show_values(shell); // always call this to show header + + uint8_t flags = this->model(); + + if (datetime_.size()) { + shell.printfln(F(" Clock: %s"), datetime_.c_str()); + if (Helpers::hasValue(ibaClockOffset_) && flags == EMS_DEVICE_FLAG_RC30_1) { + print_value(shell, 2, F("Offset clock"), ibaClockOffset_, nullptr); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s + } + } + + if (Helpers::hasValue(wwMode_)) { + 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"), 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_)) { + 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) { + print_value(shell, 2, F("Damped Outdoor temperature"), dampedoutdoortemp_, F_(degrees)); + print_value(shell, 2, F("Temp sensor 1"), tempsensor1_, F_(degrees), 10); + print_value(shell, 2, F("Temp sensor 2"), tempsensor2_, F_(degrees), 10); + } + + if (flags == EMS_DEVICE_FLAG_RC30_1) { + // settings parameters + if (Helpers::hasValue(ibaMainDisplay_)) { + if (ibaMainDisplay_ == 0) { + shell.printfln(F(" Display: internal temperature")); + } else if (ibaMainDisplay_ == 1) { + shell.printfln(F(" Display: internal setpoint")); + } else if (ibaMainDisplay_ == 2) { + shell.printfln(F(" Display: external temperature")); + } else if (ibaMainDisplay_ == 3) { + shell.printfln(F(" Display: burner temperature")); + } else if (ibaMainDisplay_ == 4) { + shell.printfln(F(" Display: WW temperature")); + } else if (ibaMainDisplay_ == 5) { + shell.printfln(F(" Display: functioning mode")); + } else if (ibaMainDisplay_ == 6) { + shell.printfln(F(" Display: time")); + } else if (ibaMainDisplay_ == 7) { + shell.printfln(F(" Display: date")); + } else if (ibaMainDisplay_ == 8) { + shell.printfln(F(" Display: smoke temperature")); + } + } + + if (Helpers::hasValue(ibaLanguage_)) { + char s[10]; + print_value(shell, 2, F("Language"), Helpers::render_enum(s, {"German","Dutch","French","Italian"}, ibaLanguage_)); + } + } + + if (flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) { + if (Helpers::hasValue(ibaCalIntTemperature_)) { + print_value(shell, 2, F("Offset int. temperature"), ibaCalIntTemperature_, F_(degrees), 2); + } + + if (Helpers::hasValue(ibaMinExtTemperature_)) { + print_value(shell, 2, F("Min ext. temperature"), ibaMinExtTemperature_, F_(degrees)); // min ext temp for heating curve, in deg. + } + + if (Helpers::hasValue(ibaBuildingType_)) { + char s[10]; + print_value(shell, 2, F("Building"), Helpers::render_enum(s, {"light","medium","heavy"}, ibaBuildingType_)); + } + } + + for (const auto & hc : heating_circuits_) { + if (!hc->is_active()) { + break; // skip this HC + } + + shell.printfln(F(" Heating Circuit %d:"), hc->hc_num()); + + // different thermostat types store their temperature values differently + uint8_t format_setpoint, format_curr; + switch (flags) { + case EMS_DEVICE_FLAG_EASY: + format_setpoint = 100; // *100 + format_curr = 100; // *100 + break; + case EMS_DEVICE_FLAG_JUNKERS: + format_setpoint = 10; // *10 + format_curr = 10; // *10 + break; + default: // RC30, RC35 etc... + format_setpoint = 2; // *2 + format_curr = 10; // *10 + break; + } + + print_value(shell, 4, F("Current room temperature"), hc->curr_roomTemp, F_(degrees), format_curr); + print_value(shell, 4, F("Setpoint room temperature"), hc->setpoint_roomTemp, F_(degrees), format_setpoint); + + if (Helpers::hasValue(hc->mode)) { + print_value(shell, 4, F("Mode"), mode_tostring(hc->get_mode(flags)).c_str()); + } + if (Helpers::hasValue(hc->mode_type)) { + print_value(shell, 4, F("Mode Type"), mode_tostring(hc->get_mode_type(flags)).c_str()); + } + + if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) { + shell.printfln(F(" Program is set to Summer mode")); + } else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) { + shell.printfln(F(" Program is set to Holiday mode")); + } + + if (Helpers::hasValue(hc->daytemp)) { + if (flags == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { + print_value(shell, 4, F("Heat temperature"), hc->daytemp, F_(degrees), 2); + } else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC300 || flags == EMSdevice::EMS_DEVICE_FLAG_RC100) { + print_value(shell, 4, F("Comfort temperature"), hc->daytemp, F_(degrees), 2); + } else { + print_value(shell, 4, F("Day temperature"), hc->daytemp, F_(degrees), 2); + } + } + + if (Helpers::hasValue(hc->nighttemp)) { + if (flags == EMSdevice::EMS_DEVICE_FLAG_JUNKERS || flags == EMSdevice::EMS_DEVICE_FLAG_RC300 || flags == EMSdevice::EMS_DEVICE_FLAG_RC100) { + print_value(shell, 4, F("Eco temperature"), hc->nighttemp, F_(degrees), 2); + } else { + print_value(shell, 4, F("Night temperature"), hc->nighttemp, F_(degrees), 2); + } + } + if (Helpers::hasValue(hc->manualtemp)) { + print_value(shell, 4, F("Manual temperature"), hc->manualtemp, F_(degrees), 2); + } + if (Helpers::hasValue(hc->nofrosttemp)) { + print_value(shell, 4, F("Nofrost temperature"), hc->nofrosttemp, F_(degrees), 2); + } + if (Helpers::hasValue(hc->holidaytemp)) { + print_value(shell, 4, F("Holiday temperature"), hc->holidaytemp, F_(degrees), 2); + } + if (Helpers::hasValue(hc->offsettemp)) { + print_value(shell, 4, F("Offset temperature"), hc->offsettemp, F_(degrees), 2); + } + if (Helpers::hasValue(hc->designtemp)) { + print_value(shell, 4, F("Design temperature"), hc->designtemp, F_(degrees)); + } + if (Helpers::hasValue(hc->summertemp)) { + print_value(shell, 4, F("Summer temperature"), hc->summertemp, F_(degrees)); + } + if (Helpers::hasValue(hc->summer_setmode)) { + 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)); + } + } + + shell.println(); +} + // 0xA8 - for reading the mode from the RC20 thermostat (0x17) void Thermostat::process_RC20Set(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); @@ -1129,11 +1365,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 +1489,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 +1503,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 +1517,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 +1531,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 +1544,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 +1561,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 +1591,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 +1607,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 +1669,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 +1697,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 +1718,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 +1740,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 +1786,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 +1822,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 +1920,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 +1928,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 +1978,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 +2171,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 +2181,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 +2248,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 +2260,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 +2277,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 5e39f814e..6ba055872 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -138,10 +138,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 @@ -246,6 +248,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); @@ -282,6 +286,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_; };