mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-12 03:04:27 +05:00
340 lines
9.6 KiB
C++
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"));
|
|
}
|
|
}
|
|
}; |