#3257 summermode back and a test for #3094

This commit is contained in:
proddy
2026-10-01 17:52:52 +02:00
parent 635daa8ab8
commit e4f9d4a96d
13 changed files with 476 additions and 325 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
- HA Discovery warning on Uptime after EMS-ESP boot due to NTP not ready
- hc/control setting for UI800 thermostats [#3181](https://github.com/emsesp/EMS-ESP32/discussions/3181)
- solar module switches [#3223](https://github.com/emsesp/EMS-ESP32/issues/3223)
- UI800/HMI800.2 thermostats without telegram 0x470 reported `summertemp` as 0 and lost the per-hc heat/cool delays [#3257](https://github.com/emsesp/EMS-ESP32/issues/3257)
- UI800/HMI800.2 thermostats without telegram 0x470 reported `summertemp` as 0 and lost the per-hc heat/cool delays. `summermode` is now also shown for UI800 heatpumps [#3257](https://github.com/emsesp/EMS-ESP32/issues/3257)
- possible crash when the WebUI asked for version information while the versions.json refresh was rewriting the cache from the main loop task
- HTTP client could write past a fixed 64 byte buffer when a URL had a hostname of 64 characters or more, could busy-spin for the whole read budget if the socket reported bytes it wouldn't return, and buffered responses without any size limit
- the "Ethernet clock mode (GPIO16/17) conflicts with PSRAM" error was never logged because Ethernet had already been skipped by the time the check ran
+3 -3
View File
@@ -31,7 +31,7 @@
"@table-library/react-table-library": "4.1.15",
"alova": "^3.5.5",
"jwt-decode": "^4.0.0",
"preact": "^10.29.8",
"preact": "^11.0.0",
"react": "^19.3.0",
"react-dom": "^19.3.0",
"react-icons": "^5.7.0",
@@ -54,9 +54,9 @@
"rollup-plugin-visualizer": "^7.1.1",
"terser": "^5.51.2",
"typescript": "^6.0.3",
"typescript-eslint": "^8.70.1",
"typescript-eslint": "^8.71.0",
"vite": "^8.3.1",
"vite-plugin-imagemin": "^0.6.1"
},
"packageManager": "pnpm@12.6.0"
"packageManager": "pnpm@12.8.1"
}
+242 -248
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -20,6 +20,8 @@
#include <Arduino.h>
#include <sys/time.h>
namespace uuid {
static uint64_t now_millis = 0;
@@ -41,4 +43,11 @@ uint32_t get_uptime() {
return (uint32_t)now_millis;
}
// both clocks are read live and in ms, whole-second values would make the offset jitter by 1s
int64_t get_wall_offset_ms() {
struct timeval tv;
gettimeofday(&tv, nullptr);
return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000 - esp_timer_get_time() / 1000;
}
} // namespace uuid
+3
View File
@@ -105,6 +105,9 @@ uint64_t get_uptime_ms();
uint32_t get_uptime();
uint32_t get_uptime_sec();
// milliseconds to add to an uptime in ms to get the wall clock time in ms since the epoch
int64_t get_wall_offset_ms();
void set_uptime();
} // namespace uuid
+5 -4
View File
@@ -106,14 +106,15 @@ void Shell::output_logs() {
}
while (1) {
time_t offset = time(nullptr) - uuid::get_uptime_sec();
if (offset < 1500000000L) {
int64_t offset_ms = uuid::get_wall_offset_ms();
if (offset_ms < 1500000000000LL) {
print(uuid::log::format_timestamp_ms(message.content_->uptime_ms, 3));
} else {
time_t t1 = offset + (time_t)(message.content_->uptime_ms / 1000);
int64_t wall_ms = offset_ms + (int64_t)message.content_->uptime_ms;
time_t t1 = (time_t)(wall_ms / 1000);
char timestr[25];
strftime(timestr, 25, "%FT%T", localtime(&t1));
printf("%s.%03d", timestr, (uint16_t)(message.content_->uptime_ms % 1000));
printf("%s.%03d", timestr, (int)(wall_ms % 1000));
}
printf(" %c %lu: [%s] ", uuid::log::format_level_char(message.content_->level), message.id_, message.content_->name);
+1 -1
View File
@@ -17,5 +17,5 @@
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"prettier": "^3.9.9"
},
"packageManager": "pnpm@12.6.0"
"packageManager": "pnpm@12.8.1"
}
+61 -61
View File
@@ -7,153 +7,153 @@ importers:
configDependencies: {}
packageManagerDependencies:
pnpm:
specifier: 12.6.0
version: 12.6.0
specifier: 12.8.1
version: 12.8.1
packages:
'@pnpm/exe.android-arm64@12.6.0':
resolution: {integrity: sha512-kviIHft9h02q+7N2In7tSL9T/HRUSGwYmU74YPtsWU5ee7vgqPyC0JT6RRX6miW+NxX1CvHgQxg69qq1qTLJYQ==}
'@pnpm/exe.android-arm64@12.8.1':
resolution: {integrity: sha512-siDxcidfz5eM6L2tJfik+i2bbUEw8UC7MZ3Yl2HYdRmqbdhHGAOQACtOOu6QVW4Jul4/w5wVKm+wM8ACtgh1Pg==}
cpu: [arm64]
os: [android]
'@pnpm/exe.android-x64@12.6.0':
resolution: {integrity: sha512-CT8aJKLq2mtZFE71pr4E5Z2xHL8uGnRGr+NclDqsXlVF4SVcQ2QAs14mWi0C8gjT4hbmi+Q0lJRRIkMAWfjjng==}
'@pnpm/exe.android-x64@12.8.1':
resolution: {integrity: sha512-0F/uqPRc3aN4vLHsa0f+6fTtmsigFQ9/yxEU43fionF//pNHEd5e97b3w/nKIgqYMCUQCJphmBRMA9Q8/wlo9Q==}
cpu: [x64]
os: [android]
'@pnpm/exe.darwin-arm64@12.6.0':
resolution: {integrity: sha512-rafpVkjzugKBMxSvGQd5wK1x5eOTkD/+lcJIFHeQhvd+BJ8kDisOOvwhQDrpGd4vd2Fx+hhW0P2Ptt638OlhFg==}
'@pnpm/exe.darwin-arm64@12.8.1':
resolution: {integrity: sha512-/rwavvMQJsl2RIxOHBnDF+4Gk+fhQFAY4M3PQZoKskJOEnaJcygG9p1xby6wcQcbS4d9dIubv09CQhufTgfmpw==}
cpu: [arm64]
os: [darwin]
'@pnpm/exe.darwin-x64@12.6.0':
resolution: {integrity: sha512-72Jpuv1m24gI8zUNcaylYpBWEhBzz1VPhnDIU2GYM2eRP+KsOqVLwV78i+JrihI39zY2NNXmaN4eAKX1inpaDQ==}
'@pnpm/exe.darwin-x64@12.8.1':
resolution: {integrity: sha512-htYt2gN7zqJKLhC99Ft6EUiO7myjZAZXfmGCTJUL1v+o7vE9hZdE1+fAkk4Oj1ZHNRti6b2woOxEkRkAusi8OQ==}
cpu: [x64]
os: [darwin]
'@pnpm/exe.freebsd-x64@12.6.0':
resolution: {integrity: sha512-LON4QgNy1w/XF4uySZIyC/5hEB0oGdelXsY9tSKqstER+2j2X2oHz67skD11RRd/HWFRtMr64shQZ4I9ZoZ0zg==}
'@pnpm/exe.freebsd-x64@12.8.1':
resolution: {integrity: sha512-PB5BULNgytxvExoOXUUeseS/DcpPENs+cg3iA6xHHeaLT4ctEGKSGXEbuj7USeqvo8JBpAx039hivnbzGqDwnA==}
cpu: [x64]
os: [freebsd]
'@pnpm/exe.linux-arm64-musl@12.6.0':
resolution: {integrity: sha512-BdDpX+DeaMUc5x6WNcE6FkmFy36NwrBbBvwsZU737Zt3u1fTY+iKFPchjEQNCM4rT6q6xvF2oN3ZwExGsJCkxQ==}
'@pnpm/exe.linux-arm64-musl@12.8.1':
resolution: {integrity: sha512-kKeyC/ArjrgdciQRBrOL0j9HtOI4gDRgoyP+eJ1CQKyadpKlf/DhDDyspXe07R3B9KagTVLUF2nlt6Dr5quFIg==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@pnpm/exe.linux-arm64@12.6.0':
resolution: {integrity: sha512-8h2sNoIhHDpHDYqZZCh9PXr6krqW10btb0GHVGuw710muDHlFAHMtUG2ogmaHge6zJG1xgY4Y7mwX5g/LWvrYg==}
'@pnpm/exe.linux-arm64@12.8.1':
resolution: {integrity: sha512-q4s9a9X2O3N9aeUFooW24orNrxvu20+jyVUFR5RanPCqOKKPBrgs2iywMkBBx1aXkkzdWT54/mfz8Be8sJlWEw==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-ppc64@12.6.0':
resolution: {integrity: sha512-ld6xgcEhFCFrsVsJhbmdmR714PnsEspO/Ij8w0/D7OSiz2hYGu3fZd5tKRxOI5m6H6Gl0/RRFAPncTHbsgXVjQ==}
'@pnpm/exe.linux-ppc64@12.8.1':
resolution: {integrity: sha512-F7XSjKJthwCh/L6abZiMpAfo2Cm61SZIT3e4dfgiIjESndlWaXCnfLKngSgZ/SEMsdmHT6dud3+kWIB3tw0/xQ==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-riscv64@12.6.0':
resolution: {integrity: sha512-HIbImydoC3J8NFt+8MXfhTCf5rO6NjCMyinSAHac0VmV8uCHw+kbQkyAzxV84rzz9ZOzmBOnj0b1N461UIYGsw==}
'@pnpm/exe.linux-riscv64@12.8.1':
resolution: {integrity: sha512-z1ecpIK/ZY08Unk69KWWE9867oaKUytGUjrHnBoGFAAhsK+q+0cfvBH+f5fWobJ7FX97leMlLO+gkJolddM45Q==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-s390x@12.6.0':
resolution: {integrity: sha512-DjSqT7+BZ/lWcDHwNMuzsRVfyxUimh+D54Xw4tSWbdVVQhtWtNMUyI93LVnwCmsoEpar2gC3SFeAgywx37svKQ==}
'@pnpm/exe.linux-s390x@12.8.1':
resolution: {integrity: sha512-KU6tnrBfu4uKXTq6N5qJwSm8FSrs9Wc8b5AUEsHK9bRXwNdsZ1/lRxG1++X29SKRW9OSNuDSjxASv5mAvGo1gA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@pnpm/exe.linux-x64-musl@12.6.0':
resolution: {integrity: sha512-31lKeGPmRE6xfV6I3VjaEGVFRei14pl/zgoFDK4w+UkbJqOuNl2Ht3O1GuqNIg3Gl14qTEb4kZRAYFHXifDx9A==}
'@pnpm/exe.linux-x64-musl@12.8.1':
resolution: {integrity: sha512-eUE8BWJkDr2tJb/yrk0yVnszlmNqFarVxUlqiZ9BAkct28Nq/5g2H0tvMDmPA7fAQW3STNj+omJPPRVT+4s5sQ==}
cpu: [x64]
os: [linux]
libc: [musl]
'@pnpm/exe.linux-x64@12.6.0':
resolution: {integrity: sha512-qFWBneHJAJ73W4whtbaFOL1M/7DBC6ILHXuxc7ZPtEhfPuT1zeZiGrmKHoMAfJA+mcm6xhOFljqVTUS+00Jabw==}
'@pnpm/exe.linux-x64@12.8.1':
resolution: {integrity: sha512-8bDZ0lZlCdi2rvnFul7EYgcC7zKeWSe76y8JV2oXobaS8p9i9d6PSf6LgLtTM0fI7R9Oh4eLCbveXyNDMmvZ+g==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@pnpm/exe.win32-arm64@12.6.0':
resolution: {integrity: sha512-OhfefXEEykZlslSUhR8PPRe6MVPV3Oink/dVfIecE5velpc7j80cZYsHlaDrtRDcm3TPwQHkaRW1SJ1efX9oFg==}
'@pnpm/exe.win32-arm64@12.8.1':
resolution: {integrity: sha512-MsT0dlrRxnCRCHCaosNbhWpEiAFnFuMEu3KuDJDU41BXgTwiINxU8goloUSUDejWZUqKaUqNC/qUTihl9nFtqg==}
cpu: [arm64]
os: [win32]
'@pnpm/exe.win32-x64@12.6.0':
resolution: {integrity: sha512-L2tuyrD2+Imgxs3VK/ST/2L3xD6vDP0ktJQxM0TaGw7TbAQEMq+RMc8iK6Ew7Id579uzjJe8jSfJID2ZGsOHCA==}
'@pnpm/exe.win32-x64@12.8.1':
resolution: {integrity: sha512-SWtPe0PsbTTk//gJND10tMdOfCYjrkq5+qV49hzVhY7xz2iJ339Rc+xwASlcvbwTfrvH39YNqpKYibD+CRGLwA==}
cpu: [x64]
os: [win32]
pnpm@12.6.0:
resolution: {integrity: sha512-PvaPlRyxEawgS0paFvCy3fDaVqluBBPoHYVdnwtV75JnFHCQKOHNAMQFwsX7e56OxNxGd3yAXQNzwvL/AP0g7A==}
pnpm@12.8.1:
resolution: {integrity: sha512-9kupB1B/XOr+BsjTjmBS0BeURFgOwSed3Vv8EctIqoomRLZlmOB+dh2oSHKp/FfV+QK4f6SdAkGY1VhhKqu+RQ==}
engines: {node: '>=18.*'}
hasBin: true
snapshots:
'@pnpm/exe.android-arm64@12.6.0':
'@pnpm/exe.android-arm64@12.8.1':
optional: true
'@pnpm/exe.android-x64@12.6.0':
'@pnpm/exe.android-x64@12.8.1':
optional: true
'@pnpm/exe.darwin-arm64@12.6.0':
'@pnpm/exe.darwin-arm64@12.8.1':
optional: true
'@pnpm/exe.darwin-x64@12.6.0':
'@pnpm/exe.darwin-x64@12.8.1':
optional: true
'@pnpm/exe.freebsd-x64@12.6.0':
'@pnpm/exe.freebsd-x64@12.8.1':
optional: true
'@pnpm/exe.linux-arm64-musl@12.6.0':
'@pnpm/exe.linux-arm64-musl@12.8.1':
optional: true
'@pnpm/exe.linux-arm64@12.6.0':
'@pnpm/exe.linux-arm64@12.8.1':
optional: true
'@pnpm/exe.linux-ppc64@12.6.0':
'@pnpm/exe.linux-ppc64@12.8.1':
optional: true
'@pnpm/exe.linux-riscv64@12.6.0':
'@pnpm/exe.linux-riscv64@12.8.1':
optional: true
'@pnpm/exe.linux-s390x@12.6.0':
'@pnpm/exe.linux-s390x@12.8.1':
optional: true
'@pnpm/exe.linux-x64-musl@12.6.0':
'@pnpm/exe.linux-x64-musl@12.8.1':
optional: true
'@pnpm/exe.linux-x64@12.6.0':
'@pnpm/exe.linux-x64@12.8.1':
optional: true
'@pnpm/exe.win32-arm64@12.6.0':
'@pnpm/exe.win32-arm64@12.8.1':
optional: true
'@pnpm/exe.win32-x64@12.6.0':
'@pnpm/exe.win32-x64@12.8.1':
optional: true
pnpm@12.6.0:
pnpm@12.8.1:
optionalDependencies:
'@pnpm/exe.android-arm64': 12.6.0
'@pnpm/exe.android-x64': 12.6.0
'@pnpm/exe.darwin-arm64': 12.6.0
'@pnpm/exe.darwin-x64': 12.6.0
'@pnpm/exe.freebsd-x64': 12.6.0
'@pnpm/exe.linux-arm64': 12.6.0
'@pnpm/exe.linux-arm64-musl': 12.6.0
'@pnpm/exe.linux-ppc64': 12.6.0
'@pnpm/exe.linux-riscv64': 12.6.0
'@pnpm/exe.linux-s390x': 12.6.0
'@pnpm/exe.linux-x64': 12.6.0
'@pnpm/exe.linux-x64-musl': 12.6.0
'@pnpm/exe.win32-arm64': 12.6.0
'@pnpm/exe.win32-x64': 12.6.0
'@pnpm/exe.android-arm64': 12.8.1
'@pnpm/exe.android-x64': 12.8.1
'@pnpm/exe.darwin-arm64': 12.8.1
'@pnpm/exe.darwin-x64': 12.8.1
'@pnpm/exe.freebsd-x64': 12.8.1
'@pnpm/exe.linux-arm64': 12.8.1
'@pnpm/exe.linux-arm64-musl': 12.8.1
'@pnpm/exe.linux-ppc64': 12.8.1
'@pnpm/exe.linux-riscv64': 12.8.1
'@pnpm/exe.linux-s390x': 12.8.1
'@pnpm/exe.linux-x64': 12.8.1
'@pnpm/exe.linux-x64-musl': 12.8.1
'@pnpm/exe.win32-arm64': 12.8.1
'@pnpm/exe.win32-x64': 12.8.1
---
lockfileVersion: '9.0'
+1
View File
@@ -50,6 +50,7 @@ build_flags =
; -D EMSESP_MQTT_STACKSIZE=5120 ; default
-D EMSESP_UART_RUNNING_CORE=1 ; default any core
; -D EMSESP_UART_STACKSIZE=2560 ; default
; -D EMSESP_GATEWAY_TX_HOLD ; hold Tx while a K30RF/KM200 gateway is syncing, see issue #3094
unbuild_flags =
${common.core_unbuild_flags}
+115
View File
@@ -49,6 +49,16 @@ uint16_t EMSESP::wait_validate_ = 0;
bool EMSESP::wait_km_ = false;
uint32_t EMSESP::last_fetch_ = 0;
#ifdef EMSESP_GATEWAY_TX_HOLD
uint32_t EMSESP::gateway_hold_until_ = 0;
uint32_t EMSESP::gateway_hold_start_ = 0;
uint32_t EMSESP::gateway_cooldown_until_ = 0;
uint32_t EMSESP::gateway_window_start_ = 0;
uint8_t EMSESP::gateway_window_count_ = 0;
uint8_t EMSESP::last_version_request_src_ = 0;
uint32_t EMSESP::last_version_request_time_ = 0;
#endif
uint32_t EMSESP::last_entity_change_ = 0;
bool EMSESP::entity_compaction_pending_ = false;
@@ -1130,9 +1140,26 @@ void EMSESP::process_version(const std::shared_ptr<const Telegram> & telegram) {
brand = EMSdevice::Brand::NO_BRAND; // unknown
}
#ifdef EMSESP_GATEWAY_TX_HOLD
// skip the name request if we already know this device and its name
bool known = false;
for (const auto & emsdevice : emsdevices) {
if (emsdevice && emsdevice->is_device_id(device_id) && emsdevice->product_id() == product_id && !emsdevice->model().empty()) {
known = true;
break;
}
}
#endif
// add it - will be overwritten if device already exists
(void)add_device(device_id, product_id, version, brand);
#ifdef EMSESP_GATEWAY_TX_HOLD
if (known) {
return;
}
#endif
// request the deviceName from telegram 0x01
send_read_request(EMSdevice::EMS_TYPE_NAME, device_id, 27);
}
@@ -1249,8 +1276,17 @@ bool EMSESP::process_telegram(const std::shared_ptr<const Telegram> & telegram)
LOG_NOTICE("%s", pretty_telegram(telegram).c_str());
}
if (!wait_km_ && !found_device && (telegram->src != EMSbus::ems_bus_id()) && (telegram->message_length > 0)) {
#ifdef EMSESP_GATEWAY_TX_HOLD
// a new device often sends several broadcasts before its version reply is processed, only ask once
if (telegram->src != last_version_request_src_ || uuid::get_uptime() - last_version_request_time_ > 5000) {
last_version_request_src_ = telegram->src;
last_version_request_time_ = uuid::get_uptime();
send_read_request(EMSdevice::EMS_TYPE_VERSION, telegram->src);
}
#else
send_read_request(EMSdevice::EMS_TYPE_VERSION, telegram->src);
#endif
}
}
}
return telegram_found;
@@ -1511,6 +1547,13 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
// Print to LOG showing we've added a new device
LOG_INFO("Detected EMS device: %s (0x%02X)", EMSdevice::device_type_2_device_name(device_type), device_id);
#ifdef EMSESP_GATEWAY_TX_HOLD
// a gateway appearing while we're running is most likely starting up and about to sync
if (device_id == EMSdevice::EMS_DEVICE_ID_GATEWAY1) {
gateway_tx_hold_start();
}
#endif
// register the MQTT subscribe topic for this device
// except for controller and gateway
if ((device_type == DeviceType::CONTROLLER) || (device_type == DeviceType::GATEWAY)) {
@@ -1656,6 +1699,11 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
}
#endif
// check for poll to us, if so send top message from Tx queue immediately and quit
#ifdef EMSESP_GATEWAY_TX_HOLD
if (poll_id == EMSbus::ems_bus_id() && gateway_tx_hold()) {
return;
}
#endif
if (poll_id == txservice_.get_send_id()) {
txservice_.send();
} else {
@@ -1670,6 +1718,10 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
#endif
Roomctrl::check(data[1], data, length); // check if there is a message for the roomcontroller
#ifdef EMSESP_GATEWAY_TX_HOLD
gateway_rx_check(data, length);
#endif
rxservice_.add(data, length); // add to RxQueue
}
}
@@ -1677,6 +1729,11 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
// fetch devices one by one
void EMSESP::scheduled_fetch_values() {
static uint8_t no = 0;
#ifdef EMSESP_GATEWAY_TX_HOLD
if (gateway_tx_hold()) {
return;
}
#endif
if (no || (uuid::get_uptime() - last_fetch_ > EMS_FETCH_FREQUENCY)) {
if (!no) {
last_fetch_ = uuid::get_uptime();
@@ -1698,6 +1755,64 @@ void EMSESP::scheduled_fetch_values() {
}
}
#ifdef EMSESP_GATEWAY_TX_HOLD
// count read requests from the gateway to other devices, a high rate means it's doing its startup sync
void EMSESP::gateway_rx_check(const uint8_t * data, const uint8_t length) {
if (length < 4 || (data[0] & 0x7F) != EMSdevice::EMS_DEVICE_ID_GATEWAY1 || !(data[1] & 0x80)) {
return;
}
uint8_t dest = data[1] & 0x7F;
if (dest == 0 || dest == EMSbus::ems_bus_id()) {
return;
}
uint32_t now = uuid::get_uptime();
if (now - gateway_window_start_ > GATEWAY_BURST_WINDOW) {
gateway_window_start_ = now;
gateway_window_count_ = 0;
}
if (++gateway_window_count_ >= GATEWAY_BURST_THRESHOLD) {
gateway_window_start_ = now;
gateway_window_count_ = 0;
gateway_tx_hold_start();
}
}
void EMSESP::gateway_tx_hold_start() {
uint32_t now = uuid::get_uptime();
if (gateway_cooldown_until_) {
if ((int32_t)(now - gateway_cooldown_until_) < 0) {
return;
}
gateway_cooldown_until_ = 0;
}
if (!gateway_hold_until_) {
gateway_hold_start_ = now;
LOG_INFO("Gateway 0x%02X is busy, holding Tx", EMSdevice::EMS_DEVICE_ID_GATEWAY1);
}
gateway_hold_until_ = (now + GATEWAY_HOLD_TIME) | 1; // 0 means no hold
}
bool EMSESP::gateway_tx_hold() {
if (!gateway_hold_until_) {
return false;
}
uint32_t now = uuid::get_uptime();
if (now - gateway_hold_start_ > GATEWAY_HOLD_MAX) {
gateway_hold_until_ = 0;
gateway_cooldown_until_ = (now + GATEWAY_HOLD_COOLDOWN) | 1;
LOG_WARNING("Gateway 0x%02X still busy after %lu s, resuming Tx", EMSdevice::EMS_DEVICE_ID_GATEWAY1, (unsigned long)(GATEWAY_HOLD_MAX / 1000));
return false;
}
if ((int32_t)(now - gateway_hold_until_) >= 0) {
gateway_hold_until_ = 0;
LOG_INFO("Gateway 0x%02X is quiet, resuming Tx after %lu s", EMSdevice::EMS_DEVICE_ID_GATEWAY1, (unsigned long)((now - gateway_hold_start_) / 1000));
return false;
}
return true;
}
#endif
// EMSESP main class
EMSESP::EMSESP()
#ifndef EMSESP_STANDALONE
+22
View File
@@ -291,6 +291,28 @@ class EMSESP {
static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute
static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute
#ifdef EMSESP_GATEWAY_TX_HOLD
// hold our Tx while a gateway (K30RF/KM200 on 0x48) is doing its startup sync, see issue #3094
// a startup sync is 55-250 read requests/min to other devices, normal operation is <10/min
static void gateway_rx_check(const uint8_t * data, const uint8_t length);
static bool gateway_tx_hold();
static void gateway_tx_hold_start();
static constexpr uint32_t GATEWAY_BURST_WINDOW = 30000; // ms window for counting gateway read requests
static constexpr uint8_t GATEWAY_BURST_THRESHOLD = 15; // read requests within window to treat gateway as busy
static constexpr uint32_t GATEWAY_HOLD_TIME = 60000; // keep holding Tx this long after the last busy window
static constexpr uint32_t GATEWAY_HOLD_MAX = 600000; // never hold longer than 10 minutes in one go
static constexpr uint32_t GATEWAY_HOLD_COOLDOWN = 600000; // after hitting the max, don't hold again for 10 minutes
static uint32_t gateway_hold_until_;
static uint32_t gateway_hold_start_;
static uint32_t gateway_cooldown_until_;
static uint32_t gateway_window_start_;
static uint8_t gateway_window_count_;
static uint8_t last_version_request_src_;
static uint32_t last_version_request_time_;
#endif
static constexpr uint32_t SYSTEM_STATUS_RESET_TIMEOUT = 300000; // return a non-normal system status to normal after this (in ms) - 5 minutes
struct Device_record {
+5
View File
@@ -1180,8 +1180,13 @@ void Thermostat::process_RC300Monitor(const std::shared_ptr<const Telegram> & te
has_update(hc->hpoperatingstate, EMS_VALUE_UINT8_NOTSET);
} else {
has_enumupdate(telegram, hc->hpoperatingstate, 20, 1); // 1:heating, 2:off, 3:cooling
// UI800 heatpumps report a valid summer bit, older RC300 heatpumps don't, #3257
if (model() == EMSdevice::EMS_DEVICE_FLAG_UI800) {
has_update(hc->summermode, hc->statusbyte & 0x50 ? 1 : 0);
} else {
has_update(hc->summermode, EMS_VALUE_UINT8_NOTSET);
}
}
has_update(telegram, hc->targetflowtemp, 4);
has_update(telegram, hc->curroominfl, 27);
has_update(telegram, hc->currSolarInfl, 29);
+5 -4
View File
@@ -156,14 +156,15 @@ void WebLogService::loop() {
// convert time to real offset
char * WebLogService::messagetime(char * out, const uint64_t t, const size_t bufsize) {
time_t offset = time(nullptr) - uuid::get_uptime_sec();
if (offset < 1500000000L) {
int64_t offset_ms = uuid::get_wall_offset_ms();
if (offset_ms < 1500000000000LL) {
strlcpy(out, uuid::log::format_timestamp_ms(t, 3).c_str(), bufsize);
} else {
time_t t1 = offset + (time_t)(t / 1000);
int64_t wall_ms = offset_ms + (int64_t)t;
time_t t1 = (time_t)(wall_ms / 1000);
char timestr[25];
strftime(timestr, 25, "%FT%T", localtime(&t1));
snprintf(out, bufsize, "%s.%03d", timestr, (uint16_t)(t % 1000));
snprintf(out, bufsize, "%s.%03d", timestr, (int)(wall_ms % 1000));
}
return out;
}