#include <Arduino.h>
#include "MHZ19.h"
#include "Adafruit_AHTX0.h"
#include "LiquidCrystal_I2C.h"

#define RX_PIN 16                                          // Rx pin which the MHZ19 Tx pin is attached to
#define TX_PIN 17                                          // Tx pin which the MHZ19 Rx pin is attached to
#define BAUDRATE 9600                                      // Device to MH-Z19 Serial baudrate (should not be changed)

MHZ19 myMHZ19;                                             // Constructor for library
Adafruit_AHTX0 aht;
LiquidCrystal_I2C LCD(0x27,2,1,0,4,5,6,7,3,POSITIVE);

int greenpin = 25;
int yellownpin = 33;
int redpin = 32;

int backlightState = HIGH;
int backlightUpdate = 0;

int update_ival = 0;
int override = 0;

int cal_time = 5; //minutes

void led(int red, int green, int yellow)
{
    analogWrite(redpin, red);
    analogWrite(greenpin, green);
    analogWrite(yellownpin, yellow);
}

void IRAM_ATTR BacklightToggle() {
    backlightUpdate = true;
}

void setup()
{
    Serial.begin(9600);                                     // Device to serial monitor feedback

    Serial2.begin(BAUDRATE, SERIAL_8N1, RX_PIN, TX_PIN);                               // (Uno example) device to MH-Z19 serial start
    myMHZ19.begin(Serial2);                                // *Serial(Stream) refence must be passed to library begin().

    myMHZ19.autoCalibration();                              // Turn auto calibration ON (OFF autoCalibration(false))
    myMHZ19.setRange(2000);

    Serial.println("MHZ19 init:");
    char myVersion[4];
    myMHZ19.getVersion(myVersion);
    Serial.print("\nFirmware Version: ");
    for(byte i = 0; i < 4; i++)
    {
        Serial.print(myVersion[i]);
        if(i == 1)
            Serial.print(".");
    }
    Serial.println("");

    Serial.print("Range: ");
    Serial.println(myMHZ19.getRange());
    Serial.print("Background CO2: ");
    Serial.println(myMHZ19.getBackgroundCO2());
    Serial.print("Temperature Cal: ");
    Serial.println(myMHZ19.getTempAdjustment());
    Serial.print("ABC Status: "); myMHZ19.getABC() ? Serial.println("ON") :  Serial.println("OFF");

    if (!aht.begin()) {
        Serial.println("Could not find AHT? Check wiring");
        while (true);
    }

    LCD.begin(16, 2);
    LCD.clear();
    LCD.setBacklight(backlightState);
    pinMode(23, INPUT_PULLUP);
    attachInterrupt(23, BacklightToggle, FALLING);
}

void loop() {
    if (backlightUpdate) {
        backlightState = !backlightState;
        backlightUpdate = false;
        Serial.printf("Setting backlight to %i \n", backlightState);
        LCD.setBacklight(backlightState);
    }

    if (update_ival-- > 0) {
        delay(1000);
        return;
    }

    update_ival = 5; //5sec

    sensors_event_t humidity, temp;
    aht.getEvent(&humidity, &temp);
    LCD.setCursor(0, 0);
    LCD.print(temp.temperature, 1);
    LCD.print(" C   ");
    LCD.setCursor(9, 0);
    LCD.print(humidity.relative_humidity, 1);
    LCD.print("%rH");

    if (millis() >= (cal_time * 60000) && !override) {
        LCD.setCursor(0, 1);
        LCD.print("          Ready.");
        override = true;
    }

    int co2 = myMHZ19.getCO2(false);
    if (myMHZ19.errorCode != RESULT_OK) {
        Serial.print("Error. Response Code: ");
        Serial.println(myMHZ19.errorCode);          // Get the Error Code value
        return;
    }
    LCD.setCursor(0, 1);
    LCD.print(co2);
    LCD.print("ppm   ");

    if (co2 < 1000)
        led(0, 1, 0);
    else if (co2 < 1500)
        led(0, 0, 5);
    else
        led(5, 0, 0);

    if (millis() < (cal_time * 60000)) {
        {
            LCD.setCursor(8, 1);
            LCD.printf("Cal..%2lum", ((cal_time * 60000) - millis()) / 60000);
        }
    }
}