diff --git a/src/MainTask.h b/src/MainTask.h index f3c2f2d..3f5e875 100644 --- a/src/MainTask.h +++ b/src/MainTask.h @@ -43,8 +43,6 @@ protected: bool telnetStarted = false; bool emergencyDetected = false; unsigned long emergencyFlipTime = 0; - bool freezeDetected = false; - unsigned long freezeDetectedTime = 0; #if defined(ARDUINO_ARCH_ESP32) const char* getTaskName() override { @@ -274,14 +272,20 @@ protected: availableSensors++; } - if (availableSensors && lowTemp <= settings.heating.freezeProtection.lowTemp) { - if (!vars.master.heating.freezing) { - if (!this->freezeDetected) { - this->freezeDetected = true; - this->freezeDetectedTime = millis(); + if (availableSensors) { + if (vars.master.heating.freezing) { + if (lowTemp - (float) settings.heating.freezeProtection.highTemp + 0.0001f >= 0.0f) { + vars.master.heating.freezing = false; - } else if (millis() - this->freezeDetectedTime > (settings.heating.freezeProtection.thresholdTime * 1000)) { - this->freezeDetected = false; + Log.sinfoln( + FPSTR(L_MAIN), + F("No freezing detected. Current low temp: %.2f, threshold (high): %hhu"), + lowTemp, settings.heating.freezeProtection.highTemp + ); + } + + } else { + if ((float) settings.heating.freezeProtection.lowTemp - lowTemp + 0.0001f >= 0.0f) { vars.master.heating.freezing = true; if (!settings.heating.enabled) { @@ -291,26 +295,16 @@ protected: Log.sinfoln( FPSTR(L_MAIN), - F("Heating turned on by freeze protection, current low temp: %.2f, threshold: %hhu"), + F("Freezing detected! Current low temp: %.2f, threshold (low): %hhu"), lowTemp, settings.heating.freezeProtection.lowTemp ); } } - } else { - if (this->freezeDetected) { - this->freezeDetected = false; - } + } else if (vars.master.heating.freezing) { + vars.master.heating.freezing = false; - if (vars.master.heating.freezing) { - vars.master.heating.freezing = false; - - Log.sinfoln( - FPSTR(L_MAIN), - F("No freezing detected, current low temp: %.2f, threshold: %hhu"), - lowTemp, settings.heating.freezeProtection.lowTemp - ); - } + Log.sinfoln(FPSTR(L_MAIN), F("No sensors available, freeze protection unavailable!")); } } } diff --git a/src/Settings.h b/src/Settings.h index c52bece..10b6850 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -121,8 +121,8 @@ struct Settings { } overheatProtection; struct { + uint8_t highTemp = 15; uint8_t lowTemp = 10; - unsigned short thresholdTime = 600; } freezeProtection; } heating; diff --git a/src/utils.h b/src/utils.h index de39c47..9253d3b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -505,8 +505,8 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { heatingOverheatProtection[FPSTR(S_LOW_TEMP)] = src.heating.overheatProtection.lowTemp; auto freezeProtection = heating[FPSTR(S_FREEZE_PROTECTION)].to(); + freezeProtection[FPSTR(S_HIGH_TEMP)] = src.heating.freezeProtection.highTemp; freezeProtection[FPSTR(S_LOW_TEMP)] = src.heating.freezeProtection.lowTemp; - freezeProtection[FPSTR(S_THRESHOLD_TIME)] = src.heating.freezeProtection.thresholdTime; auto dhw = dst[FPSTR(S_DHW)].to(); dhw[FPSTR(S_ENABLED)] = src.dhw.enabled; @@ -1426,6 +1426,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false changed = true; } + if (!src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_HIGH_TEMP)].isNull()) { + unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_HIGH_TEMP)].as(); + + if (isValidTemp(value, dst.system.unitSystem, 1, 50) && value != dst.heating.freezeProtection.highTemp) { + dst.heating.freezeProtection.highTemp = value; + changed = true; + } + } + if (!src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_LOW_TEMP)].isNull()) { unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_LOW_TEMP)].as(); @@ -1435,15 +1444,9 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (!src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_THRESHOLD_TIME)].isNull()) { - unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_THRESHOLD_TIME)].as(); - - if (value >= 30 && value <= 1800) { - if (value != dst.heating.freezeProtection.thresholdTime) { - dst.heating.freezeProtection.thresholdTime = value; - changed = true; - } - } + if (dst.heating.freezeProtection.highTemp < dst.heating.freezeProtection.lowTemp) { + dst.heating.freezeProtection.highTemp = dst.heating.freezeProtection.lowTemp; + changed = true; } diff --git a/src_data/locales/cn.json b/src_data/locales/cn.json index aafbac7..d8e6145 100644 --- a/src_data/locales/cn.json +++ b/src_data/locales/cn.json @@ -320,9 +320,15 @@ }, "freezeProtection": { "title": "防冻保护", - "desc": "当热媒或室内温度在等待时间 内降至低温阈值以下时,系统将强制启动加热功能。", - "lowTemp": "低温阈值", - "thresholdTime": "等待时间(秒)" + "desc": "如果热载体或室内温度低于 低温,加热将被强制开启。", + "highTemp": { + "title": "高温阈值", + "note": "防冻保护激活后系统恢复正常模式的阈值" + }, + "lowTemp": { + "title": "低温阈值", + "note": "强制开启加热的阈值" + } }, "portal": { diff --git a/src_data/locales/en.json b/src_data/locales/en.json index 8797eb2..8b41923 100644 --- a/src_data/locales/en.json +++ b/src_data/locales/en.json @@ -321,9 +321,15 @@ }, "freezeProtection": { "title": "Freeze protection", - "desc": "Heating will be forced to turn on if the heat carrier or indoor temperature drops below Low temperature during Waiting time.", - "lowTemp": "Low temperature threshold", - "thresholdTime": "Waiting time (sec)" + "desc": "Heating will be forced to turn on if the heat carrier or indoor temperature drops below Low temperature.", + "highTemp": { + "title": "High temperature threshold", + "note": "Threshold when the system returns to normal mode after freeze protection activation" + }, + "lowTemp": { + "title": "Low temperature threshold", + "note": "Threshold when heating is forced to turn on" + } }, "portal": { diff --git a/src_data/locales/it.json b/src_data/locales/it.json index 7469f64..4bf8c4a 100644 --- a/src_data/locales/it.json +++ b/src_data/locales/it.json @@ -320,9 +320,15 @@ }, "freezeProtection": { "title": "Protezione antigelo", - "desc": "Il riscaldamento verrà attivato forzatamente se la temperatura del vettore di calore o interna scende al di sotto della temperatura minima durante il tempo di attesa.", - "lowTemp": "Soglia di temperatura minima", - "thresholdTime": "Tempo di attesa (sec)" + "desc": "Il riscaldamento verrà forzatamente attivato se la temperatura del vettore termico o la temperatura interna scende al di sotto della Soglia di temperatura bassa.", + "highTemp": { + "title": "Soglia di temperatura alta", + "note": "Soglia quando il sistema ritorna alla modalità normale dopo l'attivazione della protezione antigelo" + }, + "lowTemp": { + "title": "Soglia di temperatura bassa", + "note": "Soglia quando il riscaldamento viene forzatamente attivato" + } }, "portal": { diff --git a/src_data/locales/nl.json b/src_data/locales/nl.json index b670292..85413ec 100644 --- a/src_data/locales/nl.json +++ b/src_data/locales/nl.json @@ -294,11 +294,18 @@ } }, "freezeProtection": { - "title": "Vorstbeveiliging", - "desc": "De verwarming wordt geforceerd ingeschakeld als de temperatuur van de warmtedrager of de binnentemperatuur onder de Lage temperatuur daalt gedurende de Wachttijd.", - "lowTemp": "Drempelwaarde lage temperatuur", - "thresholdTime": "Wachttijd (sec)" + "title": "Vorbeveiliging", + "desc": "Verwarming zal geforceerd worden ingeschakeld als de temperatuur van de warmtedrager of de binnentemperatuur daalt onder de Lage temperatuurdrempel.", + "highTemp": { + "title": "Hoge temperatuurdrempel", + "note": "Drempel waarna het systeem terugkeert naar de normale modus na activering van de vorbeveiliging" + }, + "lowTemp": { + "title": "Lage temperatuurdrempel", + "note": "Drempel wanneer de verwarming geforceerd wordt ingeschakeld" + } }, + "portal": { "login": "Gebruikersnaam", "password": "Wachtwoord", diff --git a/src_data/locales/ru.json b/src_data/locales/ru.json index 98532a6..3a5326f 100644 --- a/src_data/locales/ru.json +++ b/src_data/locales/ru.json @@ -320,9 +320,15 @@ }, "freezeProtection": { "title": "Защита от замерзания", - "desc": "Отопление будет принудительно включено, если темп. теплоносителя или внутренняя темп. опустится ниже нижнего порога в течение времени ожидания.", - "lowTemp": "Нижний порог температуры", - "thresholdTime": "Время ожидания (сек)" + "desc": "Отопление будет принудительно включено, если темп. теплоносителя или внутренняя темп. опустится ниже нижнего порога.", + "highTemp": { + "title": "Верхний порог температуры", + "note": "Порог, при котором система вернется в нормальное состояние после активации защиты от замерзания" + }, + "lowTemp": { + "title": "Нижний порог температуры", + "note": "Порог, при котором отопление будет принудительно включено" + } }, "portal": { diff --git a/src_data/pages/settings.html b/src_data/pages/settings.html index aca7079..a051572 100644 --- a/src_data/pages/settings.html +++ b/src_data/pages/settings.html @@ -265,13 +265,15 @@
@@ -1184,11 +1186,14 @@ "min": 0, "max": data.system.unitSystem == 0 ? 99 : 211 }); + setInputValue("[name='heating[freezeProtection][highTemp]']", data.heating.freezeProtection.highTemp, { + "min": data.system.unitSystem == 0 ? 1 : 34, + "max": data.system.unitSystem == 0 ? 50 : 122 + }); setInputValue("[name='heating[freezeProtection][lowTemp]']", data.heating.freezeProtection.lowTemp, { "min": data.system.unitSystem == 0 ? 1 : 34, "max": data.system.unitSystem == 0 ? 30 : 86 }); - setInputValue("[name='heating[freezeProtection][thresholdTime]']", data.heating.freezeProtection.thresholdTime); setBusy('#heating-settings-busy', '#heating-settings', false); // DHW