From dd53d1ef3ee99df81d278e6a8d493e59646dcbe1 Mon Sep 17 00:00:00 2001 From: Yurii Date: Thu, 6 Mar 2025 19:15:56 +0300 Subject: [PATCH 01/14] chore: bump version to 1.5.4 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 5394ac3..9b39f8b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,7 +14,7 @@ extra_configs = secrets.default.ini core_dir = .pio [env] -version = 1.5.3 +version = 1.5.4 framework = arduino lib_deps = bblanchon/ArduinoJson@^7.3.0 From d50b70c2117042f9f3dd6668a9c1eb9a7dfbb8ca Mon Sep 17 00:00:00 2001 From: Yurii Date: Fri, 14 Mar 2025 05:12:20 +0300 Subject: [PATCH 02/14] refactor: improved work with opentherm on esp32 --- lib/CustomOpenTherm/CustomOpenTherm.h | 54 +++++++++------------------ platformio.ini | 2 +- src/OpenThermTask.h | 34 ++++++++++------- 3 files changed, 38 insertions(+), 52 deletions(-) diff --git a/lib/CustomOpenTherm/CustomOpenTherm.h b/lib/CustomOpenTherm/CustomOpenTherm.h index 28db14d..2871eac 100644 --- a/lib/CustomOpenTherm/CustomOpenTherm.h +++ b/lib/CustomOpenTherm/CustomOpenTherm.h @@ -7,7 +7,7 @@ public: typedef std::function BeforeSendRequestCallback; typedef std::function AfterSendRequestCallback; - CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {} + CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false, bool alwaysReceive = false) : OpenTherm(inPin, outPin, isSlave, alwaysReceive) {} ~CustomOpenTherm() {} CustomOpenTherm* setDelayCallback(DelayCallback callback = nullptr) { @@ -28,8 +28,8 @@ public: return this; } - unsigned long sendRequest(unsigned long request, byte attempts = 5, byte _attempt = 0) { - _attempt++; + unsigned long sendRequest(unsigned long request) override { + this->sendRequestAttempt++; while (!this->isReady()) { if (this->delayCallback) { @@ -40,15 +40,10 @@ public: } if (this->beforeSendRequestCallback) { - this->beforeSendRequestCallback(request, _attempt); + this->beforeSendRequestCallback(request, this->sendRequestAttempt); } - unsigned long _response; - OpenThermResponseStatus _responseStatus = OpenThermResponseStatus::NONE; - if (!this->sendRequestAsync(request)) { - _response = 0; - - } else { + if (this->sendRequestAsync(request)) { do { if (this->delayCallback) { this->delayCallback(150); @@ -56,42 +51,25 @@ public: this->process(); } while (this->status != OpenThermStatus::READY && this->status != OpenThermStatus::DELAY); - - _response = this->getLastResponse(); - _responseStatus = this->getLastResponseStatus(); } if (this->afterSendRequestCallback) { - this->afterSendRequestCallback(request, _response, _responseStatus, _attempt); + this->afterSendRequestCallback(request, this->response, this->responseStatus, this->sendRequestAttempt); } - if (_responseStatus == OpenThermResponseStatus::SUCCESS || _responseStatus == OpenThermResponseStatus::INVALID || _attempt >= attempts) { - return _response; + if (this->responseStatus == OpenThermResponseStatus::SUCCESS || this->responseStatus == OpenThermResponseStatus::INVALID) { + this->sendRequestAttempt = 0; + return this->response; + + } else if (this->sendRequestAttempt >= this->sendRequestMaxAttempts) { + this->sendRequestAttempt = 0; + return this->response; } else { - return this->sendRequest(request, attempts, _attempt); + return this->sendRequest(request); } } - unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2, bool summerWinterMode, bool dhwBlocking, uint8_t lb = 0) { - unsigned int data = enableCentralHeating - | (enableHotWater << 1) - | (enableCooling << 2) - | (enableOutsideTemperatureCompensation << 3) - | (enableCentralHeating2 << 4) - | (summerWinterMode << 5) - | (dhwBlocking << 6); - - data <<= 8; - data |= lb; - - return this->sendRequest(buildRequest( - OpenThermMessageType::READ_DATA, - OpenThermMessageID::Status, - data - )); - } - bool sendBoilerReset() { unsigned int data = 1; data <<= 8; @@ -130,7 +108,7 @@ public: static bool isValidResponseId(unsigned long response, OpenThermMessageID id) { byte responseId = (response >> 16) & 0xFF; - + return (byte)id == responseId; } @@ -145,6 +123,8 @@ public: } protected: + const uint8_t sendRequestMaxAttempts = 5; + uint8_t sendRequestAttempt = 0; DelayCallback delayCallback; BeforeSendRequestCallback beforeSendRequestCallback; AfterSendRequestCallback afterSendRequestCallback; diff --git a/platformio.ini b/platformio.ini index 9b39f8b..f62eb26 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,7 +19,7 @@ framework = arduino lib_deps = bblanchon/ArduinoJson@^7.3.0 ;ihormelnyk/OpenTherm Library@^1.1.5 - https://github.com/ihormelnyk/opentherm_library#master + https://github.com/Laxilef/opentherm_library#esp32_timer arduino-libraries/ArduinoMqttClient@^0.1.8 lennarthennigs/ESP Telnet@^2.2 gyverlibs/FileData@^1.0.2 diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index b6a0e98..b99eef2 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -138,7 +138,12 @@ protected: return; } else if (this->instance->status == OpenThermStatus::NOT_INITIALIZED) { - this->instance->begin(); + if (!this->instance->begin()) { + Log.swarningln(FPSTR(L_OT), F("Failed begin")); + + this->delay(5000); + return; + } } // RX LED GPIO setup @@ -212,6 +217,20 @@ protected: F("Failed receive boiler status: %s"), CustomOpenTherm::statusToString(this->instance->getLastResponseStatus()) ); + + } else { + vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response); + vars.slave.dhw.active = settings.opentherm.options.dhwSupport ? CustomOpenTherm::isHotWaterActive(response) : false; + vars.slave.flame = CustomOpenTherm::isFlameOn(response); + vars.slave.cooling = CustomOpenTherm::isCoolingActive(response); + vars.slave.fault.active = CustomOpenTherm::isFault(response); + vars.slave.diag.active = CustomOpenTherm::isDiagnostic(response); + + Log.snoticeln( + FPSTR(L_OT), F("Received boiler status. Heating: %hhu; DHW: %hhu; flame: %hhu; cooling: %hhu; fault: %hhu; diag: %hhu"), + vars.slave.heating.active, vars.slave.dhw.active, + vars.slave.flame, vars.slave.cooling, vars.slave.fault.active, vars.slave.diag.active + ); } // 5 request retries @@ -310,19 +329,6 @@ protected: Log.sinfoln(FPSTR(L_OT_DHW), vars.master.dhw.enabled ? F("Enabled") : F("Disabled")); } - vars.slave.heating.active = CustomOpenTherm::isCentralHeatingActive(response); - vars.slave.dhw.active = settings.opentherm.options.dhwSupport ? CustomOpenTherm::isHotWaterActive(response) : false; - vars.slave.flame = CustomOpenTherm::isFlameOn(response); - vars.slave.cooling = CustomOpenTherm::isCoolingActive(response); - vars.slave.fault.active = CustomOpenTherm::isFault(response); - vars.slave.diag.active = CustomOpenTherm::isDiagnostic(response); - - Log.snoticeln( - FPSTR(L_OT), F("Received boiler status. Heating: %hhu; DHW: %hhu; flame: %hhu; cooling: %hhu; fault: %hhu; diag: %hhu"), - vars.slave.heating.active, vars.slave.dhw.active, - vars.slave.flame, vars.slave.cooling, vars.slave.fault.active, vars.slave.diag.active - ); - // These parameters will be updated every minute if (millis() - this->prevUpdateNonEssentialVars > 60000) { if (this->updateMinModulationLevel()) { From 5d0ca68dc031409496373635fe63094f716b04b3 Mon Sep 17 00:00:00 2001 From: Yurii Date: Tue, 18 Mar 2025 09:19:24 +0300 Subject: [PATCH 03/14] fix: ``OpenThermTask::setMaxHeatingTemp(const uint8_t temperature)`` changed to OpenThermTask::setMaxHeatingTemp(const float temperature) --- src/OpenThermTask.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index b99eef2..24c994e 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -1356,7 +1356,7 @@ protected: return CustomOpenTherm::getUInt(response) == request; } - bool setMaxHeatingTemp(const uint8_t temperature) { + bool setMaxHeatingTemp(const float temperature) { const unsigned int request = CustomOpenTherm::temperatureToData(temperature); const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest( OpenThermMessageType::WRITE_DATA, From dc68315166cb6b158b2a3798ca4a69d05e34d0fb Mon Sep 17 00:00:00 2001 From: Yurii Date: Tue, 18 Mar 2025 09:21:00 +0300 Subject: [PATCH 04/14] refactor: added ``Msg type`` output to opentherm log --- lib/CustomOpenTherm/CustomOpenTherm.h | 21 +++++++++++++++++++++ src/OpenThermTask.h | 9 +++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/CustomOpenTherm/CustomOpenTherm.h b/lib/CustomOpenTherm/CustomOpenTherm.h index 2871eac..389cfe5 100644 --- a/lib/CustomOpenTherm/CustomOpenTherm.h +++ b/lib/CustomOpenTherm/CustomOpenTherm.h @@ -112,6 +112,27 @@ public: return (byte)id == responseId; } + static uint8_t getResponseMessageTypeId(unsigned long response) { + return (response << 1) >> 29; + } + + static const char* getResponseMessageTypeString(unsigned long response) { + uint8_t msgType = getResponseMessageTypeId(response); + + switch (msgType) { + case (uint8_t) OpenThermMessageType::READ_ACK: + case (uint8_t) OpenThermMessageType::WRITE_ACK: + case (uint8_t) OpenThermMessageType::DATA_INVALID: + case (uint8_t) OpenThermMessageType::UNKNOWN_DATA_ID: + return CustomOpenTherm::messageTypeToString( + static_cast(msgType) + ); + + default: + return "UNKNOWN"; + } + } + // converters template static unsigned int toFloat(const T val) { diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index 24c994e..f1467c1 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -93,8 +93,13 @@ protected: this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) { Log.sverboseln( FPSTR(L_OT), - F("ID: %4d Request: %8lx Response: %8lx Attempt: %2d Status: %s"), - CustomOpenTherm::getDataID(request), request, response, attempt, CustomOpenTherm::statusToString(status) + F("ID: %4d Request: %8lx Response: %8lx Msg type: %s Attempt: %2d Status: %s"), + CustomOpenTherm::getDataID(request), + request, + response, + CustomOpenTherm::getResponseMessageTypeString(response), + attempt, + CustomOpenTherm::statusToString(status) ); if (status == OpenThermResponseStatus::SUCCESS) { From 77d80225ad040c4fe35ffcaba5c687ca34ab917b Mon Sep 17 00:00:00 2001 From: Yurii Date: Tue, 18 Mar 2025 09:26:53 +0300 Subject: [PATCH 05/14] refactor: small changes --- src/OpenThermTask.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index f1467c1..5472447 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -1190,17 +1190,17 @@ protected: bool needSetDhwTemp(const float target) { return millis() - this->dhwSetTempTime > this->dhwSetTempInterval - || fabsf(target - vars.slave.dhw.targetTemp) > 0.001f; + || fabsf(target - vars.slave.dhw.targetTemp) > 0.05f; } bool needSetHeatingTemp(const float target) { return millis() - this->heatingSetTempTime > this->heatingSetTempInterval - || fabsf(target - vars.slave.heating.targetTemp) > 0.001f; + || fabsf(target - vars.slave.heating.targetTemp) > 0.05f; } bool needSetCh2Temp(const float target) { return millis() - this->ch2SetTempTime > this->ch2SetTempInterval - || fabsf(target - vars.slave.ch2.targetTemp) > 0.001f; + || fabsf(target - vars.slave.ch2.targetTemp) > 0.05f; } bool updateSlaveConfig() { From 85932fdc1deceb801bc536dd59dd50d4938915f5 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 26 Mar 2025 16:14:32 +0300 Subject: [PATCH 06/14] refactor: rounding ``heating.setpointTemp`` --- src/RegulatorTask.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RegulatorTask.h b/src/RegulatorTask.h index cc67d39..443aee9 100644 --- a/src/RegulatorTask.h +++ b/src/RegulatorTask.h @@ -60,11 +60,11 @@ protected: this->hysteresis(); vars.master.heating.targetTemp = settings.heating.target; - vars.master.heating.setpointTemp = constrain( + vars.master.heating.setpointTemp = roundf(constrain( this->getHeatingSetpointTemp(), this->getHeatingMinSetpointTemp(), this->getHeatingMaxSetpointTemp() - ); + ), 0); Sensors::setValueByType( Sensors::Type::HEATING_SETPOINT_TEMP, vars.master.heating.setpointTemp, From 7dbd503e1e39668b4152e30163e1541a8c2fb288 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 7 May 2025 06:12:39 +0300 Subject: [PATCH 07/14] fix: restarting on critically low heap #151 --- src/MainTask.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MainTask.h b/src/MainTask.h index f581adb..65aba81 100644 --- a/src/MainTask.h +++ b/src/MainTask.h @@ -196,6 +196,7 @@ protected: // critical heap if (!vars.states.restarting && (freeHeap < 2048 || maxFreeBlockHeap < 2048)) { this->restartSignalReceivedTime = millis(); + this->restartSignalReceived = true; vars.states.restarting = true; } From 9dd5ee8da52d78a4c0ba188170d0ec8a80390bdd Mon Sep 17 00:00:00 2001 From: Yurii Date: Thu, 8 May 2025 09:39:30 +0300 Subject: [PATCH 08/14] chore: bump pioarduino/platform-espressif32 from 3.1.3 to 3.2.0 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index f62eb26..f2e2727 100644 --- a/platformio.ini +++ b/platformio.ini @@ -84,7 +84,7 @@ board_build.ldscript = eagle.flash.4m1m.ld ;platform_packages = ; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5 ; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip -platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip +platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip platform_packages = board_build.partitions = esp32_partitions.csv lib_deps = From 7c032ddc2fd83fb57812b5c12da7e30c8de17604 Mon Sep 17 00:00:00 2001 From: Yurii Date: Sun, 18 May 2025 15:29:32 +0300 Subject: [PATCH 09/14] fix: removed ``device_class`` for signal quality entities for compatibility with HA 2025.7.0 --- src/HaHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HaHelper.h b/src/HaHelper.h index be05926..689d3ec 100644 --- a/src/HaHelper.h +++ b/src/HaHelper.h @@ -395,7 +395,7 @@ public: doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->statusTopic.c_str(); doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_ENTITY_CATEGORY)] = FPSTR(HA_ENTITY_CATEGORY_DIAGNOSTIC); - doc[FPSTR(HA_DEVICE_CLASS)] = F("signal_strength"); + //doc[FPSTR(HA_DEVICE_CLASS)] = F("signal_strength"); doc[FPSTR(HA_STATE_CLASS)] = FPSTR(HA_STATE_CLASS_MEASUREMENT); doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_PERCENT); doc[FPSTR(HA_ICON)] = F("mdi:signal"); From 612b17b86fb670953e1a81fd02a93f95fa9a9ff8 Mon Sep 17 00:00:00 2001 From: Yurii Date: Sun, 18 May 2025 15:31:49 +0300 Subject: [PATCH 10/14] refactor: reworked the setting of the maximum modulation level, added the parameter of the maximum modulation level for DHW --- src/OpenThermTask.h | 64 +++++++++++++++++++++--------------- src/Settings.h | 4 +-- src/strings.h | 1 - src/utils.h | 41 ++++++++++++----------- src_data/locales/en.json | 3 +- src_data/locales/it.json | 3 +- src_data/locales/ru.json | 3 +- src_data/pages/settings.html | 24 +++++++------- 8 files changed, 75 insertions(+), 68 deletions(-) diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index 5472447..1b2e03a 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -342,13 +342,23 @@ protected: vars.slave.modulation.min, vars.slave.power.max ); - if (settings.opentherm.maxModulation < vars.slave.modulation.min) { - settings.opentherm.maxModulation = vars.slave.modulation.min; + if (settings.heating.maxModulation < vars.slave.modulation.min) { + settings.heating.maxModulation = vars.slave.modulation.min; fsSettings.update(); Log.swarningln( - FPSTR(L_SETTINGS_OT), F("Updated min modulation: %hhu%%"), - settings.opentherm.maxModulation + FPSTR(L_SETTINGS_HEATING), F("Updated min modulation: %hhu%%"), + settings.heating.maxModulation + ); + } + + if (settings.dhw.maxModulation < vars.slave.modulation.min) { + settings.dhw.maxModulation = vars.slave.modulation.min; + fsSettings.update(); + + Log.swarningln( + FPSTR(L_SETTINGS_DHW), F("Updated min modulation: %hhu%%"), + settings.dhw.maxModulation ); } @@ -367,29 +377,6 @@ protected: Log.swarningln(FPSTR(L_OT), F("Failed receive min modulation and max power")); } - if (!vars.master.heating.enabled && settings.opentherm.options.modulationSyncWithHeating) { - if (this->setMaxModulationLevel(0)) { - Log.snoticeln(FPSTR(L_OT), F("Set max modulation: 0% (response: %hhu%%)"), vars.slave.modulation.max); - - } else { - Log.swarningln(FPSTR(L_OT), F("Failed set max modulation: 0% (response: %hhu%%)"), vars.slave.modulation.max); - } - - } else { - if (this->setMaxModulationLevel(settings.opentherm.maxModulation)) { - Log.snoticeln( - FPSTR(L_OT), F("Set max modulation: %hhu%% (response: %hhu%%)"), - settings.opentherm.maxModulation, vars.slave.modulation.max - ); - - } else { - Log.swarningln( - FPSTR(L_OT), F("Failed set max modulation: %hhu%% (response: %hhu%%)"), - settings.opentherm.maxModulation, vars.slave.modulation.max - ); - } - } - // Get DHW min/max temp (if necessary) if (settings.opentherm.options.dhwSupport && settings.opentherm.options.getMinMaxTemp) { @@ -517,6 +504,29 @@ protected: this->prevUpdateNonEssentialVars = millis(); } + // Set max modulation level + uint8_t targetMaxModulation = vars.slave.modulation.max; + if (vars.slave.heating.active) { + targetMaxModulation = settings.heating.maxModulation; + + } else if (vars.slave.dhw.active) { + targetMaxModulation = settings.dhw.maxModulation; + } + + if (vars.slave.modulation.max != targetMaxModulation) { + if (this->setMaxModulationLevel(targetMaxModulation)) { + Log.snoticeln( + FPSTR(L_OT), F("Set max modulation: %hhu%% (response: %hhu%%)"), + targetMaxModulation, vars.slave.modulation.max + ); + + } else { + Log.swarningln( + FPSTR(L_OT), F("Failed set max modulation: %hhu%% (response: %hhu%%)"), + targetMaxModulation, vars.slave.modulation.max + ); + } + } // Update modulation level if ( diff --git a/src/Settings.h b/src/Settings.h index 5a493e2..4bc37b9 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -59,7 +59,6 @@ struct Settings { byte rxLedGpio = DEFAULT_OT_RX_LED_GPIO; uint8_t memberId = 0; uint8_t flags = 0; - uint8_t maxModulation = 100; float minPower = 0.0f; float maxPower = 0.0f; @@ -72,7 +71,6 @@ struct Settings { bool heatingToCh2 = false; bool dhwToCh2 = false; bool dhwBlocking = false; - bool modulationSyncWithHeating = false; bool maxTempSyncWithTargetTemp = true; bool getMinMaxTemp = true; bool nativeHeatingControl = false; @@ -104,6 +102,7 @@ struct Settings { float turboFactor = 7.5f; byte minTemp = DEFAULT_HEATING_MIN_TEMP; byte maxTemp = DEFAULT_HEATING_MAX_TEMP; + uint8_t maxModulation = 100; } heating; struct { @@ -111,6 +110,7 @@ struct Settings { float target = DEFAULT_DHW_TARGET_TEMP; byte minTemp = DEFAULT_DHW_MIN_TEMP; byte maxTemp = DEFAULT_DHW_MAX_TEMP; + uint8_t maxModulation = 100; } dhw; struct { diff --git a/src/strings.h b/src/strings.h index 32ad73a..64cf680 100644 --- a/src/strings.h +++ b/src/strings.h @@ -131,7 +131,6 @@ const char S_MIN_POWER[] PROGMEM = "minPower"; const char S_MIN_TEMP[] PROGMEM = "minTemp"; const char S_MODEL[] PROGMEM = "model"; const char S_MODULATION[] PROGMEM = "modulation"; -const char S_MODULATION_SYNC_WITH_HEATING[] PROGMEM = "modulationSyncWithHeating"; const char S_MQTT[] PROGMEM = "mqtt"; const char S_NAME[] PROGMEM = "name"; const char S_NATIVE_HEATING_CONTROL[] PROGMEM = "nativeHeatingControl"; diff --git a/src/utils.h b/src/utils.h index 261d2d2..b3ef87b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -449,7 +449,6 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { opentherm[FPSTR(S_RX_LED_GPIO)] = src.opentherm.rxLedGpio; opentherm[FPSTR(S_MEMBER_ID)] = src.opentherm.memberId; opentherm[FPSTR(S_FLAGS)] = src.opentherm.flags; - opentherm[FPSTR(S_MAX_MODULATION)] = src.opentherm.maxModulation; opentherm[FPSTR(S_MIN_POWER)] = roundf(src.opentherm.minPower, 2); opentherm[FPSTR(S_MAX_POWER)] = roundf(src.opentherm.maxPower, 2); @@ -462,7 +461,6 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { otOptions[FPSTR(S_HEATING_TO_CH2)] = src.opentherm.options.heatingToCh2; otOptions[FPSTR(S_DHW_TO_CH2)] = src.opentherm.options.dhwToCh2; otOptions[FPSTR(S_DHW_BLOCKING)] = src.opentherm.options.dhwBlocking; - otOptions[FPSTR(S_MODULATION_SYNC_WITH_HEATING)] = src.opentherm.options.modulationSyncWithHeating; otOptions[FPSTR(S_MAX_TEMP_SYNC_WITH_TARGET_TEMP)] = src.opentherm.options.maxTempSyncWithTargetTemp; otOptions[FPSTR(S_GET_MIN_MAX_TEMP)] = src.opentherm.options.getMinMaxTemp; otOptions[FPSTR(S_NATIVE_HEATING_CONTROL)] = src.opentherm.options.nativeHeatingControl; @@ -491,12 +489,14 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { heating[FPSTR(S_TURBO_FACTOR)] = roundf(src.heating.turboFactor, 3); heating[FPSTR(S_MIN_TEMP)] = src.heating.minTemp; heating[FPSTR(S_MAX_TEMP)] = src.heating.maxTemp; + heating[FPSTR(S_MAX_MODULATION)] = src.heating.maxModulation; auto dhw = dst[FPSTR(S_DHW)].to(); dhw[FPSTR(S_ENABLED)] = src.dhw.enabled; dhw[FPSTR(S_TARGET)] = roundf(src.dhw.target, 1); dhw[FPSTR(S_MIN_TEMP)] = src.dhw.minTemp; dhw[FPSTR(S_MAX_TEMP)] = src.dhw.maxTemp; + dhw[FPSTR(S_MAX_MODULATION)] = src.dhw.maxModulation; auto equitherm = dst[FPSTR(S_EQUITHERM)].to(); equitherm[FPSTR(S_ENABLED)] = src.equitherm.enabled; @@ -811,15 +811,6 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_MODULATION)].isNull()) { - unsigned char value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MAX_MODULATION)].as(); - - if (value > 0 && value <= 100 && value != dst.opentherm.maxModulation) { - dst.opentherm.maxModulation = value; - changed = true; - } - } - if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_MIN_POWER)].isNull()) { float value = src[FPSTR(S_OPENTHERM)][FPSTR(S_MIN_POWER)].as(); @@ -928,15 +919,6 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MODULATION_SYNC_WITH_HEATING)].is()) { - bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MODULATION_SYNC_WITH_HEATING)].as(); - - if (value != dst.opentherm.options.modulationSyncWithHeating) { - dst.opentherm.options.modulationSyncWithHeating = value; - changed = true; - } - } - if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MAX_TEMP_SYNC_WITH_TARGET_TEMP)].is()) { bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_MAX_TEMP_SYNC_WITH_TARGET_TEMP)].as(); @@ -1301,6 +1283,16 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } + if (!src[FPSTR(S_HEATING)][FPSTR(S_MAX_MODULATION)].isNull()) { + unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_MAX_MODULATION)].as(); + + if (value > 0 && value <= 100 && value != dst.heating.maxModulation) { + dst.heating.maxModulation = value; + changed = true; + } + } + + // dhw if (src[FPSTR(S_DHW)][FPSTR(S_ENABLED)].is()) { bool value = src[FPSTR(S_DHW)][FPSTR(S_ENABLED)].as(); @@ -1334,6 +1326,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false changed = true; } + if (!src[FPSTR(S_DHW)][FPSTR(S_MAX_MODULATION)].isNull()) { + unsigned char value = src[FPSTR(S_DHW)][FPSTR(S_MAX_MODULATION)].as(); + + if (value > 0 && value <= 100 && value != dst.dhw.maxModulation) { + dst.dhw.maxModulation = value; + changed = true; + } + } + if (!safe) { // external pump diff --git a/src_data/locales/en.json b/src_data/locales/en.json index 8dcbf79..2c4f394 100644 --- a/src_data/locales/en.json +++ b/src_data/locales/en.json @@ -292,6 +292,7 @@ "min": "Minimum temperature", "max": "Maximum temperature" }, + "maxModulation": "Max modulation level", "portal": { "login": "Login", @@ -375,7 +376,6 @@ "ledGpio": "RX LED GPIO", "memberId": "Master member ID", "flags": "Master flags", - "maxMod": "Max modulation level", "minPower": { "title": "Min boiler power (kW)", "note": "This value is at 0-1% boiler modulation level. Typically found in the boiler specification as \"minimum useful heat output\"." @@ -395,7 +395,6 @@ "heatingToCh2": "Duplicate heating to CH2", "dhwToCh2": "Duplicate DHW to CH2", "dhwBlocking": "DHW blocking", - "modulationSyncWithHeating": "Sync modulation with heating", "maxTempSyncWithTargetTemp": "Sync max heating temp with target temp", "getMinMaxTemp": "Get min/max temp from boiler", "immergasFix": "Fix for Immergas boilers" diff --git a/src_data/locales/it.json b/src_data/locales/it.json index a0b8e05..36ff42a 100644 --- a/src_data/locales/it.json +++ b/src_data/locales/it.json @@ -292,6 +292,7 @@ "min": "Temperatura minima", "max": "Temperatura massima" }, + "maxModulation": "Max livello modulazione", "portal": { "login": "Login", @@ -375,7 +376,6 @@ "ledGpio": "RX LED GPIO", "memberId": "Master member ID", "flags": "Master flags", - "maxMod": "Max livello modulazione", "minPower": { "title": "Potenza minima caldaia (kW)", "note": "Questo valore corrisponde allo livello 0-1% di modulazione della caldaia. Di solito si trova nelle specifiche delle caldaia come \"potenza minima disponibile\"." @@ -395,7 +395,6 @@ "heatingToCh2": "Riproduci riscaldamento su CH2", "dhwToCh2": "Riproduci ACS su CH2", "dhwBlocking": "Bloccare ACS", - "modulationSyncWithHeating": "Sincronizzare modulazione con caldaia", "maxTempSyncWithTargetTemp": "Sincronizza la temperatura massima di riscaldamento con la temperatura target", "getMinMaxTemp": "Prendi temp min/max dalla caldaia", "immergasFix": "Fix per caldiaie Immergas" diff --git a/src_data/locales/ru.json b/src_data/locales/ru.json index fa1daa8..acc3a90 100644 --- a/src_data/locales/ru.json +++ b/src_data/locales/ru.json @@ -292,6 +292,7 @@ "min": "Мин. температура", "max": "Макс. температура" }, + "maxModulation": "Макс. уровень модуляции", "portal": { "login": "Логин", @@ -375,7 +376,6 @@ "ledGpio": "RX LED GPIO", "memberId": "Master member ID", "flags": "Master flags", - "maxMod": "Макс. уровень модуляции", "minPower": { "title": "Мин. мощность котла (кВт)", "note": "Это значение соответствует уровню модуляции котла 0–1%. Обычно можно найти в спецификации котла как \"минимальная полезная тепловая мощность\"." @@ -395,7 +395,6 @@ "heatingToCh2": "Дублировать параметры отопления в канал 2", "dhwToCh2": "Дублировать параметры ГВС в канал 2", "dhwBlocking": "DHW blocking", - "modulationSyncWithHeating": "Синхронизировать модуляцию с отоплением", "maxTempSyncWithTargetTemp": "Синхронизировать макс. темп. отопления с целевой темп.", "getMinMaxTemp": "Получать мин. и макс. температуру от котла", "immergasFix": "Фикс для котлов Immergas" diff --git a/src_data/pages/settings.html b/src_data/pages/settings.html index 2b9d7d7..4452297 100644 --- a/src_data/pages/settings.html +++ b/src_data/pages/settings.html @@ -202,6 +202,11 @@ + + @@ -226,6 +231,11 @@ + + @@ -457,11 +467,6 @@ settings.ot.flags - -
@@ -521,11 +526,6 @@ settings.ot.options.dhwBlocking - - + + + + + + + +