diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index 900cfdd2c..a43fd0258 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -39,13 +39,19 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s 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(EMS_TYPE_ParamCfg, F("ParamCfg"), false, [&](std::shared_ptr t) { process_SM100ParamCfg(t); }); + register_telegram_type(0x0358, F("SM100SystemConfig"), true, [&](std::shared_ptr t) { process_SM100SystemConfig(t); }); + register_telegram_type(0x035A, F("SM100SolarCircuitConfig"), true, [&](std::shared_ptr t) { process_SM100SolarCircuitConfig(t); }); 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(0x0380, F("SM100CollectorConfig"), true, [&](std::shared_ptr t) { process_SM100CollectorConfig(t); }); register_telegram_type(0x038E, F("SM100Energy"), true, [&](std::shared_ptr t) { process_SM100Energy(t); }); register_telegram_type(0x0391, F("SM100Time"), true, [&](std::shared_ptr t) { process_SM100Time(t); }); + + register_mqtt_cmd(F("SM100Tank1MaxTemp"), [&](const char * value, const int8_t id) { return set_SM100Tank1MaxTemp(value, id); }); } } @@ -67,6 +73,7 @@ void Solar::device_info_web(JsonArray & root) { print_value_json(root, F("collectorTemp"), nullptr, F_(collectorTemp), F_(degrees), json); print_value_json(root, F("tankBottomTemp"), nullptr, F_(tankBottomTemp), F_(degrees), json); print_value_json(root, F("tankBottomTemp2"), nullptr, F_(tankBottomTemp2), F_(degrees), json); + print_value_json(root, F("tank1MaxTempCurrent"), nullptr, F_(tank1MaxTempCurrent), F_(degrees), json); print_value_json(root, F("heatExchangerTemp"), nullptr, F_(heatExchangerTemp), F_(degrees), json); print_value_json(root, F("solarPumpModulation"), nullptr, F_(solarPumpModulation), F_(percent), json); print_value_json(root, F("cylinderPumpModulation"), nullptr, F_(cylinderPumpModulation), F_(percent), json); @@ -102,6 +109,7 @@ void Solar::show_values(uuid::console::Shell & shell) { print_value_json(shell, F("collectorTemp"), nullptr, F_(collectorTemp), F_(degrees), json); print_value_json(shell, F("tankBottomTemp"), nullptr, F_(tankBottomTemp), F_(degrees), json); print_value_json(shell, F("tankBottomTemp2"), nullptr, F_(tankBottomTemp2), F_(degrees), json); + print_value_json(shell, F("tank1MaxTempCurrent"), nullptr, F_(tank1MaxTempCurrent), F_(degrees), json); print_value_json(shell, F("heatExchangerTemp"), nullptr, F_(heatExchangerTemp), F_(degrees), json); print_value_json(shell, F("solarPumpModulation"), nullptr, F_(solarPumpModulation), F_(percent), json); print_value_json(shell, F("cylinderPumpModulation"), nullptr, F_(cylinderPumpModulation), F_(percent), json); @@ -173,6 +181,7 @@ void Solar::register_mqtt_ha_config() { Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(collectorTemp), this->device_type(), "collectorTemp", F_(degrees), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(tankBottomTemp), this->device_type(), "tankBottomTemp", F_(degrees), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(tankBottomTemp2), this->device_type(), "tankBottomTemp2", F_(degrees), nullptr); + Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(tank1MaxTempCurrent), this->device_type(), "tank1MaxTempCurrent", F_(degrees), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(heatExchangerTemp), this->device_type(), "heatExchangerTemp", F_(degrees), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(solarPumpModulation), this->device_type(), "solarPumpModulation", F_(percent), nullptr); Mqtt::register_mqtt_ha_sensor(nullptr, nullptr, F_(cylinderPumpModulation), this->device_type(), "cylinderPumpModulation", F_(percent), nullptr); @@ -205,6 +214,10 @@ bool Solar::export_values(JsonObject & json) { json["tankBottomTemp2"] = (float)tankBottomTemp2_ / 10; } + if (Helpers::hasValue(tank1MaxTempCurrent_)) { + json["tank1MaxTempCurrent"] = tank1MaxTempCurrent_; + } + if (Helpers::hasValue(heatExchangerTemp_)) { json["heatExchangerTemp"] = (float)heatExchangerTemp_ / 10; } @@ -270,6 +283,65 @@ void Solar::process_SM10Monitor(std::shared_ptr telegram) { changed_ |= telegram->read_value(pumpWorkMin_, 8, 3); } +/* + * process_SM100SystemConfig - type 0x0358 EMS+ - for MS/SM100 and MS/SM200 + * e.g. B0 0B FF 00 02 58 FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 00 FF 01 00 00 + */ +void Solar::process_SM100SystemConfig(std::shared_ptr telegram) { + changed_ |= telegram->read_value(heatTransferSystem_ , 5, 1); + changed_ |= telegram->read_value(externalTank_ , 9, 1); + changed_ |= telegram->read_value(thermalDisinfect_ , 10, 1); + changed_ |= telegram->read_value(heatMetering_ , 14, 1); + changed_ |= telegram->read_value(solarIsEnabled_ , 19, 1); +} + +/* + * process_SM100SolarCircuitConfig - type 0x035A EMS+ - for MS/SM100 and MS/SM200 + * e.g. B0 0B FF 00 02 5A 64 05 00 58 14 01 01 32 64 00 00 00 5A 0C + */ +void Solar::process_SM100SolarCircuitConfig(std::shared_ptr telegram) { + changed_ |= telegram->read_value(collectorTempMax_ , 0, 1); + changed_ |= telegram->read_value(tank1MaxTempCurrent_ , 3, 1); + changed_ |= telegram->read_value(collectorTempMin_ , 4, 1); + changed_ |= telegram->read_value(solarPumpMode_ , 5, 1); + changed_ |= telegram->read_value(solarPumpMinRPM_ , 6, 1); + changed_ |= telegram->read_value(solarPumpTurnoffDiff_, 7, 1); + changed_ |= telegram->read_value(solarPumpTurnonDiff_ , 8, 1); + changed_ |= telegram->read_value(solarPumpKick_ , 9, 1); + changed_ |= telegram->read_value(plainWaterMode_ , 10, 1); + changed_ |= telegram->read_value(doubleMatchFlow_ , 11, 1); +} + +/* process_SM100ParamCfg - type 0xF9 EMS 1.0 + * This telegram is used to inquire the min, default, max, and current values of a value that is usually read and written with another telegram ID + * The CS200 uses this method extensively to find out which values may be set in the SM100 + * e.g. B0 10 F9 00 FF 02 5A 03 17 00 00 00 14 00 00 00 3C 00 00 00 5A 00 00 00 59 29 - requested with 90 B0 F9 00 11 FF 02 5A 03 AF + * byte 0 = 0xFF + * byte 1-2 = telegram ID used to write this value + * byte 3 = offset in telegram used to write this value + * byte 4 = unknown + * bytes 5..8 = minimum value + * bytes 9..12 = default value + * bytes 13..16 = maximum value + * bytes 17..20 = current value + * + * e.g. B0 0B F9 00 00 02 5A 00 00 6E + */ +void Solar::process_SM100ParamCfg(std::shared_ptr telegram) { + uint16_t t_id; + uint8_t of; + int32_t min,def,max,cur; + telegram->read_value(t_id, 1); + telegram->read_value(of, 3); + telegram->read_value(min, 5); + telegram->read_value(def, 9); + telegram->read_value(max, 13); + telegram->read_value(cur, 17); + + LOG_DEBUG(F("SM100ParamCfg param=0x%04X, offset=%d, min=%d, default=%d, max=%d, current=%d"), + t_id, of, min, def, max, cur); +} + /* * SM100Monitor - type 0x0362 EMS+ - for MS/SM100 and MS/SM200 * e.g. B0 0B FF 00 02 62 00 77 01 D4 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 00 F9 80 00 80 9E - for heat exchanger temp @@ -362,6 +434,17 @@ void Solar::process_SM100Status2(std::shared_ptr telegram) { changed_ |= telegram->read_bitvalue(solarPump_, 10, 2); // on if bit 2 set } +/* + * SM100CollectorConfig - type 0x0380 EMS+ - for SM100 and SM200 + * e.g. B0 0B FF 00 02 80 50 64 00 00 29 01 00 00 01 + */ +void Solar::process_SM100CollectorConfig(std::shared_ptr telegram) { + changed_ |= telegram->read_value(climateZone_, 0, 1); + changed_ |= telegram->read_value(collector1Area_, 3, 2); + changed_ |= telegram->read_value(collector1Type_, 5, 1); +} + + /* * 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 @@ -406,4 +489,15 @@ void Solar::process_ISM1Set(std::shared_ptr telegram) { changed_ |= telegram->read_value(setpoint_maxBottomTemp_, 6); } +bool Solar::set_SM100Tank1MaxTemp(const char * value, const int8_t id) { + int temperature; + if(! Helpers::value2number(value, temperature)) return false; + tank1MaxTempCurrent_=temperature; + uint8_t data=(uint8_t) temperature; + // 90 30 FF 03 02 5A 59 B3 + EMSdevice::write_command(0x35A, 0x03, &data, sizeof(data), 0); + return true; +} + + } // namespace emsesp diff --git a/src/devices/solar.h b/src/devices/solar.h index 3054b912b..fcdc998d0 100644 --- a/src/devices/solar.h +++ b/src/devices/solar.h @@ -66,10 +66,37 @@ class Solar : public EMSdevice { uint8_t configFlag_ = EMS_VALUE_BOOL_NOTSET; uint8_t userFlag_ = EMS_VALUE_BOOL_NOTSET; + // telegram 0x0358 + uint8_t heatTransferSystem_ = EMS_VALUE_UINT_NOTSET; // Umladesystem, 00=no + uint8_t externalTank_ = EMS_VALUE_UINT_NOTSET; // Heat exchanger, 00=no + uint8_t thermalDisinfect_ = EMS_VALUE_UINT_NOTSET; // Daily heatup for disinfection, 00=no + uint8_t heatMetering_ = EMS_VALUE_UINT_NOTSET; // Wärmemengenzählung, 00=no + uint8_t solarIsEnabled_ = EMS_VALUE_UINT_NOTSET; // System enable, 00=no + + // telegram 0x035A + uint8_t collectorTempMax_ = EMS_VALUE_UINT_NOTSET; // maximum allowable temperature for collector + uint8_t tank1MaxTempCurrent_ = EMS_VALUE_UINT_NOTSET; // Current value for max tank temp + uint8_t collectorTempMin_ = EMS_VALUE_UINT_NOTSET; // minimum allowable temperature for collector + uint8_t solarPumpMode_ = EMS_VALUE_UINT_NOTSET; // 00=off, 01=PWM, 02=10V + uint8_t solarPumpMinRPM_ = EMS_VALUE_UINT_NOTSET; // minimum RPM setting, *5 % + uint8_t solarPumpTurnoffDiff_ = EMS_VALUE_UINT_NOTSET; // solar pump turnoff collector/tank diff + uint8_t solarPumpTurnonDiff_ = EMS_VALUE_UINT_NOTSET; // solar pump turnon collector/tank diff + uint8_t solarPumpKick_ = EMS_VALUE_UINT_NOTSET; // pump kick for vacuum collector, 00=off + uint8_t plainWaterMode_ = EMS_VALUE_UINT_NOTSET; // system does not use antifreeze, 00=off + uint8_t doubleMatchFlow_ = EMS_VALUE_UINT_NOTSET; // double Match Flow, 00=off + + // telegram 0x380 + uint8_t climateZone_ = EMS_VALUE_UINT_NOTSET; // climate zone identifier + uint16_t collector1Area_ = EMS_VALUE_USHORT_NOTSET;// Area of collector field 1 + uint8_t collector1Type_ = EMS_VALUE_UINT_NOTSET; // Type of collector field 1, 01=flat, 02=vacuum + bool changed_ = false; bool mqtt_ha_config_ = false; // for HA MQTT Discovery void process_SM10Monitor(std::shared_ptr telegram); + void process_SM100SystemConfig(std::shared_ptr telegram); + void process_SM100SolarCircuitConfig(std::shared_ptr telegram); + void process_SM100ParamCfg(std::shared_ptr telegram); void process_SM100Monitor(std::shared_ptr telegram); void process_SM100Monitor2(std::shared_ptr telegram); @@ -77,6 +104,7 @@ class Solar : public EMSdevice { void process_SM100Status(std::shared_ptr telegram); void process_SM100Status2(std::shared_ptr telegram); + void process_SM100CollectorConfig(std::shared_ptr telegram); void process_SM100Energy(std::shared_ptr telegram); void process_SM100Time(std::shared_ptr telegram); @@ -86,6 +114,9 @@ class Solar : public EMSdevice { void process_ISM1StatusMessage(std::shared_ptr telegram); void process_ISM1Set(std::shared_ptr telegram); + + + bool set_SM100Tank1MaxTemp(const char * value, const int8_t id); }; } // namespace emsesp diff --git a/src/emsdevice.h b/src/emsdevice.h index 81ac08c44..206eeb332 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -241,6 +241,7 @@ class EMSdevice { // type IDs static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices. static constexpr uint16_t EMS_TYPE_UBADevices = 0x07; // EMS connected devices + static constexpr uint16_t EMS_TYPE_ParamCfg = 0xF9; // EMS parameter min/default/max/current // device flags: The lower 4 bits hold the unique identifier, the upper 4 bits are used for specific flags static constexpr uint8_t EMS_DEVICE_FLAG_NONE = 0; diff --git a/src/locale_EN.h b/src/locale_EN.h index e1ef6911d..380b4ac0f 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -203,6 +203,7 @@ MAKE_PSTR(UBAuptime, "Boiler total uptime") MAKE_PSTR(collectorTemp, "Collector temperature (TS1)") MAKE_PSTR(tankBottomTemp, "Bottom temperature (TS2)") MAKE_PSTR(tankBottomTemp2, "Bottom temperature (TS5)") +MAKE_PSTR(tank1MaxTempCurrent, "Maximum Tank temperature") MAKE_PSTR(heatExchangerTemp, "Heat exchanger temperature (TS6)") MAKE_PSTR(solarPumpModulation, "Solar pump modulation (PS1)") MAKE_PSTR(cylinderPumpModulation, "Cylinder pump modulation (PS5)")