SALES INQUIRIES: 1 (888) 767-9864

ESP8266 Auto Router Resetter :: Student Project

One of our customers, John Simister, had a problem.

Check out what John did in his own words (I have added emphasis and headings to break it up).

The Problem

“I have just completed a project that I have been working on for a couple of months.

As with most Routers they tend to go offline at different times, even when they are still powered up.

We live in Melbourne and regularly go and live on our boat in Queensland (1200 miles from home).

I normally access my IP cameras from the boat to see that all is ok at home.  

However, there has been occasion when the router has been offline and I have had no camera or home access.

To get around this I fitted a WEMO switch to restart the router in the event of it going offline. However, last time I was away that too failed and I still had no cameras.

Picture of esp8266 Router Auto Resetter in enclosure

ESP8266 to the rescue!

This project is not entirely my idea as I read in a magazine that it had been done before.  So I took the original idea and built on it – and here is what I finished up with.

The ESP8266 logs on to the local network and monitors access to google.com every few seconds.  If it does not get a “connected” response it tries again for a total of 3 times.

After that period the ESP8266 illuminates the “Offline” LED.  It then logs on to another WiFi network that is available and sends an email to say the “Router is Offline”.

It then logs onto ThingSpeak and updates the data in my channel.  ThingSpeak then sends a tweet to state “Router Offline”.

So as you can see I have a lot of backup notification on the router status.

After all of this, the ESP8266 switches the relay off for five seconds and then back on again.  This allows the router to come back online with a fresh reboot.

It then logs onto the network, monitors google.com and then updates Thingspeak with new data.  

I have also put in a line of code to reset the ESP8266 at the same time as the router reset.  This makes sure that it gets a fresh reboot each time for the same reason.

Also, I added an OLED display to be able to monitor at what point the program is at any time.

What if you don’t have 2 WiFi connections?

I am fortunate to have two WiFi connections at my home.  However, this could easily and cheaply still be done by anyone.

All that is needed is a cheap data sim card and an old Cell phone that could be used as a permanent hotspot.

Testing, Testing, Testing!

I have been switching the power off, the internet off and ESP8266 off all in different sequences for a couple of months to try and get it to fail.

I did have some early teething problems, however, it now seems bulletproof.

Also, there are no high voltages involved, because the relay breaks the line between the power pack and the router.

The relay is also in a continuous state whilst no power is connected.  Therefore, if the ESP8266  failed – the relay would still allow power to flow to the router.

  • There are two voltage regulators for the 3.5 and 5.00 volts required.
  • Total cost of the project was between $50 – $60 AUS.

I am going back up to the boat … for 5 weeks so this will be the big test.

Using what’s out there…

As I said this is not totally original but I think the way I have modified it may be.

I cheated in some areas and obtained the Gmail code for the Gmail sender on the net.  

Profile view of ESP8266 Auto Resetter Project in enclosure

Links and Tips…

Here are some links and tips of assistance for anyone interested in doing the project.

Gmail Sender Instructions:

I have provided the cpp and .h file with the sketch (at the bottom of this post).  You will need to make a small modification to your Gmail account for this to work.  It does reduce security slightly.

If you are not comfortable with this you can just open a new special gmail account for this purpose.  The modification for this are in the Gmail Sender instructional linked below.

Also, in the .h file you need to put in username and password.  However, it has to be done with “Base64 format”. This is very easy and takes just a minute or 2 to convert your details for the .h file.

Here is a link to a program to do the conversion.

This instructable gives step by step instructions on setting up the Gmail side of the program if you require it.  However, you will find the sketch I provided should cover all of this without you adding to it (apart from username etc).

Hardware Links:

Here are links to the hardware used in this project…

Notes on powering the ESP8266 and finishing the enclosure

I could of used the power from the Router power pack and then dropped the voltage through the voltage regulator.  However, I elected to keep it simple and used a separate power pack  for the  5 and 3.5 volts,

I used an old power pack with an output of 12 volts DC and used the two separate variable voltage regulators to drop the power.  I then just cut the line between the Router power pack and the Router and directed the positive side through the relay (be careful not to reverse the polarity when you do this).

I also cut a small hole in the side of the enclosure to fit the USB connector.  This allows me to modify the code at any time without having to pull it apart. (photo attached)

I mounted the ESP8266 on a Mini Breadboard and soldered the connections for a permanent job.

What’s Next?

“The course you run has been fantastic and it has given me a fairly good basis to learn from.

I want to start making some monitoring devices for my boat powered by 3G next.”

Arduino Code:

Router_Reset_Programming_Electronics.ino

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
#define OLED_RESET 4
#define OLED_RESET LED_BUILTIN
Adafruit_SSD1306 display(OLED_RESET);
#include <ESP8266WiFi.h>
#include "Gsender.h"   //gmail sender library
const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxx";
const char* ssid2 = "xxxxxxx";
const char* password2 = "xxxxxxxxxxx";
int state;  //variable if router is online or offline
unsigned long timer = 0;  //timer vairiable for thingSpeak to update
int duration = 20000;   //duration for thing speak using millis
#define BOOTTIME 150 //the delay for the router to boot up in "doreset command"
int relayPin = D7;   // switches relay to turn router on/off
int ledOnline = D3;   //LED online pin
int ledOffline = D4;     //LED offLine pin
int cnt = 0;   //cnt variable to count times the program checks to see if the internet is still offline
void doreset();   //reset the router user defined function

//ThingSpeak Settings,
char thingSpeakAddress[] = "api.thingspeak.com";  //The URL for the thingspeak url
String APIKey = "xxxxxxxxxxxxx";               //API key for Thing Speak
const int updateThinkSpeakInterval = 20 * 1000;   //20 second interval for update
WiFiServer server(301);   //I also reserved the IP Address and port number for the ESP8266 rather than rely on DHCP, hopefully for more stability and reliabilty. it is Probably not necessary.
WiFiClient client;

void setup() {

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  // init done

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(2000);

  display.clearDisplay();    //clear display
  display.setTextSize(1);    //set text size

  display.setTextColor(WHITE);  //set text color
  pinMode(ledOnline, OUTPUT);          //pinMode for LED online
  pinMode(ledOffline, OUTPUT);          //pinMode for LED offline
  pinMode(relayPin, OUTPUT);           //pinMode for relay
  digitalWrite(relayPin, HIGH);         //initialize pin state
  digitalWrite(ledOnline, LOW);
  digitalWrite(ledOffline, LOW);
  int routerState = state;   //variable for state of router online or offline
  String routerField = String(routerState);   //convert the sensor data into String Objects fro thingSpeak

  Serial.begin(9600);   // Serial monitor setup for troubleshooting
  delay(10);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  display.clearDisplay();    //display information for Oled
  display.setCursor(0, 0);
  display.print("Connecting to..");
  display.setCursor(0 , 8 * 3);
  display.print(ssid);

  display.display();
  WiFi.begin(ssid, password);    // Connect to WiFi network

  while ((WiFi.status() != WL_CONNECTED) && (millis() < 60000)) {
    delay(500);
    display.setCursor(0, 8 * 5);   //position the cursor on the Oled
    display.print("Waiting...");
    display.display();
  }
 
  server.begin();
  display.setCursor(0, 8 * 4);    //position the cursor on the Oled
  display.print("Server Started");
  display.setCursor(0, 8 * 6);
  display.print("IP address of this computer..");   // Print the IP address
  display.setCursor(0, 8 * 6);
  display.print("http://");
  display.setCursor(9, 8 * 6);
  display.print(WiFi.localIP());
}
void loop() {
  display.clearDisplay();
  delay(10000);

  if (client.connect("www.google.com.au", 80)) {   //check to see if the router can connect to Google
    state = 1;   //state of router is on
    display.clearDisplay();
    display.setCursor(0, 0);     //position the cursor on the Oled
    display.print("Router Online OK");
    display.setCursor(0, 8 * 2);
    display.print("IP Address..");
    display.setCursor(0, 8 * 4);
    display.print(("http://"));
    display.setCursor(50, 8 * 4);
    display.print(WiFi.localIP());
    display.setCursor(0, 8 * 6);
    display.print("Pinging Google.com");
    display.display();
    digitalWrite(ledOnline, HIGH);   //Green LED stating router up and running
    digitalWrite(ledOffline, LOW);   //Red LED to set to off
    cnt = 0;
    thingSpeak();   //invokes thingSpeak user command
  } else
  {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Connection failed:");
    cnt++;
    display.setCursor(0, 8 * 2);
    display.print("Failure Count = ");
    display.setCursor(108, 8 * 2);
    display.print(cnt);
    display.display();
    if (cnt >= 3) {      //start failure count
      digitalWrite(ledOnline, LOW);
      digitalWrite(ledOffline, HIGH);   //Red LED indicates router is offline
      state = 0;
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("Connecting to ");// Connect to WiFi network
      display.setCursor(84, 0);
      display.print(ssid2);   //connect to 2nd network to update thingSpeak and send failure email
      WiFi.begin(ssid2, password2);
      delay(1000);
      display.setCursor(0, 8 * 2);
      display.print("IP address issued:");    // Print the IP address
      display.setCursor(0, 8 * 4);
      display.print("http://");
      display.setCursor(50, 8 * 4);
      display.print(WiFi.localIP());
      display.display();
      delay(2000);

      gmail();         //Gmail user defined function
      thingSpeak();  //update thingSpeak as per user defined function
      delay(1000);
      doreset();   //reset router as per user defined function
    } //end if
  }//end else
}  //end void loop




void doreset() {     //user function to reset the router
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Resetting the Router");
  display.setCursor(0, 8 * 4);
  display.print("Reset done, waiting");
  display.setCursor(0, 8 * 6);
  display.print("2.5 Minutes Delay");   //waits for router to reboot and establish internet connection. 
  display.display();
  digitalWrite(relayPin, LOW );                  //activate relay.  relay activates on LOW signal
  delay(5000);
  digitalWrite(relayPin, HIGH);                  //turn relay back on

  delay(BOOTTIME * 1000);                        //wait for router to boot
  ESP.restart();                 //restart the ESP8266
}  //end user function

void thingSpeak() {   //user function to update thingSpeak
  int routerState = state;
  //convert the sensor data into String Objects
  String routerField = String(routerState);

  // Update ThingSpeak
  String thingSpeakData = "field1=" + routerField;

  //Establish A connection with ThingSpeak.
  if (millis() - timer >= duration)   //set up timer for thingSpeak update 20 seconds.
  {
    if (client.connect(thingSpeakAddress, 80))
    {
      client.println("POST /update HTTP/1.1");  //The message Start Line (Method URI protocolVersion);
      client.println("Host: api.thingspeak.com");
      client.println("Connection: close");
      client.println("X-THINGSPEAKAPIKEY: " + APIKey);
      client.println("Content-Type: application/x-www-form-urlencoded");
      client.print("Content-Length:  ");
      client.println(thingSpeakData.length() );
      client.println();  //This empty line says "Header Fields are complete
      //Send the Message Body.
      client.print(thingSpeakData);
      //Let us know if the connection Thingspeak was established.
      if (client.connected())
      {
        display.clearDisplay();
        display.setCursor(0, 0);
        display.print("Connecting to:  ");
        display.setCursor(0, 8 * 2);
        display.print("ThingSpeak.com");
        display.setCursor(0, 8 * 4);
        display.print("Updating Status");
        display.display();
        delay(3000);
      }  //end if
    }   //end if
  }   //end if
}   //end user function
void gmail() {    //command for the sending Gmail.

  Gsender *gsender = Gsender::Instance();    // Getting pointer to class instance
  String subject = "Router Offline";
  if (gsender->Subject(subject)->Send("someone@gmail.com", "Router Offline")) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Message send.");
  } else {
    display.setCursor(0, 0);
    display.print("Error sending message: ");
    display.setCursor(0, 8 * 3);
    display.print(gsender->getError());
    display.display();
  }  //end else
}   //end user defined function

Gsender.h

/* Gsender class helps send e-mails from Gmail account
   using Arduino core for ESP8266 WiFi chip
   by Boris Shobat
   September 29 2016
*/
#ifndef G_SENDER
#define G_SENDER
#define GS_SERIAL_LOG_1         // Print to Serial only server responce
//#define GS_SERIAL_LOG_2       //  Print to Serial client commands and server responce
#include <WiFiClientSecure.h>

class Gsender
{
  protected:
    Gsender();
  private:
    const int SMTP_PORT = 465;
    const char* SMTP_SERVER = "smtp.gmail.com";
    const char* EMAILBASE64_LOGIN = "xxxxxxxx";
    const char* EMAILBASE64_PASSWORD = "xxxxxxxxxx";
    const char* FROM = "xxxxxxxxxx";
    const char* _error = nullptr;
    char* _subject = nullptr;
    String _serverResponce;
    static Gsender* _instance;
    bool AwaitSMTPResponse(WiFiClientSecure &client, const String &resp = "", uint16_t timeOut = 10000);

  public:
    static Gsender* Instance();
    Gsender* Subject(const char* subject);
    Gsender* Subject(const String &subject);
    bool Send(const String &to, const String &message);
    String getLastResponce();
    const char* getError();
};
#endif // G_SENDER

 

Gsender.cpp

#include "Gsender.h"
Gsender* Gsender::_instance = 0;
Gsender::Gsender() {}
Gsender* Gsender::Instance()
{
  if (_instance == 0)
    _instance = new Gsender;
  return _instance;
}

Gsender* Gsender::Subject(const char* subject)
{
  delete [] _subject;
  _subject = new char;
  strcpy(_subject, subject);
  return _instance;
}
Gsender* Gsender::Subject(const String &subject)
{
  return Subject(subject.c_str());
}

bool Gsender::AwaitSMTPResponse(WiFiClientSecure &client, const String &resp, uint16_t timeOut)
{
  uint32_t ts = millis();
  while (!client.available())
  {
    if (millis() > (ts + timeOut)) {
      _error = "SMTP Response TIMEOUT!";
      return false;
    }
  }
  _serverResponce = client.readStringUntil('\n');
#if defined(GS_SERIAL_LOG_1) || defined(GS_SERIAL_LOG_2)
  Serial.println(_serverResponce);
#endif
  if (resp && _serverResponce.indexOf(resp) == -1) return false;
  return true;
}

String Gsender::getLastResponce()
{
  return _serverResponce;
}

const char* Gsender::getError()
{
  return _error;
}

bool Gsender::Send(const String &to, const String &message)
{
  WiFiClientSecure client;
#if defined(GS_SERIAL_LOG_2)
  Serial.print("Connecting to :");
  Serial.println(SMTP_SERVER);
#endif
  if (!client.connect(SMTP_SERVER, SMTP_PORT)) {
    _error = "Could not connect to mail server";
    return false;
  }
  if (!AwaitSMTPResponse(client, "220")) {
    _error = "Connection Error";
    return false;
  }

#if defined(GS_SERIAL_LOG_2)
  Serial.println("HELO friend:");
#endif
  client.println("HELO friend");
  if (!AwaitSMTPResponse(client, "250")) {
    _error = "identification error";
    return false;
  }

#if defined(GS_SERIAL_LOG_2)
  Serial.println("AUTH LOGIN:");
#endif
  client.println("AUTH LOGIN");
  AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2)
  Serial.println("EMAILBASE64_LOGIN:");
#endif
  client.println(EMAILBASE64_LOGIN);
  AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2)
  Serial.println("EMAILBASE64_PASSWORD:");
#endif
  client.println(EMAILBASE64_PASSWORD);
  if (!AwaitSMTPResponse(client, "235")) {
    _error = "SMTP AUTH error";
    return false;
  }

  String mailFrom = "MAIL FROM: <" + String(FROM) + '>';
#if defined(GS_SERIAL_LOG_2)
  Serial.println(mailFrom);
#endif
  client.println(mailFrom);
  AwaitSMTPResponse(client);

  String rcpt = "RCPT TO: <" + to + '>';
#if defined(GS_SERIAL_LOG_2)
  Serial.println(rcpt);
#endif
  client.println(rcpt);
  AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2)
  Serial.println("DATA:");
#endif
  client.println("DATA");
  if (!AwaitSMTPResponse(client, "354")) {
    _error = "SMTP DATA error";
    return false;
  }

  client.println("From: <" + String(FROM) + '>');
  client.println("To: <" + to + '>');

  client.print("Subject: ");
  client.println(_subject);

  client.println("Mime-Version: 1.0");
  client.println("Content-Type: text/html; charset=\"UTF-8\"");
  client.println("Content-Transfer-Encoding: 7bit");
  client.println();
  String body = "<!DOCTYPE html><html lang=\"en\">" + message + "</html>";
  client.println(body);
  client.println(".");
  if (!AwaitSMTPResponse(client, "250")) {
    _error = "Sending message error";
    return false;
  }
  client.println("QUIT");
  if (!AwaitSMTPResponse(client, "221")) {
    _error = "SMTP QUIT error";
    return false;
  }
  return true;
}

4 Comments

  1. Avatar JohnnyFRX on October 17, 2017 at 3:38 pm

    Very Cool Project Man! I use the heck out of the ESP’s around my house, a few connected to similar relays that handle the heat sources for our Beardie and our Gecko enclosures. As you’ve experienced, once all is configured right and happy…they are dedicated reliable little workhorses. NICE JOB ON THIS PROJECT! I wonder if LoRa would be useful for those with only one network available.

    • Avatar John Simister on October 18, 2017 at 1:18 am

      Hi JohnnyFRX,

      Yes, you are right, they are a great little workhorses. I am still amazed what can be done from such a small package.

      Thanks for your comments

      Regards, John

    • Avatar MICHAEL JAMES on October 30, 2017 at 11:11 am

      I couldn’t agree more. The ESP8266 are sweet for making things smaller and connected to the internet. I love the Adafruit Hazza package.

  2. Avatar Ivano on May 20, 2019 at 2:01 am

    Very Cool Project
    any chance to have a electric schema ? let me know
    Regards
    Ivano

Leave a Comment