Merge pull request #532 from MichaelDvP/dev

render and parse multible text parameters, add thermostat wwmode
This commit is contained in:
Proddy
2020-10-03 21:28:45 +02:00
committed by GitHub
5 changed files with 426 additions and 127 deletions

View File

@@ -1028,6 +1028,7 @@ void Boiler::process_UBAMaintenanceData(std::shared_ptr<const Telegram> 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);
}

View File

@@ -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<const Telegram> t) { process_RC300Set(t); });
register_telegram_type(summer_typeids[i], F("RC300Summer"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Summer(t); });
}
register_telegram_type(0x31D, F("RC300WWmode"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode(t); });
register_telegram_type(0x31E, F("RC300WWmode"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode(t); });
register_telegram_type(0x2F5, F("RC300WWmode"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode(t); });
register_telegram_type(0x31B, F("RC300WWtemp"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWtemp(t); });
register_telegram_type(0x31D, F("RC300WWmode2"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode2(t); });
register_telegram_type(0x31E, F("RC300WWmode2"), false, [&](std::shared_ptr<const Telegram> 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<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
@@ -1129,11 +1365,25 @@ void Thermostat::process_RC300Summer(std::shared_ptr<const Telegram> telegram) {
changed_ |= telegram->read_value(hc->summer_setmode, 7);
}
// types 0x31D and 0x31E
// types 0x31B (and 0x31C?)
void Thermostat::process_RC300WWtemp(std::shared_ptr<const Telegram> telegram) {
changed_ |= telegram->read_value(wwTemp_, 0);
changed_ |= telegram->read_value(wwTempLow_, 1);
}
// type 02F5
void Thermostat::process_RC300WWmode(std::shared_ptr<const Telegram> 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<const Telegram> 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<const Telegram> 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<Thermostat::HeatingCircuit> 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<Thermostat::HeatingCircuit> 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<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) {
LOG_WARNING(F("Set 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<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) {
LOG_WARNING(F("Set 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<Thermostat::HeatingCircuit> 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); });

View File

@@ -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<std::shared_ptr<HeatingCircuit>> heating_circuits_; // each thermostat can have multiple heating circuits
@@ -246,6 +248,8 @@ class Thermostat : public EMSdevice {
void process_RC300Set(std::shared_ptr<const Telegram> telegram);
void process_RC300Summer(std::shared_ptr<const Telegram> telegram);
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
void process_RC300WWmode2(std::shared_ptr<const Telegram> telegram);
void process_RC300WWtemp(std::shared_ptr<const Telegram> telegram);
void process_JunkersMonitor(std::shared_ptr<const Telegram> telegram);
void process_JunkersSet(std::shared_ptr<const Telegram> telegram);
void process_JunkersSet2(std::shared_ptr<const Telegram> telegram);
@@ -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);

View File

@@ -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<std::string> 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<std::string> 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

View File

@@ -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<std::string> 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<std::string> strs);
private:
static uint8_t bool_format_;
};