2 Commits

Author SHA1 Message Date
Yurii
8641f9f1e4 feat: added OT option alwaysSetIndoorTemp #180 2025-12-10 17:31:19 +03:00
Yurii
c9fee6f1eb chore: bump version to 1.6.0 2025-12-10 17:16:20 +03:00
16 changed files with 170 additions and 290 deletions

View File

@@ -70,89 +70,50 @@ public:
} }
} }
inline auto sendBoilerReset() { bool sendBoilerReset() {
return this->sendRequestCode(1); unsigned int data = 1;
} data <<= 8;
inline auto sendServiceReset() {
return this->sendRequestCode(10);
}
inline auto sendWaterFilling() {
return this->sendRequestCode(2);
}
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,
static_cast<unsigned int>(requestCode) << 8 data
)); ));
if (!isValidResponse(response) || !isValidResponseId(response, OpenThermMessageID::RemoteRequest)) { return 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) { bool sendServiceReset() {
if (buffer == nullptr || length == 0) { unsigned int data = 10;
return false; data <<= 8;
} unsigned long response = this->sendRequest(buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::RemoteRequest,
data
));
unsigned long response; return isValidResponse(response) && isValidResponseId(response, OpenThermMessageID::RemoteRequest);
uint8_t index = 0; }
uint8_t maxIndex = 255;
while (index <= maxIndex && index < length) { bool sendWaterFilling() {
response = this->sendRequest(buildRequest( unsigned int data = 2;
OpenThermMessageType::READ_DATA, data <<= 8;
id, unsigned long response = this->sendRequest(buildRequest(
static_cast<unsigned int>(index) << 8 OpenThermMessageType::WRITE_DATA,
)); OpenThermMessageID::RemoteRequest,
data
));
if (!isValidResponse(response) || !isValidResponseId(response, id)) { return isValidResponse(response) && isValidResponseId(response, OpenThermMessageID::RemoteRequest);
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) {
const uint8_t responseId = (response >> 16) & 0xFF; uint8_t responseId = (response >> 16) & 0xFF;
return static_cast<uint8_t>(id) == responseId; return (uint8_t)id == responseId;
} }
static uint8_t getResponseMessageTypeId(unsigned long response) { static uint8_t getResponseMessageTypeId(unsigned long response) {
@@ -163,10 +124,10 @@ public:
uint8_t msgType = getResponseMessageTypeId(response); uint8_t msgType = getResponseMessageTypeId(response);
switch (msgType) { switch (msgType) {
case static_cast<uint8_t>(OpenThermMessageType::READ_ACK): case (uint8_t) OpenThermMessageType::READ_ACK:
case static_cast<uint8_t>(OpenThermMessageType::WRITE_ACK): case (uint8_t) OpenThermMessageType::WRITE_ACK:
case static_cast<uint8_t>(OpenThermMessageType::DATA_INVALID): case (uint8_t) OpenThermMessageType::DATA_INVALID:
case static_cast<uint8_t>(OpenThermMessageType::UNKNOWN_DATA_ID): case (uint8_t) OpenThermMessageType::UNKNOWN_DATA_ID:
return CustomOpenTherm::messageTypeToString( return CustomOpenTherm::messageTypeToString(
static_cast<OpenThermMessageType>(msgType) static_cast<OpenThermMessageType>(msgType)
); );

View File

@@ -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

View File

@@ -319,7 +319,7 @@ protected:
emergencyFlags |= 0b00000010; emergencyFlags |= 0b00000010;
} }
if (settings.opentherm.options.nativeOTC) { if (settings.opentherm.options.nativeHeatingControl) {
emergencyFlags |= 0b00000100; emergencyFlags |= 0b00000100;
} }
} }

View File

@@ -171,7 +171,7 @@ protected:
vars.master.heating.enabled = this->isReady() vars.master.heating.enabled = this->isReady()
&& settings.heating.enabled && settings.heating.enabled
&& vars.cascadeControl.input && 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,9 +186,7 @@ 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 = !settings.opentherm.options.nativeOTC vars.master.ch2.targetTemp = vars.master.heating.setpointTemp;
? 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;
@@ -220,7 +218,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.nativeOTC, settings.opentherm.options.nativeHeatingControl,
vars.master.ch2.enabled, vars.master.ch2.enabled,
summerWinterMode, summerWinterMode,
dhwBlocking, dhwBlocking,
@@ -307,7 +305,6 @@ 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();
@@ -680,21 +677,6 @@ 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;
@@ -810,7 +792,7 @@ protected:
bool result = this->updateDhwTemp(); bool result = this->updateDhwTemp();
if (result) { if (result) {
const float convertedDhwTemp = convertTemp( float convertedDhwTemp = convertTemp(
vars.slave.dhw.currentTemp, vars.slave.dhw.currentTemp,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -834,7 +816,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()) {
const float convertedDhwTemp2 = convertTemp( float convertedDhwTemp2 = convertTemp(
vars.slave.dhw.currentTemp2, vars.slave.dhw.currentTemp2,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -858,7 +840,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()) {
const float convertedDhwFlowRate = convertVolume( float convertedDhwFlowRate = convertVolume(
vars.slave.dhw.flowRate, vars.slave.dhw.flowRate,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -882,7 +864,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()) {
const float convertedHeatingTemp = convertTemp( float convertedHeatingTemp = convertTemp(
vars.slave.heating.currentTemp, vars.slave.heating.currentTemp,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -906,7 +888,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()) {
const float convertedHeatingReturnTemp = convertTemp( float convertedHeatingReturnTemp = convertTemp(
vars.slave.heating.returnTemp, vars.slave.heating.returnTemp,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -929,9 +911,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.nativeOTC) { if (vars.master.ch2.enabled && !settings.opentherm.options.nativeHeatingControl) {
if (this->updateCh2Temp()) { if (this->updateCh2Temp()) {
const float convertedCh2Temp = convertTemp( float convertedCh2Temp = convertTemp(
vars.slave.ch2.currentTemp, vars.slave.ch2.currentTemp,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -956,7 +938,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()) {
const float convertedExhaustTemp = convertTemp( float convertedExhaustTemp = convertTemp(
vars.slave.exhaust.temp, vars.slave.exhaust.temp,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -980,7 +962,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()) {
const float convertedHeatExchTemp = convertTemp( float convertedHeatExchTemp = convertTemp(
vars.slave.heatExchangerTemp, vars.slave.heatExchangerTemp,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -1004,7 +986,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()) {
const float convertedOutdoorTemp = convertTemp( float convertedOutdoorTemp = convertTemp(
vars.slave.heating.outdoorTemp, vars.slave.heating.outdoorTemp,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -1028,7 +1010,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()) {
const float convertedSolarStorageTemp = convertTemp( float convertedSolarStorageTemp = convertTemp(
vars.slave.solar.storage, vars.slave.solar.storage,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -1052,7 +1034,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()) {
const float convertedSolarCollectorTemp = convertTemp( float convertedSolarCollectorTemp = convertTemp(
vars.slave.solar.collector, vars.slave.solar.collector,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -1098,7 +1080,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()) {
const float convertedPressure = convertPressure( float convertedPressure = convertPressure(
vars.slave.pressure, vars.slave.pressure,
settings.opentherm.unitSystem, settings.opentherm.unitSystem,
settings.system.unitSystem settings.system.unitSystem
@@ -1204,12 +1186,9 @@ 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
const float convertedTemp = convertTemp( float convertedTemp = convertTemp(
targetTemp, vars.master.dhw.targetTemp,
settings.system.unitSystem, settings.system.unitSystem,
settings.opentherm.unitSystem settings.opentherm.unitSystem
); );
@@ -1221,7 +1200,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)"),
targetTemp, convertedTemp, vars.slave.dhw.targetTemp vars.master.dhw.targetTemp, convertedTemp, vars.slave.dhw.targetTemp
); );
} else { } else {
@@ -1230,19 +1209,16 @@ protected:
} }
} }
// Send indoor temp if AlwaysSendIndoorTemp option is enabled. // Set indoor temp for Native heating control/Always set indoor temp
if (settings.opentherm.options.nativeOTC || settings.opentherm.options.alwaysSendIndoorTemp) { if (settings.opentherm.options.nativeHeatingControl || settings.opentherm.options.alwaysSetIndoorTemp) {
// Current indoor temp
const float& indoorTemp = vars.master.heating.indoorTemp;
// Converted current indoor temp // Converted current indoor temp
const float convertedTemp = convertTemp(indoorTemp, settings.system.unitSystem, settings.opentherm.unitSystem); float convertedTemp = convertTemp(vars.master.heating.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)"),
indoorTemp, convertedTemp, vars.slave.heating.indoorTemp vars.master.heating.indoorTemp, convertedTemp, vars.slave.heating.indoorTemp
); );
} else { } else {
@@ -1254,7 +1230,7 @@ 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)"),
indoorTemp, convertedTemp, vars.slave.ch2.indoorTemp vars.master.heating.indoorTemp, convertedTemp, vars.slave.ch2.indoorTemp
); );
} else { } else {
@@ -1263,17 +1239,11 @@ protected:
} }
} }
// NativeOTC
if (settings.opentherm.options.nativeOTC) {
// Target indoor temp
const float& targetTemp = vars.master.heating.targetTemp;
// Native heating control
if (settings.opentherm.options.nativeHeatingControl) {
// Converted target indoor temp // Converted target indoor temp
const float convertedTemp = convertTemp( float convertedTemp = convertTemp(vars.master.heating.targetTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
targetTemp,
settings.system.unitSystem,
settings.opentherm.unitSystem
);
// Set target indoor temp // Set target indoor temp
if (this->needSetHeatingTemp(convertedTemp)) { if (this->needSetHeatingTemp(convertedTemp)) {
@@ -1282,7 +1252,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)"),
targetTemp, convertedTemp, vars.slave.heating.targetTemp vars.master.heating.targetTemp, convertedTemp, vars.slave.heating.targetTemp
); );
} else { } else {
@@ -1297,7 +1267,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)"),
targetTemp, convertedTemp, vars.slave.ch2.targetTemp vars.master.heating.targetTemp, convertedTemp, vars.slave.ch2.targetTemp
); );
} else { } else {
@@ -1306,22 +1276,10 @@ protected:
} }
} }
// Set heating temp // Normal heating control
{ 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
const float convertedTemp = convertTemp( float convertedTemp = convertTemp(vars.master.heating.setpointTemp, settings.system.unitSystem, settings.opentherm.unitSystem);
targetTemp,
settings.system.unitSystem,
settings.opentherm.unitSystem
);
if (this->needSetHeatingTemp(convertedTemp)) { if (this->needSetHeatingTemp(convertedTemp)) {
// Set max heating temp // Set max heating temp
@@ -1329,13 +1287,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)"),
targetTemp, convertedTemp vars.master.heating.setpointTemp, 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)"),
targetTemp, convertedTemp vars.master.heating.setpointTemp, convertedTemp
); );
} }
} }
@@ -1346,7 +1304,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)"),
targetTemp, convertedTemp, vars.slave.heating.targetTemp vars.master.heating.setpointTemp, convertedTemp, vars.slave.heating.targetTemp
); );
} else { } else {
@@ -1356,30 +1314,27 @@ protected:
} }
// Set CH2 temp // Set CH2 temp
if (settings.opentherm.options.heatingToCh2 || settings.opentherm.options.dhwToCh2) { if (!settings.opentherm.options.nativeHeatingControl && vars.master.ch2.enabled) {
// Target CH2 heating temp if (settings.opentherm.options.heatingToCh2 || settings.opentherm.options.dhwToCh2) {
const float targetTemp = vars.master.ch2.enabled // Converted target CH2 temp
? vars.master.ch2.targetTemp float convertedTemp = convertTemp(
: 0.0f; vars.master.ch2.targetTemp,
settings.system.unitSystem,
settings.opentherm.unitSystem
);
// Converted target CH2 temp if (this->needSetCh2Temp(convertedTemp)) {
const float convertedTemp = convertTemp( if (this->setCh2Temp(convertedTemp)) {
targetTemp, this->ch2SetTempTime = millis();
settings.system.unitSystem,
settings.opentherm.unitSystem
);
if (this->needSetCh2Temp(convertedTemp)) { Log.sinfoln(
if (this->setCh2Temp(convertedTemp)) { FPSTR(L_OT_CH2), F("Set temp: %.2f (converted: %.2f, response: %.2f)"),
this->ch2SetTempTime = millis(); vars.master.ch2.targetTemp, convertedTemp, vars.slave.ch2.targetTemp
);
Log.sinfoln( } else {
FPSTR(L_OT_CH2), F("Set temp: %.2f (converted: %.2f, response: %.2f)"), Log.swarningln(FPSTR(L_OT_CH2), F("Failed set temp"));
targetTemp, convertedTemp, vars.slave.ch2.targetTemp }
);
} else {
Log.swarningln(FPSTR(L_OT_CH2), F("Failed set temp"));
} }
} }
} }
@@ -1387,7 +1342,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) {
const float highTemp = convertTemp( float highTemp = convertTemp(
max({ max({
vars.slave.heating.currentTemp, vars.slave.heating.currentTemp,
vars.slave.heating.returnTemp, vars.slave.heating.returnTemp,
@@ -1424,7 +1379,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) {
const float highTemp = convertTemp( float highTemp = convertTemp(
max({ max({
vars.slave.heating.currentTemp, vars.slave.heating.currentTemp,
vars.slave.heating.returnTemp, vars.slave.heating.returnTemp,
@@ -1518,19 +1473,6 @@ 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() {
@@ -1708,7 +1650,7 @@ protected:
} }
bool setRoomTemp(const float temperature) { bool setRoomTemp(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,
@@ -1728,7 +1670,7 @@ protected:
return CustomOpenTherm::getUInt(response) == request; return CustomOpenTherm::getUInt(response) == request;
} }
bool setRoomTempCh2(const float temperature) { bool setRoomTempCh2(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,
@@ -2230,25 +2172,6 @@ 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,
@@ -2263,7 +2186,7 @@ protected:
return false; return false;
} }
const float value = CustomOpenTherm::getFloat(response); float value = CustomOpenTherm::getFloat(response);
if (value < 0) { if (value < 0) {
return false; return false;
} }
@@ -2287,7 +2210,7 @@ protected:
return false; return false;
} }
const float value = CustomOpenTherm::getFloat(response); float value = CustomOpenTherm::getFloat(response);
if (value <= 0) { if (value <= 0) {
return false; return false;
} }
@@ -2311,7 +2234,7 @@ protected:
return false; return false;
} }
const float value = CustomOpenTherm::getFloat(response); float value = CustomOpenTherm::getFloat(response);
if (value <= 0) { if (value <= 0) {
return false; return false;
} }
@@ -2365,7 +2288,7 @@ protected:
return false; return false;
} }
const float value = CustomOpenTherm::getFloat(response); float value = CustomOpenTherm::getFloat(response);
if (value <= 0) { if (value <= 0) {
return false; return false;
} }
@@ -2429,7 +2352,7 @@ protected:
return false; return false;
} }
const float value = (float) CustomOpenTherm::getInt(response); 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;
} }
@@ -2453,7 +2376,7 @@ protected:
return false; return false;
} }
const float value = (float) CustomOpenTherm::getInt(response); float value = (float) CustomOpenTherm::getInt(response);
if (value <= 0) { if (value <= 0) {
return false; return false;
} }
@@ -2554,7 +2477,7 @@ protected:
return false; return false;
} }
const float value = CustomOpenTherm::getFloat(response); float value = CustomOpenTherm::getFloat(response);
if (value < 0) { if (value < 0) {
return false; return false;
} }

View File

@@ -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.nativeOTC) { if (settings.equitherm.enabled || settings.pid.enabled || settings.opentherm.options.nativeHeatingControl) {
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,12 +57,23 @@ protected:
this->turbo(); this->turbo();
this->hysteresis(); this->hysteresis();
vars.master.heating.targetTemp = settings.heating.target; if (vars.master.heating.blocking && settings.heating.hysteresis.action == HysteresisAction::SET_ZERO_TARGET) {
vars.master.heating.setpointTemp = roundf(constrain( vars.master.heating.targetTemp = 0.0f;
this->getHeatingSetpointTemp(), vars.master.heating.setpointTemp = 0.0f;
this->getHeatingMinSetpointTemp(),
this->getHeatingMaxSetpointTemp() // tick if PID enabled
), 0); if (settings.pid.enabled) {
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,
@@ -91,7 +102,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.nativeOTC; useHyst = settings.equitherm.enabled || settings.pid.enabled || settings.opentherm.options.nativeHeatingControl;
} }
if (useHyst) { if (useHyst) {
@@ -108,13 +119,13 @@ protected:
} }
inline float getHeatingMinSetpointTemp() { inline float getHeatingMinSetpointTemp() {
return settings.opentherm.options.nativeOTC return settings.opentherm.options.nativeHeatingControl
? vars.master.heating.minTemp ? vars.master.heating.minTemp
: settings.heating.minTemp; : settings.heating.minTemp;
} }
inline float getHeatingMaxSetpointTemp() { inline float getHeatingMaxSetpointTemp() {
return settings.opentherm.options.nativeOTC return settings.opentherm.options.nativeHeatingControl
? vars.master.heating.maxTemp ? vars.master.heating.maxTemp
: settings.heating.maxTemp; : settings.heating.maxTemp;
} }
@@ -135,7 +146,7 @@ protected:
if (vars.emergency.state) { if (vars.emergency.state) {
return settings.emergency.target; return settings.emergency.target;
} else if (settings.opentherm.options.nativeOTC) { } else if (settings.opentherm.options.nativeHeatingControl) {
return settings.heating.target; return settings.heating.target;
} else if (!settings.equitherm.enabled && !settings.pid.enabled) { } else if (!settings.equitherm.enabled && !settings.pid.enabled) {

View File

@@ -34,7 +34,6 @@ 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,

View File

@@ -78,8 +78,8 @@ struct Settings {
bool autoFaultReset = false; bool autoFaultReset = false;
bool autoDiagReset = false; bool autoDiagReset = false;
bool setDateAndTime = false; bool setDateAndTime = false;
bool alwaysSendIndoorTemp = true; bool alwaysSetIndoorTemp = true;
bool nativeOTC = false; bool nativeHeatingControl = false;
bool immergasFix = false; bool immergasFix = false;
} options; } options;
} opentherm; } opentherm;
@@ -389,7 +389,6 @@ 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;

View File

@@ -38,6 +38,7 @@ const char S_ACTION[] PROGMEM = "action";
const char S_ACTIONS[] PROGMEM = "actions"; const char S_ACTIONS[] PROGMEM = "actions";
const char S_ACTIVE[] PROGMEM = "active"; const char S_ACTIVE[] PROGMEM = "active";
const char S_ADDRESS[] PROGMEM = "address"; const char S_ADDRESS[] PROGMEM = "address";
const char S_ALWAYS_SET_INDOOR_TEMP[] PROGMEM = "alwaysSetIndoorTemp";
const char S_ANTI_STUCK_INTERVAL[] PROGMEM = "antiStuckInterval"; const char S_ANTI_STUCK_INTERVAL[] PROGMEM = "antiStuckInterval";
const char S_ANTI_STUCK_TIME[] PROGMEM = "antiStuckTime"; const char S_ANTI_STUCK_TIME[] PROGMEM = "antiStuckTime";
const char S_AP[] PROGMEM = "ap"; const char S_AP[] PROGMEM = "ap";
@@ -110,7 +111,6 @@ 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";
@@ -142,7 +142,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_OTC[] PROGMEM = "nativeOTC"; const char S_NATIVE_HEATING_CONTROL[] PROGMEM = "nativeHeatingControl";
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";

View File

@@ -468,11 +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_ALWAYS_SEND_INDOOR_TEMP)] = src.opentherm.options.alwaysSendIndoorTemp; otOptions[FPSTR(S_ALWAYS_SET_INDOOR_TEMP)] = src.opentherm.options.alwaysSetIndoorTemp;
otOptions[FPSTR(S_NATIVE_OTC)] = src.opentherm.options.nativeOTC; otOptions[FPSTR(S_NATIVE_HEATING_CONTROL)] = src.opentherm.options.nativeHeatingControl;
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;
mqtt[FPSTR(S_SERVER)] = src.mqtt.server; mqtt[FPSTR(S_SERVER)] = src.mqtt.server;
@@ -1005,20 +1004,20 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
} }
} }
if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_ALWAYS_SEND_INDOOR_TEMP)].is<bool>()) { if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_ALWAYS_SET_INDOOR_TEMP)].is<bool>()) {
bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_ALWAYS_SEND_INDOOR_TEMP)].as<bool>(); bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_ALWAYS_SET_INDOOR_TEMP)].as<bool>();
if (value != dst.opentherm.options.alwaysSendIndoorTemp) { if (value != dst.opentherm.options.alwaysSetIndoorTemp) {
dst.opentherm.options.alwaysSendIndoorTemp = value; dst.opentherm.options.alwaysSetIndoorTemp = value;
changed = true; changed = true;
} }
} }
if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_OTC)].is<bool>()) { if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_HEATING_CONTROL)].is<bool>()) {
bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_OTC)].as<bool>(); bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_HEATING_CONTROL)].as<bool>();
if (value != dst.opentherm.options.nativeOTC) { if (value != dst.opentherm.options.nativeHeatingControl) {
dst.opentherm.options.nativeOTC = value; dst.opentherm.options.nativeHeatingControl = value;
if (value) { if (value) {
dst.equitherm.enabled = false; dst.equitherm.enabled = false;
@@ -1038,6 +1037,7 @@ 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>();
@@ -1128,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.nativeOTC) { if (!dst.opentherm.options.nativeHeatingControl) {
if (value != dst.equitherm.enabled) { if (value != dst.equitherm.enabled) {
dst.equitherm.enabled = value; dst.equitherm.enabled = value;
changed = true; changed = true;
@@ -1181,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.nativeOTC) { if (!dst.opentherm.options.nativeHeatingControl) {
if (value != dst.pid.enabled) { if (value != dst.pid.enabled) {
dst.pid.enabled = value; dst.pid.enabled = value;
changed = true; changed = true;
@@ -1714,7 +1714,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.nativeOTC; bool noRegulators = !dst.opentherm.options.nativeHeatingControl;
bool valid = isValidTemp( bool valid = isValidTemp(
value, value,
dst.system.unitSystem, dst.system.unitSystem,
@@ -1739,7 +1739,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.nativeOTC; bool indoorTempControl = dst.equitherm.enabled || dst.pid.enabled || dst.opentherm.options.nativeHeatingControl;
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;
@@ -1932,7 +1932,6 @@ 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):
@@ -2132,7 +2131,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.protocolVersion; slave[FPSTR(S_PROTOCOL_VERSION)] = src.slave.appVersion;
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;

View File

@@ -243,7 +243,6 @@
"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 传感器",
@@ -458,13 +457,12 @@
"autoFaultReset": "自动报警复位 <small>(不推荐!)</small>", "autoFaultReset": "自动报警复位 <small>(不推荐!)</small>",
"autoDiagReset": "自动诊断复位 <small>(不推荐!)</small>", "autoDiagReset": "自动诊断复位 <small>(不推荐!)</small>",
"setDateAndTime": "同步设置锅炉日期与时间", "setDateAndTime": "同步设置锅炉日期与时间",
"immergasFix": "针对Immergas锅炉的兼容性修复", "immergasFix": "针对Immergas锅炉的兼容性修复"
"alwaysSendIndoorTemp": "向锅炉发送当前室内温度"
}, },
"nativeOTC": { "nativeHeating": {
"title": "原生热载体温度计算模式", "title": "原生锅炉供暖控制",
"note": "仅在锅炉处于 OTC 模式时<u>才</u>工作:需要并接受目标室内温度,并基于内置曲线模式自行调节热载体温度。与 PID 和 Equitherm 不兼容。" "note": "<u>注意:</u> 仅适用于锅炉需接收目标室温并自主调节载热介质温度的场景与固件中的PID及Equithermq气候补偿功能不兼容。"
} }
}, },

View File

@@ -243,7 +243,6 @@
"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",
@@ -458,13 +457,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", "alwaysSetIndoorTemp": "Always set indoor temperature",
"alwaysSendIndoorTemp": "Send current indoor temp to boiler" "immergasFix": "Fix for Immergas boilers"
}, },
"nativeOTC": { "nativeHeating": {
"title": "Native OTC mode", "title": "Native heating control (boiler)",
"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." "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."
} }
}, },

View File

@@ -243,7 +243,6 @@
"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",
@@ -458,13 +457,12 @@
"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"
}, },
"nativeOTC": { "nativeHeating": {
"title": "Modalità nativa di calcolo della temperatura del vettore termico", "title": "Controllo del riscaldamento nativo (caldaia)",
"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." "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."
} }
}, },

View File

@@ -222,8 +222,6 @@
"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",
@@ -424,13 +422,11 @@
"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": {
"nativeOTC": { "title": "Natuurlijke verwarmingsregeling (ketel)",
"title": "Native warmtedrager temperatuur berekeningsmodus", "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."
"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": {

View File

@@ -243,7 +243,6 @@
"otDhwBurnerHours": "OpenTherm, кол-во часов работы горелки (ГВС)", "otDhwBurnerHours": "OpenTherm, кол-во часов работы горелки (ГВС)",
"otHeatingPumpHours": "OpenTherm, кол-во часов работы насоса (отопление)", "otHeatingPumpHours": "OpenTherm, кол-во часов работы насоса (отопление)",
"otDhwPumpHours": "OpenTherm, кол-во часов работы насоса (ГВС)", "otDhwPumpHours": "OpenTherm, кол-во часов работы насоса (ГВС)",
"otCoolingHours": "OpenTherm, кол-во часов работы охлаждения",
"ntcTemp": "NTC датчик", "ntcTemp": "NTC датчик",
"dallasTemp": "DALLAS датчик", "dallasTemp": "DALLAS датчик",
@@ -458,13 +457,12 @@
"autoFaultReset": "Автоматический сброс ошибок <small>(не рекомендуется!)</small>", "autoFaultReset": "Автоматический сброс ошибок <small>(не рекомендуется!)</small>",
"autoDiagReset": "Автоматический сброс диагностики <small>(не рекомендуется!)</small>", "autoDiagReset": "Автоматический сброс диагностики <small>(не рекомендуется!)</small>",
"setDateAndTime": "Устанавливать время и дату на котле", "setDateAndTime": "Устанавливать время и дату на котле",
"immergasFix": "Фикс для котлов Immergas", "immergasFix": "Фикс для котлов Immergas"
"alwaysSendIndoorTemp": "Передавать текущую темп. в помещении котлу"
}, },
"nativeOTC": { "nativeHeating": {
"title": "Нативный режим OTC (расчёт температуры теплоносителя)", "title": "Передать управление отоплением котлу",
"note": "Работает <u>ТОЛЬКО</u> если котел в режиме OTC: требует и принимает целевую температуру в помещении и сам регулирует температуру теплоносителя на основе встроенного режима кривых. Несовместимо с ПИД и ПЗА." "note": "Работает <u>ТОЛЬКО</u> если котел требует и принимает целевую температуру в помещении и сам регулирует температуру теплоносителя на основе встроенного режима кривых. Несовместимо с ПИД и ПЗА."
} }
}, },

View File

@@ -113,7 +113,6 @@
<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>

View File

@@ -688,21 +688,21 @@
</label> </label>
<label> <label>
<input type="checkbox" name="opentherm[options][immergasFix]" value="true"> <input type="checkbox" name="opentherm[options][alwaysSetIndoorTemp]" value="true">
<span data-i18n>settings.ot.options.immergasFix</span> <span data-i18n>settings.ot.options.alwaysSetIndoorTemp</span>
</label> </label>
<label> <label>
<input type="checkbox" name="opentherm[options][alwaysSendIndoorTemp]" value="true"> <input type="checkbox" name="opentherm[options][immergasFix]" value="true">
<span data-i18n>settings.ot.options.alwaysSendIndoorTemp</span> <span data-i18n>settings.ot.options.immergasFix</span>
</label> </label>
<hr /> <hr />
<label> <label>
<input type="checkbox" name="opentherm[options][nativeOTC]" value="true"> <input type="checkbox" name="opentherm[options][nativeHeatingControl]" value="true">
<span data-i18n>settings.ot.nativeOTC.title</span><br /> <span data-i18n>settings.ot.nativeHeating.title</span><br />
<small data-i18n>settings.ot.nativeOTC.note</small> <small data-i18n>settings.ot.nativeHeating.note</small>
</label> </label>
</fieldset> </fieldset>
</div> </div>
@@ -1122,9 +1122,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][nativeOTC]']", data.opentherm.options.nativeOTC); setCheckboxValue("[name='opentherm[options][alwaysSetIndoorTemp]']", data.opentherm.options.alwaysSetIndoorTemp);
setCheckboxValue("[name='opentherm[options][nativeHeatingControl]']", data.opentherm.options.nativeHeatingControl);
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
@@ -1212,7 +1212,7 @@
setBusy('#dhw-settings-busy', '#dhw-settings', false); setBusy('#dhw-settings-busy', '#dhw-settings', false);
// Emergency mode // Emergency mode
if (data.opentherm.options.nativeOTC) { if (data.opentherm.options.nativeHeatingControl) {
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