diff --git a/lib/App/App.cpp b/lib/App/App.cpp index 2eaf3b8..c4c42a8 100644 --- a/lib/App/App.cpp +++ b/lib/App/App.cpp @@ -125,6 +125,10 @@ void App::defaultConfig() appcfg.led_night_mode_timeout = DEFAULT_LED_NIGHT_MODE_TIMEOUT; #endif + appcfg.inet_check_enabled = DEFAULT_INET_CHECK_ENABLED; + appcfg.inet_check_period = DEFAULT_INET_CHECK_PERIOD; + appcfg.inet_check_action = DEFAULT_INET_CHECK_ACTION; + memcpy(&appcfgWR, &appcfg, sizeof(appcfg)); memcpy(&appcfgRD, &appcfg, sizeof(appcfg)); } @@ -392,6 +396,10 @@ void App::writeConfig() j.writeEntry(A_led_night_mode_timeout, appcfgWR.led_night_mode_timeout); #endif + j.writeEntry(A_inet_check_enabled, appcfgWR.inet_check_enabled); + j.writeEntry(A_inet_check_period, appcfgWR.inet_check_period); + j.writeEntry(A_inet_check_action, appcfgWR.inet_check_action); + j.writeFooter(); configJson.close(); @@ -487,6 +495,12 @@ void App::printConfig(AppConfig ac) Serial.printf(" led_night_mode_timeout: %ds\n", ac.led_night_mode_timeout); #endif + Serial.println("\n Internet check mode:"); + Serial.printf(" Enabled: %s\n", + (ac.inet_check_enabled ? "true" : "false")); + Serial.printf(" inet_check_period: %ds\n", ac.inet_check_period); + Serial.printf(" inet_check_action: %d\n", ac.inet_check_action); + Serial.println("---------------------------------------------------------"); Serial.println(); } @@ -602,6 +616,9 @@ bool App::loadJsonConfig(const char *filename) readError |= j.readEntryBoolean(attributeName, A_led_night_mode_enabled, &appcfgRD.led_night_mode_enabled); readError |= j.readEntryInteger(attributeName, A_led_night_mode_timeout, &appcfgRD.led_night_mode_timeout); #endif + readError |= j.readEntryBoolean(attributeName, A_inet_check_enabled, &appcfgRD.inet_check_enabled); + readError |= j.readEntryInteger(attributeName, A_inet_check_period, &appcfgRD.inet_check_period); + readError |= j.readEntryInteger(attributeName, A_inet_check_action, &appcfgRD.inet_check_action); } } diff --git a/lib/App/App.hpp b/lib/App/App.hpp index e5de022..96249a6 100644 --- a/lib/App/App.hpp +++ b/lib/App/App.hpp @@ -22,6 +22,14 @@ #define POWER_BUTTON_MODE_TOGGLE 2 #define POWER_BUTTON_MODE_TOGGLE_SWITCH 3 +// Internet Check Actions +#define INET_CHECK_ACTION_ON_DISCONNECT_SWITCH_OFF 1 +#define INET_CHECK_ACTION_ON_DISCONNECT_SWITCH_ON 2 +#define INET_CHECK_ACTION_ON_CONNECT_SWITCH_OFF 3 +#define INET_CHECK_ACTION_ON_CONNECT_SWITCH_ON 4 +#define INET_CHECK_ACTION_SHOW_CONNECTION_STATE 5 +#define INET_CHECK_ACTION_SHOW_CONNECTION_STATE_INV 6 + typedef struct appconfig { char wifi_ssid[64]; @@ -87,6 +95,10 @@ typedef struct appconfig int led_night_mode_timeout; #endif + bool inet_check_enabled; // check captive.apple.de + int inet_check_period; // in seconds + int inet_check_action; + } AppConfig; class App @@ -103,6 +115,7 @@ class App int powerLedState; bool ledNightMode; bool ledActiveMode; + bool internetIsConnected; void formatSPIFFS(); void loadConfig(); diff --git a/lib/App/ConfigAttributes.hpp b/lib/App/ConfigAttributes.hpp index 4651bcc..50cde48 100644 --- a/lib/App/ConfigAttributes.hpp +++ b/lib/App/ConfigAttributes.hpp @@ -58,4 +58,8 @@ #define A_led_night_mode_enabled "led_night_mode_enabled" #define A_led_night_mode_timeout "led_night_mode_timeout" +#define A_inet_check_enabled "inet_check_enabled" +#define A_inet_check_period "inet_check_period" +#define A_inet_check_action "inet_check_action" + #endif diff --git a/lib/App/DefaultAppConfig.h b/lib/App/DefaultAppConfig.h index 3a7c997..afe1eb1 100644 --- a/lib/App/DefaultAppConfig.h +++ b/lib/App/DefaultAppConfig.h @@ -59,4 +59,8 @@ #define DEFAULT_LED_NIGHT_MODE_ENABLED false #define DEFAULT_LED_NIGHT_MODE_TIMEOUT 15 +#define DEFAULT_INET_CHECK_ENABLED false +#define DEFAULT_INET_CHECK_PERIOD 600 +#define DEFAULT_INET_CHECK_ACTION INET_CHECK_ACTION_ON_DISCONNECT_SWITCH_OFF + #endif diff --git a/lib/InternetConnectionCheckHandler/InternetConnectionCheckHandler.cpp b/lib/InternetConnectionCheckHandler/InternetConnectionCheckHandler.cpp new file mode 100644 index 0000000..3c744b0 --- /dev/null +++ b/lib/InternetConnectionCheckHandler/InternetConnectionCheckHandler.cpp @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "InternetConnectionCheckHandler.hpp" + +InternetConnectionCheckHandler internetConnectionCheckHandler; + +static AsyncClient *aClient = NULL; + +static bool successFound; +static char *successTxt = (char *)"Success"; +static char *matchPtr; +static time_t startTimestamp; +static bool initStateRead; +static bool lastState; + +void runAction( bool connected ) +{ + LOG1( "run acion = %s\n", successFound ? "true" : "false" ); + if ( initStateRead ) + { + if ( lastState != connected ) + { + LOG0( "Internet connection state changed\n" ); + + switch( appcfg.inet_check_action ) + { + case INET_CHECK_ACTION_ON_CONNECT_SWITCH_OFF: + if ( connected ) + { + relayHandler.delayedOff(); + } + break; + + case INET_CHECK_ACTION_ON_CONNECT_SWITCH_ON: + if ( connected ) + { + relayHandler.delayedOn(); + } + break; + + case INET_CHECK_ACTION_ON_DISCONNECT_SWITCH_OFF: + if ( !connected ) + { + relayHandler.delayedOff(); + } + break; + + case INET_CHECK_ACTION_ON_DISCONNECT_SWITCH_ON: + if ( !connected ) + { + relayHandler.delayedOn(); + } + break; + + case INET_CHECK_ACTION_SHOW_CONNECTION_STATE: + if ( connected ) + { + relayHandler.delayedOn(); + } + else + { + relayHandler.delayedOff(); + } + break; + + case INET_CHECK_ACTION_SHOW_CONNECTION_STATE_INV: + if ( connected ) + { + relayHandler.delayedOff(); + } + else + { + relayHandler.delayedOn(); + } + break; + + default: + LOG0( "Unknown action\n" ); + } + + lastState = connected; + } + } + else + { + LOG0( "Saving internet connection state\n" ); + lastState = connected; + initStateRead = true; + } +} + +InternetConnectionCheckHandler::InternetConnectionCheckHandler() +{ + initialized = false; + initStateRead = false; +} + +void InternetConnectionCheckHandler::setup() +{ + LOG0("Internet Connection Check Setup...\n"); + initialized = true; + lastCheckedTimestamp = 0l; + LOG0("done\n"); +} + +void InternetConnectionCheckHandler::handle(time_t now) +{ + if ( appcfg.inet_check_enabled == true && wifiHandler.isInStationMode()) + { + if ( !initialized ) + { + setup(); + } + + //////////////////////////////////////////////////////////////////////// + + if (( now - lastCheckedTimestamp ) >= (((time_t)appcfg.inet_check_period) * 1000l )) + { + LOG0("Checking internet connection...\n"); + + if ( !wifiHandler.isConnected() ) + { + runAction( false ); + lastCheckedTimestamp = now; + return; + } + + startTimestamp = millis(); + aClient = new AsyncClient(); + + successFound = false; + matchPtr = successTxt; + + if (aClient) + { + aClient->onError([](void *arg, AsyncClient *client, int error) { + Serial.println("\nConnect Error"); + aClient = NULL; + delete client; + runAction(false); + }, NULL); + + aClient->onConnect([](void *arg, AsyncClient *client) { + Serial.println("Connected"); + + aClient->onError(NULL, NULL); + + client->onDisconnect([](void *arg, AsyncClient *client) { + Serial.printf("Disconnected duration=%ld\n", millis() - startTimestamp ); + aClient = NULL; + delete client; + runAction( successFound ); + }, NULL); + + client->onData([](void *arg, AsyncClient *client, void *data, size_t len) { + Serial.print("Data: "); + Serial.println(len); + char *d = (char *)data; + for (size_t i = 0; i < len; i++) + { + // Serial.write(d[i]); + if ( *matchPtr == 0 ) + { + successFound = true; + } + else + { + if ( *matchPtr == d[i] ) + { + matchPtr++; + } + else + { + matchPtr = successTxt; + } + } + } + }, NULL); + + //send the request + client->write("GET / HTTP/1.0\r\nHost: captive.apple.com\r\n\r\n"); + }, NULL); + + if (!aClient->connect("captive.apple.com", 80)) + { + Serial.println("Connect Fail"); + AsyncClient *client = aClient; + aClient = NULL; + delete client; + runAction( false ); + } + } + + + lastCheckedTimestamp = now; + } + + //////////////////////////////////////////////////////////////////////// + } +} \ No newline at end of file diff --git a/lib/InternetConnectionCheckHandler/InternetConnectionCheckHandler.hpp b/lib/InternetConnectionCheckHandler/InternetConnectionCheckHandler.hpp new file mode 100644 index 0000000..2e1e6b3 --- /dev/null +++ b/lib/InternetConnectionCheckHandler/InternetConnectionCheckHandler.hpp @@ -0,0 +1,20 @@ +#ifndef __INTERNET_CONNECTION_CHECK_HANDLER_HPP__ +#define __INTERNET_CONNECTION_CHECK_HANDLER_HPP__ + +#include + +class InternetConnectionCheckHandler +{ + private: + bool initialized; + time_t lastCheckedTimestamp; + void setup(); + + public: + InternetConnectionCheckHandler(); + void handle( time_t now ); +}; + +extern InternetConnectionCheckHandler internetConnectionCheckHandler; + +#endif diff --git a/lib/WebHandler/pages/SaveConfig.cpp b/lib/WebHandler/pages/SaveConfig.cpp index 2df995d..8415585 100644 --- a/lib/WebHandler/pages/SaveConfig.cpp +++ b/lib/WebHandler/pages/SaveConfig.cpp @@ -132,6 +132,10 @@ void handleSavePage(AsyncWebServerRequest *request) appcfgWR.led_night_mode_timeout = paramInt(request, A_led_night_mode_timeout, DEFAULT_LED_NIGHT_MODE_TIMEOUT); #endif + appcfgWR.inet_check_enabled = paramBool(request, A_inet_check_enabled); + appcfgWR.inet_check_period = paramInt(request, A_inet_check_period, DEFAULT_INET_CHECK_PERIOD); + appcfgWR.inet_check_action = paramInt(request, A_inet_check_action, DEFAULT_INET_CHECK_ACTION); + AsyncResponseStream *response = request->beginResponseStream("text/html"); response->print(TEMPLATE_HEADER); response->print(META_REFRESH); diff --git a/lib/WebHandler/pages/SetupPage.cpp b/lib/WebHandler/pages/SetupPage.cpp index 6807b09..ff64cb6 100644 --- a/lib/WebHandler/pages/SetupPage.cpp +++ b/lib/WebHandler/pages/SetupPage.cpp @@ -157,6 +157,18 @@ String setupProcessor(const String &var) return String(appcfg.led_night_mode_timeout); #endif + if (var == A_inet_check_enabled && appcfg.inet_check_enabled == true) + return checked; + if (var == A_inet_check_period) + return String(appcfg.inet_check_period); + + String ica = String( A_inet_check_action ); + ica += "_"; + ica += appcfg.inet_check_action; + + if ( var == ica ) + return selected; + return String(); } diff --git a/lib/WebHandler/setup-html.h b/lib/WebHandler/setup-html.h index ea8d2ac..851e996 100644 --- a/lib/WebHandler/setup-html.h +++ b/lib/WebHandler/setup-html.h @@ -41,6 +41,21 @@ const char SETUP_HTML[] PROGMEM = "\n" #endif + "
Internet Check Mode
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + #if defined(POWER_BUTTON_IS_MULTIMODE) "
Power Button
\n" "
\n" diff --git a/src/main.cpp b/src/main.cpp index 623ee2e..8ebd951 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include unsigned long lifeTicker; unsigned long maxLoopTime; @@ -135,6 +136,8 @@ void loop() mqttHandler.handle(thisLoopTimestamp); } + internetConnectionCheckHandler.handle(thisLoopTimestamp); + #ifdef HAVE_HLW8012 hlw8012Handler.handle(thisLoopTimestamp); #endif