#include <ESP8266WiFi.h>
#include <time.h>

// v Arduino IDE je nastaven board:
//LOLIN(WEMOS) D1 mini (clone)

//zapojeni teplotniho cidla, termistoru a odporu do delice napeti, kde termistor je nahore, s teplotou klesa odpor, proto je odpor u delice pripraven na tuto vyssi teplotu, cca 5000 Ohmu
//bily modry drát termistor cca 10 000 Ohmu pri 25°C --- modry drat 3.3V na ESP8266, neni mozno ho zapojit na 5V
//zluty modry drat - celkovy odpor 17000 ohm         --- bíly stredni drat na A0 od ESP8266
//bily zluty odpor 5490 Ohm                          --- zluty GND na ESP8266

//zapojeni modulu rele (ma uz zabudovany tranzistor, diodu atd.)
// D1 rele    --- D1 ESP8266
// 5V rele    --- 5V ESP8266
// GRND rele  --- GRND ESP8266, spolecny s zlutym dratem od cidla, viz vyse

const double hystereze=5; // kolik stupnu ma byt hystereze kolem promenne teplota_spinana
const int teplota_spinana_vychozi=80; //60 je po carku a carka je 50°C na hornim cidlu; 80 je vodorovne

const char* ssid = "ma_mila_wifina"; //your WiFi Name
const char* password = "1324352413";  //Your Wifi Password

const int ip1=192;
const int ip2=168;
const int ip3=0;
const int ip4=100; //bojler 100

const int gateway1=192;
const int gateway2=168;
const int gateway3=0;
const int gateway4=1;

const int mask1=255;
const int mask2=255;
const int mask3=255;
const int mask4=0;

time_t now;    // this are the seconds since Epoch (1970) - UTC

const int ledPin = LED_BUILTIN; // zrejme 2
const int RELAY_PIN = 5; //D1 je petka, viz ESP8266-WeMos-D1-Mini-pinout-gpio-pin.png
const bool staticka_adresa=true;
bool rucni_nastaveni=false;
bool docasne=false;
bool client_still_silent=true;
int value = LOW;
int i; //ad hoc citac
int cekani_i;
String request; //declaration

const double dVCC = 3.3;            // NodeMCU on board 3.3v vcc
const double dR2 = 5500;            // 10k ohm series resistor
const double dAdcResolution = 1023; // 10-bit adc
double dAdcValue;
//double docasne_offset= 12*60*60;            // kolik sekund ma cekat do automatickeho modu
double docasne_offset= 20;          // kolik sekund ma cekat do automatickeho modu
double docasne_dokdy=  20;          // v kolika sekundach vyprsi docasnost
int teplota_spinana=teplota_spinana_vychozi;

const double dA = 0.002519558;   // thermistor equation parameters
const double dB = -0.000009456;
const double dC = 0.000001228113;

WiFiServer server(80); //deklarace, ale o par radku nize se musi jeste nastarovat
WiFiClient client; // strejda, co se pripojil k serveru

void setup() {
  Serial.begin(9600);
  delay(10);
  pinMode(ledPin, OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(ledPin, LOW); //nez se pripoji k internetu tak zacne svitit
  client = server.accept();
}

double teplota() {
  double dVout, dRth, dTemperature;
  dAdcValue = analogRead(A0);
  dVout = (dAdcValue * dVCC) / dAdcResolution;
  dRth = (dVCC * dR2 / dVout) - dR2;
  dTemperature = (1 / (dA + (dB * log(dRth)) + (dC * pow((log(dRth)), 3))));

//  Steinhart-Hart Thermistor Equation:
//  Temperature in Kelvin = 1 / (A + B[ln(R)] + C[ln(R)]^3)
//  where A = 0.001129148, B = 0.000234125 and C = 8.76741*10^-8
//  U sveho cidla jsem musel v Calcu metodou nejmensich ctvercu a Solverem zjistit hodnoty mych parametru
//  Temperature in Kelvin
  dTemperature = dTemperature - 273.15;
// Temperature in degree celsius

  if (i%40==0) {
    Serial.print("Temperature = ");
      Serial.print(dTemperature);
      Serial.println(" degree celsius");
    Serial.print("A0 = ");
      Serial.print(dAdcValue);
      Serial.println(" mV");
  }
  delay(100);
  return(dTemperature);
  }

void loop() {
  // Check if a client has connected
  double dTeplota;
  dTeplota=teplota();
  if (dTeplota>teplota_spinana+hystereze/2 && rucni_nastaveni==false) {
    digitalWrite(ledPin, HIGH);
    digitalWrite(RELAY_PIN, LOW );
    value = LOW;
  }
  if (dTeplota<teplota_spinana-hystereze/2 && rucni_nastaveni==false) {
    digitalWrite(ledPin, LOW);
    digitalWrite(RELAY_PIN, HIGH );
    value = HIGH;
  }
  time(&now); // read the current time and put it into variable now
  if (now > docasne_dokdy && docasne==true) {
    rucni_nastaveni=false;
    docasne=false;
  }

if (WiFi.status() != WL_CONNECTED ) {
  cekani_i=0; //zacina pocitat znova od posledniho pripojeni
  Serial.println("WiFi.status(): "+ String(WiFi.status()) );
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  if (staticka_adresa) {
    // IPAddress ip(192, 168, 0, bojler); //deklarovani promennych rucne
    // IPAddress gateway(192,168,0,1);
    // IPAddress subnet(255,255,255,0);

    IPAddress ip(ip1, ip2, ip3, ip4); //deklarovani promennych
    IPAddress gateway(gateway1,gateway2,gateway3,gateway4);
    IPAddress subnet(mask1,mask2,mask3,mask4);

    WiFi.config(ip, gateway, subnet);
    // https://forum.arduino.cc/t/setting-a-static-ip-on-an-esp8266/677153/5
  }
  WiFi.begin(ssid, password);
  digitalWrite(ledPin, LOW); //sviti, kdyz nepripojeno
  while (WiFi.status() != WL_CONNECTED && cekani_i<600) { //100 sekund ceka na odpoved routeru
    if (cekani_i==5) Serial.print("Nejsem pripojen. Zkusim se pripojit... ");
    cekani_i++;
    delay(100);
    if (cekani_i%10==0) Serial.print("&");
  }
  Serial.println();
}

  if (WiFi.status() == WL_CONNECTED) {
    if (cekani_i<600) {
    digitalWrite(ledPin, HIGH); //po startu svitici LED zhasne, kdyz se ESP pripoji k wifi routeru
    Serial.println("");
    Serial.println("WiFi connected");
    // Start the server
    server.begin();
    Serial.println("Server started");
    // Print the IP address
    Serial.print("Use this URL to connect: ");
      Serial.print("http://");
      Serial.print(WiFi.localIP());
      Serial.println("/");
    Serial.print("Mac address: ");
    Serial.println(WiFi.macAddress());
    Serial.println("");
    // Serial.println("LED_BUILTIN=" + String(LED_BUILTIN));
    // Serial.println("D1="+String(D1));
    //  return; //znova loop ale uz pripojeny
    cekani_i=601; //aby to bezelo jen jednou
    }
  }
/*
0 : WL_IDLE_STATUS when Wi-Fi is in process of changing between statuses
1 : WL_NO_SSID_AVAILin case configured SSID cannot be reached
3 : WL_CONNECTED after successful connection is established
4 : WL_CONNECT_FAILED if connection failed
6 : WL_CONNECT_WRONG_PASSWORD if password is incorrect
7 : WL_DISCONNECTED if module is not configured in station mode
*/

// Wait until the client sends some data
// i=0;
// client = server.available();
// client = server.accept(); uz je v setup
// if (i<10000 && ! client) { // kdyz bezi loop neni tady nekonecne dlouho, max cca 100 sekund
 // client = server.available(); // tady to je nakonci while
// }
  // client = server.available(); // tady to je na konci while

  //client = server.accept();
   client = server.available();
  if (i%1000==0) Serial.println("debug tisicovka cekani i=" + String(i) +
    "; \nclient: "+ String(client) +
    "; \nWiFi.status(): "+ String(WiFi.status()) + " 3=connected");

  if (!client) {
    if (client_still_silent==false) {
      Serial.println("Klient se nehlasi...");
      client_still_silent=true; //to je tu, aby se predchozi hlaska vypsala jen jednou
    }
  } else { //hlasi se klient
    Serial.println("Hlasi se klient! i="+ String(i));
    client_still_silent=false;

  request = client.readStringUntil('\r');
  Serial.print("new client: ");
  Serial.println(request);

if (request.indexOf("INFO") != -1) {
    Serial.print("Vypis informaci na WEB ");
    Serial.println(WiFi.localIP());
  }

  if (request.indexOf("TURN=AUTO") != -1) { //analyza pozadavku klienta
    rucni_nastaveni=false;
  }

  if (request.indexOf("TURN=ON") != -1) {
    digitalWrite(ledPin, LOW);
    digitalWrite(RELAY_PIN, HIGH);
    rucni_nastaveni=true;
    value = HIGH;
  }

  if (request.indexOf("TURN=OFF") != -1 ) {
    digitalWrite(ledPin, HIGH);
    digitalWrite(RELAY_PIN, LOW );
    rucni_nastaveni=true;
    value = LOW;
  }

  if (request.indexOf("TEMPORAL=ON") != -1 ) {
  //  digitalWrite(ledPin, HIGH);
  //  digitalWrite(RELAY_PIN, LOW );
    rucni_nastaveni=true;
    docasne=true;
    docasne_dokdy=now+docasne_offset;
  }
  if (request.indexOf("TEMPORAL=OFF") != -1 ) {
  //  digitalWrite(ledPin, HIGH);
  //  digitalWrite(RELAY_PIN, LOW );
    rucni_nastaveni=true;
    docasne_dokdy=now;
    docasne=false;
  }
  if (request.indexOf("TEMPORAL=H+") != -1 ) {
    rucni_nastaveni=true;
    docasne_dokdy=docasne_dokdy+3600;
    docasne=true;
  }
  if (request.indexOf("TEMPORAL=H-") != -1 ) {
    rucni_nastaveni=true;
    if (docasne_dokdy>3600) docasne_dokdy=docasne_dokdy-3600;
    docasne=true;
  }

  if (request.indexOf("TEMPERATURE=DEFAULT") != -1 ) {
    teplota_spinana=teplota_spinana_vychozi;
  }
  if (request.indexOf("TEMPERATURE=+5") != -1 ) {
    teplota_spinana=teplota_spinana+5;
    if (teplota_spinana>90) teplota_spinana=90;
  }
  if (request.indexOf("TEMPERATURE=-5") != -1 ) {
    teplota_spinana=teplota_spinana-5;
    if (teplota_spinana<10) teplota_spinana=10;
  }

  // Set ledPin according to the request
  //digitalWrite(ledPin, value);
  // Return the response
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); // do not forget this one
  client.println("<!DOCTYPE HTML>");
  client.println("<html><body>");
  client.print("<p>Teplota cidla je nyni: ");
  client.print(dTeplota);
  //client.print("<p>Teplota cidla je nyni: ");
  client.print(" &#8451; ("); //°C
  client.print(dAdcValue);
  client.println(" mV) </p>");
  //client.println(" ");
  client.print("<p>Spinana teplota: ");
  client.print(teplota_spinana);
  client.println(" &#8451;</p>");//°C
  client.print("<p>Hystereze: ");
  client.print(hystereze);
  client.println(" &#8451;</p>");//°C
  client.print("Topeni bojleru a LED jsou nyni: ");
  if(value == HIGH) {
    client.print("<b>Zapnuty</b>");
  } else {
    client.print("Vypnuty");
  }

  if (rucni_nastaveni==true)
    client.print("<p>Rucni ovladani je <b>zapnuto</b>");
  else {
    client.print("<p>Rucni ovladani je vypnuto");
    client.println(" </p>");
  }

  if (docasne==true) {
    client.print("<p>Rucni ovladani je docasne do ");
    client.print(String(docasne_dokdy)+" sekund, tzn. cca "+String(docasne_dokdy/3600)+" hodin");
    client.println("</p>");
    } else {
    client.print("<p>Rucni ovladani neni docasne");
    client.println(" </p>");
    }

  client.print("<p>Lhuta docasnosti [s]: ");
    client.print(docasne_offset);
    client.println("</p>");


  client.print("<p>Pocet sekund od zapnuti termostatu (now): ");
    client.print(String(now) +", tzn. cca "+String(now/3600)+" hod." );
    client.println("</p>");

  // HTML for buttons to work LED
  client.println("<br><br>");
  client.println("<a href=\"/INFO\"\"><button><big><big>Info</big></big></button></a><br />");
  client.println("<a href=\"/TURN=AUTO\"\"><button>Turn Auto</button></a>");
  client.println("<a href=\"/TURN=ON\"\"><button>Turn On </button></a>");
  client.println("<a href=\"/TURN=OFF\"\"><button>Turn Off </button></a></big></big><br />");

  client.println("<a href=\"/TEMPORAL=ON\"\"><button>Temporal On </button></a>");
  client.println("<a href=\"/TEMPORAL=OFF\"\"><button>Temporal Off </button></a><br />");
  client.println("<a href=\"/TEMPORAL=H+\"\">Docasna lhuta: <button>+ 1 hour</button></a>");
  client.println("<a href=\"/TEMPORAL=H-\"\"><button>- 1 hour </button></a><br />");

  client.println("<a href=\"/TEMPERATURE=-5\"\"><button>-5 &#8451;</button></a>");
  client.println("<a href=\"/TEMPERATURE=+5\"\"><button>+5  &#8451;</button></a>");
  client.println("<a href=\"/TEMPERATURE=DEFAULT\"\"><button>Default temperature ("+String(teplota_spinana_vychozi)+" &#8451;)</button></a><br />");
//  client.println("<a href=\"/TEMPORAL=OFF\"\"><button>Temporal Off </button></a><br />");
    client.print("<p>IP adresa: ");
      client.print(WiFi.localIP());
      client.println("</p>");
    client.print("<p>MAC adresa: ");
      client.print(WiFi.macAddress());
      client.println("</p>");
    client.print("<p>Port tohoto zarizeni je mozno monitorovat po pripojeni do pocitace pomoci prikazu: ");
      client.print("tio -b 9600 /dev/ttyUSB0 ap.");
      client.println("</p>");
    client.print("<p>Ziskat informace z teto stranky muzete z prikazove radky, napr. teplotu vody:<br>");
      client.print("wget -q -S -O - 192.168.0.100 2>&1 | sed -rn \"s/^.*je nyni: ([0-9.]*) .*$/\\1/p\"<br>22.11");
      client.println("</p>");
    client.println("</body></html>");

    delay(1);
    Serial.println("Client disconnected");
    // client.flush(); //zkusim to zdvojit
    Serial.println("");
  client.flush(); // toto je totez jako:  while (client.available()) { client.read(); }
  }
  i++;
  delay(10);
  request="";
} //konec loop