This commit is contained in:
proddy
2020-08-12 23:21:33 +02:00
parent 29723ffc54
commit d8f67cd2db
2 changed files with 144 additions and 166 deletions

View File

@@ -27,16 +27,16 @@ uuid::log::Logger Thermostat::logger_{F_(thermostat), uuid::log::Facility::CONSO
Thermostat::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) Thermostat::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)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// common telegram handlers // common telegram handlers
register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, std::bind(&Thermostat::process_RCOutdoorTemp, this, _1)); register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, [&](std::shared_ptr<const Telegram> t) { process_RCOutdoorTemp(t); });
register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), true, std::bind(&Thermostat::process_RCTime, this, _1)); // 0x06 register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), false, [&](std::shared_ptr<const Telegram> t) { process_RCTime(t); });
// RC10 // RC10
if (flags == EMSdevice::EMS_DEVICE_FLAG_RC10) { if (flags == EMSdevice::EMS_DEVICE_FLAG_RC10) {
monitor_typeids = {0xB1}; monitor_typeids = {0xB1};
set_typeids = {0xB0}; set_typeids = {0xB0};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC10Monitor"), false, std::bind(&Thermostat::process_RC10Monitor, this, _1)); register_telegram_type(monitor_typeids[i], F("RC10Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC10Monitor(t); });
register_telegram_type(set_typeids[i], F("RC10Set"), false, std::bind(&Thermostat::process_RC10Set, this, _1)); register_telegram_type(set_typeids[i], F("RC10Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC10Set(t); });
} }
// RC35 // RC35
@@ -45,73 +45,73 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
set_typeids = {0x3D, 0x47, 0x51, 0x5B}; set_typeids = {0x3D, 0x47, 0x51, 0x5B};
timer_typeids = {0x3F, 0x49, 0x53, 0x5D}; timer_typeids = {0x3F, 0x49, 0x53, 0x5D};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, std::bind(&Thermostat::process_RC35Monitor, this, _1)); register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC35Monitor(t); });
register_telegram_type(set_typeids[i], F("RC35Set"), false, std::bind(&Thermostat::process_RC35Set, this, _1)); register_telegram_type(set_typeids[i], F("RC35Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC35Set(t); });
} }
register_telegram_type(EMS_TYPE_IBASettings, F("IBASettings"), true, std::bind(&Thermostat::process_IBASettings, this, _1)); register_telegram_type(EMS_TYPE_IBASettings, F("IBASettings"), true, [&](std::shared_ptr<const Telegram> t) { process_IBASettings(t); });
register_telegram_type(EMS_TYPE_wwSettings, F("WWSettings"), true, std::bind(&Thermostat::process_RC35wwSettings, this, _1)); register_telegram_type(EMS_TYPE_wwSettings, F("WWSettings"), true, [&](std::shared_ptr<const Telegram> t) { process_RC35wwSettings(t); });
// RC20 // RC20
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20) { } else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20) {
monitor_typeids = {0x91}; monitor_typeids = {0x91};
set_typeids = {0xA8}; set_typeids = {0xA8};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, std::bind(&Thermostat::process_RC20Monitor, this, _1)); register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Monitor(t); });
register_telegram_type(set_typeids[i], F("RC20Set"), false, std::bind(&Thermostat::process_RC20Set, this, _1)); register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Set(t); });
} }
register_telegram_type(0xAF, F("RC20Remote"), false, std::bind(&Thermostat::process_RC20Remote, this, _1)); register_telegram_type(0xAF, F("RC20Remote"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Remote(t); });
// RC20 newer // RC20 newer
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20_2) { } else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20_2) {
monitor_typeids = {0xAE}; monitor_typeids = {0xAE};
set_typeids = {0xAD}; set_typeids = {0xAD};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, std::bind(&Thermostat::process_RC20Monitor_2, this, _1)); register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Monitor_2(t); });
register_telegram_type(set_typeids[i], F("RC20Set"), false, std::bind(&Thermostat::process_RC20Set_2, this, _1)); register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Set_2(t); });
} }
register_telegram_type(0xAF, F("RC20Remote"), false, std::bind(&Thermostat::process_RC20Remote, this, _1)); register_telegram_type(0xAF, F("RC20Remote"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Remote(t); });
// RC30 // RC30
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC30) { } else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC30) {
monitor_typeids = {0x41}; monitor_typeids = {0x41};
set_typeids = {0xA7}; set_typeids = {0xA7};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, std::bind(&Thermostat::process_RC30Monitor, this, _1)); register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC30Monitor(t); });
register_telegram_type(set_typeids[i], F("RC30Set"), false, std::bind(&Thermostat::process_RC30Set, this, _1)); register_telegram_type(set_typeids[i], F("RC30Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC30Set(t); });
} }
// EASY // EASY
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_EASY) { } else if (flags == EMSdevice::EMS_DEVICE_FLAG_EASY) {
monitor_typeids = {0x0A}; monitor_typeids = {0x0A};
set_typeids = {}; set_typeids = {};
register_telegram_type(monitor_typeids[0], F("EasyMonitor"), false, std::bind(&Thermostat::process_EasyMonitor, this, _1)); register_telegram_type(monitor_typeids[0], F("EasyMonitor"), false, [&](std::shared_ptr<const Telegram> t) { process_EasyMonitor(t); });
// RC300/RC100 // RC300/RC100
} else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC300) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC100)) { } else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC300) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC100)) {
monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8}; monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8};
set_typeids = {0x02B9, 0x02BA, 0x02BB, 0x02BC}; set_typeids = {0x02B9, 0x02BA, 0x02BB, 0x02BC};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, std::bind(&Thermostat::process_RC300Monitor, this, _1)); register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Monitor(t); });
register_telegram_type(set_typeids[i], F("RC300Set"), false, std::bind(&Thermostat::process_RC300Set, this, _1)); register_telegram_type(set_typeids[i], F("RC300Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Set(t); });
} }
register_telegram_type(0x31D, F("RC300WWmode"), false, std::bind(&Thermostat::process_RC300WWmode, this, _1)); register_telegram_type(0x31D, F("RC300WWmode"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode(t); });
register_telegram_type(0x31E, F("RC300WWmode"), false, std::bind(&Thermostat::process_RC300WWmode, this, _1)); register_telegram_type(0x31E, F("RC300WWmode"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode(t); });
// JUNKERS/HT3 // JUNKERS/HT3
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { } else if (flags == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172}; monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172};
set_typeids = {0x0165, 0x0166, 0x0167, 0x0168}; set_typeids = {0x0165, 0x0166, 0x0167, 0x0168};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, std::bind(&Thermostat::process_JunkersMonitor, this, _1)); register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, [&](std::shared_ptr<const Telegram> t) { process_JunkersMonitor(t); });
register_telegram_type(set_typeids[i], F("JunkersSet"), false, std::bind(&Thermostat::process_JunkersSet, this, _1)); register_telegram_type(set_typeids[i], F("JunkersSet"), false, [&](std::shared_ptr<const Telegram> t) { process_JunkersSet(t); });
} }
} else if (flags == (EMSdevice::EMS_DEVICE_FLAG_JUNKERS | EMSdevice::EMS_DEVICE_FLAG_JUNKERS_2)) { } else if (flags == (EMSdevice::EMS_DEVICE_FLAG_JUNKERS | EMSdevice::EMS_DEVICE_FLAG_JUNKERS_2)) {
monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172}; monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172};
set_typeids = {0x0179, 0x017A, 0x017B, 0x017C}; set_typeids = {0x0179, 0x017A, 0x017B, 0x017C};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, std::bind(&Thermostat::process_JunkersMonitor, this, _1)); register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, [&](std::shared_ptr<const Telegram> t) { process_JunkersMonitor(t); });
register_telegram_type(set_typeids[i], F("JunkersSet"), false, std::bind(&Thermostat::process_JunkersSet, this, _1)); register_telegram_type(set_typeids[i], F("JunkersSet"), false, [&](std::shared_ptr<const Telegram> t) { process_JunkersSet(t); });
} }
} }
@@ -133,19 +133,23 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
if (((num_devices == 1) && (actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT)) || (master_thermostat == device_id)) { if (((num_devices == 1) && (actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT)) || (master_thermostat == device_id)) {
EMSESP::actual_master_thermostat(device_id); EMSESP::actual_master_thermostat(device_id);
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id); LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id);
init_mqtt(); add_commands();
} else { } else {
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X"), device_id); LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X"), device_id);
return; // don't fetch data if more than 1 thermostat
} }
// for the thermostat, go a query all the heating circuits. This is only done once. The automatic fetch will from now on // reserve some memory for the heating circuits (max 4 to start with)
// only update the active heating circuits heating_circuits_.reserve(4);
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
EMSESP::send_read_request(set_typeids[i], device_id); // only for for the master-thermostat, go a query all the heating circuits. This is only done once.
} // The automatic fetch will from now on only update the active heating circuits
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
EMSESP::send_read_request(monitor_typeids[i], device_id); EMSESP::send_read_request(monitor_typeids[i], device_id);
} }
for (uint8_t i = 0; i < set_typeids.size(); i++) {
EMSESP::send_read_request(set_typeids[i], device_id);
}
} }
// prepare data for Web UI // prepare data for Web UI
@@ -208,7 +212,7 @@ void Thermostat::device_info(JsonArray & root) {
// context menu "thermostat" // context menu "thermostat"
void Thermostat::add_context_menu() { void Thermostat::add_context_menu() {
// only add it once, to prevent conflicts when there are multiple thermostats // only add it once, to prevent conflicts when there are multiple thermostats
if (device_id() != EMSESP::actual_master_thermostat()) { if (get_device_id() != EMSESP::actual_master_thermostat()) {
return; return;
} }
@@ -225,7 +229,7 @@ void Thermostat::add_context_menu() {
// we check if any of the thermostat values have changed and then republish if necessary // we check if any of the thermostat values have changed and then republish if necessary
bool Thermostat::updated_values() { bool Thermostat::updated_values() {
// only publish on the master thermostat // only publish on the master thermostat
if (EMSESP::actual_master_thermostat() != device_id()) { if (EMSESP::actual_master_thermostat() != get_device_id()) {
return false; return false;
} }
@@ -251,12 +255,10 @@ bool Thermostat::updated_values() {
// publish values via MQTT // publish values via MQTT
void Thermostat::publish_values() { void Thermostat::publish_values() {
// only publish on the master thermostat // only publish on the master thermostat
if (EMSESP::actual_master_thermostat() != device_id()) { if (EMSESP::actual_master_thermostat() != get_device_id()) {
return; return;
} }
LOG_DEBUG(F("Performing a thermostat publish (device ID 0x%02X)"), device_id());
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, stripping the option bits uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, stripping the option bits
bool has_data = false; bool has_data = false;
@@ -500,7 +502,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
} }
// create a new heating circuit object // create a new heating circuit object
heating_circuits_.emplace_back(new HeatingCircuit(hc_num, monitor_typeids[hc_num - 1], set_typeids[hc_num - 1])); auto new_hc = std::make_shared<Thermostat::HeatingCircuit>(hc_num, monitor_typeids[hc_num - 1], set_typeids[hc_num - 1]);
heating_circuits_.push_back(new_hc);
std::sort(heating_circuits_.begin(), heating_circuits_.end()); // sort based on hc number std::sort(heating_circuits_.begin(), heating_circuits_.end()); // sort based on hc number
@@ -567,9 +570,9 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
// subscribe to the temp and mode commands // subscribe to the temp and mode commands
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/cmd_temp"), hc_num); snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/cmd_temp"), hc_num);
register_mqtt_topic(topic, std::bind(&Thermostat::thermostat_cmd_temp, this, _1)); register_mqtt_topic(topic, [&](const char * m) { thermostat_cmd_temp(m); });
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/cmd_mode"), hc_num); snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/cmd_mode"), hc_num);
register_mqtt_topic(topic, std::bind(&Thermostat::thermostat_cmd_mode, this, _1)); register_mqtt_topic(topic, [&](const char * m) { thermostat_cmd_mode(m); });
} }
// decodes the thermostat mode for the heating circuit based on the thermostat type // decodes the thermostat mode for the heating circuit based on the thermostat type
@@ -650,7 +653,7 @@ uint8_t Thermostat::HeatingCircuit::get_mode_type(uint8_t flags) const {
// decodes the thermostat mode based on the thermostat type // decodes the thermostat mode based on the thermostat type
// works with both modes and mode_types // works with both modes and mode_types
std::string Thermostat::mode_tostring(uint8_t mode) const { std::string Thermostat::mode_tostring(uint8_t mode) {
switch (mode) { switch (mode) {
case HeatingCircuit::Mode::OFF: case HeatingCircuit::Mode::OFF:
return read_flash_string(F("off")); return read_flash_string(F("off"));
@@ -1127,7 +1130,7 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
flash_string_vector{F_(typeid_mandatory)}, flash_string_vector{F_(typeid_mandatory)},
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) { [=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
uint16_t type_id = Helpers::hextoint(arguments.front().c_str()); uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
EMSESP::send_read_request(type_id, device_id()); EMSESP::send_read_request(type_id, this->get_device_id());
}); });
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT, EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
@@ -1153,53 +1156,44 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
} }
// 0xA5 - Set minimum external temperature // 0xA5 - Set minimum external temperature
void Thermostat::set_settings_minexttemp(const char * value, const int8_t id) { void Thermostat::set_minexttemp(const char * value, const int8_t id) {
int mt = 0; int mt = 0;
if (!Helpers::value2number(value, mt)) { if (!Helpers::value2number(value, mt)) {
return; return;
} }
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) { LOG_INFO(F("Setting min external temperature to %d"), mt);
LOG_INFO(F("Setting min external temperature to %d"), mt); write_command(EMS_TYPE_IBASettings, 5, mt);
write_command(EMS_TYPE_IBASettings, 5, mt);
}
} }
// 0xA5 - Clock offset // 0xA5 - Clock offset
void Thermostat::set_settings_clockoffset(const char * value, const int8_t id) { void Thermostat::set_clockoffset(const char * value, const int8_t id) {
int co = 0; int co = 0;
if (!Helpers::value2number(value, co)) { if (!Helpers::value2number(value, co)) {
return; return;
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting clock offset to %d"), co);
LOG_INFO(F("Setting clock offset to %d"), co); write_command(EMS_TYPE_IBASettings, 12, co);
write_command(EMS_TYPE_IBASettings, 12, co);
}
} }
// 0xA5 - Calibrate internal temperature // 0xA5 - Calibrate internal temperature
void Thermostat::set_settings_calinttemp(const char * value, const int8_t id) { void Thermostat::set_calinttemp(const char * value, const int8_t id) {
int ct = 0; int ct = 0;
if (!Helpers::value2number(value, ct)) { if (!Helpers::value2number(value, ct)) {
return; return;
} }
// does this value need to be multiple by 10? // does this value need to be multiple by 10?
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) { LOG_INFO(F("Calibrating internal temperature to %d.%d"), ct / 10, ct < 0 ? -ct % 10 : ct % 10);
LOG_INFO(F("Calibrating internal temperature to %d.%d"), ct / 10, ct < 0 ? -ct % 10 : ct % 10); write_command(EMS_TYPE_IBASettings, 2, ct);
write_command(EMS_TYPE_IBASettings, 2, ct);
}
} }
// 0xA5 - Set the display settings // 0xA5 - Set the display settings
void Thermostat::set_settings_display(const char * value, const int8_t id) { void Thermostat::set_display(const char * value, const int8_t id) {
int ds = 0; int ds = 0;
if (!Helpers::value2number(value, ds)) { if (!Helpers::value2number(value, ds)) {
return; return;
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting display to %d"), ds);
LOG_INFO(F("Setting display to %d"), ds); write_command(EMS_TYPE_IBASettings, 0, ds);
write_command(EMS_TYPE_IBASettings, 0, ds);
}
} }
void Thermostat::set_remotetemp(const char * value, const int8_t id) { void Thermostat::set_remotetemp(const char * value, const int8_t id) {
@@ -1208,7 +1202,7 @@ void Thermostat::set_remotetemp(const char * value, const int8_t id) {
return; return;
} }
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id; uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
if (f > 100 || f < 0) { if (f > 100 || f < 0) {
Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET); Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET);
@@ -1218,7 +1212,7 @@ void Thermostat::set_remotetemp(const char * value, const int8_t id) {
} }
// 0xA5 - Set the building settings // 0xA5 - Set the building settings
void Thermostat::set_settings_building(const char * value, const int8_t id) { void Thermostat::set_building(const char * value, const int8_t id) {
std::string bd(20, '\0'); std::string bd(20, '\0');
if (!Helpers::value2string(value, bd)) { if (!Helpers::value2string(value, bd)) {
return; return;
@@ -1235,22 +1229,18 @@ void Thermostat::set_settings_building(const char * value, const int8_t id) {
return; // invalid return; // invalid
} }
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) { LOG_INFO(F("Setting building to %d"), bg);
LOG_INFO(F("Setting building to %d"), bg); write_command(EMS_TYPE_wwSettings, 6, bg);
write_command(EMS_TYPE_IBASettings, 6, bg);
}
} }
// 0xA5 Set the language settings // 0xA5 Set the language settings
void Thermostat::set_settings_language(const char * value, const int8_t id) { void Thermostat::set_language(const char * value, const int8_t id) {
int lg = 0; int lg = 0;
if (!Helpers::value2number(value, lg)) { if (!Helpers::value2number(value, lg)) {
return; return;
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting language to %d"), lg);
LOG_INFO(F("Setting language to %d"), lg); write_command(EMS_TYPE_wwSettings, 1, lg);
write_command(EMS_TYPE_IBASettings, 1, lg);
}
} }
// Set the control-mode for hc 0-off, 1-RC20, 2-RC3x // Set the control-mode for hc 0-off, 1-RC20, 2-RC3x
@@ -1260,7 +1250,7 @@ void Thermostat::set_control(const char * value, const int8_t id) {
return; return;
} }
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id; uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
@@ -1273,12 +1263,8 @@ void Thermostat::set_control(const char * value, const int8_t id) {
return; return;
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl);
LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl); write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
} else {
LOG_INFO(F("Set circuit-control not supported"));
}
} }
// sets the thermostat ww working mode, where mode is a string // sets the thermostat ww working mode, where mode is a string
@@ -1311,11 +1297,11 @@ void Thermostat::set_holiday(const char * value, const int8_t id) {
if (!Helpers::value2string(value, hd)) { if (!Helpers::value2string(value, hd)) {
return; return;
} }
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id; uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, get_device_id());
return; return;
} }
uint8_t data[6]; uint8_t data[6];
@@ -1325,12 +1311,9 @@ void Thermostat::set_holiday(const char * value, const int8_t id) {
data[3] = (hd[11] - '0') * 10 + (hd[11] - '0'); data[3] = (hd[11] - '0') * 10 + (hd[11] - '0');
data[4] = (hd[14] - '0') * 10 + (hd[15] - '0'); data[4] = (hd[14] - '0') * 10 + (hd[15] - '0');
data[5] = (hd[18] - '0') * 100 + (hd[19] - '0') * 10 + (hd[20] - '0'); data[5] = (hd[18] - '0') * 100 + (hd[19] - '0') * 10 + (hd[20] - '0');
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting holiday for hc %d"), hc->hc_num()); LOG_INFO(F("Setting holiday for hc %d"), hc->hc_num());
write_command(timer_typeids[hc->hc_num() - 1], 87, data, 6, 0); write_command(timer_typeids[hc->hc_num() - 1], 87, data, 6, 0);
} else {
LOG_INFO(F("Set holiday not supported"));
}
} }
// set pause in hours // set pause in hours
@@ -1339,19 +1322,15 @@ void Thermostat::set_pause(const char * value, const int8_t id) {
if (!Helpers::value2number(value, hrs)) { if (!Helpers::value2number(value, hrs)) {
return; return;
} }
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id; uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, get_device_id());
return; return;
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting pause: %d hours, hc: %d"), hrs, hc->hc_num());
LOG_INFO(F("Setting pause: %d hours, hc: %d"), hrs, hc->hc_num()); write_command(timer_typeids[hc->hc_num() - 1], 85, hrs);
write_command(timer_typeids[hc->hc_num() - 1], 85, hrs);
} else {
LOG_INFO(F("Set pause not supported"));
}
} }
// set partymode in hours // set partymode in hours
@@ -1360,19 +1339,15 @@ void Thermostat::set_party(const char * value, const int8_t id) {
if (!Helpers::value2number(value, hrs)) { if (!Helpers::value2number(value, hrs)) {
return; return;
} }
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id; uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, get_device_id());
return; return;
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting party: %d hours, hc: %d"), hrs, hc->hc_num());
LOG_INFO(F("Setting party: %d hours, hc: %d"), hrs, hc->hc_num()); write_command(timer_typeids[hc->hc_num() - 1], 86, hrs);
write_command(timer_typeids[hc->hc_num() - 1], 86, hrs);
} else {
LOG_INFO(F("Set party not supported"));
}
} }
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time // set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time
@@ -1413,12 +1388,8 @@ void Thermostat::set_datetime(const char * value, const int8_t id) {
data[6] = (dt[20] - '0'); // day of week data[6] = (dt[20] - '0'); // day of week
data[7] = (dt[22] - '0') + 2; // DST and flag data[7] = (dt[22] - '0') + 2; // DST and flag
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting date and time"));
LOG_INFO(F("Setting date and time")); write_command(EMS_TYPE_time, 0, data, 8, 0);
write_command(6, 0, data, 8, 0);
} else {
LOG_INFO(F("Set date not supported"));
}
} }
// sets the thermostat working mode, where mode is a string // sets the thermostat working mode, where mode is a string
@@ -1429,7 +1400,7 @@ void Thermostat::set_mode(const char * value, const int8_t id) {
return; return;
} }
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id; uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
if (mode_tostring(HeatingCircuit::Mode::OFF) == mode) { if (mode_tostring(HeatingCircuit::Mode::OFF) == mode) {
set_mode_n(HeatingCircuit::Mode::OFF, hc_num); set_mode_n(HeatingCircuit::Mode::OFF, hc_num);
@@ -1459,11 +1430,6 @@ void Thermostat::set_mode(const char * value, const int8_t id) {
// Set the thermostat working mode // Set the thermostat working mode
// mode is HeatingCircuit::Mode // mode is HeatingCircuit::Mode
void Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) { void Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
if (can_write()) {
LOG_WARNING(F("Write not supported for this model Thermostat"));
return;
}
// get hc based on number // get hc based on number
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
@@ -1550,6 +1516,7 @@ void Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
// add the write command to the Tx queue // add the write command to the Tx queue
// post validate is the corresponding monitor or set type IDs as they can differ per model // post validate is the corresponding monitor or set type IDs as they can differ per model
// write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid);
write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid); write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid);
} }
@@ -1584,15 +1551,10 @@ void Thermostat::set_temperature(const float temperature, const std::string & mo
// Set the temperature of the thermostat // Set the temperature of the thermostat
void Thermostat::set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num) { void Thermostat::set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num) {
if (can_write()) {
LOG_WARNING(F("Write not supported for this model Thermostat"));
return;
}
// get hc based on number // get hc based on number
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
LOG_WARNING(F("Set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); LOG_WARNING(F("Set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, get_device_id());
return; return;
} }
@@ -1727,8 +1689,7 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
hc->hc_num(), hc->hc_num(),
mode_tostring(mode).c_str()); mode_tostring(mode).c_str());
// add the write command to the Tx queue // add the write command to the Tx queue. value is *2
// value is *2
// post validate is the corresponding monitor or set type IDs as they can differ per model // post validate is the corresponding monitor or set type IDs as they can differ per model
write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), validate_typeid); write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), validate_typeid);
} }
@@ -1795,31 +1756,48 @@ void Thermostat::set_holidaytemp(const char * value, const int8_t id) {
} }
// commands for MQTT and Console // commands for MQTT and Console
void Thermostat::init_mqtt() { void Thermostat::add_commands() {
register_mqtt_cmd(F("wwmode"), std::bind(&Thermostat::set_wwmode, this, _1, _2)); // if this thermostat doesn't support write, don't add the commands
register_mqtt_cmd(F("control"), std::bind(&Thermostat::set_control, this, _1, _2)); if ((flags() & EMSdevice::EMS_DEVICE_FLAG_NO_WRITE) == EMSdevice::EMS_DEVICE_FLAG_NO_WRITE) {
register_mqtt_cmd(F("mode"), std::bind(&Thermostat::set_mode, this, _1, _2)); return;
register_mqtt_cmd(F("holiday"), std::bind(&Thermostat::set_holiday, this, _1, _2)); }
register_mqtt_cmd(F("pause"), std::bind(&Thermostat::set_pause, this, _1, _2));
register_mqtt_cmd(F("party"), std::bind(&Thermostat::set_party, this, _1, _2)); register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { set_wwmode(value, id); });
register_mqtt_cmd(F("datetime"), std::bind(&Thermostat::set_datetime, this, _1, _2));
register_mqtt_cmd(F("minexttemp"), std::bind(&Thermostat::set_settings_minexttemp, this, _1, _2)); // non-static functions
register_mqtt_cmd(F("clockoffset"), std::bind(&Thermostat::set_settings_clockoffset, this, _1, _2)); register_mqtt_cmd(F("temp"), [&](const char * value, const int8_t id) { set_temp(value, id); });
register_mqtt_cmd(F("calinttemp"), std::bind(&Thermostat::set_settings_calinttemp, this, _1, _2)); register_mqtt_cmd(F("mode"), [&](const char * value, const int8_t id) { set_mode(value, id); });
register_mqtt_cmd(F("display"), std::bind(&Thermostat::set_settings_display, this, _1, _2));
register_mqtt_cmd(F("building"), std::bind(&Thermostat::set_settings_building, this, _1, _2)); #if defined(EMSESP_DEBUG)
register_mqtt_cmd(F("language"), std::bind(&Thermostat::set_settings_language, this, _1, _2)); if (true) {
register_mqtt_cmd(F("remotetemp"), std::bind(&Thermostat::set_remotetemp, this, _1, _2)); #else
register_mqtt_cmd(F("temp"), std::bind(&Thermostat::set_temp, this, _1, _2)); if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
register_mqtt_cmd(F("nighttemp"), std::bind(&Thermostat::set_nighttemp, this, _1, _2)); #endif
register_mqtt_cmd(F("daytemp"), std::bind(&Thermostat::set_daytemp, this, _1, _2));
register_mqtt_cmd(F("nofrosttemp"), std::bind(&Thermostat::set_nofrosttemp, this, _1, _2)); register_mqtt_cmd(F("remotetemp"), [&](const char * value, const int8_t id) { set_remotetemp(value, id); });
register_mqtt_cmd(F("ecotemp"), std::bind(&Thermostat::set_ecotemp, this, _1, _2)); register_mqtt_cmd(F("datetime"), [&](const char * value, const int8_t id) { set_datetime(value, id); });
register_mqtt_cmd(F("heattemp"), std::bind(&Thermostat::set_heattemp, this, _1, _2)); register_mqtt_cmd(F("minexttemp"), [&](const char * value, const int8_t id) { set_minexttemp(value, id); });
register_mqtt_cmd(F("summertemp"), std::bind(&Thermostat::set_summertemp, this, _1, _2)); register_mqtt_cmd(F("clockoffset"), [&](const char * value, const int8_t id) { set_clockoffset(value, id); });
register_mqtt_cmd(F("designtemp"), std::bind(&Thermostat::set_designtemp, this, _1, _2)); register_mqtt_cmd(F("calinttemp"), [&](const char * value, const int8_t id) { set_calinttemp(value, id); });
register_mqtt_cmd(F("offsettemp"), std::bind(&Thermostat::set_offsettemp, this, _1, _2)); register_mqtt_cmd(F("display"), [&](const char * value, const int8_t id) { set_display(value, id); });
register_mqtt_cmd(F("holidaytemp"), std::bind(&Thermostat::set_holidaytemp, this, _1, _2)); register_mqtt_cmd(F("building"), [&](const char * value, const int8_t id) { set_building(value, id); });
register_mqtt_cmd(F("language"), [&](const char * value, const int8_t id) { set_language(value, id); });
// non-static functions
register_mqtt_cmd(F("control"), [&](const char * value, const int8_t id) { set_control(value, id); });
register_mqtt_cmd(F("pause"), [&](const char * value, const int8_t id) { set_pause(value, id); });
register_mqtt_cmd(F("party"), [&](const char * value, const int8_t id) { set_party(value, id); });
register_mqtt_cmd(F("holiday"), [&](const char * value, const int8_t id) { set_holiday(value, id); });
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { set_nighttemp(value, id); });
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { set_daytemp(value, id); });
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { set_nofrosttemp(value, id); });
register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { set_ecotemp(value, id); });
register_mqtt_cmd(F("heattemp"), [&](const char * value, const int8_t id) { set_heattemp(value, id); });
register_mqtt_cmd(F("summertemp"), [&](const char * value, const int8_t id) { set_summertemp(value, id); });
register_mqtt_cmd(F("designtemp"), [&](const char * value, const int8_t id) { set_designtemp(value, id); });
register_mqtt_cmd(F("offsettemp"), [&](const char * value, const int8_t id) { set_offsettemp(value, id); });
register_mqtt_cmd(F("holidaytemp"), [&](const char * value, const int8_t id) { set_holidaytemp(value, id); });
}
} }

View File

@@ -91,7 +91,7 @@ class Thermostat : public EMSdevice {
uint16_t set_typeid_; uint16_t set_typeid_;
}; };
std::string mode_tostring(uint8_t mode) const; static std::string mode_tostring(uint8_t mode);
virtual void show_values(uuid::console::Shell & shell); virtual void show_values(uuid::console::Shell & shell);
virtual void publish_values(); virtual void publish_values();
@@ -99,21 +99,17 @@ class Thermostat : public EMSdevice {
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu(); virtual void add_context_menu();
bool can_write() const { private:
return ((flags() & EMSdevice::EMS_DEVICE_FLAG_NO_WRITE) == EMSdevice::EMS_DEVICE_FLAG_NO_WRITE); static uuid::log::Logger logger_;
}
void console_commands(Shell & shell, unsigned int context);
void add_commands();
// each thermostat has a list of heating controller type IDs for reading and writing // each thermostat has a list of heating controller type IDs for reading and writing
std::vector<uint16_t> monitor_typeids; std::vector<uint16_t> monitor_typeids;
std::vector<uint16_t> set_typeids; std::vector<uint16_t> set_typeids;
std::vector<uint16_t> timer_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 std::string datetime_; // date and time stamp
uint8_t mqtt_format_; // single, nested or ha uint8_t mqtt_format_; // single, nested or ha
@@ -210,6 +206,7 @@ class Thermostat : public EMSdevice {
// Installation settings // Installation settings
static constexpr uint8_t EMS_TYPE_IBASettings = 0xA5; // installation settings static constexpr uint8_t EMS_TYPE_IBASettings = 0xA5; // installation settings
static constexpr uint8_t EMS_TYPE_wwSettings = 0x37; // ww settings static constexpr uint8_t EMS_TYPE_wwSettings = 0x37; // ww settings
static constexpr uint8_t EMS_TYPE_time = 0x06; // time
std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(std::shared_ptr<const Telegram> telegram); 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); std::shared_ptr<Thermostat::HeatingCircuit> heating_circuit(const uint8_t hc_num);
@@ -240,6 +237,7 @@ class Thermostat : public EMSdevice {
// internal helper functions // internal helper functions
void set_mode_n(const uint8_t mode, const uint8_t hc_num); void set_mode_n(const uint8_t mode, const uint8_t hc_num);
void set_temperature_value(const char * value, const int8_t id, const uint8_t mode); void set_temperature_value(const char * value, const int8_t id, const uint8_t mode);
void set_temperature(const float temperature, 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); void set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num);
@@ -254,6 +252,7 @@ class Thermostat : public EMSdevice {
void set_holiday(const char * value, const int8_t id); void set_holiday(const char * value, const int8_t id);
void set_pause(const char * value, const int8_t id); void set_pause(const char * value, const int8_t id);
void set_party(const char * value, const int8_t id); void set_party(const char * value, const int8_t id);
void set_temp(const char * value, const int8_t id); void set_temp(const char * value, const int8_t id);
void set_nighttemp(const char * value, const int8_t id); void set_nighttemp(const char * value, const int8_t id);
void set_daytemp(const char * value, const int8_t id); void set_daytemp(const char * value, const int8_t id);
@@ -264,17 +263,18 @@ class Thermostat : public EMSdevice {
void set_designtemp(const char * value, const int8_t id); void set_designtemp(const char * value, const int8_t id);
void set_offsettemp(const char * value, const int8_t id); void set_offsettemp(const char * value, const int8_t id);
void set_holidaytemp(const char * value, const int8_t id); void set_holidaytemp(const char * value, const int8_t id);
void set_remotetemp(const char * value, const int8_t id); void set_remotetemp(const char * value, const int8_t id);
// set functions - these don't use the id/hc // set functions - these don't use the id/hc, the parameters are ignored
void set_wwmode(const char * value, const int8_t id); void set_wwmode(const char * value, const int8_t id);
void set_datetime(const char * value, const int8_t id); void set_datetime(const char * value, const int8_t id);
void set_settings_minexttemp(const char * value, const int8_t id); void set_minexttemp(const char * value, const int8_t id);
void set_settings_clockoffset(const char * value, const int8_t id); void set_clockoffset(const char * value, const int8_t id);
void set_settings_calinttemp(const char * value, const int8_t id); void set_calinttemp(const char * value, const int8_t id);
void set_settings_display(const char * value, const int8_t id); void set_display(const char * value, const int8_t id);
void set_settings_building(const char * value, const int8_t id); void set_building(const char * value, const int8_t id);
void set_settings_language(const char * value, const int8_t id); void set_language(const char * value, const int8_t id);
}; };
} // namespace emsesp } // namespace emsesp