From 072137ee77407f3744db6504b6b3e2ffed2e55b2 Mon Sep 17 00:00:00 2001 From: VArt67 Date: Tue, 2 Jan 2024 23:47:39 +0100 Subject: [PATCH] * Changed reconnect on WiFi lost * Added History Data menu and charts --- src/.vscode/bookmarks.json | 0 src/app.cpp | 10 ++- src/app.h | 9 ++- src/appInterface.h | 6 ++ src/config/settings.h | 7 +- src/plugins/Display/Display.h | 1 + src/plugins/history.cpp | 84 +++++++++++++++++++++++ src/plugins/history.h | 84 +++++++++++++++++++++++ src/web/RestApi.h | 41 ++++++++++- src/web/html/api.js | 2 +- src/web/html/history.html | 121 +++++++++++++++++++++++++++++++++ src/web/html/includes/nav.html | 1 + src/web/html/style.css | 20 ++++++ src/web/web.h | 24 ++++--- src/wifi/ahoywifi.cpp | 24 +++++-- 15 files changed, 411 insertions(+), 23 deletions(-) create mode 100644 src/.vscode/bookmarks.json create mode 100644 src/plugins/history.cpp create mode 100644 src/plugins/history.h create mode 100644 src/web/html/history.html diff --git a/src/.vscode/bookmarks.json b/src/.vscode/bookmarks.json new file mode 100644 index 00000000..e69de29b diff --git a/src/app.cpp b/src/app.cpp index 179e3ba3..cb5e17ef 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -9,6 +9,7 @@ #include "utils/sun.h" +#include "plugins/history.h" //----------------------------------------------------------------------------- app::app() @@ -117,9 +118,14 @@ void app::setup() { if (mConfig->plugin.display.type != 0) mDisplay.setup(&mConfig->plugin.display, &mSys, &mTimestamp, mVersion); + mTotalPowerHistory = new TotalPowerHistory(); + mTotalPowerHistory->setup(this, &mSys, mConfig); + mYieldDayHistory = new YieldDayHistory(); + mYieldDayHistory->setup(this, &mSys, mConfig); + mPubSerial.setup(mConfig, &mSys, &mTimestamp); - #if !defined(ETHERNET) +#if !defined(ETHERNET) //mImprov.setup(this, mConfig->sys.deviceName, mVersion); #endif @@ -251,6 +257,8 @@ void app::regularTickers(void) { //everySec([this]() { mImprov.tickSerial(); }, "impro"); #endif // every([this]() { mPayload.simulation();}, 15, "simul"); + everySec(std::bind(&TotalPowerHistory::tickerSecond, mTotalPowerHistory), "totalPowerHistory"); + everySec(std::bind(&YieldDayHistory::tickerSecond, mYieldDayHistory), "yieldDayHistory"); } #if defined(ETHERNET) diff --git a/src/app.h b/src/app.h index 78a5a9df..5613770c 100644 --- a/src/app.h +++ b/src/app.h @@ -55,6 +55,8 @@ typedef PubSerial PubSerialType; // PLUGINS #include "plugins/Display/Display.h" +#include "plugins/history.h" + typedef Display DisplayType; class app : public IApp, public ah::Scheduler { @@ -257,7 +259,10 @@ class app : public IApp, public ah::Scheduler { Scheduler::setTimestamp(newTime); } - private: + TotalPowerHistory *getTotalPowerHistoryPtr() { return mTotalPowerHistory; }; + YieldDayHistory *getYieldDayHistoryPtr() { return mYieldDayHistory; }; + + private: #define CHECK_AVAIL true #define SKIP_YIELD_DAY true @@ -361,6 +366,8 @@ class app : public IApp, public ah::Scheduler { // plugins DisplayType mDisplay; + TotalPowerHistory *mTotalPowerHistory; + YieldDayHistory *mYieldDayHistory; }; #endif /*__APP_H__*/ diff --git a/src/appInterface.h b/src/appInterface.h index a6f85e84..91a3c2ef 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -14,6 +14,9 @@ #include "ESPAsyncWebServer.h" #endif +class TotalPowerHistory; +class YieldDayHistory; + // abstract interface to App. Make members of App accessible from child class // like web or API without forward declaration class IApp { @@ -62,6 +65,9 @@ class IApp { virtual void getNrfRadioCounters(uint32_t *sendCnt, uint32_t *retransmits) = 0; //virtual void getCmtRadioCounters(uint32_t *sendCnt, uint32_t *retransmits) = 0; + + virtual TotalPowerHistory *getTotalPowerHistoryPtr() = 0; + virtual YieldDayHistory *getYieldDayHistoryPtr() = 0; }; #endif /*__IAPP_H__*/ diff --git a/src/config/settings.h b/src/config/settings.h index a7cb6a4c..51843ab9 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -40,6 +40,7 @@ #define PROT_MASK_SYSTEM 0x0020 #define PROT_MASK_API 0x0040 #define PROT_MASK_MQTT 0x0080 +#define PROT_MASK_HISTORY 0x0100 #define DEF_PROT_INDEX 0x0001 #define DEF_PROT_LIVE 0x0000 @@ -49,7 +50,7 @@ #define DEF_PROT_SYSTEM 0x0020 #define DEF_PROT_API 0x0000 #define DEF_PROT_MQTT 0x0000 - +#define DEF_PROT_HISTORY 0x0000 typedef struct { uint8_t ip[4]; // ip address @@ -363,7 +364,7 @@ class settings { // erase all settings and reset to default memset(&mCfg, 0, sizeof(settings_t)); mCfg.sys.protectionMask = DEF_PROT_INDEX | DEF_PROT_LIVE | DEF_PROT_SERIAL | DEF_PROT_SETUP - | DEF_PROT_UPDATE | DEF_PROT_SYSTEM | DEF_PROT_API | DEF_PROT_MQTT; + | DEF_PROT_UPDATE | DEF_PROT_SYSTEM | DEF_PROT_API | DEF_PROT_MQTT | DEF_PROT_HISTORY; mCfg.sys.darkMode = false; mCfg.sys.schedReboot = false; // restore temp settings @@ -482,7 +483,7 @@ class settings { if(mCfg.sys.protectionMask == 0) mCfg.sys.protectionMask = DEF_PROT_INDEX | DEF_PROT_LIVE | DEF_PROT_SERIAL | DEF_PROT_SETUP - | DEF_PROT_UPDATE | DEF_PROT_SYSTEM | DEF_PROT_API | DEF_PROT_MQTT; + | DEF_PROT_UPDATE | DEF_PROT_SYSTEM | DEF_PROT_API | DEF_PROT_MQTT | DEF_PROT_HISTORY; } } diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 2340fd42..9c2dd3d7 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -14,6 +14,7 @@ #include "Display_ePaper.h" template + class Display { public: Display() { diff --git a/src/plugins/history.cpp b/src/plugins/history.cpp new file mode 100644 index 00000000..720d5689 --- /dev/null +++ b/src/plugins/history.cpp @@ -0,0 +1,84 @@ + +#include "plugins/history.h" + +#include "appInterface.h" +#include "config/config.h" +#include "utils/dbg.h" + +void TotalPowerHistory::setup(IApp *app, HmSystemType *sys, settings_t *config) { + mApp = app; + mSys = sys; + mConfig = config; + mRefreshCycle = 0; + mRefreshCycle = mConfig->nrf.sendInterval; +} + +void TotalPowerHistory::tickerSecond() { + ++mLoopCnt; + if ((mLoopCnt % mRefreshCycle) == 0) { + //DPRINTLN(DBG_DEBUG,F("TotalPowerHistory::tickerSecond > refreshCycle" + String(mRefreshCycle) + "|" + String(mLoopCnt) + "|" + String(mRefreshCycle % mLoopCnt)); + mLoopCnt = 0; + float totalPower = -0.1; + Inverter<> *iv; + record_t<> *rec; + for (uint8_t i = 0; i < mSys->getNumInverters(); i++) { + iv = mSys->getInverterByPos(i); + rec = iv->getRecordStruct(RealTimeRunData_Debug); + if (iv == NULL) + continue; + totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); + } + if (totalPower > 0) { + uint16_t iTotalPower = roundf(totalPower); + DPRINTLN(DBG_DEBUG, F("addValue(iTotalPower)=") + String(iTotalPower)); + addValue(iTotalPower); + } + } +} + +void YieldDayHistory::setup(IApp *app, HmSystemType *sys, settings_t *config) { + mApp = app; + mSys = sys; + mConfig = config; + mRefreshCycle = 60; // every minute + mDayStored = false; +}; + +void YieldDayHistory::tickerSecond() { + ++mLoopCnt; + if ((mLoopCnt % mRefreshCycle) == 0) { + mLoopCnt = 0; + // check for sunset. if so store yield of day once + uint32_t sunsetTime = mApp->getSunset(); + uint32_t sunriseTime = mApp->getSunrise(); + uint32_t currentTime = mApp->getTimestamp(); + DPRINTLN(DBG_DEBUG,F("[YieldDayHistory] current | rise | set -> ") + String(currentTime) + " | " + String(sunriseTime) + " | " + String(sunsetTime)); + + if (currentTime > sunsetTime) { + if (!mDayStored) { + DPRINTLN(DBG_DEBUG,F("currentTime > sunsetTime ") + String(currentTime) + " > " + String(sunsetTime)); + float totalYieldDay = -0.1; + Inverter<> *iv; + record_t<> *rec; + for (uint8_t i = 0; i < mSys->getNumInverters(); i++) { + iv = mSys->getInverterByPos(i); + rec = iv->getRecordStruct(RealTimeRunData_Debug); + if (iv == NULL) + continue; + totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec); + } + if (totalYieldDay > 0) { + uint16_t iTotalYieldDay = roundf(totalYieldDay); + DPRINTLN(DBG_DEBUG,F("addValue(iTotalYieldDay)=") + String(iTotalYieldDay)); + addValue(iTotalYieldDay); + mDayStored = true; + } + } + } else { + if (currentTime > sunriseTime) { + DPRINTLN(DBG_DEBUG,F("currentTime > sunriseTime ") + String(currentTime) + " > " + String(sunriseTime)); + mDayStored = false; + } + } + } +} \ No newline at end of file diff --git a/src/plugins/history.h b/src/plugins/history.h new file mode 100644 index 00000000..46a8d7b9 --- /dev/null +++ b/src/plugins/history.h @@ -0,0 +1,84 @@ +#ifndef __HISTORY_DATA_H__ +#define __HISTORY_DATA_H__ + +#include "utils/helper.h" +#include "defines.h" +#include "hm/hmSystem.h" + +typedef HmSystem HmSystemType; +class IApp; + +#define HISTORY_DATA_ARR_LENGTH 256 + +class HistoryData { + public: + HistoryData() { + for (int i = 0; i < HISTORY_DATA_ARR_LENGTH; i++) + m_dataArr[i] = 0.0; + m_listIdx = 0; + m_dispIdx = 0; + m_wrapped = false; + }; + void addValue(uint16_t value) + { + m_dataArr[m_listIdx] = value; + m_listIdx = (m_listIdx + 1) % (HISTORY_DATA_ARR_LENGTH); + if (m_listIdx == 0) + m_wrapped = true; + if (m_wrapped) // after 1st time array wrap we have to increas the display index + m_dispIdx = (m_dispIdx + 1) % (HISTORY_DATA_ARR_LENGTH); + }; + + uint16_t valueAt(int i){ + uint16_t idx = m_dispIdx + i; + idx = idx % HISTORY_DATA_ARR_LENGTH; + uint16_t value = m_dataArr[idx]; + return value; + }; + uint16_t getDisplIdx() { return m_dispIdx; }; + + private: + uint16_t m_dataArr[HISTORY_DATA_ARR_LENGTH + 1]; // ring buffer for watt history + uint16_t m_listIdx; // index for next Element to write into WattArr + uint16_t m_dispIdx; // index for 1st Element to display from WattArr + bool m_wrapped; +}; + +class TotalPowerHistory : public HistoryData { + public: + TotalPowerHistory() : HistoryData() { + mLoopCnt = 0; + }; + + void setup(IApp *app, HmSystemType *sys, settings_t *config); + void tickerSecond(); + + private: + IApp *mApp; + HmSystemType *mSys; + settings *mSettings; + settings_t *mConfig; + uint16_t mRefreshCycle; + uint16_t mLoopCnt; +}; + +class YieldDayHistory : public HistoryData { + public: + YieldDayHistory() : HistoryData(){ + mLoopCnt = 0; + }; + + void setup(IApp *app, HmSystemType *sys, settings_t *config); + void tickerSecond(); + + private: + IApp *mApp; + HmSystemType *mSys; + settings *mSettings; + settings_t *mConfig; + uint16_t mRefreshCycle; + uint16_t mLoopCnt; + bool mDayStored; +}; + +#endif \ No newline at end of file diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 861e8994..9ea3511d 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -22,6 +22,8 @@ #include "ESPAsyncWebServer.h" #endif +#include "plugins/history.h" + #if defined(F) && defined(ESP32) #undef F #define F(sl) (sl) @@ -97,7 +99,9 @@ class RestApi { #if !defined(ETHERNET) else if(path == "setup/networks") getNetworks(root); #endif /* !defined(ETHERNET) */ - else if(path == "live") getLive(request,root); + else if(path == "live") getLive(request, root); + else if (path == "powerHistory") getPowerHistory(request, root); + else if (path == "yieldDayHistory") getYieldDayHistory(request, root); /*else if(path == "record/info") getRecord(root, InverterDevInform_All); else if(path == "record/alarm") getRecord(root, AlarmData); else if(path == "record/config") getRecord(root, SystemConfigPara); @@ -166,9 +170,10 @@ class RestApi { ep[F("setup")] = url + F("setup"); ep[F("system")] = url + F("system"); ep[F("live")] = url + F("live"); + ep[F("powerHistory")] = url + F("powerHistory"); + ep[F("yieldDayHistory")] = url + F("yieldDayHistory"); } - void onDwnldSetup(AsyncWebServerRequest *request) { AsyncWebServerResponse *response; @@ -592,6 +597,38 @@ class RestApi { } } + void getPowerHistory(AsyncWebServerRequest *request, JsonObject obj) { + getGeneric(request, obj.createNestedObject(F("generic"))); + obj[F("refresh")] = mConfig->nrf.sendInterval; + obj[F("datapoints")] = HISTORY_DATA_ARR_LENGTH; + uint16_t maximum = 0; + TotalPowerHistory *p = mApp->getTotalPowerHistoryPtr(); + for (uint16_t fld = 0; fld < HISTORY_DATA_ARR_LENGTH; fld++) { + uint16_t value = p->valueAt(fld); + obj[F("value")][fld] = value; + if (value > maximum) + maximum = value; + } + obj[F("maximum")] = maximum; + obj[F("dispIndex")] = p->getDisplIdx(); + } + + void getYieldDayHistory(AsyncWebServerRequest *request, JsonObject obj) { + getGeneric(request, obj.createNestedObject(F("generic"))); + obj[F("refresh")] = 86400; // 1 day + obj[F("datapoints")] = HISTORY_DATA_ARR_LENGTH; + uint16_t maximum = 0; + YieldDayHistory *p = mApp->getYieldDayHistoryPtr(); + for (uint16_t fld = 0; fld < HISTORY_DATA_ARR_LENGTH; fld++) { + uint16_t value = p->valueAt(fld); + obj[F("value")][fld] = value; + if (value > maximum) + maximum = value; + } + obj[F("maximum")] = maximum; + obj[F("dispIndex")] = p->getDisplIdx(); + } + /*void getRecord(JsonObject obj, uint8_t recType) { JsonArray invArr = obj.createNestedArray(F("inverter")); diff --git a/src/web/html/api.js b/src/web/html/api.js index 1548190c..9dbe56c7 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -77,7 +77,7 @@ function topnav() { } function parseNav(obj) { - for(i = 0; i < 11; i++) { + for(i = 0; i < 12; i++) { if(i == 2) continue; var l = document.getElementById("nav"+i); diff --git a/src/web/html/history.html b/src/web/html/history.html new file mode 100644 index 00000000..a182b4c0 --- /dev/null +++ b/src/web/html/history.html @@ -0,0 +1,121 @@ + + + + + History + {#HTML_HEADER} + + + + + + + {#HTML_NAV} +
+
+

Total Power history

+
+
+

+ Maximum value: Watt
+ Updated every seconds

+
+ +

Yield per day history

+
+
+

+ Maximum value: Watt
+ Updated every seconds

+
+
+
+ {#HTML_FOOTER} + + + + + + \ No newline at end of file diff --git a/src/web/html/includes/nav.html b/src/web/html/includes/nav.html index 9d6b822c..9c81944c 100644 --- a/src/web/html/includes/nav.html +++ b/src/web/html/includes/nav.html @@ -7,6 +7,7 @@
Live + History Serial / Control Settings diff --git a/src/web/html/style.css b/src/web/html/style.css index bf84aaa3..a2bf171f 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -24,6 +24,26 @@ fieldset, input[type=submit], .btn { color: var(--fg2); } +svg rect {fill: #0000AA;} +svg.chart { + background: #f2f2f2; + border: 2px solid gray; + padding: 1px; +} + +div.chartDivContainer { + padding: 1px; + margin: 1px; +} +div.chartdivContainer span { + color: var(--fg2); +} +div.chartDiv { + padding: 0px; + margin: 0px; +} + + .topnav { background-color: var(--nav-bg); position: fixed; diff --git a/src/web/web.h b/src/web/web.h index 4d8ef1e8..c5d41dbe 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -21,24 +21,25 @@ #else /* defined(ETHERNET) */ #include "ESPAsyncWebServer.h" #endif /* defined(ETHERNET) */ +#include "html/h/about_html.h" #include "html/h/api_js.h" #include "html/h/colorBright_css.h" #include "html/h/colorDark_css.h" #include "html/h/favicon_ico.h" #include "html/h/index_html.h" #include "html/h/login_html.h" +#include "html/h/save_html.h" #include "html/h/serial_html.h" #include "html/h/setup_html.h" #include "html/h/style_css.h" #include "html/h/system_html.h" -#include "html/h/save_html.h" #include "html/h/update_html.h" #include "html/h/visualization_html.h" -#include "html/h/about_html.h" +#include "html/h/history_html.h" #define WEB_SERIAL_BUF_SIZE 2048 -const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinSclk", "pinMosi", "pinMiso", "pinLed0", "pinLed1", "pinLedHighActive", "pinCsb", "pinFcsb", "pinGpio3"}; + const char *const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinSclk", "pinMosi", "pinMiso", "pinLed0", "pinLed1", "pinLedHighActive", "pinCsb", "pinFcsb", "pinGpio3"}; template class Web { @@ -75,10 +76,11 @@ class Web { mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1)); mWeb.on("/save", HTTP_POST, std::bind(&Web::showSave, this, std::placeholders::_1)); - mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); - //mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); + mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); + mWeb.on("/history", HTTP_ANY, std::bind(&Web::onHistory, this, std::placeholders::_1)); + // mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); - #ifdef ENABLE_PROMETHEUS_EP +#ifdef ENABLE_PROMETHEUS_EP mWeb.on("/metrics", HTTP_ANY, std::bind(&Web::showMetrics, this, std::placeholders::_1)); #endif @@ -110,7 +112,7 @@ class Web { mProtected = true; } - DPRINTLN(DBG_DEBUG, "auto logout in " + String(mLogoutTimeout)); + //DPRINTLN(DBG_DEBUG, "auto logout in " + String(mLogoutTimeout)); } if (mSerialClientConnnected) { @@ -244,6 +246,8 @@ class Web { request->redirect(F("/index")); else if ((mConfig->sys.protectionMask & PROT_MASK_LIVE) != PROT_MASK_LIVE) request->redirect(F("/live")); + else if ((mConfig->sys.protectionMask & PROT_MASK_HISTORY) != PROT_MASK_HISTORY) + request->redirect(F("/history")); else if ((mConfig->sys.protectionMask & PROT_MASK_SERIAL) != PROT_MASK_SERIAL) request->redirect(F("/serial")); else if ((mConfig->sys.protectionMask & PROT_MASK_SYSTEM) != PROT_MASK_SYSTEM) @@ -259,7 +263,7 @@ class Web { } } - void getPage(AsyncWebServerRequest *request, uint8_t mask, const uint8_t *zippedHtml, uint32_t len) { + void getPage(AsyncWebServerRequest *request, uint16_t mask, const uint8_t *zippedHtml, uint32_t len) { if (CHECK_MASK(mConfig->sys.protectionMask, mask)) checkProtection(request); @@ -636,6 +640,10 @@ class Web { getPage(request, PROT_MASK_LIVE, visualization_html, visualization_html_len); } + void onHistory(AsyncWebServerRequest *request) { + getPage(request, PROT_MASK_HISTORY, history_html, history_html_len); + } + void onAbout(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), about_html, about_html_len); response->addHeader(F("Content-Encoding"), "gzip"); diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index 863ca88f..c1458fce 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -98,9 +98,9 @@ void ahoywifi::tickWifiLoop() { } mCnt++; - uint8_t timeout = (mStaConn == DISCONNECTED) ? 10 : 20; // seconds + uint8_t timeout = (mStaConn == DISCONNECTED) ? 20 : 30; // seconds if (mStaConn == CONNECTED) // connected but no ip - timeout = 20; + timeout = 30; if(!mScanActive && mBSSIDList.empty() && (mStaConn == DISCONNECTED)) { // start scanning APs with the given SSID DBGPRINT(F("scanning APs with SSID ")); @@ -122,16 +122,17 @@ void ahoywifi::tickWifiLoop() { #endif return; } - DBGPRINT(F("reconnect in ")); - DBGPRINT(String(timeout-mCnt)); - DBGPRINTLN(F(" seconds")); if(mScanActive) { getBSSIDs(); if((!mScanActive) && (!mBSSIDList.empty())) // scan completed if ((mCnt % timeout) < timeout - 2) mCnt = timeout - 2; } - if((mCnt % timeout) == 0) { // try to reconnect after x sec without connection + DBGPRINT(F("reconnect in ")); + DBGPRINT(String(timeout - mCnt)); + DBGPRINTLN(F(" seconds")); + if (mStaConn == DISCONNECTED) { + if ((mCnt % timeout) == 0) { // try to reconnect after x sec without connection mStaConn = CONNECTING; WiFi.disconnect(); @@ -151,6 +152,7 @@ void ahoywifi::tickWifiLoop() { mCnt = 0; } + } } #endif } @@ -347,7 +349,12 @@ void ahoywifi::connectionEvent(WiFiStatus_t status) { if(mStaConn != CONNECTED) { mStaConn = CONNECTED; DBGPRINTLN(F("\n[WiFi] Connected")); + DBGPRINTLN(F("[WiFi] RRSI: ")); + DBGPRINTLN(String(WiFi.RSSI())); } + mCnt = 0; + WiFi.setAutoReconnect(true); + WiFi.persistent(true); break; case GOT_IP: @@ -361,13 +368,16 @@ void ahoywifi::connectionEvent(WiFiStatus_t status) { WiFi.mode(WIFI_STA); DBGPRINTLN(F("[WiFi] AP disabled")); delay(100); + mCnt = 0; + WiFi.setAutoReconnect(true); + WiFi.persistent(true); mAppWifiCb(true); break; case DISCONNECTED: if(mStaConn != CONNECTING) { mStaConn = DISCONNECTED; - mCnt = 5; // try to reconnect in 5 sec + mCnt = 6; // try to reconnect in timeout - 6 sec setupWifi(); // reconnect with AP / Station setup mAppWifiCb(false); DPRINTLN(DBG_INFO, "[WiFi] Connection Lost");