/* CCs

The following code is based on the work of the following people.

MeshTastic:
https://meshtastic.org/docs/getting-started/

SGP30:
AdaFruit example code - https://learn.adafruit.com/adafruit-sgp30-gas-tvoc-eco2-mox-sensor/arduino-code

SCD30:
AdaFruit example code from Arduino IDE

OLED Screen:
Rui Santos : https://randomnerdtutorials.com/esp32-ssd1306-oled-display-arduino-ide/

LED:
FastLED example code from Arduino IDE

VMA320
Code from here : https://learn.adafruit.com/thermistor/using-a-thermistor

Some debugging was done with ChatGPT

Code arrangement by me: Patrick Dezséri

*/

/*

//Basic Library
#include <arduino.h>

#define RX_PIN 44 //RX Pin of your controller that will send the data to the MeshTastic Node
#define TX_PIN 43 //TX Pin of your controller that will send the data to the MeshTastic Node

// Math library
#include <math.h>

// I2C Communication
#include <Wire.h>


// VMA320 - TempSensor
void VMA320(int); //Temperature Sensor, Pin required, To measure temperature
float VMS320_T;
#define VMA320_PIN A0

// SGP30 - CO2 Sensor
#include "Adafruit_SGP30.h"
Adafruit_SGP30 sgp;
void SGP30_START(bool); //function to initialize the CO2 Sensor - SGP30
void SGP30_Sensor(); //CO2 Sensor - SGP30
float SGP30_TVOC;
float SGP30_CO2;
int counter = 0; // Counter for CO2 Sensor
uint32_t getAbsoluteHumidity(float, float); // Absolute humidity correction for CO2 Sensor

// I2C Scanner 
void I2C_Scan(); //I2C Scanner, no Pin required, To check I2C devices connected to the board


//LED
void BlinkLED(int time);

// ---------- Setup ----------
void setup() {
    Serial.begin(115200);     // USB for debug
    Serial1.begin(921600, SERIAL_8N1, RX_PIN, TX_PIN);    // UART for Meshtastic node

    Wire.begin(); // Initialize I2C communication

    pinMode(LED_BUILTIN, OUTPUT); // Set the built-in LED as output

    pinMode(VMA320_PIN, INPUT);   // Set the pin input for VMA320 Thermistor / Temp Sensor

    // Initialize the CO2 Sensor - SGP30
    SGP30_START(true);
}



// ---------- Loop ----------
void loop() {
    //I2C_Scan(); // Uncomment to scan I2C devices
  
    VMA320(VMA320_PIN);

    SGP30_Sensor();

    // UART to Node (Meshtastic)

    Serial1.println("");

    Serial1.print("T: ");
    Serial1.print(VMS320_T);
    Serial1.println(" °C");

    //Serial1.print("Humidity: ");
    //Serial1.print();
    //Serial1.println(" %");

    Serial1.print("Co2: ");
    Serial1.print(SGP30_CO2);
    Serial1.println(" ppm");

    Serial1.print("TVOC: ");
    Serial1.print(SGP30_TVOC);
    Serial1.println(" ppb");
    

    BlinkLED(1500);
    delay(5000);
}



// ---------- Function definitions ----------

// ---------- CO2 Sensor - Sensirion SGP30 eCO2 & TVOC Sensor
void SGP30_START(bool initialize){
    if (!initialize) return;  // If false, exit function
  
    // Initialize I2C communication for the SGP30
    Serial.println("SGP30 test");
  
    if (! sgp.begin()){
      Serial.println("Sensor not found :(");
      while (1);
    }
    Serial.print("Found SGP30 serial #");
    Serial.print(sgp.serialnumber[0], HEX);
    Serial.print(sgp.serialnumber[1], HEX);
    Serial.println(sgp.serialnumber[2], HEX);
    // If you have a baseline measurement from before you can assign it to start, to 'self-calibrate'
    //sgp.setIAQBaseline(0x8E68, 0x8F41);  // Will vary for each sensor!
  }
  
  // return absolute humidity [mg/m^3] with approximation formula
  // @param temperature [°C]
  // @param humidity [%RH]
  //
  
  
  uint32_t getAbsoluteHumidity(float temperature, float humidity) {
    // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
    const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
    const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
    return absoluteHumidityScaled;
  }
  
  
  void SGP30_Sensor(){
    // If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humidity compensation for the air quality signals
    //float temperature = 22.1; // [°C]
    //float humidity = 45.2; // [%RH]
    //sgp.setHumidity(getAbsoluteHumidity(temperature, humidity));
  
    
    if (! sgp.IAQmeasure()) {
      Serial.println("Measurement failed");
      //return;
    }
    
   
    Serial.print("TVOC "); 
    //SGP30_TVOC = sgp.TVOC;
    SGP30_TVOC = round(sgp.TVOC * 10.0) / 10.0;
    Serial.print(SGP30_TVOC); 
    Serial.print(" ppb\t");
  
    Serial.print("eCO2 ");
    //SGP30_eCO2 = sgp.eCO2;
    SGP30_CO2 = round(sgp.eCO2 * 10.0) / 10.0;
    Serial.print(SGP30_CO2); 
    Serial.println(" ppm");
  
    
    if (! sgp.IAQmeasureRaw()) {
      Serial.println("Raw Measurement failed");
      //return;
    }
    Serial.print("Raw H2 "); 
    Serial.print(sgp.rawH2); 
    Serial.print(" \t");
  
    Serial.print("Raw Ethanol "); 
    Serial.print(sgp.rawEthanol); 
    Serial.println("");
   

    delay(1000);
    
  
    
    counter++;
    if (counter == 30) {
      counter = 0;
  
      uint16_t TVOC_base, eCO2_base;
      if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
        Serial.println("Failed to get baseline readings");
        return;
      }
      Serial.print("****Baseline values: eCO2: 0x"); 
      Serial.print(eCO2_base, HEX);
  
      Serial.print(" & TVOC: 0x"); 
      Serial.println(TVOC_base, HEX);
    }
    
     
    //Code modified from Adafruit SGP30 example
}



// ---------- Temperature Sensor - VMA 320
void VMA320(int pin){
    float reading;

    // The beta coefficient of the thermistor (usually 3000-4000)
    #define BCOEFFICIENT 3950
    // the value of the 'other' resistor
    #define SERIESRESISTOR 10000     
    // resistance at 25 degrees C
    #define THERMISTORNOMINAL 10000      
    // temp. for nominal resistance (almost always 25 C)
    #define TEMPERATURENOMINAL 25 

    reading  = analogRead(pin);

    reading = 4095 / reading - 1;
    reading = SERIESRESISTOR / reading;
    //Serial.print("Thermistor resistance "); 
    //Serial.println(reading);
    
    float steinhart;
    steinhart = reading / THERMISTORNOMINAL;     // (R/Ro)
    steinhart = log(steinhart);                  // ln(R/Ro)
    steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
    steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
    steinhart = 1.0 / steinhart;                 // Invert
    steinhart -= 273.15;                         // convert absolute temp to C
    
    
    //Serial.print("Temperature "); 
    //Serial.print(steinhart);
    //Serial.println(" *C");
    

    //VMS320_T = steinhart;
    VMS320_T = round(steinhart * 10.0) / 10.0;

    //Modified from: https://learn.adafruit.com/thermistor/using-a-thermistor
}


// ---------- Integrated LED Blinking
void BlinkLED(int time) {
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("ON");
    delay(time);
    digitalWrite(LED_BUILTIN, LOW);
    delay(time);
    Serial.println("OFF");
}
    
// ---------- I2C Scanner
void I2C_Scan() {
    byte error, address;
    int nDevices;
    Serial.println("Scanning...");
    nDevices = 0;
    for(address = 1; address < 127; address++ ) {
        Wire.beginTransmission(address);
        error = Wire.endTransmission();
        if (error == 0) {
        Serial.print("I2C device found at address 0x");
        if (address<16) {
            Serial.print("0");
        }
        Serial.println(address,HEX);
        nDevices++;
        }
        else if (error==4) {
        Serial.print("Unknown error at address 0x");
        if (address<16) {
            Serial.print("0");
        }
        Serial.println(address,HEX);
        }    
    }
    if (nDevices == 0) {
        Serial.println("No I2C devices found\n");
    }
    else {
        Serial.println("done\n");
    }
    delay(5000);          
}

//*/