mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-10 18:24:27 +05:00
many changes
* migrate from jandrassy/TelnetStream to lennarthennigs/ESP Telnet * ability to turn on/off output logs to telnet and serial * memory optimization * added OT parameter DHW blocking * changed algorithm for setting OpenThermMessageID::MConfigMMemberIDcode * refactoring
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
| Boiler | Master Member ID | Notes |
|
||||
| --- | --- | --- |
|
||||
| BAXI ECO Nova | default | Pressure sensor not supported, modulation level not stable |
|
||||
| BAXI Ampera | 1028 | Pressure sensor not supported, only heating (DHW not tested) |
|
||||
| BAXI Ampera | 4 | Pressure sensor not supported, only heating (DHW not tested) |
|
||||
| [Remeha Calenta Ace 40C](https://github.com/Laxilef/OTGateway/issues/1#issuecomment-1726081554) | default | - |
|
||||
| [Baxi Nuvola DUO-TEC HT 16](https://github.com/Laxilef/OTGateway/issues/3#issuecomment-1751061488) | default | - |
|
||||
| [AEG GBA124](https://github.com/Laxilef/OTGateway/issues/3#issuecomment-1765857609) | default | Pressure sensor not supported |
|
||||
@@ -220,11 +220,11 @@ In Google you can find instructions for tuning the PID controller.
|
||||
## Dependencies
|
||||
- [ESP8266Scheduler](https://github.com/nrwiersma/ESP8266Scheduler) (for ESP8266)
|
||||
- [ESP32Scheduler](https://github.com/laxilef/ESP32Scheduler) (for ESP32)
|
||||
- [NTPClient](https://github.com/arduino-libraries/NTPClient)
|
||||
<!-- - [NTPClient](https://github.com/arduino-libraries/NTPClient)-->
|
||||
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
|
||||
- [OpenTherm Library](https://github.com/ihormelnyk/opentherm_library)
|
||||
- [PubSubClient](https://github.com/knolleary/pubsubclient)
|
||||
- [TelnetStream](https://github.com/jandrassy/TelnetStream)
|
||||
- [ESPTelnet](https://github.com/LennartHennigs/ESPTelnet)
|
||||
- [EEManager](https://github.com/GyverLibs/EEManager)
|
||||
- [GyverPID](https://github.com/GyverLibs/GyverPID)
|
||||
- [GyverBlinker](https://github.com/GyverLibs/GyverBlinker)
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
[env]
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
arduino-libraries/NTPClient@^3.2.1
|
||||
;arduino-libraries/NTPClient@^3.2.1
|
||||
bblanchon/ArduinoJson@^6.20.0
|
||||
ihormelnyk/OpenTherm Library@^1.1.4
|
||||
knolleary/PubSubClient@^2.8
|
||||
jandrassy/TelnetStream@^1.2.4
|
||||
lennarthennigs/ESP Telnet@^2.1.2
|
||||
gyverlibs/EEManager@^2.0
|
||||
gyverlibs/GyverPID@^3.3
|
||||
gyverlibs/GyverBlinker@^1.0
|
||||
milesburton/DallasTemperature@^3.11.0
|
||||
laxilef/TinyLogger@^1.0.2
|
||||
laxilef/TinyLogger@^1.0.3
|
||||
https://github.com/Laxilef/WiFiManager/archive/refs/heads/patch-1.zip
|
||||
;https://github.com/tzapu/WiFiManager.git#v2.0.16-rc.2
|
||||
build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -mtext-section-literals
|
||||
@@ -66,6 +66,7 @@ build_flags =
|
||||
-D SENSOR_INDOOR_PIN_DEFAULT=14
|
||||
-D LED_STATUS_PIN=13
|
||||
-D LED_OT_RX_PIN=15
|
||||
-D USE_SERIAL=0
|
||||
-D USE_TELNET=1
|
||||
|
||||
[env:d1_mini_lite]
|
||||
@@ -82,6 +83,7 @@ build_flags =
|
||||
-D SENSOR_INDOOR_PIN_DEFAULT=14
|
||||
-D LED_STATUS_PIN=13
|
||||
-D LED_OT_RX_PIN=15
|
||||
-D USE_SERIAL=0
|
||||
-D USE_TELNET=1
|
||||
|
||||
[env:d1_mini_pro]
|
||||
@@ -98,6 +100,7 @@ build_flags =
|
||||
-D SENSOR_INDOOR_PIN_DEFAULT=14
|
||||
-D LED_STATUS_PIN=13
|
||||
-D LED_OT_RX_PIN=15
|
||||
-D USE_SERIAL=0
|
||||
-D USE_TELNET=1
|
||||
|
||||
[env:s2_mini]
|
||||
@@ -114,6 +117,7 @@ build_flags =
|
||||
-D SENSOR_INDOOR_PIN_DEFAULT=7
|
||||
-D LED_STATUS_PIN=11
|
||||
-D LED_OT_RX_PIN=12
|
||||
-D USE_SERIAL=0
|
||||
-D USE_TELNET=1
|
||||
|
||||
[env:s3_mini]
|
||||
@@ -130,6 +134,7 @@ build_flags =
|
||||
-D SENSOR_INDOOR_PIN_DEFAULT=12
|
||||
-D LED_STATUS_PIN=11
|
||||
-D LED_OT_RX_PIN=10
|
||||
-D USE_SERIAL=0
|
||||
-D USE_TELNET=1
|
||||
|
||||
[env:c3_mini]
|
||||
@@ -146,6 +151,7 @@ build_flags =
|
||||
-D SENSOR_INDOOR_PIN_DEFAULT=1
|
||||
-D LED_STATUS_PIN=4
|
||||
-D LED_OT_RX_PIN=5
|
||||
-D USE_SERIAL=0
|
||||
-D USE_TELNET=1
|
||||
|
||||
[env:nodemcu_32s]
|
||||
@@ -162,6 +168,7 @@ build_flags =
|
||||
-D SENSOR_INDOOR_PIN_DEFAULT=13
|
||||
-D LED_STATUS_PIN=2 ; 18
|
||||
-D LED_OT_RX_PIN=19
|
||||
-D USE_SERIAL=0
|
||||
-D USE_TELNET=1
|
||||
;-D WOKWI=1
|
||||
;-D USE_TELNET=0
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
extern MqttTask* tMqtt;
|
||||
extern SensorsTask* tSensors;
|
||||
extern OpenThermTask* tOt;
|
||||
extern EEManager eeSettings;
|
||||
#if USE_TELNET
|
||||
extern ESPTelnetStream TelnetStream;
|
||||
#endif
|
||||
|
||||
|
||||
class MainTask : public Task {
|
||||
public:
|
||||
@@ -42,11 +47,15 @@ protected:
|
||||
|
||||
void loop() {
|
||||
if (eeSettings.tick()) {
|
||||
Log.sinfoln("MAIN", "Settings updated (EEPROM)");
|
||||
Log.sinfoln("MAIN", PSTR("Settings updated (EEPROM)"));
|
||||
}
|
||||
|
||||
#if USE_TELNET
|
||||
TelnetStream.loop();
|
||||
#endif
|
||||
|
||||
if (vars.actions.restart) {
|
||||
Log.sinfoln("MAIN", "Restart signal received. Restart after 10 sec.");
|
||||
Log.sinfoln("MAIN", PSTR("Restart signal received. Restart after 10 sec."));
|
||||
eeSettings.updateNow();
|
||||
restartSignalTime = millis();
|
||||
vars.actions.restart = false;
|
||||
@@ -83,7 +92,7 @@ protected:
|
||||
|
||||
if (millis() - firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
|
||||
vars.states.emergency = true;
|
||||
Log.sinfoln("MAIN", "Emergency mode enabled");
|
||||
Log.sinfoln("MAIN", PSTR("Emergency mode enabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,15 +107,15 @@ protected:
|
||||
#endif
|
||||
heap();
|
||||
|
||||
#if USE_TELNET
|
||||
yield();
|
||||
// anti memory leak
|
||||
for (Stream* stream : Log.getStreams()) {
|
||||
stream->flush();
|
||||
|
||||
// anti memory leak
|
||||
TelnetStream.flush();
|
||||
while (TelnetStream.available() > 0) {
|
||||
TelnetStream.read();
|
||||
while (stream->available()) {
|
||||
stream->read();
|
||||
yield();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (restartSignalTime > 0 && millis() - restartSignalTime > 10000) {
|
||||
restartSignalTime = 0;
|
||||
@@ -128,7 +137,7 @@ protected:
|
||||
}
|
||||
|
||||
if (millis() - lastHeapInfo > 60000 || minFreeHeapSizeDiff > 0) {
|
||||
Log.sverboseln("MAIN", "Free heap size: %u of %u bytes, min: %u bytes (diff: %u bytes)", freeHeapSize, heapSize, minFreeHeapSize, minFreeHeapSizeDiff);
|
||||
Log.sverboseln("MAIN", PSTR("Free heap size: %u of %u bytes, min: %u bytes (diff: %u bytes)"), freeHeapSize, heapSize, minFreeHeapSize, minFreeHeapSizeDiff);
|
||||
lastHeapInfo = millis();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ protected:
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Log.sinfoln("MQTT", "Started");
|
||||
Log.sinfoln("MQTT", PSTR("Started"));
|
||||
|
||||
client.setCallback(__callback);
|
||||
client.setBufferSize(1024);
|
||||
@@ -39,11 +39,11 @@ protected:
|
||||
|
||||
void loop() {
|
||||
if (!client.connected() && millis() - lastReconnectAttempt >= MQTT_RECONNECT_INTERVAL) {
|
||||
Log.sinfoln("MQTT", "Not connected, state: %i, connecting to server %s...", client.state(), settings.mqtt.server);
|
||||
Log.sinfoln("MQTT", PSTR("Not connected, state: %i, connecting to server %s..."), client.state(), settings.mqtt.server);
|
||||
|
||||
client.setServer(settings.mqtt.server, settings.mqtt.port);
|
||||
if (client.connect(settings.hostname, settings.mqtt.user, settings.mqtt.password)) {
|
||||
Log.sinfoln("MQTT", "Connected");
|
||||
Log.sinfoln("MQTT", PSTR("Connected"));
|
||||
|
||||
client.subscribe(getTopicPath("settings/set").c_str());
|
||||
client.subscribe(getTopicPath("state/set").c_str());
|
||||
@@ -54,7 +54,7 @@ protected:
|
||||
lastReconnectAttempt = 0;
|
||||
|
||||
} else {
|
||||
Log.swarningln("MQTT", "Failed to connect to server");
|
||||
Log.swarningln("MQTT", PSTR("Failed to connect to server"));
|
||||
|
||||
if (settings.emergency.enable && !vars.states.emergency) {
|
||||
if (firstFailConnect == 0) {
|
||||
@@ -63,7 +63,7 @@ protected:
|
||||
|
||||
if (millis() - firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
|
||||
vars.states.emergency = true;
|
||||
Log.sinfoln("MQTT", "Emergency mode enabled");
|
||||
Log.sinfoln("MQTT", PSTR("Emergency mode enabled"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ protected:
|
||||
if (vars.states.emergency) {
|
||||
vars.states.emergency = false;
|
||||
|
||||
Log.sinfoln("MQTT", "Emergency mode disabled");
|
||||
Log.sinfoln("MQTT", PSTR("Emergency mode disabled"));
|
||||
}
|
||||
|
||||
client.loop();
|
||||
@@ -630,16 +630,16 @@ protected:
|
||||
}
|
||||
|
||||
if (settings.debug) {
|
||||
Log.strace("MQTT.MSG", "Topic: %s\r\n> ", topic);
|
||||
Log.strace("MQTT.MSG", PSTR("Topic: %s\r\n> "), topic);
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
if ( payload[i] == 10 ) {
|
||||
Log.print("\r\n> ");
|
||||
Log.print(PSTR("\r\n> "));
|
||||
|
||||
} else {
|
||||
Log.print((char) payload[i]);
|
||||
}
|
||||
}
|
||||
Log.print("\r\n\n");
|
||||
Log.print(PSTR("\r\n\n"));
|
||||
|
||||
for (Stream* stream : Log.getStreams()) {
|
||||
stream->flush();
|
||||
@@ -654,22 +654,22 @@ protected:
|
||||
case DeserializationError::EmptyInput:
|
||||
case DeserializationError::IncompleteInput:
|
||||
case DeserializationError::InvalidInput:
|
||||
errMsg = "invalid input";
|
||||
errMsg = PSTR("invalid input");
|
||||
break;
|
||||
|
||||
case DeserializationError::NoMemory:
|
||||
errMsg = "no memory";
|
||||
errMsg = PSTR("no memory");
|
||||
break;
|
||||
|
||||
case DeserializationError::TooDeep:
|
||||
errMsg = "too deep";
|
||||
errMsg = PSTR("too deep");
|
||||
break;
|
||||
|
||||
default:
|
||||
errMsg = "failed";
|
||||
errMsg = PSTR("failed");
|
||||
break;
|
||||
}
|
||||
Log.swarningln("MQTT.MSG", "No deserialization: %s", errMsg);
|
||||
Log.swarningln("MQTT.MSG", PSTR("No deserialization: %s"), errMsg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include <CustomOpenTherm.h>
|
||||
|
||||
CustomOpenTherm* ot;
|
||||
extern EEManager eeSettings;
|
||||
|
||||
|
||||
class OpenThermTask : public Task {
|
||||
public:
|
||||
@@ -46,11 +48,11 @@ protected:
|
||||
unsigned long localResponse;
|
||||
|
||||
if (setMasterMemberIdCode()) {
|
||||
Log.straceln("OT", "Slave member id code: %u", vars.parameters.slaveMemberIdCode);
|
||||
Log.straceln("OT", "Master member id code: %u", settings.opentherm.memberIdCode > 0 ? settings.opentherm.memberIdCode : vars.parameters.slaveMemberIdCode);
|
||||
Log.straceln("OT", PSTR("Slave member id code: %u"), vars.parameters.slaveMemberIdCode);
|
||||
Log.straceln("OT", PSTR("Master member id code: %u"), settings.opentherm.memberIdCode > 0 ? settings.opentherm.memberIdCode : vars.parameters.slaveMemberIdCode);
|
||||
|
||||
} else {
|
||||
Log.swarningln("OT", "Slave member id failed");
|
||||
Log.swarningln("OT", PSTR("Slave member id failed"));
|
||||
}
|
||||
|
||||
bool heatingEnabled = (vars.states.emergency || settings.heating.enable) && pump && isReady();
|
||||
@@ -69,11 +71,11 @@ protected:
|
||||
false,
|
||||
heatingCh2Enabled,
|
||||
settings.opentherm.summerWinterMode,
|
||||
false
|
||||
settings.opentherm.dhwBlocking
|
||||
);
|
||||
|
||||
if (!ot->isValidResponse(localResponse)) {
|
||||
Log.swarningln("OT", "Invalid response after setBoilerStatus: %s", ot->statusToString(ot->getLastResponseStatus()));
|
||||
Log.swarningln("OT", PSTR("Invalid response after setBoilerStatus: %s"), ot->statusToString(ot->getLastResponseStatus()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,8 +102,8 @@ protected:
|
||||
updateSlaveParameters();
|
||||
updateMasterParameters();
|
||||
|
||||
Log.straceln("OT", "Master type: %u, version: %u", vars.parameters.masterType, vars.parameters.masterVersion);
|
||||
Log.straceln("OT", "Slave type: %u, version: %u", vars.parameters.slaveType, vars.parameters.slaveVersion);
|
||||
Log.straceln("OT", PSTR("Master type: %u, version: %u"), vars.parameters.masterType, vars.parameters.masterVersion);
|
||||
Log.straceln("OT", PSTR("Slave type: %u, version: %u"), vars.parameters.slaveType, vars.parameters.slaveVersion);
|
||||
|
||||
// DHW min/max temp
|
||||
if (settings.opentherm.dhwPresent) {
|
||||
@@ -109,17 +111,17 @@ protected:
|
||||
if (settings.dhw.minTemp < vars.parameters.dhwMinTemp) {
|
||||
settings.dhw.minTemp = vars.parameters.dhwMinTemp;
|
||||
eeSettings.update();
|
||||
Log.snoticeln("OT.DHW", "Updated min temp: %d", settings.dhw.minTemp);
|
||||
Log.snoticeln("OT.DHW", PSTR("Updated min temp: %d"), settings.dhw.minTemp);
|
||||
}
|
||||
|
||||
if (settings.dhw.maxTemp > vars.parameters.dhwMaxTemp) {
|
||||
settings.dhw.maxTemp = vars.parameters.dhwMaxTemp;
|
||||
eeSettings.update();
|
||||
Log.snoticeln("OT.DHW", "Updated max temp: %d", settings.dhw.maxTemp);
|
||||
Log.snoticeln("OT.DHW", PSTR("Updated max temp: %d"), settings.dhw.maxTemp);
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.swarningln("OT.DHW", "Failed get min/max temp");
|
||||
Log.swarningln("OT.DHW", PSTR("Failed get min/max temp"));
|
||||
}
|
||||
|
||||
if (settings.dhw.minTemp >= settings.dhw.maxTemp) {
|
||||
@@ -135,17 +137,17 @@ protected:
|
||||
if (settings.heating.minTemp < vars.parameters.heatingMinTemp) {
|
||||
settings.heating.minTemp = vars.parameters.heatingMinTemp;
|
||||
eeSettings.update();
|
||||
Log.snoticeln("OT.HEATING", "Updated min temp: %d", settings.heating.minTemp);
|
||||
Log.snoticeln("OT.HEATING", PSTR("Updated min temp: %d"), settings.heating.minTemp);
|
||||
}
|
||||
|
||||
if (settings.heating.maxTemp > vars.parameters.heatingMaxTemp) {
|
||||
settings.heating.maxTemp = vars.parameters.heatingMaxTemp;
|
||||
eeSettings.update();
|
||||
Log.snoticeln("OT.HEATING", "Updated max temp: %d", settings.heating.maxTemp);
|
||||
Log.snoticeln("OT.HEATING", PSTR("Updated max temp: %d"), settings.heating.maxTemp);
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.swarningln("OT.HEATING", "Failed get min/max temp");
|
||||
Log.swarningln("OT.HEATING", PSTR("Failed get min/max temp"));
|
||||
}
|
||||
|
||||
if (settings.heating.minTemp >= settings.heating.maxTemp) {
|
||||
@@ -193,10 +195,10 @@ protected:
|
||||
if (vars.actions.resetFault) {
|
||||
if (vars.states.fault) {
|
||||
if (ot->sendBoilerReset()) {
|
||||
Log.sinfoln("OT", "Boiler fault reset successfully");
|
||||
Log.sinfoln("OT", PSTR("Boiler fault reset successfully"));
|
||||
|
||||
} else {
|
||||
Log.serrorln("OT", "Boiler fault reset failed");
|
||||
Log.serrorln("OT", PSTR("Boiler fault reset failed"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,10 +210,10 @@ protected:
|
||||
if (vars.actions.resetDiagnostic) {
|
||||
if (vars.states.diagnostic) {
|
||||
if (ot->sendServiceReset()) {
|
||||
Log.sinfoln("OT", "Boiler diagnostic reset successfully");
|
||||
Log.sinfoln("OT", PSTR("Boiler diagnostic reset successfully"));
|
||||
|
||||
} else {
|
||||
Log.serrorln("OT", "Boiler diagnostic reset failed");
|
||||
Log.serrorln("OT", PSTR("Boiler diagnostic reset failed"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +229,7 @@ protected:
|
||||
newDhwTemp = constrain(newDhwTemp, settings.dhw.minTemp, settings.dhw.maxTemp);
|
||||
}
|
||||
|
||||
Log.sinfoln("OT.DHW", "Set temp = %u", newDhwTemp);
|
||||
Log.sinfoln("OT.DHW", PSTR("Set temp = %u"), newDhwTemp);
|
||||
|
||||
// Записываем заданную температуру ГВС
|
||||
if (ot->setDhwTemp(newDhwTemp)) {
|
||||
@@ -235,12 +237,12 @@ protected:
|
||||
dhwSetTempTime = millis();
|
||||
|
||||
} else {
|
||||
Log.swarningln("OT.DHW", "Failed set temp");
|
||||
Log.swarningln("OT.DHW", PSTR("Failed set temp"));
|
||||
}
|
||||
|
||||
if (settings.opentherm.dhwToCh2) {
|
||||
if (!ot->setHeatingCh2Temp(newDhwTemp)) {
|
||||
Log.swarningln("OT.DHW", "Failed set ch2 temp");
|
||||
Log.swarningln("OT.DHW", PSTR("Failed set ch2 temp"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +250,7 @@ protected:
|
||||
//
|
||||
// Температура отопления
|
||||
if (heatingEnabled && (needSetHeatingTemp() || fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001)) {
|
||||
Log.sinfoln("OT.HEATING", "Set temp = %u", vars.parameters.heatingSetpoint);
|
||||
Log.sinfoln("OT.HEATING", PSTR("Set temp = %u"), vars.parameters.heatingSetpoint);
|
||||
|
||||
// Записываем заданную температуру
|
||||
if (ot->setHeatingCh1Temp(vars.parameters.heatingSetpoint)) {
|
||||
@@ -256,12 +258,12 @@ protected:
|
||||
heatingSetTempTime = millis();
|
||||
|
||||
} else {
|
||||
Log.swarningln("OT.HEATING", "Failed set temp");
|
||||
Log.swarningln("OT.HEATING", PSTR("Failed set temp"));
|
||||
}
|
||||
|
||||
if (settings.opentherm.heatingCh1ToCh2) {
|
||||
if (!ot->setHeatingCh2Temp(vars.parameters.heatingSetpoint)) {
|
||||
Log.swarningln("OT.HEATING", "Failed set ch2 temp");
|
||||
Log.swarningln("OT.HEATING", PSTR("Failed set ch2 temp"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,7 +345,7 @@ protected:
|
||||
}
|
||||
|
||||
void static printRequestDetail(OpenThermMessageID id, OpenThermResponseStatus status, unsigned long request, unsigned long response, byte attempt) {
|
||||
Log.straceln("OT", "OT REQUEST ID: %4d Request: %8lx Response: %8lx Attempt: %2d Status: %s", id, request, response, attempt, ot->statusToString(status));
|
||||
Log.straceln("OT", PSTR("OT REQUEST ID: %4d Request: %8lx Response: %8lx Attempt: %2d Status: %s"), id, request, response, attempt, ot->statusToString(status));
|
||||
}
|
||||
|
||||
bool setMasterMemberIdCode() {
|
||||
@@ -361,29 +363,53 @@ protected:
|
||||
if (ot->isValidResponse(response)) {
|
||||
vars.parameters.slaveMemberIdCode = response & 0xFF;
|
||||
|
||||
/*uint8_t flags = (response & 0xFFFF) >> 8;
|
||||
Log.strace(
|
||||
uint8_t flags = (response & 0xFFFF) >> 8;
|
||||
Log.straceln(
|
||||
"OT",
|
||||
"MasterMemberIdCode:\r\n DHW present: %u\r\n Control type: %u\r\n Cooling configuration: %u\r\n DHW configuration: %u\r\n Pump control: %u\r\n CH2 present: %u\r\n Remote water filling function: %u\r\n Heat/cool mode control: %u\r\n Slave MemberID Code: %u\r\n",
|
||||
flags & 0x01,
|
||||
flags & 0x02,
|
||||
flags & 0x04,
|
||||
flags & 0x08,
|
||||
flags & 0x10,
|
||||
flags & 0x20,
|
||||
flags & 0x40,
|
||||
flags & 0x80,
|
||||
response & 0xFF
|
||||
);*/
|
||||
PSTR("MasterMemberIdCode:\r\n DHW present: %u\r\n Control type: %u\r\n Cooling configuration: %u\r\n DHW configuration: %u\r\n Pump control: %u\r\n CH2 present: %u\r\n Remote water filling function: %u\r\n Heat/cool mode control: %u\r\n Slave MemberID Code: %u\r\n Raw: %u"),
|
||||
(bool) (flags & 0x01),
|
||||
(bool) (flags & 0x02),
|
||||
(bool) (flags & 0x04),
|
||||
(bool) (flags & 0x08),
|
||||
(bool) (flags & 0x10),
|
||||
(bool) (flags & 0x20),
|
||||
(bool) (flags & 0x40),
|
||||
(bool) (flags & 0x80),
|
||||
response & 0xFF,
|
||||
response
|
||||
);
|
||||
|
||||
} else if (settings.opentherm.memberIdCode <= 0) {
|
||||
}/* else if (settings.opentherm.memberIdCode <= 0) {
|
||||
return false;
|
||||
}*/
|
||||
|
||||
unsigned int responseId = response & 0xFF;
|
||||
unsigned int responseFlags = (response & 0xFFFF) >> 8;
|
||||
|
||||
unsigned int configId = settings.opentherm.memberIdCode & 0xFF;
|
||||
unsigned int configFlags = (settings.opentherm.memberIdCode & 0xFFFF) >> 8;
|
||||
|
||||
unsigned int request = 0;
|
||||
if (configId || settings.opentherm.memberIdCode > 65535) {
|
||||
request |= configId;
|
||||
} else {
|
||||
request |= responseId;
|
||||
}
|
||||
|
||||
if (configFlags || settings.opentherm.memberIdCode > 65535) {
|
||||
request |= configFlags << 8;
|
||||
} else {
|
||||
request |= responseFlags << 8;
|
||||
}
|
||||
|
||||
if (!request) {
|
||||
return false;
|
||||
}
|
||||
|
||||
response = ot->sendRequest(ot->buildRequest(
|
||||
OpenThermRequestType::WRITE,
|
||||
OpenThermMessageID::MConfigMMemberIDcode,
|
||||
settings.opentherm.memberIdCode > 0 ? settings.opentherm.memberIdCode : vars.parameters.slaveMemberIdCode
|
||||
request
|
||||
));
|
||||
|
||||
return ot->isValidResponse(response);
|
||||
|
||||
@@ -6,6 +6,7 @@ Equitherm etRegulator;
|
||||
GyverPID pidRegulator(0, 0, 0);
|
||||
PIDtuner pidTuner;
|
||||
|
||||
|
||||
class RegulatorTask : public LeanTask {
|
||||
public:
|
||||
RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||
@@ -33,7 +34,7 @@ protected:
|
||||
if (settings.heating.turbo) {
|
||||
settings.heating.turbo = false;
|
||||
|
||||
Log.sinfoln("REGULATOR", "Turbo mode auto disabled");
|
||||
Log.sinfoln("REGULATOR", PSTR("Turbo mode auto disabled"));
|
||||
}
|
||||
|
||||
newTemp = getEmergencyModeTemp();
|
||||
@@ -43,7 +44,7 @@ protected:
|
||||
if (settings.heating.turbo) {
|
||||
settings.heating.turbo = false;
|
||||
|
||||
Log.sinfoln("REGULATOR", "Turbo mode auto disabled");
|
||||
Log.sinfoln("REGULATOR", PSTR("Turbo mode auto disabled"));
|
||||
}
|
||||
|
||||
newTemp = getTuningModeTemp();
|
||||
@@ -57,7 +58,7 @@ protected:
|
||||
if (settings.heating.turbo && (fabs(settings.heating.target - vars.temperatures.indoor) < 1 || (settings.equitherm.enable && settings.pid.enable))) {
|
||||
settings.heating.turbo = false;
|
||||
|
||||
Log.sinfoln("REGULATOR", "Turbo mode auto disabled");
|
||||
Log.sinfoln("REGULATOR", PSTR("Turbo mode auto disabled"));
|
||||
}
|
||||
|
||||
newTemp = getNormalModeTemp();
|
||||
@@ -86,7 +87,7 @@ protected:
|
||||
prevEtResult = etResult;
|
||||
newTemp += etResult;
|
||||
|
||||
Log.sinfoln("REGULATOR.EQUITHERM", "New emergency result: %u (%f)", (int)round(etResult), etResult);
|
||||
Log.sinfoln("REGULATOR.EQUITHERM", PSTR("New emergency result: %u (%f)"), (int) round(etResult), etResult);
|
||||
|
||||
} else {
|
||||
newTemp += prevEtResult;
|
||||
@@ -105,11 +106,11 @@ protected:
|
||||
|
||||
if (fabs(prevHeatingTarget - settings.heating.target) > 0.0001) {
|
||||
prevHeatingTarget = settings.heating.target;
|
||||
Log.sinfoln("REGULATOR", "New target: %f", settings.heating.target);
|
||||
Log.sinfoln("REGULATOR", PSTR("New target: %f"), settings.heating.target);
|
||||
|
||||
if (settings.equitherm.enable && settings.pid.enable) {
|
||||
pidRegulator.integral = 0;
|
||||
Log.sinfoln("REGULATOR.PID", "Integral sum has been reset");
|
||||
Log.sinfoln("REGULATOR.PID", PSTR("Integral sum has been reset"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +122,7 @@ protected:
|
||||
prevEtResult = etResult;
|
||||
newTemp += etResult;
|
||||
|
||||
Log.sinfoln("REGULATOR.EQUITHERM", "New result: %u (%f)", (int)round(etResult), etResult);
|
||||
Log.sinfoln("REGULATOR.EQUITHERM", PSTR("New result: %u (%f)"), (int) round(etResult), etResult);
|
||||
|
||||
} else {
|
||||
newTemp += prevEtResult;
|
||||
@@ -139,7 +140,7 @@ protected:
|
||||
prevPidResult = pidResult;
|
||||
newTemp += pidResult;
|
||||
|
||||
Log.sinfoln("REGULATOR.PID", "New result: %d (%f)", (int)round(pidResult), pidResult);
|
||||
Log.sinfoln("REGULATOR.PID", PSTR("New result: %d (%f)"), (int) round(pidResult), pidResult);
|
||||
|
||||
} else {
|
||||
newTemp += prevPidResult;
|
||||
@@ -168,7 +169,7 @@ protected:
|
||||
tunerInit = false;
|
||||
tunerRegulator = 0;
|
||||
tunerState = 0;
|
||||
Log.sinfoln("REGULATOR.TUNING", "Stopped");
|
||||
Log.sinfoln("REGULATOR.TUNING", PSTR("Stopped"));
|
||||
}
|
||||
|
||||
if (!vars.tuning.enable) {
|
||||
@@ -178,7 +179,7 @@ protected:
|
||||
|
||||
if (vars.tuning.regulator == 0) {
|
||||
// @TODO дописать
|
||||
Log.sinfoln("REGULATOR.TUNING.EQUITHERM", "Not implemented");
|
||||
Log.sinfoln("REGULATOR.TUNING.EQUITHERM", PSTR("Not implemented"));
|
||||
return 0;
|
||||
|
||||
} else if (vars.tuning.regulator == 1) {
|
||||
@@ -188,7 +189,7 @@ protected:
|
||||
: settings.heating.target;
|
||||
|
||||
if (tunerInit && pidTuner.getState() == 3) {
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", "Finished");
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", PSTR("Finished"));
|
||||
for (Stream* stream : Log.getStreams()) {
|
||||
pidTuner.debugText(stream);
|
||||
}
|
||||
@@ -199,7 +200,7 @@ protected:
|
||||
tunerState = 0;
|
||||
|
||||
if (pidTuner.getAccuracy() < 90) {
|
||||
Log.swarningln("REGULATOR.TUNING.PID", "Bad result, try again...");
|
||||
Log.swarningln("REGULATOR.TUNING.PID", PSTR("Bad result, try again..."));
|
||||
|
||||
} else {
|
||||
settings.pid.p_factor = pidTuner.getPID_p();
|
||||
@@ -211,7 +212,7 @@ protected:
|
||||
}
|
||||
|
||||
if (!tunerInit) {
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", "Start...");
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", PSTR("Start..."));
|
||||
|
||||
float step;
|
||||
if (vars.temperatures.indoor - vars.temperatures.outdoor > 10) {
|
||||
@@ -221,7 +222,7 @@ protected:
|
||||
}
|
||||
|
||||
float startTemp = step;
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", "Started. Start value: %f, step: %f", startTemp, step);
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", PSTR("Started. Start value: %f, step: %f"), startTemp, step);
|
||||
pidTuner.setParameters(NORMAL, startTemp, step, 20 * 60 * 1000, 0.15, 60 * 1000, 10000);
|
||||
tunerInit = true;
|
||||
tunerRegulator = 1;
|
||||
@@ -231,7 +232,7 @@ protected:
|
||||
pidTuner.compute();
|
||||
|
||||
if (tunerState > 0 && pidTuner.getState() != tunerState) {
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", "Log:");
|
||||
Log.sinfoln("REGULATOR.TUNING.PID", PSTR("Log:"));
|
||||
for (Stream* stream : Log.getStreams()) {
|
||||
pidTuner.debugText(stream);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <OneWire.h>
|
||||
#include <DallasTemperature.h>
|
||||
|
||||
|
||||
class SensorsTask : public LeanTask {
|
||||
public:
|
||||
SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||
@@ -59,7 +60,7 @@ protected:
|
||||
outdoorSensor->requestTemperatures();
|
||||
startConversionTime = millis();
|
||||
|
||||
Log.serrorln("SENSORS.OUTDOOR", "Could not read temperature data (no response)");
|
||||
Log.serrorln("SENSORS.OUTDOOR", PSTR("Could not read temperature data (no response)"));
|
||||
}
|
||||
|
||||
if (!completed) {
|
||||
@@ -68,10 +69,10 @@ protected:
|
||||
|
||||
float rawTemp = outdoorSensor->getTempCByIndex(0);
|
||||
if (rawTemp == DEVICE_DISCONNECTED_C) {
|
||||
Log.serrorln("SENSORS.OUTDOOR", "Could not read temperature data (not connected)");
|
||||
Log.serrorln("SENSORS.OUTDOOR", PSTR("Could not read temperature data (not connected)"));
|
||||
|
||||
} else {
|
||||
Log.straceln("SENSORS.OUTDOOR", "Raw temp: %f", rawTemp);
|
||||
Log.straceln("SENSORS.OUTDOOR", PSTR("Raw temp: %f"), rawTemp);
|
||||
|
||||
if (emptyOutdoorTemp) {
|
||||
filteredOutdoorTemp = rawTemp;
|
||||
@@ -85,7 +86,7 @@ protected:
|
||||
|
||||
if (fabs(vars.temperatures.outdoor - filteredOutdoorTemp) > 0.099) {
|
||||
vars.temperatures.outdoor = filteredOutdoorTemp + settings.sensors.outdoor.offset;
|
||||
Log.sinfoln("SENSORS.OUTDOOR", "New temp: %f", filteredOutdoorTemp);
|
||||
Log.sinfoln("SENSORS.OUTDOOR", PSTR("New temp: %f"), filteredOutdoorTemp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +117,7 @@ protected:
|
||||
indoorSensor->requestTemperatures();
|
||||
startConversionTime = millis();
|
||||
|
||||
Log.serrorln("SENSORS.INDOOR", "Could not read temperature data (no response)");
|
||||
Log.serrorln("SENSORS.INDOOR", PSTR("Could not read temperature data (no response)"));
|
||||
}
|
||||
|
||||
if (!completed) {
|
||||
@@ -125,10 +126,10 @@ protected:
|
||||
|
||||
float rawTemp = indoorSensor->getTempCByIndex(0);
|
||||
if (rawTemp == DEVICE_DISCONNECTED_C) {
|
||||
Log.serrorln("SENSORS.INDOOR", "Could not read temperature data (not connected)");
|
||||
Log.serrorln("SENSORS.INDOOR", PSTR("Could not read temperature data (not connected)"));
|
||||
|
||||
} else {
|
||||
Log.straceln("SENSORS.INDOOR", "Raw temp: %f", rawTemp);
|
||||
Log.straceln("SENSORS.INDOOR", PSTR("Raw temp: %f"), rawTemp);
|
||||
|
||||
if (emptyIndoorTemp) {
|
||||
filteredIndoorTemp = rawTemp;
|
||||
@@ -142,7 +143,7 @@ protected:
|
||||
|
||||
if (fabs(vars.temperatures.indoor - filteredIndoorTemp) > 0.099) {
|
||||
vars.temperatures.indoor = filteredIndoorTemp + settings.sensors.indoor.offset;
|
||||
Log.sinfoln("SENSORS.INDOOR", "New temp: %f", filteredIndoorTemp);
|
||||
Log.sinfoln("SENSORS.INDOOR", PSTR("New temp: %f"), filteredIndoorTemp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ struct Settings {
|
||||
bool heatingCh2Enabled = true;
|
||||
bool heatingCh1ToCh2 = false;
|
||||
bool dhwToCh2 = false;
|
||||
bool dhwBlocking = false;
|
||||
} opentherm;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <WiFiManagerParameters.h>
|
||||
#include <netif/etharp.h>
|
||||
|
||||
|
||||
WiFiManager wm;
|
||||
WiFiManagerParameter* wmHostname;
|
||||
WiFiManagerParameter* wmMqttServer;
|
||||
@@ -20,12 +19,18 @@ CheckboxParameter* wmOtSummerWinterMode;
|
||||
CheckboxParameter* wmOtHeatingCh2Enabled;
|
||||
CheckboxParameter* wmOtHeatingCh1ToCh2;
|
||||
CheckboxParameter* wmOtDhwToCh2;
|
||||
CheckboxParameter* wmOtDhwBlocking;
|
||||
UnsignedIntParameter* wmOutdoorSensorPin;
|
||||
UnsignedIntParameter* wmIndoorSensorPin;
|
||||
|
||||
SeparatorParameter* wmSep1;
|
||||
SeparatorParameter* wmSep2;
|
||||
|
||||
extern EEManager eeSettings;
|
||||
#if USE_TELNET
|
||||
extern ESPTelnetStream TelnetStream;
|
||||
#endif
|
||||
|
||||
|
||||
class WifiManagerTask : public Task {
|
||||
public:
|
||||
@@ -109,6 +114,9 @@ protected:
|
||||
wmOtDhwToCh2 = new CheckboxParameter("ot_dhw_to_ch2", "Opentherm DHW to CH2", settings.opentherm.dhwToCh2);
|
||||
wm.addParameter(wmOtDhwToCh2);
|
||||
|
||||
wmOtDhwBlocking = new CheckboxParameter("ot_dhw_blocking", "Opentherm DHW blocking", settings.opentherm.dhwBlocking);
|
||||
wm.addParameter(wmOtDhwBlocking);
|
||||
|
||||
wmSep2 = new SeparatorParameter();
|
||||
wm.addParameter(wmSep2);
|
||||
|
||||
@@ -150,7 +158,7 @@ protected:
|
||||
TelnetStream.stop();
|
||||
#endif
|
||||
|
||||
Log.sinfoln("WIFI", "Disconnected");
|
||||
Log.sinfoln("WIFI", PSTR("Disconnected"));
|
||||
|
||||
} else if (!connected && WiFi.status() == WL_CONNECTED) {
|
||||
connected = true;
|
||||
@@ -167,10 +175,10 @@ protected:
|
||||
}
|
||||
|
||||
#if USE_TELNET
|
||||
TelnetStream.begin();
|
||||
TelnetStream.begin(23, false);
|
||||
#endif
|
||||
|
||||
Log.sinfoln("WIFI", "Connected. IP: %s, RSSI: %d", WiFi.localIP().toString().c_str(), WiFi.RSSI());
|
||||
Log.sinfoln("WIFI", PSTR("Connected. IP: %s, RSSI: %d"), WiFi.localIP().toString().c_str(), WiFi.RSSI());
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
@@ -295,6 +303,11 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
if (wmOtDhwBlocking->getCheckboxValue() != settings.opentherm.dhwBlocking) {
|
||||
changed = true;
|
||||
settings.opentherm.dhwBlocking = wmOtDhwBlocking->getCheckboxValue();
|
||||
}
|
||||
|
||||
if (wmOutdoorSensorPin->getValue() != settings.sensors.outdoor.pin) {
|
||||
changed = true;
|
||||
needRestart = true;
|
||||
@@ -317,7 +330,7 @@ protected:
|
||||
|
||||
Log.sinfo(
|
||||
"WIFI",
|
||||
"New settings:\r\n"
|
||||
PSTR("New settings:\r\n"
|
||||
" Hostname: %s\r\n"
|
||||
" Mqtt server: %s:%d\r\n"
|
||||
" Mqtt user: %s\r\n"
|
||||
@@ -332,8 +345,9 @@ protected:
|
||||
" OT heating ch2 enabled: %d\r\n"
|
||||
" OT heating ch1 to ch2: %d\r\n"
|
||||
" OT DHW to ch2: %d\r\n"
|
||||
" OT DHW blocking: %d\r\n"
|
||||
" Outdoor sensor pin: %d\r\n"
|
||||
" Indoor sensor pin: %d\r\n",
|
||||
" Indoor sensor pin: %d\r\n"),
|
||||
settings.hostname,
|
||||
settings.mqtt.server,
|
||||
settings.mqtt.port,
|
||||
@@ -349,11 +363,12 @@ protected:
|
||||
settings.opentherm.heatingCh2Enabled,
|
||||
settings.opentherm.heatingCh1ToCh2,
|
||||
settings.opentherm.dhwToCh2,
|
||||
settings.opentherm.dhwBlocking,
|
||||
settings.sensors.outdoor.pin,
|
||||
settings.sensors.indoor.pin
|
||||
);
|
||||
|
||||
eeSettings.updateNow();
|
||||
eeSettings.update();
|
||||
}
|
||||
|
||||
static void arpGratuitous() {
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
#define WM_DEBUG_MODE WM_DEBUG_NOTIFY
|
||||
#endif
|
||||
|
||||
#ifndef USE_SERIAL
|
||||
#define USE_SERIAL true
|
||||
#endif
|
||||
|
||||
#ifndef USE_TELNET
|
||||
#define USE_TELNET true
|
||||
#endif
|
||||
|
||||
42
src/main.cpp
42
src/main.cpp
@@ -1,25 +1,24 @@
|
||||
#include <Arduino.h>
|
||||
#include "defines.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <TelnetStream.h>
|
||||
#include <EEManager.h>
|
||||
#include <TinyLogger.h>
|
||||
#include "Settings.h"
|
||||
|
||||
EEManager eeSettings(settings, 60000);
|
||||
#if USE_TELNET
|
||||
#include "ESPTelnetStream.h"
|
||||
#endif
|
||||
|
||||
#if defined(ESP32)
|
||||
#include <ESP32Scheduler.h>
|
||||
#include <Task.h>
|
||||
#include <LeanTask.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <Scheduler.h>
|
||||
#include <Task.h>
|
||||
#include <LeanTask.h>
|
||||
#elif
|
||||
#error Wrong board. Supported boards: esp8266, esp32
|
||||
#endif
|
||||
|
||||
#include <Task.h>
|
||||
#include <LeanTask.h>
|
||||
#include "WifiManagerTask.h"
|
||||
#include "MqttTask.h"
|
||||
#include "OpenThermTask.h"
|
||||
@@ -27,6 +26,12 @@ EEManager eeSettings(settings, 60000);
|
||||
#include "RegulatorTask.h"
|
||||
#include "MainTask.h"
|
||||
|
||||
// Vars
|
||||
EEManager eeSettings(settings, 60000);
|
||||
#if USE_TELNET
|
||||
ESPTelnetStream TelnetStream;
|
||||
#endif
|
||||
|
||||
// Tasks
|
||||
WifiManagerTask* tWm;
|
||||
MqttTask* tMqtt;
|
||||
@@ -37,34 +42,35 @@ MainTask* tMain;
|
||||
|
||||
|
||||
void setup() {
|
||||
Log.setLevel(TinyLogger::Level::VERBOSE);
|
||||
#if USE_SERIAL
|
||||
Serial.begin(115200);
|
||||
Log.addStream(&Serial);
|
||||
Serial.println("\n\n");
|
||||
#endif
|
||||
|
||||
#if USE_TELNET
|
||||
TelnetStream.begin();
|
||||
Log.begin(&TelnetStream, TinyLogger::Level::VERBOSE);
|
||||
delay(1000);
|
||||
#else
|
||||
Serial.begin(115200);
|
||||
Log.begin(&Serial, TinyLogger::Level::VERBOSE);
|
||||
Serial.println("\n\n");
|
||||
Log.addStream(&TelnetStream);
|
||||
#endif
|
||||
//Log.setNtpClient(&timeClient);
|
||||
|
||||
EEPROM.begin(eeSettings.blockSize());
|
||||
uint8_t eeSettingsResult = eeSettings.begin(0, 's');
|
||||
if (eeSettingsResult == 0) {
|
||||
Log.sinfoln("MAIN", "Settings loaded");
|
||||
Log.sinfoln("MAIN", PSTR("Settings loaded"));
|
||||
|
||||
if (strcmp(SETTINGS_VALID_VALUE, settings.validationValue) != 0) {
|
||||
Log.swarningln("MAIN", "Settings not valid, reset and restart...");
|
||||
Log.swarningln("MAIN", PSTR("Settings not valid, reset and restart..."));
|
||||
eeSettings.reset();
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
} else if (eeSettingsResult == 1) {
|
||||
Log.sinfoln("MAIN", "Settings NOT loaded, first start");
|
||||
Log.sinfoln("MAIN", PSTR("Settings NOT loaded, first start"));
|
||||
|
||||
} else if (eeSettingsResult == 2) {
|
||||
Log.serrorln("MAIN", "Settings NOT loaded (error)");
|
||||
Log.serrorln("MAIN", PSTR("Settings NOT loaded (error)"));
|
||||
}
|
||||
|
||||
Log.setLevel(settings.debug ? TinyLogger::Level::VERBOSE : TinyLogger::Level::INFO);
|
||||
@@ -84,7 +90,7 @@ void setup() {
|
||||
tRegulator = new RegulatorTask(true, 10000);
|
||||
Scheduler.start(tRegulator);
|
||||
|
||||
tMain = new MainTask(true, 50);
|
||||
tMain = new MainTask(true, 10);
|
||||
Scheduler.start(tMain);
|
||||
|
||||
Scheduler.begin();
|
||||
|
||||
Reference in New Issue
Block a user