#include <LGPS.h>
#include <LGPRS.h>
#include <LGPRSClient.h>
#include <LGPRSServer.h>
#include <LGPRSUdp.h>            ////gprs hearders-----------
#include <TH02_dev.h>
#include <math.h>
#include <LDateTime.h>
#include <Wire.h>
#include "MutichannelGasSensor.h"
#include "Arduino.h"
#include "Wire.h" 
#include <LTask.h>
#include "Barometer.h"
#include <LFlash.h>
#include <LSD.h>
#include <LStorage.h>
#define Drv LSD
#define DEBUG 0
datetimeInfo t;

                                                                                 // These are the variables you will want to change based on your IOT data streaming account / provider
char action[] = "POST ";  // Edit to build your command - "GET ", "POST ", "HEAD ", "OPTIONS " - note trailing space
char server[] = "45.33.61.122";
char path[] = "/openenv/v1/upload.php";  // Edit Path to include you source key
int port = 80; // HTTP
int num;                            // part of the length calculation
String le;
LGPRSClient globalClient;

int pin = 8;
int val;
unsigned char dataRevice[9];
int temperature_CO2;
int CO2PPM;
const unsigned char cmd_get_sensor[] = 
{
    0xff, 0x01, 0x86, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x79
};
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000;//sampe 30s ;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;

unsigned int rtc;
int rtime;
unsigned long ruvsum;
float concentration_dust = 0;
float ro2perc;
float rno2;
float rnh3;
float rco;
float rdust;
int rco2;
String Srco2;
float pressure;
float atm;
float altitude;
Barometer myBarometer;
int rPressBaro;
String SrPressBaro;
int rAltBaro;
String SrAltBaro;
  
int  rloud;
String Srloud;
String Srtime;
String Sruvsum;
String Sro2perc;
String Srnh3;
String Srco;
String Srno2;
String Sfinal;
String temhum;
String Srtemhum;
String Srdust;
String comp;
int gps_on=0;

int time();
unsigned long UV_sensor();
float O2_sensor();
String Temp_sensor();
float Dust_sensor();
int CO2_sensor();
int  loudness_sensor();

void setup()
{
  // put your setup code here, to run once:
 Serial1.begin(9600);
 Serial.begin(115200);
 Serial.println("****TH02_dev demo by seeed studio****\n");
  /* Power up,delay 150ms,until voltage is stable */
  delay(150);
  /* Reset HP20x_dev */
  TH02.begin();
 
  delay(100);
  myBarometer.init();
  /* Determine TH02_dev is available or not */
  Serial.println("TH02_dev is available.\n");
  Serial.println("power on!");
 //  Drv.begin();

    mutichannelGasSensor.begin(0x04); //the default I2C address of the slave is 0x04
    while(mutichannelGasSensor.readR0() < 0)
    {
        Serial.println("sensors init error!!");
        delay(1000);
    }
     mutichannelGasSensor.powerOn();
  Serial.println("Attach to GPRS network");   // Attach to GPRS network - need to add timeout
  while (!LGPRS.attachGPRS("www","","")) { //attachGPRS(const char *apn, const char *username, const char *password);
    delay(500);
  }
  LGPRSClient client;    //Client has to be initiated after GPRS is established with the correct APN settings - see above link
  globalClient = client;  // Again this is a temporary solution described in support forums

}

void loop()
{
  
  rtime=time();
  Srtime=String(rtime);// RTC string
  
  ruvsum=UV_sensor();
  Sruvsum=String(ruvsum);//UV Sum string
  
  ro2perc=O2_sensor();// o2 perc
  Sro2perc=String (ro2perc);
  
  Sfinal=MultiGas_sensor();
  
  Srtemhum=Temp_sensor();
  
  rdust=Dust_sensor();
  Srdust=String(rdust);
  
  rco2=CO2_sensor();
  Srco2=String(rco2);
  
  rloud=loudness_sensor();
  Srloud=String(rloud);
  
  rloud=loudness_sensor();
  Srloud=String(rloud);
  rPressBaro = PressBaro();
  SrPressBaro = String(rPressBaro);
  rAltBaro = AltBaro();
  SrAltBaro = String(rAltBaro);

  comp= "{ \"time\": " +Srtime+","+"\"carbon_di_oxide\":"+ Srco2 +","+"\"altitude\":"+ SrAltBaro+","+"\"pressure\":"+ SrPressBaro+","+"\"loudness\":"+ Srloud +","+ "\"uv_data\":"+ Sruvsum +","+ " \"o2percentage\": " + Sro2perc +","+ "\"multichannel_nh3_co_no2\": " +"["+ Sfinal +"]"+","+ "\"temp_humidity\": "+"[" + Srtemhum +"]"+","+ "\"dust\": " + Srdust + ","+"\"device_id\":"+"\"EMK_2\" }";
  Serial.println(comp);

 /* LFile dataFile = Drv.open("datalog.txt", FILE_WRITE);
  if (dataFile) 
  {
    dataFile.println(comp);
    dataFile.close();
    // print to the serial port too:
   // Serial.println(comp);
  }
  // if the file isn't open, pop up an error:
  else 
  {
    Serial.println("error opening datalog.txt");
  }
  */
  //----------------------------------------------------gprs code
 
  if (globalClient.available()) {// if there are incoming bytes available from the server
    char c = globalClient.read();   // read them and print them:
    Serial.print(c);
  } 
  
 // var= "{\"value\":""}"; //Build the JSON packet without GPS info
  num=comp.length();               // How long is the payload
    le=String(num);                 //this is to calcule the length of var
    Serial.print("Connect to ");    // For the console - show you are connecting
    Serial.println(server);
    
    if (globalClient.connect(server, port)){  // if you get a connection, report back via serial:
      Serial.println("connected");  // Console monitoring
      Serial.print(action);                   // These commands build a JSON request for Ubidots but fairly standard
      Serial.print(path);                     // specs for this command here
      Serial.println(" HTTP/1.1");
      Serial.println(F("Content-Type: application/json"));
      Serial.print(F("Content-Length: "));
      Serial.println(le);
   //   Serial.print(F("X-Auth-Token: "));
    //  Serial.println(token);
      Serial.print(F("Host: "));
      Serial.println(server);
      Serial.println();
      Serial.println(comp);  // The payload defined above
      Serial.println();
      Serial.println((char)26); //This terminates the JSON SEND with a carriage return
      globalClient.print(action);                   // These commands build a JSON request for Ubidots but fairly standard
      globalClient.print(path);                     // specs for this command here:
      globalClient.println(" HTTP/1.1");
      globalClient.println(F("Content-Type: application/json"));
      globalClient.print(F("Content-Length: "));
      globalClient.println(le);
      //globalClient.print(F("X-Auth-Token: "));
     // globalClient.println(token);
      globalClient.print(F("Host: "));
      globalClient.println(server);
      globalClient.println();
      globalClient.println(comp);  // The payload defined above
      globalClient.println();
      globalClient.println((char)26); //This terminates the JSON SEND with a carriage return
      
    }
    
    //gps sync--------------------
 if ((gps_on != 1) && (t.year < 2010))
 {
 Serial.println("Using GPS to sync GMT. Please wait...");
 LGPS.powerOn();
 gps_on = 1;
 }
 //Wait one second before getting new time.
 delay(1000);

}

int  time() 
{
  LDateTime.getTime(&t);
  LDateTime.getRtc(&rtc);
  delay(1000);
  return(rtc);

}

unsigned long UV_sensor()
{
  int sensorValue;
  long  sum=0;
  unsigned long uvsum;
  
 for(int i=0;i<1024;i++)
   {  
      sensorValue=analogRead(A0);
      sum=sensorValue+sum;
      delay(2);
   }   
 sum = sum >> 10;
 uvsum=(sum*4980.0/1023.0);

 return (uvsum);
}

float O2_sensor()
{

float WarningValue= 19.5;  //The minimum sate concentration of O2 in air  
float sensorValue;
float sensorVoltage; 
float Value_O2;
sensorValue = analogRead(A1);
sensorVoltage =(sensorValue/1024)*5.0;
sensorVoltage = sensorVoltage/201*10000;
Value_O2 = sensorVoltage/5.43;

return (Value_O2);

}
String MultiGas_sensor()
{
    String final;
    mutichannelGasSensor.readR();
    mutichannelGasSensor.calcGas();
    rnh3=mutichannelGasSensor.density_nh3;
    rco=mutichannelGasSensor.density_co;
    rno2=mutichannelGasSensor.density_no2;
    Srnh3=String(rnh3);
    Srco=String(rco);
    Srno2=String(rno2);
    final =Srnh3 + ","+Srco +"," +Srno2;
    return(final);

}
String Temp_sensor()
{
   float temper = TH02.ReadTemperature(); 
   float humidity = TH02.ReadHumidity();
   
   temhum=String(temper)+ "," + String(humidity);
   return(temhum);
  
}
float Dust_sensor()
{
  duration = pulseIn(pin, LOW);
  lowpulseoccupancy = lowpulseoccupancy+duration;

  if ((millis()-starttime) > sampletime_ms)//if the sampel time == 30s
  {
    ratio = lowpulseoccupancy/(sampletime_ms*10.0);  // Integer percentage 0=>100
    concentration_dust = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
    lowpulseoccupancy = 0;
    starttime = millis();
    return(concentration_dust);
  }
}
int CO2_sensor()
{
  if(dataRecieve())
  {
    return (CO2PPM);
  }
  delay(100);
}

bool dataRecieve(void)
{
  byte data[9];
  int i = 0;
  
  //transmit command data
  for(i=0; i<sizeof(cmd_get_sensor); i++)
  {
    Serial1.write(cmd_get_sensor[i]);
  }
  delay(100);
  //begin reveiceing data
  if(Serial1.available())
  {
    while(Serial1.available())
    {
      for(int i=0;i<9; i++)
      {
        data[i] = Serial1.read();
      }
    }
  }
  
  #if DEBUG
  for(int j=0; j<9; j++)
  {
    Serial.print(data[j]);
    Serial.print(" ");    
  }
  Serial.println("");
  #endif
  
  if((i != 9) || (1 + (0xFF ^ (byte)(data[1] + data[2] + data[3] 
    + data[4] + data[5] + data[6] + data[7]))) != data[8])
  {
    return false;
  }
  CO2PPM = (int)data[2] * 256 + (int)data[3];
  temperature_CO2 = (int)data[4] - 40;  
  delay(1000);
  return true;
}
int  loudness_sensor()
{
	analogRead(A2);
        val = analogRead(A2);
        return(val);
    
}
int PressBaro()
{
pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP());//Get the temperature
  return(pressure); //whole number only.  delay(1000);
}
int AltBaro()
{
altitude = myBarometer.calcAltitude(pressure); //Uncompensated caculation - in Meters
  return(altitude);
  delay(1000);
}