#include <Adafruit_VEML6070.h>
#include <Adafruit_Si7021.h>
#include <Adafruit_CCS811.h>
#include <Wire.h>

//Hardware//
enum HARDWARE{		
	I2C_SDA = 18,
	i2c_SCL = 19,
	
	DUST_PIN = 23,
	
	LED_BLUE_EXTRA = 13,
	LED_GREEN = 32,
	LED_RED = 1,
	LED_BLUE = 6,
 
};

uint8_t message_count = 0;
int data_points = 500;
int time_between_data = 10000;
float data[8][500];
int counting_up = 0;
bool want_data = false;

//Dust Sensor//
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000;//recomended sample time: 30s
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;

//sensor registors//
float dust_raw =0.0;
int UV_raw = 0;
int CO2_raw = 0;
int TVOC_raw = 0;
float CC_temp_raw = 0.0;
float si_temp_raw = 0.0;
float humidity_raw = 0.0;

//Class Instantiations//
Adafruit_CCS811 ccs;
Adafruit_Si7021 tempAndHumidity = Adafruit_Si7021();
Adafruit_VEML6070 uv = Adafruit_VEML6070();

void setup() {
	Serial.begin(9600);
	setup_hardware();
}

void loop() {
  update_sensor_data();

  if (counting_up < data_points) {
    data[0][counting_up] = millis();
    data[1][counting_up] = dust_raw;
    data[2][counting_up] = UV_raw;
    data[3][counting_up] = humidity_raw;
    data[4][counting_up] = si_temp_raw;
    data[5][counting_up] = CO2_raw;
    data[6][counting_up] = TVOC_raw;
    data[7][counting_up] = CC_temp_raw;
    counting_up++;
  }

  serial_calls();
  print_data();
  
  delay(time_between_data);
  
}

void setup_hardware(){
  
  //sensors//
  pinMode(HARDWARE::DUST_PIN, INPUT);		//set to read pulses from dust sensor
  starttime = millis();					//sets start time
  uv.begin(VEML6070_1_T);
  if (!ccs.begin())
    Serial.println("Sensor (CCS811) failed to be found.");
  if (!tempAndHumidity.begin())
    Serial.println("Sensor (Temperature & Humidity) failed to be found.");
  else
  ccs.begin();
  tempAndHumidity.begin();
  while(!ccs.available());
  float temp = ccs.calculateTemperature();
  ccs.setTempOffset(temp - 25.0);			//default temperature calibration
  
  //LEDs//
  pinMode(HARDWARE::LED_RED, OUTPUT);
  pinMode(HARDWARE::LED_GREEN, OUTPUT);
  pinMode(HARDWARE::LED_BLUE, OUTPUT);
  pinMode(HARDWARE::LED_BLUE_EXTRA, OUTPUT);
  digitalWrite(HARDWARE::LED_RED, HIGH);
  digitalWrite(HARDWARE::LED_GREEN, LOW);
  digitalWrite(HARDWARE::LED_BLUE, HIGH);
  digitalWrite(HARDWARE::LED_BLUE_EXTRA, LOW);
}

void update_sensor_data(){
  if(get_dust() > 1)
    dust_raw = concentration;
  get_humidity(humidity_raw);
  get_temperature(si_temp_raw);
  get_airQuality(CO2_raw,TVOC_raw,CC_temp_raw);
  get_UV(UV_raw);
}

float get_dust() {
  duration = pulseIn(HARDWARE::DUST_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 = (1000.0 / 283.0) * 1.1 * pow(ratio, 3) - 3.8 * pow(ratio, 2) + 520 * ratio + 0.62; // using spec sheet curve
    lowpulseoccupancy = 0;
    starttime = millis();
  }
  return concentration;
}

void get_humidity(float& humidity) {
  humidity = tempAndHumidity.readHumidity();
}

void get_temperature(float& si_temp) {
  si_temp = tempAndHumidity.readTemperature();
}

void get_UV(int & UV){
  UV = uv.readUV();  
}

void get_airQuality(int& CO2, int& TVOC, float& temp) {
  if (ccs.available() && !ccs.readData()) {
    CO2 = ccs.geteCO2();
    TVOC = ccs.getTVOC();
    temp = ccs.calculateTemperature();
  }
  else
    Serial.println("CCS811 reading failed");
}

void serial_calls() {
  if (Serial.available()) {
    char input = Serial.read();
    if (input == 'd')
      want_data = true;  
  }
}

void print_data() {
  if (want_data) {
    for(int i = 0; i < data_points; i++) {
       Serial.print("Time On: ");
       Serial.print(data[0][i]);
       Serial.print("    Dust: ");
       Serial.print(data[1][i]);
       Serial.print("pcs/L    UV: ");
       Serial.print(data[2][i]);
       Serial.print("    humidity: ");
       Serial.print(data[3][i]);
       Serial.print("    si_temperature: ");
       Serial.print(data[4][i]);
       Serial.print("C    CO2: ");
       Serial.print(data[5][i]);
       Serial.print("ppm    TVOC: ");
       Serial.print(data[6][i]);
       Serial.print("ppb    cc_temperature: ");
       Serial.println(data[7][i]);      
    }
    want_data = false;
  }
}
