refactor: optimization

* names changed: pin => gpio
* ability to change OpenTherm GPIO without rebooting
This commit is contained in:
Yurii
2024-03-10 04:10:18 +03:00
parent 07ab121788
commit b07dd46f55
12 changed files with 388 additions and 310 deletions

View File

@@ -63,13 +63,13 @@
<div id="opentherm-settings-busy" aria-busy="true"></div>
<form action="/api/settings" id="opentherm-settings" class="hidden">
<div class="grid">
<label for="opentherm-in-pin">
<label for="opentherm-in-gpio">
In GPIO
<input type="number" inputmode="numeric" class="opentherm-in-pin" name="opentherm[inPin]" min="0" max="99" step="1" required>
<input type="number" inputmode="numeric" class="opentherm-in-gpio" name="opentherm[inGpio]" min="0" max="254" step="1">
</label>
<label for="opentherm-in-pin">
<label for="opentherm-in-gpio">
Out GPIO
<input type="number" inputmode="numeric" class="opentherm-out-pin" name="opentherm[outPin]" min="0" max="99" step="1" required>
<input type="number" inputmode="numeric" class="opentherm-out-gpio" name="opentherm[outGpio]" min="0" max="254" step="1">
</label>
<label for="opentherm-member-id-code">
Master MemberID code
@@ -77,10 +77,6 @@
</label>
</div>
<fieldset>
<mark>After changing GPIO, the ESP must be restarted for the changes to take effect.</mark>
</fieldset>
<fieldset>
<legend>Options</legend>
<label for="opentherm-dhw-present">
@@ -190,9 +186,9 @@
</label>
</fieldset>
<label for="outdoor-sensor-pin">
<label for="outdoor-sensor-gpio">
GPIO
<input type="number" inputmode="numeric" class="outdoor-sensor-pin" name="sensors[outdoor][pin]" min="0" max="99" step="1" required>
<input type="number" inputmode="numeric" class="outdoor-sensor-gpio" name="sensors[outdoor][gpio]" min="0" max="254" step="1">
</label>
<label for="outdoor-sensor-offset">
Temp offset (calibration)
@@ -229,9 +225,9 @@
</label>
</fieldset>
<label for="indoor-sensor-pin">
<label for="indoor-sensor-gpio">
GPIO
<input type="number" inputmode="numeric" class="indoor-sensor-pin" name="sensors[indoor][pin]" min="0" max="99" step="1" required>
<input type="number" inputmode="numeric" class="indoor-sensor-gpio" name="sensors[indoor][gpio]" min="0" max="254" step="1">
</label>
<div class="grid">
@@ -267,9 +263,9 @@
<br>
<div class="grid">
<label for="extpump-pin">
<label for="extpump-gpio">
Relay GPIO
<input type="number" inputmode="numeric" class="extpump-pin" name="externalPump[pin]" min="0" max="99" step="1" required>
<input type="number" inputmode="numeric" class="extpump-gpio" name="externalPump[gpio]" min="0" max="254" step="1">
</label>
<label for="extpump-pc-time">
Post circulation time <small>(min)</small>

Binary file not shown.

View File

@@ -8,6 +8,7 @@ public:
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback;
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {}
~CustomOpenTherm() {}
CustomOpenTherm* setYieldCallback(YieldCallback callback = nullptr) {
this->yieldCallback = callback;

View File

@@ -17,7 +17,7 @@ framework = arduino
lib_deps =
bblanchon/ArduinoJson@^7.0.3
;ihormelnyk/OpenTherm Library@^1.1.5
https://github.com/ihormelnyk/opentherm_library.git?080324
https://github.com/ihormelnyk/opentherm_library.git
arduino-libraries/ArduinoMqttClient@^0.1.8
lennarthennigs/ESP Telnet@^2.2
gyverlibs/FileData@^1.0.2
@@ -34,18 +34,18 @@ build_flags =
-D USE_SERIAL=${secrets.use_serial}
-D USE_TELNET=${secrets.use_telnet}
-D DEBUG_BY_DEFAULT=${secrets.debug}
-D HOSTNAME_DEFAULT='"${secrets.hostname}"'
-D AP_SSID_DEFAULT='"${secrets.ap_ssid}"'
-D AP_PASSWORD_DEFAULT='"${secrets.ap_password}"'
-D STA_SSID_DEFAULT='"${secrets.sta_ssid}"'
-D STA_PASSWORD_DEFAULT='"${secrets.sta_password}"'
-D PORTAL_LOGIN_DEFAULT='"${secrets.portal_login}"'
-D PORTAL_PASSWORD_DEFAULT='"${secrets.portal_password}"'
-D MQTT_SERVER_DEFAULT='"${secrets.mqtt_server}"'
-D MQTT_PORT_DEFAULT=${secrets.mqtt_port}
-D MQTT_USER_DEFAULT='"${secrets.mqtt_user}"'
-D MQTT_PASSWORD_DEFAULT='"${secrets.mqtt_password}"'
-D MQTT_PREFIX_DEFAULT='"${secrets.mqtt_prefix}"'
-D DEFAULT_HOSTNAME='"${secrets.hostname}"'
-D DEFAULT_AP_SSID='"${secrets.ap_ssid}"'
-D DEFAULT_AP_PASSWORD='"${secrets.ap_password}"'
-D DEFAULT_STA_SSID='"${secrets.sta_ssid}"'
-D DEFAULT_STA_PASSWORD='"${secrets.sta_password}"'
-D DEFAULT_PORTAL_LOGIN='"${secrets.portal_login}"'
-D DEFAULT_PORTAL_PASSWORD='"${secrets.portal_password}"'
-D DEFAULT_MQTT_SERVER='"${secrets.mqtt_server}"'
-D DEFAULT_MQTT_PORT=${secrets.mqtt_port}
-D DEFAULT_MQTT_USER='"${secrets.mqtt_user}"'
-D DEFAULT_MQTT_PASSWORD='"${secrets.mqtt_password}"'
-D DEFAULT_MQTT_PREFIX='"${secrets.mqtt_prefix}"'
upload_speed = 921600
monitor_speed = 115200
monitor_filters = direct
@@ -67,7 +67,7 @@ board_build.ldscript = eagle.flash.1m256.ld
;board_build.ldscript = eagle.flash.4m1m.ld
[esp32_defaults]
platform = espressif32
platform = espressif32@^6.5
board_build.partitions = esp32_partitions.csv
lib_deps =
${env.lib_deps}
@@ -91,12 +91,12 @@ extra_scripts = ${esp8266_defaults.extra_scripts}
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
build_flags =
${esp8266_defaults.build_flags}
-D OT_IN_PIN_DEFAULT=4
-D OT_OUT_PIN_DEFAULT=5
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
-D SENSOR_INDOOR_PIN_DEFAULT=14
-D LED_STATUS_PIN=13
-D LED_OT_RX_PIN=15
-D DEFAULT_OT_IN_GPIO=4
-D DEFAULT_OT_OUT_GPIO=5
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
-D DEFAULT_SENSOR_INDOOR_GPIO=14
-D LED_STATUS_GPIO=13
-D LED_OT_RX_GPIO=15
[env:d1_mini_lite]
platform = ${esp8266_defaults.platform}
@@ -107,12 +107,12 @@ extra_scripts = ${esp8266_defaults.extra_scripts}
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
build_flags =
${esp8266_defaults.build_flags}
-D OT_IN_PIN_DEFAULT=4
-D OT_OUT_PIN_DEFAULT=5
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
-D SENSOR_INDOOR_PIN_DEFAULT=14
-D LED_STATUS_PIN=13
-D LED_OT_RX_PIN=15
-D DEFAULT_OT_IN_GPIO=4
-D DEFAULT_OT_OUT_GPIO=5
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
-D DEFAULT_SENSOR_INDOOR_GPIO=14
-D LED_STATUS_GPIO=13
-D LED_OT_RX_GPIO=15
[env:d1_mini_pro]
platform = ${esp8266_defaults.platform}
@@ -123,12 +123,12 @@ extra_scripts = ${esp8266_defaults.extra_scripts}
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
build_flags =
${esp8266_defaults.build_flags}
-D OT_IN_PIN_DEFAULT=4
-D OT_OUT_PIN_DEFAULT=5
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
-D SENSOR_INDOOR_PIN_DEFAULT=14
-D LED_STATUS_PIN=13
-D LED_OT_RX_PIN=15
-D DEFAULT_OT_IN_GPIO=4
-D DEFAULT_OT_OUT_GPIO=5
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
-D DEFAULT_SENSOR_INDOOR_GPIO=14
-D LED_STATUS_GPIO=13
-D LED_OT_RX_GPIO=15
[env:s2_mini]
platform = ${esp32_defaults.platform}
@@ -139,12 +139,12 @@ lib_ignore = ${esp32_defaults.lib_ignore}
extra_scripts = ${esp32_defaults.extra_scripts}
build_flags =
${esp32_defaults.build_flags}
-D OT_IN_PIN_DEFAULT=33
-D OT_OUT_PIN_DEFAULT=35
-D SENSOR_OUTDOOR_PIN_DEFAULT=9
-D SENSOR_INDOOR_PIN_DEFAULT=7
-D LED_STATUS_PIN=11
-D LED_OT_RX_PIN=12
-D DEFAULT_OT_IN_GPIO=33
-D DEFAULT_OT_OUT_GPIO=35
-D DEFAULT_SENSOR_OUTDOOR_GPIO=9
-D DEFAULT_SENSOR_INDOOR_GPIO=7
-D LED_STATUS_GPIO=11
-D LED_OT_RX_GPIO=12
[env:s3_mini]
platform = ${esp32_defaults.platform}
@@ -158,12 +158,12 @@ extra_scripts = ${esp32_defaults.extra_scripts}
build_flags =
${esp32_defaults.build_flags}
-D USE_BLE=1
-D OT_IN_PIN_DEFAULT=35
-D OT_OUT_PIN_DEFAULT=36
-D SENSOR_OUTDOOR_PIN_DEFAULT=13
-D SENSOR_INDOOR_PIN_DEFAULT=12
-D LED_STATUS_PIN=11
-D LED_OT_RX_PIN=10
-D DEFAULT_OT_IN_GPIO=35
-D DEFAULT_OT_OUT_GPIO=36
-D DEFAULT_SENSOR_OUTDOOR_GPIO=13
-D DEFAULT_SENSOR_INDOOR_GPIO=12
-D LED_STATUS_GPIO=11
-D LED_OT_RX_GPIO=10
[env:c3_mini]
platform = ${esp32_defaults.platform}
@@ -179,12 +179,12 @@ build_unflags =
build_flags =
${esp32_defaults.build_flags}
-D USE_BLE=1
-D OT_IN_PIN_DEFAULT=8
-D OT_OUT_PIN_DEFAULT=10
-D SENSOR_OUTDOOR_PIN_DEFAULT=0
-D SENSOR_INDOOR_PIN_DEFAULT=1
-D LED_STATUS_PIN=4
-D LED_OT_RX_PIN=5
-D DEFAULT_OT_IN_GPIO=8
-D DEFAULT_OT_OUT_GPIO=10
-D DEFAULT_SENSOR_OUTDOOR_GPIO=0
-D DEFAULT_SENSOR_INDOOR_GPIO=1
-D LED_STATUS_GPIO=4
-D LED_OT_RX_GPIO=5
[env:nodemcu_32s]
platform = ${esp32_defaults.platform}
@@ -198,12 +198,12 @@ extra_scripts = ${esp32_defaults.extra_scripts}
build_flags =
${esp32_defaults.build_flags}
-D USE_BLE=1
-D OT_IN_PIN_DEFAULT=21
-D OT_OUT_PIN_DEFAULT=22
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
-D SENSOR_INDOOR_PIN_DEFAULT=13
-D LED_STATUS_PIN=2 ; 18
-D LED_OT_RX_PIN=19
-D DEFAULT_OT_IN_GPIO=21
-D DEFAULT_OT_OUT_GPIO=22
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
-D DEFAULT_SENSOR_INDOOR_GPIO=13
-D LED_STATUS_GPIO=2 ; 18
-D LED_OT_RX_GPIO=19
;-D WOKWI=1
[env:d1_mini32]
@@ -218,9 +218,9 @@ extra_scripts = ${esp32_defaults.extra_scripts}
build_flags =
${esp32_defaults.build_flags}
-D USE_BLE=1
-D OT_IN_PIN_DEFAULT=21
-D OT_OUT_PIN_DEFAULT=22
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
-D SENSOR_INDOOR_PIN_DEFAULT=18
-D LED_STATUS_PIN=2
-D LED_OT_RX_PIN=19
-D DEFAULT_OT_IN_GPIO=21
-D DEFAULT_OT_OUT_GPIO=22
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
-D DEFAULT_SENSOR_INDOOR_GPIO=18
-D LED_STATUS_GPIO=2
-D LED_OT_RX_GPIO=19

View File

@@ -52,14 +52,14 @@ protected:
}
void setup() {
#ifdef LED_STATUS_PIN
pinMode(LED_STATUS_PIN, OUTPUT);
digitalWrite(LED_STATUS_PIN, LOW);
#ifdef LED_STATUS_GPIO
pinMode(LED_STATUS_GPIO, OUTPUT);
digitalWrite(LED_STATUS_GPIO, LOW);
#endif
if (settings.externalPump.pin != 0) {
pinMode(settings.externalPump.pin, OUTPUT);
digitalWrite(settings.externalPump.pin, LOW);
if (GPIO_IS_VALID(settings.externalPump.gpio)) {
pinMode(settings.externalPump.gpio, OUTPUT);
digitalWrite(settings.externalPump.gpio, LOW);
}
}
@@ -89,10 +89,6 @@ protected:
Log.sinfoln(FPSTR(L_MAIN), F("Restart signal received. Restart after 10 sec."));
}
if (!tOt->isEnabled() && settings.opentherm.inPin > 0 && settings.opentherm.outPin > 0 && settings.opentherm.inPin != settings.opentherm.outPin) {
tOt->enable();
}
if (network->isConnected()) {
vars.sensors.rssi = WiFi.RSSI();
@@ -140,8 +136,8 @@ protected:
this->yield();
#ifdef LED_STATUS_PIN
this->ledStatus(LED_STATUS_PIN);
#ifdef LED_STATUS_GPIO
this->ledStatus(LED_STATUS_GPIO);
#endif
this->externalPump();
this->yield();
@@ -211,7 +207,7 @@ protected:
}
}
void ledStatus(uint8_t ledPin) {
void ledStatus(uint8_t gpio) {
uint8_t errors[4];
uint8_t errCount = 0;
static uint8_t errPos = 0;
@@ -219,7 +215,7 @@ protected:
static bool ledOn = false;
if (!this->blinkerInitialized) {
this->blinker->init(ledPin);
this->blinker->init(gpio);
this->blinkerInitialized = true;
}
@@ -247,14 +243,14 @@ protected:
if (!this->blinker->running() && millis() - endBlinkTime >= 5000) {
if (errCount == 0) {
if (!ledOn) {
digitalWrite(ledPin, HIGH);
digitalWrite(gpio, HIGH);
ledOn = true;
}
return;
} else if (ledOn) {
digitalWrite(ledPin, LOW);
digitalWrite(gpio, LOW);
ledOn = false;
endBlinkTime = millis();
return;
@@ -283,10 +279,10 @@ protected:
this->heatingEnabled = true;
}
if (!settings.externalPump.use || settings.externalPump.pin == 0) {
if (!settings.externalPump.use || !GPIO_IS_VALID(settings.externalPump.gpio)) {
if (vars.states.externalPump) {
if (settings.externalPump.pin != 0) {
digitalWrite(settings.externalPump.pin, LOW);
if (GPIO_IS_VALID(settings.externalPump.gpio)) {
digitalWrite(settings.externalPump.gpio, LOW);
}
vars.states.externalPump = false;
@@ -300,7 +296,7 @@ protected:
if (vars.states.externalPump && !this->heatingEnabled) {
if (this->extPumpStartReason == MainTask::PumpStartReason::HEATING && millis() - this->heatingDisabledTime > (settings.externalPump.postCirculationTime * 1000u)) {
digitalWrite(settings.externalPump.pin, LOW);
digitalWrite(settings.externalPump.gpio, LOW);
vars.states.externalPump = false;
vars.parameters.extPumpLastEnableTime = millis();
@@ -308,7 +304,7 @@ protected:
Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time"));
} else if (this->extPumpStartReason == MainTask::PumpStartReason::ANTISTUCK && millis() - this->externalPumpStartTime >= (settings.externalPump.antiStuckTime * 1000u)) {
digitalWrite(settings.externalPump.pin, LOW);
digitalWrite(settings.externalPump.gpio, LOW);
vars.states.externalPump = false;
vars.parameters.extPumpLastEnableTime = millis();
@@ -324,7 +320,7 @@ protected:
this->externalPumpStartTime = millis();
this->extPumpStartReason = MainTask::PumpStartReason::HEATING;
digitalWrite(settings.externalPump.pin, HIGH);
digitalWrite(settings.externalPump.gpio, HIGH);
Log.sinfoln("EXTPUMP", F("Enabled: heating on"));
@@ -333,7 +329,7 @@ protected:
this->externalPumpStartTime = millis();
this->extPumpStartReason = MainTask::PumpStartReason::ANTISTUCK;
digitalWrite(settings.externalPump.pin, HIGH);
digitalWrite(settings.externalPump.gpio, HIGH);
Log.sinfoln("EXTPUMP", F("Enabled: anti stuck"));
}

View File

@@ -1,27 +1,35 @@
#include <CustomOpenTherm.h>
CustomOpenTherm* ot;
extern FileData fsSettings;
class OpenThermTask : public Task {
public:
OpenThermTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {
ot = new CustomOpenTherm(settings.opentherm.inPin, settings.opentherm.outPin);
OpenThermTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {}
~OpenThermTask() {
delete this->instance;
}
protected:
unsigned short readyTime = 60000;
unsigned short dhwSetTempInterval = 60000;
unsigned short heatingSetTempInterval = 60000;
const unsigned short readyTime = 60000;
const unsigned short dhwSetTempInterval = 60000;
const unsigned short heatingSetTempInterval = 60000;
const unsigned int initializingInterval = 3600000;
CustomOpenTherm* instance = nullptr;
unsigned long instanceCreatedTime = 0;
byte instanceInGpio = 0;
byte instanceOutGpio = 0;
bool isInitialized = false;
unsigned long initializedTime = 0;
unsigned int initializedMemberIdCode = 0;
byte dhwFlowRateMultiplier = 1;
byte pressureMultiplier = 1;
bool pump = true;
unsigned long lastSuccessResponse = 0;
unsigned long prevUpdateNonEssentialVars = 0;
unsigned long startupTime = millis();
unsigned long dhwSetTempTime = 0;
unsigned long heatingSetTempTime = 0;
byte dhwFlowRateMultiplier = 1;
byte pressureMultiplier = 1;
const char* getTaskName() {
return "OpenTherm";
@@ -36,9 +44,35 @@ protected:
}
void setup() {
Log.sinfoln(FPSTR(L_OT), F("Started. GPIO IN: %hhu, GPIO OUT: %hhu"), settings.opentherm.inPin, settings.opentherm.outPin);
#ifdef LED_OT_RX_GPIO
pinMode(LED_OT_RX_GPIO, OUTPUT);
digitalWrite(LED_OT_RX_GPIO, LOW);
#endif
ot->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) {
// delete instance
if (this->instance != nullptr) {
delete this->instance;
this->instance = nullptr;
Log.sinfoln(FPSTR(L_OT), F("Stopped"));
}
if (!GPIO_IS_VALID(settings.opentherm.inGpio) || !GPIO_IS_VALID(settings.opentherm.outGpio)) {
Log.swarningln(FPSTR(L_OT), F("Not started. GPIO IN: %hhu or GPIO OUT: %hhu is not valid"), settings.opentherm.inGpio, settings.opentherm.outGpio);
return;
}
// create instance
this->instance = new CustomOpenTherm(settings.opentherm.inGpio, settings.opentherm.outGpio);
// flags
this->instanceCreatedTime = millis();
this->instanceInGpio = settings.opentherm.inGpio;
this->instanceOutGpio = settings.opentherm.outGpio;
this->isInitialized = false;
Log.sinfoln(FPSTR(L_OT), F("Started. GPIO IN: %hhu, GPIO OUT: %hhu"), settings.opentherm.inGpio, settings.opentherm.outGpio);
this->instance->setAfterSendRequestCallback([this](unsigned long request, unsigned long response, OpenThermResponseStatus status, byte attempt) {
Log.straceln(
FPSTR(L_OT),
F("ID: %4d Request: %8lx Response: %8lx Attempt: %2d Status: %s"),
@@ -48,68 +82,39 @@ protected:
if (status == OpenThermResponseStatus::SUCCESS) {
this->lastSuccessResponse = millis();
#ifdef LED_OT_RX_PIN
#ifdef LED_OT_RX_GPIO
{
digitalWrite(LED_OT_RX_PIN, HIGH);
digitalWrite(LED_OT_RX_GPIO, HIGH);
delayMicroseconds(2000);
digitalWrite(LED_OT_RX_PIN, LOW);
digitalWrite(LED_OT_RX_GPIO, LOW);
}
#endif
}
});
ot->setYieldCallback([this]() {
this->instance->setYieldCallback([this]() {
this->delay(25);
});
ot->begin();
#ifdef LED_OT_RX_PIN
pinMode(LED_OT_RX_PIN, OUTPUT);
digitalWrite(LED_OT_RX_PIN, LOW);
#endif
}
void initBoiler() {
this->dhwFlowRateMultiplier = 1;
this->pressureMultiplier = 1;
// Not all boilers support these, only try once when the boiler becomes connected
if (updateSlaveVersion()) {
Log.straceln(FPSTR(L_OT), F("Slave version: %u, type: %u"), vars.parameters.slaveVersion, vars.parameters.slaveType);
} else {
Log.swarningln(FPSTR(L_OT), F("Get slave version failed"));
}
// 0x013F
if (setMasterVersion(0x3F, 0x01)) {
Log.straceln(FPSTR(L_OT), F("Master version: %u, type: %u"), vars.parameters.masterVersion, vars.parameters.masterType);
} else {
Log.swarningln(FPSTR(L_OT), F("Set master version failed"));
}
if (updateSlaveConfig()) {
Log.straceln(FPSTR(L_OT), F("Slave member id: %u, flags: %u"), vars.parameters.slaveMemberId, vars.parameters.slaveFlags);
} else {
Log.swarningln(FPSTR(L_OT), F("Get slave config failed"));
}
if (setMasterConfig(settings.opentherm.memberIdCode & 0xFF, (settings.opentherm.memberIdCode & 0xFFFF) >> 8)) {
Log.straceln(FPSTR(L_OT), F("Master member id: %u, flags: %u"), vars.parameters.masterMemberId, vars.parameters.masterFlags);
} else {
Log.swarningln(FPSTR(L_OT), F("Set master config failed"));
}
this->instance->begin();
}
void loop() {
static byte currentHeatingTemp, currentDhwTemp = 0;
unsigned long localResponse;
bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && this->pump && isReady();
if (this->instanceInGpio != settings.opentherm.inGpio || this->instanceOutGpio != settings.opentherm.outGpio) {
this->setup();
} else if (this->initializedMemberIdCode != settings.opentherm.memberIdCode || millis() - this->initializedTime > this->initializingInterval) {
this->isInitialized = false;
}
if (this->instance == nullptr) {
this->delay(5000);
return;
}
bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && this->pump && this->isReady();
bool heatingCh2Enabled = settings.opentherm.heatingCh2Enabled;
if (settings.opentherm.heatingCh1ToCh2) {
heatingCh2Enabled = heatingEnabled;
@@ -118,7 +123,7 @@ protected:
heatingCh2Enabled = settings.opentherm.dhwPresent && settings.dhw.enable;
}
localResponse = ot->setBoilerStatus(
unsigned long response = this->instance->setBoilerStatus(
heatingEnabled,
settings.opentherm.dhwPresent && settings.dhw.enable,
false,
@@ -128,20 +133,20 @@ protected:
settings.opentherm.dhwBlocking
);
if (!CustomOpenTherm::isValidResponse(localResponse)) {
Log.swarningln(FPSTR(L_OT), F("Invalid response after setBoilerStatus: %s"), CustomOpenTherm::statusToString(ot->getLastResponseStatus()));
if (!CustomOpenTherm::isValidResponse(response)) {
Log.swarningln(FPSTR(L_OT), F("Invalid response after setBoilerStatus: %s"), CustomOpenTherm::statusToString(this->instance->getLastResponseStatus()));
}
if (!vars.states.otStatus && millis() - this->lastSuccessResponse < 1150) {
Log.sinfoln(FPSTR(L_OT), F("Connected. Initializing"));
Log.sinfoln(FPSTR(L_OT), F("Connected"));
vars.states.otStatus = true;
this->initBoiler();
} else if (vars.states.otStatus && millis() - this->lastSuccessResponse > 1150) {
Log.swarningln(FPSTR(L_OT), F("Disconnected"));
vars.states.otStatus = false;
this->isInitialized = false;
}
// If boiler is disconnected, no need try setting other OT stuff
@@ -155,17 +160,27 @@ protected:
return;
}
if (!this->isInitialized) {
Log.sinfoln(FPSTR(L_OT), F("Initializing..."));
this->isInitialized = true;
this->initializedTime = millis();
this->initializedMemberIdCode = settings.opentherm.memberIdCode;
this->dhwFlowRateMultiplier = 1;
this->pressureMultiplier = 1;
this->initialize();
}
if (vars.parameters.heatingEnabled != heatingEnabled) {
this->prevUpdateNonEssentialVars = 0;
vars.parameters.heatingEnabled = heatingEnabled;
Log.sinfoln(FPSTR(L_OT_HEATING), "%s", heatingEnabled ? F("Enabled") : F("Disabled"));
}
vars.states.heating = CustomOpenTherm::isCentralHeatingActive(localResponse);
vars.states.dhw = settings.opentherm.dhwPresent ? CustomOpenTherm::isHotWaterActive(localResponse) : false;
vars.states.flame = CustomOpenTherm::isFlameOn(localResponse);
vars.states.fault = CustomOpenTherm::isFault(localResponse);
vars.states.diagnostic = CustomOpenTherm::isDiagnostic(localResponse);
vars.states.heating = CustomOpenTherm::isCentralHeatingActive(response);
vars.states.dhw = settings.opentherm.dhwPresent ? CustomOpenTherm::isHotWaterActive(response) : false;
vars.states.flame = CustomOpenTherm::isFlameOn(response);
vars.states.fault = CustomOpenTherm::isFault(response);
vars.states.diagnostic = CustomOpenTherm::isDiagnostic(response);
// These parameters will be updated every minute
if (millis() - this->prevUpdateNonEssentialVars > 60000) {
@@ -282,7 +297,7 @@ protected:
// Fault reset action
if (vars.actions.resetFault) {
if (vars.states.fault) {
if (ot->sendBoilerReset()) {
if (this->instance->sendBoilerReset()) {
Log.sinfoln(FPSTR(L_OT), F("Boiler fault reset successfully"));
} else {
@@ -296,7 +311,7 @@ protected:
// Diag reset action
if (vars.actions.resetDiagnostic) {
if (vars.states.diagnostic) {
if (ot->sendServiceReset()) {
if (this->instance->sendServiceReset()) {
Log.sinfoln(FPSTR(L_OT), F("Boiler diagnostic reset successfully"));
} else {
@@ -318,7 +333,7 @@ protected:
Log.sinfoln(FPSTR(L_OT_DHW), F("Set temp = %u"), newDhwTemp);
// Set DHW temp
if (ot->setDhwTemp(newDhwTemp)) {
if (this->instance->setDhwTemp(newDhwTemp)) {
currentDhwTemp = newDhwTemp;
this->dhwSetTempTime = millis();
@@ -328,7 +343,7 @@ protected:
// Set DHW temp to CH2
if (settings.opentherm.dhwToCh2) {
if (!ot->setHeatingCh2Temp(newDhwTemp)) {
if (!this->instance->setHeatingCh2Temp(newDhwTemp)) {
Log.swarningln(FPSTR(L_OT_DHW), F("Failed set ch2 temp"));
}
}
@@ -340,7 +355,7 @@ protected:
Log.sinfoln(FPSTR(L_OT_HEATING), F("Set temp = %u"), vars.parameters.heatingSetpoint);
// Set heating temp
if (ot->setHeatingCh1Temp(vars.parameters.heatingSetpoint)) {
if (this->instance->setHeatingCh1Temp(vars.parameters.heatingSetpoint)) {
currentHeatingTemp = vars.parameters.heatingSetpoint;
this->heatingSetTempTime = millis();
@@ -350,7 +365,7 @@ protected:
// Set heating temp to CH2
if (settings.opentherm.heatingCh1ToCh2) {
if (!ot->setHeatingCh2Temp(vars.parameters.heatingSetpoint)) {
if (!this->instance->setHeatingCh2Temp(vars.parameters.heatingSetpoint)) {
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set ch2 temp"));
}
}
@@ -373,8 +388,40 @@ protected:
}
}
void initialize() {
// Not all boilers support these, only try once when the boiler becomes connected
if (updateSlaveVersion()) {
Log.straceln(FPSTR(L_OT), F("Slave version: %u, type: %u"), vars.parameters.slaveVersion, vars.parameters.slaveType);
} else {
Log.swarningln(FPSTR(L_OT), F("Get slave version failed"));
}
// 0x013F
if (setMasterVersion(0x3F, 0x01)) {
Log.straceln(FPSTR(L_OT), F("Master version: %u, type: %u"), vars.parameters.masterVersion, vars.parameters.masterType);
} else {
Log.swarningln(FPSTR(L_OT), F("Set master version failed"));
}
if (updateSlaveConfig()) {
Log.straceln(FPSTR(L_OT), F("Slave member id: %u, flags: %u"), vars.parameters.slaveMemberId, vars.parameters.slaveFlags);
} else {
Log.swarningln(FPSTR(L_OT), F("Get slave config failed"));
}
if (setMasterConfig(settings.opentherm.memberIdCode & 0xFF, (settings.opentherm.memberIdCode & 0xFFFF) >> 8)) {
Log.straceln(FPSTR(L_OT), F("Master member id: %u, flags: %u"), vars.parameters.masterMemberId, vars.parameters.masterFlags);
} else {
Log.swarningln(FPSTR(L_OT), F("Set master config failed"));
}
}
bool isReady() {
return millis() - this->startupTime > this->readyTime;
return millis() - this->instanceCreatedTime > this->readyTime;
}
bool needSetDhwTemp() {
@@ -386,7 +433,7 @@ protected:
}
bool updateSlaveConfig() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::SConfigSMemberIDcode,
0
@@ -447,7 +494,7 @@ protected:
return true;
}
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::MConfigMMemberIDcode,
request
@@ -457,22 +504,22 @@ protected:
}
bool setMaxModulationLevel(byte value) {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::MaxRelModLevelSetting,
ot->toF88(value)
this->instance->toF88(value)
));
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
vars.parameters.maxModulation = ot->fromF88(response);
vars.parameters.maxModulation = this->instance->fromF88(response);
return true;
}
bool updateSlaveOtVersion() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::OpenThermVersionSlave,
0
@@ -487,23 +534,23 @@ protected:
}
bool setMasterOtVersion(float version) {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::OpenThermVersionMaster,
ot->toF88(version)
this->instance->toF88(version)
));
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
vars.parameters.masterOtVersion = ot->fromF88(response);
vars.parameters.masterOtVersion = this->instance->fromF88(response);
return true;
}
bool updateSlaveVersion() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::SlaveVersion,
0
@@ -520,7 +567,7 @@ protected:
}
bool setMasterVersion(uint8_t version, uint8_t type) {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::MasterVersion,
(unsigned int) version | (unsigned int) type << 8
@@ -537,7 +584,7 @@ protected:
}
bool updateMinMaxDhwTemp() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::TdhwSetUBTdhwSetLB,
0
@@ -561,7 +608,7 @@ protected:
}
bool updateMinMaxHeatingTemp() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::MaxTSetUBMaxTSetLB,
0
@@ -584,7 +631,7 @@ protected:
}
bool setMaxHeatingTemp(byte value) {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::MaxTSet,
CustomOpenTherm::temperatureToData(value)
@@ -594,7 +641,7 @@ protected:
}
bool updateOutsideTemp() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::Toutside,
0
@@ -609,7 +656,7 @@ protected:
}
bool updateHeatingTemp() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::Tboiler,
0
@@ -630,7 +677,7 @@ protected:
bool updateDhwTemp() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::Tdhw,
0
@@ -650,7 +697,7 @@ protected:
}
bool updateDhwFlowRate() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::DHWFlowRate,
0
@@ -670,7 +717,7 @@ protected:
}
bool updateFaultCode() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::ASFflags,
0
@@ -685,7 +732,7 @@ protected:
}
bool updateModulationLevel() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::RelModLevel,
0
@@ -695,7 +742,7 @@ protected:
return false;
}
float modulation = ot->fromF88(response);
float modulation = this->instance->fromF88(response);
if (!vars.states.flame) {
vars.sensors.modulation = 0;
} else {
@@ -706,7 +753,7 @@ protected:
}
bool updatePressure() {
unsigned long response = ot->sendRequest(CustomOpenTherm::buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::CHPressure,
0

View File

@@ -60,39 +60,38 @@ protected:
}
void loop() {
bool needUpdateIndoorTemp = false;
bool needUpdateOutdoorTemp = false;
bool indoorTempUpdated = false;
bool outdoorTempUpdated = false;
if (settings.sensors.outdoor.type == 2 && settings.sensors.outdoor.pin) {
if (settings.sensors.outdoor.type == 2 && GPIO_IS_VALID(settings.sensors.indoor.gpio)) {
outdoorTemperatureSensor();
needUpdateOutdoorTemp = true;
outdoorTempUpdated = true;
}
if (settings.sensors.indoor.type == 2 && settings.sensors.indoor.pin) {
if (settings.sensors.indoor.type == 2 && GPIO_IS_VALID(settings.sensors.indoor.gpio)) {
indoorTemperatureSensor();
needUpdateIndoorTemp = true;
indoorTempUpdated = true;
}
#if USE_BLE
if (settings.sensors.indoor.type == 3) {
bluetoothSensor();
needUpdateIndoorTemp = true;
else if (settings.sensors.indoor.type == 3) {
indoorTemperatureBluetoothSensor();
indoorTempUpdated = true;
}
#endif
if (needUpdateOutdoorTemp && fabs(vars.temperatures.outdoor - this->filteredOutdoorTemp) > 0.099) {
if (outdoorTempUpdated && fabs(vars.temperatures.outdoor - this->filteredOutdoorTemp) > 0.099) {
vars.temperatures.outdoor = this->filteredOutdoorTemp + settings.sensors.outdoor.offset;
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("New temp: %f"), vars.temperatures.outdoor);
}
if (needUpdateIndoorTemp && fabs(vars.temperatures.indoor - this->filteredIndoorTemp) > 0.099) {
if (indoorTempUpdated && fabs(vars.temperatures.indoor - this->filteredIndoorTemp) > 0.099) {
vars.temperatures.indoor = this->filteredIndoorTemp + settings.sensors.indoor.offset;
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("New temp: %f"), vars.temperatures.indoor);
}
}
#if USE_BLE
void bluetoothSensor() {
void indoorTemperatureBluetoothSensor() {
static bool initBleNotify = false;
if (!initBleSensor && millis() > 5000) {
Log.sinfoln(FPSTR(L_SENSORS_BLE), F("Init BLE"));
@@ -210,9 +209,9 @@ protected:
void outdoorTemperatureSensor() {
if (!this->initOutdoorSensor) {
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("Starting on gpio %hhu..."), settings.sensors.outdoor.pin);
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("Starting on gpio %hhu..."), settings.sensors.outdoor.gpio);
this->oneWireOutdoorSensor->begin(settings.sensors.outdoor.pin);
this->oneWireOutdoorSensor->begin(settings.sensors.outdoor.gpio);
this->outdoorSensor->begin();
Log.straceln(
@@ -276,9 +275,9 @@ protected:
void indoorTemperatureSensor() {
if (!this->initIndoorSensor) {
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("Starting on gpio %hhu..."), settings.sensors.indoor.pin);
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("Starting on gpio %hhu..."), settings.sensors.indoor.gpio);
this->oneWireIndoorSensor->begin(settings.sensors.indoor.pin);
this->oneWireIndoorSensor->begin(settings.sensors.indoor.gpio);
this->indoorSensor->begin();
Log.straceln(

View File

@@ -1,5 +1,5 @@
struct NetworkSettings {
char hostname[25] = HOSTNAME_DEFAULT;
char hostname[25] = DEFAULT_HOSTNAME;
bool useDhcp = true;
struct {
@@ -10,14 +10,14 @@ struct NetworkSettings {
} staticConfig;
struct {
char ssid[33] = AP_SSID_DEFAULT;
char password[65] = AP_PASSWORD_DEFAULT;
char ssid[33] = DEFAULT_AP_SSID;
char password[65] = DEFAULT_AP_PASSWORD;
byte channel = 6;
} ap;
struct {
char ssid[33] = STA_SSID_DEFAULT;
char password[65] = STA_PASSWORD_DEFAULT;
char ssid[33] = DEFAULT_STA_SSID;
char password[65] = DEFAULT_STA_PASSWORD;
byte channel = 0;
} sta;
} networkSettings;
@@ -31,13 +31,13 @@ struct Settings {
struct {
bool useAuth = false;
char login[13] = PORTAL_LOGIN_DEFAULT;
char password[33] = PORTAL_PASSWORD_DEFAULT;
char login[13] = DEFAULT_PORTAL_LOGIN;
char password[33] = DEFAULT_PORTAL_PASSWORD;
} portal;
struct {
byte inPin = OT_IN_PIN_DEFAULT;
byte outPin = OT_OUT_PIN_DEFAULT;
byte inGpio = DEFAULT_OT_IN_GPIO;
byte outGpio = DEFAULT_OT_OUT_GPIO;
unsigned int memberIdCode = 0;
bool dhwPresent = true;
bool summerWinterMode = false;
@@ -49,11 +49,11 @@ struct Settings {
} opentherm;
struct {
char server[81] = MQTT_SERVER_DEFAULT;
unsigned short port = MQTT_PORT_DEFAULT;
char user[33] = MQTT_USER_DEFAULT;
char password[33] = MQTT_PASSWORD_DEFAULT;
char prefix[33] = MQTT_PREFIX_DEFAULT;
char server[81] = DEFAULT_MQTT_SERVER;
unsigned short port = DEFAULT_MQTT_PORT;
char user[33] = DEFAULT_MQTT_USER;
char password[33] = DEFAULT_MQTT_PASSWORD;
char prefix[33] = DEFAULT_MQTT_PREFIX;
unsigned short interval = 5;
} mqtt;
@@ -102,14 +102,14 @@ struct Settings {
struct {
// 0 - boiler, 1 - manual, 2 - ds18b20
byte type = 0;
byte pin = SENSOR_OUTDOOR_PIN_DEFAULT;
byte gpio = DEFAULT_SENSOR_OUTDOOR_GPIO;
float offset = 0.0f;
} outdoor;
struct {
// 1 - manual, 2 - ds18b20, 3 - ble
byte type = 1;
byte pin = SENSOR_INDOOR_PIN_DEFAULT;
byte gpio = DEFAULT_SENSOR_INDOOR_GPIO;
uint8_t bleAddresss[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
float offset = 0.0f;
} indoor;
@@ -117,7 +117,7 @@ struct Settings {
struct {
bool use = false;
byte pin = EXT_PUMP_PIN_DEFAULT;
byte gpio = DEFAULT_EXT_PUMP_GPIO;
unsigned short postCirculationTime = 600;
unsigned int antiStuckInterval = 2592000;
unsigned short antiStuckTime = 300;

View File

@@ -4,9 +4,6 @@
#define EMERGENCY_TIME_TRESHOLD 120000
#define MQTT_RECONNECT_INTERVAL 15000
#define MQTT_KEEPALIVE 30
#define OPENTHERM_OFFLINE_TRESHOLD 10
#define EXT_SENSORS_INTERVAL 5000
#define EXT_SENSORS_FILTER_K 0.15
@@ -14,16 +11,12 @@
#define CONFIG_URL "http://%s/"
#define SETTINGS_VALID_VALUE "stvalid" // only 8 chars!
#define GPIO_IS_NOT_CONFIGURED 0xff
#define DEFAULT_HEATING_MIN_TEMP 20
#define DEFAULT_HEATING_MAX_TEMP 90
#define DEFAULT_DHW_MIN_TEMP 30
#define DEFAULT_DHW_MAX_TEMP 60
#ifndef WM_DEBUG_MODE
#define WM_DEBUG_MODE WM_DEBUG_NOTIFY
#endif
#ifndef USE_SERIAL
#define USE_SERIAL true
#endif
@@ -36,80 +29,86 @@
#define USE_BLE false
#endif
#ifndef HOSTNAME_DEFAULT
#define HOSTNAME_DEFAULT "opentherm"
#ifndef DEFAULT_HOSTNAME
#define DEFAULT_HOSTNAME "opentherm"
#endif
#ifndef AP_SSID_DEFAULT
#define AP_SSID_DEFAULT "OpenTherm Gateway"
#ifndef DEFAULT_AP_SSID
#define DEFAULT_AP_SSID "OpenTherm Gateway"
#endif
#ifndef AP_PASSWORD_DEFAULT
#define AP_PASSWORD_DEFAULT "otgateway123456"
#ifndef DEFAULT_AP_PASSWORD
#define DEFAULT_AP_PASSWORD "otgateway123456"
#endif
#ifndef STA_SSID_DEFAULT
#define STA_SSID_DEFAULT ""
#ifndef DEFAULT_STA_SSID
#define DEFAULT_STA_SSID ""
#endif
#ifndef STA_PASSWORD_DEFAULT
#define STA_PASSWORD_DEFAULT ""
#ifndef DEFAULT_STA_PASSWORD
#define DEFAULT_STA_PASSWORD ""
#endif
#ifndef DEBUG_BY_DEFAULT
#define DEBUG_BY_DEFAULT false
#endif
#ifndef PORTAL_LOGIN_DEFAULT
#define PORTAL_LOGIN_DEFAULT ""
#ifndef DEFAULT_PORTAL_LOGIN
#define DEFAULT_PORTAL_LOGIN ""
#endif
#ifndef PORTAL_PASSWORD_DEFAULT
#define PORTAL_PASSWORD_DEFAULT ""
#ifndef DEFAULT_PORTAL_PASSWORD
#define DEFAULT_PORTAL_PASSWORD ""
#endif
#ifndef MQTT_SERVER_DEFAULT
#define MQTT_SERVER_DEFAULT ""
#ifndef DEFAULT_MQTT_SERVER
#define DEFAULT_MQTT_SERVER ""
#endif
#ifndef MQTT_PORT_DEFAULT
#define MQTT_PORT_DEFAULT 1883
#ifndef DEFAULT_MQTT_PORT
#define DEFAULT_MQTT_PORT 1883
#endif
#ifndef MQTT_USER_DEFAULT
#define MQTT_USER_DEFAULT ""
#ifndef DEFAULT_MQTT_USER
#define DEFAULT_MQTT_USER ""
#endif
#ifndef MQTT_PASSWORD_DEFAULT
#define MQTT_PASSWORD_DEFAULT ""
#ifndef DEFAULT_MQTT_PASSWORD
#define DEFAULT_MQTT_PASSWORD ""
#endif
#ifndef MQTT_PREFIX_DEFAULT
#define MQTT_PREFIX_DEFAULT "opentherm"
#ifndef DEFAULT_MQTT_PREFIX
#define DEFAULT_MQTT_PREFIX "opentherm"
#endif
#ifndef OT_IN_PIN_DEFAULT
#define OT_IN_PIN_DEFAULT 0
#ifndef DEFAULT_OT_IN_GPIO
#define DEFAULT_OT_IN_GPIO GPIO_IS_NOT_CONFIGURED
#endif
#ifndef OT_OUT_PIN_DEFAULT
#define OT_OUT_PIN_DEFAULT 0
#ifndef DEFAULT_OT_OUT_GPIO
#define DEFAULT_OT_OUT_GPIO GPIO_IS_NOT_CONFIGURED
#endif
#ifndef SENSOR_OUTDOOR_PIN_DEFAULT
#define SENSOR_OUTDOOR_PIN_DEFAULT 0
#ifndef DEFAULT_SENSOR_OUTDOOR_GPIO
#define DEFAULT_SENSOR_OUTDOOR_GPIO GPIO_IS_NOT_CONFIGURED
#endif
#ifndef SENSOR_INDOOR_PIN_DEFAULT
#define SENSOR_INDOOR_PIN_DEFAULT 0
#ifndef DEFAULT_SENSOR_INDOOR_GPIO
#define DEFAULT_SENSOR_INDOOR_GPIO GPIO_IS_NOT_CONFIGURED
#endif
#ifndef EXT_PUMP_PIN_DEFAULT
#define EXT_PUMP_PIN_DEFAULT 0
#ifndef DEFAULT_EXT_PUMP_GPIO
#define DEFAULT_EXT_PUMP_GPIO GPIO_IS_NOT_CONFIGURED
#endif
#ifndef PROGMEM
#define PROGMEM
#endif
#ifndef GPIO_IS_VALID_GPIO
#define GPIO_IS_VALID_GPIO(gpioNum) (gpioNum >= 0 && gpioNum <= 16)
#endif
#define GPIO_IS_VALID(gpioNum) (gpioNum != GPIO_IS_NOT_CONFIGURED && GPIO_IS_VALID_GPIO(gpioNum))
char buffer[255];

View File

@@ -143,7 +143,7 @@ void setup() {
tMqtt = new MqttTask(false, 500);
Scheduler.start(tMqtt);
tOt = new OpenThermTask(false, 750);
tOt = new OpenThermTask(true, 750);
Scheduler.start(tOt);
tSensors = new SensorsTask(true, EXT_SENSORS_INTERVAL);

View File

@@ -273,8 +273,8 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
dst["portal"]["login"] = src.portal.login;
dst["portal"]["password"] = src.portal.password;
dst["opentherm"]["inPin"] = src.opentherm.inPin;
dst["opentherm"]["outPin"] = src.opentherm.outPin;
dst["opentherm"]["inGpio"] = src.opentherm.inGpio;
dst["opentherm"]["outGpio"] = src.opentherm.outGpio;
dst["opentherm"]["memberIdCode"] = src.opentherm.memberIdCode;
dst["opentherm"]["dhwPresent"] = src.opentherm.dhwPresent;
dst["opentherm"]["summerWinterMode"] = src.opentherm.summerWinterMode;
@@ -324,11 +324,11 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
dst["equitherm"]["t_factor"] = roundd(src.equitherm.t_factor, 3);
dst["sensors"]["outdoor"]["type"] = src.sensors.outdoor.type;
dst["sensors"]["outdoor"]["pin"] = src.sensors.outdoor.pin;
dst["sensors"]["outdoor"]["gpio"] = src.sensors.outdoor.gpio;
dst["sensors"]["outdoor"]["offset"] = roundd(src.sensors.outdoor.offset, 2);
dst["sensors"]["indoor"]["type"] = src.sensors.indoor.type;
dst["sensors"]["indoor"]["pin"] = src.sensors.indoor.pin;
dst["sensors"]["indoor"]["gpio"] = src.sensors.indoor.gpio;
char bleAddress[18];
sprintf(
@@ -346,7 +346,7 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
if (!safe) {
dst["externalPump"]["use"] = src.externalPump.use;
dst["externalPump"]["pin"] = src.externalPump.pin;
dst["externalPump"]["gpio"] = src.externalPump.gpio;
dst["externalPump"]["postCirculationTime"] = roundd(src.externalPump.postCirculationTime / 60, 0);
dst["externalPump"]["antiStuckInterval"] = roundd(src.externalPump.antiStuckInterval / 86400, 0);
dst["externalPump"]["antiStuckTime"] = roundd(src.externalPump.antiStuckTime / 60, 0);
@@ -404,21 +404,37 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
// opentherm
if (!src["opentherm"]["inPin"].isNull()) {
unsigned char value = src["opentherm"]["inPin"].as<unsigned char>();
if (!src["opentherm"]["inGpio"].isNull()) {
if (src["opentherm"]["inGpio"].is<JsonString>() && src["opentherm"]["inGpio"].as<JsonString>().size() == 0) {
if (dst.opentherm.inGpio != GPIO_IS_NOT_CONFIGURED) {
dst.opentherm.inGpio = GPIO_IS_NOT_CONFIGURED;
changed = true;
}
} else {
unsigned char value = src["opentherm"]["inGpio"].as<unsigned char>();
if (value >= 0 && value < 50) {
dst.opentherm.inPin = value;
changed = true;
if (value >= 0 && value <= 254) {
dst.opentherm.inGpio = value;
changed = true;
}
}
}
if (!src["opentherm"]["outPin"].isNull()) {
unsigned char value = src["opentherm"]["outPin"].as<unsigned char>();
if (!src["opentherm"]["outGpio"].isNull()) {
if (src["opentherm"]["outGpio"].is<JsonString>() && src["opentherm"]["outGpio"].as<JsonString>().size() == 0) {
if (dst.opentherm.outGpio != GPIO_IS_NOT_CONFIGURED) {
dst.opentherm.outGpio = GPIO_IS_NOT_CONFIGURED;
changed = true;
}
} else {
unsigned char value = src["opentherm"]["outGpio"].as<unsigned char>();
if (value >= 0 && value < 50) {
dst.opentherm.outPin = value;
changed = true;
if (value >= 0 && value <= 254) {
dst.opentherm.outGpio = value;
changed = true;
}
}
}
@@ -789,12 +805,20 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
}
if (!src["sensors"]["outdoor"]["pin"].isNull()) {
unsigned char value = src["sensors"]["outdoor"]["pin"].as<unsigned char>();
if (!src["sensors"]["outdoor"]["gpio"].isNull()) {
if (src["sensors"]["outdoor"]["gpio"].is<JsonString>() && src["sensors"]["outdoor"]["gpio"].as<JsonString>().size() == 0) {
if (dst.sensors.outdoor.gpio != GPIO_IS_NOT_CONFIGURED) {
dst.sensors.outdoor.gpio = GPIO_IS_NOT_CONFIGURED;
changed = true;
}
} else {
unsigned char value = src["sensors"]["outdoor"]["gpio"].as<unsigned char>();
if (value >= 0 && value <= 50) {
dst.sensors.outdoor.pin = value;
changed = true;
if (value >= 0 && value <= 254) {
dst.sensors.outdoor.gpio = value;
changed = true;
}
}
}
@@ -821,12 +845,20 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
}
if (!src["sensors"]["indoor"]["pin"].isNull()) {
unsigned char value = src["sensors"]["indoor"]["pin"].as<unsigned char>();
if (value >= 0 && value <= 50) {
dst.sensors.indoor.pin = value;
changed = true;
if (!src["sensors"]["indoor"]["gpio"].isNull()) {
if (src["sensors"]["indoor"]["gpio"].is<JsonString>() && src["sensors"]["indoor"]["gpio"].as<JsonString>().size() == 0) {
if (dst.sensors.indoor.gpio != GPIO_IS_NOT_CONFIGURED) {
dst.sensors.indoor.gpio = GPIO_IS_NOT_CONFIGURED;
changed = true;
}
} else {
unsigned char value = src["sensors"]["indoor"]["gpio"].as<unsigned char>();
if (value >= 0 && value <= 254) {
dst.sensors.indoor.gpio = value;
changed = true;
}
}
}
@@ -861,12 +893,20 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
changed = true;
}
if (!src["externalPump"]["pin"].isNull()) {
unsigned char value = src["externalPump"]["pin"].as<unsigned char>();
if (!src["externalPump"]["gpio"].isNull()) {
if (src["externalPump"]["gpio"].is<JsonString>() && src["externalPump"]["gpio"].as<JsonString>().size() == 0) {
if (dst.externalPump.gpio != GPIO_IS_NOT_CONFIGURED) {
dst.externalPump.gpio = GPIO_IS_NOT_CONFIGURED;
changed = true;
}
} else {
unsigned char value = src["externalPump"]["gpio"].as<unsigned char>();
if (value >= 0 && value <= 50) {
dst.externalPump.pin = value;
changed = true;
if (value >= 0 && value <= 254) {
dst.externalPump.gpio = value;
changed = true;
}
}
}

View File

@@ -491,8 +491,8 @@ async function loadSettings() {
setInputValue('.portal-password', result.portal.password);
setBusy('#portal-settings-busy', '#portal-settings', false);
setInputValue('.opentherm-in-pin', result.opentherm.inPin);
setInputValue('.opentherm-out-pin', result.opentherm.outPin);
setInputValue('.opentherm-in-gpio', result.opentherm.inGpio < 255 ? result.opentherm.inGpio : '');
setInputValue('.opentherm-out-gpio', result.opentherm.outGpio < 255 ? result.opentherm.outGpio : '');
setInputValue('.opentherm-member-id-code', result.opentherm.memberIdCode);
setCheckboxValue('.opentherm-dhw-present', result.opentherm.dhwPresent);
setCheckboxValue('.opentherm-sw-mode', result.opentherm.summerWinterMode);
@@ -512,18 +512,18 @@ async function loadSettings() {
setBusy('#mqtt-settings-busy', '#mqtt-settings', false);
setRadioValue('.outdoor-sensor-type', result.sensors.outdoor.type);
setInputValue('.outdoor-sensor-pin', result.sensors.outdoor.pin);
setInputValue('.outdoor-sensor-gpio', result.sensors.outdoor.gpio < 255 ? result.sensors.outdoor.gpio : '');
setInputValue('.outdoor-sensor-offset', result.sensors.outdoor.offset);
setBusy('#outdoor-sensor-settings-busy', '#outdoor-sensor-settings', false);
setRadioValue('.indoor-sensor-type', result.sensors.indoor.type);
setInputValue('.indoor-sensor-pin', result.sensors.indoor.pin);
setInputValue('.indoor-sensor-gpio', result.sensors.indoor.gpio < 255 ? result.sensors.indoor.gpio : '');
setInputValue('.indoor-sensor-offset', result.sensors.indoor.offset);
setInputValue('.indoor-sensor-ble-addresss', result.sensors.indoor.bleAddresss);
setBusy('#indoor-sensor-settings-busy', '#indoor-sensor-settings', false);
setCheckboxValue('.extpump-use', result.externalPump.use);
setInputValue('.extpump-pin', result.externalPump.pin);
setInputValue('.extpump-gpio', result.externalPump.gpio < 255 ? result.externalPump.gpio : '');
setInputValue('.extpump-pc-time', result.externalPump.postCirculationTime);
setInputValue('.extpump-as-interval', result.externalPump.antiStuckInterval);
setInputValue('.extpump-as-time', result.externalPump.antiStuckTime);