#include <Adafruit_GPS.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_10DOF.h>
#include <Adafruit_HTU21DF.h>
#include <Wire.h>
#define mySerial Serial1
#define GPSECHO  true


Adafruit_10DOF                dof   = Adafruit_10DOF();
Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(30301);
Adafruit_LSM303_Mag_Unified   mag   = Adafruit_LSM303_Mag_Unified(30302);
Adafruit_BMP085_Unified       bmp   = Adafruit_BMP085_Unified(18001);
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
Adafruit_GPS GPS(&mySerial);

char gpstext[ ] = "";
String gpstalk;
String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete
String lastgpsread;
int energy1 = random(10000, 20000);
int energy2 = random(10050, 19950);
int deviceid = random(1, 10000);
float temperature;
double temperatureh=0;
double humidity = 0;
double baroaltitude = 0;
double accelx = 0;
double accely = 0;
double accelz = 0;
double magx = 0;
double magy = 0;
double magz = 0;



int exacttime =0;
int uptime = 0;


/* Update this with the correct SLP for accurate altitude measurements */
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;


void setup()  
{

  initSensors();
  
  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  Serial.begin(115200);


  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
  mySerial.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  delay(1000);
  Serial.println("GPS online");
  inputString.reserve(200);

}

void loop()                     // run over and over again
{
  if (stringComplete) {
    lastgpsread = inputString;
    lastgpsread.trim();
    //Serial.println(inputString); 
    // clear the string:
    inputString = "";
    stringComplete = false;
  }

  
  sensorreadout();
  printdatajson();
  delay(100);
}

void printdatajson()
{
    //start the data output on in json format
  Serial.print("{ ");
  Serial.print("    \"gps\":");
  Serial.print("      \"");
  Serial.print(lastgpsread);
  Serial.print("\"");
  Serial.print("    ,");
  
 
  Serial.print("    \"timing\": ");
  Serial.print(exacttime);
  Serial.print(','); 
  
  Serial.print("    \"energy\": {");
  Serial.print("      \"channel1\": ");
  Serial.print(energy1);
  Serial.print(',');
  Serial.print("      \"channel2\": ");
  Serial.print(energy2);
  Serial.print("    },");
 
  Serial.print("    \"altitude\": "); 
  Serial.print(baroaltitude); 
  Serial.print(",");
 
  Serial.print("    \"humidity\": "); 
  Serial.print(humidity);
  Serial.print(",");
 
  Serial.print("    \"gravitationalOrientation\": {"); 
  Serial.print("     \"x\": ");
  Serial.print(accelx);
  Serial.print(",");
  Serial.print("     \"y\": ");
  Serial.print(accely);
  Serial.print(",");
  Serial.print("     \"z\": ");
  Serial.print(accelz);
  Serial.print("    },");  
 
  Serial.print("    \"magneticOrientation\": {"); 
  Serial.print("     \"x\": ");
  Serial.print(magx);
  Serial.print(",");
  Serial.print("     \"y\": ");
  Serial.print(magy);
  Serial.print(",");
  Serial.print("     \"z\": ");
  Serial.print(magz);
  Serial.print("    },");
 
  Serial.print("    \"temperature\": {"); 
  Serial.print("     \"value1\": ");
  Serial.print(temperatureh); //val1 is from the humidity sensor
  Serial.print(",");
  Serial.print("     \"value2\": ");
  Serial.print(temperature);
  Serial.print("    },");
 
  Serial.print("    \"uptime\": "); 
  Serial.print(uptime);
  Serial.print(",");
  
  Serial.print("    \"id\": "); 
  Serial.print(deviceid);
  Serial.println("}");
}

void serialEvent1() {
  while (Serial1.available()) {
    // get the new byte:
    char inChar = (char)Serial1.read(); 
    // add it to the inputString:
    if (inChar != char(10))
    {
      inputString += inChar;
    }
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    } 
  }
}

void serialEventRun(void)
{
  if (Serial1.available()) 
          serialEvent1();
}

void initSensors()
{
  if (!accel.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println(F("Ooops, no LSM303 detected ... Check your wiring!"));
    while (1);
  }
  if (!mag.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
    while (1);
  }
  if (!bmp.begin())
  {
    /* There was a problem detecting the BMP180 ... check your connections */
    Serial.println("Ooops, no BMP180 detected ... Check your wiring!");
    while (1);
  }
  if (!htu.begin()) {
    Serial.println("Couldn't find HTU21DF sensor!");
    while (1);
  }
}


void sensorreadout()
{
  sensors_event_t accel_event;
  sensors_event_t mag_event;
  sensors_event_t bmp_event;
  sensors_vec_t   orientation;

  /* Calculate pitch and roll from the raw accelerometer data */
  accel.getEvent(&accel_event);
  if (dof.accelGetOrientation(&accel_event, &orientation))
  {
    accelx = (accel_event.acceleration.x);
    accely = (accel_event.acceleration.y);
    accelz = (accel_event.acceleration.z);

  }

  /* Calculate the heading using the magnetometer */
  mag.getEvent(&mag_event);
  if (dof.magGetOrientation(SENSOR_AXIS_Z, &mag_event, &orientation))
  {
    magx = (mag_event.magnetic.x);
    magy = (mag_event.magnetic.y);
    magz = (mag_event.magnetic.z);
  }

  /* Calculate the altitude using the barometric pressure sensor */
  bmp.getEvent(&bmp_event);
  if (bmp_event.pressure)
  {
    /* Get ambient temperature in C */
    bmp.getTemperature(&temperature);
    /* Convert atmospheric pressure, SLP and temp to altitude    */
    baroaltitude = (bmp.pressureToAltitude(seaLevelPressure,bmp_event.pressure,temperature));
    
    temperatureh = (htu.readTemperature());
    humidity = (htu.readHumidity());
  }

  exacttime++;
  energy1= energy1 + random(-100,100);
  energy2= energy2 + random(-100,100);
  uptime++;

}


