#include <LiquidCrystal_PCF8574.h>
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

LiquidCrystal_PCF8574 lcd(0x27); // set the LCD address to 0x27 for a 16 chars and 2 line display

// DS18B20 data wire
#define ONE_WIRE_BUS 0

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

//Esta aplicación se conecta a un punto de acceso existente (red WiFi).
//Modificar las variables ssid y password y conectarse desde un móvil o PC conectado a la misma red.
const char* ssid = "your-ssid";
const char* password = "your-password";

String request;
unsigned long currentTime = millis();
unsigned long previousTime = 0; 
const long timeoutTime = 2000;

float sensor;
float tempC;

WiFiServer server(80);

#define I0 16
#define I1 14
#define I2 12

#define Q0 2
#define Q1 15
#define Q2 13

#define estado_I0 digitalRead(I0)
#define estado_I1 digitalRead(I1)
#define estado_I2 digitalRead(I2)

boolean estado_Q0 = LOW;
boolean estado_Q1 = LOW;
boolean estado_Q2 = LOW;

byte alto[] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B00000,
};

byte bajo[] = {
  B11111,
  B10001,
  B10001,
  B10001,
  B10001,
  B10001,
  B11111,
  B00000,
};

void estados() {
  lcd.setCursor(0,0);
  if (WiFi.status() == WL_CONNECTED)
  {
    lcd.print("IP: ");
    lcd.print(WiFi.localIP());
    lcd.print("    ");
  }
  else
    lcd.print("Conectando a red...");
  lcd.setCursor(0,1);
  lcd.print("I: ");
  lcd.write(digitalRead(I0));
  lcd.print(" ");
  lcd.write(digitalRead(I1));
  lcd.print(" ");
  lcd.write(digitalRead(I2));
  lcd.setCursor(0,2);
  lcd.print("   0 1 2");
  lcd.setCursor(0,3);
  lcd.print("Q: ");
  lcd.write(digitalRead(Q0));
  lcd.print(" ");
  lcd.write(digitalRead(Q1));
  lcd.print(" ");
  lcd.write(digitalRead(Q2)); 
}

void setup() {
  // put your setup code here, to run once:
  pinMode(I0, INPUT);
  pinMode(I1, INPUT);
  pinMode(I2, INPUT);
  pinMode(Q0, OUTPUT);
  pinMode(Q1, OUTPUT);
  pinMode(Q2, OUTPUT);

  sensors.begin();

  lcd.begin(20, 4);
  lcd.createChar(0, bajo);
  lcd.createChar(1, alto);
  delay(200);
  lcd.setBacklight(255);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED)
  {
    estados();
    delay(500);
  }

  server.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  WiFiClient client = server.available();   // Listen for incoming clients

  sensor = analogRead(A0);

  sensors.requestTemperatures(); // Send the command to get temperatures
  tempC = sensors.getTempCByIndex(0);

  estados();

  if (client)                               // If a new client connects,
  {
    currentTime = millis();
    previousTime = currentTime;
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime)   // loop while the client's connected
    {
      currentTime = millis();
      if (client.available())               // if there's bytes to read from the client,
      {
        char c = client.read();             // read a byte, then
        request += c;
        if (c == '\n')                      // if the byte is a newline character
        {
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0)
          {
            if (request.indexOf("/Q0_on") != -1)
              estado_Q0 = HIGH;
            if (request.indexOf("/Q0_off") != -1)
              estado_Q0 = LOW;

            if (request.indexOf("/Q1_on") != -1)
              estado_Q1 = HIGH;
            if (request.indexOf("/Q1_off") != -1)
              estado_Q1 = LOW;

            if (request.indexOf("/Q2_on") != -1)
              estado_Q2 = HIGH;
            if (request.indexOf("/Q2_off") != -1)
              estado_Q2 = LOW;

            digitalWrite(Q0, estado_Q0);
            digitalWrite(Q1, estado_Q1);
            digitalWrite(Q2, estado_Q2);

            if (request.indexOf("/json") != -1)
            {
              // HTTP Response in the form of HTML Web Page
              client.println("HTTP/1.1 206 OK");
              client.println("Content-type:text/html");
              client.println("Connection: close");
              client.println();

              StaticJsonDocument<128> doc;

              doc["sensor"] = sensor;
              doc["temperatura"] = tempC;
              doc["I0"] = estado_I0;
              doc["I1"] = estado_I1;
              doc["I2"] = estado_I2;
              doc["Q0"] = digitalRead(Q0);
              doc["Q1"] = digitalRead(Q1);
              doc["Q2"] = digitalRead(Q2);
              serializeJson(doc, client);
              break;
            }
            else
            {
              // HTTP Response in the form of HTML Web Page
              client.println("HTTP/1.1 200 OK");
              client.println("Content-type:text/html");
              client.println("Connection: close");
              client.println();

              // Display the HTML web page
              client.println("<!DOCTYPE HTML>");
              client.println("<html>");
              client.println("<head>");
              client.println("<META charset=\"utf-8\">");
              client.println("<meta http-equiv=\"refresh\" content=\"0.5\">");
              client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">");
              client.println("<link rel=\"icon\" href=\"data:,\">");

              // CSS Styling for Buttons and Web Page
              client.println("<style>");
              client.println("html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
              client.println("body {margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}");
              client.println(".button {display: inline-table;width: 50px;background-color: #1abc9c;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 20px;margin: 0px auto 35px;cursor: pointer;border-radius: 20px;}");
              client.println(".button-on {background-color: #1abc9c;}");
              client.println(".button-on:active {background-color: #16a085;}");
              client.println(".button-off {background-color: #34495e;}");
              client.println(".button-off:active {background-color: #2c3e50;}");
              client.println("</style>");
              client.println("</head>");

              // The main body of the Web Page
              client.println("<body>");
              client.println("<h1>ESP8266 Web Server</h1>\n");
              client.println("<h3>Using Station (ST) Mode</h3>\n");
              client.println("<h3>Sensor: ");
              client.println(sensor,1);
              client.println("</h3>\n");
              client.println("<h3>Temperatura: ");
              client.println(tempC,1);
              client.println("°C");
              client.println("</h3>\n");

              if (estado_I0)
                client.println("<a class=\"button button-on\">I0: ON</a>");
              else
                client.println("<a class=\"button button-off\">I0: OFF</a>");

              if (estado_I1)
                client.println("<a class=\"button button-on\">I1: ON</a>");
              else
                client.println("<a class=\"button button-off\">I1: OFF</a>");

              if (estado_I2)
                client.println("<a class=\"button button-on\">I2: ON</a>");
              else
                client.println("<a class=\"button button-off\">I2: OFF</a>");

              client.println("<br>");

              if (estado_Q0)
                client.println("<a class=\"button button-on\" href=\"/Q0_off\">Q0: ON</a>");
              else
                client.println("<a class=\"button button-off\" href=\"/Q0_on\">Q0: OFF</a>");

              if (estado_Q1)
                client.println("<a class=\"button button-on\" href=\"/Q1_off\">Q1: ON</a>");
              else
                client.println("<a class=\"button button-off\" href=\"/Q1_on\">Q1: OFF</a>");

              if (estado_Q2)
                client.println("<a class=\"button button-on\" href=\"/Q2_off\">Q2: ON</a>");
              else
                client.println("<a class=\"button button-off\" href=\"/Q2_on\">Q2: OFF</a>");

              client.println("</body>");
              client.println("</html>");
              client.println("");
              break;
            }
          }
          else                              // if you got a newline, then clear currentLine
            currentLine = "";
        }
        else if (c != '\r')                 // if you got anything else but a carriage return character,
          currentLine += c;                 // add it to the end of the currentLine
      }
    }
    request = "";
    client.stop();
  }
}