Files
OTGateway/src/MainTask.h

340 lines
9.6 KiB
C++

#include <Blinker.h>
extern NetworkTask* tNetwork;
extern MqttTask* tMqtt;
extern OpenThermTask* tOt;
extern FileData fsSettings, fsNetworkSettings;
extern ESPTelnetStream* telnetStream;
class MainTask : public Task {
public:
MainTask(bool _enabled = false, unsigned long _interval = 0) : Task(_enabled, _interval) {
this->blinker = new Blinker();
}
~MainTask() {
if (this->blinker != nullptr) {
delete this->blinker;
}
}
protected:
const static byte REASON_PUMP_START_HEATING = 1;
const static byte REASON_PUMP_START_ANTISTUCK = 2;
Blinker* blinker = nullptr;
bool blinkerInitialized = false;
unsigned long firstFailConnect = 0;
unsigned long lastHeapInfo = 0;
unsigned int minFreeHeapSize = 0;
unsigned int minMaxFreeHeapBlockSize = 0;
unsigned long restartSignalTime = 0;
bool heatingEnabled = false;
unsigned long heatingDisabledTime = 0;
byte externalPumpStartReason;
unsigned long externalPumpStartTime = 0;
bool telnetStarted = false;
const char* getTaskName() {
return "Main";
}
/*int getTaskCore() {
return 1;
}*/
int getTaskPriority() {
return 3;
}
void setup() {
#ifdef LED_STATUS_PIN
pinMode(LED_STATUS_PIN, OUTPUT);
digitalWrite(LED_STATUS_PIN, false);
#endif
if (settings.externalPump.pin != 0) {
pinMode(settings.externalPump.pin, OUTPUT);
digitalWrite(settings.externalPump.pin, false);
}
this->minFreeHeapSize = getTotalHeap();
this->minMaxFreeHeapBlockSize = getTotalHeap();
}
void loop() {
if (fsSettings.tick() == FD_WRITE) {
Log.sinfoln(FPSTR(L_SETTINGS), F("Updated"));
}
if (fsNetworkSettings.tick() == FD_WRITE) {
Log.sinfoln(FPSTR(L_NETWORK_SETTINGS), F("Updated"));
}
if (this->telnetStarted) {
telnetStream->loop();
}
if (vars.actions.restart) {
vars.actions.restart = false;
this->restartSignalTime = millis();
// save settings
fsSettings.updateNow();
// force save network settings
if (fsNetworkSettings.updateNow() == FD_FILE_ERR && LittleFS.begin()) {
fsNetworkSettings.write();
}
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 (tNetwork->isConnected()) {
if (!this->telnetStarted && telnetStream != nullptr) {
telnetStream->begin(23, false);
this->telnetStarted = true;
}
vars.sensors.rssi = WiFi.RSSI();
if (!tMqtt->isEnabled() && strlen(settings.mqtt.server) > 0) {
tMqtt->enable();
}
if (this->firstFailConnect != 0) {
this->firstFailConnect = 0;
}
if ( Log.getLevel() != TinyLogger::Level::INFO && !settings.system.debug ) {
Log.setLevel(TinyLogger::Level::INFO);
} else if ( Log.getLevel() != TinyLogger::Level::VERBOSE && settings.system.debug ) {
Log.setLevel(TinyLogger::Level::VERBOSE);
}
} else {
if (this->telnetStarted) {
telnetStream->stop();
this->telnetStarted = false;
}
if (tMqtt->isEnabled()) {
tMqtt->disable();
}
if (settings.emergency.enable && !vars.states.emergency) {
if (this->firstFailConnect == 0) {
this->firstFailConnect = millis();
}
if (millis() - this->firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
vars.states.emergency = true;
Log.sinfoln(FPSTR(L_MAIN), F("Emergency mode enabled"));
}
}
}
yield();
#ifdef LED_STATUS_PIN
ledStatus(LED_STATUS_PIN);
#endif
externalPump();
// anti memory leak
yield();
for (Stream* stream : Log.getStreams()) {
while (stream->available() > 0) {
stream->read();
}
}
heap();
if (this->restartSignalTime > 0 && millis() - this->restartSignalTime > 10000) {
this->restartSignalTime = 0;
ESP.restart();
}
}
void heap() {
unsigned int freeHeapSize = getFreeHeap();
#if defined(ARDUINO_ARCH_ESP32)
unsigned int maxFreeBlockSize = ESP.getMaxAllocHeap();
#else
unsigned int maxFreeBlockSize = ESP.getMaxFreeBlockSize();
#endif
if (!vars.actions.restart && (freeHeapSize < 2048 || maxFreeBlockSize < 2048)) {
vars.actions.restart = true;
return;
}
if (!settings.system.debug) {
return;
}
unsigned int minFreeHeapSizeDiff = 0;
#if defined(ARDUINO_ARCH_ESP32)
unsigned int currentMinFreeHeapSize = ESP.getMinFreeHeap();
if (currentMinFreeHeapSize < this->minFreeHeapSize) {
minFreeHeapSizeDiff = this->minFreeHeapSize - currentMinFreeHeapSize;
this->minFreeHeapSize = currentMinFreeHeapSize;
}
#else
if (freeHeapSize < this->minFreeHeapSize) {
minFreeHeapSizeDiff = this->minFreeHeapSize - freeHeapSize;
this->minFreeHeapSize = freeHeapSize;
}
#endif
unsigned int minMaxFreeBlockSizeDiff = 0;
if (maxFreeBlockSize < this->minMaxFreeHeapBlockSize) {
minMaxFreeBlockSizeDiff = this->minMaxFreeHeapBlockSize - maxFreeBlockSize;
this->minMaxFreeHeapBlockSize = maxFreeBlockSize;
}
uint8_t heapFrag = 100 - maxFreeBlockSize * 100.0 / freeHeapSize;
if (millis() - this->lastHeapInfo > 20000 || minFreeHeapSizeDiff > 0 || minMaxFreeBlockSizeDiff > 0) {
Log.sverboseln(
FPSTR(L_MAIN),
F("Free heap size: %u of %u bytes (min: %u, diff: %u), max free block: %u (min: %u, diff: %u, frag: %hhu%%)"),
freeHeapSize, getTotalHeap(), this->minFreeHeapSize, minFreeHeapSizeDiff, maxFreeBlockSize, this->minMaxFreeHeapBlockSize, minMaxFreeBlockSizeDiff, heapFrag
);
this->lastHeapInfo = millis();
}
}
void ledStatus(uint8_t ledPin) {
uint8_t errors[4];
uint8_t errCount = 0;
static uint8_t errPos = 0;
static unsigned long endBlinkTime = 0;
static bool ledOn = false;
if (!this->blinkerInitialized) {
this->blinker->init(ledPin);
this->blinkerInitialized = true;
}
if (!tNetwork->isConnected()) {
errors[errCount++] = 2;
}
if (!vars.states.otStatus) {
errors[errCount++] = 3;
}
if (vars.states.fault) {
errors[errCount++] = 4;
}
if (vars.states.emergency) {
errors[errCount++] = 5;
}
if (this->blinker->ready()) {
endBlinkTime = millis();
}
if (!this->blinker->running() && millis() - endBlinkTime >= 5000) {
if (errCount == 0) {
if (!ledOn) {
digitalWrite(ledPin, true);
ledOn = true;
}
return;
} else if (ledOn) {
digitalWrite(ledPin, false);
ledOn = false;
endBlinkTime = millis();
return;
}
if (errPos >= errCount) {
errPos = 0;
// end of error list
this->blinker->blink(10, 50, 50);
} else {
this->blinker->blink(errors[errPos++], 300, 300);
}
}
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 || settings.externalPump.pin == 0) {
if (vars.states.externalPump) {
if (settings.externalPump.pin != 0) {
digitalWrite(settings.externalPump.pin, false);
}
vars.states.externalPump = false;
vars.parameters.extPumpLastEnableTime = millis();
Log.sinfoln("EXTPUMP", F("Disabled: use = off"));
}
return;
}
if (vars.states.externalPump && !this->heatingEnabled) {
if (this->externalPumpStartReason == MainTask::REASON_PUMP_START_HEATING && millis() - this->heatingDisabledTime > ((unsigned int) settings.externalPump.postCirculationTime * 1000)) {
digitalWrite(settings.externalPump.pin, false);
vars.states.externalPump = false;
vars.parameters.extPumpLastEnableTime = millis();
Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time"));
} else if (this->externalPumpStartReason == MainTask::REASON_PUMP_START_ANTISTUCK && millis() - this->externalPumpStartTime >= ((unsigned int) settings.externalPump.antiStuckTime * 1000)) {
digitalWrite(settings.externalPump.pin, false);
vars.states.externalPump = false;
vars.parameters.extPumpLastEnableTime = millis();
Log.sinfoln("EXTPUMP", F("Disabled: expired anti stuck time"));
}
} else if (vars.states.externalPump && this->heatingEnabled && this->externalPumpStartReason == MainTask::REASON_PUMP_START_ANTISTUCK) {
this->externalPumpStartReason = MainTask::REASON_PUMP_START_HEATING;
} else if (!vars.states.externalPump && this->heatingEnabled) {
vars.states.externalPump = 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.states.externalPump && (vars.parameters.extPumpLastEnableTime == 0 || millis() - vars.parameters.extPumpLastEnableTime >= ((unsigned long) settings.externalPump.antiStuckInterval * 1000))) {
vars.states.externalPump = true;
this->externalPumpStartTime = millis();
this->externalPumpStartReason = MainTask::REASON_PUMP_START_ANTISTUCK;
digitalWrite(settings.externalPump.pin, true);
Log.sinfoln("EXTPUMP", F("Enabled: anti stuck"));
}
}
};