mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
master thermostat detection and HA thermostat modes
This commit is contained in:
@@ -26,7 +26,20 @@ 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) {
|
||||||
if (EMSESP::actual_master_thermostat() == 0) {
|
|
||||||
|
uint8_t actual_master_thermostat = EMSESP::actual_master_thermostat(); // what we're actually using
|
||||||
|
uint8_t master_thermostat = EMSESP_DEFAULT_MASTER_THERMOSTAT;
|
||||||
|
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
|
||||||
|
master_thermostat = settings.master_thermostat; // what the user has defined
|
||||||
|
});
|
||||||
|
// if we're on auto mode, register this thermostat if it has a device id of 0x10, 0x17 or 0x18
|
||||||
|
// or if its the master thermostat we defined
|
||||||
|
// see https://github.com/proddy/EMS-ESP/issues/362#issuecomment-629628161
|
||||||
|
if ((master_thermostat == device_id) || ((master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT) && (device_id < 0x19) &&
|
||||||
|
((actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT) || (device_id < actual_master_thermostat)))) {
|
||||||
|
|
||||||
|
EMSESP::actual_master_thermostat(device_id);
|
||||||
|
actual_master_thermostat = device_id;
|
||||||
this->reserve_mem(25); // reserve some space for the telegram registries, to avoid memory fragmentation
|
this->reserve_mem(25); // reserve some space for the telegram registries, to avoid memory fragmentation
|
||||||
|
|
||||||
// common telegram handlers
|
// common telegram handlers
|
||||||
@@ -58,7 +71,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
} 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};
|
||||||
if (EMSESP::actual_master_thermostat() == 0) {
|
if (actual_master_thermostat == device_id) {
|
||||||
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::shared_ptr<const Telegram> t) { process_RC20Monitor(t); });
|
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::shared_ptr<const Telegram> t) { process_RC20Set(t); });
|
register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Set(t); });
|
||||||
@@ -70,7 +83,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
} 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};
|
||||||
if (EMSESP::actual_master_thermostat() == 0) {
|
if (actual_master_thermostat == device_id) {
|
||||||
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::shared_ptr<const Telegram> t) { process_RC20Monitor_2(t); });
|
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::shared_ptr<const Telegram> t) { process_RC20Set_2(t); });
|
register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Set_2(t); });
|
||||||
@@ -122,29 +135,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t master_thermostat = 0;
|
|
||||||
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
|
|
||||||
master_thermostat = settings.master_thermostat; // what the user has defined
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) {
|
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) {
|
||||||
mqtt_format_ = settings.mqtt_format; // single, nested or ha
|
mqtt_format_ = settings.mqtt_format; // single, nested or ha
|
||||||
});
|
});
|
||||||
|
|
||||||
uint8_t actual_master_thermostat = EMSESP::actual_master_thermostat(); // what we're actually using
|
if (actual_master_thermostat != device_id) {
|
||||||
uint8_t num_devices = EMSESP::count_devices(EMSdevice::DeviceType::THERMOSTAT) + 1; // including this thermostat
|
|
||||||
|
|
||||||
// if we're on auto mode, register this thermostat if it has a device id of 0x10, 0x17 or 0x18
|
|
||||||
// or if its the master thermostat we defined
|
|
||||||
// see https://github.com/proddy/EMS-ESP/issues/362#issuecomment-629628161
|
|
||||||
if (((num_devices == 1) && (actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT)) || (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);
|
|
||||||
add_commands();
|
|
||||||
} 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
|
return; // don't fetch data if more than 1 thermostat
|
||||||
}
|
}
|
||||||
|
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id);
|
||||||
|
add_commands();
|
||||||
|
|
||||||
// reserve some memory for the heating circuits (max 4 to start with)
|
// reserve some memory for the heating circuits (max 4 to start with)
|
||||||
heating_circuits_.reserve(4);
|
heating_circuits_.reserve(4);
|
||||||
@@ -275,7 +275,8 @@ void Thermostat::publish_values() {
|
|||||||
JsonObject dataThermostat;
|
JsonObject dataThermostat;
|
||||||
|
|
||||||
// add external temp and other stuff specific to the RC30 and RC35
|
// add external temp and other stuff specific to the RC30 and RC35
|
||||||
if ((flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) && (mqtt_format_ == MQTT_format::SINGLE || mqtt_format_ == MQTT_format::CUSTOM)) {
|
// if ((flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) && (mqtt_format_ == MQTT_format::SINGLE || mqtt_format_ == MQTT_format::CUSTOM)) {
|
||||||
|
if (flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) {
|
||||||
if (datetime_.size()) {
|
if (datetime_.size()) {
|
||||||
rootThermostat["time"] = datetime_.c_str();
|
rootThermostat["time"] = datetime_.c_str();
|
||||||
}
|
}
|
||||||
@@ -579,9 +580,24 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
|
|||||||
doc["temp_step"] = "0.5";
|
doc["temp_step"] = "0.5";
|
||||||
|
|
||||||
JsonArray modes = doc.createNestedArray("modes");
|
JsonArray modes = doc.createNestedArray("modes");
|
||||||
modes.add("off");
|
uint8_t flags = (this->flags() & 0x0F);
|
||||||
modes.add("heat");
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20_2) {
|
||||||
modes.add("auto");
|
modes.add("night");
|
||||||
|
modes.add("day");
|
||||||
|
} else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC300) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC100)) {
|
||||||
|
modes.add("eco");
|
||||||
|
modes.add("comfort");
|
||||||
|
modes.add("auto");
|
||||||
|
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
|
||||||
|
modes.add("nofrost");
|
||||||
|
modes.add("eco");
|
||||||
|
modes.add("heat");
|
||||||
|
modes.add("auto");
|
||||||
|
} else { // default for all other thermostats
|
||||||
|
modes.add("night");
|
||||||
|
modes.add("day");
|
||||||
|
modes.add("auto");
|
||||||
|
}
|
||||||
|
|
||||||
std::string topic(100, '\0'); // e.g homeassistant/climate/hc1/thermostat/config
|
std::string topic(100, '\0'); // e.g homeassistant/climate/hc1/thermostat/config
|
||||||
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/config"), hc_num);
|
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/config"), hc_num);
|
||||||
@@ -928,15 +944,15 @@ void Thermostat::process_RC10Set(std::shared_ptr<const Telegram> telegram) {
|
|||||||
// type 0x0165, ff
|
// type 0x0165, ff
|
||||||
void Thermostat::process_JunkersSet(std::shared_ptr<const Telegram> telegram) {
|
void Thermostat::process_JunkersSet(std::shared_ptr<const Telegram> telegram) {
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||||
telegram->read_value(hc->daytemp, 17); // is * 2
|
telegram->read_value(hc->daytemp, 17); // is * 2
|
||||||
telegram->read_value(hc->nighttemp, 16); // is * 2
|
telegram->read_value(hc->nighttemp, 16); // is * 2
|
||||||
telegram->read_value(hc->nofrosttemp, 15); // is * 2
|
telegram->read_value(hc->nofrosttemp, 15); // is * 2
|
||||||
}
|
}
|
||||||
// type 0x0179, ff
|
// type 0x0179, ff
|
||||||
void Thermostat::process_JunkersSet2(std::shared_ptr<const Telegram> telegram) {
|
void Thermostat::process_JunkersSet2(std::shared_ptr<const Telegram> telegram) {
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||||
telegram->read_value(hc->daytemp, 7); // is * 2
|
telegram->read_value(hc->daytemp, 7); // is * 2
|
||||||
telegram->read_value(hc->nighttemp, 6); // is * 2
|
telegram->read_value(hc->nighttemp, 6); // is * 2
|
||||||
telegram->read_value(hc->nofrosttemp, 5); // is * 2
|
telegram->read_value(hc->nofrosttemp, 5); // is * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,15 +1159,9 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
|
|||||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
||||||
CommandFlags::ADMIN,
|
CommandFlags::ADMIN,
|
||||||
flash_string_vector{F_(set), F_(master)},
|
flash_string_vector{F_(set), F_(master)},
|
||||||
flash_string_vector{F_(deviceid_optional)},
|
flash_string_vector{F_(deviceid_mandatory)},
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
uint8_t value;
|
uint8_t value = Helpers::hextoint(arguments.front().c_str());
|
||||||
if (arguments.empty()) {
|
|
||||||
value = EMSESP_DEFAULT_MASTER_THERMOSTAT;
|
|
||||||
} else {
|
|
||||||
value = Helpers::hextoint(arguments.front().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSESP::emsespSettingsService.update(
|
EMSESP::emsespSettingsService.update(
|
||||||
[&](EMSESPSettings & settings) {
|
[&](EMSESPSettings & settings) {
|
||||||
settings.master_thermostat = value;
|
settings.master_thermostat = value;
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ MAKE_PSTR(gpio_mandatory, "<gpio>")
|
|||||||
MAKE_PSTR(data_optional, "[data]")
|
MAKE_PSTR(data_optional, "[data]")
|
||||||
MAKE_PSTR(typeid_mandatory, "<type ID>")
|
MAKE_PSTR(typeid_mandatory, "<type ID>")
|
||||||
MAKE_PSTR(deviceid_mandatory, "<device ID>")
|
MAKE_PSTR(deviceid_mandatory, "<device ID>")
|
||||||
MAKE_PSTR(deviceid_optional, "[device ID]")
|
|
||||||
MAKE_PSTR(invalid_log_level, "Invalid log level")
|
MAKE_PSTR(invalid_log_level, "Invalid log level")
|
||||||
MAKE_PSTR(log_level_fmt, "Log level = %s")
|
MAKE_PSTR(log_level_fmt, "Log level = %s")
|
||||||
MAKE_PSTR(log_level_optional, "[level]")
|
MAKE_PSTR(log_level_optional, "[level]")
|
||||||
|
|||||||
Reference in New Issue
Block a user