From 4d29dd11a2e976d6748a451b8a6980d4eb781aec Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 9 Nov 2024 15:10:51 +0100 Subject: [PATCH] test for emulating outdoor sensor, #2174 --- interface/src/app/main/types.ts | 1 + .../src/app/settings/ApplicationSettings.tsx | 10 ++++ interface/src/i18n/cz/index.ts | 3 +- interface/src/i18n/de/index.ts | 3 +- interface/src/i18n/en/index.ts | 3 +- interface/src/i18n/fr/index.ts | 3 +- interface/src/i18n/it/index.ts | 3 +- interface/src/i18n/nl/index.ts | 3 +- interface/src/i18n/no/index.ts | 3 +- interface/src/i18n/pl/index.ts | 3 +- interface/src/i18n/sk/index.ts | 3 +- interface/src/i18n/sv/index.ts | 3 +- interface/src/i18n/tr/index.ts | 3 +- src/devices/connect.cpp | 31 +++++++--- src/devices/connect.h | 1 + src/emsdevice.cpp | 3 + src/emsesp.cpp | 11 +++- src/roomcontrol.cpp | 58 ++++++++++++++++++- src/roomcontrol.h | 12 ++++ src/web/WebSettingsService.cpp | 4 ++ src/web/WebSettingsService.h | 1 + 21 files changed, 142 insertions(+), 23 deletions(-) diff --git a/interface/src/app/main/types.ts b/interface/src/app/main/types.ts index 4c20fd57f..ed58d0aa0 100644 --- a/interface/src/app/main/types.ts +++ b/interface/src/app/main/types.ts @@ -43,6 +43,7 @@ export interface Settings { modbus_max_clients: number; modbus_timeout: number; developer_mode: boolean; + outdoorsensor: boolean; } export enum busConnectionStatus { diff --git a/interface/src/app/settings/ApplicationSettings.tsx b/interface/src/app/settings/ApplicationSettings.tsx index 0789fee40..f058aee6d 100644 --- a/interface/src/app/settings/ApplicationSettings.tsx +++ b/interface/src/app/settings/ApplicationSettings.tsx @@ -697,6 +697,16 @@ const ApplicationSettings = () => { } label={LL.DEVELOPER_MODE()} /> + + } + label={LL.OUTDOORSENSOR()} + /> telegram) { (0x0880), data: 01 04 (0x0889), data: 00 80 80 01 */ - +bool Connect::set_outdoorTemp(const char * value, const int8_t id) { + float v; + if (Roomctrl::has_outdoorsensor() && Helpers::value2temperature(value, v)) { + Roomctrl::set_outdoortemp(v * 10); + return true; + } + return false; +} } // namespace emsesp diff --git a/src/devices/connect.h b/src/devices/connect.h index 5db2e11d3..46cec088c 100644 --- a/src/devices/connect.h +++ b/src/devices/connect.h @@ -29,6 +29,7 @@ class Connect : public EMSdevice { private: void process_OutdoorTemp(std::shared_ptr telegram); + bool set_outdoorTemp(const char * value, const int8_t id); int16_t outdoorTemp_; }; diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index d8fe9209e..9c9aed04a 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -257,6 +257,9 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) { if (!strcmp(lowtopic, F_(pool))) { return DeviceType::POOL; } + if (!strcmp(lowtopic, F_(connect))) { + return DeviceType::CONNECT; + } // non EMS if (!strcmp(lowtopic, F_(custom))) { diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 4c7bc5708..1bef947bc 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -685,7 +685,7 @@ void EMSESP::publish_thermostat_timer() { const char * name[] = {FL_(switchprog)[0], FL_(circswitchprog)[0]}; for (uint8_t i = 0; i < sizeof(name) / sizeof(char *); i++) { if (emsdevice->get_value_info(json, name[i], tag)) { - if (json.containsKey("value")) { + if (json["value"].is()) { if ((Mqtt::is_nested())) { if (circuit.isNull()) { circuit = output[EMSdevice::tag_to_mqtt(tag)].to(); @@ -715,9 +715,9 @@ void EMSESP::publish_other_values() { publish_device_values(EMSdevice::DeviceType::EXTENSION); publish_device_values(EMSdevice::DeviceType::ALERT); publish_device_values(EMSdevice::DeviceType::POOL); + publish_device_values(EMSdevice::DeviceType::CONNECT); // other EMS devices without values yet // publish_device_values(EMSdevice::DeviceType::GATEWAY); - // publish_device_values(EMSdevice::DeviceType::CONNECT); // publish_device_values(EMSdevice::DeviceType::GENERIC); webSchedulerService.publish(); @@ -1501,6 +1501,11 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { } else if (first_value == TxService::TX_WRITE_FAIL) { LOG_ERROR("Last Tx write rejected by host"); txservice_.send_poll(); // close the bus + txservice_.reset_retry_count(); + tx_successful = true; // no retries + } else { + txservice_.send_poll(); // close the bus + LOG_ERROR("Last Tx write host reply: 0x%02X", first_value); } } else if (tx_state == Telegram::Operation::TX_READ && length == 1) { EMSbus::tx_state(Telegram::Operation::TX_READ); // reset Tx wait state @@ -1808,7 +1813,7 @@ void EMSESP::start_serial_console() { #if defined(EMSESP_DEBUG) shell_->log_level(uuid::log::Level::DEBUG); #else - shell_->log_level(uuid::log::Level::TRACE); + shell_->log_level(uuid::log::Level::INFO); #endif } diff --git a/src/roomcontrol.cpp b/src/roomcontrol.cpp index 72e8de6b2..0721c3bab 100644 --- a/src/roomcontrol.cpp +++ b/src/roomcontrol.cpp @@ -28,14 +28,22 @@ int16_t Roomctrl::remotetemp_[HCS] = {EMS_VALUE_INT16_NOTSET, EMS_VALUE_INT16 uint8_t Roomctrl::remotehum_[HCS] = {EMS_VALUE_UINT8_NOTSET, EMS_VALUE_UINT8_NOTSET, EMS_VALUE_UINT8_NOTSET, EMS_VALUE_UINT8_NOTSET}; uint8_t Roomctrl::sendtype_[HCS] = {SendType::TEMP, SendType::TEMP, SendType::TEMP, SendType::TEMP}; uint8_t Roomctrl::type_[HCS] = {RemoteType::NONE, RemoteType::NONE, RemoteType::NONE, RemoteType::NONE}; +int16_t Roomctrl::outdoortemp_ = 0; // EMS_VALUE_INT16_NOTSET; +uint32_t Roomctrl::outdoortime_ = 0; +bool Roomctrl::outdoorsensor_ = false; uint32_t Roomctrl::timeout_ = 0; /** * set the temperature, */ +void Roomctrl::set_outdoortemp(const int16_t temp) { + outdoortemp_ = temp < 1000 ? temp : EMS_VALUE_INT16_NOTSET; +} + void Roomctrl::set_timeout(uint8_t t) { timeout_ = t * 3600000; // ms } + void Roomctrl::set_remotetemp(const uint8_t type, const uint8_t hc, const int16_t temp) { if (!type_[hc] && !type) { return; @@ -91,11 +99,22 @@ void Roomctrl::send(uint8_t addr) { if (addr & 0x80) { return; } + if (addr == 0x50 && outdoorsensor_) { + if (uuid::get_uptime() - outdoortime_ > SEND_INTERVAL && outdoortemp_ != EMS_VALUE_INT16_NOTSET) { + outdoortemp(addr, 0); + outdoortime_ = uuid::get_uptime(); + return; + } else { + EMSuart::send_poll(addr | EMSbus::ems_mask()); + return; + } + } uint8_t hc = get_hc(addr); // check address, reply only on addresses 0x18..0x1B or 0x40..0x43 if (hc >= HCS) { return; } + // no reply if the temperature is not set if (!switch_off_[hc] && remotetemp_[hc] == EMS_VALUE_INT16_NOTSET && remotehum_[hc] == EMS_VALUE_UINT8_NOTSET) { return; @@ -145,6 +164,15 @@ void Roomctrl::send(uint8_t addr) { * check if there is a message for the remote room controller */ void Roomctrl::check(uint8_t addr, const uint8_t * data, const uint8_t length) { + // check for read of outdoor temp + if (addr == 0xD0 && outdoorsensor_) { + if (data[2] == 0xD1) { + outdoortemp(0x50, data[0]); + } else if (data[2] == 0x02) { + wirelessversion(0x50, data[0]); + } + return; + } uint8_t hc = get_hc(addr); if (hc >= HCS || length < 5) { return; @@ -252,6 +280,19 @@ void Roomctrl::version(uint8_t addr, uint8_t dst, uint8_t hc) { } } +void Roomctrl::wirelessversion(uint8_t addr, uint8_t dst) { + uint8_t data[20]; + data[0] = addr | EMSbus::ems_mask(); + data[1] = dst & 0x7F; + data[2] = 0x02; + data[3] = 0; + data[4] = 236; // product_id 236 + data[5] = 3; // version 3.03 + data[6] = 3; + data[7] = EMSbus::calculate_crc(data, 7); // append CRC + EMSuart::transmit(data, 8); +} + /** * unknown message id, we reply with empty message */ @@ -308,7 +349,7 @@ void Roomctrl::temperature(uint8_t addr, uint8_t dst, uint8_t hc) { data[5] = 0x2B + hc; data[6] = (uint8_t)(remotetemp_[hc] >> 8); data[7] = (uint8_t)(remotetemp_[hc] & 0xFF); - uint16_t t1 = remotetemp_[hc] * 10 + 3; + uint16_t t1 = remotetemp_[hc] * 10; data[8] = (uint8_t)(t1 >> 8); data[9] = (uint8_t)(t1 & 0xFF); data[10] = 1; // not sure what this is and if we need it, maybe mode? @@ -339,7 +380,7 @@ void Roomctrl::temperature(uint8_t addr, uint8_t dst, uint8_t hc) { data[5] = 0x2B + hc; data[6] = (uint8_t)(remotetemp_[hc] >> 8); data[7] = (uint8_t)(remotetemp_[hc] & 0xFF); - uint16_t t1 = remotetemp_[hc] * 10 + 3; + uint16_t t1 = remotetemp_[hc] * 10; data[8] = (uint8_t)(t1 >> 8); data[9] = (uint8_t)(t1 & 0xFF); data[10] = 1; // not sure what this is and if we need it, maybe mode? @@ -422,5 +463,18 @@ int16_t Roomctrl::calc_dew(int16_t temp, uint8_t humi) { return dt; } +void Roomctrl::outdoortemp(uint8_t addr, uint8_t dst) { + uint8_t data[12]; + data[0] = addr | EMSbus::ems_mask(); + data[1] = dst & 0x7F; + data[2] = 0xD1; + data[3] = 0; + data[4] = (uint8_t)(outdoortemp_ >> 8); + data[5] = (uint8_t)(outdoortemp_ & 0xFF); + data[6] = 0; + data[7] = EMSbus::calculate_crc(data, 7); // apppend CRC + EMSuart::transmit(data, 8); +} + } // namespace emsesp diff --git a/src/roomcontrol.h b/src/roomcontrol.h index c6c5577d2..6993f1648 100644 --- a/src/roomcontrol.h +++ b/src/roomcontrol.h @@ -31,6 +31,13 @@ class Roomctrl { static void check(uint8_t addr, const uint8_t * data, const uint8_t length); static void set_remotetemp(const uint8_t type, const uint8_t hc, const int16_t temp); static void set_remotehum(const uint8_t type, const uint8_t hc, const int8_t hum); + static void set_outdoorsensor(const bool enable) { + outdoorsensor_ = enable; + } + static bool has_outdoorsensor() { + return outdoorsensor_ ; + } + static void set_outdoortemp(const int16_t temp); static bool is_remote(const uint8_t hc) { return (hc < 4 && remotetemp_[hc] != EMS_VALUE_INT16_NOTSET); } @@ -51,6 +58,8 @@ class Roomctrl { static void ack_write(); static void replyF7(uint8_t addr, uint8_t dst, uint8_t offset, uint8_t typehh, uint8_t typeh, uint8_t typel, uint8_t hc); static int16_t calc_dew(int16_t temp, uint8_t hum); + static void outdoortemp(uint8_t addr, uint8_t dst); + static void wirelessversion(uint8_t addr, uint8_t dst); static bool switch_off_[HCS]; static uint32_t send_time_[HCS]; @@ -59,6 +68,9 @@ class Roomctrl { static uint8_t remotehum_[HCS]; static uint8_t sendtype_[HCS]; static uint8_t type_[HCS]; // type is product-id 113 for RC20 or 109 for Junkers FB10 + static int16_t outdoortemp_; + static uint32_t outdoortime_; + static bool outdoorsensor_; static uint32_t timeout_; }; diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index e33f0aeed..39f1726a6 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -81,6 +81,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) { root["modbus_max_clients"] = settings.modbus_max_clients; root["modbus_timeout"] = settings.modbus_timeout; root["developer_mode"] = settings.developer_mode; + root["outdoorsensor"] = settings.outdoorsensor; } // call on initialization and also when settings are updated via web or console @@ -365,6 +366,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { settings.developer_mode = root["developer_mode"]; EMSESP::system_.developer_mode(settings.developer_mode); + settings.outdoorsensor = root["outdoorsensor"]; + emsesp::Roomctrl::set_outdoorsensor(settings.outdoorsensor); + settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT; EMSESP::system_.bool_dashboard(settings.bool_dashboard); diff --git a/src/web/WebSettingsService.h b/src/web/WebSettingsService.h index 57a2a00c8..8030af9b7 100644 --- a/src/web/WebSettingsService.h +++ b/src/web/WebSettingsService.h @@ -83,6 +83,7 @@ class WebSettings { uint8_t eth_clock_mode; bool developer_mode; // developer mode + bool outdoorsensor; static void read(WebSettings & settings, JsonObject root); static StateUpdateResult update(JsonObject root, WebSettings & settings);