From 4b029df45b68280ae2d72c9bced0a4d46e5d65fe Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Tue, 13 Oct 2020 17:14:44 +0200 Subject: [PATCH] thermostat errorcode + HA config, --- src/devices/solar.cpp | 57 +++++++++++++++++++------- src/devices/solar.h | 4 ++ src/devices/thermostat.cpp | 82 ++++++++++++++++++++++++++++++++++++-- src/devices/thermostat.h | 15 ++++++- src/locale_EN.h | 1 + src/mqtt.cpp | 4 +- 6 files changed, 142 insertions(+), 21 deletions(-) diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index 14e3276bb..2901302f5 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -34,13 +34,18 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s } if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) { - register_telegram_type(0x0362, F("SM100Monitor"), true, [&](std::shared_ptr t) { process_SM100Monitor(t); }); - register_telegram_type(0x0363, F("SM100Monitor2"), true, [&](std::shared_ptr t) { process_SM100Monitor2(t); }); - register_telegram_type(0x0366, F("SM100Config"), true, [&](std::shared_ptr t) { process_SM100Config(t); }); - - register_telegram_type(0x0364, F("SM100Status"), false, [&](std::shared_ptr t) { process_SM100Status(t); }); - register_telegram_type(0x036A, F("SM100Status2"), false, [&](std::shared_ptr t) { process_SM100Status2(t); }); - register_telegram_type(0x038E, F("SM100Energy"), true, [&](std::shared_ptr t) { process_SM100Energy(t); }); + if (device_id == 0x2A) { + register_telegram_type(0x07D6, F("SM100wwTemperatur"), false, [&](std::shared_ptr t) { process_SM100wwTemperature(t); }); + register_telegram_type(0x07AA, F("SM100wwStatus"), false, [&](std::shared_ptr t) { process_SM100wwStatus(t); }); + register_telegram_type(0x07AB, F("SM100wwCommand"), false, [&](std::shared_ptr t) { process_SM100wwCommand(t); }); + } else { + register_telegram_type(0x0362, F("SM100Monitor"), true, [&](std::shared_ptr t) { process_SM100Monitor(t); }); + register_telegram_type(0x0363, F("SM100Monitor2"), true, [&](std::shared_ptr t) { process_SM100Monitor2(t); }); + register_telegram_type(0x0366, F("SM100Config"), true, [&](std::shared_ptr t) { process_SM100Config(t); }); + register_telegram_type(0x0364, F("SM100Status"), false, [&](std::shared_ptr t) { process_SM100Status(t); }); + register_telegram_type(0x036A, F("SM100Status2"), false, [&](std::shared_ptr t) { process_SM100Status2(t); }); + register_telegram_type(0x038E, F("SM100Energy"), true, [&](std::shared_ptr t) { process_SM100Energy(t); }); + } } if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) { @@ -129,13 +134,16 @@ void Solar::publish_values(JsonObject & data) { StaticJsonDocument doc; JsonObject output = doc.to(); if (export_values(output)) { - Mqtt::publish(F("solar_data"), doc.as()); - } - - // if we're using Home Assistant and haven't created the MQTT Discovery topics, do it now - if ((Mqtt::mqtt_format() == Mqtt::Format::HA) && (!mqtt_ha_config_)) { - register_mqtt_ha_config(); - mqtt_ha_config_ = true; + if (device_id() == 0x2A) { + Mqtt::publish(F("ww_data"), doc.as()); + } else { + Mqtt::publish(F("solar_data"), doc.as()); + // if we're using Home Assistant and haven't created the MQTT Discovery topics, do it now + if ((Mqtt::mqtt_format() == Mqtt::Format::HA) && (!mqtt_ha_config_)) { + register_mqtt_ha_config(); + mqtt_ha_config_ = true; + } + } } } @@ -286,6 +294,27 @@ void Solar::process_SM100Monitor2(std::shared_ptr telegram) { // not implemented yet } +// SM100wwTemperatur - 0x07D6 +// Solar Module(0x2A) -> (0x00), (0x7D6), data: 01 C1 00 00 02 5B 01 AF 01 AD 80 00 01 90 +void Solar::process_SM100wwTemperature(std::shared_ptr telegram) { + // changed_ |= telegram->read_value(wwTemp_1_, 0); + // changed_ |= telegram->read_value(wwTemp_3_, 4); + // changed_ |= telegram->read_value(wwTemp_4_, 6); + // changed_ |= telegram->read_value(wwTemp_5_, 8); + // changed_ |= telegram->read_value(wwTemp_7_, 12); +} +// SM100wwStatus - 0x07AA +// Solar Module(0x2A) -> (0x00), (0x7AA), data: 64 00 04 00 03 00 28 01 0F +void Solar::process_SM100wwStatus(std::shared_ptr telegram) { + // changed_ |= telegram->read_value(wwPump_, 0); +} +// SM100wwCommand - 0x07AB +// Thermostat(0x10) -> Solar Module(0x2A), (0x7AB), data: 01 00 01 +void Solar::process_SM100wwCommand(std::shared_ptr telegram) { + // not implemented yet +} + + #pragma GCC diagnostic pop // SM100Config - 0x0366 diff --git a/src/devices/solar.h b/src/devices/solar.h index 20361c01f..422e78b69 100644 --- a/src/devices/solar.h +++ b/src/devices/solar.h @@ -81,6 +81,10 @@ class Solar : public EMSdevice { void process_SM100Status2(std::shared_ptr telegram); void process_SM100Energy(std::shared_ptr telegram); + void process_SM100wwTemperature(std::shared_ptr telegram); + void process_SM100wwStatus(std::shared_ptr telegram); + void process_SM100wwCommand(std::shared_ptr telegram); + void process_ISM1StatusMessage(std::shared_ptr telegram); void process_ISM1Set(std::shared_ptr telegram); }; diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index bcb1413b1..6d93997fd 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -47,6 +47,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i // common telegram handlers register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, [&](std::shared_ptr t) { process_RCOutdoorTemp(t); }); register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), false, [&](std::shared_ptr t) { process_RCTime(t); }); + register_telegram_type(0xA2, F("RCError"), false, [&](std::shared_ptr t) { process_RCError(t); }); } // RC10 if (model == EMSdevice::EMS_DEVICE_FLAG_RC10) { @@ -175,6 +176,7 @@ void Thermostat::device_info_web(JsonArray & root) { JsonObject output_main = doc_main.to(); if (export_values_main(output_main)) { print_value_json(root, F("time"), nullptr, F_(time), nullptr, output_main); + print_value_json(root, F("errorcode"), nullptr, F_(error), nullptr, output_main); print_value_json(root, F("display"), nullptr, F_(display), nullptr, output_main); print_value_json(root, F("language"), nullptr, F_(language), nullptr, output_main); print_value_json(root, F("offsetclock"), nullptr, F_(offsetclock), nullptr, output_main); @@ -256,6 +258,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) { JsonObject output_main = doc_main.to(); if (export_values_main(output_main)) { print_value_json(shell, F("time"), nullptr, F_(time), nullptr, output_main); + print_value_json(shell, F("errorcode"), nullptr, F_(error), nullptr, output_main); print_value_json(shell, F("display"), nullptr, F_(display), nullptr, output_main); print_value_json(shell, F("language"), nullptr, F_(language), nullptr, output_main); print_value_json(shell, F("offsetclock"), nullptr, F_(offsetclock), nullptr, output_main); @@ -343,6 +346,10 @@ bool Thermostat::export_values_main(JsonObject & rootThermostat) { rootThermostat["time"] = datetime_.c_str(); } + if (Helpers::hasValue(errorNumber_)) { + rootThermostat["errorcode"] = errorCode_.c_str(); + } + if (model == EMSdevice::EMS_DEVICE_FLAG_RC30_1) { // Display if (Helpers::hasValue(ibaMainDisplay_)) { @@ -443,6 +450,12 @@ bool Thermostat::export_values_main(JsonObject & rootThermostat) { rootThermostat["wwcircmode"] = Helpers::render_enum(s, {"off", "on", "auto"}, wwCircMode_); } + if ((Mqtt::mqtt_format() == Mqtt::Format::HA) && (!ha_registered())) { + // see if we have already registered this with HA MQTT Discovery, if not send the config + register_mqtt_ha_config(); + ha_registered(true); + } + return (rootThermostat.size()); } @@ -720,6 +733,43 @@ std::shared_ptr Thermostat::heating_circuit(std::sha return heating_circuits_.back(); // even after sorting, this should still point back to the newly created HC } +// publish config topic for HA MQTT Discovery +// homeassistant/climate/ems-esp/thermostat_/config +void Thermostat::register_mqtt_ha_config() { + StaticJsonDocument doc; + doc["name"] = F("Thermostat"); + doc["uniq_id"] = F("thermostat"); + doc["ic"] = F("mdi:home-thermometer-outline"); + + char stat_t[50]; + snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/thermostat_data"), System::hostname().c_str()); + doc["stat_t"] = stat_t; + + doc["val_tpl"] = F("{{value_json.time}}"); + JsonObject dev = doc.createNestedObject("dev"); + dev["name"] = F("EMS-ESP Thermostat"); + dev["sw"] = EMSESP_APP_VERSION; + dev["mf"] = this->brand_to_string(); + dev["mdl"] = this->name(); + JsonArray ids = dev.createNestedArray("ids"); + ids.add("ems-esp-thermostat"); + Mqtt::publish_retain(F("homeassistant/sensor/ems-esp/thermostat/config"), doc.as(), true); // publish the config payload with retain flag + + Mqtt::register_mqtt_ha_sensor(nullptr, F_(time), this->device_type(), "time", nullptr, nullptr); + Mqtt::register_mqtt_ha_sensor(nullptr, F_(error), this->device_type(), "errorcode", nullptr, nullptr); + + uint8_t model = this->model(); + if (model == EMS_DEVICE_FLAG_RC35 || model == EMS_DEVICE_FLAG_RC35) { + Mqtt::register_mqtt_ha_sensor(nullptr, F_(dampedtemp), this->device_type(), "dampedtemp", F_(degrees), F_(icontemperature)); + Mqtt::register_mqtt_ha_sensor(nullptr, F_(building), this->device_type(), "building", nullptr, nullptr); + Mqtt::register_mqtt_ha_sensor(nullptr, F_(minexttemp), this->device_type(), "minexttemp", F_(degrees), F_(icontemperature)); + Mqtt::register_mqtt_ha_sensor(nullptr, F_(wwmode), this->device_type(), "wwmode", nullptr, nullptr); + Mqtt::register_mqtt_ha_sensor(nullptr, F_(wwtemp), this->device_type(), "wwtemp", F_(degrees), F_(icontemperature)); + Mqtt::register_mqtt_ha_sensor(nullptr, F_(wwtemplow), this->device_type(), "wwtemplow", F_(degrees), F_(icontemperature)); + Mqtt::register_mqtt_ha_sensor(nullptr, F_(wwcircmode), this->device_type(), "wwcircmode", nullptr, nullptr); + } +} + // publish config topic for HA MQTT Discovery // homeassistant/climate/ems-esp/thermostat_hc1/config void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { @@ -1290,6 +1340,28 @@ void Thermostat::process_RCTime(std::shared_ptr telegram) { } } +// process_RCError - type 0xA2 - error maeesage - 14 bytes long +// 10 00 A2 00 41 32 32 03 30 00 02 00 00 00 00 00 00 02 CRC +// A 2 2 816 +void Thermostat::process_RCError(std::shared_ptr telegram) { + if (errorCode_.empty()) { + errorCode_.resize(10, '\0'); + } + char buf[4]; + buf[0] = telegram->message_data[0]; + buf[1] = telegram->message_data[1]; + buf[2] = telegram->message_data[2]; + buf[3] = 0; + changed_ |= telegram->read_value(errorNumber_, 3); + + snprintf_P(&errorCode_[0], + errorCode_.capacity() + 1, + PSTR("%s(%d)"), + buf, + errorNumber_ + ); +} + // 0xA5 - Set minimum external temperature bool Thermostat::set_minexttemp(const char * value, const int8_t id) { int mt = 0; @@ -1353,12 +1425,16 @@ bool Thermostat::set_remotetemp(const char * value, const int8_t id) { return false; } - uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; + uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id; + std::shared_ptr hc = heating_circuit(hc_num); + if (hc == nullptr) { + return false; + } if (f > 100 || f < 0) { - Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET); + Roomctrl::set_remotetemp(hc->hc_num() - 1, EMS_VALUE_SHORT_NOTSET); } else { - Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10)); + Roomctrl::set_remotetemp(hc->hc_num() - 1, (int16_t)(f * 10)); } return true; diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index d8c17751f..13a132490 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -110,6 +110,12 @@ class Thermostat : public EMSdevice { void add_commands(); bool export_values_main(JsonObject & doc); bool export_values_hc(uint8_t mqtt_format, JsonObject & doc); + bool ha_registered() const { + return ha_registered_; + } + void ha_registered(bool b) { + ha_registered_ = b; + } // specific thermostat characteristics, stripping the last 4 bits inline uint8_t model() const { @@ -122,9 +128,11 @@ class Thermostat : public EMSdevice { std::vector timer_typeids; std::vector summer_typeids; - std::string datetime_; // date and time stamp + std::string datetime_; // date and time stamp + std::string errorCode_; // code as string i.e. "A22(816)" - bool changed_ = false; + bool changed_ = false; + bool ha_registered_ = false; // Installation parameters uint8_t ibaMainDisplay_ = @@ -135,6 +143,7 @@ class Thermostat : public EMSdevice { 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 + uint16_t errorNumber_ = EMS_VALUE_USHORT_NOTSET; int8_t dampedoutdoortemp_ = EMS_VALUE_INT_NOTSET; uint16_t tempsensor1_ = EMS_VALUE_USHORT_NOTSET; uint16_t tempsensor2_ = EMS_VALUE_USHORT_NOTSET; @@ -226,6 +235,7 @@ class Thermostat : public EMSdevice { std::shared_ptr heating_circuit(std::shared_ptr telegram); std::shared_ptr heating_circuit(const uint8_t hc_num); + void register_mqtt_ha_config(); void register_mqtt_ha_config(uint8_t hc_num); bool thermostat_ha_cmd(const char * message, uint8_t hc_num); @@ -234,6 +244,7 @@ class Thermostat : public EMSdevice { void process_RCOutdoorTemp(std::shared_ptr telegram); void process_IBASettings(std::shared_ptr telegram); void process_RCTime(std::shared_ptr telegram); + void process_RCError(std::shared_ptr telegram); void process_RC35wwSettings(std::shared_ptr telegram); void process_RC35Monitor(std::shared_ptr telegram); void process_RC35Set(std::shared_ptr telegram); diff --git a/src/locale_EN.h b/src/locale_EN.h index af9f9e6f6..8345da681 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -224,6 +224,7 @@ MAKE_PSTR(flowSetTemp, "Setpoint flow temperature") // thermostat MAKE_PSTR(time, "Time") +MAKE_PSTR(error, "Error code") MAKE_PSTR(display, "Display") MAKE_PSTR(language, "Language") MAKE_PSTR(offsetclock, "Offset clock") diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 1468a30c9..ded15ef0b 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -696,7 +696,7 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons char state_t[50]; snprintf_P(state_t, sizeof(state_t), PSTR("%s/%s"), hostname_.c_str(), entity); doc["stat_t"] = state_t; - + /* EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { if (settings.bool_format == BOOL_FORMAT_ONOFF) { doc[F("payload_on")] = F("on"); @@ -709,7 +709,7 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons doc[F("payload_off")] = "0"; } }); - + */ JsonObject dev = doc.createNestedObject(F("dev")); JsonArray ids = dev.createNestedArray(F("ids")); char ha_device[40];