/* Start of program:
Set the number of averages in line 94.
Autogain on the VEML7700 makes the time average variable.  See where the VEML is measured on line 107. 

The surface or sky temperature using the IR MLX90614 sensor (I2C).
The thermistor for air temperature measurement (analog).
The BME280 sensor will be used for pressure, temperature, and relative humidity. I2C.
The VEML7700 for solar radiation.  I2C.
INSTALL THE ADAFRUIT LIBRARIES FOR THE I2C sensors using the library manager under Sketch.

The chronodot is used for time and date.  Time has to be set, and check the batteries to see if they are good for backup. I2C.
The microSD card for saving data. SPI interface.
 */

#include <Wire.h> // For the Chronodot, IR sensor, and BME280.
#include <Adafruit_MLX90614.h> // for the IR sensor. 
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
#include <SPI.h>  // For the microSD.
#include <SD.h>   // For the microSD.
#include "Adafruit_VEML7700.h"
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

Adafruit_VEML7700 veml = Adafruit_VEML7700();
Adafruit_BME280 bme; // I2C

File mySensorData           ;  // Filename for the microSD writing of data.
 
// Global variable definitions. 
// Thermistor temperature sensor set up variables.
int sensorPin = A0;    // Analog input pin for the thermistor voltage.

// Chronodot variables for keeping time.
int seconds; //00-59;
int minutes; //00-59;
int hours;//1-12 - 00-23;
int days;     //  1-7 assuming Sunday is day 1.
int date;//01-31
int months;//01-12
int years;//0-99;

// We put out setup code here, to run only once at the start:
void setup() {
/***************** Write header for the top of the file and the serial port ********/        ;                                            ;
Serial.begin(9600) ;  // Sets the serial port to 9600 bits per second transfer.
Serial.println(F("endDate,endTime,IRGnd_C,Therm_C,S_W/m2,P_mb,T_C,RH_%"));
        
Wire.begin();         // For the chronodot and others
mlx.begin();          // IR sensor set up.

// CS pin used for the microSD card.
pinMode(10, OUTPUT) ;
// Check the microSD card.
SD.begin(10) ; // Initialize
if (!SD.begin(10)) {
}
// Write the variable information to the top of the file.
mySensorData = SD.open("header.csv", FILE_WRITE);//Open SD File, Append if the file is already exist
mySensorData.println("endDate,endTime,IRGnd_C,Therm_C,S_W/m2,P_mb,T_C,RH_%"); //the file header
mySensorData.close(); 

// VEML Set up. 
  if (!veml.begin()) {
    Serial.println("VEML Sensor not found");
    while (1);
  }
  Serial.println("VEML Sensor found");

unsigned status;
status = bme.begin();  
    // You can also pass in a Wire library object like &Wire2
    // status = bme.begin(0x76, &Wire2)
    /*
    if (!status) {
        Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
        Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
        Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
        Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
        Serial.print("        ID of 0x60 represents a BME 280.\n");
        Serial.print("        ID of 0x61 represents a BME 680.\n");
        while (1) delay(10);
    }
    
    delay(100) ;
    */


}  // End the set up loop here.


// We put our main code here, to run repeatedly:
void loop() {

int jmax=20                  ; // Number of points to average.  10 gives about 20 seconds.  

  // Initialize variables for time averaging.
  float alux=0.0            ; // VEML 7700. 
  float aT_BME280=0.0       ; 
  float aP_BME280=0.0       ; 
  float aRH_BME280=0.0      ; 
  float aTC=0.0             ; // Thermocouple. 
  float aIRtargetTemp=0.0   ; // IR sensor values. 

  for (int j=0 ; j < jmax; j++) {  // Do a time average of the data. The upper range of this loop is needed in line 129 below.  

  // to read lux using automatic method, specify VEML_LUX_AUTO. 
  float lux = veml.readLux(VEML_LUX_AUTO)*0.0079; // Watts/m2

// Read from the BME. 
  float T_BME280=bme.readTemperature()     ;
  float P_BME280=bme.readPressure()/100.0F  ;
  float RH_BME280=bme.readHumidity() ;

// First the thermistor temperature sensor measurement.
// *************************************************** // 
float TC = 0.0 ; // Initialize the temperature measurement for doing an average measurement.
float T  ; // Instantaneous value of temperature. 
for (int i=0 ; i < 200; i++) {
    float sensorValue = analogRead(sensorPin)*0.00488759; // Converts to voltage.
    TC += get_T_From_V(sensorValue) ;  // Converts voltage to temperature.
//    delay(delTime) ; 
} // loop over i, the thermistor temperature sensor measurements.
TC = TC/200.0 ; // Must be equal to the upper range of the for loop. 
// *************************************************** // 

// Next get the IR sensor data.
// float IRbodyTemp   = mlx.readAmbientTempC()  ;
float IRtargetTemp = mlx.readObjectTempC()   ;

  alux+=lux ; aT_BME280+=T_BME280 ; aP_BME280+=P_BME280 ; aRH_BME280+=RH_BME280 ; aTC+=TC ; aIRtargetTemp+=IRtargetTemp ;  // Initialize variables.
  } // For loop for averaging


float d=float(jmax)            ; // Set this to the number of data points averaged.
alux=alux/d                    ; 
aT_BME280=aT_BME280/d          ; 
aP_BME280=aP_BME280/d          ; 
aRH_BME280=aRH_BME280/d        ; 
aTC=aTC/d                      ; 
aIRtargetTemp=aIRtargetTemp/d  ;  


// Get time and date from the Chronodot.
get_date();  // 
get_time();  // 

/************ Write the data to the serial port to look at it. *****************/
digitalClockDisplay()          ; /* Writes the time and date from the RTC to the Serial port */
Serial.print(aIRtargetTemp,3)   ; Serial.print(F(",")) ;
Serial.print(aTC,3)             ; Serial.print(F(",")) ;
// Serial.print(IRbodyTemp,3)     ; Serial.print(F(",")) ;
Serial.print(alux,3)            ; Serial.print(F(",")) ;
Serial.print(aP_BME280,3)       ; Serial.print(F(",")) ;
Serial.print(aT_BME280,3)       ; Serial.print(F(",")) ;
Serial.println(aRH_BME280,3)    ; 

/************************* WRITE DATA TO THE SD CARD NOW **********************************/
mySensorData = SD.open("sensor.csv", FILE_WRITE); /* Open SD File, Append if the file is already exist. */
digitalClockDisplaySD()     ; /* Writes the time and date from the RTC */
mySensorData.print(aIRtargetTemp,3)   ; mySensorData.print(",") ;
mySensorData.print(aTC,3)             ; mySensorData.print(",") ;
// mySensorData.print(IRbodyTemp,3)     ; mySensorData.print(",") ;
mySensorData.print(alux,3)            ; mySensorData.print(",") ;
mySensorData.print(aP_BME280,3)       ; mySensorData.print(",") ;
mySensorData.print(aT_BME280,3)       ; mySensorData.print(",") ;
mySensorData.println(aRH_BME280,3)    ;
mySensorData.close(); 

}  // Main loop repeats here.

/* Function to calculate the thermistor temperature from the voltage divider
   measurement of thermistor resistance.
   RT is the thermistor resistance calculated from the voltage divider.
   Rfixed is the fixed value of resistance. 
   5.0 is the voltage of the Arduino power supply.
   Thermistor model: Gikfun 100K ohm NTC B4267 ATC Semitic 104GT-2 Thermistor for 3D Printer Reprap EK9018.
*/
    float get_T_From_V(float sensorValue) {  // Calculate thermistor temperature from voltage.
    float Ttherm ;  // Thermistor temperature calculated here.
    float RT  ;  // Resistance of the thermistor.
    float logRT ; // Natural log of RT, used in temperature calculation.
  //  float aa=7.58546e-4   ; // thermistor calculation constant a from table.
  //  float bb=2.18117e-4   ; // thermistor calculation constant b from table.
  //  float dd=5.53062e-8  ; // thermistor calculation constant  d from table.
  //  float Rfixed=10.00   ; // Value of the fixed resistance. 

      RT = 10.0 * sensorValue / (5.0-sensorValue) ; // Thermistor resistance in kOhms.     
      logRT = log(RT) + 6.907755279 ; // The second term comes from conversion to Ohms
      Ttherm = 7.58546e-4 + 2.18117e-4*logRT + 5.53062e-8*logRT*logRT*logRT ;
      Ttherm = 1.0/Ttherm - 273.15  ; // Thermistor temperature in Celcius.
    return Ttherm ; 
  }



 //  FUNCTIONS NEEDED FOR THE CHRONODOT TIME MEASUREMENT  //
 /*  SD card printing of actual time and date.
*   Write the digital clock output to the SD card writer. */
void digitalClockDisplaySD(){
  SDPrintDigits(months)      ;
  mySensorData.print("/")    ;
  SDPrintDigits(date)        ; 
  mySensorData.print("/")  ;
  SDPrintDigits(years)       ;
  mySensorData.print(",")    ;
  SDPrintDigits(hours)       ;
  mySensorData.print(":")    ;
  SDPrintDigits(minutes)     ;
  mySensorData.print(":")    ;
  SDPrintDigits(seconds)     ;
  mySensorData.print(",")    ;
}
void SDPrintDigits(int digits){
  if(digits < 10) mySensorData.print("0") ; 
  mySensorData.print(digits) ;
}

 void digitalClockDisplay()
{
  SerialPrintDigits(months)  ;
  Serial.print(F("/"))          ;
  SerialPrintDigits(date)    ; 
  Serial.print(F("/"))          ;
  SerialPrintDigits(years)   ;
  Serial.print(F(","))          ;
  SerialPrintDigits(hours)   ;
  Serial.print(F(":"))          ;
  SerialPrintDigits(minutes) ;
  Serial.print(F(":"))          ;
  SerialPrintDigits(seconds) ;
  Serial.print(F(","))          ;
} 
void SerialPrintDigits(int digits){
  if(digits < 10)
    Serial.print('0') ; 
  Serial.print(digits) ;
}


/* Procedure to get date from the Chronodot RTC */
void get_date()
{
  Wire.beginTransmission(104); 
  Wire.write(3);//set register to 3 (day)
  Wire.endTransmission();
  Wire.requestFrom(104, 4); //get 5 bytes(day,date,month,year,control);
  days   = bcdToDec(Wire.read()); 
  date  =  bcdToDec(Wire.read());   
  months = bcdToDec(Wire.read()); 
  years  = bcdToDec(Wire.read());  
}

void get_time()
{
  Wire.beginTransmission(104); 
  Wire.write(0);//set register to 0
  Wire.endTransmission();
  Wire.requestFrom(104, 3);//get 3 bytes (seconds,minutes,hours);
  seconds = bcdToDec(Wire.read() & 0x7f);
  minutes = bcdToDec(Wire.read());
  hours   = bcdToDec(Wire.read() & 0x3f);
}
   
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}


      