#include <ESP8266WiFi.h>
#include <ESP8266Ping.h>
#include <WiFiClientSecure.h>

#define D0 16
#define D1 5    // I2C Bus SCL (clock)
#define D2 4    // I2C Bus SDA (data)
#define D3 0
#define D4 2    // Same as "LED_BUILTIN", but inverted logic
#define D5 14   // SPI Bus SCK (clock)
#define D6 12   // SPI Bus MISO 
#define D7 13   // SPI Bus MOSI
#define D8 15   // SPI Bus SS (CS)
#define D9 3    // RX0 (Serial console)
#define D10 1   // TX0 (Serial console)


// parameters.h file contains setup parameters like wifi ssid and password, host to connect, etc
#include "parameters.h"

unsigned const int HTTPS_PORT = 443;

void setup() {
  pinMode(D2, OUTPUT);       // Relay for Router 
  digitalWrite(D2, LOW);
  pinMode(D1, OUTPUT);       // Relay for Server
  digitalWrite(D1, LOW);
  pinMode(D5, OUTPUT);       // Led for displaying OK connection
  digitalWrite(D5, LOW);
  pinMode(D7, OUTPUT);       // Led for displaying KO connection
  digitalWrite(D7, LOW);
  
  
  Serial.begin(115200);
  delay(1000);
  Serial.println("");
  Serial.println("Internet Smart Plug");
  connectToWifi();
}

void loop() {
  boolean online;
  unsigned short i = 0;

  if (Ping.ping(server_ip)) {
    Serial.println("");
    Serial.println("Server is online, nothing to do!!");
    Serial.println("");
    for (int i=0; i < 4; i++){
      digitalWrite(D5, HIGH);
      delay(200);
      digitalWrite(D5, LOW);
      delay(200);
    }
  } else {
    Serial.println("");
    Serial.println("Error :( . Server is offline.");
    Serial.println("");
    cyclePower2();
  }

  do {
    boolean check1 = get(CHECK_HOST1, CHECK_URL1);
    boolean check2 = get(CHECK_HOST2, CHECK_URL2);
    online = (check1 || check2);
  } while(!online && i++ < MAX_TRIES);

  Serial.println("");
  Serial.print("status: ");
  Serial.println(online ? "OK" : "KO");
  Serial.println("");

  //get(MONITOR_HOST, online ? MONITOR_URL_UP : MONITOR_URL_DOWN);

  if (!online) {
    cyclePower();
  } else {
    Serial.println("Router is connected to Internet, nothing to do");
    for (int i=0; i < 2; i++){
      digitalWrite(D5, HIGH);
      delay(200);
      digitalWrite(D5, LOW);
      delay(200);
    }
  }
  
  

  stopWifiAndReboot();
}

void stopWifiAndReboot() {
  Serial.print("disabling WIFI then wait: ");
  Serial.print(WAIT_TIME);
  Serial.println(" miliseconds.");

  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();
  digitalWrite(D5, LOW);
  digitalWrite(D7, LOW);
  delay(1); //Needed, at least in my tests WiFi doesn't power off without this for some reason
  delay(WAIT_TIME);
  Serial.println("restarting");
  ESP.restart();
}

void connectToWifi() {
  unsigned int i = 0;

  Serial.println("");
  Serial.print("connecting to ");
  Serial.println(WIFI_SSID);

  WiFi.forceSleepWake();
  WiFi.mode(WIFI_STA);  
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    i++;
    if (i > 50) {
        Serial.println("can’t connect to wifi");
        stopWifiAndReboot();
      }
  }
  for (int i=0; i < 10; i++){
    digitalWrite(D5, HIGH);
    delay(50);
    digitalWrite(D5, LOW);
    delay(50);
  }  
  Serial.println("");
  Serial.println("wifi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println("");
}

boolean get(const char* host, const char* url) {
  WiFiClientSecure httpsClient;
  boolean status = false;
  Serial.print(">  ");
  Serial.print(host);
  Serial.print(":");
  Serial.print(HTTPS_PORT);

  if (!httpsClient.connect(host, HTTPS_PORT)) {
    Serial.println("");
    Serial.println("connection failed");
    return false;
  }

  Serial.println(url);

  httpsClient.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: ESP8266\r\n" +
               "Connection: close\r\n\r\n");

  unsigned long timeout = millis();
  while (httpsClient.available() == 0) {
    delay(1);
    if (millis() - timeout > REQUEST_TIMEOUT) {
      Serial.println("client Timeout !");
      httpsClient.stop();
      return false;
    }
  }

  if (httpsClient.connected()) {
    String line = httpsClient.readStringUntil('\n');
    Serial.print("< ");
    Serial.println(line);
    status = true;
  }
  return status;
}

// Turn Router off then on
void cyclePower() {
  for (int i=0; i < 2; i++){
    digitalWrite(D7, HIGH);
    delay(200);
    digitalWrite(D7, LOW);
    delay(200);
  }  
  Serial.println("Turning Router off");
  digitalWrite(D2, HIGH);
  delay(10000);
  digitalWrite(D2, LOW);
  Serial.println("Turning Router on");
}

// Turn Server off then on
void cyclePower2() {
  for (int i=0; i < 4; i++){
    digitalWrite(D7, HIGH);
    delay(200);
    digitalWrite(D7, LOW);
    delay(200);
  }
  Serial.println("Turning Server off");
  digitalWrite(D1, HIGH);
  delay(10000);
  digitalWrite(D1, LOW);
  Serial.println("Turning Server on");
}
