diff --git a/lib/WiFiManagerParameters/CheckboxParameter.h b/lib/WiFiManagerParameters/CheckboxParameter.h new file mode 100644 index 0000000..7392ca2 --- /dev/null +++ b/lib/WiFiManagerParameters/CheckboxParameter.h @@ -0,0 +1,29 @@ +#pragma once +#include + +class CheckboxParameter : public WiFiManagerParameter { +public: + const char* checked = "type=\"checkbox\" checked"; + const char* noChecked = "type=\"checkbox\""; + const char* trueVal = "T"; + + CheckboxParameter(const char* id, const char* label, bool value) : WiFiManagerParameter("") { + init(id, label, String(value ? trueVal : "0").c_str(), 1, "", WFM_LABEL_AFTER); + } + + const char* getValue() const override { + return trueVal; + } + + void setValue(bool value) { + WiFiManagerParameter::setValue(value ? trueVal : "0", 1); + } + + const char* getCustomHTML() const override { + return strcmp(WiFiManagerParameter::getValue(), trueVal) == 0 ? checked : noChecked; + } + + bool getCheckboxValue() { + return strcmp(WiFiManagerParameter::getValue(), trueVal) == 0 ? true : false; + } +}; \ No newline at end of file diff --git a/lib/WiFiManagerParameters/DoubleParameter.h b/lib/WiFiManagerParameters/DoubleParameter.h new file mode 100644 index 0000000..8e18f98 --- /dev/null +++ b/lib/WiFiManagerParameters/DoubleParameter.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class DoubleParameter : public WiFiManagerParameter { +public: + DoubleParameter(const char* id, const char* label, double value, const uint8_t length = 10) : WiFiManagerParameter("") { + init(id, label, String(value, length - 1).c_str(), length, "", WFM_LABEL_DEFAULT); + } + + double getValue() { + return atof(WiFiManagerParameter::getValue()); + } + + void setValue(double value, int length) { + WiFiManagerParameter::setValue(String(value, length - 1).c_str(), length); + } + + void setValue(double value) { + setValue(value, getValueLength()); + } +}; \ No newline at end of file diff --git a/lib/WiFiManagerParameters/IntParameter.h b/lib/WiFiManagerParameters/IntParameter.h new file mode 100644 index 0000000..9989acf --- /dev/null +++ b/lib/WiFiManagerParameters/IntParameter.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class IntParameter : public WiFiManagerParameter { +public: + IntParameter(const char* id, const char* label, int value, const uint8_t length = 10) : WiFiManagerParameter("") { + init(id, label, String(value).c_str(), length, "", WFM_LABEL_DEFAULT); + } + + int getValue() { + return atoi(WiFiManagerParameter::getValue()); + } + + void setValue(int value, int length) { + WiFiManagerParameter::setValue(String(value).c_str(), length); + } + + void setValue(int value) { + setValue(value, getValueLength()); + } +}; \ No newline at end of file diff --git a/lib/WiFiManagerParameters/SeparatorParameter.h b/lib/WiFiManagerParameters/SeparatorParameter.h new file mode 100644 index 0000000..292cb53 --- /dev/null +++ b/lib/WiFiManagerParameters/SeparatorParameter.h @@ -0,0 +1,8 @@ +#pragma once +#include + + +class SeparatorParameter : public WiFiManagerParameter { +public: + SeparatorParameter() : WiFiManagerParameter("
") {} +}; \ No newline at end of file diff --git a/lib/WiFiManagerParameters/ShortParameter.h b/lib/WiFiManagerParameters/ShortParameter.h new file mode 100644 index 0000000..a378da0 --- /dev/null +++ b/lib/WiFiManagerParameters/ShortParameter.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class ShortParameter : public WiFiManagerParameter { +public: + ShortParameter(const char* id, const char* label, short value, const uint8_t length = 10) : WiFiManagerParameter("") { + init(id, label, String(value).c_str(), length, "", WFM_LABEL_DEFAULT); + } + + short getValue() { + return atoi(WiFiManagerParameter::getValue()); + } + + void setValue(short value, int length) { + WiFiManagerParameter::setValue(String(value).c_str(), length); + } + + void setValue(short value) { + setValue(value, getValueLength()); + } +}; \ No newline at end of file diff --git a/lib/WiFiManagerParameters/UnsignedIntParameter.h b/lib/WiFiManagerParameters/UnsignedIntParameter.h new file mode 100644 index 0000000..c5d7720 --- /dev/null +++ b/lib/WiFiManagerParameters/UnsignedIntParameter.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class UnsignedIntParameter : public WiFiManagerParameter { +public: + UnsignedIntParameter(const char* id, const char* label, unsigned int value, const uint8_t length = 10) : WiFiManagerParameter("") { + init(id, label, String(value).c_str(), length, "", WFM_LABEL_DEFAULT); + } + + unsigned int getValue() { + return (unsigned int) atoi(WiFiManagerParameter::getValue()); + } + + void setValue(unsigned int value, int length) { + WiFiManagerParameter::setValue(String(value).c_str(), length); + } + + void setValue(unsigned int value) { + setValue(value, getValueLength()); + } +}; \ No newline at end of file diff --git a/lib/WiFiManagerParameters/UnsignedShortParameter.h b/lib/WiFiManagerParameters/UnsignedShortParameter.h new file mode 100644 index 0000000..7e702b3 --- /dev/null +++ b/lib/WiFiManagerParameters/UnsignedShortParameter.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class UnsignedShortParameter : public WiFiManagerParameter { +public: + UnsignedShortParameter(const char* id, const char* label, unsigned short value, const uint8_t length = 10) : WiFiManagerParameter("") { + init(id, label, String(value).c_str(), length, "", WFM_LABEL_DEFAULT); + } + + unsigned short getValue() { + return (unsigned short) atoi(WiFiManagerParameter::getValue()); + } + + void setValue(unsigned short value, int length) { + WiFiManagerParameter::setValue(String(value).c_str(), length); + } + + void setValue(unsigned short value) { + setValue(value, getValueLength()); + } +}; \ No newline at end of file diff --git a/lib/WiFiManagerParameters/WiFiManagerParameters.h b/lib/WiFiManagerParameters/WiFiManagerParameters.h deleted file mode 100644 index cbe916b..0000000 --- a/lib/WiFiManagerParameters/WiFiManagerParameters.h +++ /dev/null @@ -1,88 +0,0 @@ -class IntParameter : public WiFiManagerParameter { -public: - IntParameter(const char* id, const char* label, int value, const uint8_t length = 10) : WiFiManagerParameter("") { - init(id, label, String(value).c_str(), length, "", WFM_LABEL_DEFAULT); - } - - int getValue() { - return atoi(WiFiManagerParameter::getValue()); - } - - void setValue(int value, int length) { - WiFiManagerParameter::setValue(String(value).c_str(), length); - } - - void setValue(int value) { - setValue(value, getValueLength()); - } -}; - -class UnsignedIntParameter : public WiFiManagerParameter { -public: - UnsignedIntParameter(const char* id, const char* label, unsigned int value, const uint8_t length = 10) : WiFiManagerParameter("") { - init(id, label, String(value).c_str(), length, "", WFM_LABEL_DEFAULT); - } - - unsigned int getValue() { - return (unsigned int) atoi(WiFiManagerParameter::getValue()); - } - - void setValue(unsigned int value, int length) { - WiFiManagerParameter::setValue(String(value).c_str(), length); - } - - void setValue(unsigned int value) { - setValue(value, getValueLength()); - } -}; - -class DoubleParameter : public WiFiManagerParameter { -public: - DoubleParameter(const char* id, const char* label, double value, const uint8_t length = 10) : WiFiManagerParameter("") { - init(id, label, String(value, length - 1).c_str(), length, "", WFM_LABEL_DEFAULT); - } - - double getValue() { - return atof(WiFiManagerParameter::getValue()); - } - - void setValue(double value, int length) { - WiFiManagerParameter::setValue(String(value, length - 1).c_str(), length); - } - - void setValue(double value) { - setValue(value, getValueLength()); - } -}; - -class CheckboxParameter : public WiFiManagerParameter { -public: - const char* checked = "type=\"checkbox\" checked"; - const char* noChecked = "type=\"checkbox\""; - const char* trueVal = "T"; - - CheckboxParameter(const char* id, const char* label, bool value) : WiFiManagerParameter("") { - init(id, label, String(value ? trueVal : "0").c_str(), 1, "", WFM_LABEL_AFTER); - } - - const char* getValue() const override { - return trueVal; - } - - void setValue(bool value) { - WiFiManagerParameter::setValue(value ? trueVal : "0", 1); - } - - const char* getCustomHTML() const override { - return strcmp(WiFiManagerParameter::getValue(), trueVal) == 0 ? checked : noChecked; - } - - bool getCheckboxValue() { - return strcmp(WiFiManagerParameter::getValue(), trueVal) == 0 ? true : false; - } -}; - -class SeparatorParameter : public WiFiManagerParameter { -public: - SeparatorParameter() : WiFiManagerParameter("
") {} -}; \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 9d9b681..20c7c2d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,8 @@ framework = arduino lib_deps = ;arduino-libraries/NTPClient@^3.2.1 bblanchon/ArduinoJson@^6.20.0 - ihormelnyk/OpenTherm Library@^1.1.4 + ;ihormelnyk/OpenTherm Library@^1.1.4 + https://github.com/Laxilef/opentherm_library/archive/refs/heads/master.zip knolleary/PubSubClient@^2.8 bblanchon/StreamUtils@^1.7.3 lennarthennigs/ESP Telnet@^2.1.2 @@ -31,7 +32,7 @@ build_flags = -D USE_TELNET=1 upload_speed = 921600 monitor_speed = 115200 -version = 1.3.4 +version = 1.4.0 ; Defaults [esp8266_defaults] @@ -167,7 +168,7 @@ build_flags = ;-D DEBUG_BY_DEFAULT=1 ;-D WM_DEBUG_MODE=3 -[env:wemos_d1_mini32] +[env:d1_mini32] platform = ${esp32_defaults.platform} board = wemos_d1_mini32 lib_deps = ${esp32_defaults.lib_deps} diff --git a/src/MainTask.h b/src/MainTask.h index cd9cda1..ee49234 100644 --- a/src/MainTask.h +++ b/src/MainTask.h @@ -14,12 +14,19 @@ public: MainTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {} protected: + const static byte REASON_PUMP_START_HEATING = 1; + const static byte REASON_PUMP_START_ANTISTUCK = 2; + Blinker* blinker = nullptr; unsigned long lastHeapInfo = 0; unsigned long firstFailConnect = 0; unsigned int heapSize = 0; unsigned int minFreeHeapSize = 0; unsigned long restartSignalTime = 0; + bool heatingEnabled = false; + unsigned long heatingDisabledTime = 0; + byte externalPumpStartReason; + unsigned long externalPumpStartTime = 0; const char* getTaskName() { return "Main"; @@ -38,6 +45,7 @@ protected: pinMode(LED_STATUS_PIN, OUTPUT); digitalWrite(LED_STATUS_PIN, false); #endif + pinMode(settings.externalPump.pin, OUTPUT); #if defined(ESP32) heapSize = ESP.getHeapSize(); @@ -107,9 +115,9 @@ protected: #ifdef LED_STATUS_PIN ledStatus(LED_STATUS_PIN); - yield(); #endif heap(); + externalPump(); // anti memory leak if (Log.lock()) { @@ -207,4 +215,67 @@ protected: this->blinker->tick(); } + + void externalPump() { + if (!vars.states.heating && this->heatingEnabled) { + this->heatingEnabled = false; + this->heatingDisabledTime = millis(); + + } else if (vars.states.heating && !this->heatingEnabled) { + this->heatingEnabled = true; + } + + if (!settings.externalPump.use) { + if (vars.externalPump.enable) { + digitalWrite(settings.externalPump.pin, false); + + vars.externalPump.enable = false; + vars.externalPump.lastEnableTime = millis(); + + Log.sinfoln("EXTPUMP", F("Disabled: use = off")); + } + + return; + } + + if (vars.externalPump.enable && !this->heatingEnabled) { + if (this->externalPumpStartReason == MainTask::REASON_PUMP_START_HEATING && millis() - this->heatingDisabledTime > settings.externalPump.postCirculationTime) { + digitalWrite(settings.externalPump.pin, false); + + vars.externalPump.enable = false; + vars.externalPump.lastEnableTime = millis(); + + Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time")); + + } else if (this->externalPumpStartReason == MainTask::REASON_PUMP_START_ANTISTUCK && millis() - this->externalPumpStartTime >= settings.externalPump.antiStuckTime) { + digitalWrite(settings.externalPump.pin, false); + + vars.externalPump.enable = false; + vars.externalPump.lastEnableTime = millis(); + + Log.sinfoln("EXTPUMP", F("Disabled: expired anti stuck time")); + } + + } else if (vars.externalPump.enable && this->heatingEnabled && this->externalPumpStartReason == MainTask::REASON_PUMP_START_ANTISTUCK) { + this->externalPumpStartReason = MainTask::REASON_PUMP_START_HEATING; + + } else if (!vars.externalPump.enable && this->heatingEnabled) { + vars.externalPump.enable = true; + this->externalPumpStartTime = millis(); + this->externalPumpStartReason = MainTask::REASON_PUMP_START_HEATING; + + digitalWrite(settings.externalPump.pin, true); + + Log.sinfoln("EXTPUMP", F("Enabled: heating on")); + + } else if (!vars.externalPump.enable && millis() - vars.externalPump.lastEnableTime >= settings.externalPump.antiStuckInterval) { + vars.externalPump.enable = true; + this->externalPumpStartTime = millis(); + this->externalPumpStartReason = MainTask::REASON_PUMP_START_ANTISTUCK; + + digitalWrite(settings.externalPump.pin, true); + + Log.sinfoln("EXTPUMP", F("Enabled: anti stuck")); + } + } }; \ No newline at end of file diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index f521837..99822e6 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -55,11 +55,6 @@ protected: pinMode(LED_OT_RX_PIN, OUTPUT); digitalWrite(LED_OT_RX_PIN, false); #endif - - #ifdef HEATING_STATUS_PIN - pinMode(HEATING_STATUS_PIN, OUTPUT); - digitalWrite(HEATING_STATUS_PIN, false); - #endif } void loop() { @@ -127,10 +122,6 @@ protected: prevUpdateNonEssentialVars = 0; vars.parameters.heatingEnabled = heatingEnabled; Log.sinfoln(FPSTR(S_OT_HEATING), "%s", heatingEnabled ? F("Enabled") : F("Disabled")); - - #ifdef HEATING_STATUS_PIN - digitalWrite(HEATING_STATUS_PIN, heatingEnabled); - #endif } vars.states.heating = ot->isCentralHeatingActive(localResponse); diff --git a/src/Settings.h b/src/Settings.h index 0a6da03..6e34f50 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -79,6 +79,14 @@ struct Settings { } indoor; } sensors; + struct { + bool use = false; + byte pin = EXT_PUMP_PIN_DEFAULT; + unsigned short postCirculationTime = 600; + unsigned int antiStuckInterval = 2592000; + unsigned short antiStuckTime = 300; + } externalPump; + char validationValue[8] = SETTINGS_VALID_VALUE; } settings; @@ -113,6 +121,11 @@ struct Variables { float dhw = 0.0f; } temperatures; + struct { + bool enable = false; + unsigned long lastEnableTime = 0; + } externalPump; + struct { bool heatingEnabled = false; byte heatingMinTemp = DEFAULT_HEATING_MIN_TEMP; diff --git a/src/WifiManagerTask.h b/src/WifiManagerTask.h index 5a763b1..659c595 100644 --- a/src/WifiManagerTask.h +++ b/src/WifiManagerTask.h @@ -1,6 +1,9 @@ #define WM_MDNS #include -#include +#include +#include +#include +#include #include WiFiManager wm; @@ -11,6 +14,7 @@ WiFiManagerParameter* wmMqttUser; WiFiManagerParameter* wmMqttPassword; WiFiManagerParameter* wmMqttPrefix; UnsignedIntParameter* wmMqttPublishInterval; + UnsignedIntParameter* wmOtInPin; UnsignedIntParameter* wmOtOutPin; UnsignedIntParameter* wmOtMemberIdCode; @@ -21,11 +25,17 @@ CheckboxParameter* wmOtHeatingCh1ToCh2; CheckboxParameter* wmOtDhwToCh2; CheckboxParameter* wmOtDhwBlocking; CheckboxParameter* wmOtModSyncWithHeating; + UnsignedIntParameter* wmOutdoorSensorPin; UnsignedIntParameter* wmIndoorSensorPin; -SeparatorParameter* wmSep1; -SeparatorParameter* wmSep2; +CheckboxParameter* wmExtPumpUse; +UnsignedIntParameter* wmExtPumpPin; +UnsignedShortParameter* wmExtPumpPostCirculationTime; +UnsignedIntParameter* wmExtPumpAntiStuckInterval; +UnsignedShortParameter* wmExtPumpAntiStuckTime; + +SeparatorParameter* wmSep; extern EEManager eeSettings; #if USE_TELNET @@ -37,7 +47,7 @@ class WifiManagerTask : public Task { public: WifiManagerTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {} - WifiManagerTask* addTaskForDisable(Task* task) { + WifiManagerTask* addTaskForDisable(AbstractTask* task) { this->tasksForDisable.push_back(task); return this; } @@ -45,7 +55,7 @@ public: protected: bool connected = false; unsigned long lastArpGratuitous = 0; - std::vector tasksForDisable; + std::vector tasksForDisable; const char* getTaskName() { return "WifiManager"; @@ -77,6 +87,8 @@ protected: std::vector menu = {"custom", "wifi", "param", "sep", "info", "update", "restart"}; wm.setMenu(menu); + wmSep = new SeparatorParameter(); + wmHostname = new WiFiManagerParameter("hostname", "Hostname", settings.hostname, 80); wm.addParameter(wmHostname); @@ -98,8 +110,7 @@ protected: wmMqttPublishInterval = new UnsignedIntParameter("mqtt_publish_interval", "MQTT publish interval", settings.mqtt.interval, 5); wm.addParameter(wmMqttPublishInterval); - wmSep1 = new SeparatorParameter(); - wm.addParameter(wmSep1); + wm.addParameter(wmSep); wmOtInPin = new UnsignedIntParameter("ot_in_pin", "Opentherm GPIO IN", settings.opentherm.inPin, 2); wm.addParameter(wmOtInPin); @@ -131,8 +142,7 @@ protected: wmOtModSyncWithHeating = new CheckboxParameter("ot_mod_sync_with_heating", "Modulation sync with heating", settings.opentherm.modulationSyncWithHeating); wm.addParameter(wmOtModSyncWithHeating); - wmSep2 = new SeparatorParameter(); - wm.addParameter(wmSep2); + wm.addParameter(wmSep); wmOutdoorSensorPin = new UnsignedIntParameter("outdoor_sensor_pin", "Outdoor sensor GPIO", settings.sensors.outdoor.pin, 2); wm.addParameter(wmOutdoorSensorPin); @@ -140,6 +150,23 @@ protected: wmIndoorSensorPin = new UnsignedIntParameter("indoor_sensor_pin", "Indoor sensor GPIO", settings.sensors.indoor.pin, 2); wm.addParameter(wmIndoorSensorPin); + wm.addParameter(wmSep); + + wmExtPumpUse = new CheckboxParameter("ext_pump_use", "Use external pump", settings.externalPump.use); + wm.addParameter(wmExtPumpUse); + + wmExtPumpPin = new UnsignedIntParameter("ext_pump_pin", "External pump GPIO", settings.externalPump.pin, 2); + wm.addParameter(wmExtPumpPin); + + wmExtPumpPostCirculationTime = new UnsignedShortParameter("ext_pump_ps_time", "External pump post circulation time", settings.externalPump.postCirculationTime, 5); + wm.addParameter(wmExtPumpPostCirculationTime); + + wmExtPumpAntiStuckInterval = new UnsignedIntParameter("ext_pump_as_interval", "External pump anti stuck interval", settings.externalPump.antiStuckInterval, 7); + wm.addParameter(wmExtPumpAntiStuckInterval); + + wmExtPumpAntiStuckTime = new UnsignedShortParameter("ext_pump_as_time", "External pump anti stuck time", settings.externalPump.antiStuckTime, 5); + wm.addParameter(wmExtPumpAntiStuckTime); + //wm.setCleanConnect(true); wm.setRestorePersistent(false); @@ -149,7 +176,7 @@ protected: wm.setConfigPortalBlocking(false); wm.setSaveParamsCallback(saveParamsCallback); wm.setPreOtaUpdateCallback([this] { - for (Task* task : this->tasksForDisable) { + for (AbstractTask* task : this->tasksForDisable) { if (task->isEnabled()) { task->disable(); } @@ -347,6 +374,32 @@ protected: settings.sensors.indoor.pin = wmIndoorSensorPin->getValue(); } + if (wmExtPumpUse->getCheckboxValue() != settings.externalPump.use) { + changed = true; + settings.externalPump.use = wmExtPumpUse->getCheckboxValue(); + } + + if (wmExtPumpPin->getValue() != settings.externalPump.pin) { + changed = true; + needRestart = true; + settings.externalPump.pin = wmExtPumpPin->getValue(); + } + + if (wmExtPumpPostCirculationTime->getValue() != settings.externalPump.postCirculationTime) { + changed = true; + settings.externalPump.postCirculationTime = wmExtPumpPostCirculationTime->getValue(); + } + + if (wmExtPumpAntiStuckInterval->getValue() != settings.externalPump.antiStuckInterval) { + changed = true; + settings.externalPump.antiStuckInterval = wmExtPumpAntiStuckInterval->getValue(); + } + + if (wmExtPumpAntiStuckTime->getValue() != settings.externalPump.antiStuckTime) { + changed = true; + settings.externalPump.antiStuckTime = wmExtPumpAntiStuckTime->getValue(); + } + if (!changed) { return; } diff --git a/src/defines.h b/src/defines.h index 3e13a4c..dd9767c 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,5 +1,5 @@ #define PROJECT_NAME "OpenTherm Gateway" -#define PROJECT_VERSION "1.3.4" +#define PROJECT_VERSION "1.4.0" #define PROJECT_REPO "https://github.com/Laxilef/OTGateway" #define AP_SSID "OpenTherm Gateway" #define AP_PASSWORD "otgateway123456" @@ -54,6 +54,10 @@ #define SENSOR_INDOOR_PIN_DEFAULT 0 #endif +#ifndef EXT_PUMP_PIN_DEFAULT + #define EXT_PUMP_PIN_DEFAULT 0 +#endif + #ifndef PROGMEM #define PROGMEM #endif