14 Commits

Author SHA1 Message Date
Yurii
9e3ef7a465 chore: bump version 2024-03-14 13:08:11 +03:00
Yurii
a5f6749101 refactor: added SensorType enum 2024-03-14 13:07:42 +03:00
Yurii
b07dd46f55 refactor: optimization
* names changed: pin => gpio
* ability to change OpenTherm GPIO without rebooting
2024-03-10 04:10:18 +03:00
Yurii
07ab121788 chore: bump OpenTherm Library to master 2024-03-09 00:03:34 +03:00
Yurii
7cbc52a8b0 chore: bump version 2024-03-01 00:26:41 +03:00
Laxilef
e090be380c Merge pull request #49 from blitzu/patch-3
fix: fix typo in settings.html
2024-03-01 00:22:32 +03:00
Laxilef
0bf49d2249 Merge pull request #50 from blitzu/patch-2
fix: fix typo in network.html
2024-03-01 00:22:13 +03:00
Laxilef
a83d94d361 Merge pull request #51 from blitzu/patch-1
fix: fix typo in index.html
2024-03-01 00:21:49 +03:00
Laxilef
358980da4c Merge pull request #48 from blitzu/patch-4
fix: fix typo in upgrade.html
2024-03-01 00:21:13 +03:00
blitzu
f91e39d067 Update upgrade.html 2024-02-29 18:52:31 +02:00
blitzu
1d53f21d46 Update settings.html 2024-02-29 18:52:08 +02:00
blitzu
c225e7c2a8 Update network.html 2024-02-29 18:51:25 +02:00
blitzu
6831c4331f Update index.html 2024-02-29 18:50:36 +02:00
Yurii
8fb62ce8ae fix: set temperature for sensors in manual mode fixed 2024-02-23 03:50:30 +03:00
20 changed files with 509 additions and 395 deletions

View File

@@ -16,7 +16,7 @@
- PID
- Equithermic curves - adjusts the temperature based on indoor and outdoor temperatures
- Hysteresis setting (for accurate maintenance of room temperature)
- Ability to connect an external sensors to monitor outdoor and indoor temperature ([compatible sensors](#compatible-temperature-sensors))
- Ability to connect an external sensors to monitor outdoor and indoor temperature ([compatible sensors](https://github.com/Laxilef/OTGateway/wiki/Compatibility#temperature-sensors))
- Emergency mode. If the Wi-Fi connection is lost or the gateway cannot connect to the MQTT server, the mode will turn on. This mode will automatically maintain the set temperature and prevent your home from freezing. In this mode it is also possible to use equithermal curves (weather-compensated control).
- Automatic error reset (not with all boilers)
- Diagnostics:
@@ -72,7 +72,7 @@ All available information and instructions can be found in the wiki:
- [ESP32Scheduler](https://github.com/laxilef/ESP32Scheduler) (for ESP32)
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
- [OpenTherm Library](https://github.com/ihormelnyk/opentherm_library)
- [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient) /
- [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient)
- [ESPTelnet](https://github.com/LennartHennigs/ESPTelnet)
- [FileData](https://github.com/GyverLibs/FileData)
- [GyverPID](https://github.com/GyverLibs/GyverPID)

View File

@@ -210,7 +210,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -227,4 +227,4 @@
};
</script>
</body>
</html>
</html>

View File

@@ -145,7 +145,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -163,4 +163,4 @@
</script>
</body>
</html>
</html>

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>
@@ -333,7 +329,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -354,4 +350,4 @@
</script>
</body>
</html>
</html>

Binary file not shown.

View File

@@ -91,7 +91,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -105,4 +105,4 @@
</script>
</body>
</html>
</html>

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;
@@ -46,7 +47,7 @@ public:
unsigned long _response;
OpenThermResponseStatus _responseStatus = OpenThermResponseStatus::NONE;
if (!this->sendRequestAync(request)) {
if (!this->sendRequestAsync(request)) {
_response = 0;
} else {
@@ -88,7 +89,7 @@ public:
| (dhwBlocking << 6);
data <<= 8;
return this->sendRequest(this->buildRequest(
return this->sendRequest(buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::Status,
data
@@ -96,30 +97,30 @@ public:
}
bool setHeatingCh1Temp(float temperature) {
unsigned long response = this->sendRequest(this->buildRequest(
unsigned long response = this->sendRequest(buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::TSet,
this->temperatureToData(temperature)
temperatureToData(temperature)
));
return isValidResponse(response);
}
bool setHeatingCh2Temp(float temperature) {
unsigned long response = this->sendRequest(this->buildRequest(
unsigned long response = this->sendRequest(buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::TsetCH2,
this->temperatureToData(temperature)
temperatureToData(temperature)
));
return isValidResponse(response);
}
bool setDhwTemp(float temperature) {
unsigned long response = this->sendRequest(this->buildRequest(
unsigned long response = this->sendRequest(buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::TdhwSet,
this->temperatureToData(temperature)
temperatureToData(temperature)
));
return isValidResponse(response);
@@ -128,9 +129,9 @@ public:
bool sendBoilerReset() {
unsigned int data = 1;
data <<= 8;
unsigned long response = this->sendRequest(this->buildRequest(
unsigned long response = this->sendRequest(buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::Command,
OpenThermMessageID::RemoteRequest,
data
));
@@ -140,9 +141,9 @@ public:
bool sendServiceReset() {
unsigned int data = 10;
data <<= 8;
unsigned long response = this->sendRequest(this->buildRequest(
unsigned long response = this->sendRequest(buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::Command,
OpenThermMessageID::RemoteRequest,
data
));
@@ -152,9 +153,9 @@ public:
bool sendWaterFilling() {
unsigned int data = 2;
data <<= 8;
unsigned long response = this->sendRequest(this->buildRequest(
unsigned long response = this->sendRequest(buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::Command,
OpenThermMessageID::RemoteRequest,
data
));

View File

@@ -174,7 +174,7 @@ public:
Log.serrorln(
FPSTR(L_PORTAL_OTA),
F("File '%s', on writing %d bytes: %s"),
upload.filename.c_str(), upload.totalSize, result->error
upload.filename.c_str(), upload.totalSize, result->error.c_str()
);
} else {

View File

@@ -16,8 +16,8 @@ extra_configs = secrets.default.ini
framework = arduino
lib_deps =
bblanchon/ArduinoJson@^7.0.3
;ihormelnyk/OpenTherm Library@^1.1.4
https://github.com/Laxilef/opentherm_library/archive/refs/heads/fix_start_bit.zip
;ihormelnyk/OpenTherm Library@^1.1.5
https://github.com/ihormelnyk/opentherm_library.git
arduino-libraries/ArduinoMqttClient@^0.1.8
lennarthennigs/ESP Telnet@^2.2
gyverlibs/FileData@^1.0.2
@@ -34,24 +34,24 @@ 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
board_build.flash_mode = dio
board_build.filesystem = littlefs
version = 1.4.0-rc.15
version = 1.4.0-rc.17
; Defaults
[esp8266_defaults]
@@ -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

@@ -69,7 +69,7 @@ protected:
}*/
int getTaskPriority() {
return 1;
return 2;
}
bool isReadyForSend() {
@@ -385,8 +385,8 @@ protected:
bool isStupidMode = !settings.pid.enable && !settings.equitherm.enable;
byte heatingMinTemp = isStupidMode ? settings.heating.minTemp : 10;
byte heatingMaxTemp = isStupidMode ? settings.heating.maxTemp : 30;
bool editableOutdoorTemp = settings.sensors.outdoor.type == 1;
bool editableIndoorTemp = settings.sensors.indoor.type == 1;
bool editableOutdoorTemp = settings.sensors.outdoor.type == SensorType::MANUAL;
bool editableIndoorTemp = settings.sensors.indoor.type == SensorType::MANUAL;
if (force || _dhwPresent != settings.opentherm.dhwPresent) {
_dhwPresent = settings.opentherm.dhwPresent;

View File

@@ -1,31 +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) {}
static void IRAM_ATTR handleInterrupt() {
ot->handleInterrupt();
~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,85 +40,81 @@ protected:
}
int getTaskPriority() {
return 2;
return 5;
}
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"),
ot->getDataID(request), request, response, attempt, ot->statusToString(status)
CustomOpenTherm::getDataID(request), request, response, attempt, CustomOpenTherm::statusToString(status)
);
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->setMinWaitTimeForStartBit(20000);
ot->begin(OpenThermTask::handleInterrupt);
#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;
@@ -123,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,
@@ -133,20 +133,20 @@ protected:
settings.opentherm.dhwBlocking
);
if (!ot->isValidResponse(localResponse)) {
Log.swarningln(FPSTR(L_OT), F("Invalid response after setBoilerStatus: %s"), ot->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
@@ -160,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 = ot->isCentralHeatingActive(localResponse);
vars.states.dhw = settings.opentherm.dhwPresent ? ot->isHotWaterActive(localResponse) : false;
vars.states.flame = ot->isFlameOn(localResponse);
vars.states.fault = ot->isFault(localResponse);
vars.states.diagnostic = ot->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) {
@@ -247,7 +257,7 @@ protected:
setMaxHeatingTemp(settings.heating.maxTemp);
// Get outdoor temp (if necessary)
if (settings.sensors.outdoor.type == 0) {
if (settings.sensors.outdoor.type == SensorType::BOILER) {
updateOutsideTemp();
}
@@ -287,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 {
@@ -301,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 {
@@ -323,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();
@@ -333,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"));
}
}
@@ -345,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();
@@ -355,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"));
}
}
@@ -378,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() {
@@ -391,13 +433,13 @@ protected:
}
bool updateSlaveConfig() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::SConfigSMemberIDcode,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
@@ -452,69 +494,69 @@ protected:
return true;
}
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::MConfigMMemberIDcode,
request
));
return ot->isValidResponse(response);
return CustomOpenTherm::isValidResponse(response);
}
bool setMaxModulationLevel(byte value) {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::MaxRelModLevelSetting,
ot->toF88(value)
this->instance->toF88(value)
));
if (!ot->isValidResponse(response)) {
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(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::OpenThermVersionSlave,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
vars.parameters.slaveOtVersion = ot->getFloat(response);
vars.parameters.slaveOtVersion = CustomOpenTherm::getFloat(response);
return true;
}
bool setMasterOtVersion(float version) {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::OpenThermVersionMaster,
ot->toF88(version)
this->instance->toF88(version)
));
if (!ot->isValidResponse(response)) {
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(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::SlaveVersion,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
@@ -525,13 +567,13 @@ protected:
}
bool setMasterVersion(uint8_t version, uint8_t type) {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::WRITE_DATA,
OpenThermMessageID::MasterVersion,
(unsigned int) version | (unsigned int) type << 8
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
@@ -542,13 +584,13 @@ protected:
}
bool updateMinMaxDhwTemp() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::TdhwSetUBTdhwSetLB,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
@@ -566,13 +608,13 @@ protected:
}
bool updateMinMaxHeatingTemp() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::MaxTSetUBMaxTSetLB,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
@@ -589,42 +631,42 @@ protected:
}
bool setMaxHeatingTemp(byte value) {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::MaxTSet,
ot->temperatureToData(value)
CustomOpenTherm::temperatureToData(value)
));
return ot->isValidResponse(response);
return CustomOpenTherm::isValidResponse(response);
}
bool updateOutsideTemp() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::Toutside,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
vars.temperatures.outdoor = ot->getFloat(response) + settings.sensors.outdoor.offset;
vars.temperatures.outdoor = CustomOpenTherm::getFloat(response) + settings.sensors.outdoor.offset;
return true;
}
bool updateHeatingTemp() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::Tboiler,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
float value = ot->getFloat(response);
float value = CustomOpenTherm::getFloat(response);
if (value <= 0) {
return false;
}
@@ -635,17 +677,17 @@ protected:
bool updateDhwTemp() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::Tdhw,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
float value = ot->getFloat(response);
float value = CustomOpenTherm::getFloat(response);
if (value <= 0) {
return false;
}
@@ -655,17 +697,17 @@ protected:
}
bool updateDhwFlowRate() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::READ_DATA,
OpenThermMessageID::DHWFlowRate,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
float value = ot->getFloat(response);
float value = CustomOpenTherm::getFloat(response);
if (value > 16 && this->dhwFlowRateMultiplier != 10) {
this->dhwFlowRateMultiplier = 10;
}
@@ -675,13 +717,13 @@ protected:
}
bool updateFaultCode() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::ASFflags,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
@@ -690,17 +732,17 @@ protected:
}
bool updateModulationLevel() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::RelModLevel,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
float modulation = ot->fromF88(response);
float modulation = this->instance->fromF88(response);
if (!vars.states.flame) {
vars.sensors.modulation = 0;
} else {
@@ -711,17 +753,17 @@ protected:
}
bool updatePressure() {
unsigned long response = ot->sendRequest(ot->buildRequest(
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
OpenThermMessageID::CHPressure,
0
));
if (!ot->isValidResponse(response)) {
if (!CustomOpenTherm::isValidResponse(response)) {
return false;
}
float value = ot->getFloat(response);
float value = CustomOpenTherm::getFloat(response);
if (value > 5 && this->pressureMultiplier != 10) {
this->pressureMultiplier = 10;
}

View File

@@ -62,7 +62,7 @@ protected:
}*/
int getTaskPriority() {
return 0;
return 1;
}
void setup() {

View File

@@ -84,7 +84,7 @@ protected:
float newTemp = 0;
// if use equitherm
if (settings.emergency.useEquitherm && settings.sensors.outdoor.type != 1) {
if (settings.emergency.useEquitherm && settings.sensors.outdoor.type != SensorType::MANUAL) {
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
if (fabs(prevEtResult - etResult) + 0.0001 >= 0.5) {
@@ -97,7 +97,7 @@ protected:
newTemp += prevEtResult;
}
} else if(settings.emergency.usePid && settings.sensors.indoor.type != 1) {
} else if(settings.emergency.usePid && settings.sensors.indoor.type != SensorType::MANUAL) {
if (vars.parameters.heatingEnabled) {
float pidResult = getPidTemp(
settings.heating.minTemp,

View File

@@ -60,33 +60,38 @@ protected:
}
void loop() {
if (settings.sensors.outdoor.type == 2 && settings.sensors.outdoor.pin) {
bool indoorTempUpdated = false;
bool outdoorTempUpdated = false;
if (settings.sensors.outdoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.indoor.gpio)) {
outdoorTemperatureSensor();
outdoorTempUpdated = true;
}
if (settings.sensors.indoor.type == 2 && settings.sensors.indoor.pin) {
if (settings.sensors.indoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.indoor.gpio)) {
indoorTemperatureSensor();
indoorTempUpdated = true;
}
#if USE_BLE
if (settings.sensors.indoor.type == 3) {
bluetoothSensor();
#if USE_BLE
else if (settings.sensors.indoor.type == SensorType::BLUETOOTH) {
indoorTemperatureBluetoothSensor();
indoorTempUpdated = true;
}
#endif
#endif
if (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 (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"));
@@ -204,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(
@@ -270,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;
@@ -100,16 +100,14 @@ struct Settings {
struct {
struct {
// 0 - boiler, 1 - manual, 2 - ds18b20
byte type = 0;
byte pin = SENSOR_OUTDOOR_PIN_DEFAULT;
SensorType type = SensorType::BOILER;
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;
SensorType type = SensorType::MANUAL;
byte gpio = DEFAULT_SENSOR_INDOOR_GPIO;
uint8_t bleAddresss[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
float offset = 0.0f;
} indoor;
@@ -117,7 +115,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

@@ -1,12 +1,9 @@
#define PROJECT_NAME "OpenTherm Gateway"
#define PROJECT_VERSION "1.4.0-rc.15"
#define PROJECT_VERSION "1.4.0-rc.17"
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
#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,93 @@
#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))
enum class SensorType : byte {
BOILER,
MANUAL,
DS18B20,
BLUETOOTH
};
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;
@@ -323,12 +323,12 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
dst["equitherm"]["k_factor"] = roundd(src.equitherm.k_factor, 3);
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"]["type"] = static_cast<byte>(src.sensors.outdoor.type);
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"]["type"] = static_cast<byte>(src.sensors.indoor.type);
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;
}
}
}
@@ -558,7 +574,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
if (src["emergency"]["useEquitherm"].is<bool>()) {
if (dst.sensors.outdoor.type != 1) {
if (dst.sensors.outdoor.type != SensorType::MANUAL) {
dst.emergency.useEquitherm = src["emergency"]["useEquitherm"].as<bool>();
} else {
@@ -573,7 +589,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
if (src["emergency"]["usePid"].is<bool>()) {
if (dst.sensors.indoor.type != 1) {
if (dst.sensors.indoor.type != SensorType::MANUAL) {
dst.emergency.usePid = src["emergency"]["usePid"].as<bool>();
} else {
@@ -776,25 +792,44 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
// sensors
if (!src["sensors"]["outdoor"]["type"].isNull()) {
unsigned char value = src["sensors"]["outdoor"]["type"].as<unsigned char>();
byte value = src["sensors"]["outdoor"]["type"].as<unsigned char>();
if (value >= 0 && value <= 2) {
dst.sensors.outdoor.type = value;
switch (value) {
case static_cast<byte>(SensorType::BOILER):
dst.sensors.outdoor.type = SensorType::BOILER;
changed = true;
break;
if (dst.sensors.outdoor.type == 1) {
case static_cast<byte>(SensorType::MANUAL):
dst.sensors.outdoor.type = SensorType::MANUAL;
dst.emergency.useEquitherm = false;
}
changed = true;
break;
changed = true;
case static_cast<byte>(SensorType::DS18B20):
dst.sensors.outdoor.type = SensorType::DS18B20;
changed = true;
break;
default:
break;
}
}
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;
}
}
}
@@ -808,25 +843,52 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
}
if (!src["sensors"]["indoor"]["type"].isNull()) {
unsigned char value = src["sensors"]["indoor"]["type"].as<unsigned char>();
byte value = src["sensors"]["indoor"]["type"].as<unsigned char>();
if (value >= 1 && value <= 3) {
dst.sensors.indoor.type = value;
if (dst.sensors.indoor.type == 1) {
dst.emergency.usePid = false;
}
switch (value) {
case static_cast<byte>(SensorType::BOILER):
dst.sensors.indoor.type = SensorType::BOILER;
changed = true;
break;
changed = true;
case static_cast<byte>(SensorType::MANUAL):
dst.sensors.indoor.type = SensorType::MANUAL;
dst.emergency.useEquitherm = false;
changed = true;
break;
case static_cast<byte>(SensorType::DS18B20):
dst.sensors.indoor.type = SensorType::DS18B20;
changed = true;
break;
#if USE_BLE
case static_cast<byte>(SensorType::BLUETOOTH):
dst.sensors.indoor.type = SensorType::BLUETOOTH;
changed = true;
break;
#endif
default:
break;
}
}
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 +923,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;
}
}
}
@@ -961,7 +1031,7 @@ bool jsonToVars(const JsonVariantConst src, Variables& dst) {
if (!src["temperatures"]["indoor"].isNull()) {
double value = src["temperatures"]["indoor"].as<double>();
if (settings.sensors.indoor.type == 1 && value > -100 && value < 100) {
if (settings.sensors.indoor.type == SensorType::MANUAL && value > -100 && value < 100) {
dst.temperatures.indoor = roundd(value, 2);
changed = true;
}
@@ -970,7 +1040,7 @@ bool jsonToVars(const JsonVariantConst src, Variables& dst) {
if (!src["temperatures"]["outdoor"].isNull()) {
double value = src["temperatures"]["outdoor"].as<double>();
if (settings.sensors.outdoor.type == 1 && value > -100 && value < 100) {
if (settings.sensors.outdoor.type == SensorType::MANUAL && value > -100 && value < 100) {
dst.temperatures.outdoor = roundd(value, 2);
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);