From 49eb0495334a346510a0bbd2fb186a684e2ddc01 Mon Sep 17 00:00:00 2001 From: kwertie01 <48419274+kwertie01@users.noreply.github.com> Date: Mon, 11 Apr 2022 11:43:15 +0200 Subject: [PATCH 01/10] Added Moduline 400 WW settings and clock program --- src/devices/thermostat.cpp | 209 ++++++++++++++++++++++++++++++++++++- src/devices/thermostat.h | 19 +++- src/locale_DE.h | 2 + src/locale_EN.h | 2 + 4 files changed, 224 insertions(+), 8 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index c34f40c62..c4778a232 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -107,10 +107,15 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i } else if (model == EMSdevice::EMS_DEVICE_FLAG_RC30) { monitor_typeids = {0x41}; set_typeids = {0xA7}; + curve_typeids = {0x40}; + timer_typeids = {0x3F}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, MAKE_PF_CB(process_RC30Monitor)); register_telegram_type(set_typeids[i], F("RC30Set"), false, MAKE_PF_CB(process_RC30Set)); + register_telegram_type(curve_typeids[i], F("RC30Temp"), false, MAKE_PF_CB(process_RC30Temp)); + register_telegram_type(timer_typeids[i], F("RC30Timer"), false, MAKE_PF_CB(process_RC30Timer)); } + register_telegram_type(EMS_TYPE_RC30wwSettings, F("RC30WWSettings"), true, MAKE_PF_CB(process_RC30wwSettings)); // EASY } else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) { @@ -788,6 +793,15 @@ void Thermostat::process_RC35wwSettings(std::shared_ptr telegram has_update(telegram, wwOneTimeKey_, 9); // 0-off, 0xFF on } +// Settings WW 0x3A - RC30 +void Thermostat::process_RC30wwSettings(std::shared_ptr telegram) { + has_update(telegram, wwMode_, 0); // 0-on, 1-off, 2-auto + has_update(telegram, wwWhenModeOff_, 1); // 0-off, 0xFF on + has_update(telegram, wwDisinfecting_, 2); // 0-off, 0xFF on + has_update(telegram, wwDisinfectDay_, 3); // 0-6 Day of week, 7 every day + has_update(telegram, wwDisinfectHour_, 4); +} + // type 0x38 (ww) and 0x39 (circ) void Thermostat::process_RC35wwTimer(std::shared_ptr telegram) { if ((telegram->message_length == 2 && telegram->offset < 83 && !(telegram->offset & 1)) @@ -1040,7 +1054,7 @@ void Thermostat::process_RC30Monitor(std::shared_ptr telegram) { add_ha_climate(hc); } -// type 0xA7 - for reading the mode from the RC30 thermostat (0x10) +// type 0xA7 - for reading the mode from the RC30 thermostat (0x10) and all the installation settings void Thermostat::process_RC30Set(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); if (hc == nullptr) { @@ -1060,6 +1074,87 @@ void Thermostat::process_RC30Set(std::shared_ptr telegram) { has_update(telegram, preheating_, 26); // Preheating in the clock program: (0x00 = off, 0xFF = on) } +// type 0x40 (HC1) - for reading the operating mode from the RC30 thermostat (0x10) +void Thermostat::process_RC30Temp(std::shared_ptr telegram) { + // check to see we have a valid type. heating: 1 radiator, 2 convectors, 3 floors + if (telegram->offset == 0 && telegram->message_data[0] == 0x00) { + return; + } + + std::shared_ptr hc = heating_circuit(telegram); + if (hc == nullptr) { + return; + } + + has_update(telegram, hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor + has_update(telegram, hc->controlmode, 1); // 0-outdoortemp, 1-roomtemp + has_update(telegram, hc->nighttemp, 3); // is * 2 (T1) + has_update(telegram, hc->daylowtemp, 4); // is * 2 (T2) + has_update(telegram, hc->daymidtemp, 5); // is * 2 (T3) + has_update(telegram, hc->daytemp, 6); // is * 2 (T4) + has_update(telegram, hc->holidaytemp, 7); // is * 2 + +} + +// type 0x3F (HC1) - timer setting for RC30 +void Thermostat::process_RC30Timer(std::shared_ptr telegram) { + std::shared_ptr hc = heating_circuit(telegram); + if (hc == nullptr) { + return; + } + + if ((telegram->message_length == 2 && telegram->offset < 83 && !(telegram->offset & 1)) + || (!telegram->offset && telegram->message_length > 1 && !strlen(hc->switchtime1))) { + + char data[sizeof(hc->switchtime1)]; + uint8_t no = telegram->offset / 2; + uint8_t day = telegram->message_data[0] >> 5; + uint8_t temp = telegram->message_data[0] & 7; + uint8_t time = telegram->message_data[1]; + + std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); + if (day == 7) { + snprintf(data, sizeof(data), "%02d not_set", no); + } else { + snprintf(data, sizeof(data), "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), temp); + } + strlcpy(hc->switchtime1, data, sizeof(hc->switchtime1)); + has_update(hc->switchtime1); // always publish + } + + has_update(telegram, hc->program, 84); // 0 .. 10, 0-userprogram 1, 10-userprogram 2 + has_update(telegram, hc->pause, 85); // time in hours + has_update(telegram, hc->party, 86); // time in hours + + if (telegram->message_length + telegram->offset >= 92 && telegram->offset <= 87) { + char data[sizeof(hc->vacation)]; + snprintf(data, + sizeof(data), + "%02d.%02d.%04d-%02d.%02d.%04d", + telegram->message_data[87 - telegram->offset], + telegram->message_data[88 - telegram->offset], + telegram->message_data[89 - telegram->offset] + 2000, + telegram->message_data[90 - telegram->offset], + telegram->message_data[91 - telegram->offset], + telegram->message_data[92 - telegram->offset] + 2000); + has_update(hc->vacation, data, sizeof(hc->vacation)); + } + + if (telegram->message_length + telegram->offset >= 98 && telegram->offset <= 93) { + char data[sizeof(hc->holiday)]; + snprintf(data, + sizeof(data), + "%02d.%02d.%04d-%02d.%02d.%04d", + telegram->message_data[93 - telegram->offset], + telegram->message_data[94 - telegram->offset], + telegram->message_data[95 - telegram->offset] + 2000, + telegram->message_data[96 - telegram->offset], + telegram->message_data[97 - telegram->offset], + telegram->message_data[98 - telegram->offset] + 2000); + has_update(hc->holiday, data, sizeof(hc->holiday)); + } +} + // type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes void Thermostat::process_RC35Monitor(std::shared_ptr telegram) { // exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature @@ -1525,6 +1620,11 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) { return false; } write_command(0x02F5, 2, set, 0x02F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + if (!Helpers::value2enum(value, set, FL_(enum_wwMode3))) { + return false; + } + write_command(EMS_TYPE_RC30wwSettings, 0, set, EMS_TYPE_RC30wwSettings); } else { if (!Helpers::value2enum(value, set, FL_(enum_wwMode2))) { return false; @@ -1535,6 +1635,18 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) { return true; } +//Set ww when thermostat mode is off (RC30) +bool Thermostat::set_wwwhenmodeoff(const char * value, const int8_t id) { + bool b = false; + if (!Helpers::value2bool(value, b)) { + return false; + } + + write_command(EMS_TYPE_RC30wwSettings, 1, b ? 0xFF : 0x00, EMS_TYPE_RC30wwSettings); + + return true; +} + // Set ww temperature, ems+ bool Thermostat::set_wwtemp(const char * value, const int8_t id) { int t = 0; @@ -1656,6 +1768,8 @@ bool Thermostat::set_wwDisinfect(const char * value, const int8_t id) { if ((model() == EMS_DEVICE_FLAG_RC300) || (model() == EMS_DEVICE_FLAG_RC100)) { write_command(0x2F5, 5, b ? 0xFF : 0x00, 0x2F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + write_command(EMS_TYPE_RC30wwSettings, 2, b ? 0xFF : 0x00, EMS_TYPE_RC30wwSettings); } else { write_command(0x37, 4, b ? 0xFF : 0x00, 0x37); } @@ -1671,6 +1785,8 @@ bool Thermostat::set_wwDisinfectDay(const char * value, const int8_t id) { if ((model() == EMS_DEVICE_FLAG_RC300) || (model() == EMS_DEVICE_FLAG_RC100)) { write_command(0x2F5, 7, set, 0x2F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + write_command(EMS_TYPE_RC30wwSettings, 3, set, EMS_TYPE_RC30wwSettings); } else { write_command(0x37, 5, set, 0x37); } @@ -1685,6 +1801,11 @@ bool Thermostat::set_wwDisinfectHour(const char * value, const int8_t id) { return false; } write_command(0x2F5, 6, (set + 8) / 15, 0x2F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + if (!Helpers::value2number(value, set, 0, 23)) { + return false; + } + write_command(EMS_TYPE_RC30wwSettings, 4, set, EMS_TYPE_RC30wwSettings); } else { if (!Helpers::value2number(value, set, 0, 23)) { return false; @@ -2247,6 +2368,8 @@ bool Thermostat::set_heatingtype(const char * value, const int8_t id) { write_command(set_typeids[hc->hc()], 0, set, set_typeids[hc->hc()]); } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) { write_command(set_typeids[hc->hc()], 0, set, set_typeids[hc->hc()]); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + write_command(curve_typeids[hc->hc()], 0, set, curve_typeids[hc->hc()]); } else { write_command(curve_typeids[hc->hc()], 1, set, curve_typeids[hc->hc()]); return true; @@ -2270,6 +2393,11 @@ bool Thermostat::set_controlmode(const char * value, const int8_t id) { write_command(curve_typeids[hc->hc()], 0, set, curve_typeids[hc->hc()]); return true; } + } else if (model() == EMS_DEVICE_FLAG_RC30) { + if (Helpers::value2enum(value, set, FL_(enum_controlmode2))) { + write_command(curve_typeids[hc->hc()], 1, set, curve_typeids[hc->hc()]); + return true; + } } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) { if (Helpers::value2enum(value, set, FL_(enum_controlmode2))) { write_command(set_typeids[hc->hc()], 33, set, set_typeids[hc->hc()]); @@ -2489,7 +2617,7 @@ bool Thermostat::set_program(const char * value, const int8_t id) { if (Helpers::value2enum(value, set, FL_(enum_progMode3))) { write_command(set_typeids[hc->hc()], 11, set + 1, set_typeids[hc->hc()]); } - } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) { + } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N || model() == EMS_DEVICE_FLAG_RC30) { if (Helpers::value2enum(value, set, FL_(enum_progMode2))) { write_command(timer_typeids[hc->hc()], 84, set, timer_typeids[hc->hc()]); } @@ -2584,7 +2712,32 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co } } else if (model == EMS_DEVICE_FLAG_RC30) { - offset = EMS_OFFSET_RC30Set_temp; + + switch (mode) { + case HeatingCircuit::Mode::NIGHT: // change the night temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_night; + break; + case HeatingCircuit::Mode::DAYLOW: // change the offset temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_daylow; + break; + case HeatingCircuit::Mode::DAYMID: // change the offset of flowtemp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_daymid; + break; + case HeatingCircuit::Mode::DAY: // change the day temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_day; + break; + case HeatingCircuit::Mode::HOLIDAY: // change the holiday temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_holiday; + break; + default: + offset = EMS_OFFSET_RC30Set_temp; + break; + } } else if ((model == EMS_DEVICE_FLAG_RC300) || (model == EMS_DEVICE_FLAG_RC100)) { validate_typeid = set_typeids[hc->hc()]; @@ -3136,7 +3289,7 @@ void Thermostat::register_device_values() { DeviceValueType::ENUM, FL_(enum_ibaMainDisplay), FL_(ibaMainDisplay), - DeviceValueUOM::NONE); + DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_THERMOSTAT_DATA, &backlight_, DeviceValueType::BOOL, nullptr, FL_(backlight), DeviceValueUOM::NONE, MAKE_CF_CB(set_backlight)); register_device_value(DeviceValueTAG::TAG_THERMOSTAT_DATA, &brightness_, @@ -3187,6 +3340,38 @@ void Thermostat::register_device_values() { MAKE_CF_CB(set_offtemp), 5, 30); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwMode_, + DeviceValueType::ENUM, + FL_(enum_wwMode3), + FL_(wwMode), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwmode)); + register_device_value( + DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwWhenModeOff_, DeviceValueType::BOOL, nullptr, FL_(wwWhenModeOff), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwwhenmodeoff)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwDisinfecting_, + DeviceValueType::BOOL, + nullptr, + FL_(wwDisinfecting), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwDisinfect)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwDisinfectDay_, + DeviceValueType::ENUM, + FL_(enum_dayOfWeek), + FL_(wwDisinfectDay), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwDisinfectDay)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwDisinfectHour_, + DeviceValueType::UINT, + nullptr, + FL_(wwDisinfectHour), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwDisinfectHour), + 0, + 23); break; case EMS_DEVICE_FLAG_RC30_N: register_device_value(DeviceValueTAG::TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime @@ -3552,6 +3737,22 @@ void Thermostat::register_device_values_hc(std::shared_ptrmode, DeviceValueType::ENUM, FL_(enum_mode3), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); + register_device_value(tag, &hc->holiday, DeviceValueType::STRING, FL_(tpl_holidays), FL_(holidays), DeviceValueUOM::NONE, MAKE_CF_CB(set_holiday)); + register_device_value(tag, &hc->vacation, DeviceValueType::STRING, FL_(tpl_holidays), FL_(vacations), DeviceValueUOM::NONE, MAKE_CF_CB(set_vacation)); + register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode2), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); + register_device_value(tag, &hc->pause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); + register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); + register_device_value( + tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime), FL_(switchtime1), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); + register_device_value( + tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); + register_device_value( + tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode2), FL_(controlmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_controlmode)); + register_device_value(tag, &hc->holidaytemp, DeviceValueType::UINT, FL_(div2), FL_(holidaytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_holidaytemp)); + register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp2), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value(tag, &hc->daylowtemp, DeviceValueType::UINT, FL_(div2), FL_(daylowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daylowtemp)); + register_device_value(tag, &hc->daymidtemp, DeviceValueType::UINT, FL_(div2), FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); + register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); break; case EMS_DEVICE_FLAG_RC30_N: case EMS_DEVICE_FLAG_RC35: diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 4c0a42b6c..b72e2f97f 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -215,6 +215,7 @@ class Thermostat : public EMSdevice { char wwCircSwitchTime_[16]; uint8_t wwDailyHeating_; uint8_t wwDailyHeatTime_; + uint8_t wwWhenModeOff_; std::vector> heating_circuits_; // each thermostat can have multiple heating circuits @@ -243,6 +244,11 @@ class Thermostat : public EMSdevice { static constexpr uint8_t EMS_OFFSET_RC30StatusMessage_curr = 2; // current temp static constexpr uint8_t EMS_OFFSET_RC30Set_mode = 23; // position of thermostat mode static constexpr uint8_t EMS_OFFSET_RC30Set_temp = 28; // position of thermostat setpoint temperature + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_night = 3; // position of thermostat setpoint temperature for night time (T1) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_daylow = 4; // position of thermostat setpoint temperature for daylow time (T2) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_daymid = 5; // position of thermostat setpoint temperature for daymid time (T3) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_day = 6; // position of thermostat setpoint temperature for day time (T4) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_holiday = 7; // temp during holiday mode static constexpr uint8_t EMS_OFFSET_RC35StatusMessage_setpoint = 2; // desired temp static constexpr uint8_t EMS_OFFSET_RC35StatusMessage_curr = 3; // current temp @@ -300,10 +306,11 @@ class Thermostat : public EMSdevice { static constexpr uint8_t AUTO_HEATING_CIRCUIT = 0; // Installation settings - static constexpr uint8_t EMS_TYPE_IBASettings = 0xA5; // installation settings - static constexpr uint8_t EMS_TYPE_RC30Settings = 0xA7; // RC30 settings - static constexpr uint8_t EMS_TYPE_wwSettings = 0x37; // ww settings - static constexpr uint8_t EMS_TYPE_time = 0x06; // time + static constexpr uint8_t EMS_TYPE_IBASettings = 0xA5; // installation settings + static constexpr uint8_t EMS_TYPE_RC30Settings = 0xA7; // RC30 settings + static constexpr uint8_t EMS_TYPE_wwSettings = 0x37; // ww settings + static constexpr uint8_t EMS_TYPE_RC30wwSettings = 0x3A; // RC30 ww settings + static constexpr uint8_t EMS_TYPE_time = 0x06; // time std::shared_ptr heating_circuit(std::shared_ptr telegram); std::shared_ptr heating_circuit(const uint8_t hc_num); @@ -324,6 +331,9 @@ class Thermostat : public EMSdevice { void process_RC35Timer(std::shared_ptr telegram); void process_RC30Monitor(std::shared_ptr telegram); void process_RC30Set(std::shared_ptr telegram); + void process_RC30Temp(std::shared_ptr telegram); + void process_RC30wwSettings(std::shared_ptr telegram); + void process_RC30Timer(std::shared_ptr telegram); void process_RC20Monitor(std::shared_ptr telegram); void process_RC20Set(std::shared_ptr telegram); void process_RC20Temp(std::shared_ptr telegram); @@ -423,6 +433,7 @@ class Thermostat : public EMSdevice { bool set_wwCircSwitchTime(const char * value, const int8_t id); bool set_wwDailyHeating(const char * value, const int8_t id); bool set_wwDailyHeatTime(const char * value, const int8_t id); + bool set_wwwhenmodeoff(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/locale_DE.h b/src/locale_DE.h index 703e33a9b..ca48445b7 100644 --- a/src/locale_DE.h +++ b/src/locale_DE.h @@ -600,6 +600,7 @@ MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("Kreis 1 Extra")) MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("Kreis 2 Extra")) MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) +MAKE_PSTR_LIST(wwWhenModeOff, F("wwwhenmodeoff"), F("wenn Thermostatmodus ist aus")) // thermostat hc MAKE_PSTR_LIST(climate, F("climate")) MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("Sollwert Raumtemperatur")) @@ -613,6 +614,7 @@ MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("Tagestemperatur T3")) MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("Tagestemperatur T4")) MAKE_PSTR_LIST(heattemp, F("heattemp"), F("Heizen Temperatur")) MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("Nachttemperatur")) +MAKE_PSTR_LIST(nighttemp2, F("nighttemp2"), F("Nachttemperatur T1")) MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco Temperatur")) MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manuelle Temperatur")) MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("zwischenzeitliche Solltemperatur")) diff --git a/src/locale_EN.h b/src/locale_EN.h index 3823a7bde..bac97b951 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -590,6 +590,7 @@ MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("circuit 1 extra")) MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra")) MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) +MAKE_PSTR_LIST(wwWhenModeOff, F("wwwhenmodeoff"), F("when thermostat mode off")) // thermostat hc MAKE_PSTR_LIST(climate, F("climate")) MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature")) @@ -603,6 +604,7 @@ MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("day temperature T3")) MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("day temperature T4")) MAKE_PSTR_LIST(heattemp, F("heattemp"), F("heat temperature")) MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("night temperature")) +MAKE_PSTR_LIST(nighttemp2, F("nighttemp2"), F("night temperature T1")) MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco temperature")) MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manual temperature")) MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("temporary set temperature automode")) From cffc2695dd3b0cef99aec219dd6d1170b918c405 Mon Sep 17 00:00:00 2001 From: kwertie01 <48419274+kwertie01@users.noreply.github.com> Date: Mon, 11 Apr 2022 11:57:42 +0200 Subject: [PATCH 02/10] fix wrong offset in set_party --- src/devices/thermostat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index c4778a232..6e61b9886 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -1986,7 +1986,7 @@ bool Thermostat::set_party(const char * value, const int8_t id) { } if (value == nullptr) { - read_command(timer_typeids[hc->hc()], 85, 1); + read_command(timer_typeids[hc->hc()], 86, 1); return true; } From 5882218cff61ceefe59cc35b5aed4ba7139cd1be Mon Sep 17 00:00:00 2001 From: kwertie01 <48419274+kwertie01@users.noreply.github.com> Date: Mon, 11 Apr 2022 11:59:29 +0200 Subject: [PATCH 03/10] fix sunday in dayofweek enum --- src/locale_EN.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale_EN.h b/src/locale_EN.h index bac97b951..819836664 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -382,7 +382,7 @@ MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x)) MAKE_PSTR_LIST(enum_j_control, F_(off), F("fb10"), F("fb100")) MAKE_PSTR_LIST(enum_wwProgMode, F("std_prog"), F_(own_prog)) -MAKE_PSTR_LIST(enum_dayOfWeek, F("mo"), F("tu"), F("we"), F("th"), F("fr"), F("sa"), F("so"), F("all")) +MAKE_PSTR_LIST(enum_dayOfWeek, F("mo"), F("tu"), F("we"), F("th"), F("fr"), F("sa"), F("su"), F("all")) MAKE_PSTR_LIST(enum_progMode, F("prog_1"), F("prog_2")) MAKE_PSTR_LIST(enum_progMode2, F("own_1"), F("family"), F("morning"), F("evening"), F("am"), F("pm"), F("midday"), F("singles"), F("seniors"), F("new"), F("own_2")) MAKE_PSTR_LIST(enum_progMode3, F("family"), F("morning"), F("evening"), F("am"), F("pm"), F("midday"), F("singles"), F("seniors")) From 88399094253b89ad2c09b9722b55dea23547ceda Mon Sep 17 00:00:00 2001 From: kwertie01 <48419274+kwertie01@users.noreply.github.com> Date: Mon, 11 Apr 2022 11:43:15 +0200 Subject: [PATCH 04/10] Added Moduline 400 WW settings and clock program --- src/devices/thermostat.cpp | 207 ++++++++++++++++++++++++++++++++++++- src/devices/thermostat.h | 19 +++- src/locale_DE.h | 2 + src/locale_EN.h | 2 + 4 files changed, 223 insertions(+), 7 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 48253bb2b..05190370a 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -107,10 +107,15 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i } else if (model == EMSdevice::EMS_DEVICE_FLAG_RC30) { monitor_typeids = {0x41}; set_typeids = {0xA7}; + curve_typeids = {0x40}; + timer_typeids = {0x3F}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, MAKE_PF_CB(process_RC30Monitor)); register_telegram_type(set_typeids[i], F("RC30Set"), false, MAKE_PF_CB(process_RC30Set)); + register_telegram_type(curve_typeids[i], F("RC30Temp"), false, MAKE_PF_CB(process_RC30Temp)); + register_telegram_type(timer_typeids[i], F("RC30Timer"), false, MAKE_PF_CB(process_RC30Timer)); } + register_telegram_type(EMS_TYPE_RC30wwSettings, F("RC30WWSettings"), true, MAKE_PF_CB(process_RC30wwSettings)); // EASY } else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) { @@ -788,6 +793,15 @@ void Thermostat::process_RC35wwSettings(std::shared_ptr telegram has_update(telegram, wwOneTimeKey_, 9); // 0-off, 0xFF on } +// Settings WW 0x3A - RC30 +void Thermostat::process_RC30wwSettings(std::shared_ptr telegram) { + has_update(telegram, wwMode_, 0); // 0-on, 1-off, 2-auto + has_update(telegram, wwWhenModeOff_, 1); // 0-off, 0xFF on + has_update(telegram, wwDisinfecting_, 2); // 0-off, 0xFF on + has_update(telegram, wwDisinfectDay_, 3); // 0-6 Day of week, 7 every day + has_update(telegram, wwDisinfectHour_, 4); +} + // type 0x38 (ww) and 0x39 (circ) void Thermostat::process_RC35wwTimer(std::shared_ptr telegram) { if ((telegram->message_length == 2 && telegram->offset < 83 && !(telegram->offset & 1)) @@ -1040,7 +1054,7 @@ void Thermostat::process_RC30Monitor(std::shared_ptr telegram) { add_ha_climate(hc); } -// type 0xA7 - for reading the mode from the RC30 thermostat (0x10) +// type 0xA7 - for reading the mode from the RC30 thermostat (0x10) and all the installation settings void Thermostat::process_RC30Set(std::shared_ptr telegram) { std::shared_ptr hc = heating_circuit(telegram); if (hc == nullptr) { @@ -1060,6 +1074,87 @@ void Thermostat::process_RC30Set(std::shared_ptr telegram) { has_update(telegram, preheating_, 26); // Preheating in the clock program: (0x00 = off, 0xFF = on) } +// type 0x40 (HC1) - for reading the operating mode from the RC30 thermostat (0x10) +void Thermostat::process_RC30Temp(std::shared_ptr telegram) { + // check to see we have a valid type. heating: 1 radiator, 2 convectors, 3 floors + if (telegram->offset == 0 && telegram->message_data[0] == 0x00) { + return; + } + + std::shared_ptr hc = heating_circuit(telegram); + if (hc == nullptr) { + return; + } + + has_update(telegram, hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor + has_update(telegram, hc->controlmode, 1); // 0-outdoortemp, 1-roomtemp + has_update(telegram, hc->nighttemp, 3); // is * 2 (T1) + has_update(telegram, hc->daylowtemp, 4); // is * 2 (T2) + has_update(telegram, hc->daymidtemp, 5); // is * 2 (T3) + has_update(telegram, hc->daytemp, 6); // is * 2 (T4) + has_update(telegram, hc->holidaytemp, 7); // is * 2 + +} + +// type 0x3F (HC1) - timer setting for RC30 +void Thermostat::process_RC30Timer(std::shared_ptr telegram) { + std::shared_ptr hc = heating_circuit(telegram); + if (hc == nullptr) { + return; + } + + if ((telegram->message_length == 2 && telegram->offset < 83 && !(telegram->offset & 1)) + || (!telegram->offset && telegram->message_length > 1 && !strlen(hc->switchtime1))) { + + char data[sizeof(hc->switchtime1)]; + uint8_t no = telegram->offset / 2; + uint8_t day = telegram->message_data[0] >> 5; + uint8_t temp = telegram->message_data[0] & 7; + uint8_t time = telegram->message_data[1]; + + std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); + if (day == 7) { + snprintf(data, sizeof(data), "%02d not_set", no); + } else { + snprintf(data, sizeof(data), "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), temp); + } + strlcpy(hc->switchtime1, data, sizeof(hc->switchtime1)); + has_update(hc->switchtime1); // always publish + } + + has_update(telegram, hc->program, 84); // 0 .. 10, 0-userprogram 1, 10-userprogram 2 + has_update(telegram, hc->pause, 85); // time in hours + has_update(telegram, hc->party, 86); // time in hours + + if (telegram->message_length + telegram->offset >= 92 && telegram->offset <= 87) { + char data[sizeof(hc->vacation)]; + snprintf(data, + sizeof(data), + "%02d.%02d.%04d-%02d.%02d.%04d", + telegram->message_data[87 - telegram->offset], + telegram->message_data[88 - telegram->offset], + telegram->message_data[89 - telegram->offset] + 2000, + telegram->message_data[90 - telegram->offset], + telegram->message_data[91 - telegram->offset], + telegram->message_data[92 - telegram->offset] + 2000); + has_update(hc->vacation, data, sizeof(hc->vacation)); + } + + if (telegram->message_length + telegram->offset >= 98 && telegram->offset <= 93) { + char data[sizeof(hc->holiday)]; + snprintf(data, + sizeof(data), + "%02d.%02d.%04d-%02d.%02d.%04d", + telegram->message_data[93 - telegram->offset], + telegram->message_data[94 - telegram->offset], + telegram->message_data[95 - telegram->offset] + 2000, + telegram->message_data[96 - telegram->offset], + telegram->message_data[97 - telegram->offset], + telegram->message_data[98 - telegram->offset] + 2000); + has_update(hc->holiday, data, sizeof(hc->holiday)); + } +} + // type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes void Thermostat::process_RC35Monitor(std::shared_ptr telegram) { // exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature @@ -1509,6 +1604,11 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) { return false; } write_command(0x02F5, 2, set, 0x02F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + if (!Helpers::value2enum(value, set, FL_(enum_wwMode3))) { + return false; + } + write_command(EMS_TYPE_RC30wwSettings, 0, set, EMS_TYPE_RC30wwSettings); } else { if (!Helpers::value2enum(value, set, FL_(enum_wwMode2))) { return false; @@ -1519,6 +1619,18 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) { return true; } +//Set ww when thermostat mode is off (RC30) +bool Thermostat::set_wwwhenmodeoff(const char * value, const int8_t id) { + bool b = false; + if (!Helpers::value2bool(value, b)) { + return false; + } + + write_command(EMS_TYPE_RC30wwSettings, 1, b ? 0xFF : 0x00, EMS_TYPE_RC30wwSettings); + + return true; +} + // Set ww temperature, ems+ bool Thermostat::set_wwtemp(const char * value, const int8_t id) { int t = 0; @@ -1640,6 +1752,8 @@ bool Thermostat::set_wwDisinfect(const char * value, const int8_t id) { if ((model() == EMS_DEVICE_FLAG_RC300) || (model() == EMS_DEVICE_FLAG_RC100)) { write_command(0x2F5, 5, b ? 0xFF : 0x00, 0x2F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + write_command(EMS_TYPE_RC30wwSettings, 2, b ? 0xFF : 0x00, EMS_TYPE_RC30wwSettings); } else { write_command(0x37, 4, b ? 0xFF : 0x00, 0x37); } @@ -1655,6 +1769,8 @@ bool Thermostat::set_wwDisinfectDay(const char * value, const int8_t id) { if ((model() == EMS_DEVICE_FLAG_RC300) || (model() == EMS_DEVICE_FLAG_RC100)) { write_command(0x2F5, 7, set, 0x2F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + write_command(EMS_TYPE_RC30wwSettings, 3, set, EMS_TYPE_RC30wwSettings); } else { write_command(0x37, 5, set, 0x37); } @@ -1669,6 +1785,11 @@ bool Thermostat::set_wwDisinfectHour(const char * value, const int8_t id) { return false; } write_command(0x2F5, 6, (set + 8) / 15, 0x2F5); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + if (!Helpers::value2number(value, set, 0, 23)) { + return false; + } + write_command(EMS_TYPE_RC30wwSettings, 4, set, EMS_TYPE_RC30wwSettings); } else { if (!Helpers::value2number(value, set, 0, 23)) { return false; @@ -2226,6 +2347,8 @@ bool Thermostat::set_heatingtype(const char * value, const int8_t id) { write_command(set_typeids[hc->hc()], 0, set, set_typeids[hc->hc()]); } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) { write_command(set_typeids[hc->hc()], 0, set, set_typeids[hc->hc()]); + } else if (model() == EMS_DEVICE_FLAG_RC30) { + write_command(curve_typeids[hc->hc()], 0, set, curve_typeids[hc->hc()]); } else { write_command(curve_typeids[hc->hc()], 1, set, curve_typeids[hc->hc()]); return true; @@ -2249,6 +2372,11 @@ bool Thermostat::set_controlmode(const char * value, const int8_t id) { write_command(curve_typeids[hc->hc()], 0, set, curve_typeids[hc->hc()]); return true; } + } else if (model() == EMS_DEVICE_FLAG_RC30) { + if (Helpers::value2enum(value, set, FL_(enum_controlmode2))) { + write_command(curve_typeids[hc->hc()], 1, set, curve_typeids[hc->hc()]); + return true; + } } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) { if (Helpers::value2enum(value, set, FL_(enum_controlmode2))) { write_command(set_typeids[hc->hc()], 33, set, set_typeids[hc->hc()]); @@ -2468,7 +2596,7 @@ bool Thermostat::set_program(const char * value, const int8_t id) { if (Helpers::value2enum(value, set, FL_(enum_progMode3))) { write_command(set_typeids[hc->hc()], 11, set + 1, set_typeids[hc->hc()]); } - } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) { + } else if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N || model() == EMS_DEVICE_FLAG_RC30) { if (Helpers::value2enum(value, set, FL_(enum_progMode2))) { write_command(timer_typeids[hc->hc()], 84, set, timer_typeids[hc->hc()]); } @@ -2563,7 +2691,32 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co } } else if (model == EMS_DEVICE_FLAG_RC30) { - offset = EMS_OFFSET_RC30Set_temp; + + switch (mode) { + case HeatingCircuit::Mode::NIGHT: // change the night temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_night; + break; + case HeatingCircuit::Mode::DAYLOW: // change the offset temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_daylow; + break; + case HeatingCircuit::Mode::DAYMID: // change the offset of flowtemp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_daymid; + break; + case HeatingCircuit::Mode::DAY: // change the day temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_day; + break; + case HeatingCircuit::Mode::HOLIDAY: // change the holiday temp + set_typeid = curve_typeids[hc->hc()]; + offset = EMS_OFFSET_RC30Temp_temp_holiday; + break; + default: + offset = EMS_OFFSET_RC30Set_temp; + break; + } } else if ((model == EMS_DEVICE_FLAG_RC300) || (model == EMS_DEVICE_FLAG_RC100)) { validate_typeid = set_typeids[hc->hc()]; @@ -3174,6 +3327,38 @@ void Thermostat::register_device_values() { MAKE_CF_CB(set_offtemp), 5, 30); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwMode_, + DeviceValueType::ENUM, + FL_(enum_wwMode3), + FL_(wwMode), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwmode)); + register_device_value( + DeviceValueTAG::TAG_DEVICE_DATA_WW, &wwWhenModeOff_, DeviceValueType::BOOL, nullptr, FL_(wwWhenModeOff), DeviceValueUOM::NONE, MAKE_CF_CB(set_wwwhenmodeoff)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwDisinfecting_, + DeviceValueType::BOOL, + nullptr, + FL_(wwDisinfecting), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwDisinfect)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwDisinfectDay_, + DeviceValueType::ENUM, + FL_(enum_dayOfWeek), + FL_(wwDisinfectDay), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwDisinfectDay)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW, + &wwDisinfectHour_, + DeviceValueType::UINT, + nullptr, + FL_(wwDisinfectHour), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_wwDisinfectHour), + 0, + 23); break; case EMS_DEVICE_FLAG_RC30_N: register_device_value(DeviceValueTAG::TAG_THERMOSTAT_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime @@ -3539,6 +3724,22 @@ void Thermostat::register_device_values_hc(std::shared_ptrmode, DeviceValueType::ENUM, FL_(enum_mode3), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); + register_device_value(tag, &hc->holiday, DeviceValueType::STRING, FL_(tpl_holidays), FL_(holidays), DeviceValueUOM::NONE, MAKE_CF_CB(set_holiday)); + register_device_value(tag, &hc->vacation, DeviceValueType::STRING, FL_(tpl_holidays), FL_(vacations), DeviceValueUOM::NONE, MAKE_CF_CB(set_vacation)); + register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode2), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program)); + register_device_value(tag, &hc->pause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); + register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); + register_device_value( + tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime), FL_(switchtime1), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); + register_device_value( + tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); + register_device_value( + tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode2), FL_(controlmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_controlmode)); + register_device_value(tag, &hc->holidaytemp, DeviceValueType::UINT, FL_(div2), FL_(holidaytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_holidaytemp)); + register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp2), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value(tag, &hc->daylowtemp, DeviceValueType::UINT, FL_(div2), FL_(daylowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daylowtemp)); + register_device_value(tag, &hc->daymidtemp, DeviceValueType::UINT, FL_(div2), FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); + register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); break; case EMS_DEVICE_FLAG_RC30_N: case EMS_DEVICE_FLAG_RC35: diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 4c0a42b6c..b72e2f97f 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -215,6 +215,7 @@ class Thermostat : public EMSdevice { char wwCircSwitchTime_[16]; uint8_t wwDailyHeating_; uint8_t wwDailyHeatTime_; + uint8_t wwWhenModeOff_; std::vector> heating_circuits_; // each thermostat can have multiple heating circuits @@ -243,6 +244,11 @@ class Thermostat : public EMSdevice { static constexpr uint8_t EMS_OFFSET_RC30StatusMessage_curr = 2; // current temp static constexpr uint8_t EMS_OFFSET_RC30Set_mode = 23; // position of thermostat mode static constexpr uint8_t EMS_OFFSET_RC30Set_temp = 28; // position of thermostat setpoint temperature + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_night = 3; // position of thermostat setpoint temperature for night time (T1) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_daylow = 4; // position of thermostat setpoint temperature for daylow time (T2) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_daymid = 5; // position of thermostat setpoint temperature for daymid time (T3) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_day = 6; // position of thermostat setpoint temperature for day time (T4) + static constexpr uint8_t EMS_OFFSET_RC30Temp_temp_holiday = 7; // temp during holiday mode static constexpr uint8_t EMS_OFFSET_RC35StatusMessage_setpoint = 2; // desired temp static constexpr uint8_t EMS_OFFSET_RC35StatusMessage_curr = 3; // current temp @@ -300,10 +306,11 @@ class Thermostat : public EMSdevice { static constexpr uint8_t AUTO_HEATING_CIRCUIT = 0; // Installation settings - static constexpr uint8_t EMS_TYPE_IBASettings = 0xA5; // installation settings - static constexpr uint8_t EMS_TYPE_RC30Settings = 0xA7; // RC30 settings - static constexpr uint8_t EMS_TYPE_wwSettings = 0x37; // ww settings - static constexpr uint8_t EMS_TYPE_time = 0x06; // time + static constexpr uint8_t EMS_TYPE_IBASettings = 0xA5; // installation settings + static constexpr uint8_t EMS_TYPE_RC30Settings = 0xA7; // RC30 settings + static constexpr uint8_t EMS_TYPE_wwSettings = 0x37; // ww settings + static constexpr uint8_t EMS_TYPE_RC30wwSettings = 0x3A; // RC30 ww settings + static constexpr uint8_t EMS_TYPE_time = 0x06; // time std::shared_ptr heating_circuit(std::shared_ptr telegram); std::shared_ptr heating_circuit(const uint8_t hc_num); @@ -324,6 +331,9 @@ class Thermostat : public EMSdevice { void process_RC35Timer(std::shared_ptr telegram); void process_RC30Monitor(std::shared_ptr telegram); void process_RC30Set(std::shared_ptr telegram); + void process_RC30Temp(std::shared_ptr telegram); + void process_RC30wwSettings(std::shared_ptr telegram); + void process_RC30Timer(std::shared_ptr telegram); void process_RC20Monitor(std::shared_ptr telegram); void process_RC20Set(std::shared_ptr telegram); void process_RC20Temp(std::shared_ptr telegram); @@ -423,6 +433,7 @@ class Thermostat : public EMSdevice { bool set_wwCircSwitchTime(const char * value, const int8_t id); bool set_wwDailyHeating(const char * value, const int8_t id); bool set_wwDailyHeatTime(const char * value, const int8_t id); + bool set_wwwhenmodeoff(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/locale_DE.h b/src/locale_DE.h index 894d55274..05e8d83f0 100644 --- a/src/locale_DE.h +++ b/src/locale_DE.h @@ -600,6 +600,7 @@ MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("Kreis 1 Extra")) MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("Kreis 2 Extra")) MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) +MAKE_PSTR_LIST(wwWhenModeOff, F("wwwhenmodeoff"), F("wenn Thermostatmodus ist aus")) // thermostat hc MAKE_PSTR_LIST(climate, F("climate")) MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("Sollwert Raumtemperatur")) @@ -613,6 +614,7 @@ MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("Tagestemperatur T3")) MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("Tagestemperatur T4")) MAKE_PSTR_LIST(heattemp, F("heattemp"), F("Heizen Temperatur")) MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("Nachttemperatur")) +MAKE_PSTR_LIST(nighttemp2, F("nighttemp2"), F("Nachttemperatur T1")) MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco Temperatur")) MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manuelle Temperatur")) MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("zwischenzeitliche Solltemperatur")) diff --git a/src/locale_EN.h b/src/locale_EN.h index c1b14c3a2..d1fdc828c 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -590,6 +590,7 @@ MAKE_PSTR_LIST(wwExtra1, F("wwextra1"), F("circuit 1 extra")) MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra")) MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) +MAKE_PSTR_LIST(wwWhenModeOff, F("wwwhenmodeoff"), F("when thermostat mode off")) // thermostat hc MAKE_PSTR_LIST(climate, F("climate")) MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature")) @@ -603,6 +604,7 @@ MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("day temperature T3")) MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("day temperature T4")) MAKE_PSTR_LIST(heattemp, F("heattemp"), F("heat temperature")) MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("night temperature")) +MAKE_PSTR_LIST(nighttemp2, F("nighttemp2"), F("night temperature T1")) MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco temperature")) MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manual temperature")) MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("temporary set temperature automode")) From f23bf270d0f5bf0291212ad7936137421c8e9b33 Mon Sep 17 00:00:00 2001 From: kwertie01 <48419274+kwertie01@users.noreply.github.com> Date: Mon, 11 Apr 2022 11:57:42 +0200 Subject: [PATCH 05/10] fix wrong offset in set_party --- src/devices/thermostat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 05190370a..1e624462a 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -1970,7 +1970,7 @@ bool Thermostat::set_party(const char * value, const int8_t id) { } if (value == nullptr) { - read_command(timer_typeids[hc->hc()], 85, 1); + read_command(timer_typeids[hc->hc()], 86, 1); return true; } From 7bad5d10d8ca1d4305ad8350088b2870d95bd938 Mon Sep 17 00:00:00 2001 From: kwertie01 <48419274+kwertie01@users.noreply.github.com> Date: Mon, 11 Apr 2022 11:59:29 +0200 Subject: [PATCH 06/10] fix sunday in dayofweek enum --- src/locale_EN.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale_EN.h b/src/locale_EN.h index d1fdc828c..bc43d7857 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -382,7 +382,7 @@ MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x)) MAKE_PSTR_LIST(enum_j_control, F_(off), F("fb10"), F("fb100")) MAKE_PSTR_LIST(enum_wwProgMode, F("std_prog"), F_(own_prog)) -MAKE_PSTR_LIST(enum_dayOfWeek, F("mo"), F("tu"), F("we"), F("th"), F("fr"), F("sa"), F("so"), F("all")) +MAKE_PSTR_LIST(enum_dayOfWeek, F("mo"), F("tu"), F("we"), F("th"), F("fr"), F("sa"), F("su"), F("all")) MAKE_PSTR_LIST(enum_progMode, F("prog_1"), F("prog_2")) MAKE_PSTR_LIST(enum_progMode2, F("own_1"), F("family"), F("morning"), F("evening"), F("am"), F("pm"), F("midday"), F("singles"), F("seniors"), F("new"), F("own_2")) MAKE_PSTR_LIST(enum_progMode3, F("family"), F("morning"), F("evening"), F("am"), F("pm"), F("midday"), F("singles"), F("seniors")) From 9ed2a99f50650d12fcc645b0c78988b99e38a5de Mon Sep 17 00:00:00 2001 From: Friso <48419274+kwertie01@users.noreply.github.com> Date: Tue, 12 Apr 2022 07:00:41 +0200 Subject: [PATCH 07/10] fix duplicate functions after rebase --- src/devices/thermostat.cpp | 81 -------------------------------------- 1 file changed, 81 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index dac15dc07..1e624462a 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -1155,87 +1155,6 @@ void Thermostat::process_RC30Timer(std::shared_ptr telegram) { } } -// type 0x40 (HC1) - for reading the operating mode from the RC30 thermostat (0x10) -void Thermostat::process_RC30Temp(std::shared_ptr telegram) { - // check to see we have a valid type. heating: 1 radiator, 2 convectors, 3 floors - if (telegram->offset == 0 && telegram->message_data[0] == 0x00) { - return; - } - - std::shared_ptr hc = heating_circuit(telegram); - if (hc == nullptr) { - return; - } - - has_update(telegram, hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor - has_update(telegram, hc->controlmode, 1); // 0-outdoortemp, 1-roomtemp - has_update(telegram, hc->nighttemp, 3); // is * 2 (T1) - has_update(telegram, hc->daylowtemp, 4); // is * 2 (T2) - has_update(telegram, hc->daymidtemp, 5); // is * 2 (T3) - has_update(telegram, hc->daytemp, 6); // is * 2 (T4) - has_update(telegram, hc->holidaytemp, 7); // is * 2 - -} - -// type 0x3F (HC1) - timer setting for RC30 -void Thermostat::process_RC30Timer(std::shared_ptr telegram) { - std::shared_ptr hc = heating_circuit(telegram); - if (hc == nullptr) { - return; - } - - if ((telegram->message_length == 2 && telegram->offset < 83 && !(telegram->offset & 1)) - || (!telegram->offset && telegram->message_length > 1 && !strlen(hc->switchtime1))) { - - char data[sizeof(hc->switchtime1)]; - uint8_t no = telegram->offset / 2; - uint8_t day = telegram->message_data[0] >> 5; - uint8_t temp = telegram->message_data[0] & 7; - uint8_t time = telegram->message_data[1]; - - std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); - if (day == 7) { - snprintf(data, sizeof(data), "%02d not_set", no); - } else { - snprintf(data, sizeof(data), "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), temp); - } - strlcpy(hc->switchtime1, data, sizeof(hc->switchtime1)); - has_update(hc->switchtime1); // always publish - } - - has_update(telegram, hc->program, 84); // 0 .. 10, 0-userprogram 1, 10-userprogram 2 - has_update(telegram, hc->pause, 85); // time in hours - has_update(telegram, hc->party, 86); // time in hours - - if (telegram->message_length + telegram->offset >= 92 && telegram->offset <= 87) { - char data[sizeof(hc->vacation)]; - snprintf(data, - sizeof(data), - "%02d.%02d.%04d-%02d.%02d.%04d", - telegram->message_data[87 - telegram->offset], - telegram->message_data[88 - telegram->offset], - telegram->message_data[89 - telegram->offset] + 2000, - telegram->message_data[90 - telegram->offset], - telegram->message_data[91 - telegram->offset], - telegram->message_data[92 - telegram->offset] + 2000); - has_update(hc->vacation, data, sizeof(hc->vacation)); - } - - if (telegram->message_length + telegram->offset >= 98 && telegram->offset <= 93) { - char data[sizeof(hc->holiday)]; - snprintf(data, - sizeof(data), - "%02d.%02d.%04d-%02d.%02d.%04d", - telegram->message_data[93 - telegram->offset], - telegram->message_data[94 - telegram->offset], - telegram->message_data[95 - telegram->offset] + 2000, - telegram->message_data[96 - telegram->offset], - telegram->message_data[97 - telegram->offset], - telegram->message_data[98 - telegram->offset] + 2000); - has_update(hc->holiday, data, sizeof(hc->holiday)); - } -} - // type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes void Thermostat::process_RC35Monitor(std::shared_ptr telegram) { // exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature From b59ef15cae15a896ba410b607c9fe6faca61e4e0 Mon Sep 17 00:00:00 2001 From: Friso <48419274+kwertie01@users.noreply.github.com> Date: Wed, 13 Apr 2022 09:17:22 +0200 Subject: [PATCH 08/10] fixed set_switchtemp, process_RC20Timer --- src/devices/thermostat.cpp | 12 ++++++++---- src/locale_DE.h | 3 ++- src/locale_EN.h | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 1e624462a..36c220100 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -629,7 +629,7 @@ void Thermostat::process_RC20Timer(std::shared_ptr telegram) { char data[sizeof(hc->switchtime1)]; uint8_t no = telegram->offset / 2; uint8_t day = telegram->message_data[0] >> 5; - uint8_t temp = telegram->message_data[0] & 1; + uint8_t temp = telegram->message_data[0] & 7; uint8_t time = telegram->message_data[1]; std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); @@ -2480,6 +2480,8 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char } if (strlen(value) > 13 && value[12] == 'o') { on = value[13] == 'n' ? 1 : 0; + } else if (strlen(value) == 14 && value[12] == 'T') { + on = value[13] - '0'; } else if (strlen(value) == 13) { on = value[12] - '0'; } @@ -2499,6 +2501,8 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char uint8_t max_on = 3; if ((model() == EMS_DEVICE_FLAG_RC35) || (model() == EMS_DEVICE_FLAG_RC30_N)) { max_on = 1; + } else if (model() == EMS_DEVICE_FLAG_RC30) { + max_on = 4; } if (no > 41 || time > 0x90 || (on > max_on && on != 7)) { // LOG_WARNING(F("Setting switchtime: Invalid data: %s"), value); @@ -2509,7 +2513,7 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char std::string sday = read_flash_string(FL_(enum_dayOfWeek)[day]); if ((model() == EMS_DEVICE_FLAG_RC35) || (model() == EMS_DEVICE_FLAG_RC30_N)) { snprintf(out, len, "%02d %s %02d:%02d %s", no, sday.c_str(), time / 6, 10 * (time % 6), on ? "on" : "off"); - } else if (model() == EMS_DEVICE_FLAG_RC20) { + } else if ((model() == EMS_DEVICE_FLAG_RC20) || (model() == EMS_DEVICE_FLAG_RC30)){ snprintf(out, len, "%02d %s %02d:%02d T%d", no, sday.c_str(), time / 6, 10 * (time % 6), on); } else { std::string son = read_flash_string(FL_(enum_switchmode)[on]); @@ -3691,7 +3695,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrdaymidtemp, DeviceValueType::UINT, FL_(div2), FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); - register_device_value(tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime), FL_(switchtime), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); + register_device_value(tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime1), FL_(switchtime), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); break; case EMS_DEVICE_FLAG_RC20_N: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); @@ -3730,7 +3734,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrpause, DeviceValueType::UINT, nullptr, FL_(pause), DeviceValueUOM::HOURS, MAKE_CF_CB(set_pause)); register_device_value(tag, &hc->party, DeviceValueType::UINT, nullptr, FL_(party), DeviceValueUOM::HOURS, MAKE_CF_CB(set_party)); register_device_value( - tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime), FL_(switchtime1), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); + tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime1), FL_(switchtime1), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); register_device_value( tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); register_device_value( diff --git a/src/locale_DE.h b/src/locale_DE.h index 05e8d83f0..f7a41d1bd 100644 --- a/src/locale_DE.h +++ b/src/locale_DE.h @@ -335,6 +335,7 @@ MAKE_PSTR(smoke_temperature, "Abgastemperatur") // thermostat lists MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-dw-dst >")) MAKE_PSTR_LIST(tpl_switchtime, F("Format: < nn.d.o.hh:mm >")) +MAKE_PSTR_LIST(tpl_switchtime1, F("Format: [ not_set | day hh:mm Tn ]")) MAKE_PSTR_LIST(tpl_holidays, F("Format: < dd.mm.yyyy-dd.mm.yyyy >")) MAKE_PSTR_LIST(enum_ibaMainDisplay, F_(internal_temperature), @@ -614,7 +615,7 @@ MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("Tagestemperatur T3")) MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("Tagestemperatur T4")) MAKE_PSTR_LIST(heattemp, F("heattemp"), F("Heizen Temperatur")) MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("Nachttemperatur")) -MAKE_PSTR_LIST(nighttemp2, F("nighttemp2"), F("Nachttemperatur T1")) +MAKE_PSTR_LIST(nighttemp2, F("nighttemp"), F("Nachttemperatur T1")) MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco Temperatur")) MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manuelle Temperatur")) MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("zwischenzeitliche Solltemperatur")) diff --git a/src/locale_EN.h b/src/locale_EN.h index bc43d7857..c2ed561d4 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -335,6 +335,7 @@ MAKE_PSTR(smoke_temperature, "smoke temperature") // thermostat lists MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-dw-dst >")) MAKE_PSTR_LIST(tpl_switchtime, F("Format: [ not_set | day hh:mm on|off ]")) +MAKE_PSTR_LIST(tpl_switchtime1, F("Format: [ not_set | day hh:mm Tn ]")) MAKE_PSTR_LIST(tpl_holidays, F("format: < dd.mm.yyyy-dd.mm.yyyy >")) MAKE_PSTR_LIST(enum_ibaMainDisplay, F_(internal_temperature), @@ -604,7 +605,7 @@ MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("day temperature T3")) MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("day temperature T4")) MAKE_PSTR_LIST(heattemp, F("heattemp"), F("heat temperature")) MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("night temperature")) -MAKE_PSTR_LIST(nighttemp2, F("nighttemp2"), F("night temperature T1")) +MAKE_PSTR_LIST(nighttemp2, F("nighttemp"), F("night temperature T1")) MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco temperature")) MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manual temperature")) MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("temporary set temperature automode")) From 258db5c7e8d66903497160f8fc4217b5399f2685 Mon Sep 17 00:00:00 2001 From: Friso <48419274+kwertie01@users.noreply.github.com> Date: Wed, 13 Apr 2022 11:09:31 +0200 Subject: [PATCH 09/10] disable usage of T0 for RC30 in set_switchtime --- src/devices/thermostat.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 36c220100..d3b2c8bcf 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -2498,13 +2498,15 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char data[1] = time; } + uint8_t min_on = 0; uint8_t max_on = 3; if ((model() == EMS_DEVICE_FLAG_RC35) || (model() == EMS_DEVICE_FLAG_RC30_N)) { max_on = 1; } else if (model() == EMS_DEVICE_FLAG_RC30) { + min_on = 1; max_on = 4; } - if (no > 41 || time > 0x90 || (on > max_on && on != 7)) { + if (no > 41 || time > 0x90 || ((on < min_on || on > max_on) && on != 7)) { // LOG_WARNING(F("Setting switchtime: Invalid data: %s"), value); // LOG_WARNING(F("Setting switchtime: Invalid data: %02d.%1d.0x%02X.%1d"), no, day, time, on); return false; From 4cdeef212d02f0cdda9e6369870c4047733ea8a8 Mon Sep 17 00:00:00 2001 From: Friso <48419274+kwertie01@users.noreply.github.com> Date: Wed, 13 Apr 2022 11:18:28 +0200 Subject: [PATCH 10/10] fixed T1 to T4 for RC20 --- src/devices/thermostat.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index d3b2c8bcf..3c56635be 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -2498,13 +2498,11 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char data[1] = time; } - uint8_t min_on = 0; - uint8_t max_on = 3; + uint8_t min_on = 1; + uint8_t max_on = 4; if ((model() == EMS_DEVICE_FLAG_RC35) || (model() == EMS_DEVICE_FLAG_RC30_N)) { + min_on = 0; max_on = 1; - } else if (model() == EMS_DEVICE_FLAG_RC30) { - min_on = 1; - max_on = 4; } if (no > 41 || time > 0x90 || ((on < min_on || on > max_on) && on != 7)) { // LOG_WARNING(F("Setting switchtime: Invalid data: %s"), value); @@ -3696,7 +3694,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrdaylowtemp, DeviceValueType::UINT, FL_(div2), FL_(daylowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daylowtemp)); register_device_value(tag, &hc->daymidtemp, DeviceValueType::UINT, FL_(div2), FL_(daymidtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daymidtemp)); register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), FL_(dayhightemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), FL_(nighttemp2), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); register_device_value(tag, &hc->switchtime1, DeviceValueType::STRING, FL_(tpl_switchtime1), FL_(switchtime), DeviceValueUOM::NONE, MAKE_CF_CB(set_switchtime1)); break; case EMS_DEVICE_FLAG_RC20_N: