diff --git a/interface/src/app/status/Status.tsx b/interface/src/app/status/Status.tsx index a3ce5e18a..7477d07d1 100644 --- a/interface/src/app/status/Status.tsx +++ b/interface/src/app/status/Status.tsx @@ -139,7 +139,7 @@ const SystemStatus = () => { case NTPSyncStatus.NTP_INACTIVE: return LL.INACTIVE(0); case NTPSyncStatus.NTP_ACTIVE: - return LL.ACTIVE() + ' (' + formatDateTime(data.ntp_time ?? '') + ')'; + return LL.ACTIVE() + (data.ntp_time !== undefined) ? ' (' + formatDateTime(data.ntp_time) + ')' : ''; default: return LL.UNKNOWN(); } diff --git a/src/device_library.h b/src/device_library.h index 4d4ebb457..fd3e0d17b 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -82,7 +82,7 @@ // Thermostat - Buderus/Nefit/Bosch specific - 0x17 / 0x10 / 0x18 / 0x19-0x1B for hc2-4 / 0x38 { 4, DeviceType::THERMOSTAT, "UI800, BC400", DeviceFlags::EMS_DEVICE_FLAG_BC400}, // 0x10 -{ 10, DeviceType::THERMOSTAT, "CR11", DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18 +{ 10, DeviceType::THERMOSTAT, "CR11", DeviceFlags::EMS_DEVICE_FLAG_CR11}, // 0x18 { 65, DeviceType::THERMOSTAT, "RC10", DeviceFlags::EMS_DEVICE_FLAG_RC20_N},// 0x17 { 67, DeviceType::THERMOSTAT, "RC30", DeviceFlags::EMS_DEVICE_FLAG_RC30_N},// 0x10 - based on RC35 { 77, DeviceType::THERMOSTAT, "RC20, Moduline 300", DeviceFlags::EMS_DEVICE_FLAG_RC20},// 0x17 diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index e2fce386f..0014b4929 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -143,6 +143,14 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i register_telegram_type(monitor_typeids[i], "CRFMonitor", false, MAKE_PF_CB(process_CRFMonitor)); } + } else if (model == EMSdevice::EMS_DEVICE_FLAG_CR11) { + monitor_typeids = {0x02A5}; + set_typeids = {0x2B9}; + curve_typeids = {0x029B}; + register_telegram_type(monitor_typeids[0], "RC300Monitor", true, MAKE_PF_CB(process_CR11Monitor)); + register_telegram_type(set_typeids[0], "RC300Set", false, MAKE_PF_CB(process_RC300Set)); + register_telegram_type(curve_typeids[0], "RC300Curves", true, MAKE_PF_CB(process_RC300Curve)); + // RC300/RC100 variants } else if (isRC300() || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) { monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC}; @@ -491,6 +499,8 @@ uint8_t Thermostat::HeatingCircuit::get_mode() const { } else if (mode == 1) { return HeatingCircuit::Mode::OFF; } + } else if (model == EMSdevice::EMS_DEVICE_FLAG_CR11) { + return HeatingCircuit::Mode::MANUAL; } else if (model == EMSdevice::EMS_DEVICE_FLAG_BC400 || model == EMSdevice::EMS_DEVICE_FLAG_CR120) { if (mode_new == 0) { return HeatingCircuit::Mode::OFF; @@ -1053,6 +1063,21 @@ void Thermostat::process_CRFMonitor(std::shared_ptr telegram) { add_ha_climate(hc); } +// type 0x02A5 - data from CR11 +void Thermostat::process_CR11Monitor(std::shared_ptr telegram) { + auto hc = heating_circuit(telegram); + if (hc == nullptr) { + return; + } + + has_update(telegram, hc->roomTemp, 0); // is * 10 + has_update(hc->mode, 0); // set manual for CR11 + has_update(telegram, hc->selTemp, 6, 1); // is * 2, force as single byte + has_update(telegram, hc->targetflowtemp, 4); + + add_ha_climate(hc); +} + // type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10 // Rx: 10 0B FF 00 01 A5 80 00 01 30 23 00 30 28 01 E7 03 03 01 01 E7 02 33 00 00 11 01 03 FF FF 00 04 void Thermostat::process_RC300Monitor(std::shared_ptr telegram) { @@ -1096,7 +1121,7 @@ void Thermostat::process_RC300Monitor(std::shared_ptr telegram) // Thermostat(0x10) -> Me(0x0B), RC300Set(0x2B9), data: FF 2E 2A 26 1E 02 4E FF FF 00 1C 01 E1 20 01 0F 05 00 00 02 1F void Thermostat::process_RC300Set(std::shared_ptr telegram) { auto hc = heating_circuit(telegram); - if (hc == nullptr) { + if (hc == nullptr || model() == EMSdevice::EMS_DEVICE_FLAG_CR11) { return; } @@ -1112,9 +1137,6 @@ void Thermostat::process_RC300Set(std::shared_ptr telegram) { // set mode for CR120, BC400, https://github.com/emsesp/EMS-ESP32/discussions/1779 has_update(telegram, hc->mode_new, 21); // for BC400, CR120 has_bitupdate(telegram, hc->mode, 0, 0); // RC300, RC100 - if (hc->mode == EMS_VALUE_UINT8_NOTSET) { - has_update(hc->mode, 0); // set manual for CR11 - } has_update(telegram, hc->daytemp, 2); // is * 2 has_update(telegram, hc->nighttemp, 4); // is * 2 @@ -3726,6 +3748,9 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co break; } + } else if (model == EMSdevice::EMS_DEVICE_FLAG_CR11) { + offset = 10; // just seltemp write to manualtemp + } else if (isRC300() || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) { validate_typeid = set_typeids[hc->hc()]; switch (mode) { @@ -4485,6 +4510,8 @@ void Thermostat::register_device_values() { // Easy TC100 have no date/time, see issue #100, not sure about CT200, so leave it. register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime break; + case EMSdevice::EMS_DEVICE_FLAG_CR11: + break; case EMSdevice::EMS_DEVICE_FLAG_CRF: default: register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(dateTime), DeviceValueUOM::NONE); // can't set datetime @@ -4680,13 +4707,21 @@ void Thermostat::register_device_values_hc(std::shared_ptrmode, DeviceValueType::ENUM, FL_(enum_mode5), FL_(mode), DeviceValueUOM::NONE); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype5), FL_(modetype), DeviceValueUOM::NONE); register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT8, FL_(targetflowtemp), DeviceValueUOM::DEGREES); break; + case EMSdevice::EMS_DEVICE_FLAG_CR11: + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode), FL_(mode), DeviceValueUOM::NONE); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT8, FL_(targetflowtemp), DeviceValueUOM::DEGREES); + register_device_value( + tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); + break; case EMSdevice::EMS_DEVICE_FLAG_RC20: register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode2), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index d12821da1..a2792fd57 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -429,6 +429,7 @@ class Thermostat : public EMSdevice { void process_RC10Set(std::shared_ptr telegram); void process_RC10Set_2(std::shared_ptr telegram); void process_CRFMonitor(std::shared_ptr telegram); + void process_CR11Monitor(std::shared_ptr telegram); void process_RC300Monitor(std::shared_ptr telegram); void process_RC300Set(std::shared_ptr telegram); void process_RC300Set2(std::shared_ptr telegram); diff --git a/src/emsdevice.h b/src/emsdevice.h index 99f1a90c9..0804228fb 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -467,6 +467,7 @@ class EMSdevice { static constexpr uint8_t EMS_DEVICE_FLAG_BC400 = 14; // mostly like RC300, but some changes static constexpr uint8_t EMS_DEVICE_FLAG_R3000 = 15; // Rego3000, same as RC300 with different wwmodes static constexpr uint8_t EMS_DEVICE_FLAG_CR120 = 16; // mostly like RC300, but some changes + static constexpr uint8_t EMS_DEVICE_FLAG_CR11 = 17; // CRF200 only monitor uint8_t count_entities(); uint8_t count_entities_fav(); diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 3710ab374..a93f39f5b 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -68,6 +68,12 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { } return 0; }(); + time_t now = time(nullptr); + if (now > 1500000000L) { + char t[25]; + strftime(t, sizeof(t), "%FT%T", localtime(&now)); + root["ntp_time"] = t; + } #endif root["ap_status"] = EMSESP::esp8266React.apStatus();