mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-09 09:19:51 +03:00
initial commit
This commit is contained in:
896
src/devices/boiler.cpp
Normal file
896
src/devices/boiler.cpp
Normal file
@@ -0,0 +1,896 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "boiler.h"
|
||||
|
||||
MAKE_PSTR_WORD(boiler)
|
||||
MAKE_PSTR_WORD(wwtemp)
|
||||
MAKE_PSTR_WORD(flowtemp)
|
||||
MAKE_PSTR_WORD(wwactive)
|
||||
MAKE_PSTR_WORD(wwonetime)
|
||||
MAKE_PSTR_WORD(wwcirculation)
|
||||
MAKE_PSTR_WORD(comfort)
|
||||
MAKE_PSTR_WORD(eco)
|
||||
MAKE_PSTR_WORD(intelligent)
|
||||
MAKE_PSTR_WORD(hot)
|
||||
|
||||
MAKE_PSTR(comfort_mandatory, "<hot | eco | intelligent>")
|
||||
|
||||
// shower
|
||||
MAKE_PSTR_WORD(shower)
|
||||
MAKE_PSTR_WORD(timer)
|
||||
MAKE_PSTR_WORD(alert)
|
||||
MAKE_PSTR(shower_timer_fmt, "Shower Timer is %s")
|
||||
MAKE_PSTR(shower_alert_fmt, "Shower Alert is %s")
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Boiler, EMSdevice::DeviceType::BOILER)
|
||||
MAKE_PSTR(logger_name, "boiler")
|
||||
uuid::log::Logger Boiler::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
LOG_DEBUG(F("Registering new Boiler with device ID 0x%02X"), device_id);
|
||||
|
||||
// the telegram handlers...
|
||||
register_telegram_type(0x10, F("UBAErrorMessage1"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
|
||||
register_telegram_type(0x11, F("UBAErrorMessage2"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
|
||||
register_telegram_type(0x18, F("UBAMonitorFast"), false, std::bind(&Boiler::process_UBAMonitorFast, this, _1));
|
||||
register_telegram_type(0x19, F("UBAMonitorSlow"), true, std::bind(&Boiler::process_UBAMonitorSlow, this, _1));
|
||||
register_telegram_type(0x34, F("UBAMonitorWW"), false, std::bind(&Boiler::process_UBAMonitorWW, this, _1));
|
||||
register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, std::bind(&Boiler::process_UBAMaintenanceStatus, this, _1));
|
||||
register_telegram_type(0x2A, F("MC10Status"), false, std::bind(&Boiler::process_MC10Status, this, _1));
|
||||
register_telegram_type(0x33, F("UBAParameterWW"), true, std::bind(&Boiler::process_UBAParameterWW, this, _1));
|
||||
register_telegram_type(0x14, F("UBATotalUptime"), false, std::bind(&Boiler::process_UBATotalUptime, this, _1));
|
||||
register_telegram_type(0x35, F("UBAFlags"), false, std::bind(&Boiler::process_UBAFlags, this, _1));
|
||||
register_telegram_type(0x15, F("UBAMaintenanceSettings"), false, std::bind(&Boiler::process_UBAMaintenanceSettings, this, _1));
|
||||
register_telegram_type(0x16, F("UBAParameters"), true, std::bind(&Boiler::process_UBAParameters, this, _1));
|
||||
register_telegram_type(0x1A, F("UBASetPoints"), false, std::bind(&Boiler::process_UBASetPoints, this, _1));
|
||||
register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, std::bind(&Boiler::process_UBAOutdoorTemp, this, _1));
|
||||
register_telegram_type(0xE3, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus2, this, _1));
|
||||
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, std::bind(&Boiler::process_UBAMonitorFastPlus, this, _1));
|
||||
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus, this, _1));
|
||||
|
||||
register_telegram_type(0xE9, F("UBADHWStatus"), false, std::bind(&Boiler::process_UBADHWStatus, this, _1));
|
||||
|
||||
// MQTT callbacks
|
||||
register_mqtt_topic("boiler_cmd", std::bind(&Boiler::boiler_cmd, this, _1));
|
||||
register_mqtt_topic("boiler_cmd_wwactivated", std::bind(&Boiler::boiler_cmd_wwactivated, this, _1));
|
||||
register_mqtt_topic("boiler_cmd_wwonetime", std::bind(&Boiler::boiler_cmd_wwonetime, this, _1));
|
||||
register_mqtt_topic("boiler_cmd_wwcirculation", std::bind(&Boiler::boiler_cmd_wwcirculation, this, _1));
|
||||
register_mqtt_topic("boiler_cmd_wwtemp", std::bind(&Boiler::boiler_cmd_wwtemp, this, _1));
|
||||
}
|
||||
|
||||
// add submenu context
|
||||
void Boiler::add_context_menu() {
|
||||
EMSESPShell::commands->add_command(ShellContext::MAIN,
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(boiler)},
|
||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
Boiler::console_commands(shell, ShellContext::BOILER);
|
||||
});
|
||||
}
|
||||
|
||||
// boiler_cmd topic
|
||||
void Boiler::boiler_cmd(const char * message) {
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||
DeserializationError error = deserializeJson(doc, message);
|
||||
if (error) {
|
||||
LOG_DEBUG(F("MQTT error: payload %s, error %s"), message, error.c_str());
|
||||
return;
|
||||
}
|
||||
if (nullptr != doc["flowtemp"]) {
|
||||
uint8_t t = doc["flowtemp"];
|
||||
set_flow_temp(t);
|
||||
}
|
||||
if (nullptr != doc["wwtemp"]) {
|
||||
uint8_t t = doc["wwtemp"];
|
||||
set_warmwater_temp(t);
|
||||
}
|
||||
|
||||
const char * command = doc["cmd"];
|
||||
if (command == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// boiler ww comfort setting
|
||||
if (strcmp(command, "comfort") == 0) {
|
||||
const char * data = doc["data"];
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (strcmp((char *)data, "hot") == 0) {
|
||||
set_warmwater_mode(1);
|
||||
} else if (strcmp((char *)data, "eco") == 0) {
|
||||
set_warmwater_mode(2);
|
||||
} else if (strcmp((char *)data, "intelligent") == 0) {
|
||||
set_warmwater_mode(3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// boiler flowtemp setting
|
||||
if (strcmp(command, "flowtemp") == 0) {
|
||||
uint8_t t = doc["data"];
|
||||
if (t) {
|
||||
set_flow_temp(t);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Boiler::boiler_cmd_wwactivated(const char * message) {
|
||||
if ((message[0] == '1' || strcmp(message, "on") == 0) || (strcmp(message, "auto") == 0)) {
|
||||
set_warmwater_activated(true);
|
||||
} else if (message[0] == '0' || strcmp(message, "off") == 0) {
|
||||
set_warmwater_activated(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Boiler::boiler_cmd_wwonetime(const char * message) {
|
||||
if (message[0] == '1' || strcmp(message, "on") == 0) {
|
||||
set_warmwater_onetime(true);
|
||||
} else if (message[0] == '0' || strcmp(message, "off") == 0) {
|
||||
set_warmwater_onetime(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Boiler::boiler_cmd_wwcirculation(const char * message) {
|
||||
if (message[0] == '1' || strcmp(message, "on") == 0) {
|
||||
set_warmwater_circulation(true);
|
||||
} else if (message[0] == '0' || strcmp(message, "off") == 0) {
|
||||
set_warmwater_circulation(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Boiler::boiler_cmd_wwtemp(const char * message) {
|
||||
uint8_t t = atoi((char *)message);
|
||||
if (t) {
|
||||
set_warmwater_temp(t);
|
||||
}
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Boiler::publish_values() {
|
||||
const size_t capacity = JSON_OBJECT_SIZE(47); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/
|
||||
DynamicJsonDocument doc(capacity);
|
||||
|
||||
char s[10]; // for formatting strings
|
||||
|
||||
if (Helpers::hasValue(wWComfort_)) {
|
||||
if (wWComfort_ == 0x00) {
|
||||
doc["wWComfort"] = "Hot";
|
||||
} else if (wWComfort_ == 0xD8) {
|
||||
doc["wWComfort"] = "Eco";
|
||||
} else if (wWComfort_ == 0xEC) {
|
||||
doc["wWComfort"] = "Intelligent";
|
||||
}
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(wWSelTemp_)) {
|
||||
doc["wWSelTemp"] = wWSelTemp_;
|
||||
}
|
||||
if (Helpers::hasValue(wWSetTmp_)) {
|
||||
doc["wWSetTemp"] = wWSetTmp_;
|
||||
}
|
||||
if (Helpers::hasValue(wWDisinfectTemp_)) {
|
||||
doc["wWDisinfectionTemp"] = wWDisinfectTemp_;
|
||||
}
|
||||
if (Helpers::hasValue(selFlowTemp_)) {
|
||||
doc["selFlowTemp"] = selFlowTemp_;
|
||||
}
|
||||
if (Helpers::hasValue(selBurnPow_)) {
|
||||
doc["selBurnPow"] = selBurnPow_;
|
||||
}
|
||||
if (Helpers::hasValue(curBurnPow_)) {
|
||||
doc["curBurnPow"] = curBurnPow_;
|
||||
}
|
||||
if (Helpers::hasValue(pumpMod_)) {
|
||||
doc["pumpMod"] = pumpMod_;
|
||||
}
|
||||
if (Helpers::hasValue(pumpMod2_)) {
|
||||
doc["pumpMod2"] = pumpMod2_;
|
||||
}
|
||||
if (Helpers::hasValue(wWCircPump_, true)) {
|
||||
doc["wWCircPump"] = Helpers::render_value(s, wWCircPump_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWCircPumpType_)) {
|
||||
doc["wWCiPuType"] = wWCircPumpType_ ? "valve" : "pump";
|
||||
}
|
||||
if (Helpers::hasValue(wWCircPumpMode_)) {
|
||||
doc["wWCiPuMode"] = wWCircPumpMode_;
|
||||
}
|
||||
if (Helpers::hasValue(wWCirc_)) {
|
||||
doc["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(extTemp_)) {
|
||||
doc["outdoorTemp"] = (float)extTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(wWCurTmp_)) {
|
||||
doc["wWCurTmp"] = (float)wWCurTmp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(wWCurFlow_)) {
|
||||
doc["wWCurFlow"] = (float)wWCurFlow_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(curFlowTemp_)) {
|
||||
doc["curFlowTemp"] = (float)curFlowTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(retTemp_)) {
|
||||
doc["retTemp"] = (float)retTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(switchTemp_)) {
|
||||
doc["switchTemp"] = (float)switchTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(sysPress_)) {
|
||||
doc["sysPress"] = (float)sysPress_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(boilTemp_)) {
|
||||
doc["boilTemp"] = (float)boilTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(wwStorageTemp1_)) {
|
||||
doc["wwStorageTemp1"] = (float)wwStorageTemp1_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(wwStorageTemp2_)) {
|
||||
doc["wwStorageTemp2"] = (float)wwStorageTemp2_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(exhaustTemp_)) {
|
||||
doc["exhaustTemp"] = (float)exhaustTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(wWActivated_, true)) {
|
||||
doc["wWActivated"] = Helpers::render_value(s, wWActivated_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWOneTime_, true)) {
|
||||
doc["wWOnetime"] = Helpers::render_value(s, wWOneTime_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWDesinfecting_, true)) {
|
||||
doc["wWDesinfecting"] = Helpers::render_value(s, wWDesinfecting_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWReadiness_, true)) {
|
||||
doc["wWReady"] = Helpers::render_value(s, wWReadiness_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWRecharging_, true)) {
|
||||
doc["wWRecharge"] = Helpers::render_value(s, wWRecharging_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWTemperatureOK_, true)) {
|
||||
doc["wWTempOK"] = Helpers::render_value(s, wWTemperatureOK_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWCirc_, true)) {
|
||||
doc["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(burnGas_, true)) {
|
||||
doc["burnGas"] = Helpers::render_value(s, burnGas_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(flameCurr_)) {
|
||||
doc["flameCurr"] = (float)(int16_t)flameCurr_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(heatPmp_, true)) {
|
||||
doc["heatPmp"] = Helpers::render_value(s, heatPmp_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(fanWork_, true)) {
|
||||
doc["fanWork"] = Helpers::render_value(s, fanWork_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(ignWork_, true)) {
|
||||
doc["ignWork"] = Helpers::render_value(s, ignWork_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(wWHeat_, true)) {
|
||||
doc["wWHeat"] = Helpers::render_value(s, wWHeat_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(heating_temp_)) {
|
||||
doc["heating_temp"] = heating_temp_;
|
||||
}
|
||||
if (Helpers::hasValue(pump_mod_max_)) {
|
||||
doc["pump_mod_max"] = pump_mod_max_;
|
||||
}
|
||||
if (Helpers::hasValue(pump_mod_min_)) {
|
||||
doc["pump_mod_min"] = pump_mod_min_;
|
||||
}
|
||||
if (Helpers::hasValue(wWStarts_)) {
|
||||
doc["wWStarts"] = wWStarts_;
|
||||
}
|
||||
if (Helpers::hasValue(wWWorkM_)) {
|
||||
doc["wWWorkM"] = wWWorkM_;
|
||||
}
|
||||
if (Helpers::hasValue(UBAuptime_)) {
|
||||
doc["UBAuptime"] = UBAuptime_;
|
||||
}
|
||||
if (Helpers::hasValue(burnStarts_)) {
|
||||
doc["burnStarts"] = burnStarts_;
|
||||
}
|
||||
if (Helpers::hasValue(burnWorkMin_)) {
|
||||
doc["burnWorkMin"] = burnWorkMin_;
|
||||
}
|
||||
if (Helpers::hasValue(heatWorkMin_)) {
|
||||
doc["heatWorkMin"] = heatWorkMin_;
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(serviceCode_)) {
|
||||
doc["serviceCode"] = serviceCodeChar_;
|
||||
doc["serviceCodeNumber"] = serviceCode_;
|
||||
}
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
LOG_DEBUG(F("[DEBUG] Performing a boiler publish"));
|
||||
#endif
|
||||
|
||||
// if we have data, publish it
|
||||
if (!doc.isNull()) {
|
||||
Mqtt::publish("boiler_data", doc);
|
||||
}
|
||||
}
|
||||
|
||||
// called after a process command is called, to check values and see if we need to force an MQTT publish
|
||||
bool Boiler::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// print values to shell console
|
||||
void Boiler::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // for showing the header
|
||||
|
||||
if (Helpers::hasValue(tap_water_active_, true)) {
|
||||
print_value(shell, 2, F("Hot tap water"), tap_water_active_ ? F("running") : F("off"));
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(heating_active_, true)) {
|
||||
print_value(shell, 2, F("Central heating"), heating_active_ ? F("active") : F("off"));
|
||||
}
|
||||
|
||||
print_value(shell, 2, F("Warm Water activated"), wWActivated_, nullptr, EMS_VALUE_BOOL);
|
||||
if (Helpers::hasValue(wWCircPumpType_, true)) {
|
||||
print_value(shell, 2, F("Warm Water charging type"), wWCircPumpType_ ? F("3-way valve") : F("charge pump"));
|
||||
}
|
||||
print_value(shell, 2, F("Warm Water circulation pump available"), wWCircPump_, nullptr, EMS_VALUE_BOOL);
|
||||
|
||||
if (Helpers::hasValue(wWCircPumpMode_)) {
|
||||
if (wWCircPumpMode_ == 7) {
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), F("continuous"));
|
||||
} else {
|
||||
char s[7];
|
||||
char buffer[2];
|
||||
buffer[0] = (wWCircPumpMode_ % 10) + '0';
|
||||
buffer[1] = '\0';
|
||||
strlcpy(s, buffer, 7);
|
||||
strlcat(s, "x3min", 7);
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), s);
|
||||
}
|
||||
}
|
||||
|
||||
print_value(shell, 2, F("Warm Water circulation active"), wWCirc_, nullptr, EMS_VALUE_BOOL);
|
||||
|
||||
if (wWComfort_ == 0x00) {
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), F("Hot"));
|
||||
} else if (wWComfort_ == 0xD8) {
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), F("Eco"));
|
||||
} else if (wWComfort_ == 0xEC) {
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), F("Intelligent"));
|
||||
}
|
||||
|
||||
print_value(shell, 2, F("Warm water mix temperature"), wwMixTemperature_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm water buffer boiler temperature"), wwBufferBoilerTemperature_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm Water disinfection temperature"), wWDisinfectTemp_, F_(degrees));
|
||||
print_value(shell, 2, F("Warm Water selected temperature"), wWSelTemp_, F_(degrees));
|
||||
print_value(shell, 2, F("Warm Water set temperature"), wWSetTmp_, F_(degrees));
|
||||
print_value(shell, 2, F("Warm Water current temperature (intern)"), wWCurTmp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm water storage temperature (intern)"), wwStorageTemp1_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm Water current temperature (extern)"), wWCurTmp2_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm water storage temperature (extern)"), wwStorageTemp2_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm Water current tap water flow"), wWCurFlow_, F("l/min"), 10);
|
||||
print_value(shell, 2, F("Warm Water # starts"), wWStarts_, nullptr);
|
||||
if (Helpers::hasValue(wWWorkM_)) {
|
||||
shell.printfln(F(" Warm Water active time: %d days %d hours %d minutes"), wWWorkM_ / 1440, (wWWorkM_ % 1440) / 60, wWWorkM_ % 60);
|
||||
}
|
||||
print_value(shell, 2, F("Warm Water charging"), wWHeat_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Warm Water disinfecting"), wWDesinfecting_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Selected flow temperature"), selFlowTemp_, F_(degrees));
|
||||
print_value(shell, 2, F("Current flow temperature"), curFlowTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Max boiler temperature"), boilTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Return temperature"), retTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Gas"), burnGas_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Boiler pump"), heatPmp_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Fan"), fanWork_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Ignition"), ignWork_, nullptr, EMS_VALUE_BOOL);
|
||||
|
||||
print_value(shell, 2, F("Burner selected max power"), selBurnPow_, F_(percent));
|
||||
print_value(shell, 2, F("Burner current power"), curBurnPow_, F_(percent));
|
||||
print_value(shell, 2, F("Flame current"), flameCurr_, F("uA"), 10);
|
||||
print_value(shell, 2, F("System pressure"), sysPress_, F("bar"), 10);
|
||||
if (Helpers::hasValue(serviceCode_)) {
|
||||
shell.printfln(F(" System service code: %s (%d)"), serviceCodeChar_, serviceCode_);
|
||||
} else if (serviceCodeChar_[0] != '\0') {
|
||||
print_value(shell, 2, F("System service code"), serviceCodeChar_);
|
||||
}
|
||||
|
||||
// UBAParameters
|
||||
print_value(shell, 2, F("Heating temperature setting on the boiler"), heating_temp_, F_(degrees));
|
||||
print_value(shell, 2, F("Boiler circuit pump modulation max power"), pump_mod_max_, F_(percent));
|
||||
print_value(shell, 2, F("Boiler circuit pump modulation min power"), pump_mod_min_, F_(percent));
|
||||
|
||||
// UBAMonitorSlow
|
||||
if (Helpers::hasValue(extTemp_)) {
|
||||
print_value(shell, 2, F("Outside temperature"), extTemp_, F_(degrees), 10);
|
||||
}
|
||||
|
||||
print_value(shell, 2, F("Exhaust temperature"), exhaustTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Pump modulation"), pumpMod_, F_(percent));
|
||||
print_value(shell, 2, F("Pump modulation2"), pumpMod2_, F_(percent));
|
||||
print_value(shell, 2, F("Burner # starts"), burnStarts_, nullptr);
|
||||
if (Helpers::hasValue(burnWorkMin_)) {
|
||||
shell.printfln(F(" Total burner operating time: %d days %d hours %d minutes"), burnWorkMin_ / 1440, (burnWorkMin_ % 1440) / 60, burnWorkMin_ % 60);
|
||||
}
|
||||
if (Helpers::hasValue(heatWorkMin_)) {
|
||||
shell.printfln(F(" Total heat operating time: %d days %d hours %d minutes"), heatWorkMin_ / 1440, (heatWorkMin_ % 1440) / 60, heatWorkMin_ % 60);
|
||||
}
|
||||
if (Helpers::hasValue(UBAuptime_)) {
|
||||
shell.printfln(F(" Total UBA working time: %d days %d hours %d minutes"), UBAuptime_ / 1440, (UBAuptime_ % 1440) / 60, UBAuptime_ % 60);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if hot tap water or heating is active
|
||||
* If a value has changed, post it immediately to MQTT so we get real time data
|
||||
*/
|
||||
void Boiler::check_active() {
|
||||
// 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_)) {
|
||||
tap_water_active_ = ((wWCurFlow_ != 0) && (burnGas_ != EMS_VALUE_BOOL_OFF));
|
||||
EMSESP::tap_water_active(tap_water_active_);
|
||||
}
|
||||
|
||||
// heating
|
||||
// using a quick hack for checking the heating by looking at the Selected Flow Temp, but doesn't work for all boilers apparently
|
||||
if (Helpers::hasValue(selFlowTemp_) && Helpers::hasValue(burnGas_)) {
|
||||
heating_active_ = (!tap_water_active_ && ((selFlowTemp_ >= EMS_BOILER_SELFLOWTEMP_HEATING) && (burnGas_ != EMS_VALUE_BOOL_OFF)));
|
||||
}
|
||||
|
||||
// see if the heating or hot tap water has changed, if so send
|
||||
// last_boilerActive stores heating in bit 1 and tap water in bit 2
|
||||
if (Helpers::hasValue(tap_water_active_, true) && Helpers::hasValue(heating_active_, true)) {
|
||||
uint8_t latest_boilerState = (tap_water_active_ << 1) + heating_active_;
|
||||
if (latest_boilerState != last_boilerState) {
|
||||
last_boilerState = latest_boilerState;
|
||||
Mqtt::publish("tapwater_active", tap_water_active_);
|
||||
Mqtt::publish("heating_active", heating_active_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x33
|
||||
void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wWActivated_, 1); // 0xFF means on
|
||||
telegram->read_value(wWCircPump_, 6); // 0xFF means on
|
||||
telegram->read_value(wWCircPumpMode_, 7); // 1=1x3min... 6=6x3min, 7=continuous
|
||||
telegram->read_value(wWCircPumpType_, 10); // 0 = charge pump, 0xff = 3-way valve
|
||||
telegram->read_value(wWSelTemp_, 2);
|
||||
telegram->read_value(wWDisinfectTemp_, 8);
|
||||
telegram->read_value(wWComfort_, 9);
|
||||
}
|
||||
|
||||
// 0x18
|
||||
void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(selFlowTemp_, 0);
|
||||
telegram->read_value(curFlowTemp_, 1);
|
||||
telegram->read_value(selBurnPow_, 3); // burn power max setting
|
||||
telegram->read_value(curBurnPow_, 4);
|
||||
|
||||
telegram->read_bitvalue(burnGas_, 7, 0);
|
||||
telegram->read_bitvalue(fanWork_, 7, 2);
|
||||
telegram->read_bitvalue(ignWork_, 7, 3);
|
||||
telegram->read_bitvalue(heatPmp_, 7, 5);
|
||||
telegram->read_bitvalue(wWHeat_, 7, 6);
|
||||
telegram->read_bitvalue(wWCirc_, 7, 7);
|
||||
|
||||
// warm water storage sensors (if present)
|
||||
// wwStorageTemp2 is also used by some brands as the boiler temperature - see https://github.com/proddy/EMS-ESP/issues/206
|
||||
telegram->read_value(wwStorageTemp1_, 9); // 0x8300 if not available
|
||||
telegram->read_value(wwStorageTemp2_, 11); // 0x8000 if not available - this is boiler temp
|
||||
|
||||
telegram->read_value(retTemp_, 13);
|
||||
telegram->read_value(flameCurr_, 15);
|
||||
telegram->read_value(serviceCode_, 20);
|
||||
|
||||
// system pressure. FF means missing
|
||||
telegram->read_value(sysPress_, 17); // is *10
|
||||
|
||||
// read the service code / installation status as appears on the display
|
||||
if ((telegram->message_length > 18) && (telegram->offset == 0)) {
|
||||
serviceCodeChar_[0] = char(telegram->message_data[18]); // ascii character 1
|
||||
serviceCodeChar_[1] = char(telegram->message_data[19]); // ascii character 2
|
||||
serviceCodeChar_[2] = '\0'; // null terminate string
|
||||
}
|
||||
|
||||
// at this point do a quick check to see if the hot water or heating is active
|
||||
check_active();
|
||||
}
|
||||
|
||||
/*
|
||||
* UBATotalUptime - type 0x14 - total uptime
|
||||
* received only after requested (not broadcasted)
|
||||
*/
|
||||
void Boiler::process_UBATotalUptime(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(UBAuptime_, 0, 3); // force to 3 bytes
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAParameters - type 0x16
|
||||
*/
|
||||
void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(heating_temp_, 1);
|
||||
telegram->read_value(pump_mod_max_, 9);
|
||||
telegram->read_value(pump_mod_min_, 10);
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorWW - type 0x34 - warm water monitor. 19 bytes long
|
||||
* received every 10 seconds
|
||||
*/
|
||||
void Boiler::process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wWSetTmp_, 0);
|
||||
telegram->read_value(wWCurTmp_, 1);
|
||||
telegram->read_value(wWCurTmp2_, 3);
|
||||
telegram->read_value(wWCurFlow_, 9);
|
||||
|
||||
telegram->read_value(wWWorkM_, 10, 3); // force to 3 bytes
|
||||
telegram->read_value(wWStarts_, 13, 3); // force to 3 bytes
|
||||
|
||||
telegram->read_bitvalue(wWOneTime_, 5, 1);
|
||||
telegram->read_bitvalue(wWDesinfecting_, 5, 2);
|
||||
telegram->read_bitvalue(wWReadiness_, 5, 3);
|
||||
telegram->read_bitvalue(wWRecharging_, 5, 4);
|
||||
telegram->read_bitvalue(wWTemperatureOK_, 5, 5);
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorFastPlus - type 0xE4 - central heating monitor EMS+
|
||||
* Still to figure out are: serviceCode, retTemp, sysPress
|
||||
*/
|
||||
void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(selFlowTemp_, 6);
|
||||
telegram->read_bitvalue(burnGas_, 11, 0);
|
||||
telegram->read_bitvalue(wWHeat_, 11, 2);
|
||||
telegram->read_value(curBurnPow_, 10);
|
||||
telegram->read_value(selBurnPow_, 9);
|
||||
telegram->read_value(curFlowTemp_, 7);
|
||||
telegram->read_value(flameCurr_, 19);
|
||||
|
||||
// read the service code / installation status as appears on the display
|
||||
if ((telegram->message_length > 4) && (telegram->offset == 0)) {
|
||||
serviceCodeChar_[0] = char(telegram->message_data[4]); // ascii character 1
|
||||
serviceCodeChar_[1] = char(telegram->message_data[5]); // ascii character 2
|
||||
serviceCodeChar_[2] = '\0';
|
||||
}
|
||||
|
||||
// at this point do a quick check to see if the hot water or heating is active
|
||||
check_active();
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorSlow - type 0x19 - central heating monitor part 2 (27 bytes long)
|
||||
* received every 60 seconds
|
||||
* e.g. 08 00 19 00 80 00 02 41 80 00 00 00 00 00 03 91 7B 05 B8 40 00 00 00 04 92 AD 00 5E EE 80 00
|
||||
* 08 0B 19 00 FF EA 02 47 80 00 00 00 00 62 03 CA 24 2C D6 23 00 00 00 27 4A B6 03 6E 43
|
||||
* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 17 19 20 21 22 23 24
|
||||
*/
|
||||
void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(extTemp_, 0);
|
||||
telegram->read_value(boilTemp_, 2);
|
||||
telegram->read_value(exhaustTemp_, 4);
|
||||
telegram->read_value(switchTemp_, 25); // only if there is a mixing module present
|
||||
telegram->read_value(pumpMod_, 9);
|
||||
telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
|
||||
telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
|
||||
telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorSlowPlus2 - type 0xE3
|
||||
*/
|
||||
void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(pumpMod2_, 13);
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorSlowPlus - type 0xE5 - central heating monitor EMS+
|
||||
*/
|
||||
void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_bitvalue(fanWork_, 2, 2);
|
||||
telegram->read_bitvalue(ignWork_, 2, 3);
|
||||
telegram->read_bitvalue(heatPmp_, 2, 5);
|
||||
telegram->read_bitvalue(wWCirc_, 2, 7);
|
||||
telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
|
||||
telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
|
||||
telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
|
||||
telegram->read_value(pumpMod_, 25);
|
||||
}
|
||||
|
||||
// 0xE9 - DHW Status
|
||||
// e.g. 08 00 E9 00 37 01 F6 01 ED 00 00 00 00 41 3C 00 00 00 00 00 00 00 00 00 00 00 00 37 00 00 00 (CRC=77) #data=27
|
||||
void Boiler::process_UBADHWStatus(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wWSetTmp_, 0);
|
||||
telegram->read_value(wWCurTmp_, 1);
|
||||
telegram->read_value(wWCurTmp2_, 3);
|
||||
|
||||
telegram->read_value(wWWorkM_, 17, 3); // force to 3 bytes
|
||||
telegram->read_value(wWStarts_, 14, 3); // force to 3 bytes
|
||||
|
||||
telegram->read_bitvalue(wWOneTime_, 12, 2);
|
||||
telegram->read_bitvalue(wWDesinfecting_, 12, 3);
|
||||
telegram->read_bitvalue(wWReadiness_, 12, 4);
|
||||
telegram->read_bitvalue(wWRecharging_, 13, 4);
|
||||
telegram->read_bitvalue(wWTemperatureOK_, 13, 5);
|
||||
telegram->read_bitvalue(wWCircPump_, 13, 2);
|
||||
|
||||
telegram->read_value(wWActivated_, 20);
|
||||
telegram->read_value(wWSelTemp_, 10);
|
||||
telegram->read_value(wWDisinfectTemp_, 9);
|
||||
}
|
||||
|
||||
// 0x2A - MC10Status
|
||||
// e.g. 88 00 2A 00 00 00 00 00 00 00 00 00 D2 00 00 80 00 00 01 08 80 00 02 47 00
|
||||
// see https://github.com/proddy/EMS-ESP/issues/397
|
||||
void Boiler::process_MC10Status(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wwMixTemperature_, 14);
|
||||
telegram->read_value(wwBufferBoilerTemperature_, 18);
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAOutdoorTemp - type 0xD1 - external temperature EMS+
|
||||
*/
|
||||
void Boiler::process_UBAOutdoorTemp(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(extTemp_, 0);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
// UBASetPoint 0x1A
|
||||
// not yet implemented
|
||||
void Boiler::process_UBASetPoints(std::shared_ptr<const Telegram> telegram) {
|
||||
// uint8_t setpoint = telegram->message_data[0]; // boiler flow temp
|
||||
// uint8_t ww_power = telegram->message_data[2]; // power in %
|
||||
}
|
||||
|
||||
// 0x35
|
||||
// not yet implemented
|
||||
void Boiler::process_UBAFlags(std::shared_ptr<const Telegram> telegram) {
|
||||
}
|
||||
|
||||
// 0x1C
|
||||
// not yet implemented
|
||||
void Boiler::process_UBAMaintenanceStatus(std::shared_ptr<const Telegram> telegram) {
|
||||
}
|
||||
|
||||
// 0x15
|
||||
// not yet implemented
|
||||
void Boiler::process_UBAMaintenanceSettings(std::shared_ptr<const Telegram> telegram) {
|
||||
}
|
||||
|
||||
// 0x10, 0x11, 0x12
|
||||
// not yet implemented
|
||||
void Boiler::process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram) {
|
||||
// data: displaycode(2), errornumner(2), year, month, hour, day, minute, duration(2), src-addr
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// Set the warm water temperature 0x33
|
||||
void Boiler::set_warmwater_temp(const uint8_t temperature) {
|
||||
LOG_INFO(F("Setting boiler warm water temperature to %d C"), temperature);
|
||||
write_command(EMS_TYPE_UBAParameterWW, 2, temperature);
|
||||
// for i9000, see #397
|
||||
write_command(EMS_TYPE_UBAFlags, 3, temperature);
|
||||
}
|
||||
|
||||
// flow temp
|
||||
void Boiler::set_flow_temp(const uint8_t temperature) {
|
||||
LOG_INFO(F("Setting boiler flow temperature to %d C"), temperature);
|
||||
write_command(EMS_TYPE_UBASetPoints, 0, temperature);
|
||||
}
|
||||
|
||||
// 1=hot, 2=eco, 3=intelligent
|
||||
// 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)
|
||||
void Boiler::set_warmwater_mode(const uint8_t comfort) {
|
||||
uint8_t set;
|
||||
if (comfort == 1) {
|
||||
LOG_INFO(F("Setting boiler warm water to Hot"));
|
||||
set = 0x00;
|
||||
} else if (comfort == 2) {
|
||||
LOG_INFO(F("Setting boiler warm water to Eco"));
|
||||
set = 0xD8;
|
||||
} else if (comfort == 3) {
|
||||
LOG_INFO(F("Setting boiler warm water to Intelligent"));
|
||||
set = 0xEC;
|
||||
} else {
|
||||
return; // do nothing
|
||||
}
|
||||
write_command(EMS_TYPE_UBAParameterWW, 9, set);
|
||||
}
|
||||
|
||||
// turn on/off warm water
|
||||
void Boiler::set_warmwater_activated(const bool activated) {
|
||||
LOG_INFO(F("Setting boiler warm water %s"), activated ? "on" : "off");
|
||||
uint8_t value;
|
||||
|
||||
// https://github.com/proddy/EMS-ESP/issues/268
|
||||
if (EMSbus::is_ht3()) {
|
||||
value = (activated ? 0x08 : 0x00); // 0x08 is on, 0x00 is off
|
||||
} else {
|
||||
value = (activated ? 0xFF : 0x00); // 0xFF is on, 0x00 is off
|
||||
}
|
||||
write_command(EMS_TYPE_UBAParameterWW, 1, value);
|
||||
}
|
||||
|
||||
// Activate / De-activate the Warm Tap Water
|
||||
// true = on, false = off
|
||||
// Note: Using the type 0x1D to put the boiler into Test mode. This may be shown on the boiler with a flashing 'T'
|
||||
void Boiler::set_tapwarmwater_activated(const bool activated) {
|
||||
LOG_INFO(F("Setting boiler warm tap water %s"), activated ? "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;
|
||||
}
|
||||
|
||||
// we use the special test mode 0x1D for this. Setting the first data to 5A puts the system into test mode and
|
||||
// a setting of 0x00 puts it back into normal operating mode
|
||||
// when in test mode we're able to mess around with the 3-way valve settings
|
||||
if (!activated) {
|
||||
// on
|
||||
message_data[0] = 0x5A; // test mode on
|
||||
message_data[1] = 0x00; // burner output 0%
|
||||
message_data[3] = 0x64; // boiler pump capacity 100%
|
||||
message_data[4] = 0xFF; // 3-way valve hot water only
|
||||
} 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);
|
||||
}
|
||||
|
||||
// Activate / De-activate One Time warm water 0x35
|
||||
// true = on, false = off
|
||||
// See also https://github.com/proddy/EMS-ESP/issues/341#issuecomment-596245458 for Junkers
|
||||
void Boiler::set_warmwater_onetime(const bool activated) {
|
||||
LOG_INFO(F("Setting boiler warm water OneTime loading %s"), activated ? "on" : "off");
|
||||
write_command(EMS_TYPE_UBAFlags, 0, (activated ? 0x22 : 0x02));
|
||||
}
|
||||
|
||||
// Activate / De-activate circulation of warm water 0x35
|
||||
// true = on, false = off
|
||||
void Boiler::set_warmwater_circulation(const bool activated) {
|
||||
LOG_INFO(F("Setting boiler warm water circulation %s"), activated ? "on" : "off");
|
||||
write_command(EMS_TYPE_UBAFlags, 1, (activated ? 0x22 : 0x02));
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Boiler::console_commands(Shell & shell, unsigned int context) {
|
||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(read)},
|
||||
flash_string_vector{F_(typeid_mandatory)},
|
||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
||||
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
|
||||
EMSESP::send_read_request(type_id, device_id());
|
||||
});
|
||||
|
||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(wwtemp)},
|
||||
flash_string_vector{F_(degrees_mandatory)},
|
||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
||||
set_warmwater_temp(Helpers::atoint(arguments.front().c_str()));
|
||||
});
|
||||
|
||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(flowtemp)},
|
||||
flash_string_vector{F_(degrees_mandatory)},
|
||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
||||
set_flow_temp(Helpers::atoint(arguments.front().c_str()));
|
||||
});
|
||||
|
||||
EMSESPShell::commands->add_command(
|
||||
ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(wwactive)},
|
||||
flash_string_vector{F_(bool_mandatory)},
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
||||
if (arguments[0] == read_flash_string(F_(on))) {
|
||||
set_warmwater_activated(true);
|
||||
} else if (arguments[0] == read_flash_string(F_(off))) {
|
||||
set_warmwater_activated(false);
|
||||
} else {
|
||||
shell.println(F("Must be on or off"));
|
||||
return;
|
||||
}
|
||||
},
|
||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
||||
return std::vector<std::string>{read_flash_string(F_(on)), read_flash_string(F_(off))};
|
||||
});
|
||||
|
||||
EMSESPShell::commands->add_command(
|
||||
ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(wwonetime)},
|
||||
flash_string_vector{F_(bool_mandatory)},
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
||||
if (arguments[0] == read_flash_string(F_(on))) {
|
||||
set_warmwater_onetime(true);
|
||||
} else if (arguments[0] == read_flash_string(F_(off))) {
|
||||
set_warmwater_onetime(false);
|
||||
} else {
|
||||
shell.println(F("Must be on or off"));
|
||||
return;
|
||||
}
|
||||
},
|
||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
||||
return std::vector<std::string>{read_flash_string(F_(on)), read_flash_string(F_(off))};
|
||||
});
|
||||
|
||||
EMSESPShell::commands->add_command(
|
||||
ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(wwcirculation)},
|
||||
flash_string_vector{F_(bool_mandatory)},
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
||||
if (arguments[0] == read_flash_string(F_(on))) {
|
||||
set_warmwater_circulation(true);
|
||||
} else if (arguments[0] == read_flash_string(F_(off))) {
|
||||
set_warmwater_circulation(false);
|
||||
} else {
|
||||
shell.println(F("Must be on or off"));
|
||||
return;
|
||||
}
|
||||
},
|
||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
||||
return std::vector<std::string>{read_flash_string(F_(on)), read_flash_string(F_(off))};
|
||||
});
|
||||
|
||||
EMSESPShell::commands->add_command(
|
||||
ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(comfort)},
|
||||
flash_string_vector{F_(comfort_mandatory)},
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
||||
if (arguments[0] == read_flash_string(F_(hot))) {
|
||||
set_warmwater_mode(1);
|
||||
} else if (arguments[0] == read_flash_string(F_(eco))) {
|
||||
set_warmwater_mode(2);
|
||||
} else if (arguments[0] == read_flash_string(F_(intelligent))) {
|
||||
set_warmwater_mode(3);
|
||||
} else {
|
||||
shell.println(F("Invalid value. Must be hot, eco or intelligent"));
|
||||
}
|
||||
},
|
||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
||||
return std::vector<std::string>{read_flash_string(F_(hot)), read_flash_string(F_(eco)), read_flash_string(F_(intelligent))};
|
||||
});
|
||||
|
||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(show)},
|
||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { show_values(shell); });
|
||||
|
||||
// enter the context
|
||||
Console::enter_custom_context(shell, context);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
168
src/devices/boiler.h
Normal file
168
src/devices/boiler.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_BOILER_H
|
||||
#define EMSESP_BOILER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "emsesp.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Boiler : public EMSdevice {
|
||||
public:
|
||||
Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands(Shell & shell, unsigned int context);
|
||||
|
||||
uint8_t last_boilerState = 0xFF; // remember last state of heating and warm water on/off
|
||||
|
||||
static constexpr uint8_t EMS_TYPE_UBAParameterWW = 0x33;
|
||||
static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D;
|
||||
static constexpr uint8_t EMS_TYPE_UBAFlags = 0x35;
|
||||
static constexpr uint8_t EMS_TYPE_UBASetPoints = 0x1A;
|
||||
|
||||
static constexpr uint8_t EMS_BOILER_SELFLOWTEMP_HEATING = 20; // was originally 70, changed to 30 for issue #193, then to 20 with issue #344
|
||||
|
||||
// UBAParameterWW
|
||||
uint8_t wWActivated_ = EMS_VALUE_BOOL_NOTSET; // Warm Water activated
|
||||
uint8_t wWSelTemp_ = EMS_VALUE_UINT_NOTSET; // Warm Water selected temperature
|
||||
uint8_t wWCircPump_ = EMS_VALUE_BOOL_NOTSET; // Warm Water circulation pump available
|
||||
uint8_t wWCircPumpMode_ = EMS_VALUE_UINT_NOTSET; // Warm Water circulation pump mode
|
||||
uint8_t wWCircPumpType_ = EMS_VALUE_BOOL_NOTSET; // Warm Water circulation pump type
|
||||
uint8_t wWDisinfectTemp_ = EMS_VALUE_UINT_NOTSET; // Warm Water disinfection temperature to prevent infection
|
||||
uint8_t wWComfort_ = EMS_VALUE_UINT_NOTSET; // WW comfort mode
|
||||
|
||||
// MC10Status
|
||||
uint16_t wwMixTemperature_ = EMS_VALUE_USHORT_NOTSET; // mengertemperatuur
|
||||
uint16_t wwBufferBoilerTemperature_ = EMS_VALUE_USHORT_NOTSET; // bufferboilertemperatuur
|
||||
|
||||
// UBAMonitorFast - 0x18 on EMS1
|
||||
uint8_t selFlowTemp_ = EMS_VALUE_UINT_NOTSET; // Selected flow temperature
|
||||
uint16_t curFlowTemp_ = EMS_VALUE_USHORT_NOTSET; // Current flow temperature
|
||||
uint16_t wwStorageTemp1_ = EMS_VALUE_USHORT_NOTSET; // warm water storage temp 1
|
||||
uint16_t wwStorageTemp2_ = EMS_VALUE_USHORT_NOTSET; // warm water storage temp 2
|
||||
uint16_t retTemp_ = EMS_VALUE_USHORT_NOTSET; // Return temperature
|
||||
uint8_t burnGas_ = EMS_VALUE_BOOL_NOTSET; // Gas on/off
|
||||
uint8_t fanWork_ = EMS_VALUE_BOOL_NOTSET; // Fan on/off
|
||||
uint8_t ignWork_ = EMS_VALUE_BOOL_NOTSET; // Ignition on/off
|
||||
uint8_t heatPmp_ = EMS_VALUE_BOOL_NOTSET; // Boiler pump on/off
|
||||
uint8_t wWHeat_ = EMS_VALUE_BOOL_NOTSET; // 3-way valve on WW
|
||||
uint8_t wWCirc_ = EMS_VALUE_BOOL_NOTSET; // Circulation on/off
|
||||
uint8_t selBurnPow_ = EMS_VALUE_UINT_NOTSET; // Burner max power %
|
||||
uint8_t curBurnPow_ = EMS_VALUE_UINT_NOTSET; // Burner current power %
|
||||
uint16_t flameCurr_ = EMS_VALUE_USHORT_NOTSET; // Flame current in micro amps
|
||||
uint8_t sysPress_ = EMS_VALUE_UINT_NOTSET; // System pressure
|
||||
char serviceCodeChar_[3] = {'\0'}; // 2 character status/service code
|
||||
uint16_t serviceCode_ = EMS_VALUE_USHORT_NOTSET; // error/service code
|
||||
|
||||
// UBAMonitorSlow - 0x19 on EMS1
|
||||
int16_t extTemp_ = EMS_VALUE_SHORT_NOTSET; // Outside temperature
|
||||
uint16_t boilTemp_ = EMS_VALUE_USHORT_NOTSET; // Boiler temperature
|
||||
uint16_t exhaustTemp_ = EMS_VALUE_USHORT_NOTSET; // Exhaust temperature
|
||||
uint8_t pumpMod_ = EMS_VALUE_UINT_NOTSET; // Pump modulation %
|
||||
uint32_t burnStarts_ = EMS_VALUE_ULONG_NOTSET; // # burner restarts
|
||||
uint32_t burnWorkMin_ = EMS_VALUE_ULONG_NOTSET; // Total burner operating time
|
||||
uint32_t heatWorkMin_ = EMS_VALUE_ULONG_NOTSET; // Total heat operating time
|
||||
uint16_t switchTemp_ = EMS_VALUE_USHORT_NOTSET; // Switch temperature
|
||||
|
||||
// UBAMonitorWW
|
||||
uint8_t wWSetTmp_ = EMS_VALUE_UINT_NOTSET; // Warm Water set temperature
|
||||
uint16_t wWCurTmp_ = EMS_VALUE_USHORT_NOTSET; // Warm Water current temperature
|
||||
uint16_t wWCurTmp2_ = EMS_VALUE_USHORT_NOTSET; // Warm Water current temperature storage
|
||||
uint32_t wWStarts_ = EMS_VALUE_ULONG_NOTSET; // Warm Water # starts
|
||||
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 wWDesinfecting_ = EMS_VALUE_BOOL_NOTSET; // Warm Water disinfection on/off
|
||||
uint8_t wWReadiness_ = EMS_VALUE_BOOL_NOTSET; // Warm Water readiness 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
|
||||
|
||||
// UBATotalUptime
|
||||
uint32_t UBAuptime_ = EMS_VALUE_ULONG_NOTSET; // Total UBA working hours
|
||||
|
||||
// UBAParameters
|
||||
uint8_t heating_temp_ = EMS_VALUE_UINT_NOTSET; // Heating temperature setting on the boiler
|
||||
uint8_t pump_mod_max_ = EMS_VALUE_UINT_NOTSET; // Boiler circuit pump modulation max. power %
|
||||
uint8_t pump_mod_min_ = EMS_VALUE_UINT_NOTSET; // Boiler circuit pump modulation min. power
|
||||
|
||||
uint8_t tap_water_active_ = EMS_VALUE_BOOL_NOTSET; // Hot tap water is on/off
|
||||
uint8_t heating_active_ = EMS_VALUE_BOOL_NOTSET; // Central heating is on/off
|
||||
|
||||
uint8_t pumpMod2_ = EMS_VALUE_UINT_NOTSET; // heatpump modulation from 0xE3 (heatpumps)
|
||||
|
||||
void process_UBAParameterWW(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBATotalUptime(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAParameters(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorSlowPlus2(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_UBAOutdoorTemp(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBASetPoints(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAFlags(std::shared_ptr<const Telegram> telegram);
|
||||
void process_MC10Status(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMaintenanceStatus(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMaintenanceSettings(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_UBADHWStatus(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void check_active();
|
||||
|
||||
void set_warmwater_temp(const uint8_t temperature);
|
||||
void set_flow_temp(const uint8_t temperature);
|
||||
void set_warmwater_mode(const uint8_t comfort);
|
||||
void set_warmwater_activated(const bool activated);
|
||||
void set_tapwarmwater_activated(const bool activated);
|
||||
void set_warmwater_onetime(const bool activated);
|
||||
void set_warmwater_circulation(const bool activated);
|
||||
|
||||
// mqtt callbacks
|
||||
void boiler_cmd(const char * message);
|
||||
void boiler_cmd_wwactivated(const char * message);
|
||||
void boiler_cmd_wwonetime(const char * message);
|
||||
void boiler_cmd_wwcirculation(const char * message);
|
||||
void boiler_cmd_wwtemp(const char * message);
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
58
src/devices/connect.cpp
Normal file
58
src/devices/connect.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "connect.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Connect, EMSdevice::DeviceType::CONNECT);
|
||||
|
||||
MAKE_PSTR(logger_name, "connect")
|
||||
uuid::log::Logger Connect::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
// telegram handlers
|
||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
||||
|
||||
// MQTT callbacks
|
||||
// register_mqtt_topic("cmd", std::bind(&Controller::cmd, this, _1));
|
||||
}
|
||||
|
||||
void Connect::add_context_menu() {
|
||||
}
|
||||
|
||||
// display all values into the shell console
|
||||
void Connect::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Connect::publish_values() {
|
||||
}
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Connect::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Connect::console_commands() {
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
51
src/devices/connect.h
Normal file
51
src/devices/connect.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_CONNECT_H
|
||||
#define EMSESP_CONNECT_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Connect : public EMSdevice {
|
||||
public:
|
||||
Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
60
src/devices/controller.cpp
Normal file
60
src/devices/controller.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
// MAKE_PSTR_WORD(controller)
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER);
|
||||
|
||||
MAKE_PSTR(logger_name, "controller")
|
||||
uuid::log::Logger Controller::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
// telegram handlers
|
||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
||||
|
||||
// MQTT callbacks
|
||||
// register_mqtt_topic("cmd", std::bind(&Controller::cmd, this, _1));
|
||||
}
|
||||
|
||||
void Controller::add_context_menu() {
|
||||
}
|
||||
|
||||
// display all values into the shell console
|
||||
void Controller::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Controller::publish_values() {
|
||||
}
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Controller::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Controller::console_commands() {
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
51
src/devices/controller.h
Normal file
51
src/devices/controller.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_CONTROLLER_H
|
||||
#define EMSESP_CONTROLLER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Controller : public EMSdevice {
|
||||
public:
|
||||
Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
60
src/devices/gateway.cpp
Normal file
60
src/devices/gateway.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gateway.h"
|
||||
|
||||
// MAKE_PSTR_WORD(gateway)
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Gateway, EMSdevice::DeviceType::GATEWAY);
|
||||
|
||||
MAKE_PSTR(logger_name, "gateway")
|
||||
uuid::log::Logger Gateway::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Gateway::Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
// telegram handlers
|
||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
||||
|
||||
// MQTT callbacks
|
||||
// register_mqtt_topic("cmd", std::bind(&Controller::cmd, this, _1));
|
||||
}
|
||||
|
||||
void Gateway::add_context_menu() {
|
||||
}
|
||||
|
||||
// display all values into the shell console
|
||||
void Gateway::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Gateway::publish_values() {
|
||||
}
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Gateway::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Gateway::console_commands() {
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
51
src/devices/gateway.h
Normal file
51
src/devices/gateway.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_GATEWAY_H
|
||||
#define EMSESP_GATEWAY_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Gateway : public EMSdevice {
|
||||
public:
|
||||
Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
92
src/devices/heatpump.cpp
Normal file
92
src/devices/heatpump.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "heatpump.h"
|
||||
|
||||
// MAKE_PSTR_WORD(heatpump)
|
||||
|
||||
/*
|
||||
example telegrams 0x32B, 0x37B
|
||||
"38 10 FF 00 03 7B 08 24 00 4B",
|
||||
"38 10 FF 00 03 2B 00 C7 07 C3 01",
|
||||
"38 10 FF 00 03 2B 00 D1 08 2A 01",
|
||||
*/
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Heatpump, EMSdevice::DeviceType::HEATPUMP);
|
||||
|
||||
MAKE_PSTR(logger_name, "heatpump")
|
||||
uuid::log::Logger Heatpump::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
LOG_DEBUG(F("Registering new Heat Pump module with device ID 0x%02X"), device_id);
|
||||
|
||||
// telegram handlers
|
||||
register_telegram_type(0x047B, F("HP1"), true, std::bind(&Heatpump::process_HPMonitor1, this, _1));
|
||||
register_telegram_type(0x042B, F("HP2"), true, std::bind(&Heatpump::process_HPMonitor2, this, _1));
|
||||
|
||||
// MQTT callbacks
|
||||
// register_mqtt_topic("cmd", std::bind(&Heatpump::cmd, this, _1));
|
||||
}
|
||||
|
||||
// context submenu
|
||||
void Heatpump::add_context_menu() {
|
||||
}
|
||||
|
||||
// display all values into the shell console
|
||||
void Heatpump::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Heatpump::publish_values() {
|
||||
}
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Heatpump::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Heatpump::console_commands() {
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
/*
|
||||
* Type 0x42B- HeatPump Monitor 1
|
||||
* e.g. "38 10 FF 00 03 2B 00 D1 08 2A 01"
|
||||
*/
|
||||
void Heatpump::process_HPMonitor1(std::shared_ptr<const Telegram> telegram) {
|
||||
// still to implement
|
||||
}
|
||||
|
||||
/*
|
||||
* Type 0x47B - HeatPump Monitor 2
|
||||
* e.g. "38 10 FF 00 03 7B 08 24 00 4B"
|
||||
*/
|
||||
void Heatpump::process_HPMonitor2(std::shared_ptr<const Telegram> telegram) {
|
||||
// still to implement
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
} // namespace emsesp
|
||||
54
src/devices/heatpump.h
Normal file
54
src/devices/heatpump.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_HEATPUMP_H
|
||||
#define EMSESP_HEATPUMP_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Heatpump : public EMSdevice {
|
||||
public:
|
||||
Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
|
||||
void process_HPMonitor1(std::shared_ptr<const Telegram> telegram);
|
||||
void process_HPMonitor2(std::shared_ptr<const Telegram> telegram);
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
213
src/devices/mixing.cpp
Normal file
213
src/devices/mixing.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mixing.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Mixing, EMSdevice::DeviceType::MIXING);
|
||||
|
||||
MAKE_PSTR(logger_name, "mixing")
|
||||
uuid::log::Logger Mixing::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
LOG_DEBUG(F("Registering new Mixing module with device ID 0x%02X"), device_id);
|
||||
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
|
||||
if (device_id <= 0x27) {
|
||||
// telegram handlers 0x20 - 0x27 for HC
|
||||
register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_HC, this, _1));
|
||||
} else {
|
||||
// telegram handlers for warm water/DHW 0x28, 0x29
|
||||
register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_WWC, this, _1));
|
||||
}
|
||||
}
|
||||
// EMS 1.0
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) {
|
||||
register_telegram_type(0x00AA, F("MMConfigMessage"), false, std::bind(&Mixing::process_MMConfigMessage, this, _1));
|
||||
register_telegram_type(0x00AB, F("MMStatusMessage"), true, std::bind(&Mixing::process_MMStatusMessage, this, _1));
|
||||
register_telegram_type(0x00AC, F("MMSetMessage"), false, std::bind(&Mixing::process_MMSetMessage, this, _1));
|
||||
}
|
||||
// HT3
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
|
||||
register_telegram_type(0x010C, F("IPMSetMessage"), false, std::bind(&Mixing::process_IPMStatusMessage, this, _1));
|
||||
}
|
||||
|
||||
// MQTT callbacks
|
||||
// register_mqtt_topic("cmd", std::bind(&Mixing::cmd, this, _1));
|
||||
}
|
||||
|
||||
// add context submenu
|
||||
void Mixing::add_context_menu() {
|
||||
}
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Mixing::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Mixing::console_commands() {
|
||||
}
|
||||
|
||||
// display all values into the shell console
|
||||
void Mixing::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
|
||||
if (type_ == Type::NONE) {
|
||||
return; // don't have any values yet
|
||||
}
|
||||
|
||||
if (type_ == Type::WWC) {
|
||||
print_value(shell, 2, F("Warm Water Circuit"), hc_, nullptr);
|
||||
} else {
|
||||
print_value(shell, 2, F("Heating Circuit"), hc_, nullptr);
|
||||
}
|
||||
print_value(shell, 4, F("Current flow temperature"), flowTemp_, F_(degrees), 10);
|
||||
print_value(shell, 4, F("Setpoint flow temperature"), flowSetTemp_, F_(degrees));
|
||||
print_value(shell, 4, F("Current pump modulation"), pumpMod_, F_(percent));
|
||||
print_value(shell, 4, F("Current valve status"), status_, nullptr);
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
// ideally we should group up all the mixing units together into a nested JSON but for now we'll send them individually
|
||||
void Mixing::publish_values() {
|
||||
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_SMALL);
|
||||
|
||||
switch (type_) {
|
||||
case Type::HC:
|
||||
doc["type"] = "hc";
|
||||
break;
|
||||
case Type::WWC:
|
||||
doc["type"] = "wwc";
|
||||
break;
|
||||
case Type::NONE:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(flowTemp_)) {
|
||||
doc["flowTemp"] = (float)flowTemp_ / 10;
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(pumpMod_)) {
|
||||
doc["pumpMod"] = pumpMod_;
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(status_)) {
|
||||
doc["status"] = status_;
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(flowSetTemp_)) {
|
||||
doc["flowSetTemp"] = flowSetTemp_;
|
||||
}
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
LOG_DEBUG(F("[DEBUG] Performing a mixing module publish"));
|
||||
#endif
|
||||
char topic[30];
|
||||
char s[3]; // for formatting strings
|
||||
strlcpy(topic, "mixing_data", 30);
|
||||
strlcat(topic, Helpers::itoa(s, device_id() - 0x20 + 1), 30); // append hc to topic
|
||||
Mqtt::publish(topic, doc);
|
||||
}
|
||||
|
||||
// heating circuits 0x02D7, 0x02D8 etc...
|
||||
// e.g. A0 00 FF 00 01 D7 00 00 00 80 00 00 00 00 03 C5
|
||||
// A0 0B FF 00 01 D7 00 00 00 80 00 00 00 00 03 80
|
||||
void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram) {
|
||||
type_ = Type::HC;
|
||||
hc_ = telegram->type_id - 0x02D7 + 1; // determine which circuit this is
|
||||
telegram->read_value(flowTemp_, 3); // is * 10
|
||||
telegram->read_value(flowSetTemp_, 5);
|
||||
telegram->read_value(pumpMod_, 2);
|
||||
telegram->read_value(status_, 1); // valve status
|
||||
}
|
||||
|
||||
// Mixing module warm water loading/DHW - 0x0331, 0x0332
|
||||
// e.g. A9 00 FF 00 02 32 02 6C 00 3C 00 3C 3C 46 02 03 03 00 3C // on 0x28
|
||||
// A8 00 FF 00 02 31 02 35 00 3C 00 3C 3C 46 02 03 03 00 3C // in 0x29
|
||||
void Mixing::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram) {
|
||||
type_ = Type::WWC;
|
||||
hc_ = telegram->type_id - 0x0331 + 1; // determine which circuit this is. There are max 2.
|
||||
telegram->read_value(flowTemp_, 0); // is * 10
|
||||
telegram->read_value(pumpMod_, 2);
|
||||
telegram->read_value(status_, 11); // temp status
|
||||
}
|
||||
|
||||
// Mixing IMP - 0x010C
|
||||
// e.g. A0 00 FF 00 00 0C 01 00 00 00 00 00 54
|
||||
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
||||
void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||
type_ = Type::HC;
|
||||
hc_ = device_id() - 0x20 + 1;
|
||||
uint8_t ismixed = 0;
|
||||
telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed
|
||||
if (ismixed == 0) {
|
||||
return;
|
||||
}
|
||||
if (ismixed == 2) { // we have a mixed circuit
|
||||
telegram->read_value(flowTemp_, 3); // is * 10
|
||||
telegram->read_value(flowSetTemp_, 5);
|
||||
telegram->read_value(status_, 2); // valve status
|
||||
}
|
||||
uint8_t pump = 0xFF;
|
||||
telegram->read_bitvalue(pump, 1, 0); // pump is also in unmixed circuits
|
||||
if (pump != 0xFF) {
|
||||
pumpMod_ = 100 * pump;
|
||||
}
|
||||
}
|
||||
|
||||
// Mixing on a MM10 - 0xAB
|
||||
// e.g. Mixing Module -> All, type 0xAB, telegram: 21 00 AB 00 2D 01 BE 64 04 01 00 (CRC=15) #data=7
|
||||
// see also https://github.com/proddy/EMS-ESP/issues/386
|
||||
void Mixing::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||
type_ = Type::HC;
|
||||
|
||||
// the heating circuit is determine by which device_id it is, 0x20 - 0x23
|
||||
// 0x21 is position 2. 0x20 is typically reserved for the WM10 switch module
|
||||
// see https://github.com/proddy/EMS-ESP/issues/270 and https://github.com/proddy/EMS-ESP/issues/386#issuecomment-629610918
|
||||
hc_ = device_id() - 0x20 + 1;
|
||||
telegram->read_value(flowTemp_, 1); // is * 10
|
||||
telegram->read_value(pumpMod_, 3);
|
||||
telegram->read_value(flowSetTemp_, 0);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
// Mixing on a MM10 - 0xAA
|
||||
// e.g. Thermostat -> Mixing Module, type 0xAA, telegram: 10 21 AA 00 FF 0C 0A 11 0A 32 xx
|
||||
void Mixing::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
|
||||
hc_ = device_id() - 0x20 + 1;
|
||||
// pos 0: active FF = on
|
||||
// pos 1: valve runtime 0C = 120 sec in units of 10 sec
|
||||
}
|
||||
|
||||
// Mixing on a MM10 - 0xAC
|
||||
// e.g. Thermostat -> Mixing Module, type 0xAC, telegram: 10 21 AC 00 1E 64 01 AB
|
||||
void Mixing::process_MMSetMessage(std::shared_ptr<const Telegram> telegram) {
|
||||
hc_ = device_id() - 0x20 + 1;
|
||||
// pos 0: flowtemp setpoint 1E = 30°C
|
||||
// pos 1: position in %
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
} // namespace emsesp
|
||||
72
src/devices/mixing.h
Normal file
72
src/devices/mixing.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_MIXING_H
|
||||
#define EMSESP_MIXING_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Mixing : public EMSdevice {
|
||||
public:
|
||||
Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
|
||||
void process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram);
|
||||
void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram);
|
||||
void process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_MMStatusMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_MMConfigMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_MMSetMessage(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
enum class Type {
|
||||
NONE,
|
||||
HC, // heating circuit
|
||||
WWC // warm water circuit
|
||||
};
|
||||
|
||||
private:
|
||||
uint16_t hc_ = EMS_VALUE_USHORT_NOTSET;
|
||||
uint16_t flowTemp_ = EMS_VALUE_USHORT_NOTSET;
|
||||
uint8_t pumpMod_ = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t status_ = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t flowSetTemp_ = EMS_VALUE_UINT_NOTSET;
|
||||
Type type_ = Type::NONE;
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
236
src/devices/solar.cpp
Normal file
236
src/devices/solar.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "solar.h"
|
||||
|
||||
MAKE_PSTR(kwh, "kWh")
|
||||
MAKE_PSTR(wh, "Wh")
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Solar, EMSdevice::DeviceType::SOLAR);
|
||||
|
||||
MAKE_PSTR(logger_name, "solar")
|
||||
uuid::log::Logger Solar::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
LOG_DEBUG(F("Registering new Solar module with device ID 0x%02X"), device_id);
|
||||
|
||||
// telegram handlers
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
|
||||
register_telegram_type(0x0097, F("SM10Monitor"), true, std::bind(&Solar::process_SM10Monitor, this, _1));
|
||||
}
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
|
||||
register_telegram_type(0x0362, F("SM100Monitor"), true, std::bind(&Solar::process_SM100Monitor, this, _1));
|
||||
register_telegram_type(0x0363, F("SM100Monitor2"), true, std::bind(&Solar::process_SM100Monitor2, this, _1));
|
||||
register_telegram_type(0x0366, F("SM100Config"), true, std::bind(&Solar::process_SM100Config, this, _1));
|
||||
|
||||
register_telegram_type(0x0364, F("SM100Status"), false, std::bind(&Solar::process_SM100Status, this, _1));
|
||||
register_telegram_type(0x036A, F("SM100Status2"), false, std::bind(&Solar::process_SM100Status2, this, _1));
|
||||
register_telegram_type(0x038E, F("SM100Energy"), true, std::bind(&Solar::process_SM100Energy, this, _1));
|
||||
}
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
|
||||
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, std::bind(&Solar::process_ISM1StatusMessage, this, _1));
|
||||
register_telegram_type(0x0101, F("ISM1Set"), false, std::bind(&Solar::process_ISM1Set, this, _1));
|
||||
}
|
||||
|
||||
// MQTT callbacks
|
||||
// register_mqtt_topic("cmd", std::bind(&Solar::cmd, this, _1));
|
||||
}
|
||||
|
||||
// context submenu
|
||||
void Solar::add_context_menu() {
|
||||
}
|
||||
|
||||
// display all values into the shell console
|
||||
void Solar::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
|
||||
print_value(shell, 2, F("Collector temperature (TS1)"), collectorTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Bottom temperature (TS2)"), bottomTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Bottom temperature (TS5)"), bottomTemp2_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Pump modulation"), pumpModulation_, F_(percent));
|
||||
print_value(shell, 2, F("Valve (VS2) status"), valveStatus_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Pump (PS1) active"), pump_, nullptr, EMS_VALUE_BOOL);
|
||||
|
||||
if (Helpers::hasValue(pumpWorkMin_)) {
|
||||
shell.printfln(F(" Pump working time: %d days %d hours %d minutes"), pumpWorkMin_ / 1440, (pumpWorkMin_ % 1440) / 60, pumpWorkMin_ % 60);
|
||||
}
|
||||
|
||||
print_value(shell, 2, F("Energy last hour"), energyLastHour_, F_(wh), 10);
|
||||
print_value(shell, 2, F("Energy today"), energyToday_, F_(wh));
|
||||
print_value(shell, 2, F("Energy total"), energyTotal_, F_(kwh), 10);
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Solar::publish_values() {
|
||||
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_MEDIUM);
|
||||
|
||||
char s[10]; // for formatting strings
|
||||
|
||||
if (Helpers::hasValue(collectorTemp_)) {
|
||||
doc["collectortemp"] = (float)collectorTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(bottomTemp_)) {
|
||||
doc["bottomtemp"] = (float)bottomTemp_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(bottomTemp2_)) {
|
||||
doc["bottomtemp2"] = (float)bottomTemp2_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(pumpModulation_)) {
|
||||
doc["pumpmodulation"] = pumpModulation_;
|
||||
}
|
||||
if (Helpers::hasValue(pump_, true)) {
|
||||
doc["pump"] = Helpers::render_value(s, pump_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(valveStatus_, true)) {
|
||||
doc["valvestatus"] = Helpers::render_value(s, valveStatus_, EMS_VALUE_BOOL);
|
||||
}
|
||||
if (Helpers::hasValue(pumpWorkMin_)) {
|
||||
doc["pumpWorkMin"] = (float)pumpWorkMin_;
|
||||
}
|
||||
if (Helpers::hasValue(energyLastHour_)) {
|
||||
doc["energylasthour"] = (float)energyLastHour_ / 10;
|
||||
}
|
||||
if (Helpers::hasValue(energyToday_)) {
|
||||
doc["energytoday"] = energyToday_;
|
||||
}
|
||||
if (Helpers::hasValue(energyTotal_)) {
|
||||
doc["energytotal"] = (float)energyTotal_ / 10;
|
||||
}
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
LOG_DEBUG(F("[DEBUG] Performing a solar module publish"));
|
||||
#endif
|
||||
|
||||
Mqtt::publish("sm_data", doc);
|
||||
}
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Solar::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Solar::console_commands() {
|
||||
}
|
||||
|
||||
// SM10Monitor - type 0x97
|
||||
void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10
|
||||
telegram->read_value(bottomTemp_, 5); // bottom temp from SM10, is *10
|
||||
telegram->read_value(pumpModulation_, 4); // modulation solar pump
|
||||
telegram->read_bitvalue(pump_, 7, 1);
|
||||
telegram->read_value(pumpWorkMin_, 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* SM100Monitor - type 0x0362 EMS+ - for SM100 and SM200
|
||||
* e.g. B0 0B FF 00 02 62 00 44 02 7A 80 00 80 00 80 00 80 00 80 00 80 00 00 7C 80 00 80 00 80 00 80
|
||||
* e.g, 30 00 FF 00 02 62 01 AC
|
||||
* 30 00 FF 18 02 62 80 00
|
||||
* 30 00 FF 00 02 62 01 A1 - for bottom temps
|
||||
* bytes 0+1 = TS1 Temperature sensor for collector
|
||||
* bytes 2+3 = TS2 Temperature sensor bottom cylinder 1
|
||||
* bytes 16+17 = TS5 Temperature sensor bottom cylinder 2
|
||||
*/
|
||||
void Solar::process_SM100Monitor(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(collectorTemp_, 0); // is *10
|
||||
telegram->read_value(bottomTemp_, 2); // is *10
|
||||
telegram->read_value(bottomTemp2_, 16); // is *10
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
// SM100Monitor2 - 0x0363
|
||||
// e.g. B0 00 FF 00 02 63 80 00 80 00 00 00 80 00 80 00 80 00 00 80 00 5A
|
||||
void Solar::process_SM100Monitor2(std::shared_ptr<const Telegram> telegram) {
|
||||
// not implemented yet
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// SM100Config - 0x0366
|
||||
// e.g. B0 00 FF 00 02 66 01 62 00 13 40 14
|
||||
void Solar::process_SM100Config(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(availabilityFlag_, 0);
|
||||
telegram->read_value(configFlag_, 1);
|
||||
telegram->read_value(userFlag_, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* SM100Status - type 0x0364 EMS+ for pump modulation - for SM100 and SM200
|
||||
* e.g. 30 00 FF 09 02 64 64 = 100%
|
||||
* 30 00 FF 09 02 64 1E = 30%
|
||||
*/
|
||||
void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) {
|
||||
uint8_t pumpmod = pumpModulation_;
|
||||
telegram->read_value(pumpModulation_, 9);
|
||||
if (pumpmod == 0 && pumpModulation_ == 100) { // mask out boosts
|
||||
pumpModulation_ = 15; // set to minimum
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SM100Status2 - type 0x036A EMS+ for pump on/off at offset 0x0A - for SM100 and SM200
|
||||
* e.g. B0 00 FF 00 02 6A 03 03 03 03 01 03 03 03 03 03 01 03
|
||||
* byte 4 = VS2 3-way valve for cylinder 2 : test=01, on=04 and off=03
|
||||
* byte 10 = PS1 Solar circuit pump for collector array 1: test=b0001(1), on=b0100(4) and off=b0011(3)
|
||||
*/
|
||||
void Solar::process_SM100Status2(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_bitvalue(valveStatus_, 4, 2); // on if bit 2 set
|
||||
telegram->read_bitvalue(pump_, 10, 2); // on if bit 2 set
|
||||
}
|
||||
|
||||
/*
|
||||
* SM100Energy - type 0x038E EMS+ for energy readings
|
||||
* e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35
|
||||
*/
|
||||
void Solar::process_SM100Energy(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(energyLastHour_, 0); // last hour / 10 in Wh
|
||||
telegram->read_value(energyToday_, 4); // todays in Wh
|
||||
telegram->read_value(energyTotal_, 8); // total / 10 in kWh
|
||||
}
|
||||
|
||||
/*
|
||||
* Junkers ISM1 Solar Module - type 0x0103 EMS+ for energy readings
|
||||
* e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0
|
||||
*/
|
||||
void Solar::process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(collectorTemp_, 4); // Collector Temperature
|
||||
telegram->read_value(bottomTemp_, 6); // Temperature Bottom of Solar Boiler
|
||||
uint16_t Wh = 0xFFFF;
|
||||
telegram->read_value(Wh, 2); // Solar Energy produced in last hour only ushort, is not * 10
|
||||
if (Wh != 0xFFFF) {
|
||||
energyLastHour_ = Wh * 10; // set to *10
|
||||
}
|
||||
telegram->read_bitvalue(pump_, 8, 0); // Solar pump on (1) or off (0)
|
||||
telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes
|
||||
}
|
||||
|
||||
/*
|
||||
* Junkers ISM1 Solar Module - type 0x0101 EMS+ for setting values
|
||||
* e.g. 90 30 FF 06 00 01 50
|
||||
*/
|
||||
void Solar::process_ISM1Set(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(setpoint_maxBottomTemp_, 6);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
80
src/devices/solar.h
Normal file
80
src/devices/solar.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_SOLAR_H
|
||||
#define EMSESP_SOLAR_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Solar : public EMSdevice {
|
||||
public:
|
||||
Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
|
||||
int16_t collectorTemp_ = EMS_VALUE_SHORT_NOTSET; // collector temp (TS1)
|
||||
int16_t bottomTemp_ = EMS_VALUE_SHORT_NOTSET; // bottom temp (TS2)
|
||||
int16_t bottomTemp2_ = EMS_VALUE_SHORT_NOTSET; // bottom temp cylinder 2 (TS5)
|
||||
uint8_t pumpModulation_ = EMS_VALUE_UINT_NOTSET; // modulation solar pump
|
||||
uint8_t pump_ = EMS_VALUE_BOOL_NOTSET; // pump active
|
||||
uint8_t valveStatus_ = EMS_VALUE_BOOL_NOTSET; // valve status (VS2)
|
||||
int16_t setpoint_maxBottomTemp_ = EMS_VALUE_SHORT_NOTSET; // setpoint for maximum collector temp
|
||||
uint32_t energyLastHour_ = EMS_VALUE_ULONG_NOTSET;
|
||||
uint32_t energyToday_ = EMS_VALUE_ULONG_NOTSET;
|
||||
uint32_t energyTotal_ = EMS_VALUE_ULONG_NOTSET;
|
||||
uint32_t pumpWorkMin_ = EMS_VALUE_ULONG_NOTSET; // Total solar pump operating time
|
||||
|
||||
uint8_t availabilityFlag_ = EMS_VALUE_BOOL_NOTSET;
|
||||
uint8_t configFlag_ = EMS_VALUE_BOOL_NOTSET;
|
||||
uint8_t userFlag_ = EMS_VALUE_BOOL_NOTSET;
|
||||
|
||||
void process_SM10Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_SM100Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_SM100Monitor2(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_SM100Config(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_SM100Status(std::shared_ptr<const Telegram> telegram);
|
||||
void process_SM100Status2(std::shared_ptr<const Telegram> telegram);
|
||||
void process_SM100Energy(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_ISM1Set(std::shared_ptr<const Telegram> telegram);
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
60
src/devices/switch.cpp
Normal file
60
src/devices/switch.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "switch.h"
|
||||
|
||||
// MAKE_PSTR_WORD(switch)
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
REGISTER_FACTORY(Switch, EMSdevice::DeviceType::SWITCH);
|
||||
|
||||
MAKE_PSTR(logger_name, "switch")
|
||||
uuid::log::Logger Switch::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
||||
|
||||
Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
// telegram handlers
|
||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
||||
|
||||
// MQTT callbacks
|
||||
// register_mqtt_topic("cmd", std::bind(&Controller::cmd, this, _1));
|
||||
}
|
||||
|
||||
void Switch::add_context_menu() {
|
||||
}
|
||||
|
||||
// display all values into the shell console
|
||||
void Switch::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Switch::publish_values() {
|
||||
}
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Switch::updated_values() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Switch::console_commands() {
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
51
src/devices/switch.h
Normal file
51
src/devices/switch.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_SWITCH_H
|
||||
#define EMSESP_SWITCH_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Switch : public EMSdevice {
|
||||
public:
|
||||
Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
1888
src/devices/thermostat.cpp
Normal file
1888
src/devices/thermostat.cpp
Normal file
File diff suppressed because it is too large
Load Diff
272
src/devices/thermostat.h
Normal file
272
src/devices/thermostat.h
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_THERMOSTAT_H
|
||||
#define EMSESP_THERMOSTAT_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "telegram.h"
|
||||
#include "emsesp.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Thermostat : public EMSdevice {
|
||||
public:
|
||||
Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand);
|
||||
class HeatingCircuit {
|
||||
public:
|
||||
HeatingCircuit(const uint8_t hc_num, const uint16_t monitor_typeid, const uint16_t set_typeid)
|
||||
: hc_num_(hc_num)
|
||||
, monitor_typeid_(monitor_typeid)
|
||||
, set_typeid_(set_typeid) {
|
||||
}
|
||||
~HeatingCircuit() = default;
|
||||
|
||||
int16_t setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
int16_t curr_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
uint8_t mode = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t mode_type = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t summer_mode = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t holiday_mode = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t daytemp = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t nighttemp = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t holidaytemp = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t heatingtype = EMS_VALUE_UINT_NOTSET; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
|
||||
uint8_t targetflowtemp = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t summertemp = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t nofrosttemp = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heatingcurve design temp at MinExtTemp
|
||||
int8_t offsettemp = EMS_VALUE_INT_NOTSET; // heatingcurve offest temp at roomtemp signed!
|
||||
|
||||
uint8_t hc_num() const {
|
||||
return hc_num_; // 1..10
|
||||
}
|
||||
|
||||
uint8_t get_mode(uint8_t flags) const;
|
||||
uint8_t get_mode_type(uint8_t flags) const;
|
||||
|
||||
uint16_t monitor_typeid() const {
|
||||
return monitor_typeid_;
|
||||
}
|
||||
|
||||
uint16_t set_typeid() const {
|
||||
return set_typeid_;
|
||||
}
|
||||
|
||||
enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN, SUMMER };
|
||||
|
||||
// for sorting
|
||||
friend inline bool operator<(const std::shared_ptr<HeatingCircuit> & lhs, const std::shared_ptr<HeatingCircuit> & rhs) {
|
||||
return (lhs->hc_num_ < rhs->hc_num_);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t hc_num_; // 1..10
|
||||
uint16_t monitor_typeid_;
|
||||
uint16_t set_typeid_;
|
||||
};
|
||||
|
||||
std::string mode_tostring(uint8_t mode) const;
|
||||
|
||||
virtual void show_values(uuid::console::Shell & shell);
|
||||
virtual void publish_values();
|
||||
virtual bool updated_values();
|
||||
virtual void add_context_menu();
|
||||
|
||||
bool can_write() const {
|
||||
return ((flags() & EMSdevice::EMS_DEVICE_FLAG_NO_WRITE) == EMSdevice::EMS_DEVICE_FLAG_NO_WRITE);
|
||||
}
|
||||
|
||||
// each thermostat has a list of heating controller type IDs for reading and writing
|
||||
std::vector<uint16_t> monitor_typeids;
|
||||
std::vector<uint16_t> set_typeids;
|
||||
std::vector<uint16_t> timer_typeids;
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands(Shell & shell, unsigned int context);
|
||||
void init_mqtt();
|
||||
|
||||
std::string datetime_; // date and time stamp
|
||||
|
||||
uint8_t mqtt_format_; // single, nested or ha
|
||||
|
||||
// Installation parameters
|
||||
uint8_t ibaMainDisplay_ =
|
||||
EMS_VALUE_UINT_NOTSET; // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp
|
||||
uint8_t ibaLanguage_ = EMS_VALUE_UINT_NOTSET; // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian
|
||||
int8_t ibaCalIntTemperature_ = EMS_VALUE_INT_NOTSET; // offset int. temperature sensor, by * 0.1 Kelvin (-5.0 to 5.0K)
|
||||
int8_t ibaMinExtTemperature_ = EMS_VALUE_INT_NOTSET; // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1
|
||||
uint8_t ibaBuildingType_ = EMS_VALUE_UINT_NOTSET; // building type: 0 = light, 1 = medium, 2 = heavy
|
||||
uint8_t ibaClockOffset_ = EMS_VALUE_UINT_NOTSET; // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||
|
||||
int8_t dampedoutdoortemp_ = EMS_VALUE_INT_NOTSET;
|
||||
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;
|
||||
|
||||
std::vector<std::shared_ptr<HeatingCircuit>> heating_circuits_; // each thermostat can have multiple heating circuits
|
||||
|
||||
// Generic Types
|
||||
static constexpr uint16_t EMS_TYPE_RCTime = 0x06; // time
|
||||
static constexpr uint16_t EMS_TYPE_RCOutdoorTemp = 0xA3; // is an automatic thermostat broadcast, outdoor external temp
|
||||
|
||||
// Type offsets
|
||||
static constexpr uint8_t EMS_OFFSET_RC10StatusMessage_setpoint = 1; // setpoint temp
|
||||
static constexpr uint8_t EMS_OFFSET_RC10StatusMessage_curr = 2; // current temp
|
||||
static constexpr uint8_t EMS_OFFSET_RC10Set_temp = 4; // position of thermostat setpoint temperature
|
||||
|
||||
static constexpr uint8_t EMS_OFFSET_RC20StatusMessage_setpoint = 1; // setpoint temp
|
||||
static constexpr uint8_t EMS_OFFSET_RC20StatusMessage_curr = 2; // current temp
|
||||
static constexpr uint8_t EMS_OFFSET_RC20Set_mode = 23; // position of thermostat mode
|
||||
static constexpr uint8_t EMS_OFFSET_RC20Set_temp = 28; // position of thermostat setpoint temperature
|
||||
|
||||
static constexpr uint8_t EMS_OFFSET_RC20_2_Set_mode = 3; // ES72 - see https://github.com/proddy/EMS-ESP/issues/334
|
||||
static constexpr uint8_t EMS_OFFSET_RC20_2_Set_temp_night = 1; // ES72
|
||||
static constexpr uint8_t EMS_OFFSET_RC20_2_Set_temp_day = 2; // ES72
|
||||
|
||||
static constexpr uint8_t EMS_OFFSET_RC30StatusMessage_setpoint = 1; // setpoint temp
|
||||
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_RC35StatusMessage_setpoint = 2; // desired temp
|
||||
static constexpr uint8_t EMS_OFFSET_RC35StatusMessage_curr = 3; // current temp
|
||||
static constexpr uint8_t EMS_OFFSET_RC35StatusMessage_mode = 1; // day mode, also summer on RC3's
|
||||
static constexpr uint8_t EMS_OFFSET_RC35StatusMessage_mode1 = 0; // for holiday mode
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_mode = 7; // position of thermostat mode
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_day = 2; // position of thermostat setpoint temperature for day time
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_night = 1; // position of thermostat setpoint temperature for night time
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_holiday = 3; // temp during holiday mode
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_heatingtype = 0; // e.g. floor heating = 3
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_targetflowtemp = 14; // target flow temperature
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_seltemp = 37; // selected temp
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_offset = 6;
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_design = 17;
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_summer = 22;
|
||||
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_nofrost = 23;
|
||||
|
||||
static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_setpoint = 10; // setpoint temp
|
||||
static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_curr = 8; // current temp
|
||||
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSStatusMessage_mode = 10; // thermostat mode (auto, manual)
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSStatusMessage_setpoint = 3; // setpoint temp
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSStatusMessage_curr = 0; // current temp
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSStatusMessage_currsetpoint = 6; // target setpoint temp
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSSet_mode = 0; // operation mode(Auto=0xFF, Manual=0x00)
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSSet_temp_comfort3 = 1; // comfort3 level
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSSet_temp_comfort2 = 2; // comfort2 level
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSSet_temp_comfort1 = 3; // comfort1 level
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSSet_temp_eco = 4; // eco level
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSSet_temp_setpoint = 8; // temp setpoint, when changing of templevel (in auto) value is reset to FF
|
||||
static constexpr uint8_t EMS_OFFSET_RCPLUSSet_manual_setpoint = 10; // manual setpoint
|
||||
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersStatusMessage_daymode = 0; // 3 = day, 2 = night, 1 = nofrost
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersStatusMessage_mode = 1; // current mode, 1 = manual, 2 = auto
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersStatusMessage_setpoint = 2; // setpoint temp
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersStatusMessage_curr = 4; // current temp
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage_day_temp = 17; // EMS offset to set temperature on thermostat for day mode
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage_night_temp = 16; // EMS offset to set temperature on thermostat for night mode
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage_no_frost_temp = 15; // EMS offset to set temperature on thermostat for no frost mode
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage_set_mode = 14; // EMS offset to set mode on thermostat
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage2_set_mode = 4; // EMS offset to set mode on thermostat
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage2_no_frost_temp = 5;
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage2_eco_temp = 6;
|
||||
static constexpr uint8_t EMS_OFFSET_JunkersSetMessage3_heat = 7;
|
||||
|
||||
#define AUTO_HEATING_CIRCUIT 0
|
||||
#define DEFAULT_HEATING_CIRCUIT 1
|
||||
|
||||
// Installation settings
|
||||
static constexpr uint8_t EMS_TYPE_IBASettings = 0xA5; // installation settings
|
||||
static constexpr uint8_t EMS_TYPE_wwSettings = 0x37; // ww settings
|
||||
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(std::shared_ptr<const Telegram> telegram);
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(const uint8_t hc_num);
|
||||
|
||||
void process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram);
|
||||
void process_IBASettings(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RCTime(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC35wwSettings(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_RC35Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC35Set(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_RC30Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC30Set(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_RC20Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC20Set(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC20Remote(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_RC20Monitor_2(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC20Set_2(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_RC10Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC10Set(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_RC300Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC300Set(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_EasyMonitor(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
// set functions
|
||||
void set_settings_minexttemp(const int8_t mt);
|
||||
void set_settings_calinttemp(const int8_t ct);
|
||||
void set_settings_clockoffset(const int8_t co);
|
||||
void set_settings_display(const uint8_t ds);
|
||||
void set_settings_building(const uint8_t bg);
|
||||
void set_settings_language(const uint8_t lg);
|
||||
void set_control(const uint8_t ctrl, const uint8_t hc_num);
|
||||
void set_ww_mode(const std::string & mode);
|
||||
void set_holiday(const char * hd, const uint8_t hc_num);
|
||||
void set_datetime(const char * dt);
|
||||
void set_pause(const uint8_t hrs, const uint8_t hc_num);
|
||||
void set_party(const uint8_t hrs, const uint8_t hc_num);
|
||||
void set_mode(const uint8_t mode, const uint8_t hc_num);
|
||||
void set_mode(const std::string & mode, const uint8_t hc_num);
|
||||
void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);
|
||||
void set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num);
|
||||
|
||||
// MQTT functions
|
||||
void thermostat_cmd(const char * message);
|
||||
void thermostat_cmd_temp(const char * message);
|
||||
void thermostat_cmd_mode(const char * message);
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user