From 2d2e9398560171956f057487fe4c3e64c63543a6 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Tue, 29 Sep 2020 14:36:49 +0200 Subject: [PATCH] add enable ADC, add boiler circulation commands, add thermostat RC300 summermodes --- .../src/project/EMSESPSettingsController.tsx | 15 ++ interface/src/project/EMSESPtypes.ts | 1 + src/EMSESPSettingsService.cpp | 2 + src/EMSESPSettingsService.h | 2 + src/devices/boiler.cpp | 73 ++++++--- src/devices/boiler.h | 5 +- src/devices/thermostat.cpp | 141 +++++++++++++++--- src/devices/thermostat.h | 14 +- src/emsdevice.h | 2 +- src/helpers.h | 2 +- src/system.cpp | 34 +++-- src/system.h | 3 +- 12 files changed, 240 insertions(+), 54 deletions(-) diff --git a/interface/src/project/EMSESPSettingsController.tsx b/interface/src/project/EMSESPSettingsController.tsx index b633ff984..11533b0d1 100644 --- a/interface/src/project/EMSESPSettingsController.tsx +++ b/interface/src/project/EMSESPSettingsController.tsx @@ -247,6 +247,21 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps) onChange={handleValueChange('syslog_mark_interval')} margin="normal" /> +

+ + Analog input + + + } + label="Enable ADC" + /> +

} variant="contained" color="primary" type="submit"> Save diff --git a/interface/src/project/EMSESPtypes.ts b/interface/src/project/EMSESPtypes.ts index f3d58086c..39b1fcae4 100644 --- a/interface/src/project/EMSESPtypes.ts +++ b/interface/src/project/EMSESPtypes.ts @@ -15,6 +15,7 @@ export interface EMSESPSettings { hide_led: boolean; api_enabled: boolean; bool_format: number; + analog_enabled: boolean; } export enum busConnectionStatus { diff --git a/src/EMSESPSettingsService.cpp b/src/EMSESPSettingsService.cpp index ae6ed3248..3441b4f11 100644 --- a/src/EMSESPSettingsService.cpp +++ b/src/EMSESPSettingsService.cpp @@ -44,6 +44,7 @@ void EMSESPSettings::read(EMSESPSettings & settings, JsonObject & root) { root["hide_led"] = settings.hide_led; root["api_enabled"] = settings.api_enabled; root["bool_format"] = settings.bool_format; + root["analog_enabled"] = settings.analog_enabled; } StateUpdateResult EMSESPSettings::update(JsonObject & root, EMSESPSettings & settings) { @@ -63,6 +64,7 @@ StateUpdateResult EMSESPSettings::update(JsonObject & root, EMSESPSettings & set settings.hide_led = root["hide_led"] | EMSESP_DEFAULT_HIDE_LED; settings.api_enabled = root["api_enabled"] | EMSESP_DEFAULT_API_ENABLED; settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT; + settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED; return StateUpdateResult::CHANGED; } diff --git a/src/EMSESPSettingsService.h b/src/EMSESPSettingsService.h index 6e200260e..4fd819903 100644 --- a/src/EMSESPSettingsService.h +++ b/src/EMSESPSettingsService.h @@ -37,6 +37,7 @@ #define EMSESP_DEFAULT_DALLAS_PARASITE false #define EMSESP_DEFAULT_API_ENABLED true #define EMSESP_DEFAULT_BOOL_FORMAT 1 // on/off +#define EMSESP_DEFAULT_ANALOG_ENABLED false // Default GPIO PIN definitions #if defined(ESP8266) @@ -77,6 +78,7 @@ class EMSESPSettings { bool hide_led; bool api_enabled; uint8_t bool_format; + bool analog_enabled; static void read(EMSESPSettings & settings, JsonObject & root); static StateUpdateResult update(JsonObject & root, EMSESPSettings & settings); diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index ae42ade1d..ea513c0e9 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -33,17 +33,17 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const // the telegram handlers... register_telegram_type(0x10, F("UBAErrorMessage1"), false, [&](std::shared_ptr t) { process_UBAErrorMessage(t); }); register_telegram_type(0x11, F("UBAErrorMessage2"), false, [&](std::shared_ptr t) { process_UBAErrorMessage(t); }); + register_telegram_type(0x14, F("UBATotalUptime"), true, [&](std::shared_ptr t) { process_UBATotalUptime(t); }); + register_telegram_type(0x15, F("UBAMaintenanceData"), false, [&](std::shared_ptr t) { process_UBAMaintenanceData(t); }); + register_telegram_type(0x16, F("UBAParameters"), true, [&](std::shared_ptr t) { process_UBAParameters(t); }); register_telegram_type(0x18, F("UBAMonitorFast"), false, [&](std::shared_ptr t) { process_UBAMonitorFast(t); }); register_telegram_type(0x19, F("UBAMonitorSlow"), true, [&](std::shared_ptr t) { process_UBAMonitorSlow(t); }); - register_telegram_type(0x34, F("UBAMonitorWW"), false, [&](std::shared_ptr t) { process_UBAMonitorWW(t); }); + register_telegram_type(0x1A, F("UBASetPoints"), false, [&](std::shared_ptr t) { process_UBASetPoints(t); }); register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, [&](std::shared_ptr t) { process_UBAMaintenanceStatus(t); }); register_telegram_type(0x2A, F("MC10Status"), false, [&](std::shared_ptr t) { process_MC10Status(t); }); register_telegram_type(0x33, F("UBAParameterWW"), true, [&](std::shared_ptr t) { process_UBAParameterWW(t); }); - register_telegram_type(0x14, F("UBATotalUptime"), true, [&](std::shared_ptr t) { process_UBATotalUptime(t); }); + register_telegram_type(0x34, F("UBAMonitorWW"), false, [&](std::shared_ptr t) { process_UBAMonitorWW(t); }); register_telegram_type(0x35, F("UBAFlags"), false, [&](std::shared_ptr t) { process_UBAFlags(t); }); - register_telegram_type(0x15, F("UBAMaintenanceData"), false, [&](std::shared_ptr t) { process_UBAMaintenanceData(t); }); - register_telegram_type(0x16, F("UBAParameters"), true, [&](std::shared_ptr t) { process_UBAParameters(t); }); - register_telegram_type(0x1A, F("UBASetPoints"), false, [&](std::shared_ptr t) { process_UBASetPoints(t); }); register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, [&](std::shared_ptr t) { process_UBAOutdoorTemp(t); }); register_telegram_type(0xE3, F("UBAMonitorSlowPlus"), false, [&](std::shared_ptr t) { process_UBAMonitorSlowPlus2(t); }); register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, [&](std::shared_ptr t) { process_UBAMonitorFastPlus(t); }); @@ -57,7 +57,9 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_mqtt_cmd(F("wwactivated"), [&](const char * value, const int8_t id) { return set_warmwater_activated(value, id); }); register_mqtt_cmd(F("wwtapactivated"), [&](const char * value, const int8_t id) { return set_tapwarmwater_activated(value, id); }); register_mqtt_cmd(F("wwonetime"), [&](const char * value, const int8_t id) { return set_warmwater_onetime(value, id); }); + register_mqtt_cmd(F("wwcircpump"), [&](const char * value, const int8_t id) { return set_warmwater_circulation_pump(value, id); }); register_mqtt_cmd(F("wwcirculation"), [&](const char * value, const int8_t id) { return set_warmwater_circulation(value, id); }); + register_mqtt_cmd(F("wwcircmode"), [&](const char * value, const int8_t id) { return set_warmwater_circulation_mode(value, id); }); register_mqtt_cmd(F("flowtemp"), [&](const char * value, const int8_t id) { return set_flow_temp(value, id); }); register_mqtt_cmd(F("wwtemp"), [&](const char * value, const int8_t id) { return set_warmwater_temp(value, id); }); register_mqtt_cmd(F("heatingactivated"), [&](const char * value, const int8_t id) { return set_heating_activated(value, id); }); @@ -237,8 +239,8 @@ bool Boiler::export_values(JsonObject & output) { if (Helpers::hasValue(wWDisinfecting_, EMS_VALUE_BOOL)) { output["wWDisinfecting"] = Helpers::render_value(s, wWDisinfecting_, EMS_VALUE_BOOL); } - if (Helpers::hasValue(wWReadiness_, EMS_VALUE_BOOL)) { - output["wWReady"] = Helpers::render_value(s, wWReadiness_, EMS_VALUE_BOOL); + if (Helpers::hasValue(wWCharging_, EMS_VALUE_BOOL)) { + output["wWCharge"] = Helpers::render_value(s, wWCharging_, EMS_VALUE_BOOL); } if (Helpers::hasValue(wWRecharging_, EMS_VALUE_BOOL)) { output["wWRecharge"] = Helpers::render_value(s, wWRecharging_, EMS_VALUE_BOOL); @@ -246,8 +248,8 @@ bool Boiler::export_values(JsonObject & output) { if (Helpers::hasValue(wWTemperatureOK_, EMS_VALUE_BOOL)) { output["wWTempOK"] = Helpers::render_value(s, wWTemperatureOK_, EMS_VALUE_BOOL); } - if (Helpers::hasValue(wWCirc_, EMS_VALUE_BOOL)) { - output["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL); + if (Helpers::hasValue(wWActive_, EMS_VALUE_BOOL)) { + output["wWActive"] = Helpers::render_value(s, wWActive_, EMS_VALUE_BOOL); } if (Helpers::hasValue(burnGas_, EMS_VALUE_BOOL)) { output["burnGas"] = Helpers::render_value(s, burnGas_, EMS_VALUE_BOOL); @@ -480,14 +482,14 @@ void Boiler::show_values(uuid::console::Shell & shell) { */ void Boiler::check_active() { if ((boilerState_ & 0x09) != (last_boilerState & 0x09)) { - char s[5]; + char s[7]; bool b = ((boilerState_ & 0x09) == 0x09); Mqtt::publish(F("heating_active"), Helpers::render_boolean(s, b)); heating_active_ = b ? EMS_VALUE_BOOL_ON : EMS_VALUE_BOOL_OFF; } if ((boilerState_ & 0x0A) != (last_boilerState & 0x0A)) { - char s[5]; + char s[7]; bool b = ((boilerState_ & 0x0A) == 0x0A); Mqtt::publish(F("tapwater_active"), Helpers::render_boolean(s, b)); tap_water_active_ = b ? EMS_VALUE_BOOL_ON : EMS_VALUE_BOOL_OFF; @@ -497,7 +499,6 @@ void Boiler::check_active() { last_boilerState = boilerState_; /* - // hot tap water, using flow to check instead of the burner power // send these values back to the main EMSESP, so other classes (e.g. Shower) can use it if (Helpers::hasValue(wWCurFlow_) && Helpers::hasValue(burnGas_) && (wWType_ > 0) && (wWType_ < 3)) { @@ -613,9 +614,10 @@ void Boiler::process_UBAMonitorWW(std::shared_ptr telegram) { changed_ |= telegram->read_bitvalue(wWOneTime_, 5, 1); changed_ |= telegram->read_bitvalue(wWDisinfecting_, 5, 2); - changed_ |= telegram->read_bitvalue(wWReadiness_, 5, 3); + changed_ |= telegram->read_bitvalue(wWCharging_, 5, 3); changed_ |= telegram->read_bitvalue(wWRecharging_, 5, 4); changed_ |= telegram->read_bitvalue(wWTemperatureOK_, 5, 5); + changed_ |= telegram->read_bitvalue(wWActive_, 5, 6); } /* @@ -715,7 +717,7 @@ void Boiler::process_UBADHWStatus(std::shared_ptr telegram) { changed_ |= telegram->read_bitvalue(wWOneTime_, 12, 2); changed_ |= telegram->read_bitvalue(wWDisinfecting_, 12, 3); - changed_ |= telegram->read_bitvalue(wWReadiness_, 12, 4); + changed_ |= telegram->read_bitvalue(wWCharging_, 12, 4); changed_ |= telegram->read_bitvalue(wWRecharging_, 13, 4); changed_ |= telegram->read_bitvalue(wWTemperatureOK_, 13, 5); changed_ |= telegram->read_bitvalue(wWCircPump_, 13, 2); @@ -816,7 +818,7 @@ bool Boiler::set_heating_activated(const char * value, const int8_t id) { return false; } - LOG_INFO(F("Setting boiler heating "), v ? "on" : "off"); + LOG_INFO(F("Setting boiler heating %s"), v ? "on" : "off"); if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) { write_command(EMS_TYPE_UBAParametersPlus, 0, v ? 0x01 : 0, EMS_TYPE_UBAParametersPlus); } else { @@ -992,7 +994,7 @@ bool Boiler::set_warmwater_activated(const char * value, const int8_t id) { if (get_toggle_fetch(EMS_TYPE_UBAParameterWWPlus)) { write_command(EMS_TYPE_UBAParameterWWPlus, 1, v ? 1 : 0, EMS_TYPE_UBAParameterWWPlus); } else { - write_command(EMS_TYPE_UBAParameterWW, 1, n, EMS_TYPE_UBAParameterWW); + write_command(EMS_TYPE_UBAParameterWW, 1, n, 0x34); } return true; @@ -1024,7 +1026,6 @@ bool Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) { } else { // get out of test mode. Send all zeros. // telegram: 0B 08 1D 00 00 - message_data[4] = 0x00; // test mode off } write_command(EMS_TYPE_UBAFunctionTest, 0, message_data, sizeof(message_data), 0); @@ -1069,4 +1070,42 @@ bool Boiler::set_warmwater_circulation(const char * value, const int8_t id) { return true; } +// configuration of warm water circulation pump +bool Boiler::set_warmwater_circulation_pump(const char * value, const int8_t id) { + bool v = false; + if (!Helpers::value2bool(value, v)) { + return false; + } + + LOG_INFO(F("Setting boiler warm water circulation %s"), v ? "on" : "off"); + + if (get_toggle_fetch(EMS_TYPE_UBAParameterWWPlus)) { + write_command(EMS_TYPE_UBAParameterWWPlus, 10, v ? 0x01 : 0x00, EMS_TYPE_UBAParameterWWPlus); + } else { + write_command(EMS_TYPE_UBAParameterWW, 6, v ? 0xFF : 0x00, EMS_TYPE_UBAParameterWW); + } + + return true; +} + +// Set the mode of circulation, 1x3min, ... 6x3min, continous +// true = on, false = off +bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id) { + int v = 0; + if (!Helpers::value2number(value, v)) { + return false; + } + + if (get_toggle_fetch(EMS_TYPE_UBAParameterWW)) { + if (v < 7) { + LOG_INFO(F("Setting circulation mode %dx3min"), v); + } else { + LOG_INFO(F("Setting circulation mode continous")); + } + write_command(EMS_TYPE_UBAParameterWW, 6, v, EMS_TYPE_UBAParameterWW); + } + + return true; +} + } // namespace emsesp diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 931e6ac1d..377667843 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -116,11 +116,12 @@ class Boiler : public EMSdevice { uint32_t wWWorkM_ = EMS_VALUE_ULONG_NOTSET; // Warm Water # minutes uint8_t wWOneTime_ = EMS_VALUE_BOOL_NOTSET; // Warm Water one time function on/off uint8_t wWDisinfecting_ = EMS_VALUE_BOOL_NOTSET; // Warm Water disinfection on/off - uint8_t wWReadiness_ = EMS_VALUE_BOOL_NOTSET; // Warm Water readiness on/off + uint8_t wWCharging_ = EMS_VALUE_BOOL_NOTSET; // Warm Water charging on/off uint8_t wWRecharging_ = EMS_VALUE_BOOL_NOTSET; // Warm Water recharge on/off uint8_t wWTemperatureOK_ = EMS_VALUE_BOOL_NOTSET; // Warm Water temperature ok on/off uint8_t wWCurFlow_ = EMS_VALUE_UINT_NOTSET; // Warm Water current flow temp in l/min uint8_t wWType_ = EMS_VALUE_UINT_NOTSET; // 0-off, 1-flow, 2-flowbuffer, 3-buffer, 4-layered buffer + uint8_t wWActive_ = EMS_VALUE_BOOL_NOTSET; // UBATotalUptime uint32_t UBAuptime_ = EMS_VALUE_ULONG_NOTSET; // Total UBA working hours @@ -175,6 +176,8 @@ class Boiler : public EMSdevice { bool set_tapwarmwater_activated(const char * value, const int8_t id); bool set_warmwater_onetime(const char * value, const int8_t id); bool set_warmwater_circulation(const char * value, const int8_t id); + bool set_warmwater_circulation_pump(const char * value, const int8_t id); + bool set_warmwater_circulation_mode(const char * value, const int8_t id); bool set_warmwater_temp(const char * value, const int8_t id); bool set_flow_temp(const char * value, const int8_t id); bool set_heating_activated(const char * value, const int8_t id); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index ac59f5288..3e8c966ae 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -112,9 +112,11 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i } else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC300) || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) { monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8}; set_typeids = {0x02B9, 0x02BA, 0x02BB, 0x02BC}; + summer_typeids = {0x02AF, 0x02B0, 0x02B1, 0x02B2}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, [&](std::shared_ptr t) { process_RC300Monitor(t); }); register_telegram_type(set_typeids[i], F("RC300Set"), false, [&](std::shared_ptr t) { process_RC300Set(t); }); + register_telegram_type(summer_typeids[i], F("RC300Summer"), false, [&](std::shared_ptr t) { process_RC300Summer(t); }); } register_telegram_type(0x31D, F("RC300WWmode"), false, [&](std::shared_ptr t) { process_RC300WWmode(t); }); register_telegram_type(0x31E, F("RC300WWmode"), false, [&](std::shared_ptr t) { process_RC300WWmode(t); }); @@ -288,12 +290,20 @@ bool Thermostat::export_values(uint8_t mqtt_format, JsonObject & rootThermostat) } } if (Helpers::hasValue(wwMode_)) { - if (wwMode_ == 0) { - rootThermostat["wwmode"] = "off"; - } else if (wwMode_ == 1) { - rootThermostat["wwmode"] = "on"; - } else if (wwMode_ == 2) { + if (wwMode_ == 2) { rootThermostat["wwmode"] = "auto"; + } else { + char s[7]; + rootThermostat["wwmode"] = Helpers::render_boolean(s, (wwMode_ == 1)); + } + } + + if (Helpers::hasValue(wwCircMode_)) { + if (wwCircMode_ == 2) { + rootThermostat["wwcircmode"] = "auto"; + } else { + char s[7]; + rootThermostat["wwcircmode"] = Helpers::render_boolean(s, (wwCircMode_ == 1)); } } @@ -388,10 +398,20 @@ bool Thermostat::export_values(uint8_t mqtt_format, JsonObject & rootThermostat) if (Helpers::hasValue(hc->designtemp)) { dataThermostat["designtemp"] = hc->designtemp; } + if (Helpers::hasValue(hc->summertemp)) { dataThermostat["summertemp"] = hc->summertemp; } + if (Helpers::hasValue(hc->summer_setmode)) { + if (hc->summer_setmode == 1) { + dataThermostat["summermode"] = "auto"; + } else { + char s[7]; + rootThermostat["summermode"] = Helpers::render_boolean(s, (hc->summer_setmode == 0)); + } + } + // mode - always force showing this when in HA so not to break HA's climate component if ((Helpers::hasValue(hc->mode)) || (mqtt_format == Mqtt::Format::HA)) { uint8_t hc_mode = hc->get_mode(flags); @@ -744,20 +764,29 @@ void Thermostat::show_values(uuid::console::Shell & shell) { print_value(shell, 2, F("Offset clock"), ibaClockOffset_, nullptr); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s } } + if (Helpers::hasValue(wwMode_)) { - if (wwMode_ == 0) { - shell.printfln(F(" Warm Water mode: off")); - } else if (wwMode_ == 1) { - shell.printfln(F(" Warm Water mode: on")); - } else if (wwMode_ == 2) { - shell.printfln(F(" Warm Water mode: auto")); + if (wwMode_ == 2) { + print_value(shell, 2, F("Warm Water mode"), F("auto")); + } else { + print_value(shell, 2, F("Warm Water mode"), wwMode_, nullptr, EMS_VALUE_BOOL); } } + + if (Helpers::hasValue(wwCircMode_)) { + if (wwCircMode_ == 2) { + print_value(shell, 2, F("Warm Water circulation mode"), F("auto")); + } else { + print_value(shell, 2, F("Warm Water circulation mode"), wwCircMode_, nullptr, EMS_VALUE_BOOL); + } + } + 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_)) { @@ -794,6 +823,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) { } } } + 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); @@ -887,6 +917,14 @@ void Thermostat::show_values(uuid::console::Shell & shell) { if (Helpers::hasValue(hc->summertemp)) { print_value(shell, 4, F("Summer temperature"), hc->summertemp, F_(degrees)); } + if (Helpers::hasValue(hc->summer_setmode)) { + if (hc->summer_setmode == 1) { + print_value(shell, 4, F("Summer mode"), F("auto")); + } else { + char s[7]; + print_value(shell, 4, F("Summer mode"), Helpers::render_boolean(s, (hc->summer_setmode == 0))); + } + } if (Helpers::hasValue(hc->targetflowtemp)) { print_value(shell, 4, F("Target flow temperature"), hc->targetflowtemp, F_(degrees)); } @@ -995,7 +1033,8 @@ void Thermostat::process_IBASettings(std::shared_ptr telegram) { // Settings WW 0x37 - RC35 void Thermostat::process_RC35wwSettings(std::shared_ptr telegram) { - changed_ |= telegram->read_value(wwMode_, 2); // 0 off, 1-on, 2-auto + changed_ |= telegram->read_value(wwMode_, 2); // 0 off, 1-on, 2-auto + changed_ |= telegram->read_value(wwCircMode_, 3); // 0 off, 1-on, 2-auto } // type 0x6F - FR10/FR50/FR100 Junkers @@ -1055,6 +1094,13 @@ void Thermostat::process_RC300Set(std::shared_ptr telegram) { changed_ |= telegram->read_value(hc->manualtemp, 10); // is * 2 } +// types 0x2AF ff +void Thermostat::process_RC300Summer(std::shared_ptr telegram) { + std::shared_ptr hc = heating_circuit(telegram); + changed_ |= telegram->read_value(hc->summertemp, 6); + changed_ |= telegram->read_value(hc->summer_setmode, 7); +} + // types 0x31D and 0x31E void Thermostat::process_RC300WWmode(std::shared_ptr telegram) { // 0x31D for WW system 1, 0x31E for WW system 2 @@ -1301,11 +1347,11 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) { } uint8_t set = 0xFF; // some dummy value - if (v == "off") { + if (v == "off" || v == "0" || v == "false") { set = 0; - } else if (v == "on") { + } else if (v == "on" || v == "1" || v == "true") { set = 1; - } else if (v == "auto") { + } else if (v == "auto" || v == "2") { set = 2; } @@ -1319,6 +1365,32 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) { 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)) { + 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 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()); + } + + return true; +} + // set the holiday as string dd.mm.yyyy-dd.mm.yyyy bool Thermostat::set_holiday(const char * value, const int8_t id) { std::string hd(30, '\0'); @@ -1569,6 +1641,32 @@ bool Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) { return true; } +bool Thermostat::set_summermode(const char * value, const int8_t id) { + uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; + std::shared_ptr hc = heating_circuit(hc_num); + std::string v(10, '\0'); + if (!Helpers::value2string(value, v)) { + 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 { + return false; + } + write_command(summer_typeids[hc->hc_num() - 1], 7, set, summer_typeids[hc->hc_num() - 1]); + return true; +} + + // sets the thermostat temp, where mode is a string bool Thermostat::set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num) { if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) { @@ -1626,6 +1724,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co int8_t offset = -1; // we use -1 to check if there is a value uint8_t factor = 2; // some temperatures only use 1 uint16_t validate_typeid = monitor_typeids[hc->hc_num() - 1]; + uint16_t set_typeid = set_typeids[hc->hc_num() - 1]; if (model == EMS_DEVICE_FLAG_RC10) { offset = EMS_OFFSET_RC10Set_temp; @@ -1639,6 +1738,11 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co } else if ((model == EMS_DEVICE_FLAG_RC300) || (model == EMS_DEVICE_FLAG_RC100)) { validate_typeid = set_typeids[hc->hc_num() - 1]; switch (mode) { + case HeatingCircuit::Mode::SUMMER: + offset = 0x06; + set_typeid = summer_typeids[hc->hc_num() - 1]; + validate_typeid = set_typeid; + break; case HeatingCircuit::Mode::MANUAL: offset = 0x0A; // manual offset break; @@ -1790,7 +1894,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co // add the write command to the Tx queue. value is *2 // post validate is the corresponding monitor or set type IDs as they can differ per model - write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), validate_typeid); + write_command(set_typeid, offset, (uint8_t)((float)temperature * (float)factor), validate_typeid); return true; } @@ -1868,7 +1972,6 @@ void Thermostat::add_commands() { } // common to all thermostats - register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { return set_wwmode(value, id); }); 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)) { @@ -1885,6 +1988,8 @@ void Thermostat::add_commands() { register_mqtt_cmd(F("manualtemp"), [&](const char * value, const int8_t id) { return set_manualtemp(value, id); }); register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { return set_ecotemp(value, id); }); 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); }); break; case EMS_DEVICE_FLAG_RC20_2: register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); }); @@ -1911,6 +2016,8 @@ void Thermostat::add_commands() { register_mqtt_cmd(F("designtemp"), [&](const char * value, const int8_t id) { return set_designtemp(value, id); }); register_mqtt_cmd(F("offsettemp"), [&](const char * value, const int8_t id) { return set_offsettemp(value, id); }); register_mqtt_cmd(F("holidaytemp"), [&](const char * value, const int8_t id) { return set_holidaytemp(value, id); }); + register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { return set_wwmode(value, id); }); + register_mqtt_cmd(F("wwcircmode"), [&](const char * value, const int8_t id) { return set_wwcircmode(value, id); }); break; case EMS_DEVICE_FLAG_JUNKERS: register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); }); diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 7f2a604e3..2dd3c170f 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -62,6 +62,7 @@ class Thermostat : public EMSdevice { uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heating curve design temp at MinExtTemp int8_t offsettemp = EMS_VALUE_INT_NOTSET; // heating curve offest temp at roomtemp signed! uint8_t manualtemp = EMS_VALUE_UINT_NOTSET; + uint8_t summer_setmode = EMS_VALUE_UINT_NOTSET; uint8_t hc_num() const { return hc_num_; @@ -117,6 +118,7 @@ class Thermostat : public EMSdevice { std::vector monitor_typeids; std::vector set_typeids; std::vector timer_typeids; + std::vector summer_typeids; std::string datetime_; // date and time stamp @@ -135,9 +137,10 @@ 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 wwMode_ = EMS_VALUE_UINT_NOTSET; + uint8_t wwSystem_ = EMS_VALUE_UINT_NOTSET; + uint8_t wwExtra_ = EMS_VALUE_UINT_NOTSET; + uint8_t wwMode_ = EMS_VALUE_UINT_NOTSET; + uint8_t wwCircMode_ = EMS_VALUE_UINT_NOTSET; std::vector> heating_circuits_; // each thermostat can have multiple heating circuits @@ -240,11 +243,12 @@ class Thermostat : public EMSdevice { void process_RC10Set(std::shared_ptr telegram); void process_RC300Monitor(std::shared_ptr telegram); void process_RC300Set(std::shared_ptr telegram); + void process_RC300Summer(std::shared_ptr telegram); + void process_RC300WWmode(std::shared_ptr telegram); void process_JunkersMonitor(std::shared_ptr telegram); void process_JunkersSet(std::shared_ptr telegram); void process_JunkersSet2(std::shared_ptr telegram); void process_EasyMonitor(std::shared_ptr telegram); - void process_RC300WWmode(std::shared_ptr telegram); // internal helper functions bool set_mode_n(const uint8_t mode, const uint8_t hc_num); @@ -259,6 +263,7 @@ class Thermostat : public EMSdevice { bool set_holiday(const char * value, const int8_t id); bool set_pause(const char * value, const int8_t id); bool set_party(const char * value, const int8_t id); + bool set_summermode(const char * value, const int8_t id); bool set_temp(const char * value, const int8_t id); bool set_nighttemp(const char * value, const int8_t id); @@ -276,6 +281,7 @@ 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_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); bool set_clockoffset(const char * value, const int8_t id); diff --git a/src/emsdevice.h b/src/emsdevice.h index d50772921..f3d416226 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -192,7 +192,7 @@ class EMSdevice { Value & value, const __FlashStringHelper * suffix, const uint8_t format = 0) { - + // create the value as a string using the render_value function char buffer[15]; if (Helpers::render_value(buffer, value, format) == nullptr) { diff --git a/src/helpers.h b/src/helpers.h index b84f4f699..034ddbe36 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -41,7 +41,7 @@ class Helpers { static char * render_value(char * result, const uint32_t value, const uint8_t format); static char * render_value(char * result, const int16_t value, const uint8_t format); static char * render_value(char * result, const char * value, uint8_t format); - + static char * render_boolean(char * result, bool value); static char * smallitoa(char * result, const uint8_t value); diff --git a/src/system.cpp b/src/system.cpp index 942c1dfef..cfdada737 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -30,12 +30,13 @@ uuid::syslog::SyslogService System::syslog_; #endif // init statics -uint32_t System::heap_start_ = 0; -int System::reset_counter_ = 0; -bool System::upload_status_ = false; -bool System::hide_led_ = false; -uint8_t System::led_gpio_ = 0; -uint16_t System::analog_ = 0; +uint32_t System::heap_start_ = 0; +int System::reset_counter_ = 0; +bool System::upload_status_ = false; +bool System::hide_led_ = false; +uint8_t System::led_gpio_ = 0; +uint16_t System::analog_ = 0; +bool System::analog_enabled_ = false; // send on/off to a gpio pin // value: true = HIGH, false = LOW @@ -162,7 +163,10 @@ void System::init() { set_led(); // init LED // set the boolean format used for rendering booleans - EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { Helpers::bool_format(settings.bool_format); }); + EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { + Helpers::bool_format(settings.bool_format); + analog_enabled_ = settings.analog_enabled; + }); EMSESP::init_tx(); // start UART } @@ -203,7 +207,9 @@ void System::loop() { #endif led_monitor(); // check status and report back using the LED system_check(); // check system health - measure_analog(); + if (analog_enabled_) { + measure_analog(); + } // send out heartbeat uint32_t currentMillis = uuid::get_uptime(); @@ -257,7 +263,9 @@ void System::send_heartbeat() { doc["mqttpublishfails"] = Mqtt::publish_fails(); doc["txfails"] = EMSESP::txservice_.telegram_fail_count(); doc["rxfails"] = EMSESP::rxservice_.telegram_error_count(); - doc["adc"] = analog_; //analogRead(A0); + if (analog_enabled_) { + doc["adc"] = analog_; + } Mqtt::publish_retain(F("heartbeat"), doc.as(), false); // send to MQTT with retain off. This will add to MQTT queue. } @@ -279,10 +287,10 @@ void System::measure_analog() { if (!analog_) { // init first time analog_ = a; - sum_ = a * 256; + sum_ = a * 512; } else { // simple moving average filter - sum_ = sum_ * 255 / 256 + a; - analog_ = sum_ / 256; + sum_ = (sum_ * 511) / 512 + a; + analog_ = sum_ / 512; } } } @@ -789,6 +797,7 @@ bool System::check_upgrade() { settings.dallas_gpio = custom_settings["dallas_gpio"] | EMSESP_DEFAULT_DALLAS_GPIO; settings.dallas_parasite = custom_settings["dallas_parasite"] | EMSESP_DEFAULT_DALLAS_PARASITE; settings.led_gpio = custom_settings["led_gpio"] | EMSESP_DEFAULT_LED_GPIO; + settings.analog_enabled = EMSESP_DEFAULT_ANALOG_ENABLED; return StateUpdateResult::CHANGED; }, @@ -912,6 +921,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp node["hide_led"] = Helpers::render_boolean(s, settings.hide_led); node["api_enabled"] = Helpers::render_boolean(s, settings.api_enabled); node["bool_format"] = settings.bool_format; + node["analog_enabled"] = settings.analog_enabled; }); #endif diff --git a/src/system.h b/src/system.h index 28059ed98..4b5e38336 100644 --- a/src/system.h +++ b/src/system.h @@ -74,7 +74,7 @@ class System { static constexpr uint32_t LED_WARNING_BLINK = 1000; // pulse to show no connection, 1 sec static constexpr uint32_t LED_WARNING_BLINK_FAST = 100; // flash quickly for boot up sequence static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min) - static constexpr uint32_t SYSTEM_MEASURE_ANALOG_INTERVAL = 1100; + static constexpr uint32_t SYSTEM_MEASURE_ANALOG_INTERVAL = 500; // internal LED static constexpr uint8_t LED_ON = LOW; @@ -103,6 +103,7 @@ class System { uint32_t syslog_mark_interval_; String syslog_host_; static uint8_t led_gpio_; + static bool analog_enabled_; }; } // namespace emsesp