From 1475fc094d6203892b8ba557c10a10f76cf9ce51 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 13:55:57 +0100 Subject: [PATCH 01/42] ESPAsyncWebServer @ 3.9.4 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 85ebc08bd..2495f1022 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.3 + ESP32Async/ESPAsyncWebServer @ 3.9.4 https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8 From 92c34dddba169107c0699bdd118b70e14396d0f1 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 13:56:11 +0100 Subject: [PATCH 02/42] add comment --- src/core/system.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/system.cpp b/src/core/system.cpp index 6363a76da..3d40f8e19 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2843,6 +2843,7 @@ void System::set_valid_system_gpios() { #elif CONFIG_IDF_TARGET_ESP32 // 1 and 3 are UART0 pins, but used for some eth-boards (BBQKees-E32, OlimexPOE) // 32-39 is ADC1, input only + // 25 and 26 are DAC (Digital-to-Analog Converter) pins if (ESP.getPsramSize() > 0) { // if psram is enabled remove pins 16 and 17 from the list valid_system_gpios_ = string_range_to_vector("0-5, 12-15, 18-19, 23, 25-27, 32-39"); From b992f90fe2b6e094d429a23db4af8c879b2863ea Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 13:56:27 +0100 Subject: [PATCH 03/42] AsyncTCP changes --- src/ESP32React/UploadFileService.cpp | 2 +- src/web/WebSettingsService.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp index 8ef5bfc13..4d016dce4 100644 --- a/src/ESP32React/UploadFileService.cpp +++ b/src/ESP32React/UploadFileService.cpp @@ -172,7 +172,7 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) { // check for invalid extension and immediately kill the connection, which will throw an error // that is caught by the web code. Unfortunately the http error code is not sent to the client on fast network connections if (code == 406) { - request->client()->close(true); + request->client()->close(); _is_firmware = false; Update.abort(); } diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 7067516c9..2d58e22b1 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -308,8 +308,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { // if we encountered an invalid GPIO, rollback changes and don't save settings, and report the error to WebUI if (!have_valid_gpios) { // replace settings with original settings - settings = original_settings; // the original settings are still valid - // restore the GPIOs from the snapshot + settings = original_settings; EMSESP::system_.restore_snapshot_gpios(used_gpios, system_gpios); // report the error to WebUI From 5b303bd58a5336927bda088e761781cd9d8a96c3 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 13:58:00 +0100 Subject: [PATCH 04/42] package update --- interface/package.json | 2 +- interface/pnpm-lock.yaml | 22 +++++++++++----------- mock-api/package.json | 2 +- mock-api/pnpm-lock.yaml | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/interface/package.json b/interface/package.json index 3e242cb24..34670860e 100644 --- a/interface/package.json +++ b/interface/package.json @@ -51,7 +51,7 @@ "@eslint/js": "^9.39.2", "@preact/compat": "^18.3.1", "@preact/preset-vite": "^2.10.2", - "@trivago/prettier-plugin-sort-imports": "^6.0.0", + "@trivago/prettier-plugin-sort-imports": "^6.0.1", "@types/node": "^25.0.3", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index e37fff143..839a6879f 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -85,8 +85,8 @@ importers: specifier: ^2.10.2 version: 2.10.2(@babel/core@7.28.5)(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) '@trivago/prettier-plugin-sort-imports': - specifier: ^6.0.0 - version: 6.0.0(prettier@3.7.4) + specifier: ^6.0.1 + version: 6.0.1(prettier@3.7.4) '@types/node': specifier: ^25.0.3 version: 25.0.3 @@ -800,8 +800,8 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@trivago/prettier-plugin-sort-imports@6.0.0': - resolution: {integrity: sha512-Xarx55ow0R8oC7ViL5fPmDsg1EBa1dVhyZFVbFXNtPPJyW2w9bJADIla8YFSaNG9N06XfcklA9O9vmw4noNxkQ==} + '@trivago/prettier-plugin-sort-imports@6.0.1': + resolution: {integrity: sha512-6B13DCWDfAfh4AEJ43gRgeCSAQmlKG5LHqHzHc0lbUwgBy0rX7o41US+46Fd4XiXBx+JDGEz3NBadCbUls0dUQ==} engines: {node: '>= 20'} peerDependencies: '@vue/compiler-sfc': 3.x @@ -2884,8 +2884,8 @@ packages: resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} engines: {node: '>=0.10.0'} - ts-api-utils@2.3.0: - resolution: {integrity: sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg==} + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -3713,7 +3713,7 @@ snapshots: react-virtualized-auto-sizer: 1.0.26(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-window: 1.8.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@trivago/prettier-plugin-sort-imports@6.0.0(prettier@3.7.4)': + '@trivago/prettier-plugin-sort-imports@6.0.1(prettier@3.7.4)': dependencies: '@babel/generator': 7.28.5 '@babel/parser': 7.28.5 @@ -3814,7 +3814,7 @@ snapshots: eslint: 9.39.2 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.3.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3856,7 +3856,7 @@ snapshots: '@typescript-eslint/utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2 - ts-api-utils: 2.3.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3873,7 +3873,7 @@ snapshots: minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 - ts-api-utils: 2.3.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -5882,7 +5882,7 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - ts-api-utils@2.3.0(typescript@5.9.3): + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 diff --git a/mock-api/package.json b/mock-api/package.json index 1934da897..8780817cc 100644 --- a/mock-api/package.json +++ b/mock-api/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@msgpack/msgpack": "^3.1.3", - "@trivago/prettier-plugin-sort-imports": "^6.0.0", + "@trivago/prettier-plugin-sort-imports": "^6.0.1", "formidable": "^3.5.4", "itty-router": "^5.0.22", "prettier": "^3.7.4" diff --git a/mock-api/pnpm-lock.yaml b/mock-api/pnpm-lock.yaml index 0151c466c..9586176a7 100644 --- a/mock-api/pnpm-lock.yaml +++ b/mock-api/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^3.1.3 version: 3.1.3 '@trivago/prettier-plugin-sort-imports': - specifier: ^6.0.0 - version: 6.0.0(prettier@3.7.4) + specifier: ^6.0.1 + version: 6.0.1(prettier@3.7.4) formidable: specifier: ^3.5.4 version: 3.5.4 @@ -87,8 +87,8 @@ packages: '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} - '@trivago/prettier-plugin-sort-imports@6.0.0': - resolution: {integrity: sha512-Xarx55ow0R8oC7ViL5fPmDsg1EBa1dVhyZFVbFXNtPPJyW2w9bJADIla8YFSaNG9N06XfcklA9O9vmw4noNxkQ==} + '@trivago/prettier-plugin-sort-imports@6.0.1': + resolution: {integrity: sha512-6B13DCWDfAfh4AEJ43gRgeCSAQmlKG5LHqHzHc0lbUwgBy0rX7o41US+46Fd4XiXBx+JDGEz3NBadCbUls0dUQ==} engines: {node: '>= 20'} peerDependencies: '@vue/compiler-sfc': 3.x @@ -246,7 +246,7 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 - '@trivago/prettier-plugin-sort-imports@6.0.0(prettier@3.7.4)': + '@trivago/prettier-plugin-sort-imports@6.0.1(prettier@3.7.4)': dependencies: '@babel/generator': 7.28.5 '@babel/parser': 7.28.5 From af349edd541077542167aa11ef5a642794fff4e6 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 13:58:10 +0100 Subject: [PATCH 05/42] text changes --- CHANGELOG.md | 4 ++-- CHANGELOG_LATEST.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 110b43c9e..6314e7c64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,8 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - FW200 display options [#2610](https://github.com/emsesp/EMS-ESP32/discussions/2610) - CR11 mode settings OFF/MANUAL depends on selTemp [#2437](https://github.com/emsesp/EMS-ESP32/issues/2437) - implemented eFuse settings for BBQKees boards to store model type and ESP chipset -- Analogsensors for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624) -- Analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631) +- analogsensors for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624) +- analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631) - SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636) - Greenstar 2000 [#2645](https://github.com/emsesp/EMS-ESP32/issues/2645) - RC3xx `dhw modetype` [#2659](https://github.com/emsesp/EMS-ESP32/discussions/2659) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 24c3a9cb1..67bb64156 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -6,12 +6,12 @@ For more details go to [emsesp.org](https://emsesp.org/). ## Added -- update time safed in nvs +- update time saved in nvs ## Fixed -- selflowtemp [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876) +- selflowtemp fix [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876) ## Changed -- snapshot gpios in temporarly ram +- snapshot gpios stored in temporary ram From 41bf293db33a6a8d38956bc79ad1795496f86ba6 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 13:58:25 +0100 Subject: [PATCH 06/42] AsyncTCP change --- lib/eModbus/src/ModbusServerTCPasync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eModbus/src/ModbusServerTCPasync.cpp b/lib/eModbus/src/ModbusServerTCPasync.cpp index e8d0a43dc..be2b0cbf1 100644 --- a/lib/eModbus/src/ModbusServerTCPasync.cpp +++ b/lib/eModbus/src/ModbusServerTCPasync.cpp @@ -253,7 +253,7 @@ void ModbusServerTCPasync::onClientConnect(AsyncClient* client) { LOG_D("nr clients: %u\n", clients.size()); } else { LOG_D("max number of clients reached, closing new\n"); - client->close(true); + client->close(); delete client; } } From 425b44e334c3ed3778085a8149d1c88f773adf07 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 14:13:54 +0100 Subject: [PATCH 07/42] init settings --- src/ESP32React/APSettingsService.h | 8 ++--- src/ESP32React/MqttSettingsService.h | 45 +++++++++++++------------ src/ESP32React/NTPSettingsService.h | 2 +- src/ESP32React/NetworkSettingsService.h | 14 ++++---- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/ESP32React/APSettingsService.h b/src/ESP32React/APSettingsService.h index 67c9e03bf..d895e94a3 100644 --- a/src/ESP32React/APSettingsService.h +++ b/src/ESP32React/APSettingsService.h @@ -58,12 +58,12 @@ enum APNetworkStatus { ACTIVE = 0, INACTIVE, LINGERING }; class APSettings { public: - uint8_t provisionMode; // 0 = on, 2 = off + uint8_t provisionMode = FACTORY_AP_PROVISION_MODE; // 0 = on, 2 = off String ssid; String password; - uint8_t channel; - bool ssidHidden; - uint8_t maxClients; + uint8_t channel = FACTORY_AP_CHANNEL; + bool ssidHidden = FACTORY_AP_SSID_HIDDEN; + uint8_t maxClients = FACTORY_AP_MAX_CLIENTS; IPAddress localIP; IPAddress gatewayIP; diff --git a/src/ESP32React/MqttSettingsService.h b/src/ESP32React/MqttSettingsService.h index b844e2ea1..4c3ad7c06 100644 --- a/src/ESP32React/MqttSettingsService.h +++ b/src/ESP32React/MqttSettingsService.h @@ -8,6 +8,7 @@ #include #include +#include #define MQTT_RECONNECTION_DELAY 2000 // 2 seconds @@ -65,37 +66,37 @@ class MqttSettings { public: - bool enabled; + bool enabled = FACTORY_MQTT_ENABLED; String host; - uint16_t port; + uint16_t port = FACTORY_MQTT_PORT; String rootCA; - bool enableTLS; + bool enableTLS = false; String username; String password; String clientId; - uint16_t keepAlive; - bool cleanSession; + uint16_t keepAlive = FACTORY_MQTT_KEEP_ALIVE; + bool cleanSession = FACTORY_MQTT_CLEAN_SESSION; // EMS-ESP specific String base; - uint16_t publish_time_boiler; - uint16_t publish_time_thermostat; - uint16_t publish_time_solar; - uint16_t publish_time_mixer; - uint16_t publish_time_water; - uint16_t publish_time_other; - uint16_t publish_time_sensor; - uint16_t publish_time_heartbeat; - uint8_t mqtt_qos; - bool mqtt_retain; - bool ha_enabled; - uint8_t nested_format; + uint16_t publish_time_boiler = EMSESP_DEFAULT_PUBLISH_TIME; + uint16_t publish_time_thermostat = EMSESP_DEFAULT_PUBLISH_TIME; + uint16_t publish_time_solar = EMSESP_DEFAULT_PUBLISH_TIME; + uint16_t publish_time_mixer = EMSESP_DEFAULT_PUBLISH_TIME; + uint16_t publish_time_water = EMSESP_DEFAULT_PUBLISH_TIME; + uint16_t publish_time_other = EMSESP_DEFAULT_PUBLISH_TIME_OTHER; + uint16_t publish_time_sensor = EMSESP_DEFAULT_PUBLISH_TIME; + uint16_t publish_time_heartbeat = EMSESP_DEFAULT_PUBLISH_HEARTBEAT; + uint8_t mqtt_qos = EMSESP_DEFAULT_MQTT_QOS; + bool mqtt_retain = EMSESP_DEFAULT_MQTT_RETAIN; + bool ha_enabled = EMSESP_DEFAULT_HA_ENABLED; + uint8_t nested_format = EMSESP_DEFAULT_NESTED_FORMAT; String discovery_prefix; - uint8_t discovery_type; - bool publish_single; - bool publish_single2cmd; - bool send_response; - uint8_t entity_format; + uint8_t discovery_type = EMSESP_DEFAULT_DISCOVERY_TYPE; + bool publish_single = EMSESP_DEFAULT_PUBLISH_SINGLE; + bool publish_single2cmd = EMSESP_DEFAULT_PUBLISH_SINGLE2CMD; + bool send_response = EMSESP_DEFAULT_SEND_RESPONSE; + uint8_t entity_format = EMSESP_DEFAULT_ENTITY_FORMAT; static void read(MqttSettings & settings, JsonObject root); static StateUpdateResult update(JsonObject root, MqttSettings & settings); diff --git a/src/ESP32React/NTPSettingsService.h b/src/ESP32React/NTPSettingsService.h index 38f4ed5e2..cd55284d7 100644 --- a/src/ESP32React/NTPSettingsService.h +++ b/src/ESP32React/NTPSettingsService.h @@ -30,7 +30,7 @@ class NTPSettings { public: - bool enabled; + bool enabled = FACTORY_NTP_ENABLED; String tzLabel; String tzFormat; String server; diff --git a/src/ESP32React/NetworkSettingsService.h b/src/ESP32React/NetworkSettingsService.h index a12536b78..80e27c695 100644 --- a/src/ESP32React/NetworkSettingsService.h +++ b/src/ESP32React/NetworkSettingsService.h @@ -68,13 +68,13 @@ class NetworkSettings { String bssid; String password; String hostname; - bool staticIPConfig; - bool bandwidth20; - uint8_t tx_power; - bool nosleep; - bool enableMDNS; - bool enableCORS; - String CORSOrigin; + bool staticIPConfig = false; + bool bandwidth20 = false; + uint8_t tx_power = 0; + bool nosleep = true; + bool enableMDNS = true; + bool enableCORS = false; + String CORSOrigin = "*"; // optional configuration for static IP address IPAddress localIP; From 616c73f658eaca1633394134ee5e02b96429c553 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 22:16:33 +0100 Subject: [PATCH 08/42] first test to exclude gpios --- src/core/system.cpp | 127 ++++++++++++++++++++++++++++++++++--------- src/core/system.h | 2 +- src/emsesp_version.h | 2 +- 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 3d40f8e19..8d528ba31 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1432,7 +1432,7 @@ bool System::check_upgrade() { if (this_version > settings_version) { // we need to do an upgrade if (missing_version) { - LOG_NOTICE("Upgrading to version %d.%d.%d%s", this_version.major(), this_version.minor(), this_version.patch(), this_version_type); + LOG_NOTICE("Upgrading to version %d.%d.%d%s", this_version.major(), this_version.minor(), this_version.patch(), this_version_type.c_str()); } else { LOG_NOTICE("Upgrading from version %d.%d.%d%s to %d.%d.%d%s", settings_version.major(), @@ -2033,6 +2033,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output #endif node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); node["uptimeSec"] = uuid::get_uptime_sec(); + node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1); #ifndef EMSESP_STANDALONE node["platform"] = EMSESP_PLATFORM; node["cpuType"] = ESP.getChipModel(); @@ -2044,10 +2045,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["usedApp"] = EMSESP::system_.appUsed(); // kilobytes node["freeApp"] = EMSESP::system_.appFree(); // kilobytes node["partition"] = (const char *)esp_ota_get_running_partition()->label; // active partition - node["flash_chip_size"] = ESP.getFlashChipSize() / 1024; // kilobytes -#endif - node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1); -#ifndef EMSESP_STANDALONE + node["flash_chip_size"] = ESP.getFlashChipSize() / 1024; // kilobytes node["psram"] = (EMSESP::system_.PSram() > 0); // make boolean if (EMSESP::system_.PSram()) { node["psramSize"] = EMSESP::system_.PSram(); @@ -2057,9 +2055,27 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output #if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 node["temperature"] = EMSESP::system_.temperature(); #endif - - node["txpause"] = EMSbus::tx_mode() == EMS_TXMODE_OFF; #endif + node["txpause"] = EMSbus::tx_mode() == EMS_TXMODE_OFF; + + // GPIO information + std::string gpios_in_use_str; + for (const auto & gpio : EMSESP::system_.used_gpios_) { + if (!gpios_in_use_str.empty()) { + gpios_in_use_str += ","; + } + gpios_in_use_str += Helpers::itoa(gpio); + } + node["gpios_in_use"] = gpios_in_use_str; + + std::string gpios_available_str; + for (const auto & gpio : EMSESP::system_.available_gpios()) { + if (!gpios_available_str.empty()) { + gpios_available_str += ","; + } + gpios_available_str += Helpers::itoa(gpio); + } + node["gpios_available"] = gpios_available_str; // Network Status node = output["network"].to(); @@ -2784,7 +2800,7 @@ uint8_t System::systemStatus() { } // takes a string range like "6-11, 1, 23, 24-48" which has optional ranges and single values and converts to a vector of ints -std::vector> System::string_range_to_vector(const std::string & range) { +std::vector> System::string_range_to_vector(const std::string & range, const std::string & exclude) { std::vector> gpios; std::string::size_type pos = 0; std::string::size_type prev = 0; @@ -2816,10 +2832,50 @@ std::vector> System::string_range_to_vector(con // handle the last part process_part(range.substr(prev)); + // if exclude list is provided, parse it and remove excluded GPIOs + if (!exclude.empty()) { + std::vector> exclude_gpios; + pos = 0; + prev = 0; + + auto process_exclude = [&exclude_gpios](std::string part) { + // trim whitespace + part.erase(0, part.find_first_not_of(" \t")); + part.erase(part.find_last_not_of(" \t") + 1); + + // check if it's a range (contains '-') + std::string::size_type dash_pos = part.find('-'); + if (dash_pos != std::string::npos) { + // it's a range like "6-11" + int start = std::stoi(part.substr(0, dash_pos)); + int end = std::stoi(part.substr(dash_pos + 1)); + for (int i = start; i <= end; i++) { + exclude_gpios.push_back(static_cast(i)); + } + } else { + exclude_gpios.push_back(static_cast(std::stoi(part))); + } + }; + + while ((pos = exclude.find(',', prev)) != std::string::npos) { + process_exclude(exclude.substr(prev, pos - prev)); + prev = pos + 1; + } + + // handle the last part + process_exclude(exclude.substr(prev)); + + // remove excluded GPIOs from the main list + gpios.erase(std::remove_if(gpios.begin(), gpios.end(), [&exclude_gpios](uint8_t gpio) { + return std::find(exclude_gpios.begin(), exclude_gpios.end(), gpio) != exclude_gpios.end(); + }), gpios.end()); + } + return gpios; } // initialize a list of valid GPIOs based on the ESP32 board +// string_to_vector() take two strings, the first is the range of GPIOs to use, the second is the range of GPIOs to exclude // note: we always allow 0, which is used to indicate Dallas or LED is disabled void System::set_valid_system_gpios() { valid_system_gpios_.clear(); // reset system list @@ -2827,31 +2883,52 @@ void System::set_valid_system_gpios() { // get free gpios based on board/platform type #if CONFIG_IDF_TARGET_ESP32C3 - // https://www.wemos.cc/en/latest/c3/c3_mini.html - valid_system_gpios_ = string_range_to_vector("0-10"); // UART0=20,21 + // not valid: + // 20-21 are UART0 + valid_system_gpios_ = string_range_to_vector("0-10", "20-21"); #elif CONFIG_IDF_TARGET_ESP32S2 - // 43 and 44 are UART0 pins - // 38 and 39 are strapping pins, input only - valid_system_gpios_ = string_range_to_vector("0-14, 19, 20, 21, 33-37, 45, 46"); + // not valid: + // 6-11 are used for SPI flash and PSRAM + // 16-17 are also used for SPI flash and PSRAM + // 45-46 are strapping pins + // 43-44 are UART0 + // notes: + // 34-39 are input only + valid_system_gpios_ = string_range_to_vector("0-46", "6-11, 16-17, 45-46, 43-44"); #elif CONFIG_IDF_TARGET_ESP32S3 - // 43 and 44 are UART0 pins - // 33-37 for Octal SPI (SPIIO4 through SPIIO7 and SPIDQS) - // 38 and 39 are input only - // 45 and 36 are strapping pins, input only - // 47 and 48 are valid on a Wemos S3 (https://github.com/emsesp/EMS-ESP32/issues/2874) - valid_system_gpios_ = string_range_to_vector("0-14, 17, 18, 21, 33-39, 45-48"); + // not valid: + // 43-44 are UART0 pins + // 19-20 are USB-JTAG pins + // 33-37 for Octal SPI (SPIIO4 through SPIIO7 and SPIDQS) on 32MB boards + // 3, 45-46 are strapping pins + // 26-32 are typically used for SPI flash and PSRAM + // 42 transitions low on reset, slower than other GPIOs which can cause issues in time-sensitive applications + // notes: + // 34-39 are input only, and can be used + // 47 and 48 are valid on a Wemos S3 (https://github.com/emsesp/EMS-ESP32/issues/2874) + valid_system_gpios_ = string_range_to_vector("0-48", "43-44, 19-20, 33-37, 3, 45-46, 26-32, 42"); #elif CONFIG_IDF_TARGET_ESP32 - // 1 and 3 are UART0 pins, but used for some eth-boards (BBQKees-E32, OlimexPOE) - // 32-39 is ADC1, input only - // 25 and 26 are DAC (Digital-to-Analog Converter) pins + // not valid: + // 6-11 are used for SPI flash and PSRAM + // 16-17 are also used for SPI flash and PSRAM + // 26-32 are used for SPI flash and PSRAM + // 33-37 also used for SPI flash and PSRAM, on Octal SPI PSRAM (ESP32-S3R8, ESP32-S3R8V, ESP32-S3R16V) + // 9-10 are used for SPI flash and PSRAM + // 19-20 used for JTAG-USB + // 45-46 are strapping pins + // 1 and 3 are UART0 pins, but used for some eth-boards (BBQKees-E32, OlimexPOE) + // 42 transitions low on reset, slower than other GPIOs which can cause issues in time-sensitive applications + // notes: + // 34-39 are input only (ADC1), and can be used + // 25 and 26 are DAC (Digital-to-Analog Converter) pins, and can be used if (ESP.getPsramSize() > 0) { // if psram is enabled remove pins 16 and 17 from the list - valid_system_gpios_ = string_range_to_vector("0-5, 12-15, 18-19, 23, 25-27, 32-39"); + valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 26-32, 33-37, 9-10, 19-20, 45-46, 1, 3, 42"); } else { - valid_system_gpios_ = string_range_to_vector("0-5, 12-19, 23, 25-27, 32-39"); + valid_system_gpios_ = string_range_to_vector("0-39", "19-20, 45-46, 1, 3, 42"); } #elif defined(EMSESP_STANDALONE) - valid_system_gpios_ = string_range_to_vector("0-5, 12-19, 23, 25-27, 32-39"); + valid_system_gpios_ = string_range_to_vector("0-39"); #endif } diff --git a/src/core/system.h b/src/core/system.h index 1ed74833c..f082bc273 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -434,7 +434,7 @@ class System { void led_monitor(); void system_check(); - static std::vector> string_range_to_vector(const std::string & range); + static std::vector> string_range_to_vector(const std::string & range, const std::string & exclude = ""); // GPIOs static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used diff --git a/src/emsesp_version.h b/src/emsesp_version.h index 7ae47456b..0afe1d82c 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.8.1-dev.3" +#define EMSESP_APP_VERSION "3.8.1-dev.4" From 4ae4000944a5155c4c7cff04ffd28369f4007017 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 3 Jan 2026 22:48:17 +0100 Subject: [PATCH 09/42] asyncTCP fix --- lib/espMqttClient/src/Transport/ClientAsync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/espMqttClient/src/Transport/ClientAsync.cpp b/lib/espMqttClient/src/Transport/ClientAsync.cpp index 4f8d69eeb..0ca91564f 100644 --- a/lib/espMqttClient/src/Transport/ClientAsync.cpp +++ b/lib/espMqttClient/src/Transport/ClientAsync.cpp @@ -42,7 +42,7 @@ int ClientAsync::read(uint8_t* buf, size_t size) { } void ClientAsync::stop() { - client.close(false); + client.close(); } bool ClientAsync::connected() { From 5a82064a88dd27c7726fbb0004882585d3772a7f Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 00:08:17 +0100 Subject: [PATCH 10/42] add name to gpios --- src/core/analogsensor.cpp | 2 +- src/core/system.cpp | 40 +++++++++++++++-------------- src/core/system.h | 9 +++++-- src/web/WebCustomizationService.cpp | 5 ++-- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index d62701ded..74532a876 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -576,7 +576,7 @@ bool AnalogSensor::update(uint8_t gpio, const char * org_name, double offset, do newSensor.is_system = is_system; settings.analogCustomizations.push_back(newSensor); // check the gpio again and add to used list - if (EMSESP::system_.add_gpio(gpio, "Analog Sensor")) { + if (EMSESP::system_.add_gpio(gpio, name)) { LOG_DEBUG("Adding customization for analog sensor GPIO %02d", gpio); return StateUpdateResult::CHANGED; // persist the change } else { diff --git a/src/core/system.cpp b/src/core/system.cpp index 8d528ba31..31976d7ba 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -105,8 +105,8 @@ uint32_t System::led_flash_duration_ = 0; bool System::led_flash_timer_ = false; // GPIOs -std::vector> System::valid_system_gpios_; -std::vector> System::used_gpios_; +std::vector> System::valid_system_gpios_; +std::vector> System::used_gpios_; // find the index of the language // 0 = EN, 1 = DE, etc... @@ -1216,8 +1216,8 @@ void System::show_system(uuid::console::Shell & shell) { // GPIOs shell.println(" GPIOs:"); shell.printf(" in use:"); - for (const auto & gpio : used_gpios_) { - shell.printf(" %d", gpio); + for (const auto & gpio_info : used_gpios_) { + shell.printf(" %d(%s)", gpio_info.pin, gpio_info.name.c_str()); } shell.printfln(" (total %d)", used_gpios_.size()); auto available = available_gpios(); @@ -2060,18 +2060,18 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output // GPIO information std::string gpios_in_use_str; - for (const auto & gpio : EMSESP::system_.used_gpios_) { + for (const auto & gpio_info : EMSESP::system_.used_gpios_) { if (!gpios_in_use_str.empty()) { - gpios_in_use_str += ","; + gpios_in_use_str += ", "; } - gpios_in_use_str += Helpers::itoa(gpio); + gpios_in_use_str += Helpers::itoa(gpio_info.pin) + "(" + gpio_info.name + ")"; } node["gpios_in_use"] = gpios_in_use_str; std::string gpios_available_str; for (const auto & gpio : EMSESP::system_.available_gpios()) { if (!gpios_available_str.empty()) { - gpios_available_str += ","; + gpios_available_str += ", "; } gpios_available_str += Helpers::itoa(gpio); } @@ -2938,8 +2938,9 @@ bool System::add_gpio(uint8_t pin, const char * source_name) { // check if this is a valid user GPIO if (std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin) != valid_system_gpios_.end()) { // It's valid now check if it's already in the used list - if (std::find(used_gpios_.begin(), used_gpios_.end(), pin) != used_gpios_.end()) { - LOG_WARNING("GPIO %d for %s is already in use", pin, source_name); + auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin, source_name](const GpioInfo & gpio_info) { return gpio_info.pin == pin && gpio_info.name != source_name; }); + if (it != used_gpios_.end()) { + LOG_WARNING("Can't add GPIO %d for %s, already in use by %s", pin, source_name, it->name.c_str()); return false; // Pin is already used } } else { @@ -2952,24 +2953,24 @@ bool System::add_gpio(uint8_t pin, const char * source_name) { remove_gpio(pin); LOG_DEBUG("Adding GPIO %d for %s to used gpio list", pin, source_name); - used_gpios_.push_back(pin); // add to used list + used_gpios_.push_back({pin, source_name}); // add to used list with name return true; } // remove a gpio from both valid and used lists void System::remove_gpio(uint8_t pin, bool also_system) { - auto it = std::find(used_gpios_.begin(), used_gpios_.end(), pin); + auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioInfo & gpio_info) { return gpio_info.pin == pin; }); if (it != used_gpios_.end()) { LOG_DEBUG("GPIO %d removed from used gpio list", pin); used_gpios_.erase(it); } if (also_system) { - it = std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin); - if (it != valid_system_gpios_.end()) { + auto it_sys = std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin); + if (it_sys != valid_system_gpios_.end()) { LOG_DEBUG("GPIO %d removed from valid gpio list", pin); - valid_system_gpios_.erase(it); + valid_system_gpios_.erase(it_sys); } } } @@ -2978,7 +2979,8 @@ void System::remove_gpio(uint8_t pin, bool also_system) { std::vector System::available_gpios() { std::vector gpios; for (const auto & gpio : valid_system_gpios_) { - if (std::find(used_gpios_.begin(), used_gpios_.end(), gpio) == used_gpios_.end()) { + auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [gpio](const GpioInfo & gpio_info) { return gpio_info.pin == gpio; }); + if (it == used_gpios_.end()) { gpios.push_back(gpio); // didn't find it in used_gpios_, so it's available } } @@ -2987,8 +2989,8 @@ std::vector System::available_gpios() { // make a snapshot of the current GPIOs void System::make_snapshot_gpios(std::vector & u_gpios, std::vector & s_gpios) { - for (const auto & gpio : used_gpios_) { - u_gpios.push_back(gpio); + for (const auto & gpio_info : used_gpios_) { + u_gpios.push_back(gpio_info.pin); } for (const auto & gpio : valid_system_gpios_) { s_gpios.push_back(gpio); @@ -2999,7 +3001,7 @@ void System::make_snapshot_gpios(std::vector & u_gpios, std::vector & u_gpios, std::vector & s_gpios) { used_gpios_.clear(); for (const auto & gpio : u_gpios) { - used_gpios_.push_back(gpio); + used_gpios_.push_back({static_cast(gpio), "restored"}); } valid_system_gpios_.clear(); diff --git a/src/core/system.h b/src/core/system.h index f082bc273..7dfb5174e 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -160,6 +160,11 @@ class System { static bool saveSettings(const char * filename, const char * section, JsonObject input); // GPIOs + struct GpioInfo { + uint8_t pin; + std::string name; + }; + static bool add_gpio(uint8_t pin, const char * source_name); static std::vector available_gpios(); static bool load_board_profile(std::vector & data, const std::string & board_profile); @@ -437,8 +442,8 @@ class System { static std::vector> string_range_to_vector(const std::string & range, const std::string & exclude = ""); // GPIOs - static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used - static std::vector> used_gpios_; // list of GPIOs used by the application + static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used + static std::vector> used_gpios_; // list of GPIOs used by the application with their names int8_t wifi_quality(int8_t dBm); diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 9490b8067..80e1108b9 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -120,10 +120,11 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c for (const JsonObject analogJson : analogJsons) { // create each of the sensor, overwriting any previous settings // if the gpio is invalid skip the sensor - if (!EMSESP::system_.add_gpio(analogJson["gpio"].as(), "Analog Sensor")) { + auto analog_sensor_name = analogJson["name"].as(); + if (!EMSESP::system_.add_gpio(analogJson["gpio"].as(), analog_sensor_name)) { EMSESP::logger().warning("Analog sensor: Invalid GPIO %d for %s. Skipping.", analogJson["gpio"].as(), - analogJson["name"].as()); + analog_sensor_name); continue; } auto analog = AnalogCustomization(); From 68ebcdded46427df1732d25c98cb0e63c96f7734 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 11:44:28 +0100 Subject: [PATCH 11/42] gpio exclusion, add name --- src/core/emsesp.cpp | 6 +-- src/core/system.cpp | 70 +++++++++++++++++----------------- src/core/system.h | 8 +++- src/web/WebLogService.cpp | 2 +- src/web/WebSettingsService.cpp | 3 +- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 04b5b1e34..f74c9d32e 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1721,11 +1721,11 @@ void EMSESP::start() { LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION); #endif - // check if the firmware is fresh + // check if the firmware is fresh, i.e. a new install or a new version has been uploaded // this is set in UploadFileService::uploadComplete() // and reset in System::set_partition_install_date() if (!EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) { - LOG_DEBUG("Firmware is fresh"); + LOG_DEBUG("Firmware is fresh install"); } LOG_DEBUG("System is running in Debug mode"); @@ -1837,7 +1837,7 @@ void EMSESP::loop() { if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) { static bool only_once = false; if (!only_once) { - LOG_ERROR("Invalid GPIOs used. Please check your settings and log"); + LOG_ERROR("Invalid GPIOs used. Please check your settings and the system log"); only_once = true; } } diff --git a/src/core/system.cpp b/src/core/system.cpp index 31976d7ba..31ab34e41 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -105,8 +105,8 @@ uint32_t System::led_flash_duration_ = 0; bool System::led_flash_timer_ = false; // GPIOs -std::vector> System::valid_system_gpios_; -std::vector> System::used_gpios_; +std::vector> System::valid_system_gpios_; +std::vector> System::used_gpios_; // find the index of the language // 0 = EN, 1 = DE, etc... @@ -1216,16 +1216,16 @@ void System::show_system(uuid::console::Shell & shell) { // GPIOs shell.println(" GPIOs:"); shell.printf(" in use:"); - for (const auto & gpio_info : used_gpios_) { - shell.printf(" %d(%s)", gpio_info.pin, gpio_info.name.c_str()); + for (const auto & usage : used_gpios_) { + shell.printf(" %d(%s)", usage.pin, usage.source.c_str()); } - shell.printfln(" (total %d)", used_gpios_.size()); + shell.printfln(" [total %d]", used_gpios_.size()); auto available = available_gpios(); shell.printf(" available:"); for (const auto & gpio : available) { shell.printf(" %d", gpio); } - shell.printfln(" (total %d)", available.size()); + shell.printfln(" [total %d]", available.size()); // List all partitions and their version info shell.println(" Partitions:"); for (const auto & partition : partition_info_) { @@ -1410,7 +1410,7 @@ bool System::check_upgrade() { // see if we're missing a version, will be < 3.5.0b13 from Dec 23 2022 missing_version = (settingsVersion.empty() || (settingsVersion.length() < 5)); if (missing_version) { - LOG_WARNING("No version information found"); + LOG_WARNING("No version information found. Assuming version 3.5.0"); settingsVersion = "3.5.0"; // this was the last stable version without version info } @@ -1422,7 +1422,7 @@ bool System::check_upgrade() { bool save_version = true; bool reboot_required = false; - LOG_DEBUG("Checking for version upgrades (settings file is v%d.%d.%d%s)", + LOG_DEBUG("Checking for version upgrades from v%d.%d.%d%s", settings_version.major(), settings_version.minor(), settings_version.patch(), @@ -2031,8 +2031,8 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output #else node["version"] = EMSESP_APP_VERSION; #endif - node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); - node["uptimeSec"] = uuid::get_uptime_sec(); + node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); + node["uptimeSec"] = uuid::get_uptime_sec(); node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1); #ifndef EMSESP_STANDALONE node["platform"] = EMSESP_PLATFORM; @@ -2045,8 +2045,8 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["usedApp"] = EMSESP::system_.appUsed(); // kilobytes node["freeApp"] = EMSESP::system_.appFree(); // kilobytes node["partition"] = (const char *)esp_ota_get_running_partition()->label; // active partition - node["flash_chip_size"] = ESP.getFlashChipSize() / 1024; // kilobytes - node["psram"] = (EMSESP::system_.PSram() > 0); // make boolean + node["flash_chip_size"] = ESP.getFlashChipSize() / 1024; // kilobytes + node["psram"] = (EMSESP::system_.PSram() > 0); // make boolean if (EMSESP::system_.PSram()) { node["psramSize"] = EMSESP::system_.PSram(); node["freePsram"] = ESP.getFreePsram() / 1024; @@ -2057,17 +2057,17 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output #endif #endif node["txpause"] = EMSbus::tx_mode() == EMS_TXMODE_OFF; - + // GPIO information std::string gpios_in_use_str; - for (const auto & gpio_info : EMSESP::system_.used_gpios_) { + for (const auto & usage : EMSESP::system_.used_gpios_) { if (!gpios_in_use_str.empty()) { gpios_in_use_str += ", "; } - gpios_in_use_str += Helpers::itoa(gpio_info.pin) + "(" + gpio_info.name + ")"; + gpios_in_use_str += Helpers::itoa(usage.pin); } node["gpios_in_use"] = gpios_in_use_str; - + std::string gpios_available_str; for (const auto & gpio : EMSESP::system_.available_gpios()) { if (!gpios_available_str.empty()) { @@ -2866,9 +2866,10 @@ std::vector> System::string_range_to_vector(con process_exclude(exclude.substr(prev)); // remove excluded GPIOs from the main list - gpios.erase(std::remove_if(gpios.begin(), gpios.end(), [&exclude_gpios](uint8_t gpio) { - return std::find(exclude_gpios.begin(), exclude_gpios.end(), gpio) != exclude_gpios.end(); - }), gpios.end()); + gpios.erase(std::remove_if(gpios.begin(), + gpios.end(), + [&exclude_gpios](uint8_t gpio) { return std::find(exclude_gpios.begin(), exclude_gpios.end(), gpio) != exclude_gpios.end(); }), + gpios.end()); } return gpios; @@ -2885,7 +2886,7 @@ void System::set_valid_system_gpios() { #if CONFIG_IDF_TARGET_ESP32C3 // not valid: // 20-21 are UART0 - valid_system_gpios_ = string_range_to_vector("0-10", "20-21"); + valid_system_gpios_ = string_range_to_vector("0-21", "20-21"); #elif CONFIG_IDF_TARGET_ESP32S2 // not valid: // 6-11 are used for SPI flash and PSRAM @@ -2911,19 +2912,19 @@ void System::set_valid_system_gpios() { // not valid: // 6-11 are used for SPI flash and PSRAM // 16-17 are also used for SPI flash and PSRAM - // 26-32 are used for SPI flash and PSRAM - // 33-37 also used for SPI flash and PSRAM, on Octal SPI PSRAM (ESP32-S3R8, ESP32-S3R8V, ESP32-S3R16V) - // 9-10 are used for SPI flash and PSRAM - // 19-20 used for JTAG-USB + // 26-31 are used for SPI flash and PSRAM + // 19-20 are used for JTAG-USB // 45-46 are strapping pins - // 1 and 3 are UART0 pins, but used for some eth-boards (BBQKees-E32, OlimexPOE) + // 1 & 3 are UART0 pins, but used for some eth-boards (BBQKees-E32, OlimexPOE) // 42 transitions low on reset, slower than other GPIOs which can cause issues in time-sensitive applications // notes: + // 32 is reserved for LED on E32V2_2 boards // 34-39 are input only (ADC1), and can be used - // 25 and 26 are DAC (Digital-to-Analog Converter) pins, and can be used + // 25-26 are DAC (Digital-to-Analog Converter) pins, and can be used + // 36 & 39 are reserved for the internal supply_voltage and core_voltage if (ESP.getPsramSize() > 0) { // if psram is enabled remove pins 16 and 17 from the list - valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 26-32, 33-37, 9-10, 19-20, 45-46, 1, 3, 42"); + valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 26-31, 19-20, 45-46, 1, 3, 42"); } else { valid_system_gpios_ = string_range_to_vector("0-39", "19-20, 45-46, 1, 3, 42"); } @@ -2938,9 +2939,9 @@ bool System::add_gpio(uint8_t pin, const char * source_name) { // check if this is a valid user GPIO if (std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin) != valid_system_gpios_.end()) { // It's valid now check if it's already in the used list - auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin, source_name](const GpioInfo & gpio_info) { return gpio_info.pin == pin && gpio_info.name != source_name; }); + auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioUsage & usage) { return usage.pin == pin; }); if (it != used_gpios_.end()) { - LOG_WARNING("Can't add GPIO %d for %s, already in use by %s", pin, source_name, it->name.c_str()); + LOG_WARNING("GPIO %d for %s is already in use by %s", pin, source_name, it->source.c_str()); return false; // Pin is already used } } else { @@ -2953,14 +2954,14 @@ bool System::add_gpio(uint8_t pin, const char * source_name) { remove_gpio(pin); LOG_DEBUG("Adding GPIO %d for %s to used gpio list", pin, source_name); - used_gpios_.push_back({pin, source_name}); // add to used list with name + used_gpios_.push_back({pin, source_name}); // add to used list return true; } // remove a gpio from both valid and used lists void System::remove_gpio(uint8_t pin, bool also_system) { - auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioInfo & gpio_info) { return gpio_info.pin == pin; }); + auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioUsage & usage) { return usage.pin == pin; }); if (it != used_gpios_.end()) { LOG_DEBUG("GPIO %d removed from used gpio list", pin); used_gpios_.erase(it); @@ -2979,8 +2980,7 @@ void System::remove_gpio(uint8_t pin, bool also_system) { std::vector System::available_gpios() { std::vector gpios; for (const auto & gpio : valid_system_gpios_) { - auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [gpio](const GpioInfo & gpio_info) { return gpio_info.pin == gpio; }); - if (it == used_gpios_.end()) { + if (std::find_if(used_gpios_.begin(), used_gpios_.end(), [gpio](const GpioUsage & usage) { return usage.pin == gpio; }) == used_gpios_.end()) { gpios.push_back(gpio); // didn't find it in used_gpios_, so it's available } } @@ -2989,8 +2989,8 @@ std::vector System::available_gpios() { // make a snapshot of the current GPIOs void System::make_snapshot_gpios(std::vector & u_gpios, std::vector & s_gpios) { - for (const auto & gpio_info : used_gpios_) { - u_gpios.push_back(gpio_info.pin); + for (const auto & usage : used_gpios_) { + u_gpios.push_back(usage.pin); } for (const auto & gpio : valid_system_gpios_) { s_gpios.push_back(gpio); diff --git a/src/core/system.h b/src/core/system.h index 7dfb5174e..6e7612766 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -442,8 +442,12 @@ class System { static std::vector> string_range_to_vector(const std::string & range, const std::string & exclude = ""); // GPIOs - static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used - static std::vector> used_gpios_; // list of GPIOs used by the application with their names + struct GpioUsage { + uint8_t pin; + std::string source; + }; + static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used + static std::vector> used_gpios_; // list of GPIOs used by the application int8_t wifi_quality(int8_t dBm); diff --git a/src/web/WebLogService.cpp b/src/web/WebLogService.cpp index 15cdbc877..46e70ef14 100644 --- a/src/web/WebLogService.cpp +++ b/src/web/WebLogService.cpp @@ -97,7 +97,7 @@ void WebLogService::show(Shell & shell) { } shell.println(); - shell.printfln("Recent Log (level %s, max %d messages):", uuid::log::format_level_uppercase(level_), maximum_log_messages_); + shell.printfln("Recent Log:"); shell.println(); for (const auto & message : log_messages_) { diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 2d58e22b1..3cd0aba47 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -116,7 +116,8 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { // see if the user has changed the board profile // this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type // this will always run when EMS-ESP starts since original_settings{} is empty - if (original_settings.board_profile != settings.board_profile) { + if (original_settings.board_profile != settings.board_profile || original_settings.board_profile == "default" + || original_settings.board_profile.length() == 0) { set_board_profile(settings); add_flags(ChangeFlags::RESTART); } From be1e08af9cf7d3090e30f1602bf7a301444861a3 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 12:21:17 +0100 Subject: [PATCH 12/42] update --- CHANGELOG_LATEST.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 67bb64156..3909be7dd 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -11,7 +11,12 @@ For more details go to [emsesp.org](https://emsesp.org/). ## Fixed - selflowtemp fix [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876) +- valid GPIOs for ESP32S2, ESP32S3 and ESP32 +- Junkers wwcharge offset [#2860](https://github.com/emsesp/EMS-ESP32/issues/2860) +- fixed minflowtemp [#2890](https://github.com/emsesp/EMS-ESP32/issues/2890) +- don't add HA uom/classes for bool values [#2885](https://github.com/emsesp/EMS-ESP32/issues/2885) ## Changed - snapshot gpios stored in temporary ram +- GPIOs stored along with the name From 89dfe11ee30b7ee137d5693181fa57fd3c0fd3f6 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 12:45:54 +0100 Subject: [PATCH 13/42] fix tests --- test/test_api/test_api.cpp | 37 ++++-- test/test_api/test_api.h | 249 +++++++++++++++++++++++++++++-------- 2 files changed, 228 insertions(+), 58 deletions(-) diff --git a/test/test_api/test_api.cpp b/test/test_api/test_api.cpp index a003ecde1..67273e127 100644 --- a/test/test_api/test_api.cpp +++ b/test/test_api/test_api.cpp @@ -203,17 +203,40 @@ void capture(const char * url = nullptr) { } if (url) { - // call API, find and replace all double quotes with escaped quotes - std::string escaped_response = call_url(url); + // call API, store the response in a string + std::string response = call_url(url); - size_t pos = 0; - while ((pos = escaped_response.find("\"", pos)) != std::string::npos) { - escaped_response.replace(pos, 1, "\\\""); - pos += 2; + // escape all special characters for C++ string literal + std::string escaped_response; + escaped_response.reserve(response.length() * 2); // pre-allocate for efficiency + + for (char c : response) { + switch (c) { + case '\n': + escaped_response += "\\n"; + break; + case '\r': + escaped_response += "\\r"; + break; + case '\t': + escaped_response += "\\t"; + break; + case '\\': + escaped_response += "\\\\"; + break; + case '\"': + escaped_response += "\\\""; + break; + default: + escaped_response += c; + break; + } } Serial.printf("void test_%d() {\n", count++); - Serial.printf(" auto expected_response = \"%s\";\n", escaped_response.c_str()); + Serial.print(" auto expected_response = \""); + Serial.print(escaped_response.c_str()); + Serial.println("\";"); Serial.printf(" TEST_ASSERT_EQUAL_STRING(expected_response, call_url(\"%s\"));\n", url); Serial.println("}"); Serial.println(); diff --git a/test/test_api/test_api.h b/test/test_api/test_api.h index 1e2974d63..23e5e8101 100644 --- a/test/test_api/test_api.h +++ b/test/test_api/test_api.h @@ -67,103 +67,159 @@ void test_4() { } void test_5() { + auto expected_response = + "[{\"api_data\":\"# HELP emsesp_heatingoff force heating off, boolean, readable, writeable, visible\\n# TYPE emsesp_heatingoff " + "gauge\\nemsesp_heatingoff 0\\n# HELP emsesp_heatingactive is my heating on?, boolean, readable, visible\\n# TYPE emsesp_heatingactive " + "gauge\\nemsesp_heatingactive 0\\n# HELP emsesp_tapwateractive tapwater active, boolean, readable, visible\\n# TYPE emsesp_tapwateractive " + "gauge\\nemsesp_tapwateractive 1\\n# HELP emsesp_selflowtemp selected flow temperature, °C, readable, writeable, visible\\n# TYPE emsesp_selflowtemp " + "gauge\\nemsesp_selflowtemp 0\\n# HELP emsesp_curflowtemp current flow temperature, °C, readable, visible\\n# TYPE emsesp_curflowtemp " + "gauge\\nemsesp_curflowtemp 60.20\\n# HELP emsesp_rettemp return temperature, °C, readable, visible\\n# TYPE emsesp_rettemp gauge\\nemsesp_rettemp " + "48.10\\n# HELP emsesp_syspress system pressure, bar, readable, visible\\n# TYPE emsesp_syspress gauge\\nemsesp_syspress 1.40\\n# HELP emsesp_burngas " + "gas, boolean, readable, visible\\n# TYPE emsesp_burngas gauge\\nemsesp_burngas 1\\n# HELP emsesp_burngas2 gas stage 2, boolean, readable, visible\\n# " + "TYPE emsesp_burngas2 gauge\\nemsesp_burngas2 0\\n# HELP emsesp_flamecurr flame current, µA, readable, visible\\n# TYPE emsesp_flamecurr " + "gauge\\nemsesp_flamecurr 37.40\\n# HELP emsesp_fanwork fan, boolean, readable, visible\\n# TYPE emsesp_fanwork gauge\\nemsesp_fanwork 1\\n# HELP " + "emsesp_ignwork ignition, boolean, readable, visible\\n# TYPE emsesp_ignwork gauge\\nemsesp_ignwork 0\\n# HELP emsesp_oilpreheat oil preheating, " + "boolean, readable, visible\\n# TYPE emsesp_oilpreheat gauge\\nemsesp_oilpreheat 0\\n# HELP emsesp_heatingpump heating pump, boolean, readable, " + "visible\\n# TYPE emsesp_heatingpump gauge\\nemsesp_heatingpump 1\\n# HELP emsesp_selburnpow burner selected max power, %, readable, writeable, " + "visible\\n# TYPE emsesp_selburnpow gauge\\nemsesp_selburnpow 115\\n# HELP emsesp_curburnpow burner current power, %, readable, visible\\n# TYPE " + "emsesp_curburnpow gauge\\nemsesp_curburnpow 61\\n# HELP emsesp_ubauptime total UBA operating time, minutes, readable, visible\\n# TYPE " + "emsesp_ubauptime gauge\\nemsesp_ubauptime 3940268\\n# HELP emsesp_servicecodenumber service code number, readable, visible\\n# TYPE " + "emsesp_servicecodenumber gauge\\nemsesp_servicecodenumber 201\\n# HELP emsesp_seltemp selected temperature, °C, readable, writeable, visible\\n# TYPE " + "emsesp_seltemp gauge\\nemsesp_seltemp{circuit=\\\"dhw\\\"} 52\\n# HELP emsesp_comfort comfort, enum, (0: hot; 1: eco; 2: intelligent), readable, " + "writeable, visible\\n# TYPE emsesp_comfort gauge\\nemsesp_comfort{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_flowtempoffset flow temperature offset, °C, " + "readable, writeable, visible\\n# TYPE emsesp_flowtempoffset gauge\\nemsesp_flowtempoffset{circuit=\\\"dhw\\\"} 40\\n# HELP emsesp_chargeoptimization " + "charge optimization, boolean, readable, writeable, visible\\n# TYPE emsesp_chargeoptimization gauge\\nemsesp_chargeoptimization{circuit=\\\"dhw\\\"} " + "0\\n# HELP emsesp_circpump circulation pump available, boolean, readable, writeable, visible\\n# TYPE emsesp_circpump " + "gauge\\nemsesp_circpump{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_chargetype charging type, enum, (0: chargepump; 1: 3-way valve), readable, visible\\n# " + "TYPE emsesp_chargetype gauge\\nemsesp_chargetype{circuit=\\\"dhw\\\"} 1\\n# HELP emsesp_hyston hysteresis on temperature, °C, readable, writeable, " + "visible\\n# TYPE emsesp_hyston gauge\\nemsesp_hyston{circuit=\\\"dhw\\\"} -5\\n# HELP emsesp_disinfectiontemp disinfection temperature, °C, readable, " + "writeable, visible\\n# TYPE emsesp_disinfectiontemp gauge\\nemsesp_disinfectiontemp{circuit=\\\"dhw\\\"} 70\\n# HELP emsesp_circmode circulation pump " + "mode, enum, (0: off; 1: 1x3min; 2: 2x3min; 3: 3x3min; 4: 4x3min; 5: 5x3min; 6: 6x3min; 7: continuous), readable, writeable, visible\\n# TYPE " + "emsesp_circmode gauge\\nemsesp_circmode{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_circ circulation active, boolean, readable, writeable, visible\\n# " + "TYPE emsesp_circ gauge\\nemsesp_circ{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_storagetemp1 storage intern temperature, °C, readable, visible\\n# TYPE " + "emsesp_storagetemp1 gauge\\nemsesp_storagetemp1{circuit=\\\"dhw\\\"} 53.80\\n# HELP emsesp_activated activated, boolean, readable, writeable, " + "visible\\n# TYPE emsesp_activated gauge\\nemsesp_activated{circuit=\\\"dhw\\\"} 1\\n# HELP emsesp_3wayvalve 3-way valve active, boolean, readable, " + "visible\\n# TYPE emsesp_3wayvalve gauge\\nemsesp_3wayvalve{circuit=\\\"dhw\\\"} 1\\n# HELP emsesp_chargepump charge pump, boolean, readable, " + "visible\\n# TYPE emsesp_chargepump gauge\\nemsesp_chargepump{circuit=\\\"dhw\\\"} 0\\n# HELP emsesp_nompower nominal Power, kW, readable, writeable, " + "visible\\n# TYPE emsesp_nompower gauge\\nemsesp_nompower 0\\n# HELP emsesp_nrgtotal total energy, kWh, readable, visible\\n# TYPE emsesp_nrgtotal " + "gauge\\nemsesp_nrgtotal 0\\n# HELP emsesp_nrgheat energy heating, kWh, readable, writeable, visible\\n# TYPE emsesp_nrgheat gauge\\nemsesp_nrgheat " + "0\\n# HELP emsesp_nrg energy, kWh, readable, writeable, visible\\n# TYPE emsesp_nrg gauge\\nemsesp_nrg{circuit=\\\"dhw\\\"} 0\\n\"}]"; + TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/metrics")); +} + +void test_6() { auto expected_response = "[{\"name\":\"comfort\",\"fullname\":\"dhw " "comfort\",\"circuit\":\"dhw\",\"index\":0,\"enum\":[\"hot\",\"eco\",\"intelligent\"],\"value\":\"hot\",\"type\":\"enum\"," "\"readable\":true,\"writeable\":true,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort")); } -void test_6() { +void test_7() { auto expected_response = "[{\"api_data\":\"hot\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/value")); } -void test_7() { +void test_8() { auto expected_response = "[{\"api_data\":\"dhw comfort\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/fullname")); } -void test_8() { +void test_9() { auto expected_response = "[{\"name\":\"outdoortemp\",\"fullname\":\"outside " "temperature\",\"circuit\":\"\",\"type\":\"number\",\"uom\":\"°C\",\"state_class\":\"measurement\",\"device_class\":" "\"temperature\",\"readable\":true,\"writeable\":false,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/outdoortemp")); } -void test_9() { +void test_10() { auto expected_response = "[{\"name\":\"chargetype\",\"fullname\":\"dhw charging type\",\"circuit\":\"dhw\",\"index\":1,\"enum\":[\"chargepump\",\"3-way " "valve\"],\"value\":\"3-way valve\",\"type\":\"enum\",\"readable\":true,\"writeable\":false,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/dhw/chargetype")); } -void test_10() { +void test_11() { auto expected_response = "[{\"api_data\":\"false\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/dhw.chargetype/writeable")); } -void test_11() { +void test_12() { auto expected_response = "[{\"api_data\":\"37.4\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/flamecurr/value")); } -void test_12() { +void test_13() { auto expected_response = "[{\"hc1\":{\"seltemp\":20.5,\"currtemp\":22.8,\"haclimate\":\"roomTemp\",\"modetype\":\"heat\",\"remotetemp\":null},\"hc2\":{" "\"seltemp\":20.6,\"currtemp\":22.9,\"haclimate\":\"roomTemp\",\"modetype\":\"eco\",\"remotetemp\":null},\"hc3\":{\"seltemp\":20." "7,\"currtemp\":23.0,\"haclimate\":\"roomTemp\",\"modetype\":\"nofrost\",\"remotetemp\":null},\"dhw\":{}}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat")); } -void test_13() { +void test_14() { auto expected_response = "[{\"seltemp\":20.5,\"currtemp\":22.8,\"haclimate\":\"roomTemp\",\"modetype\":\"heat\",\"remotetemp\":null}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc1/values")); } -void test_14() { +void test_15() { + auto expected_response = + "[{\"api_data\":\"# HELP emsesp_seltemp selected room temperature, °C, readable, writeable, visible\\n# TYPE emsesp_seltemp " + "gauge\\nemsesp_seltemp{circuit=\\\"hc1\\\"} 20.50\\n# HELP emsesp_currtemp current room temperature, °C, readable, visible\\n# TYPE emsesp_currtemp " + "gauge\\nemsesp_currtemp{circuit=\\\"hc1\\\"} 22.80\\n# HELP emsesp_haclimate mqtt discovery current room temperature, enum, (0: selTemp; 1: " + "roomTemp), readable, visible\\n# TYPE emsesp_haclimate gauge\\nemsesp_haclimate{circuit=\\\"hc1\\\"} 1\\n# HELP emsesp_modetype mode type, enum, (0: " + "nofrost; 1: eco; 2: heat), readable, visible\\n# TYPE emsesp_modetype gauge\\nemsesp_modetype{circuit=\\\"hc1\\\"} " + "2\\nemsesp_seltemp{circuit=\\\"hc2\\\"} 20.60\\nemsesp_currtemp{circuit=\\\"hc2\\\"} 22.90\\nemsesp_haclimate{circuit=\\\"hc2\\\"} " + "1\\nemsesp_modetype{circuit=\\\"hc2\\\"} 1\\nemsesp_seltemp{circuit=\\\"hc3\\\"} 20.70\\nemsesp_currtemp{circuit=\\\"hc3\\\"} " + "23\\nemsesp_haclimate{circuit=\\\"hc3\\\"} 1\\nemsesp_modetype{circuit=\\\"hc3\\\"} 0\\n\"}]"; + TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/metrics")); +} + +void test_16() { auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"hc1 selected room " "temperature\",\"circuit\":\"hc1\",\"value\":20.5,\"type\":\"number\",\"min\":0,\"max\":30,\"uom\":\"°C\",\"state_class\":" "\"measurement\",\"device_class\":\"temperature\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc1/seltemp")); } -void test_15() { +void test_17() { auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"hc2 selected room " "temperature\",\"circuit\":\"hc2\",\"value\":20.6,\"type\":\"number\",\"min\":0,\"max\":30,\"uom\":\"°C\",\"state_class\":" "\"measurement\",\"device_class\":\"temperature\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/hc2/seltemp")); } -void test_16() { +void test_18() { auto expected_response = "[{\"test_custom\":0.00,\"test_read_only\":70.00,\"test_ram\":\"14\",\"test_seltemp\":\"14\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom")); } -void test_17() { +void test_19() { auto expected_response = "[{\"test_custom\":0.00,\"test_read_only\":70.00,\"test_ram\":\"14\",\"test_seltemp\":\"14\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/info")); } -void test_18() { +void test_20() { auto expected_response = "[{\"name\":\"test_seltemp\",\"fullname\":\"test_seltemp\",\"storage\":\"ram\",\"type\":\"number\",\"readable\":true," "\"writeable\":true,\"visible\":true,\"ent_cat\":\"diagnostic\",\"value\":\"14\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp")); } -void test_19() { +void test_21() { auto expected_response = "[{\"api_data\":\"14\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp/value")); } -void test_20() { +void test_22() { auto expected_response = "[{\"name\":\"test_custom\",\"fullname\":\"test_custom\",\"storage\":\"ems\",\"type\":\"number\",\"readable\":true,\"writeable\":" "true,\"visible\":true,\"device_id\":\"0x08\",\"type_id\":\"0x18\",\"offset\":0,\"factor\":1,\"ent_cat\":\"diagnostic\",\"uom\":" "\"°C\",\"state_class\":\"measurement\",\"device_class\":\"temperature\",\"value\":0.00}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_custom")); } -void test_21() { +void test_23() { auto expected_response = "[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / " - "Unknown\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," + "Unknown\",\"txpause\":false,\"gpios_in_use\":\"23, 5, 2, 18, 0\",\"gpios_available\":\"1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, " + "21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, " + "39\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," "\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\"," "\"tzLabel\":\"Europe/" "London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\"," @@ -189,10 +245,12 @@ void test_21() { TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system")); } -void test_22() { +void test_24() { auto expected_response = "[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / " - "Unknown\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," + "Unknown\",\"txpause\":false,\"gpios_in_use\":\"23, 5, 2, 18, 0\",\"gpios_available\":\"1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, " + "21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, " + "39\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," "\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\"," "\"tzLabel\":\"Europe/" "London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\"," @@ -218,169 +276,255 @@ void test_22() { TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/info")); } -void test_23() { +void test_25() { + auto expected_response = + "[{\"api_data\":\"# HELP emsesp_system_uptimesec uptimeSec\\n# TYPE emsesp_system_uptimesec gauge\\nemsesp_system_uptimesec 0\\n# HELP " + "emsesp_system_txpause txpause\\n# TYPE emsesp_system_txpause gauge\\nemsesp_system_txpause 0\\n# HELP emsesp_system_info info\\n# TYPE " + "emsesp_system_info gauge\\nemsesp_system_info{version=\\\"dev\\\", resetreason=\\\"Unknown / Unknown\\\", gpios_in_use=\\\"23, 5, 2, 18, 0\\\", " + "gpios_available=\\\"1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, " + "39\\\"} 1\\n# HELP emsesp_network_rssi RSSI\\n# TYPE emsesp_network_rssi gauge\\nemsesp_network_rssi -23\\n# HELP emsesp_network_txpowersetting " + "TxPowerSetting\\n# TYPE emsesp_network_txpowersetting gauge\\nemsesp_network_txpowersetting 0\\n# HELP emsesp_network_staticip staticIP\\n# TYPE " + "emsesp_network_staticip gauge\\nemsesp_network_staticip 0\\n# HELP emsesp_network_lowbandwidth lowBandwidth\\n# TYPE emsesp_network_lowbandwidth " + "gauge\\nemsesp_network_lowbandwidth 0\\n# HELP emsesp_network_disablesleep disableSleep\\n# TYPE emsesp_network_disablesleep " + "gauge\\nemsesp_network_disablesleep 1\\n# HELP emsesp_network_enablemdns enableMDNS\\n# TYPE emsesp_network_enablemdns " + "gauge\\nemsesp_network_enablemdns 1\\n# HELP emsesp_network_enablecors enableCORS\\n# TYPE emsesp_network_enablecors " + "gauge\\nemsesp_network_enablecors 0\\n# HELP emsesp_network_info info\\n# TYPE emsesp_network_info gauge\\nemsesp_network_info{network=\\\"WiFi\\\", " + "hostname=\\\"ems-esp\\\"} 1\\n# HELP emsesp_ntp_enabled enabled\\n# TYPE emsesp_ntp_enabled gauge\\nemsesp_ntp_enabled 1\\n# HELP emsesp_ntp_info " + "info\\n# TYPE emsesp_ntp_info gauge\\nemsesp_ntp_info{ntpstatus=\\\"disconnected\\\", server=\\\"pool.ntp.org\\\", tzlabel=\\\"Europe/London\\\"} " + "1\\n# HELP emsesp_ap_info info\\n# TYPE emsesp_ap_info gauge\\nemsesp_ap_info{provisionmode=\\\"always\\\", ssid=\\\"ems-esp\\\"} 1\\n# HELP " + "emsesp_mqtt_mqttpublishes MQTTPublishes\\n# TYPE emsesp_mqtt_mqttpublishes gauge\\nemsesp_mqtt_mqttpublishes 0\\n# HELP emsesp_mqtt_mqttqueued " + "MQTTQueued\\n# TYPE emsesp_mqtt_mqttqueued gauge\\nemsesp_mqtt_mqttqueued 0\\n# HELP emsesp_mqtt_mqttpublishfails MQTTPublishFails\\n# TYPE " + "emsesp_mqtt_mqttpublishfails gauge\\nemsesp_mqtt_mqttpublishfails 0\\n# HELP emsesp_mqtt_mqttreconnects MQTTReconnects\\n# TYPE " + "emsesp_mqtt_mqttreconnects gauge\\nemsesp_mqtt_mqttreconnects 0\\n# HELP emsesp_mqtt_enabled enabled\\n# TYPE emsesp_mqtt_enabled " + "gauge\\nemsesp_mqtt_enabled 1\\n# HELP emsesp_mqtt_keepalive keepAlive\\n# TYPE emsesp_mqtt_keepalive gauge\\nemsesp_mqtt_keepalive 60\\n# HELP " + "emsesp_mqtt_cleansession cleanSession\\n# TYPE emsesp_mqtt_cleansession gauge\\nemsesp_mqtt_cleansession 0\\n# HELP emsesp_mqtt_entityformat " + "entityFormat\\n# TYPE emsesp_mqtt_entityformat gauge\\nemsesp_mqtt_entityformat 1\\n# HELP emsesp_mqtt_discoverytype discoveryType\\n# TYPE " + "emsesp_mqtt_discoverytype gauge\\nemsesp_mqtt_discoverytype 0\\n# HELP emsesp_mqtt_nestedformat nestedFormat\\n# TYPE emsesp_mqtt_nestedformat " + "gauge\\nemsesp_mqtt_nestedformat 1\\n# HELP emsesp_mqtt_haenabled haEnabled\\n# TYPE emsesp_mqtt_haenabled gauge\\nemsesp_mqtt_haenabled 1\\n# HELP " + "emsesp_mqtt_mqttqos mqttQos\\n# TYPE emsesp_mqtt_mqttqos gauge\\nemsesp_mqtt_mqttqos 0\\n# HELP emsesp_mqtt_mqttretain mqttRetain\\n# TYPE " + "emsesp_mqtt_mqttretain gauge\\nemsesp_mqtt_mqttretain 0\\n# HELP emsesp_mqtt_publishtimeheartbeat publishTimeHeartbeat\\n# TYPE " + "emsesp_mqtt_publishtimeheartbeat gauge\\nemsesp_mqtt_publishtimeheartbeat 60\\n# HELP emsesp_mqtt_publishtimeboiler publishTimeBoiler\\n# TYPE " + "emsesp_mqtt_publishtimeboiler gauge\\nemsesp_mqtt_publishtimeboiler 10\\n# HELP emsesp_mqtt_publishtimethermostat publishTimeThermostat\\n# TYPE " + "emsesp_mqtt_publishtimethermostat gauge\\nemsesp_mqtt_publishtimethermostat 10\\n# HELP emsesp_mqtt_publishtimesolar publishTimeSolar\\n# TYPE " + "emsesp_mqtt_publishtimesolar gauge\\nemsesp_mqtt_publishtimesolar 10\\n# HELP emsesp_mqtt_publishtimemixer publishTimeMixer\\n# TYPE " + "emsesp_mqtt_publishtimemixer gauge\\nemsesp_mqtt_publishtimemixer 10\\n# HELP emsesp_mqtt_publishtimewater publishTimeWater\\n# TYPE " + "emsesp_mqtt_publishtimewater gauge\\nemsesp_mqtt_publishtimewater 0\\n# HELP emsesp_mqtt_publishtimeother publishTimeOther\\n# TYPE " + "emsesp_mqtt_publishtimeother gauge\\nemsesp_mqtt_publishtimeother 10\\n# HELP emsesp_mqtt_publishtimesensor publishTimeSensor\\n# TYPE " + "emsesp_mqtt_publishtimesensor gauge\\nemsesp_mqtt_publishtimesensor 10\\n# HELP emsesp_mqtt_publishsingle publishSingle\\n# TYPE " + "emsesp_mqtt_publishsingle gauge\\nemsesp_mqtt_publishsingle 0\\n# HELP emsesp_mqtt_publish2command publish2command\\n# TYPE " + "emsesp_mqtt_publish2command gauge\\nemsesp_mqtt_publish2command 0\\n# HELP emsesp_mqtt_sendresponse sendResponse\\n# TYPE emsesp_mqtt_sendresponse " + "gauge\\nemsesp_mqtt_sendresponse 0\\n# HELP emsesp_mqtt_info info\\n# TYPE emsesp_mqtt_info gauge\\nemsesp_mqtt_info{mqttstatus=\\\"disconnected\\\", " + "clientid=\\\"ems-esp\\\", base=\\\"ems-esp\\\", discoveryprefix=\\\"homeassistant\\\"} 1\\n# HELP emsesp_syslog_enabled enabled\\n# TYPE " + "emsesp_syslog_enabled gauge\\nemsesp_syslog_enabled 0\\n# HELP emsesp_sensor_temperaturesensors temperatureSensors\\n# TYPE " + "emsesp_sensor_temperaturesensors gauge\\nemsesp_sensor_temperaturesensors 3\\n# HELP emsesp_sensor_temperaturesensorreads temperatureSensorReads\\n# " + "TYPE emsesp_sensor_temperaturesensorreads gauge\\nemsesp_sensor_temperaturesensorreads 0\\n# HELP emsesp_sensor_temperaturesensorfails " + "temperatureSensorFails\\n# TYPE emsesp_sensor_temperaturesensorfails gauge\\nemsesp_sensor_temperaturesensorfails 0\\n# HELP " + "emsesp_sensor_analogsensors analogSensors\\n# TYPE emsesp_sensor_analogsensors gauge\\nemsesp_sensor_analogsensors 5\\n# HELP " + "emsesp_sensor_analogsensorreads analogSensorReads\\n# TYPE emsesp_sensor_analogsensorreads gauge\\nemsesp_sensor_analogsensorreads 0\\n# HELP " + "emsesp_sensor_analogsensorfails analogSensorFails\\n# TYPE emsesp_sensor_analogsensorfails gauge\\nemsesp_sensor_analogsensorfails 0\\n# HELP " + "emsesp_api_apicalls APICalls\\n# TYPE emsesp_api_apicalls gauge\\nemsesp_api_apicalls 0\\n# HELP emsesp_api_apifails APIFails\\n# TYPE " + "emsesp_api_apifails gauge\\nemsesp_api_apifails 0\\n# HELP emsesp_bus_bustelegramsreceived busTelegramsReceived\\n# TYPE " + "emsesp_bus_bustelegramsreceived gauge\\nemsesp_bus_bustelegramsreceived 8\\n# HELP emsesp_bus_busreads busReads\\n# TYPE emsesp_bus_busreads " + "gauge\\nemsesp_bus_busreads 0\\n# HELP emsesp_bus_buswrites busWrites\\n# TYPE emsesp_bus_buswrites gauge\\nemsesp_bus_buswrites 0\\n# HELP " + "emsesp_bus_busincompletetelegrams busIncompleteTelegrams\\n# TYPE emsesp_bus_busincompletetelegrams gauge\\nemsesp_bus_busincompletetelegrams 0\\n# " + "HELP emsesp_bus_busreadsfailed busReadsFailed\\n# TYPE emsesp_bus_busreadsfailed gauge\\nemsesp_bus_busreadsfailed 0\\n# HELP " + "emsesp_bus_buswritesfailed busWritesFailed\\n# TYPE emsesp_bus_buswritesfailed gauge\\nemsesp_bus_buswritesfailed 0\\n# HELP " + "emsesp_bus_busrxlinequality busRxLineQuality\\n# TYPE emsesp_bus_busrxlinequality gauge\\nemsesp_bus_busrxlinequality 100\\n# HELP " + "emsesp_bus_bustxlinequality busTxLineQuality\\n# TYPE emsesp_bus_bustxlinequality gauge\\nemsesp_bus_bustxlinequality 100\\n# HELP emsesp_bus_info " + "info\\n# TYPE emsesp_bus_info gauge\\nemsesp_bus_info{busstatus=\\\"connected\\\", busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode " + "txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 8\\n# HELP emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid " + "gauge\\nemsesp_settings_emsbusid 11\\n# HELP emsesp_settings_showertimer showerTimer\\n# TYPE emsesp_settings_showertimer " + "gauge\\nemsesp_settings_showertimer 0\\n# HELP emsesp_settings_showerminduration showerMinDuration\\n# TYPE emsesp_settings_showerminduration " + "gauge\\nemsesp_settings_showerminduration 180\\n# HELP emsesp_settings_showeralert showerAlert\\n# TYPE emsesp_settings_showeralert " + "gauge\\nemsesp_settings_showeralert 0\\n# HELP emsesp_settings_hideled hideLed\\n# TYPE emsesp_settings_hideled gauge\\nemsesp_settings_hideled 0\\n# " + "HELP emsesp_settings_notokenapi noTokenApi\\n# TYPE emsesp_settings_notokenapi gauge\\nemsesp_settings_notokenapi 0\\n# HELP " + "emsesp_settings_readonlymode readonlyMode\\n# TYPE emsesp_settings_readonlymode gauge\\nemsesp_settings_readonlymode 0\\n# HELP " + "emsesp_settings_fahrenheit fahrenheit\\n# TYPE emsesp_settings_fahrenheit gauge\\nemsesp_settings_fahrenheit 0\\n# HELP " + "emsesp_settings_dallasparasite dallasParasite\\n# TYPE emsesp_settings_dallasparasite gauge\\nemsesp_settings_dallasparasite 0\\n# HELP " + "emsesp_settings_boolformat boolFormat\\n# TYPE emsesp_settings_boolformat gauge\\nemsesp_settings_boolformat 1\\n# HELP emsesp_settings_booldashboard " + "boolDashboard\\n# TYPE emsesp_settings_booldashboard gauge\\nemsesp_settings_booldashboard 1\\n# HELP emsesp_settings_enumformat enumFormat\\n# TYPE " + "emsesp_settings_enumformat gauge\\nemsesp_settings_enumformat 1\\n# HELP emsesp_settings_analogenabled analogEnabled\\n# TYPE " + "emsesp_settings_analogenabled gauge\\nemsesp_settings_analogenabled 1\\n# HELP emsesp_settings_telnetenabled telnetEnabled\\n# TYPE " + "emsesp_settings_telnetenabled gauge\\nemsesp_settings_telnetenabled 1\\n# HELP emsesp_settings_maxweblogbuffer maxWebLogBuffer\\n# TYPE " + "emsesp_settings_maxweblogbuffer gauge\\nemsesp_settings_maxweblogbuffer 25\\n# HELP emsesp_settings_modbusenabled modbusEnabled\\n# TYPE " + "emsesp_settings_modbusenabled gauge\\nemsesp_settings_modbusenabled 0\\n# HELP emsesp_settings_forceheatingoff forceHeatingOff\\n# TYPE " + "emsesp_settings_forceheatingoff gauge\\nemsesp_settings_forceheatingoff 0\\n# HELP emsesp_settings_developermode developerMode\\n# TYPE " + "emsesp_settings_developermode gauge\\nemsesp_settings_developermode 0\\n# HELP emsesp_settings_info info\\n# TYPE emsesp_settings_info " + "gauge\\nemsesp_settings_info{boardprofile=\\\"S32\\\", locale=\\\"en\\\"} 1\\n# HELP emsesp_device_productid productID\\n# TYPE " + "emsesp_device_productid gauge\\nemsesp_device_productid{type=\\\"boiler\\\", name=\\\"My Custom Boiler\\\", deviceid=\\\"0x08\\\", " + "version=\\\"01.00\\\"} 123\\n# HELP emsesp_device_entities entities\\n# TYPE emsesp_device_entities " + "gauge\\nemsesp_device_entities{type=\\\"boiler\\\", name=\\\"My Custom Boiler\\\", deviceid=\\\"0x08\\\", version=\\\"01.00\\\"} " + "39\\nemsesp_device_productid{type=\\\"thermostat\\\", name=\\\"FW120\\\", deviceid=\\\"0x10\\\", version=\\\"01.00\\\"} " + "192\\nemsesp_device_entities{type=\\\"thermostat\\\", name=\\\"FW120\\\", deviceid=\\\"0x10\\\", version=\\\"01.00\\\"} " + "15\\nemsesp_device_entities{type=\\\"temperaturesensor\\\", name=\\\"temperaturesensor\\\"} 3\\nemsesp_device_entities{type=\\\"analogsensor\\\", " + "name=\\\"analogsensor\\\"} 5\\nemsesp_device_entities{type=\\\"scheduler\\\", name=\\\"scheduler\\\"} 2\\nemsesp_device_entities{type=\\\"custom\\\", " + "name=\\\"custom\\\"} 4\\n\"}]"; + TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/metrics")); +} + +void test_26() { auto expected_response = "[{\"name\":\"locale\",\"circuit\":\"settings\",\"readable\":true,\"writeable\":false,\"visible\":true,\"value\":\"en\",\"type\":\"string\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings/locale")); } -void test_24() { +void test_27() { auto expected_response = "[{}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/fetch")); } -void test_25() { +void test_28() { auto expected_response = "[{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":\"-23\",\"TxPowerSetting\":\"0\",\"staticIP\":\"false\"," "\"lowBandwidth\":\"false\",\"disableSleep\":\"true\",\"enableMDNS\":\"true\",\"enableCORS\":\"false\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/network/values")); } -void test_26() { +void test_29() { auto expected_response = "[{\"test_scheduler\":\"on\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler")); } -void test_27() { +void test_30() { auto expected_response = "[{\"test_scheduler\":\"on\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/info")); } -void test_28() { +void test_31() { auto expected_response = "[{\"name\":\"test_scheduler\",\"fullname\":\"test_scheduler\",\"type\":\"boolean\",\"value\":\"on\",\"time\":\"12:00\"," "\"command\":\"system/fetch\",\"cmd_data\":\"10\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler")); } -void test_29() { +void test_32() { auto expected_response = "[{\"test_tempsensor1\":12.3,\"test_tempsensor2\":45.6,\"gateway_temperature\":28.1}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor")); } -void test_30() { +void test_33() { auto expected_response = "[{\"test_tempsensor1\":12.3,\"test_tempsensor2\":45.6,\"gateway_temperature\":28.1}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/info")); } -void test_31() { +void test_34() { auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":" "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2")); } -void test_32() { +void test_35() { auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":" "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_1011")); } -void test_33() { +void test_36() { auto expected_response = "[{\"api_data\":\"45.6\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2/value")); } -void test_34() { +void test_37() { auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0,\"test_analogsensor4\":0,\"test_analogsensor5\":0}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor")); } -void test_35() { +void test_38() { auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0,\"test_analogsensor4\":0,\"test_analogsensor5\":0}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/info")); } -void test_36() { +void test_39() { auto expected_response = "[{\"name\":\"test_analogsensor1\",\"fullname\":\"test_analogsensor1\",\"gpio\":36,\"type\":\"number\",\"analog\":\"adc\",\"value\":0,\"readable\":" "true,\"writeable\":false,\"visible\":true,\"is_system\":false,\"offset\":0,\"factor\":0.2,\"uom\":\"mV\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1")); } -void test_37() { +void test_40() { auto expected_response = "[{\"api_data\":\"0\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1/offset")); } -void test_38() { +void test_41() { auto expected_response = "[{\"message\":\"unknown device boiler2\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler2")); } -void test_39() { +void test_42() { auto expected_response = "[{}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/bad/value")); } -void test_40() { +void test_43() { auto expected_response = "[{\"message\":\"no attribute 'valu' in comfort\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/valu")); } -void test_41() { +void test_44() { auto expected_response = "[{\"message\":\"no 'settings' in system\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings/locale2")); } -void test_42() { +void test_45() { auto expected_response = "[{\"message\":\"no 'settings2' in system\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings2")); } -void test_43() { +void test_46() { auto expected_response = "[{\"message\":\"no 'settings2' in system\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/settings2/locale2")); } -void test_44() { +void test_47() { auto expected_response = "[{\"message\":\"no 'test_scheduler2' in scheduler\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler2")); } -void test_45() { +void test_48() { auto expected_response = "[{\"message\":\"no attribute 'val' in test_scheduler\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler/val")); } -void test_46() { +void test_49() { auto expected_response = "[{\"message\":\"no 'test_scheduler2' in scheduler\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler2/val2")); } -void test_47() { +void test_50() { auto expected_response = "[{\"message\":\"no 'test_seltemp2' in custom\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp2")); } -void test_48() { +void test_51() { auto expected_response = "[{\"message\":\"Command test_seltemp failed (Error)\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/test_seltemp/val")); } -void test_49() { +void test_52() { auto expected_response = "[{\"message\":\"no 'test_sensor20' in temperaturesensor\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_sensor20")); } -void test_50() { +void test_53() { auto expected_response = "[{\"message\":\"no '0b_0c0d_0e0f_xxxx' in temperaturesensor\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_XXXX")); } -void test_51() { +void test_54() { auto expected_response = "[{\"message\":\"no attribute 'bad' in test_tempsensor2\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2/bad")); } -void test_52() { +void test_55() { auto expected_response = "[{\"message\":\"no attribute 'bad' in test_analogsensor1\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1/bad")); } -void test_53() { +void test_56() { auto expected_response = "[{\"message\":\"no 'test_analog10' in analogsensor\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analog10")); } -void test_54() { +void test_57() { auto expected_response = "[{\"message\":\"no 'test_analog10' in analogsensor\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analog10/bad2")); } @@ -440,6 +584,9 @@ void run_tests() { RUN_TEST(test_52); RUN_TEST(test_53); RUN_TEST(test_54); + RUN_TEST(test_55); + RUN_TEST(test_56); + RUN_TEST(test_57); } // ---------- END - CUT HERE ---------- \ No newline at end of file From bb22386f7fcdb1cc39a11786fee14bafc632c357 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 21:32:15 +0100 Subject: [PATCH 14/42] updated --- CHANGELOG_LATEST.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 3909be7dd..b226b857e 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -10,8 +10,9 @@ For more details go to [emsesp.org](https://emsesp.org/). ## Fixed +- fix EMS bus disconnected [#2881](https://github.com/emsesp/EMS-ESP32/issues/2881) - selflowtemp fix [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876) -- valid GPIOs for ESP32S2, ESP32S3 and ESP32 +- updated valid GPIOs for ESP32S2, ESP32S3 and ESP32 [#2887](https://github.com/emsesp/EMS-ESP32/issues/2887) - Junkers wwcharge offset [#2860](https://github.com/emsesp/EMS-ESP32/issues/2860) - fixed minflowtemp [#2890](https://github.com/emsesp/EMS-ESP32/issues/2890) - don't add HA uom/classes for bool values [#2885](https://github.com/emsesp/EMS-ESP32/issues/2885) From 712a8537c9adf206d616eac816c7031f75075a32 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 21:32:32 +0100 Subject: [PATCH 15/42] remove unused struct --- src/core/system.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/core/system.h b/src/core/system.h index 6e7612766..79e45a9c8 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -159,12 +159,6 @@ class System { static void extractSettings(const char * filename, const char * section, JsonObject output); static bool saveSettings(const char * filename, const char * section, JsonObject input); - // GPIOs - struct GpioInfo { - uint8_t pin; - std::string name; - }; - static bool add_gpio(uint8_t pin, const char * source_name); static std::vector available_gpios(); static bool load_board_profile(std::vector & data, const std::string & board_profile); @@ -446,8 +440,8 @@ class System { uint8_t pin; std::string source; }; - static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used - static std::vector> used_gpios_; // list of GPIOs used by the application + static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used + static std::vector> used_gpios_; // list of GPIOs used by the application int8_t wifi_quality(int8_t dBm); From 84af132e2c1f00b5b16cdfe79a09f510d40b51e3 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 21:33:30 +0100 Subject: [PATCH 16/42] fix mix-up of GPIOs --- src/core/system.cpp | 74 ++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 31ab34e41..d7f71e707 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2799,7 +2799,10 @@ uint8_t System::systemStatus() { return systemStatus_; } -// takes a string range like "6-11, 1, 23, 24-48" which has optional ranges and single values and converts to a vector of ints +// takes two arguments: +// the first is the full range of pins to consider +// the second is a string range of GPIOs to exclude, like "6-11, 1, 23, 24-48" +// returns a vector array of GPIOs that are valid for use std::vector> System::string_range_to_vector(const std::string & range, const std::string & exclude) { std::vector> gpios; std::string::size_type pos = 0; @@ -2876,7 +2879,7 @@ std::vector> System::string_range_to_vector(con } // initialize a list of valid GPIOs based on the ESP32 board -// string_to_vector() take two strings, the first is the range of GPIOs to use, the second is the range of GPIOs to exclude +// string_to_vector() take two strings, the first is the range of GPIOs to use, the second is a list of GPIOs to exclude // note: we always allow 0, which is used to indicate Dallas or LED is disabled void System::set_valid_system_gpios() { valid_system_gpios_.clear(); // reset system list @@ -2884,49 +2887,44 @@ void System::set_valid_system_gpios() { // get free gpios based on board/platform type #if CONFIG_IDF_TARGET_ESP32C3 - // not valid: - // 20-21 are UART0 - valid_system_gpios_ = string_range_to_vector("0-21", "20-21"); + // non valid GPIOs: + // 3, 9-10 are strapping pins that can affect boot behaviour + // 8 is connected to the internal ULP (Ultra Low Power) coprocessor and should be avoided for external connections + // 11 is used for internal flash connection + // notes on valid GPIOs: + // there are no input only pins on a C3 + valid_system_gpios_ = string_range_to_vector("0-21", "3, 9-10, 8, 11"); #elif CONFIG_IDF_TARGET_ESP32S2 - // not valid: - // 6-11 are used for SPI flash and PSRAM - // 16-17 are also used for SPI flash and PSRAM - // 45-46 are strapping pins - // 43-44 are UART0 - // notes: + // non valid GPIOs: + // 3, 45-46 are strapping pins that can affect boot behaviour + // 6-11 and 35 are used for SPI flash and PSRAM + // notes on valid GPIOs: // 34-39 are input only - valid_system_gpios_ = string_range_to_vector("0-46", "6-11, 16-17, 45-46, 43-44"); + valid_system_gpios_ = string_range_to_vector("0-46", "3, 45-46, 6-11, 35"); #elif CONFIG_IDF_TARGET_ESP32S3 - // not valid: - // 43-44 are UART0 pins - // 19-20 are USB-JTAG pins - // 33-37 for Octal SPI (SPIIO4 through SPIIO7 and SPIDQS) on 32MB boards - // 3, 45-46 are strapping pins - // 26-32 are typically used for SPI flash and PSRAM - // 42 transitions low on reset, slower than other GPIOs which can cause issues in time-sensitive applications - // notes: - // 34-39 are input only, and can be used - // 47 and 48 are valid on a Wemos S3 (https://github.com/emsesp/EMS-ESP32/issues/2874) - valid_system_gpios_ = string_range_to_vector("0-48", "43-44, 19-20, 33-37, 3, 45-46, 26-32, 42"); -#elif CONFIG_IDF_TARGET_ESP32 - // not valid: + // non valid GPIOs: + // 3 is a strapping pin that could affect boot behaviour if pulled high/low at boot time // 6-11 are used for SPI flash and PSRAM - // 16-17 are also used for SPI flash and PSRAM - // 26-31 are used for SPI flash and PSRAM - // 19-20 are used for JTAG-USB - // 45-46 are strapping pins - // 1 & 3 are UART0 pins, but used for some eth-boards (BBQKees-E32, OlimexPOE) - // 42 transitions low on reset, slower than other GPIOs which can cause issues in time-sensitive applications - // notes: - // 32 is reserved for LED on E32V2_2 boards - // 34-39 are input only (ADC1), and can be used + // 19-20 are USB-JTAG pins + // 26-32 are usually used for SPI flash and PSRAM and not recommended for other use + // 33-37 are used for Octal SPI flash or PSRAM + // 45-46 are strapping pins that can affect boot behaviour + // notes on valid GPIOs: + // 11-20 are ADC analog input only pins + // 47 and 48 are valid on a Wemos S3 (https://github.com/emsesp/EMS-ESP32/issues/2874) + // 16 and 17 is UART2, which we allow + valid_system_gpios_ = string_range_to_vector("0-48", "3, 6-11, 19-20, 26-32, 33-37, 45-46"); +#elif CONFIG_IDF_TARGET_ESP32 + // non valid GPIOs: + // 2, 4, 12-15, 25-27 are ADC2 and can conflict with the Wi-Fi module (12-15 is also USB-JTAG) + // 6-11 and 16-17 are used for SPI flash and PSRAM + // notes on valid GPIOs: // 25-26 are DAC (Digital-to-Analog Converter) pins, and can be used - // 36 & 39 are reserved for the internal supply_voltage and core_voltage + // 34-39 are input only, and can't be used for output (36=internal supply_voltage, 39=internal core_voltage on a BBQKees E32V2.2) if (ESP.getPsramSize() > 0) { - // if psram is enabled remove pins 16 and 17 from the list - valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 26-31, 19-20, 45-46, 1, 3, 42"); + valid_system_gpios_ = string_range_to_vector("0-39", "2, 4, 12-15, 25-27, 6-11, 16-17"); // remove PSRAM pins from the list } else { - valid_system_gpios_ = string_range_to_vector("0-39", "19-20, 45-46, 1, 3, 42"); + valid_system_gpios_ = string_range_to_vector("0-39", "2, 4, 12-15, 25-27"); } #elif defined(EMSESP_STANDALONE) valid_system_gpios_ = string_range_to_vector("0-39"); From da76fe38719f57f4f6907cc92a06b8f25c19eeae Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 21:51:57 +0100 Subject: [PATCH 17/42] asyncTCP change --- lib/eModbus/src/ModbusClientTCPasync.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eModbus/src/ModbusClientTCPasync.cpp b/lib/eModbus/src/ModbusClientTCPasync.cpp index 949de2c49..cebdd7a30 100644 --- a/lib/eModbus/src/ModbusClientTCPasync.cpp +++ b/lib/eModbus/src/ModbusClientTCPasync.cpp @@ -52,7 +52,7 @@ ModbusClientTCPasync::~ModbusClientTCPasync() { } } // force close client - MTA_client.close(true); + MTA_client.close(); } // optionally manually connect to modbus server. Otherwise connection will be made upon first request @@ -79,7 +79,7 @@ void ModbusClientTCPasync::connect(IPAddress host, uint16_t port) { // manually disconnect from modbus server. Connection will also auto close after idle time void ModbusClientTCPasync::disconnect(bool force) { LOG_D("disconnecting\n"); - MTA_client.close(force); + MTA_client.close(); } // Set timeout value From 53a43ca147f38ed67b6cc9ea4d9dcba62f10f12b Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 4 Jan 2026 21:56:37 +0100 Subject: [PATCH 18/42] update gpio to not conflict with board profile --- src/core/system.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index d7f71e707..c48bb9774 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2888,12 +2888,13 @@ void System::set_valid_system_gpios() { // get free gpios based on board/platform type #if CONFIG_IDF_TARGET_ESP32C3 // non valid GPIOs: - // 3, 9-10 are strapping pins that can affect boot behaviour + // 3 and 10 are strapping pins that can affect boot behaviour // 8 is connected to the internal ULP (Ultra Low Power) coprocessor and should be avoided for external connections // 11 is used for internal flash connection // notes on valid GPIOs: // there are no input only pins on a C3 - valid_system_gpios_ = string_range_to_vector("0-21", "3, 9-10, 8, 11"); + // 9 is used as the button on BOARD_C3_MINI_V1 + valid_system_gpios_ = string_range_to_vector("0-21", "3, 10, 8, 11"); #elif CONFIG_IDF_TARGET_ESP32S2 // non valid GPIOs: // 3, 45-46 are strapping pins that can affect boot behaviour @@ -2904,7 +2905,7 @@ void System::set_valid_system_gpios() { #elif CONFIG_IDF_TARGET_ESP32S3 // non valid GPIOs: // 3 is a strapping pin that could affect boot behaviour if pulled high/low at boot time - // 6-11 are used for SPI flash and PSRAM + // 6-7, 9-11 are used for SPI flash and PSRAM (we allow 8) // 19-20 are USB-JTAG pins // 26-32 are usually used for SPI flash and PSRAM and not recommended for other use // 33-37 are used for Octal SPI flash or PSRAM @@ -2913,18 +2914,20 @@ void System::set_valid_system_gpios() { // 11-20 are ADC analog input only pins // 47 and 48 are valid on a Wemos S3 (https://github.com/emsesp/EMS-ESP32/issues/2874) // 16 and 17 is UART2, which we allow - valid_system_gpios_ = string_range_to_vector("0-48", "3, 6-11, 19-20, 26-32, 33-37, 45-46"); + // Liligo S3 profile uses 8 for Rx + valid_system_gpios_ = string_range_to_vector("0-48", "3, 6-7, 9-11, 19-20, 26-32, 33-37, 45-46"); #elif CONFIG_IDF_TARGET_ESP32 // non valid GPIOs: - // 2, 4, 12-15, 25-27 are ADC2 and can conflict with the Wi-Fi module (12-15 is also USB-JTAG) + // 12-13, 15, 25-27 are ADC2 and can conflict with the Wi-Fi module (12-15 is also USB-JTAG) // 6-11 and 16-17 are used for SPI flash and PSRAM // notes on valid GPIOs: + // 2, 4, 14 are used on BBQKees boards for the LED, Dallas and/or Rx // 25-26 are DAC (Digital-to-Analog Converter) pins, and can be used // 34-39 are input only, and can't be used for output (36=internal supply_voltage, 39=internal core_voltage on a BBQKees E32V2.2) if (ESP.getPsramSize() > 0) { - valid_system_gpios_ = string_range_to_vector("0-39", "2, 4, 12-15, 25-27, 6-11, 16-17"); // remove PSRAM pins from the list + valid_system_gpios_ = string_range_to_vector("0-39", "12-13, 15, 25-27, 6-11, 16-17"); // remove PSRAM pins from the list } else { - valid_system_gpios_ = string_range_to_vector("0-39", "2, 4, 12-15, 25-27"); + valid_system_gpios_ = string_range_to_vector("0-39", "12-13, 15, 25-27"); } #elif defined(EMSESP_STANDALONE) valid_system_gpios_ = string_range_to_vector("0-39"); From aa6f5c50b2decdd5d04b1f85be9be37a9d0b146f Mon Sep 17 00:00:00 2001 From: g6094199 <37833326+g6094199@users.noreply.github.com> Date: Mon, 5 Jan 2026 09:03:12 +0100 Subject: [PATCH 19/42] Update mqtt.cpp: use the same nomenclature as Tasmota and OpenBK uses for Homeassistant to be compliant to the HA typical nomenclatura use the same wording. since we are anyway connecting via wifi or ethernet the wording of "WIFI rssi" is redundant. just use "RSSI" as other platforms do. --- src/core/mqtt.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index 71f4e38de..e1e664d71 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -562,8 +562,8 @@ void Mqtt::ha_status() { // Note we don't use camelCase as it would change the HA entity_id and impact historic data #ifndef EMSESP_STANDALONE if (!EMSESP::system_.ethernet_connected() || WiFi.isConnected()) { - publish_system_ha_sensor_config(DeviceValueType::INT8, "WiFi RSSI", "rssi", DeviceValueUOM::DBM); - publish_system_ha_sensor_config(DeviceValueType::INT8, "WiFi strength", "wifistrength", DeviceValueUOM::PERCENT); + publish_system_ha_sensor_config(DeviceValueType::INT8, "RSSI", "rssi", DeviceValueUOM::DBM); + publish_system_ha_sensor_config(DeviceValueType::INT8, "Signal", "wifistrength", DeviceValueUOM::PERCENT); } #endif @@ -1628,4 +1628,4 @@ void Mqtt::add_value_bool(JsonObject doc, const char * name, bool value) { } } -} // namespace emsesp \ No newline at end of file +} // namespace emsesp From 18a55d46226a3a0181eac6af412a53fd09d0e61d Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 13:31:27 +0100 Subject: [PATCH 20/42] more gpio pin updates --- src/core/system.cpp | 87 ++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index c48bb9774..4da165a79 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2880,54 +2880,67 @@ std::vector> System::string_range_to_vector(con // initialize a list of valid GPIOs based on the ESP32 board // string_to_vector() take two strings, the first is the range of GPIOs to use, the second is a list of GPIOs to exclude -// note: we always allow 0, which is used to indicate Dallas or LED is disabled +// notes: +// we always allow 0 (which is usually a strapping pin), because it's used to indicate whether EMS-ESP Dallas or the LED is disabled +// we allow UART0, 1 and 2 as they are configurable +// strapping pins are disabled as they can affect boot behaviour +// we accept GPIOs that are fixed on BBQKees boards +// void System::set_valid_system_gpios() { valid_system_gpios_.clear(); // reset system list used_gpios_.clear(); // reset used list // get free gpios based on board/platform type #if CONFIG_IDF_TARGET_ESP32C3 - // non valid GPIOs: - // 3 and 10 are strapping pins that can affect boot behaviour - // 8 is connected to the internal ULP (Ultra Low Power) coprocessor and should be avoided for external connections - // 11 is used for internal flash connection - // notes on valid GPIOs: - // there are no input only pins on a C3 - // 9 is used as the button on BOARD_C3_MINI_V1 - valid_system_gpios_ = string_range_to_vector("0-21", "3, 10, 8, 11"); + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32c3/api-reference/peripherals/gpio.html + // GPIO2, GPIO8 - GPIO9 = strapping pins + // GPIO12 - GPIO17 = used for SPI flash and PSRAM + // GPIO18 - GPIO19 = USB-JTAG + // + // notes on what is allowed: + // GPIO10 = button on BOARD_C3_MINI_V1 + valid_system_gpios_ = string_range_to_vector("0-21", "2, 8-9, 12-17, 18-19"); + #elif CONFIG_IDF_TARGET_ESP32S2 - // non valid GPIOs: - // 3, 45-46 are strapping pins that can affect boot behaviour - // 6-11 and 35 are used for SPI flash and PSRAM - // notes on valid GPIOs: - // 34-39 are input only - valid_system_gpios_ = string_range_to_vector("0-46", "3, 45-46, 6-11, 35"); + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-reference/peripherals/gpio.html + // GPIO26 - GPIO32 = SPI flash and PSRAM + // GPIO45 - GPIO46 = strapping pins + // GPIO39 - GPIO42 = USB-JTAG + // + // notes on what is allowed: + valid_system_gpios_ = string_range_to_vector("0-46", "26-32, 45-46, 39-42"); + #elif CONFIG_IDF_TARGET_ESP32S3 - // non valid GPIOs: - // 3 is a strapping pin that could affect boot behaviour if pulled high/low at boot time - // 6-7, 9-11 are used for SPI flash and PSRAM (we allow 8) - // 19-20 are USB-JTAG pins - // 26-32 are usually used for SPI flash and PSRAM and not recommended for other use - // 33-37 are used for Octal SPI flash or PSRAM - // 45-46 are strapping pins that can affect boot behaviour - // notes on valid GPIOs: - // 11-20 are ADC analog input only pins - // 47 and 48 are valid on a Wemos S3 (https://github.com/emsesp/EMS-ESP32/issues/2874) - // 16 and 17 is UART2, which we allow - // Liligo S3 profile uses 8 for Rx - valid_system_gpios_ = string_range_to_vector("0-48", "3, 6-7, 9-11, 19-20, 26-32, 33-37, 45-46"); + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html + // GPIO3, GPIO45 - GPIO46 = strapping pins + // GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended + // GPIO33 - GPIO37 = Octal flash/PSRAM + // GPIO19 - GPIO20 = USB-JTAG + // + // notes on what is allowed: + // GPIO11 - GPIO19 = ADC analog input only pins + // GPIO47 - GPIO48 = valid on a Wemos S3 + // GPIO8 = used by Liligo S3 board profile for Rx + valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20"); + #elif CONFIG_IDF_TARGET_ESP32 - // non valid GPIOs: - // 12-13, 15, 25-27 are ADC2 and can conflict with the Wi-Fi module (12-15 is also USB-JTAG) - // 6-11 and 16-17 are used for SPI flash and PSRAM - // notes on valid GPIOs: - // 2, 4, 14 are used on BBQKees boards for the LED, Dallas and/or Rx - // 25-26 are DAC (Digital-to-Analog Converter) pins, and can be used - // 34-39 are input only, and can't be used for output (36=internal supply_voltage, 39=internal core_voltage on a BBQKees E32V2.2) + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html + // GPIO5 = strapping pins + // GPIO6 - GPIO11, GPIO16 - GPIO17 = used for SPI flash and PSRAM + // GPIO12 - GPIO15 = USB-JTAG (12 and 15 are also strapping pins) but we allow GPIO14 (see below) + // + // notes on what is allowed: + // GPIO34, GPIO35, GPIO37 = input only + // GPIO2, GPIO4, GPIO14 = used on BBQKees boards for either LED, Dallas or Rx + // GPIO25 - GPIO37 = ADC2 + // GPIO32 - GPIO39 = ADC1 + // GPIO36 = used on BBQKees boards for supply_voltage (E32V2.2) (note may conflict with WiFI on other boards) + // GPIO39 = used on BBQKees boards for core_voltage (E32V2.2) (note may conflict with WiFI on other boards) if (ESP.getPsramSize() > 0) { - valid_system_gpios_ = string_range_to_vector("0-39", "12-13, 15, 25-27, 6-11, 16-17"); // remove PSRAM pins from the list + // remove PSRAM pins from the list + valid_system_gpios_ = string_range_to_vector("0-39", "5, 6-11, 16-17, 12, 13, 15"); } else { - valid_system_gpios_ = string_range_to_vector("0-39", "12-13, 15, 25-27"); + valid_system_gpios_ = string_range_to_vector("0-39", "5, 12, 13, 15"); } #elif defined(EMSESP_STANDALONE) valid_system_gpios_ = string_range_to_vector("0-39"); From feeb8500ac478d1ed315a7ac7283d54f05a8a46a Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 13:34:10 +0100 Subject: [PATCH 21/42] #2896 --- boards/s2_4M_P.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/s2_4M_P.json b/boards/s2_4M_P.json index 349b065b1..3c313da37 100644 --- a/boards/s2_4M_P.json +++ b/boards/s2_4M_P.json @@ -37,8 +37,8 @@ "flash_size": "4MB", "maximum_ram_size": 327680, "maximum_size": 4194304, - "use_1200bps_touch": true, - "wait_for_upload_port": true, + "use_1200bps_touch": false, + "wait_for_upload_port": false, "require_upload_port": true, "speed": 921600 }, From 1cc4dc52d4c9d03cfd6218849521f7b359e6b7a1 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 20:12:12 +0100 Subject: [PATCH 22/42] package update --- interface/package.json | 2 +- interface/pnpm-lock.yaml | 345 +++++++++++++++++++++------------------ 2 files changed, 187 insertions(+), 160 deletions(-) diff --git a/interface/package.json b/interface/package.json index 34670860e..f2a69f90c 100644 --- a/interface/package.json +++ b/interface/package.json @@ -62,7 +62,7 @@ "prettier": "^3.7.4", "rollup-plugin-visualizer": "^6.0.5", "terser": "^5.44.1", - "typescript-eslint": "^8.51.0", + "typescript-eslint": "^8.52.0", "vite": "^7.3.0", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^6.0.3" diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 839a6879f..74c710e8a 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -113,13 +113,13 @@ importers: version: 3.7.4 rollup-plugin-visualizer: specifier: ^6.0.5 - version: 6.0.5(rollup@4.54.0) + version: 6.0.5(rollup@4.55.1) terser: specifier: ^5.44.1 version: 5.44.1 typescript-eslint: - specifier: ^8.51.0 - version: 8.51.0(eslint@9.39.2)(typescript@5.9.3) + specifier: ^8.52.0 + version: 8.52.0(eslint@9.39.2)(typescript@5.9.3) vite: specifier: ^7.3.0 version: 7.3.0(@types/node@25.0.3)(terser@5.44.1) @@ -679,113 +679,128 @@ packages: resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} - '@rollup/rollup-android-arm-eabi@4.54.0': - resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} + '@rollup/rollup-android-arm-eabi@4.55.1': + resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.54.0': - resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} + '@rollup/rollup-android-arm64@4.55.1': + resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.54.0': - resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} + '@rollup/rollup-darwin-arm64@4.55.1': + resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.54.0': - resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} + '@rollup/rollup-darwin-x64@4.55.1': + resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.54.0': - resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} + '@rollup/rollup-freebsd-arm64@4.55.1': + resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.54.0': - resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} + '@rollup/rollup-freebsd-x64@4.55.1': + resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.54.0': - resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.54.0': - resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.54.0': - resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} + '@rollup/rollup-linux-arm64-gnu@4.55.1': + resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.54.0': - resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} + '@rollup/rollup-linux-arm64-musl@4.55.1': + resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.54.0': - resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} + '@rollup/rollup-linux-loong64-gnu@4.55.1': + resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.54.0': - resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} + '@rollup/rollup-linux-loong64-musl@4.55.1': + resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.54.0': - resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} + '@rollup/rollup-linux-ppc64-musl@4.55.1': + resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.54.0': - resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} + '@rollup/rollup-linux-riscv64-musl@4.55.1': + resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.54.0': - resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} + '@rollup/rollup-linux-s390x-gnu@4.55.1': + resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.54.0': - resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} + '@rollup/rollup-linux-x64-gnu@4.55.1': + resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.54.0': - resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} + '@rollup/rollup-linux-x64-musl@4.55.1': + resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.54.0': - resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} + '@rollup/rollup-openbsd-x64@4.55.1': + resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.1': + resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.54.0': - resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} + '@rollup/rollup-win32-arm64-msvc@4.55.1': + resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.54.0': - resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} + '@rollup/rollup-win32-ia32-msvc@4.55.1': + resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.54.0': - resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} + '@rollup/rollup-win32-x64-gnu@4.55.1': + resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.54.0': - resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} + '@rollup/rollup-win32-x64-msvc@4.55.1': + resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} cpu: [x64] os: [win32] @@ -888,63 +903,63 @@ packages: '@types/svgo@2.6.4': resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} - '@typescript-eslint/eslint-plugin@8.51.0': - resolution: {integrity: sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==} + '@typescript-eslint/eslint-plugin@8.52.0': + resolution: {integrity: sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.51.0 + '@typescript-eslint/parser': ^8.52.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.51.0': - resolution: {integrity: sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==} + '@typescript-eslint/parser@8.52.0': + resolution: {integrity: sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.51.0': - resolution: {integrity: sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ==} + '@typescript-eslint/project-service@8.52.0': + resolution: {integrity: sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.51.0': - resolution: {integrity: sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA==} + '@typescript-eslint/scope-manager@8.52.0': + resolution: {integrity: sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.51.0': - resolution: {integrity: sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw==} + '@typescript-eslint/tsconfig-utils@8.52.0': + resolution: {integrity: sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.51.0': - resolution: {integrity: sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q==} + '@typescript-eslint/type-utils@8.52.0': + resolution: {integrity: sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.51.0': - resolution: {integrity: sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag==} + '@typescript-eslint/types@8.52.0': + resolution: {integrity: sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.51.0': - resolution: {integrity: sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng==} + '@typescript-eslint/typescript-estree@8.52.0': + resolution: {integrity: sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.51.0': - resolution: {integrity: sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA==} + '@typescript-eslint/utils@8.52.0': + resolution: {integrity: sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.51.0': - resolution: {integrity: sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg==} + '@typescript-eslint/visitor-keys@8.52.0': + resolution: {integrity: sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: @@ -2625,8 +2640,8 @@ packages: rollup: optional: true - rollup@4.54.0: - resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} + rollup@4.55.1: + resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2924,8 +2939,8 @@ packages: peerDependencies: typescript: '>=3.5.1' - typescript-eslint@8.51.0: - resolution: {integrity: sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA==} + typescript-eslint@8.52.0: + resolution: {integrity: sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -3636,70 +3651,79 @@ snapshots: estree-walker: 2.0.2 picomatch: 2.3.1 - '@rollup/rollup-android-arm-eabi@4.54.0': + '@rollup/rollup-android-arm-eabi@4.55.1': optional: true - '@rollup/rollup-android-arm64@4.54.0': + '@rollup/rollup-android-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-arm64@4.54.0': + '@rollup/rollup-darwin-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-x64@4.54.0': + '@rollup/rollup-darwin-x64@4.55.1': optional: true - '@rollup/rollup-freebsd-arm64@4.54.0': + '@rollup/rollup-freebsd-arm64@4.55.1': optional: true - '@rollup/rollup-freebsd-x64@4.54.0': + '@rollup/rollup-freebsd-x64@4.55.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.54.0': + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.54.0': + '@rollup/rollup-linux-arm-musleabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.54.0': + '@rollup/rollup-linux-arm64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.54.0': + '@rollup/rollup-linux-arm64-musl@4.55.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.54.0': + '@rollup/rollup-linux-loong64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.54.0': + '@rollup/rollup-linux-loong64-musl@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.54.0': + '@rollup/rollup-linux-ppc64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.54.0': + '@rollup/rollup-linux-ppc64-musl@4.55.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.54.0': + '@rollup/rollup-linux-riscv64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.54.0': + '@rollup/rollup-linux-riscv64-musl@4.55.1': optional: true - '@rollup/rollup-linux-x64-musl@4.54.0': + '@rollup/rollup-linux-s390x-gnu@4.55.1': optional: true - '@rollup/rollup-openharmony-arm64@4.54.0': + '@rollup/rollup-linux-x64-gnu@4.55.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.54.0': + '@rollup/rollup-linux-x64-musl@4.55.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.54.0': + '@rollup/rollup-openbsd-x64@4.55.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.54.0': + '@rollup/rollup-openharmony-arm64@4.55.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.54.0': + '@rollup/rollup-win32-arm64-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.55.1': optional: true '@sindresorhus/is@0.7.0': {} @@ -3803,14 +3827,14 @@ snapshots: dependencies: '@types/node': 25.0.3 - '@typescript-eslint/eslint-plugin@8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.51.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.51.0 - '@typescript-eslint/type-utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.51.0 + '@typescript-eslint/parser': 8.52.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.52.0 + '@typescript-eslint/type-utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.52.0 eslint: 9.39.2 ignore: 7.0.5 natural-compare: 1.4.0 @@ -3819,41 +3843,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.51.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.51.0 - '@typescript-eslint/types': 8.51.0 - '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.51.0 + '@typescript-eslint/scope-manager': 8.52.0 + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.52.0 debug: 4.4.3 eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.51.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.52.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.51.0(typescript@5.9.3) - '@typescript-eslint/types': 8.51.0 + '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3) + '@typescript-eslint/types': 8.52.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.51.0': + '@typescript-eslint/scope-manager@8.52.0': dependencies: - '@typescript-eslint/types': 8.51.0 - '@typescript-eslint/visitor-keys': 8.51.0 + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/visitor-keys': 8.52.0 - '@typescript-eslint/tsconfig-utils@8.51.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.52.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.51.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.52.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.51.0 - '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -3861,14 +3885,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.51.0': {} + '@typescript-eslint/types@8.52.0': {} - '@typescript-eslint/typescript-estree@8.51.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.52.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.51.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.51.0(typescript@5.9.3) - '@typescript-eslint/types': 8.51.0 - '@typescript-eslint/visitor-keys': 8.51.0 + '@typescript-eslint/project-service': 8.52.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3) + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/visitor-keys': 8.52.0 debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.3 @@ -3878,20 +3902,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.51.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/utils@8.52.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) - '@typescript-eslint/scope-manager': 8.51.0 - '@typescript-eslint/types': 8.51.0 - '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.52.0 + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.51.0': + '@typescript-eslint/visitor-keys@8.52.0': dependencies: - '@typescript-eslint/types': 8.51.0 + '@typescript-eslint/types': 8.52.0 eslint-visitor-keys: 4.2.1 acorn-jsx@5.3.2(acorn@8.15.0): @@ -5614,41 +5638,44 @@ snapshots: dependencies: glob: 7.2.3 - rollup-plugin-visualizer@6.0.5(rollup@4.54.0): + rollup-plugin-visualizer@6.0.5(rollup@4.55.1): dependencies: open: 8.4.2 picomatch: 4.0.3 source-map: 0.7.6 yargs: 17.7.2 optionalDependencies: - rollup: 4.54.0 + rollup: 4.55.1 - rollup@4.54.0: + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.54.0 - '@rollup/rollup-android-arm64': 4.54.0 - '@rollup/rollup-darwin-arm64': 4.54.0 - '@rollup/rollup-darwin-x64': 4.54.0 - '@rollup/rollup-freebsd-arm64': 4.54.0 - '@rollup/rollup-freebsd-x64': 4.54.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.54.0 - '@rollup/rollup-linux-arm-musleabihf': 4.54.0 - '@rollup/rollup-linux-arm64-gnu': 4.54.0 - '@rollup/rollup-linux-arm64-musl': 4.54.0 - '@rollup/rollup-linux-loong64-gnu': 4.54.0 - '@rollup/rollup-linux-ppc64-gnu': 4.54.0 - '@rollup/rollup-linux-riscv64-gnu': 4.54.0 - '@rollup/rollup-linux-riscv64-musl': 4.54.0 - '@rollup/rollup-linux-s390x-gnu': 4.54.0 - '@rollup/rollup-linux-x64-gnu': 4.54.0 - '@rollup/rollup-linux-x64-musl': 4.54.0 - '@rollup/rollup-openharmony-arm64': 4.54.0 - '@rollup/rollup-win32-arm64-msvc': 4.54.0 - '@rollup/rollup-win32-ia32-msvc': 4.54.0 - '@rollup/rollup-win32-x64-gnu': 4.54.0 - '@rollup/rollup-win32-x64-msvc': 4.54.0 + '@rollup/rollup-android-arm-eabi': 4.55.1 + '@rollup/rollup-android-arm64': 4.55.1 + '@rollup/rollup-darwin-arm64': 4.55.1 + '@rollup/rollup-darwin-x64': 4.55.1 + '@rollup/rollup-freebsd-arm64': 4.55.1 + '@rollup/rollup-freebsd-x64': 4.55.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 + '@rollup/rollup-linux-arm-musleabihf': 4.55.1 + '@rollup/rollup-linux-arm64-gnu': 4.55.1 + '@rollup/rollup-linux-arm64-musl': 4.55.1 + '@rollup/rollup-linux-loong64-gnu': 4.55.1 + '@rollup/rollup-linux-loong64-musl': 4.55.1 + '@rollup/rollup-linux-ppc64-gnu': 4.55.1 + '@rollup/rollup-linux-ppc64-musl': 4.55.1 + '@rollup/rollup-linux-riscv64-gnu': 4.55.1 + '@rollup/rollup-linux-riscv64-musl': 4.55.1 + '@rollup/rollup-linux-s390x-gnu': 4.55.1 + '@rollup/rollup-linux-x64-gnu': 4.55.1 + '@rollup/rollup-linux-x64-musl': 4.55.1 + '@rollup/rollup-openbsd-x64': 4.55.1 + '@rollup/rollup-openharmony-arm64': 4.55.1 + '@rollup/rollup-win32-arm64-msvc': 4.55.1 + '@rollup/rollup-win32-ia32-msvc': 4.55.1 + '@rollup/rollup-win32-x64-gnu': 4.55.1 + '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 run-parallel@1.2.0: @@ -5912,12 +5939,12 @@ snapshots: dependencies: typescript: 5.9.3 - typescript-eslint@8.51.0(eslint@9.39.2)(typescript@5.9.3): + typescript-eslint@8.52.0(eslint@9.39.2)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/parser': 8.51.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.51.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/parser': 8.52.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.52.0(eslint@9.39.2)(typescript@5.9.3) eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: @@ -6019,7 +6046,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.54.0 + rollup: 4.55.1 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 25.0.3 From def7501c624708e769ccce11f7101c8fbd9e5e9f Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 20:12:21 +0100 Subject: [PATCH 23/42] dictionary update --- cspell.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cspell.json b/cspell.json index 24df974df..880eedb9c 100644 --- a/cspell.json +++ b/cspell.json @@ -35,6 +35,7 @@ "managed_components/**", "pnpm-*.yaml", "vite.config.ts", - "lib/esp32-psram/**" + "lib/esp32-psram/**", + "test/test_api/test_api.h" ] } \ No newline at end of file From 664a8e9f5f847eea559fc3743ad2a37661db2566 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:26:58 +0100 Subject: [PATCH 24/42] remove defaults --- Makefile | 2 +- platformio.ini | 4 ++-- src/core/default_settings.h | 4 ---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index fdab1d661..c1ca05b90 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSO DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500 DEFINES += $(ARGS) -DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\" +DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\" #---------------------------------------------------------------------- # Sources & Files diff --git a/platformio.ini b/platformio.ini index 2495f1022..31ac85d60 100644 --- a/platformio.ini +++ b/platformio.ini @@ -228,7 +228,7 @@ build_src_flags = -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_UNITY -DARDUINOJSON_ENABLE_ARDUINO_STRING=1 - -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" + -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" -std=gnu++17 -Og -ggdb -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces @@ -284,7 +284,7 @@ build_flags = [env:standalone] extends = env:native build_flags = - -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" + -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" ; Modbus ; Creates the file modbus_entity_parameters.hpp diff --git a/src/core/default_settings.h b/src/core/default_settings.h index d8187b701..6ef742329 100644 --- a/src/core/default_settings.h +++ b/src/core/default_settings.h @@ -25,10 +25,6 @@ #define EMSESP_DEFAULT_LOCALE EMSESP_LOCALE_EN // English #endif -#ifndef EMSESP_DEFAULT_VERSION -#define EMSESP_DEFAULT_VERSION "" -#endif - #ifndef EMSESP_DEFAULT_TX_MODE #define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0 #endif From 81d46fede2521e58f58048d5053c517538ce29d5 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:34:32 +0100 Subject: [PATCH 25/42] check for USB uploads and set 'fresh' flag --- lib_standalone/Arduino.h | 4 ++++ src/core/emsesp.cpp | 23 ++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib_standalone/Arduino.h b/lib_standalone/Arduino.h index 1ac2aea3b..d13411c24 100644 --- a/lib_standalone/Arduino.h +++ b/lib_standalone/Arduino.h @@ -76,6 +76,10 @@ void ledcWrite(uint8_t chan, uint32_t duty); void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); +inline int rtc_get_reset_reason(int cpu_no) { + return 0; +} + #define PROGMEM #define PGM_P const char * diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index f74c9d32e..faa88331d 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -20,6 +20,7 @@ #ifndef EMSESP_STANDALONE #include "esp_ota_ops.h" +#include "rom/rtc.h" #endif static_assert(uuid::thread_safe, "uuid-common must be thread-safe"); @@ -1721,15 +1722,31 @@ void EMSESP::start() { LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION); #endif + LOG_DEBUG("System is running in Debug mode"); + // check if the firmware is fresh, i.e. a new install or a new version has been uploaded // this is set in UploadFileService::uploadComplete() // and reset in System::set_partition_install_date() - if (!EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) { - LOG_DEBUG("Firmware is fresh install"); + if (EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) { + LOG_DEBUG("Firmware is a new install"); + } else { +// check if the firmware has been uploaded via Serial/USB +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + if (rtc_get_reset_reason(0) == 11) { // ESP_RST_USB (Reset by USB peripheral, on CPU 0 only +#else + if ((rtc_get_reset_reason(0) == 14 || rtc_get_reset_reason(1) == 14)) { // APP CPU reset by PRO CPU, can be either CPUs +#endif + LOG_DEBUG("Firmware is a new install, uploaded via Serial/USB"); + EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true); // set flag so it's picked up later to set the install date + } } - LOG_DEBUG("System is running in Debug mode"); +// S2 are C3 are both single core +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + LOG_INFO("Last system reset reason Core0: %s", system_.reset_reason(0).c_str()); +#else LOG_INFO("Last system reset reason Core0: %s, Core1: %s", system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str()); +#endif // see if we're restoring a settings file #ifndef EMSESP_STANDALONE From 9be1cb1d3eadc132a43a464a7fd02f1b3108b00f Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:34:50 +0100 Subject: [PATCH 26/42] always set fresh flag --- src/core/system.cpp | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 4da165a79..45101dbee 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -316,11 +316,9 @@ void System::get_partition_info() { auto current_partition = (const char *)esp_ota_get_running_partition()->label; - // update the current version and partition name in NVS if not already set (saves on flash wearing) - if (EMSESP::nvs_.getString(current_partition) != EMSESP_APP_VERSION || emsesp::EMSESP::nvs_.getBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false)) { - if (EMSESP::nvs_.getBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false)) { - EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false); - } + // update the current version and partition name in NVS if not already set + if (EMSESP::nvs_.getString(current_partition) != EMSESP_APP_VERSION || emsesp::EMSESP::nvs_.getBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true)) { + EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, false); EMSESP::nvs_.putString(current_partition, EMSESP_APP_VERSION); char c[20]; snprintf(c, sizeof(c), "d_%s", current_partition); @@ -2464,15 +2462,15 @@ bool System::command_txpause(const char * value, const int8_t id) { // format command - factory reset, removing all config files bool System::command_format(const char * value, const int8_t id) { -#if !defined(EMSESP_STANDALONE) && !defined(EMSESP_DEBUG) - // don't really format the filesystem in debug or standalone mode +#if !defined(EMSESP_STANDALONE) && !defined(EMSESP_TEST) + // don't really format the filesystem in test or standalone mode if (LittleFS.format()) { LOG_INFO("Filesystem formatted successfully. All config files removed."); } else { LOG_ERROR("Format failed"); } #else - LOG_INFO("Format command not available in standalone or debug mode"); + LOG_ERROR("Format command not available in standalone or test mode"); #endif // restart will be handled by the main loop @@ -2569,21 +2567,6 @@ bool System::ntp_connected() { // see if its a BBQKees Gateway by checking the nvs values String System::getBBQKeesGatewayDetails(uint8_t detail) { #ifndef EMSESP_STANDALONE - /* - if (!EMSESP::nvs_.isKey("mfg")) { - return ""; - } - - // mfg can be either "BBQKees" or "BBQKees Electronics" - auto mfg = EMSESP::nvs_.getString("mfg"); - if (mfg) { - if (!mfg.startsWith("BBQKees")) { - return ""; - } - } - - return "BBQKees Gateway Model " + EMSESP::nvs_.getString("model") + " v" + EMSESP::nvs_.getString("hwrevision") + "/" + EMSESP::nvs_.getString("batch"); -*/ union { struct { uint32_t no : 4; @@ -2596,14 +2579,17 @@ String System::getBBQKeesGatewayDetails(uint8_t detail) { }; uint32_t reg; } gw; + for (uint8_t reg = 0; reg < 8; reg++) { gw.reg = esp_efuse_read_reg(EFUSE_BLK3, reg); if (reg == 7 || esp_efuse_read_reg(EFUSE_BLK3, reg + 1) == 0) break; } + const char * mfg[] = {"unknown", "BBQKees Electronics", "", "", "", "", "", ""}; const char * model[] = {"unknown", "S3", "E32V2", "E32V2.2", "S32", "E32", "", "", ""}; const char * board[] = {"CUSTOM", "S32S3", "E32V2", "E32V2_2", "S32", "E32", "", "", ""}; + switch (detail) { case FUSE_VALUE::MFG: return gw.mfg < 2 ? String(mfg[gw.mfg]) : "unknown"; @@ -2621,9 +2607,11 @@ String System::getBBQKeesGatewayDetails(uint8_t detail) { default: break; } + if (!gw.reg || gw.mfg > 1 || gw.model > 5) { return ""; } + return String(mfg[gw.mfg]) + " " + String(model[gw.model]) + " rev." + String(gw.rev_major) + "." + String(gw.rev_minor) + "/" + String(2000 + gw.year) + (gw.month < 10 ? "0" : "") + String(gw.month) + String(gw.no); #else @@ -2925,22 +2913,22 @@ void System::set_valid_system_gpios() { #elif CONFIG_IDF_TARGET_ESP32 // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html - // GPIO5 = strapping pins // GPIO6 - GPIO11, GPIO16 - GPIO17 = used for SPI flash and PSRAM // GPIO12 - GPIO15 = USB-JTAG (12 and 15 are also strapping pins) but we allow GPIO14 (see below) // // notes on what is allowed: // GPIO34, GPIO35, GPIO37 = input only - // GPIO2, GPIO4, GPIO14 = used on BBQKees boards for either LED, Dallas or Rx + // GPIO2, GPIO4, GPIO5, GPIO14 = used on BBQKees boards for either LED, Dallas or Rx + // GPIO23 and GPIO18 are used by Ethernet // GPIO25 - GPIO37 = ADC2 // GPIO32 - GPIO39 = ADC1 // GPIO36 = used on BBQKees boards for supply_voltage (E32V2.2) (note may conflict with WiFI on other boards) // GPIO39 = used on BBQKees boards for core_voltage (E32V2.2) (note may conflict with WiFI on other boards) if (ESP.getPsramSize() > 0) { // remove PSRAM pins from the list - valid_system_gpios_ = string_range_to_vector("0-39", "5, 6-11, 16-17, 12, 13, 15"); + valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 12, 13, 15"); } else { - valid_system_gpios_ = string_range_to_vector("0-39", "5, 12, 13, 15"); + valid_system_gpios_ = string_range_to_vector("0-39", "12, 13, 15"); } #elif defined(EMSESP_STANDALONE) valid_system_gpios_ = string_range_to_vector("0-39"); From 28ee0834d830ec794fe39e3f99f76dd9cbbf0942 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:35:03 +0100 Subject: [PATCH 27/42] don't log debug messages if nothing connected --- src/core/telegram.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/telegram.cpp b/src/core/telegram.cpp index 5d6b5d797..348f58c5c 100644 --- a/src/core/telegram.cpp +++ b/src/core/telegram.cpp @@ -221,14 +221,14 @@ void RxService::add(uint8_t * data, uint8_t length) { LOG_TRACE("Rx: %s", Helpers::data_to_hex(data, length).c_str()); } - LOG_DEBUG("New Rx telegram, message length %d", message_length); - - // if we don't have a type_id exit, - // do not exit on empty message, it is checked for toggle fetch + // if we don't have a type_id exit + // do not exit on empty message, it is checked later for toggle fetch if (type_id == 0) { return; } + LOG_DEBUG("New Rx telegram, message length %d", message_length); + // create the telegram auto telegram = std::make_shared(operation, src, dest, type_id, offset, message_data, message_length); From cff4bd0a712d47fe635d422d419234056f27688c Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:35:18 +0100 Subject: [PATCH 28/42] add debug statement --- src/ESP32React/FSPersistence.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ESP32React/FSPersistence.h b/src/ESP32React/FSPersistence.h index 299d943c2..d41e6b53d 100644 --- a/src/ESP32React/FSPersistence.h +++ b/src/ESP32React/FSPersistence.h @@ -70,6 +70,10 @@ class FSPersistence { // failed to open file, return false if (!settingsFile || !jsonObject.size()) { +#if defined(EMSESP_DEBUG) + Serial.printf("Failed to write file %s", _filePath); + Serial.println(); +#endif return false; } From bf5990a9926a79a2fc0d66a0146b232e8387bcad Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:35:39 +0100 Subject: [PATCH 29/42] fix setting default version --- src/web/WebSettingsService.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 3cd0aba47..fc2d4c3c6 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -96,9 +96,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { std::vector system_gpios; EMSESP::system_.make_snapshot_gpios(used_gpios, system_gpios); - reset_flags(); - - settings.version = root["version"] | EMSESP_DEFAULT_VERSION; // save the version, we use it later in System::check_upgrade() + settings.version = root["version"] | EMSESP_APP_VERSION; // save the version, we use it later in System::check_upgrade() settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE; // get current values that are related to the board profile @@ -113,6 +111,8 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { settings.eth_clock_mode = root["eth_clock_mode"]; settings.led_type = root["led_type"]; // 1 = RGB-LED + reset_flags(); + // see if the user has changed the board profile // this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type // this will always run when EMS-ESP starts since original_settings{} is empty @@ -307,6 +307,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { // save the settings if changed from the webUI // if we encountered an invalid GPIO, rollback changes and don't save settings, and report the error to WebUI + // without a restart if (!have_valid_gpios) { // replace settings with original settings settings = original_settings; @@ -320,7 +321,8 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { // save the setting internally, for reference later EMSESP::system_.store_settings(settings); - if (has_flags(WebSettings::ChangeFlags::RESTART)) { + // and finally always write to the settings file + if (has_flags(ChangeFlags::RESTART)) { return StateUpdateResult::CHANGED_RESTART; } From 33bde8b40718891fd17b710d1ac020d2333cf5c6 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:36:10 +0100 Subject: [PATCH 30/42] fix default version just to be sure --- src/web/WebSettingsService.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/WebSettingsService.h b/src/web/WebSettingsService.h index bc66f024c..91a01f2cc 100644 --- a/src/web/WebSettingsService.h +++ b/src/web/WebSettingsService.h @@ -30,7 +30,7 @@ namespace emsesp { class WebSettings { public: - String version; + String version = EMSESP_APP_VERSION; String locale; uint8_t tx_mode; uint8_t ems_bus_id; From db40d1d38117e7925e3ba5b1aa649ef96a98bad3 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:36:21 +0100 Subject: [PATCH 31/42] set default values, just to be sure --- src/ESP32React/APSettingsService.h | 10 +++++----- src/ESP32React/MqttSettingsService.h | 26 ++++++++++++------------- src/ESP32React/NTPSettingsService.h | 8 ++++---- src/ESP32React/NetworkSettingsService.h | 8 ++++---- src/ESP32React/SecurityManager.h | 1 - 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/ESP32React/APSettingsService.h b/src/ESP32React/APSettingsService.h index d895e94a3..fda384bc8 100644 --- a/src/ESP32React/APSettingsService.h +++ b/src/ESP32React/APSettingsService.h @@ -59,11 +59,11 @@ enum APNetworkStatus { ACTIVE = 0, INACTIVE, LINGERING }; class APSettings { public: uint8_t provisionMode = FACTORY_AP_PROVISION_MODE; // 0 = on, 2 = off - String ssid; - String password; - uint8_t channel = FACTORY_AP_CHANNEL; - bool ssidHidden = FACTORY_AP_SSID_HIDDEN; - uint8_t maxClients = FACTORY_AP_MAX_CLIENTS; + String ssid = FACTORY_AP_SSID; + String password = FACTORY_AP_PASSWORD; + uint8_t channel = FACTORY_AP_CHANNEL; + bool ssidHidden = FACTORY_AP_SSID_HIDDEN; + uint8_t maxClients = FACTORY_AP_MAX_CLIENTS; IPAddress localIP; IPAddress gatewayIP; diff --git a/src/ESP32React/MqttSettingsService.h b/src/ESP32React/MqttSettingsService.h index 4c3ad7c06..b31859201 100644 --- a/src/ESP32React/MqttSettingsService.h +++ b/src/ESP32React/MqttSettingsService.h @@ -66,19 +66,19 @@ class MqttSettings { public: - bool enabled = FACTORY_MQTT_ENABLED; - String host; - uint16_t port = FACTORY_MQTT_PORT; - String rootCA; + bool enabled = FACTORY_MQTT_ENABLED; + String host = FACTORY_MQTT_HOST; + uint16_t port = FACTORY_MQTT_PORT; + String rootCA = ""; bool enableTLS = false; - String username; - String password; + String username = FACTORY_MQTT_USERNAME; + String password = FACTORY_MQTT_PASSWORD; String clientId; uint16_t keepAlive = FACTORY_MQTT_KEEP_ALIVE; bool cleanSession = FACTORY_MQTT_CLEAN_SESSION; // EMS-ESP specific - String base; + String base = FACTORY_MQTT_BASE; uint16_t publish_time_boiler = EMSESP_DEFAULT_PUBLISH_TIME; uint16_t publish_time_thermostat = EMSESP_DEFAULT_PUBLISH_TIME; uint16_t publish_time_solar = EMSESP_DEFAULT_PUBLISH_TIME; @@ -91,12 +91,12 @@ class MqttSettings { bool mqtt_retain = EMSESP_DEFAULT_MQTT_RETAIN; bool ha_enabled = EMSESP_DEFAULT_HA_ENABLED; uint8_t nested_format = EMSESP_DEFAULT_NESTED_FORMAT; - String discovery_prefix; - uint8_t discovery_type = EMSESP_DEFAULT_DISCOVERY_TYPE; - bool publish_single = EMSESP_DEFAULT_PUBLISH_SINGLE; - bool publish_single2cmd = EMSESP_DEFAULT_PUBLISH_SINGLE2CMD; - bool send_response = EMSESP_DEFAULT_SEND_RESPONSE; - uint8_t entity_format = EMSESP_DEFAULT_ENTITY_FORMAT; + String discovery_prefix = EMSESP_DEFAULT_DISCOVERY_PREFIX; + uint8_t discovery_type = EMSESP_DEFAULT_DISCOVERY_TYPE; + bool publish_single = EMSESP_DEFAULT_PUBLISH_SINGLE; + bool publish_single2cmd = EMSESP_DEFAULT_PUBLISH_SINGLE2CMD; + bool send_response = EMSESP_DEFAULT_SEND_RESPONSE; + uint8_t entity_format = EMSESP_DEFAULT_ENTITY_FORMAT; static void read(MqttSettings & settings, JsonObject root); static StateUpdateResult update(JsonObject root, MqttSettings & settings); diff --git a/src/ESP32React/NTPSettingsService.h b/src/ESP32React/NTPSettingsService.h index cd55284d7..4b3bbce69 100644 --- a/src/ESP32React/NTPSettingsService.h +++ b/src/ESP32React/NTPSettingsService.h @@ -30,10 +30,10 @@ class NTPSettings { public: - bool enabled = FACTORY_NTP_ENABLED; - String tzLabel; - String tzFormat; - String server; + bool enabled = FACTORY_NTP_ENABLED; + String tzLabel = FACTORY_NTP_TIME_ZONE_LABEL; + String tzFormat = FACTORY_NTP_TIME_ZONE_FORMAT; + String server = FACTORY_NTP_SERVER; static void read(NTPSettings & settings, JsonObject root); static StateUpdateResult update(JsonObject root, NTPSettings & settings); diff --git a/src/ESP32React/NetworkSettingsService.h b/src/ESP32React/NetworkSettingsService.h index 80e27c695..f35186bf6 100644 --- a/src/ESP32React/NetworkSettingsService.h +++ b/src/ESP32React/NetworkSettingsService.h @@ -64,10 +64,10 @@ class NetworkSettings { public: // core wifi configuration - String ssid; - String bssid; - String password; - String hostname; + String ssid = FACTORY_WIFI_SSID; + String bssid = ""; + String password = FACTORY_WIFI_PASSWORD; + String hostname = FACTORY_WIFI_HOSTNAME; bool staticIPConfig = false; bool bandwidth20 = false; uint8_t tx_power = 0; diff --git a/src/ESP32React/SecurityManager.h b/src/ESP32React/SecurityManager.h index 247f21019..b4dc89bb8 100644 --- a/src/ESP32React/SecurityManager.h +++ b/src/ESP32React/SecurityManager.h @@ -9,7 +9,6 @@ #include #define ACCESS_TOKEN_PARAMATER "access_token" - #define AUTHORIZATION_HEADER "Authorization" #define AUTHORIZATION_HEADER_PREFIX "Bearer " #define AUTHORIZATION_HEADER_PREFIX_LEN 7 From 2fd6bed485c3be9dc2ef589cb1fce8623d8794bb Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 5 Jan 2026 21:37:40 +0100 Subject: [PATCH 32/42] update test --- test/test_api/test_api.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_api/test_api.h b/test/test_api/test_api.h index 23e5e8101..1696d48c9 100644 --- a/test/test_api/test_api.h +++ b/test/test_api/test_api.h @@ -231,7 +231,7 @@ void test_23() { "\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{" "\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0," "\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":" - "\"en\",\"txMode\":8,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," + "\"en\",\"txMode\":1,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," "\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true," "\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" "\"boiler\",\"name\":\"My Custom " @@ -262,7 +262,7 @@ void test_24() { "\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{" "\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0," "\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":" - "\"en\",\"txMode\":8,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," + "\"en\",\"txMode\":1,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," "\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true," "\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" "\"boiler\",\"name\":\"My Custom " @@ -332,7 +332,7 @@ void test_25() { "emsesp_bus_busrxlinequality busRxLineQuality\\n# TYPE emsesp_bus_busrxlinequality gauge\\nemsesp_bus_busrxlinequality 100\\n# HELP " "emsesp_bus_bustxlinequality busTxLineQuality\\n# TYPE emsesp_bus_bustxlinequality gauge\\nemsesp_bus_bustxlinequality 100\\n# HELP emsesp_bus_info " "info\\n# TYPE emsesp_bus_info gauge\\nemsesp_bus_info{busstatus=\\\"connected\\\", busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode " - "txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 8\\n# HELP emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid " + "txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 1\\n# HELP emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid " "gauge\\nemsesp_settings_emsbusid 11\\n# HELP emsesp_settings_showertimer showerTimer\\n# TYPE emsesp_settings_showertimer " "gauge\\nemsesp_settings_showertimer 0\\n# HELP emsesp_settings_showerminduration showerMinDuration\\n# TYPE emsesp_settings_showerminduration " "gauge\\nemsesp_settings_showerminduration 180\\n# HELP emsesp_settings_showeralert showerAlert\\n# TYPE emsesp_settings_showeralert " @@ -589,4 +589,4 @@ void run_tests() { RUN_TEST(test_57); } -// ---------- END - CUT HERE ---------- \ No newline at end of file +// ---------- END - CUT HERE ---------- From 4781eea66518f80ee2e62c26c62629df0dfcecd0 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 10:56:44 +0100 Subject: [PATCH 33/42] gpios --- src/core/system.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 45101dbee..35fb7af04 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2915,6 +2915,7 @@ void System::set_valid_system_gpios() { // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html // GPIO6 - GPIO11, GPIO16 - GPIO17 = used for SPI flash and PSRAM // GPIO12 - GPIO15 = USB-JTAG (12 and 15 are also strapping pins) but we allow GPIO14 (see below) + // GPIO20, GPIO24, GPIO28 - GPIO31 = don't exist // // notes on what is allowed: // GPIO34, GPIO35, GPIO37 = input only @@ -2925,10 +2926,10 @@ void System::set_valid_system_gpios() { // GPIO36 = used on BBQKees boards for supply_voltage (E32V2.2) (note may conflict with WiFI on other boards) // GPIO39 = used on BBQKees boards for core_voltage (E32V2.2) (note may conflict with WiFI on other boards) if (ESP.getPsramSize() > 0) { - // remove PSRAM pins from the list - valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 12, 13, 15"); + // remove SPI0/1 PSRAM pins GPIO16 (CS) and GPIO17 (CLK) from the list + valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 12, 13, 15, 20, 24, 28-31"); } else { - valid_system_gpios_ = string_range_to_vector("0-39", "12, 13, 15"); + valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 12, 13, 15, 20, 24, 28-31"); } #elif defined(EMSESP_STANDALONE) valid_system_gpios_ = string_range_to_vector("0-39"); From 696141721a20460c5e654be05953797f8d780878 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 11:57:21 +0100 Subject: [PATCH 34/42] updated with BBQKees pins --- src/core/system.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 35fb7af04..8ea733485 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2881,6 +2881,7 @@ void System::set_valid_system_gpios() { // get free gpios based on board/platform type #if CONFIG_IDF_TARGET_ESP32C3 // https://docs.espressif.com/projects/esp-idf/en/stable/esp32c3/api-reference/peripherals/gpio.html + // excluded: // GPIO2, GPIO8 - GPIO9 = strapping pins // GPIO12 - GPIO17 = used for SPI flash and PSRAM // GPIO18 - GPIO19 = USB-JTAG @@ -2891,6 +2892,7 @@ void System::set_valid_system_gpios() { #elif CONFIG_IDF_TARGET_ESP32S2 // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-reference/peripherals/gpio.html + // excluded: // GPIO26 - GPIO32 = SPI flash and PSRAM // GPIO45 - GPIO46 = strapping pins // GPIO39 - GPIO42 = USB-JTAG @@ -2900,6 +2902,7 @@ void System::set_valid_system_gpios() { #elif CONFIG_IDF_TARGET_ESP32S3 // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html + // excluded: // GPIO3, GPIO45 - GPIO46 = strapping pins // GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended // GPIO33 - GPIO37 = Octal flash/PSRAM @@ -2913,8 +2916,9 @@ void System::set_valid_system_gpios() { #elif CONFIG_IDF_TARGET_ESP32 // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html + // excluded: // GPIO6 - GPIO11, GPIO16 - GPIO17 = used for SPI flash and PSRAM - // GPIO12 - GPIO15 = USB-JTAG (12 and 15 are also strapping pins) but we allow GPIO14 (see below) + // GPIO12 - GPIO15 = USB-JTAG (but we allow GPIO14 for BBQKees) and GPIO12 & GPIO13 also reserved for BBQKees E32V2.2 // GPIO20, GPIO24, GPIO28 - GPIO31 = don't exist // // notes on what is allowed: @@ -2927,7 +2931,7 @@ void System::set_valid_system_gpios() { // GPIO39 = used on BBQKees boards for core_voltage (E32V2.2) (note may conflict with WiFI on other boards) if (ESP.getPsramSize() > 0) { // remove SPI0/1 PSRAM pins GPIO16 (CS) and GPIO17 (CLK) from the list - valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 16-17, 12, 13, 15, 20, 24, 28-31"); + valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 12, 13, 15, 16, 17, 20, 24, 28-31"); } else { valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 12, 13, 15, 20, 24, 28-31"); } From bcc7687b1b4904474fa88982acd82278fef64b6e Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 21:01:26 +0100 Subject: [PATCH 35/42] pins 22-25 don't exist on S2+S3 --- src/core/system.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 8ea733485..98cb63771 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1497,7 +1497,15 @@ bool System::check_upgrade() { }); } else if (this_version < settings_version) { // downgrading - LOG_NOTICE("Downgrading to version %d.%d.%d%s", this_version.major(), this_version.minor(), this_version.patch(), this_version_type.c_str()); + LOG_NOTICE("Downgrading from version %d.%d.%d%s to version %d.%d.%d%s", + settings_version.major(), + settings_version.minor(), + settings_version.patch(), + settings_version_type.c_str(), + this_version.major(), + this_version.minor(), + this_version.patch(), + this_version_type.c_str()); } else { save_version = false; // same version, do nothing } @@ -2896,9 +2904,10 @@ void System::set_valid_system_gpios() { // GPIO26 - GPIO32 = SPI flash and PSRAM // GPIO45 - GPIO46 = strapping pins // GPIO39 - GPIO42 = USB-JTAG + // GPIO22 - GPIO25 = don't exist // // notes on what is allowed: - valid_system_gpios_ = string_range_to_vector("0-46", "26-32, 45-46, 39-42"); + valid_system_gpios_ = string_range_to_vector("0-46", "26-32, 45-46, 39-42, 22-25"); #elif CONFIG_IDF_TARGET_ESP32S3 // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html @@ -2907,12 +2916,13 @@ void System::set_valid_system_gpios() { // GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended // GPIO33 - GPIO37 = Octal flash/PSRAM // GPIO19 - GPIO20 = USB-JTAG + // GPIO22 - GPIO25 = don't exist // // notes on what is allowed: // GPIO11 - GPIO19 = ADC analog input only pins // GPIO47 - GPIO48 = valid on a Wemos S3 // GPIO8 = used by Liligo S3 board profile for Rx - valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20"); + valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20, 22-25"); #elif CONFIG_IDF_TARGET_ESP32 // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html From 3a74abb4dbe19c73f629caa6c183894f1c047f08 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 22:03:53 +0100 Subject: [PATCH 36/42] fix blue dots appearing when transitioning --- interface/src/components/layout/LayoutMenuItem.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/components/layout/LayoutMenuItem.tsx b/interface/src/components/layout/LayoutMenuItem.tsx index b19652cca..a0dbc8354 100644 --- a/interface/src/components/layout/LayoutMenuItem.tsx +++ b/interface/src/components/layout/LayoutMenuItem.tsx @@ -39,9 +39,8 @@ const LayoutMenuItemComponent = ({ left: 0, top: 0, bottom: 0, - width: selected ? '4px' : '0px', + width: selected ? '3px' : '0px', backgroundColor: '#90caf9', - borderRadius: '0 2px 2px 0', transition: 'width 0.05s cubic-bezier(0.55, 0.085, 0.68, 0.53)' } }), From 35a8db4581bce4d9c6d8144d8b82ed49c6d5a9c6 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 22:04:15 +0100 Subject: [PATCH 37/42] fix missing progress bar on WebUI upload --- src/core/system.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 98cb63771..12faa3af8 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2696,6 +2696,9 @@ bool System::uploadFirmwareURL(const char * url) { // we're about to start the upload, set the status so the Web System Monitor spots it EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING); + // set a callback so we can monitor progress in the WebUI + Update.onProgress([](size_t progress, size_t total) { EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING + (progress * 100 / total)); }); + // get tcp stream and send it to Updater WiFiClient * stream = http.getStreamPtr(); if (Update.writeStream(*stream) != firmware_size) { @@ -2784,10 +2787,15 @@ bool System::command_read(const char * value, const int8_t id) { } // set the system status code - SYSTEM_STATUS in system.h +// this is also used in the SystemMonitor.tsx WebUI to show the progress of the firmware upload, start at 100 void System::systemStatus(uint8_t status_code) { if (systemStatus_ != status_code) { systemStatus_ = status_code; - LOG_DEBUG("Setting System status code %d", status_code); +#ifdef EMSESP_DEBUG + if (status_code < SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING) { + LOG_DEBUG("Setting System status code %d", status_code); + } +#endif } } From 949172128f8b7a7a12fcdb811cf4a1f340850b23 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 22:04:26 +0100 Subject: [PATCH 38/42] update packages --- interface/package.json | 4 ++-- interface/pnpm-lock.yaml | 42 ++++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/interface/package.json b/interface/package.json index f2a69f90c..4bc3b941d 100644 --- a/interface/package.json +++ b/interface/package.json @@ -37,7 +37,7 @@ "jwt-decode": "^4.0.0", "magic-string": "^0.30.21", "mime-types": "^3.0.2", - "preact": "^10.28.1", + "preact": "^10.28.2", "react": "^19.2.3", "react-dom": "^19.2.3", "react-icons": "^5.5.0", @@ -55,7 +55,7 @@ "@types/node": "^25.0.3", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "axe-core": "^4.11.0", + "axe-core": "^4.11.1", "concurrently": "^9.2.1", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 74c710e8a..091e63690 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -25,7 +25,7 @@ importers: version: 7.3.6(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@preact/compat': specifier: ^18.3.1 - version: 18.3.1(preact@10.28.1) + version: 18.3.1(preact@10.28.2) '@table-library/react-table-library': specifier: 4.1.15 version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -51,8 +51,8 @@ importers: specifier: ^3.0.2 version: 3.0.2 preact: - specifier: ^10.28.1 - version: 10.28.1 + specifier: ^10.28.2 + version: 10.28.2 react: specifier: ^19.2.3 version: 19.2.3 @@ -83,7 +83,7 @@ importers: version: 9.39.2 '@preact/preset-vite': specifier: ^2.10.2 - version: 2.10.2(@babel/core@7.28.5)(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) + version: 2.10.2(@babel/core@7.28.5)(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.1 version: 6.0.1(prettier@3.7.4) @@ -97,8 +97,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.7) axe-core: - specifier: ^4.11.0 - version: 4.11.0 + specifier: ^4.11.1 + version: 4.11.1 concurrently: specifier: ^9.2.1 version: 9.2.1 @@ -1023,8 +1023,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.11.0: - resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + axe-core@4.11.1: + resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} babel-plugin-macros@3.1.0: @@ -2475,8 +2475,8 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - preact@10.28.1: - resolution: {integrity: sha512-u1/ixq/lVQI0CakKNvLDEcW5zfCjUQfZdK9qqWuIJtsezuyG6pk9TWj75GMuI/EzRSZB/VAE43sNWWZfiy8psw==} + preact@10.28.2: + resolution: {integrity: sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -3606,16 +3606,16 @@ snapshots: '@popperjs/core@2.11.8': {} - '@preact/compat@18.3.1(preact@10.28.1)': + '@preact/compat@18.3.1(preact@10.28.2)': dependencies: - preact: 10.28.1 + preact: 10.28.2 - '@preact/preset-vite@2.10.2(@babel/core@7.28.5)(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': + '@preact/preset-vite@2.10.2(@babel/core@7.28.5)(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5) - '@prefresh/vite': 2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) + '@prefresh/vite': 2.4.11(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) '@rollup/pluginutils': 4.2.1 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.5) debug: 4.4.3 @@ -3628,20 +3628,20 @@ snapshots: '@prefresh/babel-plugin@0.5.2': {} - '@prefresh/core@1.5.9(preact@10.28.1)': + '@prefresh/core@1.5.9(preact@10.28.2)': dependencies: - preact: 10.28.1 + preact: 10.28.2 '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': + '@prefresh/vite@2.4.11(preact@10.28.2)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': dependencies: '@babel/core': 7.28.5 '@prefresh/babel-plugin': 0.5.2 - '@prefresh/core': 1.5.9(preact@10.28.1) + '@prefresh/core': 1.5.9(preact@10.28.2) '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 - preact: 10.28.1 + preact: 10.28.2 vite: 7.3.0(@types/node@25.0.3)(terser@5.44.1) transitivePeerDependencies: - supports-color @@ -3966,7 +3966,7 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axe-core@4.11.0: {} + axe-core@4.11.1: {} babel-plugin-macros@3.1.0: dependencies: @@ -5497,7 +5497,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - preact@10.28.1: {} + preact@10.28.2: {} prelude-ls@1.2.1: {} From e8fbbe5a1cc66b0d1c4e4e4628337a977c1fad30 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 22:04:54 +0100 Subject: [PATCH 39/42] skip blured paper component when in systemMonitor --- interface/src/app/main/Customizations.tsx | 6 ++++-- interface/src/app/settings/ApplicationSettings.tsx | 6 ++++-- interface/src/app/settings/Settings.tsx | 2 +- interface/src/app/settings/network/NetworkSettings.tsx | 6 ++++-- interface/src/app/status/Status.tsx | 2 +- interface/src/app/status/SystemMonitor.tsx | 4 ++-- interface/src/app/status/Version.tsx | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/interface/src/app/main/Customizations.tsx b/interface/src/app/main/Customizations.tsx index a387774cc..21711380e 100644 --- a/interface/src/app/main/Customizations.tsx +++ b/interface/src/app/main/Customizations.tsx @@ -788,10 +788,12 @@ const Customizations = () => { ); - return ( + return restarting ? ( + + ) : ( {blocker ? : null} - {restarting ? : renderContent()} + {renderContent()} {selectedDeviceEntity && ( { ); }; - return ( + return restarting ? ( + + ) : ( {blocker ? : null} - {restarting ? : content()} + {content()} ); }; diff --git a/interface/src/app/settings/Settings.tsx b/interface/src/app/settings/Settings.tsx index 608c37ee9..a8130bb24 100644 --- a/interface/src/app/settings/Settings.tsx +++ b/interface/src/app/settings/Settings.tsx @@ -182,7 +182,7 @@ const Settings = () => { restarting ]); - return {restarting ? : content}; + return restarting ? : {content}; }; export default Settings; diff --git a/interface/src/app/settings/network/NetworkSettings.tsx b/interface/src/app/settings/network/NetworkSettings.tsx index 5f525a992..92651c654 100644 --- a/interface/src/app/settings/network/NetworkSettings.tsx +++ b/interface/src/app/settings/network/NetworkSettings.tsx @@ -397,10 +397,12 @@ const NetworkSettings = () => { ); }; - return ( + return restarting ? ( + + ) : ( {blocker ? : null} - {restarting ? : content()} + {content()} ); }; diff --git a/interface/src/app/status/Status.tsx b/interface/src/app/status/Status.tsx index be5427785..1d87a5d4d 100644 --- a/interface/src/app/status/Status.tsx +++ b/interface/src/app/status/Status.tsx @@ -443,7 +443,7 @@ const SystemStatus = () => { renderRestartDialog ]); - return {restarting ? : content}; + return restarting ? : {content}; }; export default SystemStatus; diff --git a/interface/src/app/status/SystemMonitor.tsx b/interface/src/app/status/SystemMonitor.tsx index 492049074..7e7c289af 100644 --- a/interface/src/app/status/SystemMonitor.tsx +++ b/interface/src/app/status/SystemMonitor.tsx @@ -103,8 +103,8 @@ const SystemMonitor = () => { height: '100vh', display: 'flex', alignItems: 'center', - justifyContent: 'center', - backdropFilter: 'blur(8px)' + justifyContent: 'center' + // backdropFilter: 'blur(8px)' }} > { installPartitionFirmware ]); - return {restarting ? : content}; + return restarting ? : {content}; }; export default memo(Version); From b5defa552e10280b845b3cc038f96b0a3947ac76 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 22:15:22 +0100 Subject: [PATCH 40/42] improve chunking and fix circular refs --- interface/vite.config.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/interface/vite.config.ts b/interface/vite.config.ts index d73dc869f..2369cc845 100644 --- a/interface/vite.config.ts +++ b/interface/vite.config.ts @@ -136,9 +136,16 @@ const createManualChunks = (detailed = false) => { return 'vendor'; } if (detailed) { - if (id.includes('components/')) return 'components'; - if (id.includes('app/')) return 'app'; - if (id.includes('utils/')) return 'utils'; + // Group circularly dependent modules together to avoid circular chunk warnings + // components, app, and utils are tightly coupled, so combine them + if ( + id.includes('components/') || + id.includes('app/') || + id.includes('utils/') + ) { + return 'app'; + } + // Keep api separate as it's typically more independent if (id.includes('api/')) return 'api'; } return undefined; From 39919b4ad8e6b1e59e4006cdadf18b0255d6415e Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 22:17:54 +0100 Subject: [PATCH 41/42] update --- CHANGELOG_LATEST.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index b226b857e..febf8b0fd 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -16,8 +16,9 @@ For more details go to [emsesp.org](https://emsesp.org/). - Junkers wwcharge offset [#2860](https://github.com/emsesp/EMS-ESP32/issues/2860) - fixed minflowtemp [#2890](https://github.com/emsesp/EMS-ESP32/issues/2890) - don't add HA uom/classes for bool values [#2885](https://github.com/emsesp/EMS-ESP32/issues/2885) +- fixed missing progress bar on web firmware uploads ## Changed - snapshot gpios stored in temporary ram -- GPIOs stored along with the name +- GPIOs stored along with the name and reported in log if conflicting From 927e7c80f4042328c315f316cb8436541cd19009 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 6 Jan 2026 22:18:35 +0100 Subject: [PATCH 42/42] update --- CHANGELOG_LATEST.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index febf8b0fd..557966ecf 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -10,9 +10,9 @@ For more details go to [emsesp.org](https://emsesp.org/). ## Fixed -- fix EMS bus disconnected [#2881](https://github.com/emsesp/EMS-ESP32/issues/2881) +- fix EMS bus disconnected errors on some systems [#2881](https://github.com/emsesp/EMS-ESP32/issues/2881) - selflowtemp fix [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876) -- updated valid GPIOs for ESP32S2, ESP32S3 and ESP32 [#2887](https://github.com/emsesp/EMS-ESP32/issues/2887) +- updated valid GPIOs for ESP32S2, ESP32S3 and ESP32 that caused custom systems to block gpios [#2887](https://github.com/emsesp/EMS-ESP32/issues/2887) - Junkers wwcharge offset [#2860](https://github.com/emsesp/EMS-ESP32/issues/2860) - fixed minflowtemp [#2890](https://github.com/emsesp/EMS-ESP32/issues/2890) - don't add HA uom/classes for bool values [#2885](https://github.com/emsesp/EMS-ESP32/issues/2885)