// ###############    senzory ovzdusi verze 2     ########################
#include <Wire.h>    // I2C library
#include "Adafruit_CCS811.h"  // CCS811 library
#include <Adafruit_Sensor.h> // knihovna na senzory 
#include <Adafruit_BMP280.h> //senzor tlaku, teploty, nadmorske vysky
#include "ClosedCube_HDC1080.h" // senzor teploty, vlhkosti
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <NTPClient.h> // knihovna pro komunikaci s NTP servery
#include <WiFiUdp.h> // pomocna knihovna pro NTP
#include <Timestamps.h> // prevadi cas na epoch time
#include <TimeLib.h> //pomocna knihovna na cas
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
//#########################################################################

//definice promennych
const char *ssid     = "xxxxxxx";
const char *password = "cccccccc";
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "0.cz.pool.ntp.org");
Timestamps ts(3600);

//####################  CCS811 #######################
// Wiring for ESP8266 NodeMCU boards: VDD to 3V3, GND to GND, SDA to D2, SCL to D1, nWAKE to D3 (or GND)
Adafruit_CCS811 ccs;

//#######################  BMP280  ################
#define BMP280_ADRESA (0x76)
Adafruit_BMP280 bmp;
// konstanta s korekcí měření v hPa
int korekce = 32;
 /*
 https://www.chmi.cz/aktualni-situace/aktualni-stav-pocasi/ceska-republika/stanice/profesionalni-stanice/prehled-stanic/praha-karlov?l=en
 29.92 inHg = 1.0 atm = 101325 Pa = 1013.25 mb
*/

//############## HDC1080 ########################
ClosedCube_HDC1080 hdc1080;
//###########################################

// ### definice pro MySQL ####
IPAddress server_addr(192,168,88,210);
char mysqluser[] = "sssssss";
char mysqlpassword[] = "dddddddd";
WiFiClient client;
MySQL_Connection conn((Client *)&client);
//##########################################

//############# S E T U P #######################
void setup() {
  // Enable serial
  Serial.begin(115200);
  delay(500);
  Serial.println("");
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
Serial.println("");
  Serial.println("WiFi se pripojuje");
  Serial.println("IP adresa: ");
  Serial.println(WiFi.localIP()); 
   Serial.print("pripojuji se do SQL...  ");
  if (conn.connect(server_addr, 3306, mysqluser, mysqlpassword))
    Serial.println("OK.");
  else
    Serial.println("CHYBA."); 
      
  // Enable I2C
  Serial.println("Start I2C komunikace");
  Wire.begin(); 
  if(!ccs.begin()){
    Serial.println("Senzor CCS811 nenalezen. Zkontroluj zapojeni!");
    while(1);
  }
  while(!ccs.available());

}

//####### L O O P ##############################
void loop() {
  bmp280(); //pripravime mereni tlaku, teploty, nadmorske vysky
  delay(500);
  hdc180(); // zmerime teplotu, vlhkost
  delay(500);
  // Read
  senzorCCS811(); //nacteme smrady v ovzdusi
  cas(); //zjistime presny cas
  datadodatabase(); //odesleme to do databaze
  // Wait
  delay(1000*60*5); //delay 5 minut 
}

//############################ CCS811 ##############################
void senzorCCS811(){
 if(ccs.available()){
  float teplota = bmp.readTemperature();
  float vlhkost = hdc1080.readHumidity();
    ccs.setEnvironmentalData(vlhkost,teplota);
    if(!ccs.readData()){
      Serial.print("CO2: ");
      Serial.print(ccs.geteCO2());
      int co2 = ccs.geteCO2();
      Serial.print("ppm, TVOC: ");
      Serial.println(ccs.getTVOC());
      int tovc = ccs.getTVOC();
    }
    else{
      Serial.println("ERROR!");
      while(1);
    }
 }
 
}  
//############################ BMP280 ##############################
void bmp280(){
  if (!bmp.begin(BMP280_ADRESA)) {
    Serial.println("BMP280 senzor nenalezen, zkontroluj zapojeni!");
    while (1);
  }
  // načtení naměřené teploty ze senzoru
  float teplota = bmp.readTemperature();
  // načtení naměřeného tlaku ze senzoru
  float tlak = (bmp.readPressure()/100.00) + korekce;
  // výpis všech dostupných informací ze senzoru BMP
  // výpis teploty
  Serial.print("Teplota: ");
  Serial.print(teplota);
  Serial.println(" stupnu Celsia.");
  // výpis barometrického tlaku v hekto Pascalech
  Serial.print("Barometricky tlak: ");
  Serial.print(tlak);
  Serial.println(" hPa");
}

//######################## HDC1080 #################################
void hdc180(){
hdc1080.begin(0x40);
Serial.print("T=");
  Serial.print(hdc1080.readTemperature());
  float teplota2 = hdc1080.readTemperature();
  Serial.print("C, RH=");
  Serial.print(hdc1080.readHumidity());
  float vlhkost = hdc1080.readHumidity();
  Serial.println("%");  
}

//##########################################################

void cas(){
timeClient.update();
unsigned long epochTime = timeClient.getEpochTime();
int currentHour = timeClient.getHours();
int currentMinute = timeClient.getMinutes();
int currentSecond = timeClient.getSeconds();
struct tm *ptm = gmtime ((time_t *)&epochTime); 
int monthDay = ptm->tm_mday;
int currentMonth = ptm->tm_mon+1;
int currentYear = ptm->tm_year+1900;
Serial.print("Aktualni cas je: ");
Serial.println(epochTime);
}

//#########################################################
void dejmicas(){
timeClient.update();

  unsigned long epochTime = timeClient.getEpochTime();
  Serial.print("Epoch Time: ");
  Serial.println(epochTime);
  
  
  String formattedTime = timeClient.getFormattedTime();
  Serial.print("Formatted Time: ");
  Serial.println(formattedTime);  

  int currentHour = timeClient.getHours();
  Serial.print("Hour: ");
  Serial.println(currentHour);  

  int currentMinute = timeClient.getMinutes();
  Serial.print("Minutes: ");
  Serial.println(currentMinute); 
   
  int currentSecond = timeClient.getSeconds();
  Serial.print("Seconds: ");
  Serial.println(currentSecond);  
  
  struct tm *ptm = gmtime ((time_t *)&epochTime); 

  int monthDay = ptm->tm_mday;
  Serial.print("Month day: ");
  Serial.println(monthDay);

  int currentMonth = ptm->tm_mon+1;
  Serial.print("Month: ");
  Serial.println(currentMonth);

  int currentYear = ptm->tm_year+1900;
  Serial.print("Year: ");
  Serial.println(currentYear);

  
  String currentDate = String(currentYear) + "-" + String(currentMonth) + "-" + String(monthDay);
  Serial.print("Current date: ");
  Serial.println(currentDate);
  Serial.println(ts.getTimestampUNIX((currentYear), (currentMonth), (monthDay), (currentHour), (currentMinute), (currentSecond)));
  }

//#############################################################
void datadodatabase(){
char query[162];
// char INSERT_SQL[] = "INSERT INTO balkon.archive (`dateTime`,`usUnits`,`interval`, 'co2', 'extraHumid2','appTemp1','extraHumid1','pressure','pm10_0','pm1_0','pm2_5' ) VALUES (epochtime,16,5,%co2,%teplota,%vlhkost,%tlak,%prach10,prach1,prach25)"; // s prachem
// char INSERT_DATA[] = "INSERT INTO test_arduino.hello_sensor (message, sensor_num, value) VALUES ('%s',%d,%s)";
Serial.println("Pripravuji data do databaze");

char INSERT_SQL[] = "INSERT INTO balkon.archive (`dateTime`, `usUnits`, `interval`, `co2`, `extraHumid2`, `appTemp1`, `extraHumid1`, `pressure`) VALUES (epochTime,16,5,co2,tovc,teplota,vlhkost,tlak)"; // bez mereni prachu
 // Initiate the query class instance
    MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
    //cursor = new MySQL_Cursor(&conn);
    // Save
    //dtostrf(50.125, 1, 1, temperature);
    //sprintf(query, INSERT_DATA, "test sensor", 24, temperature);
    // Execute the query
    //cursor->execute(INSERT_SQL);
    cur_mem->execute(INSERT_SQL);
    // Note: since there are no results, we do not need to read any data
    // Deleting the cursor also frees up memory used
    delete cur_mem;
    //delete cursor;
    Serial.println("Data recorded.");
}

//############################################################
void httpclient(){
/*const String endpoint = "http://api.openweathermap.org/data/2.5/weather?q=Lisbon,pt&APPID=";
const String key = "yourAPIkey";
http.begin(endpoint + key); //Specify the URL
    int httpCode = http.GET();  //Make the request
 
    if (httpCode > 0) { //Check for the returning code
 
        String payload = http.getString();
        Serial.println(httpCode);
        Serial.println(payload);}
 
    else {
      Serial.println("Error on HTTP request");
    }
 
    http.end(); //Free the resources
  }*/
  HTTPClient http;  //Declare an object of class HTTPClient
 
    http.begin("http://api.sunrise-sunset.org/json?lat=50.0874654&lng=14.4212535&formatted=0");  //Specify request destination
    int httpCode = http.GET();                                  //Send the request
 
    if (httpCode > 0) { //Check the returning code
 
      String payload = http.getString();   //Get the request response payload
      Serial.println(payload);             //Print the response payload
}
}

//############################################################

void printInfoSerial()
{
  //getCO2() gets the previously read data from the library
  /*Serial.println("CCS811 data:");
  Serial.print(" CO2 concentration : ");
  int co2 = myCCS811.getCO2();
  Serial.print(myCCS811.getCO2());
  Serial.println(" ppm");

  //getTVOC() gets the previously read data from the library
  Serial.print(" TVOC concentration : ");
  Serial.print(myCCS811.getTVOC());
  int tovc = myCCS811.getTVOC();
  Serial.println(" ppb");
*/
  Serial.println("BME280 data:");
  Serial.print(" Temperature: ");
  Serial.print(bmp.readTemperature(), 2);
  Serial.println(" degrees C");
/*
  Serial.print(" Temperature: ");
  Serial.print(myBME280.readTempF(), 2);
  Serial.println(" degrees F");
*/
  Serial.print(" Pressure: ");
  Serial.print(bmp.readPressure()/100.00) + korekce;
  Serial.println(" Pa");
/*
  Serial.print(" Pressure: ");
  Serial.print((myBME280.readFloatPressure() * 0.0002953), 2);
  Serial.println(" InHg");

  Serial.print(" Altitude: ");
  Serial.print(myBME280.readFloatAltitudeMeters(), 2);
  Serial.println("m");

  Serial.print(" Altitude: ");
  Serial.print(myBME280.readFloatAltitudeFeet(), 2);
  Serial.println("ft");
*/
  Serial.print(" %RH: ");
  Serial.print(hdc1080.readHumidity(), 2);
  Serial.println(" %");

  Serial.println();
}

//printSensorError gets, clears, then prints the errors
//saved within the error register.

//########################################################################
/*void printSensorError()
{
  uint8_t error = myCCS811.getErrorRegister();

  if (error == 0xFF) //comm error
  {
    Serial.println("Failed to get ERROR_ID register.");
  }
  else
  {
    Serial.print("Error: ");
    if (error & 1 << 5)
      Serial.print("HeaterSupply");
    if (error & 1 << 4)
      Serial.print("HeaterFault");
    if (error & 1 << 3)
      Serial.print("MaxResistance");
    if (error & 1 << 2)
      Serial.print("MeasModeInvalid");
    if (error & 1 << 1)
      Serial.print("ReadRegInvalid");
    if (error & 1 << 0)
      Serial.print("MsgInvalid");
    Serial.println();
  }
}*/
//########################################################################
/*void opakuj(){
  int vzdalenost = sonar.ping_cm();
  vzdalenost = 0;
    // pro získání stabilnějších výsledků provedeme 5 měření
    // a výsledky budeme přičítat do proměnné vzdalenost
    for(int i=0; i<5; i++) {
      vzdalenost += sonar.ping_cm();
      delay(50);
    }
    // v proměnné vzdálenost máme součet posledních 5 měření
    // a musíme tedy provést dělení 5 pro získání průměru
    vzdalenost = vzdalenost/5;
    // vytištění informací po sériové lince
    Serial.print("Vzdalenost mezi senzorem a predmetem je ");
    Serial.print(vzdalenost);
    Serial.println(" cm.");
 }
 */
