#include <BH1750.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include "DHT.h"

//Implementace piny pro UART rozhrani
SoftwareSerial espSerial(5, 6); // RX, TX
SoftwareSerial simSerial(7, 8); // RX, TX

//Implementace typu cidla teploty a osvetleni
DHT dht(10, DHT11);
BH1750 lightMeter;

//Impementace promennych
#define DEBUG true
#define BUFFER_SIZE 128
char buffer[BUFFER_SIZE];
String strBuffer = "";
boolean ifSms = false;
int channel, packet_len;
char *pb;
float t;
uint16_t l;

void setup() {
  // Nastaveni rychlosti Seroveho rozhrani
  Serial.begin(9600);           
  Serial.println("\nStart");

  //Implementace ovladacich piny
  pinMode(11, OUTPUT); 
  pinMode(2, OUTPUT); 
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(9,OUTPUT);
  digitalWrite(11,LOW);
  digitalWrite(2,LOW);
  digitalWrite(3,LOW);
  digitalWrite(4,LOW);
  digitalWrite(9,LOW);
  
  // Implementace UART pro ESP8266    
  espSerial.begin(9600); 
  
  //Nastaveni modulu ESP8266
  dataExchange("AT+RST\r\n",espSerial, 2000, DEBUG);
  dataExchange("AT\r\n",espSerial, 2000, DEBUG);
  dataExchange("AT+CWMODE=2\r\n",espSerial, 2000, DEBUG);
  dataExchange("AT+CIFSR\r\n", espSerial, 2000, DEBUG);
  dataExchange("AT+CIPMUX=1\r\n",espSerial, 2000, DEBUG);
  dataExchange("AT+CIPSERVER=1,80\r\n",espSerial, 2000, DEBUG);

  // Implementace UART pro SIM900 
  simSerial.begin(9600);
  
  //Nastaveni modulu SIM900
  dataExchange("AT+CMGF=1\r",simSerial ,300, DEBUG);
  dataExchange("AT+IFC=1",simSerial ,300, DEBUG);
  dataExchange("AT+CPBS=\"SM\"\r",simSerial ,300, DEBUG);
  dataExchange("AT+CNMI=1,2,2,1,0\r",simSerial ,300, DEBUG);

  //Zapnuti SIM900
  digitalWrite(9,HIGH);
  delay(3500);
  digitalWrite(9,LOW);
  delay(3000);

  dht.begin();
  lightMeter.begin(); 
}// Setup konec

void loop() {
  //Nacitani data z cidel
  float t = dht.readTemperature();
  uint16_t l = lightMeter.readLightLevel();

  //Poslouchani na ESP8266
  espSerial.listen();
  while (espSerial.available()){
    Serial.print("ESP loop\n");      
    espSerial.readBytesUntil('\n', buffer, BUFFER_SIZE);

    if(strncmp(buffer, "+IPD,", 5)==0) {
      Serial.print("Nasel jsem +IPD\n");
      
      // Nacitani buffer podle tvaru: +IPD,ch,len:data
      sscanf(buffer+5, "%d,%d", &channel, &packet_len);   
      if (packet_len > 0) {
        pb = buffer+5;
        while(*pb!=':') pb++;
        pb++;
        
        //Spinani vystupu na zaklade prichozeho HTML kodu
        if (strncmp(pb, "GET /?v1on", 10) == 0) {          
          digitalWrite(11, HIGH);
          webserver(channel,t,l);
          Serial.print("Zarizeni na vystupu 1 ZAPNUTO\n");              
        } 
        
        if (strncmp(pb, "GET /?v1off", 11) == 0) {
          digitalWrite(11, LOW);
          webserver(channel,t,l);     
          Serial.print("Zarizeni na vystupu 1 VYPNUTO\n");         
        } 

        if (strncmp(pb, "GET /?v2on", 10) == 0) {          
          digitalWrite(2, HIGH);
          webserver(channel,t,l);
          Serial.print("Zarizeni na vystupu 2 ZAPNUTO\n");              
        } 
        
        if (strncmp(pb, "GET /?v2off", 11) == 0) {
          digitalWrite(2, LOW);
          webserver(channel,t,l);     
          Serial.print("Zarizeni na vystupu 2 VYPNUTO\n");         
        } 
        
        if (strncmp(pb, "GET / ", 6) == 0) {
          webserver(channel,t,l);             
        }    
      }
    }
  } 

  //Poslouchani na SIM900
  simSerial.listen();
  while (simSerial.available()){
    Serial.print("SIM900 loop\n");
    char symbBuffer = simSerial.read(); 
    if ('\r' == symbBuffer) {
      // Zobrazeni zvravy pro kontrolu
      Serial.print(strBuffer);
      Serial.print("\n");
      if (ifSms) {
        
        //Spinani vystupu na zaklade prichozi zpravy
        if (!strBuffer.compareTo("v1on")) {
          digitalWrite(11, HIGH);
          Serial.print("Zarizeni na vystupu 1 ZAPNUTO\n"); 
        } else if (!strBuffer.compareTo("v1off")) {
          digitalWrite(11, LOW);
          Serial.print("Zarizeni na vystupu 1 VYPNUTO\n"); 
        } else if (!strBuffer.compareTo("v2on")) {
          digitalWrite(2, HIGH);
          Serial.print("Zarizeni na vystupu 2 ZAPNUTO\n");
        } else if (!strBuffer.compareTo("v2off")) {
          digitalWrite(2, LOW);
          Serial.print("Zarizeni na vystupu 2 VYPNUTO\n");
        }
        ifSms = false;
      } else {
        // Je to SMS zprava?
        if (strBuffer.startsWith("+CMT")) {
          ifSms = true;
        }
      }
      strBuffer = "";
    } else if ('\n' != symbBuffer) {
      strBuffer += String(symbBuffer);
      Serial.print("Nasel jsem +CMT\n");
    } 
  }

  // Automaticke spinani vystupu 3 na zaklade osvetleni
  if (l < 12) 
  digitalWrite(3,HIGH);
  else digitalWrite(3,LOW);
  // Automaticke spinani vystupu 4 na zaklade teploty
  if (t < 23) 
  digitalWrite(4,HIGH);
  else digitalWrite(4,LOW);

}

void webserver(int channel, float t, uint16_t l ) {

  //Zacatek html kodu webove stranky
  String header;
  header =  "HTTP/1.1 200 OK\r\n";
  header += "Content-Type: text/html\r\n";
  header += "Connection: close\r\n";  
  String htmlCode;
  htmlCode = "<html><header><title>ESP8266</title></header>";
  htmlCode += "<h2><center><u>Web ovladani</u>";
  htmlCode += "Zasuvka 1: <a href=\"/?v1on\"><button>ON</button>";
  htmlCode += "<a href=\"/?v1off\"><button>OFF</button></a>";
  htmlCode += "<p>Zasuvka 2: <a href=\"/?v2on\"><button>ON</button>";
  htmlCode += "<a href=\"/?v2on\"><button>OFF</button></a>";
  htmlCode +="<p>Teplota:<p>";
  htmlCode +=t;
  htmlCode +=" C<p>Int. osveteni:<p>";
  htmlCode +=l;
  htmlCode += " lx</body></html>";
  //Konec html kodu webove stranky
  
  header += "Content-Length: ";
  header += (int)(htmlCode.length());
  header += "\r\n\r\n";

  //Preprava na odesilani dat pro ESP8266
  START_SENT: 
  espSerial.print("AT+CIPSEND="); 
  espSerial.print(channel);
  espSerial.print(",");
  espSerial.println(header.length()+htmlCode.length());

  //zozbrazeni pro kontrolu v Serial
  Serial.print("AT+CIPSEND=");
  Serial.print(channel);
  Serial.print(",");
  Serial.println(header.length()+htmlCode.length()); 
  delay(10);                                       

  //odesilani data na ESP8266
  if (espSerial.find(">")) {
    espSerial.print(header);
    espSerial.print(htmlCode);
    delay(10);     
  } 

  clearBufferArray();

}

// Vycisteni buffer
void clearBufferArray(void) {
  for (int i = 0;i<BUFFER_SIZE;i++ ) {
    buffer[i]=0;
  }
}

// Metoda pro UART komunikace
String dataExchange(String at, SoftwareSerial modul, const int delay, boolean debug)
{
  String answer = "";
  modul.print(at);
  long int time = millis();
  while((time + delay) > millis())
  {while(modul.available())
    {
      char c=modul.read();
      answer+=c;
    }
  }
  if (debug)
  {
    Serial.print(answer);
  }
  return answer;
}
