mirror of
https://github.com/Laxilef/OTGateway.git
synced 2026-03-22 10:18:39 +05:00
Compare commits
18 Commits
eafb33cb6a
...
freeze_pro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6539211b8f | ||
|
|
40fe40eb8a | ||
|
|
3a6bb03456 | ||
|
|
7fcca3c4aa | ||
|
|
2f6bd237c7 | ||
|
|
e4d1ba7d7b | ||
|
|
b70c212235 | ||
|
|
781b2a1f9c | ||
|
|
10ab75c055 | ||
|
|
56a8574aba | ||
|
|
3adfabdf40 | ||
|
|
a9220d9fa1 | ||
|
|
5a14857f52 | ||
|
|
e487c78921 | ||
|
|
6c3b79bda1 | ||
|
|
09c50d5df8 | ||
|
|
348fab39bb | ||
|
|
f9cb421893 |
@@ -1,5 +1,5 @@
|
|||||||
# Blueprint for reporting indoor/outdoor temperature to OpenTherm Gateway from any home assistant sensor
|
# Blueprint for reporting indoor/outdoor temperature to OpenTherm Gateway from any home assistant sensor
|
||||||
# Updated: 03.09.2024
|
# Updated: 26.01.2026
|
||||||
|
|
||||||
blueprint:
|
blueprint:
|
||||||
name: Report temp to OpenTherm Gateway
|
name: Report temp to OpenTherm Gateway
|
||||||
@@ -15,7 +15,6 @@ blueprint:
|
|||||||
multiple: false
|
multiple: false
|
||||||
filter:
|
filter:
|
||||||
- domain: sensor
|
- domain: sensor
|
||||||
device_class: temperature
|
|
||||||
target_entity:
|
target_entity:
|
||||||
name: Target entity
|
name: Target entity
|
||||||
description: "Usually ``number.opentherm_indoor_temp`` or ``number.opentherm_outdoor_temp``"
|
description: "Usually ``number.opentherm_indoor_temp`` or ``number.opentherm_outdoor_temp``"
|
||||||
@@ -38,8 +37,12 @@ condition:
|
|||||||
value_template: "{{ states(source_entity) != 'unavailable' and states(target_entity) != 'unavailable' }}"
|
value_template: "{{ states(source_entity) != 'unavailable' and states(target_entity) != 'unavailable' }}"
|
||||||
action:
|
action:
|
||||||
- if:
|
- if:
|
||||||
- condition: template
|
- condition: or
|
||||||
value_template: "{{ (states(source_entity)|float(0) - states(target_entity)|float(0)) | abs | round(2) >= 0.01 }}"
|
conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ (states(source_entity)|float(0) - states(target_entity)|float(0)) | abs | round(2) >= 0.01 }}"
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ (as_timestamp(now()) - as_timestamp(states[target_entity].last_updated)) | int(0) > 300 }}"
|
||||||
then:
|
then:
|
||||||
- service: number.set_value
|
- service: number.set_value
|
||||||
data:
|
data:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Blueprint for reporting temperature to OpenTherm Gateway from home assistant weather integration
|
# Blueprint for reporting temperature to OpenTherm Gateway from home assistant weather integration
|
||||||
# Updated: 03.09.2024
|
# Updated: 26.01.2026
|
||||||
|
|
||||||
blueprint:
|
blueprint:
|
||||||
name: Report temp to OpenTherm Gateway from Weather
|
name: Report temp to OpenTherm Gateway from Weather
|
||||||
@@ -37,8 +37,12 @@ condition:
|
|||||||
value_template: "{{ states(source_entity) != 'unavailable' and states(target_entity) != 'unavailable' }}"
|
value_template: "{{ states(source_entity) != 'unavailable' and states(target_entity) != 'unavailable' }}"
|
||||||
action:
|
action:
|
||||||
- if:
|
- if:
|
||||||
- condition: template
|
- condition: or
|
||||||
value_template: "{{ (state_attr(source_entity, 'temperature')|float(0) - states(target_entity)|float(0)) | abs | round(2) >= 0.1 }}"
|
conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ (state_attr(source_entity, 'temperature')|float(0) - states(target_entity)|float(0)) | abs | round(2) >= 0.1 }}"
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ (as_timestamp(now()) - as_timestamp(states[target_entity].last_updated)) | int(0) > 300 }}"
|
||||||
then:
|
then:
|
||||||
- service: number.set_value
|
- service: number.set_value
|
||||||
data:
|
data:
|
||||||
|
|||||||
@@ -70,50 +70,89 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sendBoilerReset() {
|
inline auto sendBoilerReset() {
|
||||||
unsigned int data = 1;
|
return this->sendRequestCode(1);
|
||||||
data <<= 8;
|
|
||||||
unsigned long response = this->sendRequest(buildRequest(
|
|
||||||
OpenThermMessageType::WRITE_DATA,
|
|
||||||
OpenThermMessageID::RemoteRequest,
|
|
||||||
data
|
|
||||||
));
|
|
||||||
|
|
||||||
return isValidResponse(response) && isValidResponseId(response, OpenThermMessageID::RemoteRequest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sendServiceReset() {
|
inline auto sendServiceReset() {
|
||||||
unsigned int data = 10;
|
return this->sendRequestCode(10);
|
||||||
data <<= 8;
|
|
||||||
unsigned long response = this->sendRequest(buildRequest(
|
|
||||||
OpenThermMessageType::WRITE_DATA,
|
|
||||||
OpenThermMessageID::RemoteRequest,
|
|
||||||
data
|
|
||||||
));
|
|
||||||
|
|
||||||
return isValidResponse(response) && isValidResponseId(response, OpenThermMessageID::RemoteRequest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sendWaterFilling() {
|
inline auto sendWaterFilling() {
|
||||||
unsigned int data = 2;
|
return this->sendRequestCode(2);
|
||||||
data <<= 8;
|
}
|
||||||
|
|
||||||
|
bool sendRequestCode(const uint8_t requestCode) {
|
||||||
unsigned long response = this->sendRequest(buildRequest(
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
OpenThermMessageID::RemoteRequest,
|
OpenThermMessageID::RemoteRequest,
|
||||||
data
|
static_cast<unsigned int>(requestCode) << 8
|
||||||
));
|
));
|
||||||
|
|
||||||
return isValidResponse(response) && isValidResponseId(response, OpenThermMessageID::RemoteRequest);
|
if (!isValidResponse(response) || !isValidResponseId(response, OpenThermMessageID::RemoteRequest)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t responseRequestCode = (response & 0xFFFF) >> 8;
|
||||||
|
const uint8_t responseCode = response & 0xFF;
|
||||||
|
if (responseRequestCode != requestCode || responseCode < 128) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset
|
||||||
|
this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
OpenThermMessageID::RemoteRequest,
|
||||||
|
0u << 8
|
||||||
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getStr(OpenThermMessageID id, char* buffer, uint16_t length = 50) {
|
||||||
|
if (buffer == nullptr || length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long response;
|
||||||
|
uint8_t index = 0;
|
||||||
|
uint8_t maxIndex = 255;
|
||||||
|
|
||||||
|
while (index <= maxIndex && index < length) {
|
||||||
|
response = this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::READ_DATA,
|
||||||
|
id,
|
||||||
|
static_cast<unsigned int>(index) << 8
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!isValidResponse(response) || !isValidResponseId(response, id)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t character = response & 0xFF;
|
||||||
|
if (character == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
maxIndex = (response & 0xFFFF) >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[index++] = static_cast<char>(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[index] = '\0';
|
||||||
|
return index > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isCh2Active(unsigned long response) {
|
static bool isCh2Active(unsigned long response) {
|
||||||
return response & 0x20;
|
return response & 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isValidResponseId(unsigned long response, OpenThermMessageID id) {
|
static bool isValidResponseId(unsigned long response, OpenThermMessageID id) {
|
||||||
uint8_t responseId = (response >> 16) & 0xFF;
|
const uint8_t responseId = (response >> 16) & 0xFF;
|
||||||
|
|
||||||
return (uint8_t)id == responseId;
|
return static_cast<uint8_t>(id) == responseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t getResponseMessageTypeId(unsigned long response) {
|
static uint8_t getResponseMessageTypeId(unsigned long response) {
|
||||||
@@ -124,10 +163,10 @@ public:
|
|||||||
uint8_t msgType = getResponseMessageTypeId(response);
|
uint8_t msgType = getResponseMessageTypeId(response);
|
||||||
|
|
||||||
switch (msgType) {
|
switch (msgType) {
|
||||||
case (uint8_t) OpenThermMessageType::READ_ACK:
|
case static_cast<uint8_t>(OpenThermMessageType::READ_ACK):
|
||||||
case (uint8_t) OpenThermMessageType::WRITE_ACK:
|
case static_cast<uint8_t>(OpenThermMessageType::WRITE_ACK):
|
||||||
case (uint8_t) OpenThermMessageType::DATA_INVALID:
|
case static_cast<uint8_t>(OpenThermMessageType::DATA_INVALID):
|
||||||
case (uint8_t) OpenThermMessageType::UNKNOWN_DATA_ID:
|
case static_cast<uint8_t>(OpenThermMessageType::UNKNOWN_DATA_ID):
|
||||||
return CustomOpenTherm::messageTypeToString(
|
return CustomOpenTherm::messageTypeToString(
|
||||||
static_cast<OpenThermMessageType>(msgType)
|
static_cast<OpenThermMessageType>(msgType)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ extra_configs = secrets.default.ini
|
|||||||
core_dir = .pio
|
core_dir = .pio
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
version = 1.5.6
|
version = 1.6.0
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^7.4.2
|
bblanchon/ArduinoJson@^7.4.2
|
||||||
@@ -25,8 +25,11 @@ lib_deps =
|
|||||||
gyverlibs/FileData@^1.0.3
|
gyverlibs/FileData@^1.0.3
|
||||||
gyverlibs/GyverPID@^3.3.2
|
gyverlibs/GyverPID@^3.3.2
|
||||||
gyverlibs/GyverBlinker@^1.1.1
|
gyverlibs/GyverBlinker@^1.1.1
|
||||||
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg
|
pstolarz/OneWireNg@^0.14.1
|
||||||
|
;milesburton/DallasTemperature@^4.0.5
|
||||||
|
https://github.com/Laxilef/Arduino-Temperature-Control-Library#fix_85c
|
||||||
laxilef/TinyLogger@^1.1.1
|
laxilef/TinyLogger@^1.1.1
|
||||||
|
lib_ignore = OneWire
|
||||||
build_type = ${secrets.build_type}
|
build_type = ${secrets.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
-mtext-section-literals
|
-mtext-section-literals
|
||||||
@@ -73,7 +76,7 @@ platform_packages = ${env.platform_packages}
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
nrwiersma/ESP8266Scheduler@^1.2
|
nrwiersma/ESP8266Scheduler@^1.2
|
||||||
lib_ignore =
|
lib_ignore = ${env.lib_ignore}
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
post:tools/build.py
|
post:tools/build.py
|
||||||
build_type = ${env.build_type}
|
build_type = ${env.build_type}
|
||||||
@@ -92,14 +95,14 @@ check_flags = ${env.check_flags}
|
|||||||
;platform_packages =
|
;platform_packages =
|
||||||
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
|
; 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
|
; 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/55.03.34/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.36/platform-espressif32.zip
|
||||||
platform_packages = ${env.platform_packages}
|
platform_packages = ${env.platform_packages}
|
||||||
board_build.partitions = esp32_partitions.csv
|
board_build.partitions = esp32_partitions.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
laxilef/ESP32Scheduler@^1.0.1
|
laxilef/ESP32Scheduler@^1.0.1
|
||||||
nimble_lib = h2zero/NimBLE-Arduino@2.3.7
|
nimble_lib = h2zero/NimBLE-Arduino@2.3.7
|
||||||
lib_ignore =
|
lib_ignore = ${env.lib_ignore}
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
post:tools/esp32.py
|
post:tools/esp32.py
|
||||||
post:tools/build.py
|
post:tools/build.py
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ protected:
|
|||||||
bool telnetStarted = false;
|
bool telnetStarted = false;
|
||||||
bool emergencyDetected = false;
|
bool emergencyDetected = false;
|
||||||
unsigned long emergencyFlipTime = 0;
|
unsigned long emergencyFlipTime = 0;
|
||||||
bool freezeDetected = false;
|
|
||||||
unsigned long freezeDetectedTime = 0;
|
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
const char* getTaskName() override {
|
const char* getTaskName() override {
|
||||||
@@ -135,8 +133,6 @@ protected:
|
|||||||
tMqtt->disable();
|
tMqtt->disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
Sensors::setConnectionStatusByType(Sensors::Type::MANUAL, !settings.mqtt.enabled || vars.mqtt.connected, false);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (this->ntpStarted) {
|
if (this->ntpStarted) {
|
||||||
this->ntpStarted = false;
|
this->ntpStarted = false;
|
||||||
@@ -245,7 +241,7 @@ protected:
|
|||||||
|
|
||||||
void heating() {
|
void heating() {
|
||||||
// freeze protection
|
// freeze protection
|
||||||
if (!settings.heating.enabled) {
|
{
|
||||||
float lowTemp = 255.0f;
|
float lowTemp = 255.0f;
|
||||||
uint8_t availableSensors = 0;
|
uint8_t availableSensors = 0;
|
||||||
|
|
||||||
@@ -276,29 +272,40 @@ protected:
|
|||||||
availableSensors++;
|
availableSensors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (availableSensors && lowTemp <= settings.heating.freezeProtection.lowTemp) {
|
if (availableSensors) {
|
||||||
if (!this->freezeDetected) {
|
if (vars.master.heating.freezing) {
|
||||||
this->freezeDetected = true;
|
if (lowTemp - (float) settings.heating.freezeProtection.highTemp + 0.0001f >= 0.0f) {
|
||||||
this->freezeDetectedTime = millis();
|
vars.master.heating.freezing = false;
|
||||||
|
|
||||||
} else if (millis() - this->freezeDetectedTime > (settings.heating.freezeProtection.thresholdTime * 1000)) {
|
Log.sinfoln(
|
||||||
this->freezeDetected = false;
|
FPSTR(L_MAIN),
|
||||||
settings.heating.enabled = true;
|
F("No freezing detected. Current low temp: %.2f, threshold (high): %hhu"),
|
||||||
fsSettings.update();
|
lowTemp, settings.heating.freezeProtection.highTemp
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Log.sinfoln(
|
} else {
|
||||||
FPSTR(L_MAIN),
|
if ((float) settings.heating.freezeProtection.lowTemp - lowTemp + 0.0001f >= 0.0f) {
|
||||||
F("Heating turned on by freeze protection, current low temp: %.2f, threshold: %hhu"),
|
vars.master.heating.freezing = true;
|
||||||
lowTemp, settings.heating.freezeProtection.lowTemp
|
|
||||||
);
|
if (!settings.heating.enabled) {
|
||||||
|
settings.heating.enabled = true;
|
||||||
|
fsSettings.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.sinfoln(
|
||||||
|
FPSTR(L_MAIN),
|
||||||
|
F("Freezing detected! Current low temp: %.2f, threshold (low): %hhu"),
|
||||||
|
lowTemp, settings.heating.freezeProtection.lowTemp
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (this->freezeDetected) {
|
} else if (vars.master.heating.freezing) {
|
||||||
this->freezeDetected = false;
|
vars.master.heating.freezing = false;
|
||||||
}
|
|
||||||
|
|
||||||
} else if (this->freezeDetected) {
|
Log.sinfoln(FPSTR(L_MAIN), F("No sensors available, freeze protection unavailable!"));
|
||||||
this->freezeDetected = false;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +326,7 @@ protected:
|
|||||||
emergencyFlags |= 0b00000010;
|
emergencyFlags |= 0b00000010;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.opentherm.options.nativeHeatingControl) {
|
if (settings.opentherm.options.nativeOTC) {
|
||||||
emergencyFlags |= 0b00000100;
|
emergencyFlags |= 0b00000100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,8 +170,7 @@ protected:
|
|||||||
// Heating settings
|
// Heating settings
|
||||||
vars.master.heating.enabled = this->isReady()
|
vars.master.heating.enabled = this->isReady()
|
||||||
&& settings.heating.enabled
|
&& settings.heating.enabled
|
||||||
&& vars.cascadeControl.input
|
&& (vars.master.heating.freezing || (vars.cascadeControl.input && !vars.master.heating.blocking))
|
||||||
&& (!vars.master.heating.blocking || settings.heating.hysteresis.action != HysteresisAction::DISABLE_HEATING)
|
|
||||||
&& !vars.master.heating.overheat;
|
&& !vars.master.heating.overheat;
|
||||||
|
|
||||||
// DHW settings
|
// DHW settings
|
||||||
@@ -186,7 +185,9 @@ protected:
|
|||||||
|| (settings.opentherm.options.dhwToCh2 && settings.opentherm.options.dhwSupport && settings.dhw.enabled);
|
|| (settings.opentherm.options.dhwToCh2 && settings.opentherm.options.dhwSupport && settings.dhw.enabled);
|
||||||
|
|
||||||
if (settings.opentherm.options.heatingToCh2) {
|
if (settings.opentherm.options.heatingToCh2) {
|
||||||
vars.master.ch2.targetTemp = vars.master.heating.setpointTemp;
|
vars.master.ch2.targetTemp = !settings.opentherm.options.nativeOTC
|
||||||
|
? vars.master.heating.setpointTemp
|
||||||
|
: vars.master.heating.targetTemp;
|
||||||
|
|
||||||
} else if (settings.opentherm.options.dhwToCh2) {
|
} else if (settings.opentherm.options.dhwToCh2) {
|
||||||
vars.master.ch2.targetTemp = vars.master.dhw.targetTemp;
|
vars.master.ch2.targetTemp = vars.master.dhw.targetTemp;
|
||||||
@@ -218,7 +219,7 @@ protected:
|
|||||||
vars.master.heating.enabled,
|
vars.master.heating.enabled,
|
||||||
vars.master.dhw.enabled,
|
vars.master.dhw.enabled,
|
||||||
settings.opentherm.options.coolingSupport,
|
settings.opentherm.options.coolingSupport,
|
||||||
settings.opentherm.options.nativeHeatingControl,
|
settings.opentherm.options.nativeOTC,
|
||||||
vars.master.ch2.enabled,
|
vars.master.ch2.enabled,
|
||||||
summerWinterMode,
|
summerWinterMode,
|
||||||
dhwBlocking,
|
dhwBlocking,
|
||||||
@@ -305,6 +306,7 @@ protected:
|
|||||||
Sensors::setConnectionStatusByType(Sensors::Type::OT_DHW_BURNER_HOURS, false);
|
Sensors::setConnectionStatusByType(Sensors::Type::OT_DHW_BURNER_HOURS, false);
|
||||||
Sensors::setConnectionStatusByType(Sensors::Type::OT_HEATING_PUMP_HOURS, false);
|
Sensors::setConnectionStatusByType(Sensors::Type::OT_HEATING_PUMP_HOURS, false);
|
||||||
Sensors::setConnectionStatusByType(Sensors::Type::OT_DHW_PUMP_HOURS, false);
|
Sensors::setConnectionStatusByType(Sensors::Type::OT_DHW_PUMP_HOURS, false);
|
||||||
|
Sensors::setConnectionStatusByType(Sensors::Type::OT_COOLING_HOURS, false);
|
||||||
|
|
||||||
this->initialized = false;
|
this->initialized = false;
|
||||||
this->disconnectedTime = millis();
|
this->disconnectedTime = millis();
|
||||||
@@ -677,6 +679,21 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update cooling hours
|
||||||
|
if (Sensors::getAmountByType(Sensors::Type::OT_COOLING_HOURS, true)) {
|
||||||
|
if (this->updateCoolingHours()) {
|
||||||
|
Log.snoticeln(FPSTR(L_OT), F("Received cooling hours: %hu"), vars.slave.stats.coolingHours);
|
||||||
|
|
||||||
|
Sensors::setValueByType(
|
||||||
|
Sensors::Type::OT_COOLING_HOURS, vars.slave.stats.coolingHours,
|
||||||
|
Sensors::ValueType::PRIMARY, true, true
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.swarningln(FPSTR(L_OT), F("Failed receive cooling hours"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Auto fault reset
|
// Auto fault reset
|
||||||
if (settings.opentherm.options.autoFaultReset && vars.slave.fault.active && !vars.actions.resetFault) {
|
if (settings.opentherm.options.autoFaultReset && vars.slave.fault.active && !vars.actions.resetFault) {
|
||||||
vars.actions.resetFault = true;
|
vars.actions.resetFault = true;
|
||||||
@@ -792,7 +809,7 @@ protected:
|
|||||||
bool result = this->updateDhwTemp();
|
bool result = this->updateDhwTemp();
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
float convertedDhwTemp = convertTemp(
|
const float convertedDhwTemp = convertTemp(
|
||||||
vars.slave.dhw.currentTemp,
|
vars.slave.dhw.currentTemp,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -816,7 +833,7 @@ protected:
|
|||||||
// Update DHW temp 2
|
// Update DHW temp 2
|
||||||
if (settings.opentherm.options.dhwSupport && Sensors::getAmountByType(Sensors::Type::OT_DHW_TEMP2, true)) {
|
if (settings.opentherm.options.dhwSupport && Sensors::getAmountByType(Sensors::Type::OT_DHW_TEMP2, true)) {
|
||||||
if (this->updateDhwTemp2()) {
|
if (this->updateDhwTemp2()) {
|
||||||
float convertedDhwTemp2 = convertTemp(
|
const float convertedDhwTemp2 = convertTemp(
|
||||||
vars.slave.dhw.currentTemp2,
|
vars.slave.dhw.currentTemp2,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -840,7 +857,7 @@ protected:
|
|||||||
// Update DHW flow rate
|
// Update DHW flow rate
|
||||||
if (settings.opentherm.options.dhwSupport && Sensors::getAmountByType(Sensors::Type::OT_DHW_FLOW_RATE, true)) {
|
if (settings.opentherm.options.dhwSupport && Sensors::getAmountByType(Sensors::Type::OT_DHW_FLOW_RATE, true)) {
|
||||||
if (this->updateDhwFlowRate()) {
|
if (this->updateDhwFlowRate()) {
|
||||||
float convertedDhwFlowRate = convertVolume(
|
const float convertedDhwFlowRate = convertVolume(
|
||||||
vars.slave.dhw.flowRate,
|
vars.slave.dhw.flowRate,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -864,7 +881,7 @@ protected:
|
|||||||
// Update heating temp
|
// Update heating temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_HEATING_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_HEATING_TEMP, true)) {
|
||||||
if (this->updateHeatingTemp()) {
|
if (this->updateHeatingTemp()) {
|
||||||
float convertedHeatingTemp = convertTemp(
|
const float convertedHeatingTemp = convertTemp(
|
||||||
vars.slave.heating.currentTemp,
|
vars.slave.heating.currentTemp,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -888,7 +905,7 @@ protected:
|
|||||||
// Update heating return temp
|
// Update heating return temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_HEATING_RETURN_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_HEATING_RETURN_TEMP, true)) {
|
||||||
if (this->updateHeatingReturnTemp()) {
|
if (this->updateHeatingReturnTemp()) {
|
||||||
float convertedHeatingReturnTemp = convertTemp(
|
const float convertedHeatingReturnTemp = convertTemp(
|
||||||
vars.slave.heating.returnTemp,
|
vars.slave.heating.returnTemp,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -911,9 +928,9 @@ protected:
|
|||||||
|
|
||||||
// Update CH2 temp
|
// Update CH2 temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_CH2_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_CH2_TEMP, true)) {
|
||||||
if (vars.master.ch2.enabled && !settings.opentherm.options.nativeHeatingControl) {
|
if (vars.master.ch2.enabled && !settings.opentherm.options.nativeOTC) {
|
||||||
if (this->updateCh2Temp()) {
|
if (this->updateCh2Temp()) {
|
||||||
float convertedCh2Temp = convertTemp(
|
const float convertedCh2Temp = convertTemp(
|
||||||
vars.slave.ch2.currentTemp,
|
vars.slave.ch2.currentTemp,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -938,7 +955,7 @@ protected:
|
|||||||
// Update exhaust temp
|
// Update exhaust temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_EXHAUST_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_EXHAUST_TEMP, true)) {
|
||||||
if (this->updateExhaustTemp()) {
|
if (this->updateExhaustTemp()) {
|
||||||
float convertedExhaustTemp = convertTemp(
|
const float convertedExhaustTemp = convertTemp(
|
||||||
vars.slave.exhaust.temp,
|
vars.slave.exhaust.temp,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -962,7 +979,7 @@ protected:
|
|||||||
// Update heat exchanger temp
|
// Update heat exchanger temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_HEAT_EXCHANGER_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_HEAT_EXCHANGER_TEMP, true)) {
|
||||||
if (this->updateHeatExchangerTemp()) {
|
if (this->updateHeatExchangerTemp()) {
|
||||||
float convertedHeatExchTemp = convertTemp(
|
const float convertedHeatExchTemp = convertTemp(
|
||||||
vars.slave.heatExchangerTemp,
|
vars.slave.heatExchangerTemp,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -986,7 +1003,7 @@ protected:
|
|||||||
// Update outdoor temp
|
// Update outdoor temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_OUTDOOR_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_OUTDOOR_TEMP, true)) {
|
||||||
if (this->updateOutdoorTemp()) {
|
if (this->updateOutdoorTemp()) {
|
||||||
float convertedOutdoorTemp = convertTemp(
|
const float convertedOutdoorTemp = convertTemp(
|
||||||
vars.slave.heating.outdoorTemp,
|
vars.slave.heating.outdoorTemp,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -1010,7 +1027,7 @@ protected:
|
|||||||
// Update solar storage temp
|
// Update solar storage temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_SOLAR_STORAGE_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_SOLAR_STORAGE_TEMP, true)) {
|
||||||
if (this->updateSolarStorageTemp()) {
|
if (this->updateSolarStorageTemp()) {
|
||||||
float convertedSolarStorageTemp = convertTemp(
|
const float convertedSolarStorageTemp = convertTemp(
|
||||||
vars.slave.solar.storage,
|
vars.slave.solar.storage,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -1034,7 +1051,7 @@ protected:
|
|||||||
// Update solar collector temp
|
// Update solar collector temp
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_SOLAR_COLLECTOR_TEMP, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_SOLAR_COLLECTOR_TEMP, true)) {
|
||||||
if (this->updateSolarCollectorTemp()) {
|
if (this->updateSolarCollectorTemp()) {
|
||||||
float convertedSolarCollectorTemp = convertTemp(
|
const float convertedSolarCollectorTemp = convertTemp(
|
||||||
vars.slave.solar.collector,
|
vars.slave.solar.collector,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -1080,7 +1097,7 @@ protected:
|
|||||||
// Update pressure
|
// Update pressure
|
||||||
if (Sensors::getAmountByType(Sensors::Type::OT_PRESSURE, true)) {
|
if (Sensors::getAmountByType(Sensors::Type::OT_PRESSURE, true)) {
|
||||||
if (this->updatePressure()) {
|
if (this->updatePressure()) {
|
||||||
float convertedPressure = convertPressure(
|
const float convertedPressure = convertPressure(
|
||||||
vars.slave.pressure,
|
vars.slave.pressure,
|
||||||
settings.opentherm.unitSystem,
|
settings.opentherm.unitSystem,
|
||||||
settings.system.unitSystem
|
settings.system.unitSystem
|
||||||
@@ -1186,9 +1203,12 @@ protected:
|
|||||||
|
|
||||||
// Update DHW temp
|
// Update DHW temp
|
||||||
if (vars.master.dhw.enabled) {
|
if (vars.master.dhw.enabled) {
|
||||||
|
// Target dhw temp
|
||||||
|
const float& targetTemp = vars.master.dhw.targetTemp;
|
||||||
|
|
||||||
// Converted target dhw temp
|
// Converted target dhw temp
|
||||||
float convertedTemp = convertTemp(
|
const float convertedTemp = convertTemp(
|
||||||
vars.master.dhw.targetTemp,
|
targetTemp,
|
||||||
settings.system.unitSystem,
|
settings.system.unitSystem,
|
||||||
settings.opentherm.unitSystem
|
settings.opentherm.unitSystem
|
||||||
);
|
);
|
||||||
@@ -1200,7 +1220,7 @@ protected:
|
|||||||
|
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT_DHW), F("Set temp: %.2f (converted: %.2f, response: %.2f)"),
|
FPSTR(L_OT_DHW), F("Set temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||||
vars.master.dhw.targetTemp, convertedTemp, vars.slave.dhw.targetTemp
|
targetTemp, convertedTemp, vars.slave.dhw.targetTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1209,16 +1229,19 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Native heating control
|
// Send indoor temp if AlwaysSendIndoorTemp option is enabled.
|
||||||
if (settings.opentherm.options.nativeHeatingControl) {
|
if (settings.opentherm.options.nativeOTC || settings.opentherm.options.alwaysSendIndoorTemp) {
|
||||||
|
// Current indoor temp
|
||||||
|
const float& indoorTemp = vars.master.heating.indoorTemp;
|
||||||
|
|
||||||
// Converted current indoor temp
|
// Converted current indoor temp
|
||||||
float convertedTemp = convertTemp(vars.master.heating.indoorTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
|
const float convertedTemp = convertTemp(indoorTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
|
||||||
|
|
||||||
// Set current indoor temp
|
// Set current indoor temp
|
||||||
if (this->setRoomTemp(convertedTemp)) {
|
if (this->setRoomTemp(convertedTemp)) {
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT_HEATING), F("Set current indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
FPSTR(L_OT_HEATING), F("Set current indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||||
vars.master.heating.indoorTemp, convertedTemp, vars.slave.heating.indoorTemp
|
indoorTemp, convertedTemp, vars.slave.heating.indoorTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1230,17 +1253,26 @@ protected:
|
|||||||
if (this->setRoomTempCh2(convertedTemp)) {
|
if (this->setRoomTempCh2(convertedTemp)) {
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT_HEATING), F("Set current CH2 indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
FPSTR(L_OT_HEATING), F("Set current CH2 indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||||
vars.master.heating.indoorTemp, convertedTemp, vars.slave.ch2.indoorTemp
|
indoorTemp, convertedTemp, vars.slave.ch2.indoorTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set current CH2 indoor temp"));
|
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set current CH2 indoor temp"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NativeOTC
|
||||||
|
if (settings.opentherm.options.nativeOTC) {
|
||||||
|
// Target indoor temp
|
||||||
|
const float& targetTemp = vars.master.heating.targetTemp;
|
||||||
|
|
||||||
// Converted target indoor temp
|
// Converted target indoor temp
|
||||||
convertedTemp = convertTemp(vars.master.heating.targetTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
|
const float convertedTemp = convertTemp(
|
||||||
|
targetTemp,
|
||||||
|
settings.system.unitSystem,
|
||||||
|
settings.opentherm.unitSystem
|
||||||
|
);
|
||||||
|
|
||||||
// Set target indoor temp
|
// Set target indoor temp
|
||||||
if (this->needSetHeatingTemp(convertedTemp)) {
|
if (this->needSetHeatingTemp(convertedTemp)) {
|
||||||
@@ -1249,7 +1281,7 @@ protected:
|
|||||||
|
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT_HEATING), F("Set target indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
FPSTR(L_OT_HEATING), F("Set target indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||||
vars.master.heating.targetTemp, convertedTemp, vars.slave.heating.targetTemp
|
targetTemp, convertedTemp, vars.slave.heating.targetTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1264,7 +1296,7 @@ protected:
|
|||||||
|
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT_HEATING), F("Set target CH2 indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
FPSTR(L_OT_HEATING), F("Set target CH2 indoor temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||||
vars.master.heating.targetTemp, convertedTemp, vars.slave.ch2.targetTemp
|
targetTemp, convertedTemp, vars.slave.ch2.targetTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1273,10 +1305,22 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal heating control
|
// Set heating temp
|
||||||
if (!settings.opentherm.options.nativeHeatingControl && vars.master.heating.enabled) {
|
{
|
||||||
|
// Target heating temp
|
||||||
|
float targetTemp = 0.0f;
|
||||||
|
if (vars.master.heating.enabled) {
|
||||||
|
targetTemp = !settings.opentherm.options.nativeOTC
|
||||||
|
? vars.master.heating.setpointTemp
|
||||||
|
: vars.master.heating.targetTemp;
|
||||||
|
}
|
||||||
|
|
||||||
// Converted target heating temp
|
// Converted target heating temp
|
||||||
float convertedTemp = convertTemp(vars.master.heating.setpointTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
|
const float convertedTemp = convertTemp(
|
||||||
|
targetTemp,
|
||||||
|
settings.system.unitSystem,
|
||||||
|
settings.opentherm.unitSystem
|
||||||
|
);
|
||||||
|
|
||||||
if (this->needSetHeatingTemp(convertedTemp)) {
|
if (this->needSetHeatingTemp(convertedTemp)) {
|
||||||
// Set max heating temp
|
// Set max heating temp
|
||||||
@@ -1284,13 +1328,13 @@ protected:
|
|||||||
if (this->setMaxHeatingTemp(convertedTemp)) {
|
if (this->setMaxHeatingTemp(convertedTemp)) {
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT_HEATING), F("Set max heating temp: %.2f (converted: %.2f)"),
|
FPSTR(L_OT_HEATING), F("Set max heating temp: %.2f (converted: %.2f)"),
|
||||||
vars.master.heating.setpointTemp, convertedTemp
|
targetTemp, convertedTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_OT_HEATING), F("Failed set max heating temp: %.2f (converted: %.2f)"),
|
FPSTR(L_OT_HEATING), F("Failed set max heating temp: %.2f (converted: %.2f)"),
|
||||||
vars.master.heating.setpointTemp, convertedTemp
|
targetTemp, convertedTemp
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1301,7 +1345,7 @@ protected:
|
|||||||
|
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT_HEATING), F("Set target temp: %.2f (converted: %.2f, response: %.2f)"),
|
FPSTR(L_OT_HEATING), F("Set target temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||||
vars.master.heating.setpointTemp, convertedTemp, vars.slave.heating.targetTemp
|
targetTemp, convertedTemp, vars.slave.heating.targetTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1311,27 +1355,30 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set CH2 temp
|
// Set CH2 temp
|
||||||
if (!settings.opentherm.options.nativeHeatingControl && vars.master.ch2.enabled) {
|
if (settings.opentherm.options.heatingToCh2 || settings.opentherm.options.dhwToCh2) {
|
||||||
if (settings.opentherm.options.heatingToCh2 || settings.opentherm.options.dhwToCh2) {
|
// Target CH2 heating temp
|
||||||
// Converted target CH2 temp
|
const float targetTemp = vars.master.ch2.enabled
|
||||||
float convertedTemp = convertTemp(
|
? vars.master.ch2.targetTemp
|
||||||
vars.master.ch2.targetTemp,
|
: 0.0f;
|
||||||
settings.system.unitSystem,
|
|
||||||
settings.opentherm.unitSystem
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this->needSetCh2Temp(convertedTemp)) {
|
// Converted target CH2 temp
|
||||||
if (this->setCh2Temp(convertedTemp)) {
|
const float convertedTemp = convertTemp(
|
||||||
this->ch2SetTempTime = millis();
|
targetTemp,
|
||||||
|
settings.system.unitSystem,
|
||||||
|
settings.opentherm.unitSystem
|
||||||
|
);
|
||||||
|
|
||||||
Log.sinfoln(
|
if (this->needSetCh2Temp(convertedTemp)) {
|
||||||
FPSTR(L_OT_CH2), F("Set temp: %.2f (converted: %.2f, response: %.2f)"),
|
if (this->setCh2Temp(convertedTemp)) {
|
||||||
vars.master.ch2.targetTemp, convertedTemp, vars.slave.ch2.targetTemp
|
this->ch2SetTempTime = millis();
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
Log.sinfoln(
|
||||||
Log.swarningln(FPSTR(L_OT_CH2), F("Failed set temp"));
|
FPSTR(L_OT_CH2), F("Set temp: %.2f (converted: %.2f, response: %.2f)"),
|
||||||
}
|
targetTemp, convertedTemp, vars.slave.ch2.targetTemp
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.swarningln(FPSTR(L_OT_CH2), F("Failed set temp"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1339,7 +1386,7 @@ protected:
|
|||||||
|
|
||||||
// Heating overheat control
|
// Heating overheat control
|
||||||
if (settings.heating.overheatProtection.highTemp > 0 && settings.heating.overheatProtection.lowTemp > 0) {
|
if (settings.heating.overheatProtection.highTemp > 0 && settings.heating.overheatProtection.lowTemp > 0) {
|
||||||
float highTemp = convertTemp(
|
const float highTemp = convertTemp(
|
||||||
max({
|
max({
|
||||||
vars.slave.heating.currentTemp,
|
vars.slave.heating.currentTemp,
|
||||||
vars.slave.heating.returnTemp,
|
vars.slave.heating.returnTemp,
|
||||||
@@ -1376,7 +1423,7 @@ protected:
|
|||||||
|
|
||||||
// DHW overheat control
|
// DHW overheat control
|
||||||
if (settings.dhw.overheatProtection.highTemp > 0 && settings.dhw.overheatProtection.lowTemp > 0) {
|
if (settings.dhw.overheatProtection.highTemp > 0 && settings.dhw.overheatProtection.lowTemp > 0) {
|
||||||
float highTemp = convertTemp(
|
const float highTemp = convertTemp(
|
||||||
max({
|
max({
|
||||||
vars.slave.heating.currentTemp,
|
vars.slave.heating.currentTemp,
|
||||||
vars.slave.heating.returnTemp,
|
vars.slave.heating.returnTemp,
|
||||||
@@ -1470,6 +1517,19 @@ protected:
|
|||||||
} else {
|
} else {
|
||||||
Log.swarningln(FPSTR(L_OT), F("Failed set master config"));
|
Log.swarningln(FPSTR(L_OT), F("Failed set master config"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*char buf[100];
|
||||||
|
if (this->instance->getStr(OpenThermMessageID::Brand, buf, sizeof(buf) - 1)) {
|
||||||
|
Log.snoticeln(FPSTR(L_OT), F("Slave brand: %s"), buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->instance->getStr(OpenThermMessageID::BrandVersion, buf, sizeof(buf) - 1)) {
|
||||||
|
Log.snoticeln(FPSTR(L_OT), F("Slave brand version: %s"), buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->instance->getStr(OpenThermMessageID::BrandSerialNumber, buf, sizeof(buf) - 1)) {
|
||||||
|
Log.snoticeln(FPSTR(L_OT), F("Slave brand s/n: %s"), buf);
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isReady() {
|
bool isReady() {
|
||||||
@@ -1647,7 +1707,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool setRoomTemp(float temperature) {
|
bool setRoomTemp(const float temperature) {
|
||||||
const unsigned int request = CustomOpenTherm::temperatureToData(temperature);
|
const unsigned int request = CustomOpenTherm::temperatureToData(temperature);
|
||||||
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
@@ -1667,7 +1727,7 @@ protected:
|
|||||||
return CustomOpenTherm::getUInt(response) == request;
|
return CustomOpenTherm::getUInt(response) == request;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setRoomTempCh2(float temperature) {
|
bool setRoomTempCh2(const float temperature) {
|
||||||
const unsigned int request = CustomOpenTherm::temperatureToData(temperature);
|
const unsigned int request = CustomOpenTherm::temperatureToData(temperature);
|
||||||
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
@@ -2169,6 +2229,25 @@ protected:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool updateCoolingHours() {
|
||||||
|
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
||||||
|
OpenThermRequestType::READ_DATA,
|
||||||
|
OpenThermMessageID::CoolingOperationHours,
|
||||||
|
0
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!CustomOpenTherm::isValidResponse(response)) {
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else if (!CustomOpenTherm::isValidResponseId(response, OpenThermMessageID::CoolingOperationHours)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.slave.stats.coolingHours = CustomOpenTherm::getUInt(response);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool updateModulationLevel() {
|
bool updateModulationLevel() {
|
||||||
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
|
||||||
OpenThermRequestType::READ_DATA,
|
OpenThermRequestType::READ_DATA,
|
||||||
@@ -2183,7 +2262,7 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = CustomOpenTherm::getFloat(response);
|
const float value = CustomOpenTherm::getFloat(response);
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2207,7 +2286,7 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = CustomOpenTherm::getFloat(response);
|
const float value = CustomOpenTherm::getFloat(response);
|
||||||
if (value <= 0) {
|
if (value <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2231,7 +2310,7 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = CustomOpenTherm::getFloat(response);
|
const float value = CustomOpenTherm::getFloat(response);
|
||||||
if (value <= 0) {
|
if (value <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2285,7 +2364,7 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = CustomOpenTherm::getFloat(response);
|
const float value = CustomOpenTherm::getFloat(response);
|
||||||
if (value <= 0) {
|
if (value <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2349,7 +2428,7 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = (float) CustomOpenTherm::getInt(response);
|
const float value = (float) CustomOpenTherm::getInt(response);
|
||||||
if (!isValidTemp(value, settings.opentherm.unitSystem, -40, 500)) {
|
if (!isValidTemp(value, settings.opentherm.unitSystem, -40, 500)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2373,7 +2452,7 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = (float) CustomOpenTherm::getInt(response);
|
const float value = (float) CustomOpenTherm::getInt(response);
|
||||||
if (value <= 0) {
|
if (value <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2474,7 +2553,7 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = CustomOpenTherm::getFloat(response);
|
const float value = CustomOpenTherm::getFloat(response);
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,17 @@ protected:
|
|||||||
|
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
this->webServer->sendHeader(F("Content-Disposition"), F("attachment; filename=\"backup.json\""));
|
char filename[64];
|
||||||
|
getFilename(filename, sizeof(filename), "backup");
|
||||||
|
|
||||||
|
char contentDispositionHeaderValue[128];
|
||||||
|
snprintf_P(
|
||||||
|
contentDispositionHeaderValue,
|
||||||
|
sizeof(contentDispositionHeaderValue),
|
||||||
|
PSTR("attachment; filename=\"%s\""),
|
||||||
|
filename
|
||||||
|
);
|
||||||
|
this->webServer->sendHeader(F("Content-Disposition"), contentDispositionHeaderValue);
|
||||||
this->bufferedWebServer->send(200, F("application/json"), doc);
|
this->bufferedWebServer->send(200, F("application/json"), doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -839,7 +849,18 @@ protected:
|
|||||||
|
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
this->webServer->sendHeader(F("Content-Disposition"), F("attachment; filename=\"debug.json\""));
|
char filename[64];
|
||||||
|
getFilename(filename, sizeof(filename), "debug");
|
||||||
|
|
||||||
|
char contentDispositionHeaderValue[128];
|
||||||
|
snprintf_P(
|
||||||
|
contentDispositionHeaderValue,
|
||||||
|
sizeof(contentDispositionHeaderValue),
|
||||||
|
PSTR("attachment; filename=\"%s\""),
|
||||||
|
filename
|
||||||
|
);
|
||||||
|
|
||||||
|
this->webServer->sendHeader(F("Content-Disposition"), contentDispositionHeaderValue);
|
||||||
this->bufferedWebServer->send(200, F("application/json"), doc, true);
|
this->bufferedWebServer->send(200, F("application/json"), doc, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1046,4 +1067,12 @@ protected:
|
|||||||
this->dnsServer->stop();
|
this->dnsServer->stop();
|
||||||
this->dnsServerEnabled = false;
|
this->dnsServerEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void getFilename(char* filename, size_t maxSizeFilename, const char* type) {
|
||||||
|
const time_t now = time(nullptr);
|
||||||
|
const tm* localNow = localtime(&now);
|
||||||
|
char localNowValue[20];
|
||||||
|
strftime(localNowValue, sizeof(localNowValue), PSTR("%Y-%m-%d-%H-%M-%S"), localNow);
|
||||||
|
snprintf_P(filename, maxSizeFilename, PSTR("%s_%s_%s.json"), networkSettings.hostname, localNowValue, type);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -37,7 +37,7 @@ protected:
|
|||||||
this->indoorSensorsConnected = Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP);
|
this->indoorSensorsConnected = Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP);
|
||||||
//this->outdoorSensorsConnected = Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::OUTDOOR_TEMP);
|
//this->outdoorSensorsConnected = Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::OUTDOOR_TEMP);
|
||||||
|
|
||||||
if (settings.equitherm.enabled || settings.pid.enabled || settings.opentherm.options.nativeHeatingControl) {
|
if (settings.equitherm.enabled || settings.pid.enabled || settings.opentherm.options.nativeOTC) {
|
||||||
vars.master.heating.indoorTempControl = true;
|
vars.master.heating.indoorTempControl = true;
|
||||||
vars.master.heating.minTemp = THERMOSTAT_INDOOR_MIN_TEMP;
|
vars.master.heating.minTemp = THERMOSTAT_INDOOR_MIN_TEMP;
|
||||||
vars.master.heating.maxTemp = THERMOSTAT_INDOOR_MAX_TEMP;
|
vars.master.heating.maxTemp = THERMOSTAT_INDOOR_MAX_TEMP;
|
||||||
@@ -57,23 +57,12 @@ protected:
|
|||||||
this->turbo();
|
this->turbo();
|
||||||
this->hysteresis();
|
this->hysteresis();
|
||||||
|
|
||||||
if (vars.master.heating.blocking && settings.heating.hysteresis.action == HysteresisAction::SET_ZERO_TARGET) {
|
vars.master.heating.targetTemp = settings.heating.target;
|
||||||
vars.master.heating.targetTemp = 0.0f;
|
vars.master.heating.setpointTemp = roundf(constrain(
|
||||||
vars.master.heating.setpointTemp = 0.0f;
|
this->getHeatingSetpointTemp(),
|
||||||
|
this->getHeatingMinSetpointTemp(),
|
||||||
// tick if PID enabled
|
this->getHeatingMaxSetpointTemp()
|
||||||
if (settings.pid.enabled) {
|
), 0);
|
||||||
this->getHeatingSetpointTemp();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
vars.master.heating.targetTemp = settings.heating.target;
|
|
||||||
vars.master.heating.setpointTemp = roundf(constrain(
|
|
||||||
this->getHeatingSetpointTemp(),
|
|
||||||
this->getHeatingMinSetpointTemp(),
|
|
||||||
this->getHeatingMaxSetpointTemp()
|
|
||||||
), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sensors::setValueByType(
|
Sensors::setValueByType(
|
||||||
Sensors::Type::HEATING_SETPOINT_TEMP, vars.master.heating.setpointTemp,
|
Sensors::Type::HEATING_SETPOINT_TEMP, vars.master.heating.setpointTemp,
|
||||||
@@ -102,7 +91,7 @@ protected:
|
|||||||
void hysteresis() {
|
void hysteresis() {
|
||||||
bool useHyst = false;
|
bool useHyst = false;
|
||||||
if (settings.heating.hysteresis.enabled && this->indoorSensorsConnected) {
|
if (settings.heating.hysteresis.enabled && this->indoorSensorsConnected) {
|
||||||
useHyst = settings.equitherm.enabled || settings.pid.enabled || settings.opentherm.options.nativeHeatingControl;
|
useHyst = settings.equitherm.enabled || settings.pid.enabled || settings.opentherm.options.nativeOTC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useHyst) {
|
if (useHyst) {
|
||||||
@@ -119,13 +108,13 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline float getHeatingMinSetpointTemp() {
|
inline float getHeatingMinSetpointTemp() {
|
||||||
return settings.opentherm.options.nativeHeatingControl
|
return settings.opentherm.options.nativeOTC
|
||||||
? vars.master.heating.minTemp
|
? vars.master.heating.minTemp
|
||||||
: settings.heating.minTemp;
|
: settings.heating.minTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float getHeatingMaxSetpointTemp() {
|
inline float getHeatingMaxSetpointTemp() {
|
||||||
return settings.opentherm.options.nativeHeatingControl
|
return settings.opentherm.options.nativeOTC
|
||||||
? vars.master.heating.maxTemp
|
? vars.master.heating.maxTemp
|
||||||
: settings.heating.maxTemp;
|
: settings.heating.maxTemp;
|
||||||
}
|
}
|
||||||
@@ -146,7 +135,7 @@ protected:
|
|||||||
if (vars.emergency.state) {
|
if (vars.emergency.state) {
|
||||||
return settings.emergency.target;
|
return settings.emergency.target;
|
||||||
|
|
||||||
} else if (settings.opentherm.options.nativeHeatingControl) {
|
} else if (settings.opentherm.options.nativeOTC) {
|
||||||
return settings.heating.target;
|
return settings.heating.target;
|
||||||
|
|
||||||
} else if (!settings.equitherm.enabled && !settings.pid.enabled) {
|
} else if (!settings.equitherm.enabled && !settings.pid.enabled) {
|
||||||
@@ -251,6 +240,11 @@ protected:
|
|||||||
) * settings.heating.turboFactor;
|
) * settings.heating.turboFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If freezing, set temperature to no lower than low temp provided by freeze protection
|
||||||
|
if (vars.master.heating.freezing && fabsf(settings.heating.freezeProtection.lowTemp - newTemp) < 0.0001f) {
|
||||||
|
newTemp = settings.heating.freezeProtection.lowTemp;
|
||||||
|
}
|
||||||
|
|
||||||
return newTemp;
|
return newTemp;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public:
|
|||||||
OT_DHW_BURNER_HOURS = 24,
|
OT_DHW_BURNER_HOURS = 24,
|
||||||
OT_HEATING_PUMP_HOURS = 25,
|
OT_HEATING_PUMP_HOURS = 25,
|
||||||
OT_DHW_PUMP_HOURS = 26,
|
OT_DHW_PUMP_HOURS = 26,
|
||||||
|
OT_COOLING_HOURS = 27,
|
||||||
|
|
||||||
NTC_10K_TEMP = 50,
|
NTC_10K_TEMP = 50,
|
||||||
DALLAS_TEMP = 51,
|
DALLAS_TEMP = 51,
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const unsigned int disconnectedTimeout = 120000;
|
const unsigned int wiredDisconnectTimeout = 180000u;
|
||||||
|
const unsigned int wirelessDisconnectTimeout = 600000u;
|
||||||
const unsigned short dallasSearchInterval = 60000;
|
const unsigned short dallasSearchInterval = 60000;
|
||||||
const unsigned short dallasPollingInterval = 10000;
|
const unsigned short dallasPollingInterval = 10000;
|
||||||
const unsigned short globalPollingInterval = 15000;
|
const unsigned short globalPollingInterval = 15000;
|
||||||
@@ -1004,12 +1005,16 @@ protected:
|
|||||||
} else if (rSensor.connected && sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
} else if (rSensor.connected && sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||||
Sensors::setConnectionStatusById(sensorId, false, false);
|
Sensors::setConnectionStatusById(sensorId, false, false);
|
||||||
|
|
||||||
} else if (sSensor.type != Sensors::Type::MANUAL && rSensor.connected && (millis() - rSensor.activityTime) > this->disconnectedTimeout) {
|
} else if (rSensor.connected) {
|
||||||
Sensors::setConnectionStatusById(sensorId, false, false);
|
if (sSensor.type == Sensors::Type::MANUAL || sSensor.type == Sensors::Type::BLUETOOTH) {
|
||||||
|
if ((millis() - rSensor.activityTime) > this->wirelessDisconnectTimeout) {
|
||||||
|
Sensors::setConnectionStatusById(sensorId, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
}/* else if (!rSensor.connected) {
|
} else if ((millis() - rSensor.activityTime) > this->wiredDisconnectTimeout) {
|
||||||
rSensor.connected = true;
|
Sensors::setConnectionStatusById(sensorId, false, false);
|
||||||
}*/
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ struct Settings {
|
|||||||
bool autoFaultReset = false;
|
bool autoFaultReset = false;
|
||||||
bool autoDiagReset = false;
|
bool autoDiagReset = false;
|
||||||
bool setDateAndTime = false;
|
bool setDateAndTime = false;
|
||||||
bool nativeHeatingControl = false;
|
bool alwaysSendIndoorTemp = true;
|
||||||
|
bool nativeOTC = false;
|
||||||
bool immergasFix = false;
|
bool immergasFix = false;
|
||||||
} options;
|
} options;
|
||||||
} opentherm;
|
} opentherm;
|
||||||
@@ -120,8 +121,8 @@ struct Settings {
|
|||||||
} overheatProtection;
|
} overheatProtection;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
uint8_t highTemp = 15;
|
||||||
uint8_t lowTemp = 10;
|
uint8_t lowTemp = 10;
|
||||||
unsigned short thresholdTime = 600;
|
|
||||||
} freezeProtection;
|
} freezeProtection;
|
||||||
} heating;
|
} heating;
|
||||||
|
|
||||||
@@ -303,6 +304,7 @@ struct Variables {
|
|||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
bool indoorTempControl = false;
|
bool indoorTempControl = false;
|
||||||
bool overheat = false;
|
bool overheat = false;
|
||||||
|
bool freezing = false;
|
||||||
float setpointTemp = 0.0f;
|
float setpointTemp = 0.0f;
|
||||||
float targetTemp = 0.0f;
|
float targetTemp = 0.0f;
|
||||||
float currentTemp = 0.0f;
|
float currentTemp = 0.0f;
|
||||||
@@ -388,6 +390,7 @@ struct Variables {
|
|||||||
uint16_t dhwBurnerStarts = 0;
|
uint16_t dhwBurnerStarts = 0;
|
||||||
uint16_t heatingPumpStarts = 0;
|
uint16_t heatingPumpStarts = 0;
|
||||||
uint16_t dhwPumpStarts = 0;
|
uint16_t dhwPumpStarts = 0;
|
||||||
|
uint16_t coolingHours = 0;
|
||||||
uint16_t burnerHours = 0;
|
uint16_t burnerHours = 0;
|
||||||
uint16_t dhwBurnerHours = 0;
|
uint16_t dhwBurnerHours = 0;
|
||||||
uint16_t heatingPumpHours = 0;
|
uint16_t heatingPumpHours = 0;
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ const char S_EXTERNAL_PUMP[] PROGMEM = "externalPump";
|
|||||||
const char S_FACTOR[] PROGMEM = "factor";
|
const char S_FACTOR[] PROGMEM = "factor";
|
||||||
const char S_FAULT[] PROGMEM = "fault";
|
const char S_FAULT[] PROGMEM = "fault";
|
||||||
const char S_FREEZE_PROTECTION[] PROGMEM = "freezeProtection";
|
const char S_FREEZE_PROTECTION[] PROGMEM = "freezeProtection";
|
||||||
|
const char S_FREEZING[] PROGMEM = "freezing";
|
||||||
const char S_FILTERING[] PROGMEM = "filtering";
|
const char S_FILTERING[] PROGMEM = "filtering";
|
||||||
const char S_FILTERING_FACTOR[] PROGMEM = "filteringFactor";
|
const char S_FILTERING_FACTOR[] PROGMEM = "filteringFactor";
|
||||||
const char S_FLAGS[] PROGMEM = "flags";
|
const char S_FLAGS[] PROGMEM = "flags";
|
||||||
@@ -110,6 +111,7 @@ const char S_HYSTERESIS[] PROGMEM = "hysteresis";
|
|||||||
const char S_ID[] PROGMEM = "id";
|
const char S_ID[] PROGMEM = "id";
|
||||||
const char S_IGNORE_DIAG_STATE[] PROGMEM = "ignoreDiagState";
|
const char S_IGNORE_DIAG_STATE[] PROGMEM = "ignoreDiagState";
|
||||||
const char S_IMMERGAS_FIX[] PROGMEM = "immergasFix";
|
const char S_IMMERGAS_FIX[] PROGMEM = "immergasFix";
|
||||||
|
const char S_ALWAYS_SEND_INDOOR_TEMP[] PROGMEM = "alwaysSendIndoorTemp";
|
||||||
const char S_INDOOR_TEMP[] PROGMEM = "indoorTemp";
|
const char S_INDOOR_TEMP[] PROGMEM = "indoorTemp";
|
||||||
const char S_INDOOR_TEMP_CONTROL[] PROGMEM = "indoorTempControl";
|
const char S_INDOOR_TEMP_CONTROL[] PROGMEM = "indoorTempControl";
|
||||||
const char S_IN_GPIO[] PROGMEM = "inGpio";
|
const char S_IN_GPIO[] PROGMEM = "inGpio";
|
||||||
@@ -141,7 +143,7 @@ const char S_MODEL[] PROGMEM = "model";
|
|||||||
const char S_MODULATION[] PROGMEM = "modulation";
|
const char S_MODULATION[] PROGMEM = "modulation";
|
||||||
const char S_MQTT[] PROGMEM = "mqtt";
|
const char S_MQTT[] PROGMEM = "mqtt";
|
||||||
const char S_NAME[] PROGMEM = "name";
|
const char S_NAME[] PROGMEM = "name";
|
||||||
const char S_NATIVE_HEATING_CONTROL[] PROGMEM = "nativeHeatingControl";
|
const char S_NATIVE_OTC[] PROGMEM = "nativeOTC";
|
||||||
const char S_NETWORK[] PROGMEM = "network";
|
const char S_NETWORK[] PROGMEM = "network";
|
||||||
const char S_NTP[] PROGMEM = "ntp";
|
const char S_NTP[] PROGMEM = "ntp";
|
||||||
const char S_OFFSET[] PROGMEM = "offset";
|
const char S_OFFSET[] PROGMEM = "offset";
|
||||||
|
|||||||
76
src/utils.h
76
src/utils.h
@@ -468,8 +468,10 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
|||||||
otOptions[FPSTR(S_AUTO_FAULT_RESET)] = src.opentherm.options.autoFaultReset;
|
otOptions[FPSTR(S_AUTO_FAULT_RESET)] = src.opentherm.options.autoFaultReset;
|
||||||
otOptions[FPSTR(S_AUTO_DIAG_RESET)] = src.opentherm.options.autoDiagReset;
|
otOptions[FPSTR(S_AUTO_DIAG_RESET)] = src.opentherm.options.autoDiagReset;
|
||||||
otOptions[FPSTR(S_SET_DATE_AND_TIME)] = src.opentherm.options.setDateAndTime;
|
otOptions[FPSTR(S_SET_DATE_AND_TIME)] = src.opentherm.options.setDateAndTime;
|
||||||
otOptions[FPSTR(S_NATIVE_HEATING_CONTROL)] = src.opentherm.options.nativeHeatingControl;
|
otOptions[FPSTR(S_ALWAYS_SEND_INDOOR_TEMP)] = src.opentherm.options.alwaysSendIndoorTemp;
|
||||||
|
otOptions[FPSTR(S_NATIVE_OTC)] = src.opentherm.options.nativeOTC;
|
||||||
otOptions[FPSTR(S_IMMERGAS_FIX)] = src.opentherm.options.immergasFix;
|
otOptions[FPSTR(S_IMMERGAS_FIX)] = src.opentherm.options.immergasFix;
|
||||||
|
|
||||||
|
|
||||||
auto mqtt = dst[FPSTR(S_MQTT)].to<JsonObject>();
|
auto mqtt = dst[FPSTR(S_MQTT)].to<JsonObject>();
|
||||||
mqtt[FPSTR(S_ENABLED)] = src.mqtt.enabled;
|
mqtt[FPSTR(S_ENABLED)] = src.mqtt.enabled;
|
||||||
@@ -503,8 +505,8 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
|||||||
heatingOverheatProtection[FPSTR(S_LOW_TEMP)] = src.heating.overheatProtection.lowTemp;
|
heatingOverheatProtection[FPSTR(S_LOW_TEMP)] = src.heating.overheatProtection.lowTemp;
|
||||||
|
|
||||||
auto freezeProtection = heating[FPSTR(S_FREEZE_PROTECTION)].to<JsonObject>();
|
auto freezeProtection = heating[FPSTR(S_FREEZE_PROTECTION)].to<JsonObject>();
|
||||||
|
freezeProtection[FPSTR(S_HIGH_TEMP)] = src.heating.freezeProtection.highTemp;
|
||||||
freezeProtection[FPSTR(S_LOW_TEMP)] = src.heating.freezeProtection.lowTemp;
|
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<JsonObject>();
|
auto dhw = dst[FPSTR(S_DHW)].to<JsonObject>();
|
||||||
dhw[FPSTR(S_ENABLED)] = src.dhw.enabled;
|
dhw[FPSTR(S_ENABLED)] = src.dhw.enabled;
|
||||||
@@ -1003,11 +1005,20 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_HEATING_CONTROL)].is<bool>()) {
|
if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_ALWAYS_SEND_INDOOR_TEMP)].is<bool>()) {
|
||||||
bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_HEATING_CONTROL)].as<bool>();
|
bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_ALWAYS_SEND_INDOOR_TEMP)].as<bool>();
|
||||||
|
|
||||||
if (value != dst.opentherm.options.nativeHeatingControl) {
|
if (value != dst.opentherm.options.alwaysSendIndoorTemp) {
|
||||||
dst.opentherm.options.nativeHeatingControl = value;
|
dst.opentherm.options.alwaysSendIndoorTemp = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_OTC)].is<bool>()) {
|
||||||
|
bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_OTC)].as<bool>();
|
||||||
|
|
||||||
|
if (value != dst.opentherm.options.nativeOTC) {
|
||||||
|
dst.opentherm.options.nativeOTC = value;
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
dst.equitherm.enabled = false;
|
dst.equitherm.enabled = false;
|
||||||
@@ -1027,7 +1038,6 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// mqtt
|
// mqtt
|
||||||
if (src[FPSTR(S_MQTT)][FPSTR(S_ENABLED)].is<bool>()) {
|
if (src[FPSTR(S_MQTT)][FPSTR(S_ENABLED)].is<bool>()) {
|
||||||
bool value = src[FPSTR(S_MQTT)][FPSTR(S_ENABLED)].as<bool>();
|
bool value = src[FPSTR(S_MQTT)][FPSTR(S_ENABLED)].as<bool>();
|
||||||
@@ -1118,7 +1128,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
if (src[FPSTR(S_EQUITHERM)][FPSTR(S_ENABLED)].is<bool>()) {
|
if (src[FPSTR(S_EQUITHERM)][FPSTR(S_ENABLED)].is<bool>()) {
|
||||||
bool value = src[FPSTR(S_EQUITHERM)][FPSTR(S_ENABLED)].as<bool>();
|
bool value = src[FPSTR(S_EQUITHERM)][FPSTR(S_ENABLED)].as<bool>();
|
||||||
|
|
||||||
if (!dst.opentherm.options.nativeHeatingControl) {
|
if (!dst.opentherm.options.nativeOTC) {
|
||||||
if (value != dst.equitherm.enabled) {
|
if (value != dst.equitherm.enabled) {
|
||||||
dst.equitherm.enabled = value;
|
dst.equitherm.enabled = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
@@ -1171,7 +1181,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
if (src[FPSTR(S_PID)][FPSTR(S_ENABLED)].is<bool>()) {
|
if (src[FPSTR(S_PID)][FPSTR(S_ENABLED)].is<bool>()) {
|
||||||
bool value = src[FPSTR(S_PID)][FPSTR(S_ENABLED)].as<bool>();
|
bool value = src[FPSTR(S_PID)][FPSTR(S_ENABLED)].as<bool>();
|
||||||
|
|
||||||
if (!dst.opentherm.options.nativeHeatingControl) {
|
if (!dst.opentherm.options.nativeOTC) {
|
||||||
if (value != dst.pid.enabled) {
|
if (value != dst.pid.enabled) {
|
||||||
dst.pid.enabled = value;
|
dst.pid.enabled = value;
|
||||||
changed = true;
|
changed = true;
|
||||||
@@ -1416,6 +1426,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
changed = true;
|
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<uint8_t>();
|
||||||
|
|
||||||
|
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()) {
|
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<uint8_t>();
|
unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_LOW_TEMP)].as<uint8_t>();
|
||||||
|
|
||||||
@@ -1425,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()) {
|
if (dst.heating.freezeProtection.highTemp < dst.heating.freezeProtection.lowTemp) {
|
||||||
unsigned short value = src[FPSTR(S_HEATING)][FPSTR(S_FREEZE_PROTECTION)][FPSTR(S_THRESHOLD_TIME)].as<unsigned short>();
|
dst.heating.freezeProtection.highTemp = dst.heating.freezeProtection.lowTemp;
|
||||||
|
changed = true;
|
||||||
if (value >= 30 && value <= 1800) {
|
|
||||||
if (value != dst.heating.freezeProtection.thresholdTime) {
|
|
||||||
dst.heating.freezeProtection.thresholdTime = value;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1704,7 +1717,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
// force check emergency target
|
// force check emergency target
|
||||||
{
|
{
|
||||||
float value = !src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].isNull() ? src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].as<float>() : dst.emergency.target;
|
float value = !src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].isNull() ? src[FPSTR(S_EMERGENCY)][FPSTR(S_TARGET)].as<float>() : dst.emergency.target;
|
||||||
bool noRegulators = !dst.opentherm.options.nativeHeatingControl;
|
bool noRegulators = !dst.opentherm.options.nativeOTC;
|
||||||
bool valid = isValidTemp(
|
bool valid = isValidTemp(
|
||||||
value,
|
value,
|
||||||
dst.system.unitSystem,
|
dst.system.unitSystem,
|
||||||
@@ -1729,7 +1742,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
|
|
||||||
// force check heating target
|
// force check heating target
|
||||||
{
|
{
|
||||||
bool indoorTempControl = dst.equitherm.enabled || dst.pid.enabled || dst.opentherm.options.nativeHeatingControl;
|
bool indoorTempControl = dst.equitherm.enabled || dst.pid.enabled || dst.opentherm.options.nativeOTC;
|
||||||
float minTemp = indoorTempControl ? THERMOSTAT_INDOOR_MIN_TEMP : dst.heating.minTemp;
|
float minTemp = indoorTempControl ? THERMOSTAT_INDOOR_MIN_TEMP : dst.heating.minTemp;
|
||||||
float maxTemp = indoorTempControl ? THERMOSTAT_INDOOR_MAX_TEMP : dst.heating.maxTemp;
|
float maxTemp = indoorTempControl ? THERMOSTAT_INDOOR_MAX_TEMP : dst.heating.maxTemp;
|
||||||
|
|
||||||
@@ -1922,6 +1935,7 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se
|
|||||||
case static_cast<uint8_t>(Sensors::Type::OT_DHW_BURNER_HOURS):
|
case static_cast<uint8_t>(Sensors::Type::OT_DHW_BURNER_HOURS):
|
||||||
case static_cast<uint8_t>(Sensors::Type::OT_HEATING_PUMP_HOURS):
|
case static_cast<uint8_t>(Sensors::Type::OT_HEATING_PUMP_HOURS):
|
||||||
case static_cast<uint8_t>(Sensors::Type::OT_DHW_PUMP_HOURS):
|
case static_cast<uint8_t>(Sensors::Type::OT_DHW_PUMP_HOURS):
|
||||||
|
case static_cast<uint8_t>(Sensors::Type::OT_COOLING_HOURS):
|
||||||
|
|
||||||
case static_cast<uint8_t>(Sensors::Type::NTC_10K_TEMP):
|
case static_cast<uint8_t>(Sensors::Type::NTC_10K_TEMP):
|
||||||
case static_cast<uint8_t>(Sensors::Type::DALLAS_TEMP):
|
case static_cast<uint8_t>(Sensors::Type::DALLAS_TEMP):
|
||||||
@@ -2098,21 +2112,18 @@ bool jsonToSensorResult(const uint8_t sensorId, const JsonVariantConst src) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& dst = Sensors::results[sensorId];
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
// value
|
// value
|
||||||
if (!src[FPSTR(S_VALUE)].isNull()) {
|
if (!src[FPSTR(S_VALUE)].isNull()) {
|
||||||
float value = src[FPSTR(S_VALUE)].as<float>();
|
return Sensors::setValueById(
|
||||||
|
sensorId,
|
||||||
uint8_t vType = static_cast<uint8_t>(Sensors::ValueType::PRIMARY);
|
src[FPSTR(S_VALUE)].as<float>(),
|
||||||
if (fabsf(value - dst.values[vType]) > 0.0001f) {
|
Sensors::ValueType::PRIMARY,
|
||||||
dst.values[vType] = roundf(value, 2);
|
true,
|
||||||
changed = true;
|
true
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void varsToJson(const Variables& src, JsonVariant dst) {
|
void varsToJson(const Variables& src, JsonVariant dst) {
|
||||||
@@ -2121,7 +2132,7 @@ void varsToJson(const Variables& src, JsonVariant dst) {
|
|||||||
slave[FPSTR(S_FLAGS)] = src.slave.flags;
|
slave[FPSTR(S_FLAGS)] = src.slave.flags;
|
||||||
slave[FPSTR(S_TYPE)] = src.slave.type;
|
slave[FPSTR(S_TYPE)] = src.slave.type;
|
||||||
slave[FPSTR(S_APP_VERSION)] = src.slave.appVersion;
|
slave[FPSTR(S_APP_VERSION)] = src.slave.appVersion;
|
||||||
slave[FPSTR(S_PROTOCOL_VERSION)] = src.slave.appVersion;
|
slave[FPSTR(S_PROTOCOL_VERSION)] = src.slave.protocolVersion;
|
||||||
slave[FPSTR(S_CONNECTED)] = src.slave.connected;
|
slave[FPSTR(S_CONNECTED)] = src.slave.connected;
|
||||||
slave[FPSTR(S_FLAME)] = src.slave.flame;
|
slave[FPSTR(S_FLAME)] = src.slave.flame;
|
||||||
|
|
||||||
@@ -2162,6 +2173,7 @@ void varsToJson(const Variables& src, JsonVariant dst) {
|
|||||||
mHeating[FPSTR(S_BLOCKING)] = src.master.heating.blocking;
|
mHeating[FPSTR(S_BLOCKING)] = src.master.heating.blocking;
|
||||||
mHeating[FPSTR(S_INDOOR_TEMP_CONTROL)] = src.master.heating.indoorTempControl;
|
mHeating[FPSTR(S_INDOOR_TEMP_CONTROL)] = src.master.heating.indoorTempControl;
|
||||||
mHeating[FPSTR(S_OVERHEAT)] = src.master.heating.overheat;
|
mHeating[FPSTR(S_OVERHEAT)] = src.master.heating.overheat;
|
||||||
|
mHeating[FPSTR(S_FREEZING)] = src.master.heating.freezing;
|
||||||
mHeating[FPSTR(S_SETPOINT_TEMP)] = roundf(src.master.heating.setpointTemp, 2);
|
mHeating[FPSTR(S_SETPOINT_TEMP)] = roundf(src.master.heating.setpointTemp, 2);
|
||||||
mHeating[FPSTR(S_TARGET_TEMP)] = roundf(src.master.heating.targetTemp, 2);
|
mHeating[FPSTR(S_TARGET_TEMP)] = roundf(src.master.heating.targetTemp, 2);
|
||||||
mHeating[FPSTR(S_CURRENT_TEMP)] = roundf(src.master.heating.currentTemp, 2);
|
mHeating[FPSTR(S_CURRENT_TEMP)] = roundf(src.master.heating.currentTemp, 2);
|
||||||
|
|||||||
@@ -243,6 +243,7 @@
|
|||||||
"otDhwBurnerHours": "OpenTherm, number of burner operating hours (DHW)",
|
"otDhwBurnerHours": "OpenTherm, number of burner operating hours (DHW)",
|
||||||
"otHeatingPumpHours": "OpenTherm, number of pump operating hours (heating)",
|
"otHeatingPumpHours": "OpenTherm, number of pump operating hours (heating)",
|
||||||
"otDhwPumpHours": "OpenTherm, number of pump operating hours (DHW)",
|
"otDhwPumpHours": "OpenTherm, number of pump operating hours (DHW)",
|
||||||
|
"otCoolingHours": "OpenTherm, number of cooling hours",
|
||||||
|
|
||||||
"ntcTemp": "NTC 传感器",
|
"ntcTemp": "NTC 传感器",
|
||||||
"dallasTemp": "DALLAS 传感器",
|
"dallasTemp": "DALLAS 传感器",
|
||||||
@@ -319,9 +320,15 @@
|
|||||||
},
|
},
|
||||||
"freezeProtection": {
|
"freezeProtection": {
|
||||||
"title": "防冻保护",
|
"title": "防冻保护",
|
||||||
"desc": "当热媒或室内温度在<b>等待时间</b> 内降至<b>低温阈值</b>以下时,系统将强制启动加热功能。",
|
"desc": "如果热载体或室内温度低于 <b>低温</b>,加热将被强制开启。",
|
||||||
"lowTemp": "低温阈值",
|
"highTemp": {
|
||||||
"thresholdTime": "等待时间<small>(秒)</small>"
|
"title": "高温阈值",
|
||||||
|
"note": "防冻保护激活后系统恢复正常模式的阈值"
|
||||||
|
},
|
||||||
|
"lowTemp": {
|
||||||
|
"title": "低温阈值",
|
||||||
|
"note": "强制开启加热的阈值"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"portal": {
|
"portal": {
|
||||||
@@ -457,12 +464,13 @@
|
|||||||
"autoFaultReset": "自动报警复位 <small>(不推荐!)</small>",
|
"autoFaultReset": "自动报警复位 <small>(不推荐!)</small>",
|
||||||
"autoDiagReset": "自动诊断复位 <small>(不推荐!)</small>",
|
"autoDiagReset": "自动诊断复位 <small>(不推荐!)</small>",
|
||||||
"setDateAndTime": "同步设置锅炉日期与时间",
|
"setDateAndTime": "同步设置锅炉日期与时间",
|
||||||
"immergasFix": "针对Immergas锅炉的兼容性修复"
|
"immergasFix": "针对Immergas锅炉的兼容性修复",
|
||||||
|
"alwaysSendIndoorTemp": "向锅炉发送当前室内温度"
|
||||||
},
|
},
|
||||||
|
|
||||||
"nativeHeating": {
|
"nativeOTC": {
|
||||||
"title": "原生锅炉供暖控制",
|
"title": "原生热载体温度计算模式",
|
||||||
"note": "<u>注意:</u> 仅适用于锅炉需接收目标室温并自主调节载热介质温度的场景,与固件中的PID及Equithermq气候补偿功能不兼容。"
|
"note": "仅在锅炉处于 OTC 模式时<u>才</u>工作:需要并接受目标室内温度,并基于内置曲线模式自行调节热载体温度。与 PID 和 Equitherm 不兼容。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,7 @@
|
|||||||
"mHeatEnabled": "Heating enabled",
|
"mHeatEnabled": "Heating enabled",
|
||||||
"mHeatBlocking": "Heating blocked",
|
"mHeatBlocking": "Heating blocked",
|
||||||
"mHeatOverheat": "Heating overheat",
|
"mHeatOverheat": "Heating overheat",
|
||||||
|
"mHeatFreezing": "Heating freezing",
|
||||||
"sHeatActive": "Heating active",
|
"sHeatActive": "Heating active",
|
||||||
"mHeatSetpointTemp": "Heating setpoint temp",
|
"mHeatSetpointTemp": "Heating setpoint temp",
|
||||||
"mHeatTargetTemp": "Heating target temp",
|
"mHeatTargetTemp": "Heating target temp",
|
||||||
@@ -243,6 +244,7 @@
|
|||||||
"otDhwBurnerHours": "OpenTherm, number of burner operating hours (DHW)",
|
"otDhwBurnerHours": "OpenTherm, number of burner operating hours (DHW)",
|
||||||
"otHeatingPumpHours": "OpenTherm, number of pump operating hours (heating)",
|
"otHeatingPumpHours": "OpenTherm, number of pump operating hours (heating)",
|
||||||
"otDhwPumpHours": "OpenTherm, number of pump operating hours (DHW)",
|
"otDhwPumpHours": "OpenTherm, number of pump operating hours (DHW)",
|
||||||
|
"otCoolingHours": "OpenTherm, number of cooling hours",
|
||||||
|
|
||||||
"ntcTemp": "NTC sensor",
|
"ntcTemp": "NTC sensor",
|
||||||
"dallasTemp": "DALLAS sensor",
|
"dallasTemp": "DALLAS sensor",
|
||||||
@@ -319,9 +321,15 @@
|
|||||||
},
|
},
|
||||||
"freezeProtection": {
|
"freezeProtection": {
|
||||||
"title": "Freeze protection",
|
"title": "Freeze protection",
|
||||||
"desc": "Heating will be forced to turn on if the heat carrier or indoor temperature drops below <b>Low temperature</b> during <b>Waiting time</b>.",
|
"desc": "Heating will be forced to turn on if the heat carrier or indoor temperature drops below <b>Low temperature</b>.",
|
||||||
"lowTemp": "Low temperature threshold",
|
"highTemp": {
|
||||||
"thresholdTime": "Waiting time <small>(sec)</small>"
|
"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": {
|
"portal": {
|
||||||
@@ -457,12 +465,13 @@
|
|||||||
"autoFaultReset": "Auto fault reset <small>(not recommended!)</small>",
|
"autoFaultReset": "Auto fault reset <small>(not recommended!)</small>",
|
||||||
"autoDiagReset": "Auto diag reset <small>(not recommended!)</small>",
|
"autoDiagReset": "Auto diag reset <small>(not recommended!)</small>",
|
||||||
"setDateAndTime": "Set date & time on boiler",
|
"setDateAndTime": "Set date & time on boiler",
|
||||||
"immergasFix": "Fix for Immergas boilers"
|
"immergasFix": "Fix for Immergas boilers",
|
||||||
|
"alwaysSendIndoorTemp": "Send current indoor temp to boiler"
|
||||||
},
|
},
|
||||||
|
|
||||||
"nativeHeating": {
|
"nativeOTC": {
|
||||||
"title": "Native heating control (boiler)",
|
"title": "Native OTC mode",
|
||||||
"note": "Works <u>ONLY</u> if the boiler requires the desired room temperature and regulates the temperature of the coolant itself. Not compatible with PID and Equitherm regulators in firmware."
|
"note": "Works <u>ONLY</u> if the boiler is in OTC mode: requires and accepts the target indoor temperature and self-regulates the heat carrier temperature based on the built-in curves mode. Incompatible with PID and Equitherm."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -243,6 +243,7 @@
|
|||||||
"otDhwBurnerHours": "OpenTherm, numero di ore di funzionamento del bruciatore (ACS)",
|
"otDhwBurnerHours": "OpenTherm, numero di ore di funzionamento del bruciatore (ACS)",
|
||||||
"otHeatingPumpHours": "OpenTherm, numero di ore di funzionamento della pompa (riscaldamento)",
|
"otHeatingPumpHours": "OpenTherm, numero di ore di funzionamento della pompa (riscaldamento)",
|
||||||
"otDhwPumpHours": "OpenTherm, numero di ore di funzionamento della pompa (ACS)",
|
"otDhwPumpHours": "OpenTherm, numero di ore di funzionamento della pompa (ACS)",
|
||||||
|
"otCoolingHours": "OpenTherm, numero di ore di funzionamento della cooling",
|
||||||
|
|
||||||
"ntcTemp": "Sensore NTC",
|
"ntcTemp": "Sensore NTC",
|
||||||
"dallasTemp": "Sensore DALLAS",
|
"dallasTemp": "Sensore DALLAS",
|
||||||
@@ -319,9 +320,15 @@
|
|||||||
},
|
},
|
||||||
"freezeProtection": {
|
"freezeProtection": {
|
||||||
"title": "Protezione antigelo",
|
"title": "Protezione antigelo",
|
||||||
"desc": "Il riscaldamento verrà attivato forzatamente se la temperatura del vettore di calore o interna scende al di sotto della <b>temperatura minima</b> durante il <b>tempo di attesa</b>.",
|
"desc": "Il riscaldamento verrà forzatamente attivato se la temperatura del vettore termico o la temperatura interna scende al di sotto della <b>Soglia di temperatura bassa</b>.",
|
||||||
"lowTemp": "Soglia di temperatura minima",
|
"highTemp": {
|
||||||
"thresholdTime": "Tempo di attesa <small>(sec)</small>"
|
"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": {
|
"portal": {
|
||||||
@@ -457,12 +464,13 @@
|
|||||||
"autoFaultReset": "Ripristino automatico degli errori <small>(sconsigliato!)</small>",
|
"autoFaultReset": "Ripristino automatico degli errori <small>(sconsigliato!)</small>",
|
||||||
"autoDiagReset": "Ripristino diagnostico automatica <small>(sconsigliato!)</small>",
|
"autoDiagReset": "Ripristino diagnostico automatica <small>(sconsigliato!)</small>",
|
||||||
"setDateAndTime": "Imposta data e ora sulla caldaia",
|
"setDateAndTime": "Imposta data e ora sulla caldaia",
|
||||||
"immergasFix": "Fix per caldiaie Immergas"
|
"immergasFix": "Fix per caldiaie Immergas",
|
||||||
|
"alwaysSendIndoorTemp": "Invia la temp attuale interna alla caldaia"
|
||||||
},
|
},
|
||||||
|
|
||||||
"nativeHeating": {
|
"nativeOTC": {
|
||||||
"title": "Controllo del riscaldamento nativo (caldaia)",
|
"title": "Modalità nativa di calcolo della temperatura del vettore termico",
|
||||||
"note": "Lavora <u>SOLO</u> se la caldaia richiede la temperatura ambiente desiderata e regola autonomamente la temperatura del fluido. Non compatiblile con regolazioni PID e Equitherm del sistema."
|
"note": "Funziona <u>SOLO</u> se la caldaia è in modalità OTC: richiede e accetta la temperatura interna target e regola autonomamente la temperatura del vettore termico basata sulla modalità curve integrata. Incompatibile con PID e Equitherm."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -222,6 +222,8 @@
|
|||||||
"otDhwBurnerHours": "OpenTherm, aantal branderuren (warm water)",
|
"otDhwBurnerHours": "OpenTherm, aantal branderuren (warm water)",
|
||||||
"otHeatingPumpHours": "OpenTherm, aantal pompuren (verwarming)",
|
"otHeatingPumpHours": "OpenTherm, aantal pompuren (verwarming)",
|
||||||
"otDhwPumpHours": "OpenTherm, aantal pompuren (warm water)",
|
"otDhwPumpHours": "OpenTherm, aantal pompuren (warm water)",
|
||||||
|
"otCoolingHours": "OpenTherm, aantal cooling",
|
||||||
|
|
||||||
"ntcTemp": "NTC-sensor",
|
"ntcTemp": "NTC-sensor",
|
||||||
"dallasTemp": "DALLAS-sensor",
|
"dallasTemp": "DALLAS-sensor",
|
||||||
"bluetooth": "BLE-sensor",
|
"bluetooth": "BLE-sensor",
|
||||||
@@ -292,11 +294,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"freezeProtection": {
|
"freezeProtection": {
|
||||||
"title": "Vorstbeveiliging",
|
"title": "Vorbeveiliging",
|
||||||
"desc": "De verwarming wordt geforceerd ingeschakeld als de temperatuur van de warmtedrager of de binnentemperatuur onder de <b>Lage temperatuur</b> daalt gedurende de <b>Wachttijd</b>.",
|
"desc": "Verwarming zal geforceerd worden ingeschakeld als de temperatuur van de warmtedrager of de binnentemperatuur daalt onder de <b>Lage temperatuurdrempel</b>.",
|
||||||
"lowTemp": "Drempelwaarde lage temperatuur",
|
"highTemp": {
|
||||||
"thresholdTime": "Wachttijd <small>(sec)</small>"
|
"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": {
|
"portal": {
|
||||||
"login": "Gebruikersnaam",
|
"login": "Gebruikersnaam",
|
||||||
"password": "Wachtwoord",
|
"password": "Wachtwoord",
|
||||||
@@ -422,11 +431,13 @@
|
|||||||
"autoFaultReset": "Automatische storingsreset <small>(niet aanbevolen!)</small>",
|
"autoFaultReset": "Automatische storingsreset <small>(niet aanbevolen!)</small>",
|
||||||
"autoDiagReset": "Automatische diagnosereset <small>(niet aanbevolen!)</small>",
|
"autoDiagReset": "Automatische diagnosereset <small>(niet aanbevolen!)</small>",
|
||||||
"setDateAndTime": "Stel datum & tijd in op ketel",
|
"setDateAndTime": "Stel datum & tijd in op ketel",
|
||||||
"immergasFix": "Fix voor Immergas-ketels"
|
"immergasFix": "Fix voor Immergas-ketels",
|
||||||
|
"alwaysSendIndoorTemp": "Stuur huidige binnentemp naar ketel"
|
||||||
},
|
},
|
||||||
"nativeHeating": {
|
|
||||||
"title": "Natuurlijke verwarmingsregeling (ketel)",
|
"nativeOTC": {
|
||||||
"note": "Werkt <u>ALLEEN</u> als de ketel de gewenste kamertemperatuur vereist en zelf de temperatuur van de warmtedrager regelt. Niet compatibel met PID- en Equitherm-regelaars in de firmware."
|
"title": "Native warmtedrager temperatuur berekeningsmodus",
|
||||||
|
"note": "Werkt <u>ALLEEN</u> als de ketel in OTC-modus is: vereist en accepteert de doel binnentemperatuur en regelt zelf de warmtedrager temperatuur op basis van de ingebouwde curves modus. Incompatibel met PID en Equitherm."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
|
|||||||
@@ -243,6 +243,7 @@
|
|||||||
"otDhwBurnerHours": "OpenTherm, кол-во часов работы горелки (ГВС)",
|
"otDhwBurnerHours": "OpenTherm, кол-во часов работы горелки (ГВС)",
|
||||||
"otHeatingPumpHours": "OpenTherm, кол-во часов работы насоса (отопление)",
|
"otHeatingPumpHours": "OpenTherm, кол-во часов работы насоса (отопление)",
|
||||||
"otDhwPumpHours": "OpenTherm, кол-во часов работы насоса (ГВС)",
|
"otDhwPumpHours": "OpenTherm, кол-во часов работы насоса (ГВС)",
|
||||||
|
"otCoolingHours": "OpenTherm, кол-во часов работы охлаждения",
|
||||||
|
|
||||||
"ntcTemp": "NTC датчик",
|
"ntcTemp": "NTC датчик",
|
||||||
"dallasTemp": "DALLAS датчик",
|
"dallasTemp": "DALLAS датчик",
|
||||||
@@ -319,9 +320,15 @@
|
|||||||
},
|
},
|
||||||
"freezeProtection": {
|
"freezeProtection": {
|
||||||
"title": "Защита от замерзания",
|
"title": "Защита от замерзания",
|
||||||
"desc": "Отопление будет принудительно включено, если темп. теплоносителя или внутренняя темп. опустится ниже <b>нижнего порога</b> в течение <b>времени ожидания</b>.",
|
"desc": "Отопление будет принудительно включено, если темп. теплоносителя или внутренняя темп. опустится ниже <b>нижнего порога</b>.",
|
||||||
"lowTemp": "Нижний порог температуры",
|
"highTemp": {
|
||||||
"thresholdTime": "Время ожидания <small>(сек)</small>"
|
"title": "Верхний порог температуры",
|
||||||
|
"note": "Порог, при котором система вернется в нормальное состояние после активации защиты от замерзания"
|
||||||
|
},
|
||||||
|
"lowTemp": {
|
||||||
|
"title": "Нижний порог температуры",
|
||||||
|
"note": "Порог, при котором отопление будет принудительно включено"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"portal": {
|
"portal": {
|
||||||
@@ -457,12 +464,13 @@
|
|||||||
"autoFaultReset": "Автоматический сброс ошибок <small>(не рекомендуется!)</small>",
|
"autoFaultReset": "Автоматический сброс ошибок <small>(не рекомендуется!)</small>",
|
||||||
"autoDiagReset": "Автоматический сброс диагностики <small>(не рекомендуется!)</small>",
|
"autoDiagReset": "Автоматический сброс диагностики <small>(не рекомендуется!)</small>",
|
||||||
"setDateAndTime": "Устанавливать время и дату на котле",
|
"setDateAndTime": "Устанавливать время и дату на котле",
|
||||||
"immergasFix": "Фикс для котлов Immergas"
|
"immergasFix": "Фикс для котлов Immergas",
|
||||||
|
"alwaysSendIndoorTemp": "Передавать текущую темп. в помещении котлу"
|
||||||
},
|
},
|
||||||
|
|
||||||
"nativeHeating": {
|
"nativeOTC": {
|
||||||
"title": "Передать управление отоплением котлу",
|
"title": "Нативный режим OTC (расчёт температуры теплоносителя)",
|
||||||
"note": "Работает <u>ТОЛЬКО</u> если котел требует и принимает целевую температуру в помещении и сам регулирует температуру теплоносителя на основе встроенного режима кривых. Несовместимо с ПИД и ПЗА."
|
"note": "Работает <u>ТОЛЬКО</u> если котел в режиме OTC: требует и принимает целевую температуру в помещении и сам регулирует температуру теплоносителя на основе встроенного режима кривых. Несовместимо с ПИД и ПЗА."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,10 @@
|
|||||||
<th scope="row" data-i18n>dashboard.states.mHeatOverheat</th>
|
<th scope="row" data-i18n>dashboard.states.mHeatOverheat</th>
|
||||||
<td><i class="mHeatOverheat"></i></td>
|
<td><i class="mHeatOverheat"></i></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row" data-i18n>dashboard.states.mHeatFreezing</th>
|
||||||
|
<td><i class="mHeatFreezing"></i></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" data-i18n>dashboard.states.sHeatActive</th>
|
<th scope="row" data-i18n>dashboard.states.sHeatActive</th>
|
||||||
<td><i class="sHeatActive"></i></td>
|
<td><i class="sHeatActive"></i></td>
|
||||||
@@ -633,6 +637,11 @@
|
|||||||
result.master.heating.overheat ? "success" : "error",
|
result.master.heating.overheat ? "success" : "error",
|
||||||
result.master.heating.overheat ? "red" : "green"
|
result.master.heating.overheat ? "red" : "green"
|
||||||
);
|
);
|
||||||
|
setStatus(
|
||||||
|
'.mHeatFreezing',
|
||||||
|
result.master.heating.freezing ? "success" : "error",
|
||||||
|
result.master.heating.freezing ? "red" : "green"
|
||||||
|
);
|
||||||
setValue('.mHeatSetpointTemp', result.master.heating.setpointTemp);
|
setValue('.mHeatSetpointTemp', result.master.heating.setpointTemp);
|
||||||
setValue('.mHeatTargetTemp', result.master.heating.targetTemp);
|
setValue('.mHeatTargetTemp', result.master.heating.targetTemp);
|
||||||
setValue('.mHeatCurrTemp', result.master.heating.currentTemp);
|
setValue('.mHeatCurrTemp', result.master.heating.currentTemp);
|
||||||
|
|||||||
@@ -113,6 +113,7 @@
|
|||||||
<option value="24" data-i18n>sensors.types.otDhwBurnerHours</option>
|
<option value="24" data-i18n>sensors.types.otDhwBurnerHours</option>
|
||||||
<option value="25" data-i18n>sensors.types.otHeatingPumpHours</option>
|
<option value="25" data-i18n>sensors.types.otHeatingPumpHours</option>
|
||||||
<option value="26" data-i18n>sensors.types.otDhwPumpHours</option>
|
<option value="26" data-i18n>sensors.types.otDhwPumpHours</option>
|
||||||
|
<option value="27" data-i18n>sensors.types.otCoolingHours</option>
|
||||||
|
|
||||||
<option value="50" data-i18n>sensors.types.ntcTemp</option>
|
<option value="50" data-i18n>sensors.types.ntcTemp</option>
|
||||||
<option value="51" data-i18n>sensors.types.dallasTemp</option>
|
<option value="51" data-i18n>sensors.types.dallasTemp</option>
|
||||||
|
|||||||
@@ -265,13 +265,15 @@
|
|||||||
|
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<label>
|
<label>
|
||||||
<span data-i18n>settings.freezeProtection.lowTemp</span>
|
<span data-i18n>settings.freezeProtection.highTemp.title</span>
|
||||||
<input type="number" inputmode="numeric" name="heating[freezeProtection][lowTemp]" min="0" max="0" step="1" required>
|
<input type="number" inputmode="numeric" name="heating[freezeProtection][highTemp]" min="0" max="0" step="1" required>
|
||||||
|
<small data-i18n>settings.freezeProtection.highTemp.note</small>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<span data-i18n>settings.freezeProtection.thresholdTime</span>
|
<span data-i18n>settings.freezeProtection.lowTemp.title</span>
|
||||||
<input type="number" inputmode="numeric" name="heating[freezeProtection][thresholdTime]" min="30" max="1800" step="1" required>
|
<input type="number" inputmode="numeric" name="heating[freezeProtection][lowTemp]" min="0" max="0" step="1" required>
|
||||||
|
<small data-i18n>settings.freezeProtection.lowTemp.note</small>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -692,12 +694,17 @@
|
|||||||
<span data-i18n>settings.ot.options.immergasFix</span>
|
<span data-i18n>settings.ot.options.immergasFix</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="opentherm[options][alwaysSendIndoorTemp]" value="true">
|
||||||
|
<span data-i18n>settings.ot.options.alwaysSendIndoorTemp</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="opentherm[options][nativeHeatingControl]" value="true">
|
<input type="checkbox" name="opentherm[options][nativeOTC]" value="true">
|
||||||
<span data-i18n>settings.ot.nativeHeating.title</span><br />
|
<span data-i18n>settings.ot.nativeOTC.title</span><br />
|
||||||
<small data-i18n>settings.ot.nativeHeating.note</small>
|
<small data-i18n>settings.ot.nativeOTC.note</small>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
@@ -1117,8 +1124,9 @@
|
|||||||
setCheckboxValue("[name='opentherm[options][autoFaultReset]']", data.opentherm.options.autoFaultReset);
|
setCheckboxValue("[name='opentherm[options][autoFaultReset]']", data.opentherm.options.autoFaultReset);
|
||||||
setCheckboxValue("[name='opentherm[options][autoDiagReset]']", data.opentherm.options.autoDiagReset);
|
setCheckboxValue("[name='opentherm[options][autoDiagReset]']", data.opentherm.options.autoDiagReset);
|
||||||
setCheckboxValue("[name='opentherm[options][setDateAndTime]']", data.opentherm.options.setDateAndTime);
|
setCheckboxValue("[name='opentherm[options][setDateAndTime]']", data.opentherm.options.setDateAndTime);
|
||||||
setCheckboxValue("[name='opentherm[options][nativeHeatingControl]']", data.opentherm.options.nativeHeatingControl);
|
setCheckboxValue("[name='opentherm[options][nativeOTC]']", data.opentherm.options.nativeOTC);
|
||||||
setCheckboxValue("[name='opentherm[options][immergasFix]']", data.opentherm.options.immergasFix);
|
setCheckboxValue("[name='opentherm[options][immergasFix]']", data.opentherm.options.immergasFix);
|
||||||
|
setCheckboxValue("[name='opentherm[options][alwaysSendIndoorTemp]']", data.opentherm.options.alwaysSendIndoorTemp);
|
||||||
setBusy('#ot-settings-busy', '#ot-settings', false);
|
setBusy('#ot-settings-busy', '#ot-settings', false);
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
@@ -1178,11 +1186,14 @@
|
|||||||
"min": 0,
|
"min": 0,
|
||||||
"max": data.system.unitSystem == 0 ? 99 : 211
|
"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, {
|
setInputValue("[name='heating[freezeProtection][lowTemp]']", data.heating.freezeProtection.lowTemp, {
|
||||||
"min": data.system.unitSystem == 0 ? 1 : 34,
|
"min": data.system.unitSystem == 0 ? 1 : 34,
|
||||||
"max": data.system.unitSystem == 0 ? 30 : 86
|
"max": data.system.unitSystem == 0 ? 30 : 86
|
||||||
});
|
});
|
||||||
setInputValue("[name='heating[freezeProtection][thresholdTime]']", data.heating.freezeProtection.thresholdTime);
|
|
||||||
setBusy('#heating-settings-busy', '#heating-settings', false);
|
setBusy('#heating-settings-busy', '#heating-settings', false);
|
||||||
|
|
||||||
// DHW
|
// DHW
|
||||||
@@ -1206,7 +1217,7 @@
|
|||||||
setBusy('#dhw-settings-busy', '#dhw-settings', false);
|
setBusy('#dhw-settings-busy', '#dhw-settings', false);
|
||||||
|
|
||||||
// Emergency mode
|
// Emergency mode
|
||||||
if (data.opentherm.options.nativeHeatingControl) {
|
if (data.opentherm.options.nativeOTC) {
|
||||||
setInputValue("[name='emergency[target]']", data.emergency.target, {
|
setInputValue("[name='emergency[target]']", data.emergency.target, {
|
||||||
"min": data.system.unitSystem == 0 ? 5 : 41,
|
"min": data.system.unitSystem == 0 ? 5 : 41,
|
||||||
"max": data.system.unitSystem == 0 ? 40 : 104
|
"max": data.system.unitSystem == 0 ? 40 : 104
|
||||||
|
|||||||
Reference in New Issue
Block a user