From 97bb03d703aaacadcb5e78c60a93babab26fbde6 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 15 Feb 2026 12:01:10 +0100 Subject: [PATCH 1/9] add missing check for number mode change --- src/ESP32React/MqttSettingsService.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ESP32React/MqttSettingsService.cpp b/src/ESP32React/MqttSettingsService.cpp index 1c07748f0..5bcaa9562 100644 --- a/src/ESP32React/MqttSettingsService.cpp +++ b/src/ESP32React/MqttSettingsService.cpp @@ -316,6 +316,10 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) changed = true; } + if (newSettings.ha_number_mode != settings.ha_number_mode) { + changed = true; + } + if (newSettings.entity_format != settings.entity_format) { changed = true; } From e303972d263b6eb7a7f3a1e7ef2282d1d803ee2a Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 15 Feb 2026 12:01:50 +0100 Subject: [PATCH 2/9] update AsyncWebserver and pkg --- interface/pnpm-lock.yaml | 62 +++++++++++++++++++++++++--------------- platformio.ini | 2 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index cefa009f5..84c3fb679 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -508,13 +508,9 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.1': - resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} - engines: {node: 20 || >=22} + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1062,6 +1058,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.2: + resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} + engines: {node: 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1101,6 +1101,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.2: + resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==} + engines: {node: 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -1155,8 +1159,8 @@ packages: resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} engines: {node: '>=0.10.0'} - caniuse-lite@1.0.30001769: - resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} + caniuse-lite@1.0.30001770: + resolution: {integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==} caw@2.0.1: resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==} @@ -2077,6 +2081,10 @@ packages: resolution: {integrity: sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==} engines: {node: '>= 4'} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} + javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} @@ -2247,8 +2255,8 @@ packages: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} - minimatch@10.1.2: - resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} + minimatch@10.2.0: + resolution: {integrity: sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==} engines: {node: 20 || >=22} minimatch@3.1.2: @@ -3432,7 +3440,7 @@ snapshots: dependencies: '@eslint/object-schema': 3.0.1 debug: 4.4.3 - minimatch: 10.1.2 + minimatch: 10.2.0 transitivePeerDependencies: - supports-color @@ -3466,11 +3474,7 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.1': - dependencies: - '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@9.0.0': {} '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -3805,7 +3809,7 @@ snapshots: '@types/minimatch@6.0.0': dependencies: - minimatch: 10.1.2 + minimatch: 10.2.0 '@types/node@25.2.3': dependencies: @@ -3986,6 +3990,10 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.2: + dependencies: + jackspeak: 4.2.3 + base64-js@1.5.1: {} baseline-browser-mapping@2.9.19: {} @@ -4039,6 +4047,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.2: + dependencies: + balanced-match: 4.0.2 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -4046,7 +4058,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.19 - caniuse-lite: 1.0.30001769 + caniuse-lite: 1.0.30001770 electron-to-chromium: 1.5.286 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -4105,7 +4117,7 @@ snapshots: camelcase@2.1.1: {} - caniuse-lite@1.0.30001769: {} + caniuse-lite@1.0.30001770: {} caw@2.0.1: dependencies: @@ -4581,7 +4593,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.1.2 + minimatch: 10.2.0 natural-compare: 1.4.0 optionator: 0.9.4 transitivePeerDependencies: @@ -5116,6 +5128,10 @@ snapshots: has-to-string-tag-x: 1.4.1 is-object: 1.0.2 + jackspeak@4.2.3: + dependencies: + '@isaacs/cliui': 9.0.0 + javascript-natural-sort@0.7.1: {} jpegtran-bin@5.0.2: @@ -5274,9 +5290,9 @@ snapshots: mimic-response@1.0.1: {} - minimatch@10.1.2: + minimatch@10.2.0: dependencies: - '@isaacs/brace-expansion': 5.0.1 + brace-expansion: 5.0.2 minimatch@3.1.2: dependencies: diff --git a/platformio.ini b/platformio.ini index 19b466fdc..c0319c603 100644 --- a/platformio.ini +++ b/platformio.ini @@ -106,7 +106,7 @@ board_build.filesystem = littlefs lib_deps = bblanchon/ArduinoJson @ 7.4.2 ESP32Async/AsyncTCP @ 3.4.10 - ESP32Async/ESPAsyncWebServer @ 3.9.6 + ESP32Async/ESPAsyncWebServer @ 3.10.0 https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8 From 27c471f45ff4370335851da38a0544917da7f645 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 15 Feb 2026 12:02:36 +0100 Subject: [PATCH 3/9] set model for ems-esp devices, #2958 --- src/core/mqtt.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index d559efcac..225c7f56e 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -1545,9 +1545,7 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool crea // add mf (manufacturer/brand), mdl (model), sw (software version) and via_device dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP"; - if (model != nullptr) { - dev_json["mdl"] = model; - } + dev_json["mdl"] = model != nullptr ? model : "EMS-ESP"; dev_json["sw"] = version != nullptr ? version : "v" + std::string(EMSESP_APP_VERSION); dev_json["via_device"] = Mqtt::basename(); } From 72f08a86cfc856643af12cee24cc3ff8e42106ca Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 15 Feb 2026 12:03:07 +0100 Subject: [PATCH 4/9] fix SRC climate, #2960 --- src/core/emsdevice.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/core/emsdevice.cpp b/src/core/emsdevice.cpp index dc558c413..12b594d41 100644 --- a/src/core/emsdevice.cpp +++ b/src/core/emsdevice.cpp @@ -2135,7 +2135,7 @@ void EMSdevice::mqtt_ha_entity_config_create() { if (needs_update) { const char * const ** mode_options = nullptr; - for (auto & d : devicevalues_) { + for (const auto & d : devicevalues_) { // make sure mode in same circuit is DeviceValueType::ENUM if ((d.tag == dv.tag) && (d.type == DeviceValueType::ENUM) && !strcmp(d.short_name, FL_(mode)[0]) && (d.options_size > 0)) { // get options @@ -2167,19 +2167,25 @@ void EMSdevice::mqtt_ha_entity_config_create() { } // SRC thermostats mapped to connect/src1/... always contains mode, seltemp, currtemp - if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(mode)[0])) { - // add icon if we have one - const char * icon = nullptr; - for (auto & d : devicevalues_) { - if (d.tag == dv.tag && !strcmp(d.short_name, FL_(icon)[0]) && (dv.type == DeviceValueType::ENUM)) { + if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(seltemp)[0])) { + // add modes and icon if we have one + const char * icon = nullptr; + const char * const ** mode_options = nullptr; + for (const auto & d : devicevalues_) { + if ((d.tag != dv.tag) || (d.type != DeviceValueType::ENUM)) { + continue; + } + if (!strcmp(d.short_name, FL_(mode)[0]) && (d.options_size > 0)) { + mode_options = d.options; + } + if (!strcmp(d.short_name, FL_(icon)[0])) { uint8_t val = *(uint8_t *)(d.value_p); if (val != 0 && val < d.options_size) { icon = d.options[val][0]; } - break; } } - Mqtt::publish_ha_climate_config(dv, true, dv.options, false, icon); + Mqtt::publish_ha_climate_config(dv, true, mode_options, false, icon); count++; } From a811670c5a2fa48b8b92d2618c2a1f228504f016 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 15 Feb 2026 12:03:33 +0100 Subject: [PATCH 5/9] 3.8.2-dev.6, changelog --- CHANGELOG_LATEST.md | 3 ++- src/emsesp_version.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 232b748fb..c537e0dc4 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -8,10 +8,11 @@ For more details go to [emsesp.org](https://emsesp.org/). - comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935) - customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784) +- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958) ## Fixed -- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) +- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960) ## Changed diff --git a/src/emsesp_version.h b/src/emsesp_version.h index 1d71f4366..3945693dd 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.8.2-dev.5" +#define EMSESP_APP_VERSION "3.8.2-dev.6" From 148a721e173928351b85cb03c87f12dc35babaf5 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 15 Feb 2026 16:49:21 +0100 Subject: [PATCH 6/9] read connect seltemp after mode/icon to create HA-climate --- src/devices/connect.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp index 4a96c0700..256d26d3f 100644 --- a/src/devices/connect.cpp +++ b/src/devices/connect.cpp @@ -129,15 +129,20 @@ void Connect::process_roomThermostat(std::shared_ptr telegram) { } has_update(telegram, rc->temp_, 0); has_update(telegram, rc->humidity_, 2); // could show -3 if not set - has_update(telegram, rc->seltemp_, 3); + // make sure we have read mode and icon, needed for ha climate + if (!Mqtt::ha_enabled() || (Helpers::hasValue(rc->mode_) && Helpers::hasValue(rc->icon_))) { + has_update(telegram, rc->seltemp_, 3); + } // calculate dew temperature - const float k2 = 17.62; - const float k3 = 243.12; - const float t = (float)rc->temp_ / 10; - const float h = (float)rc->humidity_ / 100; - int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h))); - has_update(rc->dewtemp_, dt); + if (rc->humidity_ >= 0 && rc->humidity_ <= 100) { + const float k2 = 17.62; + const float k3 = 243.12; + const float t = (float)rc->temp_ / 10; + const float h = (float)rc->humidity_ / 100; + int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h))); + has_update(rc->dewtemp_, dt); + } } // gateway(0x48) W gateway(0x50), ?(0x0B42), data: 01 // icon in offset 0 From d627404dc2bd0552f7c5a2b272dc2c1e9609740a Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 16 Feb 2026 07:47:13 +0100 Subject: [PATCH 7/9] skip onEvent for AP, MQTT, NTP --- src/ESP32React/APSettingsService.cpp | 43 +++++++++----------------- src/ESP32React/APSettingsService.h | 1 - src/ESP32React/ESP32React.cpp | 1 + src/ESP32React/MqttSettingsService.cpp | 34 ++++++-------------- src/ESP32React/MqttSettingsService.h | 1 - src/ESP32React/NTPSettingsService.cpp | 28 ++++------------- src/ESP32React/NTPSettingsService.h | 2 +- 7 files changed, 33 insertions(+), 77 deletions(-) diff --git a/src/ESP32React/APSettingsService.cpp b/src/ESP32React/APSettingsService.cpp index 47d90a8b1..a68037738 100644 --- a/src/ESP32React/APSettingsService.cpp +++ b/src/ESP32React/APSettingsService.cpp @@ -10,7 +10,6 @@ APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityM , _reconfigureAp(false) , _connected(0) { addUpdateHandler([this] { reconfigureAP(); }, false); - WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); }); } void APSettingsService::begin() { @@ -19,39 +18,27 @@ void APSettingsService::begin() { // reconfigureAP(); } -// wait 10 sec on STA disconnect before starting AP -void APSettingsService::WiFiEvent(WiFiEvent_t event) { - const uint8_t was_connected = _connected; - switch (event) { - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - _connected &= ~1U; - break; - case ARDUINO_EVENT_ETH_DISCONNECTED: - _connected &= ~2U; - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP: - case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - _connected |= 1U; - break; - case ARDUINO_EVENT_ETH_GOT_IP: - case ARDUINO_EVENT_ETH_GOT_IP6: - _connected |= 2U; - break; - default: - return; - } - // wait 10 sec before starting AP - if (was_connected && !_connected) { - _lastManaged = uuid::get_uptime(); - } -} - void APSettingsService::reconfigureAP() { _lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY; _reconfigureAp = true; } void APSettingsService::loop() { + const uint8_t was_connected = _connected; + if (WiFi.isConnected()) { + _connected |= 1U; + } else { + _connected &= ~1U; + } + if (ETH.connected()) { + _connected |= 2U; + } else { + _connected &= ~2U; + } + // wait 10 sec before starting AP + if (was_connected && !_connected) { + _lastManaged = uuid::get_uptime(); + } const unsigned long currentMillis = uuid::get_uptime(); if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) { _lastManaged = currentMillis; diff --git a/src/ESP32React/APSettingsService.h b/src/ESP32React/APSettingsService.h index 9b52f84d0..21eb24075 100644 --- a/src/ESP32React/APSettingsService.h +++ b/src/ESP32React/APSettingsService.h @@ -104,7 +104,6 @@ class APSettingsService : public StatefulService { void startAP(); void stopAP(); void handleDNS(); - void WiFiEvent(WiFiEvent_t event); }; #endif diff --git a/src/ESP32React/ESP32React.cpp b/src/ESP32React/ESP32React.cpp index 41536153f..9b533dfba 100644 --- a/src/ESP32React/ESP32React.cpp +++ b/src/ESP32React/ESP32React.cpp @@ -84,4 +84,5 @@ void ESP32React::loop() { _networkSettingsService.loop(); _apSettingsService.loop(); _mqttSettingsService.loop(); + _ntpSettingsService.loop(); } \ No newline at end of file diff --git a/src/ESP32React/MqttSettingsService.cpp b/src/ESP32React/MqttSettingsService.cpp index 63879e6a8..7049c5713 100644 --- a/src/ESP32React/MqttSettingsService.cpp +++ b/src/ESP32React/MqttSettingsService.cpp @@ -9,7 +9,6 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur , _disconnectedAt(0) , _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED) , _mqttClient(nullptr) { - WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); }); addUpdateHandler([this] { onConfigUpdated(); }, false); } @@ -29,6 +28,7 @@ MqttSettingsService::~MqttSettingsService() { void MqttSettingsService::begin() { _fsPersistence.readFromFS(); startClient(); + _reconfigureMqtt = true; } void MqttSettingsService::startClient() { @@ -79,6 +79,10 @@ void MqttSettingsService::startClient() { } void MqttSettingsService::loop() { + if (_state.enabled && _mqttClient && _mqttClient->connected() && !emsesp::EMSESP::system_.network_connected()) { + // emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client"); + _mqttClient->disconnect(true); + } if (_reconfigureMqtt || (_disconnectedAt && static_cast(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) { // reconfigure MQTT client _disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime(); @@ -142,28 +146,6 @@ void MqttSettingsService::onConfigUpdated() { emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings } -void MqttSettingsService::WiFiEvent(WiFiEvent_t event) { - switch (event) { - case ARDUINO_EVENT_WIFI_STA_GOT_IP: - case ARDUINO_EVENT_ETH_GOT_IP: - case ARDUINO_EVENT_ETH_GOT_IP6: - case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - if (_state.enabled && !_mqttClient->connected()) { - onConfigUpdated(); - } - break; - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - case ARDUINO_EVENT_ETH_DISCONNECTED: - if (_state.enabled) { - _mqttClient->disconnect(true); - } - break; - - default: - break; - } -} - bool MqttSettingsService::configureMqtt() { // disconnect if already connected if (_mqttClient->connected()) { @@ -256,7 +238,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject root) { StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) { MqttSettings newSettings; - bool changed = false; + bool changed = false; #ifndef NO_TLS_SUPPORT newSettings.enableTLS = root["enableTLS"]; @@ -316,6 +298,10 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) changed = true; } + if (newSettings.ha_number_mode != settings.ha_number_mode) { + changed = true; + } + if (newSettings.entity_format != settings.entity_format) { changed = true; } diff --git a/src/ESP32React/MqttSettingsService.h b/src/ESP32React/MqttSettingsService.h index 36b52fa74..c286c3544 100644 --- a/src/ESP32React/MqttSettingsService.h +++ b/src/ESP32React/MqttSettingsService.h @@ -134,7 +134,6 @@ class MqttSettingsService : public StatefulService { // the MQTT client instance MqttClient * _mqttClient; - void WiFiEvent(WiFiEvent_t event); void onMqttConnect(bool sessionPresent); void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason); void diff --git a/src/ESP32React/NTPSettingsService.cpp b/src/ESP32React/NTPSettingsService.cpp index 81e5cdf82..b12d69bbf 100644 --- a/src/ESP32React/NTPSettingsService.cpp +++ b/src/ESP32React/NTPSettingsService.cpp @@ -11,7 +11,6 @@ NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, Securit configureTime(request, json); }); - WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); }); addUpdateHandler([this] { configureNTP(); }, false); } @@ -20,27 +19,10 @@ void NTPSettingsService::begin() { configureNTP(); } -// handles both WiFI and Ethernet -void NTPSettingsService::WiFiEvent(WiFiEvent_t event) { - switch (event) { - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - case ARDUINO_EVENT_ETH_DISCONNECTED: - if (_connected && emsesp::EMSESP::system_.ntp_connected()) { - emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP"); - _connected = false; - configureNTP(); - } - break; - - case ARDUINO_EVENT_WIFI_STA_GOT_IP: - case ARDUINO_EVENT_ETH_GOT_IP: - // emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization"); - _connected = true; +void NTPSettingsService::loop() { + if (_connected != emsesp::EMSESP::system_.network_connected()) { + _connected = emsesp::EMSESP::system_.network_connected(); configureNTP(); - break; - - default: - break; } } @@ -55,7 +37,9 @@ void NTPSettingsService::configureNTP() { } else { setenv("TZ", _state.tzFormat.c_str(), 1); tzset(); - esp_sntp_stop(); + if (esp_sntp_enabled()) { + esp_sntp_stop(); + } } } diff --git a/src/ESP32React/NTPSettingsService.h b/src/ESP32React/NTPSettingsService.h index 635b68f1c..ca75c5dd9 100644 --- a/src/ESP32React/NTPSettingsService.h +++ b/src/ESP32React/NTPSettingsService.h @@ -44,6 +44,7 @@ class NTPSettingsService : public StatefulService { NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager); void begin(); + void loop(); static void ntp_received(struct timeval * tv); private: @@ -51,7 +52,6 @@ class NTPSettingsService : public StatefulService { FSPersistence _fsPersistence; volatile bool _connected; - void WiFiEvent(WiFiEvent_t event); void configureNTP(); void configureTime(AsyncWebServerRequest * request, JsonVariant json); }; From 421da246edd143231af0b2c08c6058b8c9ff4262 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 16 Feb 2026 07:51:10 +0100 Subject: [PATCH 8/9] fix SRC seltemp offset for auto mode #2960 --- src/devices/connect.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp index 256d26d3f..2ae873c3c 100644 --- a/src/devices/connect.cpp +++ b/src/devices/connect.cpp @@ -226,8 +226,9 @@ bool Connect::set_seltemp(const char * value, const int8_t id) { } float v; if (Helpers::value2float(value, v)) { - // write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2)); - write_command(0xBB5 + rc->room(), rc->mode_ == 0 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2)); + // depends on mode, auto (2 for enum_mode2, 0 for enum_mode8) set in offset 1 + write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2)); + // write_command(0xBB5 + rc->room(), rc->mode_ == 0 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2)); return true; } return false; From 0be1b209967d0bd4b75ea593cc361d1a2ae1be39 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 16 Feb 2026 10:37:28 +0100 Subject: [PATCH 9/9] statemachine for network connection replaces onEvent --- src/ESP32React/NetworkSettingsService.cpp | 58 +++++++++++++++++++++-- src/ESP32React/NetworkSettingsService.h | 2 +- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/ESP32React/NetworkSettingsService.cpp b/src/ESP32React/NetworkSettingsService.cpp index 2e9bd6d04..b274c5208 100644 --- a/src/ESP32React/NetworkSettingsService.cpp +++ b/src/ESP32React/NetworkSettingsService.cpp @@ -9,7 +9,7 @@ NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs, , _stopping(false) { addUpdateHandler([this] { reconfigureWiFiConnection(); }, false); // Eth is also bound to the WifiGeneric event handler - WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event, info); }); + // Network.onEvent([this](arduino_event_id_t event, arduino_event_info_t info) { WiFiEvent(event, info); }); } static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) { @@ -62,14 +62,62 @@ void NetworkSettingsService::loop() { _lastConnectionAttempt = currentMillis; manageSTA(); } + static uint8_t connect = 0; + enum uint8_t { CONNECT_IDLE = 0, CONNECT_WAIT_ETH, CONNECT_ETH_ACTIVE, CONNECT_WIFI_ACTIVE }; + switch (connect) { + default: + connect = CONNECT_IDLE; + break; + case CONNECT_IDLE: + if (ETH.started() && _state.ssid.length() == 0) { + emsesp::EMSESP::logger().info("ETH started"); + connect = CONNECT_WAIT_ETH; + ETH.enableIPv6(true); + if (_state.staticIPConfig) { + ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); + } + ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str()); + } + if (WiFi.isConnected()) { + emsesp::EMSESP::logger().info("Wifi connected"); + connect = CONNECT_WIFI_ACTIVE; + if (_state.tx_power == 0) { + setWiFiPowerOnRSSI(); + } + mDNS_start(); + } + break; + case CONNECT_WAIT_ETH: + if (ETH.connected()) { + emsesp::EMSESP::logger().info("ETH connected"); + connect = CONNECT_ETH_ACTIVE; + emsesp::EMSESP::system_.ethernet_connected(true); + mDNS_start(); + } + break; + case CONNECT_ETH_ACTIVE: + if (!ETH.connected()) { + emsesp::EMSESP::logger().info("ETH disconnected"); + emsesp::EMSESP::system_.ethernet_connected(false); + connect = CONNECT_IDLE; + } + break; + case CONNECT_WIFI_ACTIVE: + if (!WiFi.isConnected()) { + emsesp::EMSESP::logger().info("WiFi disconnected"); + connect = CONNECT_IDLE; + if (_stopping) { + _lastConnectionAttempt = 0; + _stopping = false; + } + } + break; + } } void NetworkSettingsService::manageSTA() { // Abort if already connected, or if we have no SSID if (WiFi.isConnected() || _state.ssid.length() == 0) { - if (_state.ssid.length() == 0) { - ETH.enableIPv6(true); - } return; } @@ -289,7 +337,7 @@ const char * NetworkSettingsService::disconnectReason(uint8_t code) { } // handles both WiFI and Ethernet -void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { +void NetworkSettingsService::WiFiEvent(arduino_event_id_t event, arduino_event_info_t info) { #ifndef EMSESP_STANDALONE switch (event) { diff --git a/src/ESP32React/NetworkSettingsService.h b/src/ESP32React/NetworkSettingsService.h index 7c1ed0ff7..4635c5181 100644 --- a/src/ESP32React/NetworkSettingsService.h +++ b/src/ESP32React/NetworkSettingsService.h @@ -107,7 +107,7 @@ class NetworkSettingsService : public StatefulService { volatile uint16_t connectcount_ = 0; // number of wifi reconnects - void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info); + void WiFiEvent(arduino_event_id_t event, arduino_event_info_t info); void mDNS_start() const; const char * disconnectReason(uint8_t code); void reconfigureWiFiConnection();