Last active
January 29, 2022 17:23
-
-
Save ItKindaWorks/24fac4d9b0dcc11670a1ffcc947babf7 to your computer and use it in GitHub Desktop.
An ESP8266 based Arduino program for connecting to and automatically rebooting a router when it loses an internet connection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
configAndStatusAPDemo.ino | |
Copyright (c) 2017 ItKindaWorks All right reserved. | |
github.com/ItKindaWorks | |
This file is part of ESPHelper | |
ESPHelper is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
ESPHelper is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with ESPHelper. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
#include "ESPHelper.h" //ESPHelper & links to its dependencies found here: https://github.com/ItKindaWorks/ESPHelper | |
#include "ESPHelperFS.h" | |
#include "ESPHelperWebConfig.h" | |
#include <ESP8266Ping.h> //ESP8266Ping found here: https://github.com/dancol90/ESP8266Ping | |
#include "Metro.h" //Metro library found here: http://playground.arduino.cc/Code/Metro | |
netInfo config; | |
ESPHelper myESP; | |
//setup a server on port 80 (http). We use an external server here because we want more than just a config page | |
//but also a status page or anything else that we want to display | |
ESP8266WebServer server(80); | |
ESPHelperWebConfig configPage(&server, "/config"); | |
//defualt net info for unconfigured devices | |
netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT | |
.mqttUser = "YOUR MQTT USERNAME", //can be blank | |
.mqttPass = "", //can be blank | |
.mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. | |
.ssid = "YOUR SSID", | |
.pass = "", | |
.otaPassword = "", | |
.hostname = "NEW-ESP8266"}; | |
//AP moade setup info | |
const char* broadcastSSID = "ESP-Hotspot"; | |
const char* broadcastPASS = ""; | |
IPAddress broadcastIP = {192, 168, 1, 1}; | |
const int configBtnPin = D2; | |
//timeout before triggering the relay to turn off and on | |
Metro connectTimeout = Metro(30000); | |
Metro pingTimer = Metro(5000); | |
bool pingStatus = false; | |
const char* pingHost = "google.com"; | |
//variables for controlling the router relay | |
const int relayPin = 5; | |
Metro relayTimer = Metro(10000); | |
//cooldown timer to prevent the system from restarting the router over and over before it | |
//can fully start up | |
Metro cooldownTimer = Metro(130000); | |
enum states {CHECKING, RUNNING, COOLDOWN, AP_MODE}; | |
int8_t currentState = CHECKING; | |
void setup(void){ | |
Serial.begin(115200); | |
//print some debug | |
Serial.println("Starting Up - Please Wait..."); | |
delay(100); | |
pinMode(configBtnPin, INPUT); | |
pinMode(relayPin, OUTPUT); | |
digitalWrite(relayPin, LOW); | |
//startup the wifi and web server (more in the lines below) | |
startWifi(); | |
//setup the http server and config page (fillConfig will take the netInfo file and use that for | |
//default values) | |
configPage.fillConfig(&config); | |
configPage.begin(config.hostname); | |
// Actually start the server (again this would be done automatically | |
//if we were just using the config page and didnt use an external server...) | |
server.begin(); | |
server.on("/", HTTP_GET, handleStatus); | |
} | |
void loop(void){ | |
////// config handling ////// | |
//check to see if the AP mode button has been pressed and go into AP mode if needed | |
checkForAPMode(); | |
//handle saving a new network config | |
if(configPage.handle()){ | |
Serial.println("Saving new network config and restarting..."); | |
myESP.saveConfigFile(configPage.getConfig(), "/netConfig.json"); | |
delay(500); | |
ESP.restart(); | |
} | |
////// main state machine ////// | |
//get the current status of ESPHelper | |
int espHelperStatus = myESP.loop(); | |
//if the ping timer has elapsed and we are connected to WiFi then ping the test host | |
if(currentState == CHECKING && pingTimer.check()){ | |
//update pingstatus with results of ping or false if no wifi | |
if(espHelperStatus >= WIFI_ONLY){pingStatus = Ping.ping(pingHost);} | |
else{pingStatus = false;} | |
//print out results of ping attempt | |
if(pingStatus){ Serial.println(String("Good ping to " + String(pingHost)));} | |
else{ Serial.println(String("Could not ping " + String(pingHost)));} | |
pingTimer.reset(); | |
} | |
//reset the timer if the pingStatus is true or if we are in AP mode | |
if(currentState == AP_MODE || pingStatus){ | |
connectTimeout.reset(); | |
} | |
//if the ESP cannot connect (and based on the above if statement is not in AP broadcast mode) | |
//then trigger the relay pin and start (reset) the relay timer | |
if(currentState == CHECKING && connectTimeout.check() ){ | |
Serial.println("Cannot connect to wifi or cannot reach WAN, restarting router..."); | |
digitalWrite(relayPin, HIGH); | |
relayTimer.reset(); | |
cooldownTimer.reset(); | |
currentState = RUNNING; | |
} | |
//if the relay is on and the timer for turning the relay off has elapsed | |
//then turn the relay off | |
else if(currentState == RUNNING && relayTimer.check()){ | |
Serial.println("Turning router back on..."); | |
digitalWrite(relayPin, LOW); | |
currentState = COOLDOWN; | |
} | |
//cooldown state timer checker (cooldown to prevent the router from being rebooted while still starting up) | |
if(currentState == COOLDOWN && cooldownTimer.check()){ | |
Serial.println("Router restart cooldown complete returning to normal state."); | |
connectTimeout.reset(); | |
currentState = CHECKING; | |
} | |
//after each loop give the ESP some time to do other (networking related) functions | |
delay(50); | |
} | |
//ESPHelper & config setup and runtime handler functions | |
//function that checks for the config button to be pressed and drops the ESP into AP mode for configuring | |
void checkForAPMode(){ | |
if(digitalRead(configBtnPin) && currentState != AP_MODE){ | |
Serial.println("AP mode button pressed - starting broadcast (AP) mode..."); | |
currentState = AP_MODE; | |
myESP.broadcastMode(broadcastSSID, broadcastPASS, broadcastIP); | |
myESP.OTA_setPassword(config.otaPassword); | |
myESP.OTA_setHostnameWithVersion(config.hostname); | |
myESP.OTA_enable(); | |
Serial.println("Done."); | |
} | |
} | |
void startWifi(){ | |
loadConfig(); | |
//setup other ESPHelper info and enable OTA updates | |
myESP.setHopping(false); | |
myESP.OTA_setPassword(config.otaPassword); | |
myESP.OTA_setHostnameWithVersion(config.hostname); | |
myESP.OTA_enable(); | |
Serial.println("Connecting to network"); | |
Serial.println( String("SSID: " + String(myESP.getSSID()) + "\nWiFiPass: " + String(myESP.getPASS()) + " ") ); | |
delay(10); | |
//connect to wifi before proceeding. (also check for the AP button being pressed and drop into AP mode if it is) | |
//this will timeout after 20 seconds and just continue the loop regardless | |
Metro startupTimeout = Metro(20000); | |
while(myESP.loop() < WIFI_ONLY){ | |
checkForAPMode(); | |
if(currentState == AP_MODE){return;} | |
if(startupTimeout.check()){break;} | |
delay(10); | |
} | |
if(myESP.loop() >= WIFI_ONLY){ | |
Serial.println("Success!"); | |
Serial.print("IP Address: "); | |
Serial.println(myESP.getIP()); | |
} | |
else{ | |
Serial.println("Could not connect to router. Make sure your device is configured \ncorrectly and/or put it into AP mode for configuration"); | |
} | |
} | |
//attempt to load a network configuration from the filesystem | |
void loadConfig(){ | |
//check for a good config file and start ESPHelper with the file stored on the ESP | |
if(ESPHelperFS::begin()){ | |
Serial.println("Filesystem loaded - Loading Config"); | |
if(ESPHelperFS::validateConfig("/netConfig.json") == GOOD_CONFIG){ | |
Serial.println("Config loaded"); | |
delay(10); | |
myESP.begin("/netConfig.json"); | |
} | |
//if no good config can be loaded (no file/corruption/etc.) then | |
//attempt to generate a new config and restart the module | |
else{ | |
Serial.println("Could not load config - saving new config from default values and restarting"); | |
delay(10); | |
ESPHelperFS::createConfig(&homeNet, "/netConfig.json"); | |
ESPHelperFS::end(); | |
ESP.restart(); | |
} | |
} | |
//if the filesystem cannot be started, just fail over to the | |
//built in network config hardcoded in here | |
else{ | |
Serial.println("Could not load filesystem, proceeding with default config values"); | |
delay(10); | |
myESP.begin(&homeNet); | |
} | |
//load the netInfo from espHelper for use in the config page | |
config = myESP.getNetInfo(); | |
} | |
//main config page that allows user to enter in configuration info | |
void handleStatus() { | |
server.send(200, "text/html", \ | |
String("<html>\ | |
<header>\ | |
<title>Device Info</title>\ | |
</header>\ | |
<body>\ | |
<p><strong>System Status</strong></br>\ | |
Device Name: " + String(myESP.getHostname()) + "</br>\ | |
Connected SSID: " + String(myESP.getSSID()) + "</br>\ | |
Device IP: " + String(myESP.getIP()) + "</br>\ | |
Uptime (ms): " + String(millis()) + "</p>\ | |
<p> </p>\ | |
<p><strong>Device Variables</strong></p>\ | |
<p>Ping Status: " + String(pingStatus) + "</p>\ | |
<p>States: 0: CHECKING | 1: RUNNING | 2: COOLDOWN | 3: AP_MODE </p>\ | |
<p>Device State: " + String(currentState) + "</p>\ | |
</body>\ | |
</html>")); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello. First of all, this project is amazing. Thanks.
I was searching for it for a long time and this is the best approach that I found. Unfortunately, I tried to compile in Arduino IDE 1.8.13 and I get some errors. I tried to correct these errors by compiling many versions of ESP8266 boards (from 2.0 to 2.7). I tried to use Chrono library instead of a Metro too, but no success in any case.
One of the errors is:
c:/users/douglas/appdata/local/arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-3-20ed2b9/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld.exe: sketch\WIFI_REBOOT.ino.cpp.o: in function
_GLOBAL__sub_I__ZN9PingClassC2Ev': C:\Users\Douglas\Documents\Arduino\libraries\ESPHelper-master\src/sharedData.h:135: undefined reference to
Metro::Metro(unsigned long)'What that I doing wrong?
Thanks a lot