#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>

SoftwareSerial s_serial(2, 3);      // TX, RX
#define sensor s_serial

#define PIN            4
#define NUMPIXELS      8

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

//Construction of the instruction for the sensor
const unsigned char cmd_get_sensor[] =
{
    0xff, 0x01, 0x86, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x79
};

unsigned char dataRevice[9];
int temperature=0;
int CO2PPM=0;
int CO2PPMArray[120];
unsigned int avg10=0;
long avg60=0; //unsigned int is just big enough for an average of 60 values, we use a long variable to be safe
long avg120=0; //unsigned int is too small for an average of 120 values
int time=0;
int switchingLight=0;
int test;

void setup()
{
    sensor.begin(9600);
    Serial.begin(9600);
    Serial.println("Beginning to read from sensor!");
    Serial.println("********************************************************");
    Serial.println();

    pixels.begin(); //Initializes the NeoPixel library
    pixels.setPixelColor(0, pixels.Color(10,10,10));
    pixels.show();

    for(int i=0; i<100; i++) 
    {
      CO2PPMArray[i] = 0;
    }
}

void loop()
{
    if(dataRecieve())
    {
        Serial.print("Temperature: ");
        Serial.print(temperature);
        Serial.print("  CO2(PPM): ");
        Serial.print(CO2PPM);
        Serial.println("");

        CO2PPMArray[0]=CO2PPM;
          for (int i=119; i>0; i--)
          {
            CO2PPMArray[i] = CO2PPMArray[i-1];
          }

        pixels.setPixelColor(3, pixels.Color(0,0,10));
    }
    else
    {
        pixels.setPixelColor(3, pixels.Color(16,0,8));
    }

    average(CO2PPMArray, &avg10, &avg60, &avg120);
    
    Serial.print("Average of the last 10 CO2PPM values: ");
    Serial.println(avg10);
    
    Serial.print("Average of the last 60 CO2PPM values: ");
    Serial.println(avg60);
    
    Serial.print("Average of the last 120 CO2PPM values: ");
    Serial.println(avg120);
    
    if (switchingLight==0)
    {
        pixels.setPixelColor(1, pixels.Color(0,0,10));
    }
    else
    {
        pixels.setPixelColor(1, pixels.Color(0,0,0));
    }

    if(time<180)
    {
        time++;
        pixels.setPixelColor(2, pixels.Color(16,0,8));
        Serial.println("The sensor is not hot yet, the values may be incorrect!");
    }
    else
    {
        pixels.setPixelColor(2, pixels.Color(0,0,10));
        Serial.println("The sensor is hot, the values are correct!");
    }

    if (CO2PPM<1000)
    {
        pixels.setPixelColor(4, pixels.Color(0,10,0));
    }
    else if (CO2PPM>1500)
    {
        pixels.setPixelColor(4, pixels.Color(10,0,0));
    }
    
    else
    {
        pixels.setPixelColor(4, pixels.Color(13,5,0));
    }

    if (avg10<1000)
    {
        pixels.setPixelColor(5, pixels.Color(0,10,0));
    }
    else if (avg10>1500)
    {
        pixels.setPixelColor(5, pixels.Color(10,0,0));
    }
    
    else
    {
        pixels.setPixelColor(5, pixels.Color(13,5,0));
    }

    if (avg60<1000)
    {
        pixels.setPixelColor(6, pixels.Color(0,10,0));
    }
    else if (avg60>1500)
    {
        pixels.setPixelColor(6, pixels.Color(10,0,0));
    }
    
    else
    {
        pixels.setPixelColor(6, pixels.Color(13,5,0));
    }

    if (avg120<1000)
    {
        pixels.setPixelColor(7, pixels.Color(0,10,0));
    }
    else if (avg120>1500)
    {
        pixels.setPixelColor(7, pixels.Color(175,0,0));
    }
    
    else
    {
        pixels.setPixelColor(7, pixels.Color(65,25,0));
    }

    Serial.println("");
    pixels.show();
    delay(1000);
}

bool dataRecieve(void)
{
    byte data[9];
    int i=0;
    //transmit command data
    for(i=0; i<sizeof(cmd_get_sensor); i++)
    {
        sensor.write(cmd_get_sensor[i]);
    }
    Serial.flush();
    //begin reveiceing data
    if(sensor.available())
    {
        while(sensor.available())
        {
            for(int i=0;i<9; i++)
            {
                data[i] = sensor.read();
            }
        }
    }
 
    if((i != 9) || (1 + (0xFF ^ (byte)(data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]))) != data[8])
    {
        return false;
    }
    
    if (switchingLight==0)
    {
        switchingLight++;
    }
    else
    {
        switchingLight--;
    }

    CO2PPM = (int)data[2] * 256 + (int)data[3];
    temperature = (int)data[4] - 40;

    return true;
}

void average(int val[100], unsigned int *average10, long *average60, long *average120)
{
    for (int i = 0; i < 10; i++)
    {
        *average10+=val[i];
    }
    *average10=*average10/10;

    for (int i = 0; i < 60; i++)
    {
        *average60+=val[i];
    }
    *average60=*average60/60;

    for (int i = 0; i < 120; i++)
    {
        *average120+=val[i];
    }
    *average120=*average120/120;
}
