Methane and Carbon Dioxide sensor: Difference between revisions

From Sensors in Schools
Jump to navigation Jump to search
Line 1,275: Line 1,275:
                 #print("Aquarium plot saved as temperature_plot.html")
                 #print("Aquarium plot saved as temperature_plot.html")


</syntaxhighlight>
== Working Arduino Code 6 June 2024 ==
<syntaxhighlight lang="c++">
// A simple CH4, CO2, RH, T data logger for the Arduino analog pins
// By David Bastviken and Nguyen Thanh Duc, Linkoping University, Sweden.
//Thanks to cactus.io and Adafruit for code components. For setup of RTC, see separate logger shield documentation.
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>
//#include "RTClib.h" //RTC library
#include <cactus_io_DHT22.h>
//#include "cactus_io_DHT22.h" //RH_Temp library
#define LOG_INTERVAL 2000 // mills between logging entries (reduce to take more/faster data)
 
  // milliseconds before writing the logged data permanently to disk
  // LOG_INTERVAL write each time (safest)
#define SYNC_INTERVAL 5000 // mills between calls to flush() - to write data to the card
uint32_t syncTime = 0; // time of last sync()
#define ECHO_TO_SERIAL  1 // echo data to serial port
#define WAIT_TO_START    0 // Wait for serial input in setup()
#define DHT22_PIN 7 // DHT22 (RH_T) data pin
DHT22 dht(DHT22_PIN);  // Initialize DHT sensor for normal 16mhz Arduino.
// The analog pins that connect to the sensors
#define CH4sens A1 //CH4 sensor Vout
#define CH4ref A2 //CH4 sensor Vref
#define Vb A0 //Battery voltage
int CH4s = 0;
int CH4r = 0;
int Vbat = 0;
float CH4smV = 0;
float CH4rmV = 0;
float VbatmV = 0;
float mV = 5000;
float steps = 1024;
//RTC_PCF8523 RTC; // define the Real Time Clock object
RTC_DS1307 RTC;
// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = 10;
// the logging file
File logfile;
void error(char *str) //Halt if error
{
  Serial.print("error: ");
  Serial.println(str);
  //digitalWrite(redLEDpin, HIGH); // red LED indicates error
  while(1); //halt command
}
double RHValue = 0;
double TempValue = 0;
double CO2Value = 0;
// This is the modified address of the CO2 sensor, 7bits shifted left (defaul 0x68, but collide with RTC chip)
int co2Addr = 0x7F;
///////////////////////////////////////////////////////////////////
// Function : void initPoll()
// Executes : Tells sensor to take a measurement.
// Notes    : A fuller implementation would read the register back and 
//            ensure the flag was set, but in our case we ensure the poll
//            period is >25s and life is generally good.
///////////////////////////////////////////////////////////////////
void initPoll() {
Wire.beginTransmission(co2Addr);
Wire.write(0x11);
Wire.write(0x00);
Wire.write(0x60);
Wire.write(0x35);
Wire.write(0xA6);
 
Wire.endTransmission();
delay(20); 
Wire.requestFrom(co2Addr, 2);
 
byte i = 0;
byte buffer[2] = {0, 0};
while(Wire.available()) {
    buffer[i] = Wire.read();
    i++;
}
///////////////////////////////////////////////////////////////////
// Function : double readRH()
// Returns  : The current RH Value, ?1 if error has occured
///////////////////////////////////////////////////////////////////
double readRH() {
int RH_value = 0;  // We will store the RH value inside this variable. 
digitalWrite(13, HIGH);               
//////////////////////////
/* Begin Write Sequence */
//////////////////////////
 
Wire.beginTransmission(co2Addr);
Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
Wire.write(0x00); //Sensor address in ?? EEPROM ??
Wire.write(0x14); //Two bytes starting from 0x14 (high byte) and 0x15 (low byte)
Wire.write(0x36); //Checksum
 
Wire.endTransmission();
delay(20);
///////////////////////// 
/* Begin Read Sequence */
///////////////////////// 
 
Wire.requestFrom(co2Addr, 4);
 
byte i = 0;
byte buffer[4] = {0, 0, 0, 0};
while(Wire.available()) {
    buffer[i] = Wire.read();
    i++;
 
RH_value = 0;
RH_value |= buffer[1] & 0xFF;
RH_value = RH_value << 8;
RH_value |= buffer[2] & 0xFF;
/*
Serial.print("RH  Data ");
Serial.print(buffer[0], HEX);
Serial.print("|");
Serial.print(buffer[1], HEX);
Serial.print("|"); 
Serial.print(buffer[2], HEX);
Serial.print("|");
Serial.println(buffer[3], HEX);
*/
byte sum = 0;                              //Checksum Byte
sum = buffer[0] + buffer[1] + buffer[2];  //Byte addition utilizes overflow
 
if(sum == buffer[3]) {
    // Success!
    digitalWrite(13, LOW);
    delay(10);
    return ((double)RH_value / (double) 100);
else {
  // Failure! 
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1);
}
///////////////////////////////////////////////////////////////////
// Function : double readTemp()
// Returns  : The current Temperature Value, ?1 if error has occured
///////////////////////////////////////////////////////////////////
double readTemp() {
int Temp_value = 0;  // We will store the temperature value inside this variable. 
digitalWrite(13, HIGH);               
//////////////////////////
/* Begin Write Sequence */
//////////////////////////
 
Wire.beginTransmission(co2Addr); //int K33 == 0x68
Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
Wire.write(0x00); //Sensor address in ?? EEPROM ??
Wire.write(0x12); //Two bytes starting from 0x12 (high byte) and 0x13 (low byte)
Wire.write(0x34); //Checksum
 
Wire.endTransmission();
delay(20);
 
///////////////////////// 
/* Begin Read Sequence */
///////////////////////// 
 
Wire.requestFrom(co2Addr, 4);
 
byte i = 0;
byte buffer[4] = {0, 0, 0, 0};
while(Wire.available()) {
    buffer[i] = Wire.read();
    i++;
 
Temp_value = 0;
Temp_value |= buffer[1] & 0xFF;
Temp_value = Temp_value << 8;
Temp_value |= buffer[2] & 0xFF;
/*
Serial.print("T  Data ");
Serial.print(buffer[0], HEX);
Serial.print("|");
Serial.print(buffer[1], HEX);
Serial.print("|"); 
Serial.print(buffer[2], HEX);
Serial.print("|");
Serial.println(buffer[3], HEX);
*/
byte sum = 0;                              //Checksum Byte
sum = buffer[0] + buffer[1] + buffer[2];  //Byte addition utilizes overflow
 
if(sum == buffer[3]) {
    // Success!
    digitalWrite(13, LOW);
    delay(10);
    return ((double)Temp_value / (double) 100);
else {
  // Failure! 
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1);
}
///////////////////////////////////////////////////////////////////
// Function : double readCO2()
// Returns  : The current CO2 Value, ?1 if error has occured
///////////////////////////////////////////////////////////////////
double readCO2() {
int CO2_value = 0;  // We will store the temperature value inside this variable. 
digitalWrite(13, HIGH);               
//////////////////////////
/* Begin Write Sequence */
//////////////////////////
 
Wire.beginTransmission(co2Addr); //int K33 == 0x68
Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
Wire.write(0x00); //Sensor address in ?? EEPROM ??
Wire.write(0x08); //Two bytes starting from 0x08 (high byte) and 0x09 (low byte). They contain the CO2 data
Wire.write(0x2A); //Checksum
 
Wire.endTransmission();
delay(50);
///////////////////////// 
/* Begin Read Sequence */
///////////////////////// 
 
Wire.requestFrom(co2Addr, 4);
 
byte i = 0;
byte buffer[4] = {0, 0, 0, 0};
while(Wire.available()) {
    buffer[i] = Wire.read();
    i++;
 
CO2_value = 0;
CO2_value |= buffer[1] & 0xFF;
CO2_value = CO2_value << 8;
CO2_value |= buffer[2] & 0xFF;
/*
Serial.print("CO2 Data ");
Serial.print(buffer[0], HEX);
Serial.print("|");
Serial.print(buffer[1], HEX);
Serial.print("|"); 
Serial.print(buffer[2], HEX);
Serial.print("|");
Serial.println(buffer[3], HEX);
*/
byte sum = 0;                              //Checksum Byte
sum = buffer[0] + buffer[1] + buffer[2];  //Byte addition utilizes overflow
 
if(sum == buffer[3]) {
    // Success!
    digitalWrite(13, LOW);
    delay(10);
    return ((double)CO2_value * (double) 1);
else {
  // Failure! 
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1);
}
void setup(void)
{
  Serial.begin(9600);
  Serial.println();
  dht.begin(); //start RH_T_sensor   
 
//#if WAIT_TO_START
//  Serial.println("Type any character to start");
//  while (!Serial.available());
//#endif //WAIT_TO_START
  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
 
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");
 
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE);
      break;  // leave the loop!
    }
  }
 
  if (! logfile) {
    error("couldnt create file");
  }
 
  Serial.print("Logging to: ");
  Serial.println(filename);
  // connect to RTC
  Wire.begin(); 
  if (!RTC.begin()) {
    logfile.println("RTC failed");
#if ECHO_TO_SERIAL
    Serial.println("RTC failed");
#endif  //ECHO_TO_SERIAL
  }
  //if (! RTC.initialized()) {
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //RTC.adjust(DateTime(2024, 5, 5, 20, 33, 0));
  }
  //Edmond 31 May 2024
  //logfile.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");   
#if ECHO_TO_SERIAL
  Serial.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");
#endif //ECHO_TO_SERIAL
}
char time_to_read_CO2 = 1;
char n_delay_wait = 0; 
void loop(){
 
  DateTime now;
 
 
  if (time_to_read_CO2 == 1) {
    initPoll();
    delay(50);
    CO2Value = readCO2();
    delay(20);
    RHValue = readRH();     
    delay(20);
    TempValue = readTemp(); 
// if(RHValue >= 0) {
//      Serial.print("RH: ");
//      Serial.print(RHValue);
//      Serial.print("% | Temp: ");
//      Serial.print(TempValue);
//      Serial.print("C | CO2: ");
//      Serial.print(CO2Value, 0);
//      Serial.println("ppm");
//      Serial.println();     
// }   
// else {
//      Serial.println(" | Checksum failed / Communication failure");
// }   
  time_to_read_CO2 = 0;
  }
  // delay for the amount of time we want between readings
  delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
 
  // log milliseconds since starting
  uint32_t m = millis();
  logfile.print(m);          // milliseconds since start
  logfile.print(", ");   
#if ECHO_TO_SERIAL
  //Serial.print(m);        // milliseconds since start
  //Serial.print(", "); 
#endif
  // fetch the time
  now = RTC.now();
  //Serial.println(now.unixtime());
  // log time
  /*
  logfile.print(now.unixtime()); // seconds since 1/1/1970
  logfile.print(", ");
  //logfile.print('"');
  logfile.print(now.year(), DEC);
  logfile.print("/");
  logfile.print(now.month(), DEC);
  logfile.print("/");
  logfile.print(now.day(), DEC);
  logfile.print(" ");
  logfile.print(now.hour(), DEC);
  logfile.print(":");
  logfile.print(now.minute(), DEC);
  logfile.print(":");
  logfile.print(now.second(), DEC);
  //logfile.print('"');
  */
#if ECHO_TO_SERIAL
  Serial.print(now.unixtime()); // seconds since 1/1/1970
  Serial.print(",");
  //Serial.print('"');
  Serial.print(now.year(), DEC);
  Serial.print("/");
  Serial.print(now.month(), DEC);
  Serial.print("/");
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(":");
  Serial.print(now.minute(), DEC);
  Serial.print(":");
  Serial.print(now.second(), DEC);
  //Serial.print('"');
#endif //ECHO_TO_SERIAL
  // Reading temperature or humidity takes about 250 milliseconds.
  // Sensor readings may also be up to 2 seconds 'old' (its a slow sensor)
  dht.readHumidity();
  dht.readTemperature();
    // Check if any reads failed and exit early (to try again).
  if (isnan(dht.humidity) || isnan(dht.temperature_C)) {
    Serial.print("DHT sensor read failure!");
    return;
  }
  CH4s = analogRead(CH4sens); //read CH4 Vout
  CH4smV = CH4s*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  CH4r = analogRead(CH4ref); //read CH4 Vref
  CH4rmV = CH4r*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  Vbat = analogRead(Vb); //read CH4 Vref
  VbatmV = Vbat *(mV/steps); //convert pin reading to mV, NOT YET correcting for the voltage divider.
  delay(10); //delay between reading of different analogue pins adviced.
  /*
  logfile.print(", ");   
  logfile.print(dht.humidity);
  logfile.print(", ");   
  logfile.print(dht.temperature_C);
  logfile.print(", ");   
  logfile.print(CH4smV);   
  logfile.print(", ");   
  logfile.print(CH4rmV);
  logfile.print(", ");
  logfile.print(VbatmV);   
  logfile.print(", ");
  logfile.print(RHValue);   
  logfile.print(", ");
  logfile.print(TempValue);   
  logfile.print(", ");
  logfile.print(CO2Value);   
  */
#if ECHO_TO_SERIAL
  Serial.print(",");   
  Serial.print(dht.humidity);
  Serial.print(",");   
  Serial.print(dht.temperature_C);
  Serial.print(",");   
  Serial.print(CH4smV);   
  Serial.print(",");   
  Serial.print(CH4rmV);
  Serial.print(",");
  Serial.print(VbatmV);
  Serial.print(",");
  Serial.print(RHValue);
  Serial.print(",");
  Serial.print(TempValue);
  Serial.print(",");
  Serial.print(CO2Value);
#endif //ECHO_TO_SERIAL
  /*
  logfile.println();
  */
#if ECHO_TO_SERIAL
  Serial.println();
#endif // ECHO_TO_SERIAL
if (time_to_read_CO2 == 0 ) {
  if (n_delay_wait < 29)
    n_delay_wait += 1;
    else { 
      time_to_read_CO2 = 1; 
      /*
      Serial.print("Time to read K33 sensor: ");
      */
      n_delay_wait = 0;
  }
}
  // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
  // which uses power and takes time
  if ((millis() - syncTime) < SYNC_INTERVAL) return;
  syncTime = millis();
  /*
  logfile.flush();
  */
}




</syntaxhighlight>
</syntaxhighlight>

Revision as of 05:08, 11 June 2024

References

Dropbox Methane Folder

More References


Circuit Diagram

Pinout for Methane Sensor

Pinout for CO2 Sensor

Pinout DHT22 Temperature and Humidity sensor


Arduino code

// A simple CH4, CO2, RH, T data logger for the Arduino analog pins
// By David Bastviken and Nguyen Thanh Duc, Linkoping University, Sweden.
//Thanks to cactus.io and Adafruit for code components. For setup of RTC, see separate logger shield documentation.
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>
//#include "RTClib.h" //RTC library
#include <cactus_io_DHT22.h>
//#include "cactus_io_DHT22.h" //RH_Temp library

#define LOG_INTERVAL 2000 // mills between logging entries (reduce to take more/faster data)
  
  // milliseconds before writing the logged data permanently to disk
  // LOG_INTERVAL write each time (safest)
#define SYNC_INTERVAL 5000 // mills between calls to flush() - to write data to the card

uint32_t syncTime = 0; // time of last sync()
#define ECHO_TO_SERIAL   1 // echo data to serial port
#define WAIT_TO_START    0 // Wait for serial input in setup()

#define DHT22_PIN 7 // DHT22 (RH_T) data pin
DHT22 dht(DHT22_PIN);   // Initialize DHT sensor for normal 16mhz Arduino. 

// The analog pins that connect to the sensors
#define CH4sens A1 //CH4 sensor Vout
#define CH4ref A2 //CH4 sensor Vref
#define Vb A0 //Battery voltage
int CH4s = 0;
int CH4r = 0;
int Vbat = 0;
float CH4smV = 0;
float CH4rmV = 0;
float VbatmV = 0;
float mV = 5000;
float steps = 1024;

//RTC_PCF8523 RTC; // define the Real Time Clock object
RTC_DS1307 RTC;


// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = 10;
// the logging file
File logfile;

void error(char *str) //Halt if error
{
  Serial.print("error: ");
  Serial.println(str);
  //digitalWrite(redLEDpin, HIGH); // red LED indicates error
  while(1); //halt command
}

double RHValue = 0;
double TempValue = 0;
double CO2Value = 0;
// This is the modified address of the CO2 sensor, 7bits shifted left (defaul 0x68, but collide with RTC chip)
int co2Addr = 0x7F;


/////////////////////////////////////////////////////////////////// 
// Function : void initPoll() 
// Executes : Tells sensor to take a measurement. 
// Notes    : A fuller implementation would read the register back and  
//            ensure the flag was set, but in our case we ensure the poll 
//            period is >25s and life is generally good. 
/////////////////////////////////////////////////////////////////// 
void initPoll() { 
 Wire.beginTransmission(co2Addr); 
 Wire.write(0x11); 
 Wire.write(0x00); 
 Wire.write(0x60); 
 Wire.write(0x35); 
 Wire.write(0xA6); 
  
 Wire.endTransmission(); 
 delay(20);  
 Wire.requestFrom(co2Addr, 2); 
   
 byte i = 0; 
 byte buffer[2] = {0, 0}; 

 while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
}

/////////////////////////////////////////////////////////////////// 
// Function : double readRH() 
// Returns  : The current RH Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readRH() {
 int RH_value = 0;   // We will store the RH value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); 
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x14); //Two bytes starting from 0x14 (high byte) and 0x15 (low byte)
 Wire.write(0x36); //Checksum
  
 Wire.endTransmission(); 
 
 delay(20); 
 
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 RH_value = 0; 
 RH_value |= buffer[1] & 0xFF;
 RH_value = RH_value << 8; 
 RH_value |= buffer[2] & 0xFF;
 Serial.print("RH  Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)RH_value / (double) 100); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 

/////////////////////////////////////////////////////////////////// 
// Function : double readTemp() 
// Returns  : The current Temperature Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readTemp() {
 int Temp_value = 0;   // We will store the temperature value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); //int K33 == 0x68
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x12); //Two bytes starting from 0x12 (high byte) and 0x13 (low byte)
 Wire.write(0x34); //Checksum
  
 Wire.endTransmission(); 
 
 delay(20); 
 
  
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 Temp_value = 0; 
 Temp_value |= buffer[1] & 0xFF;
 Temp_value = Temp_value << 8; 
 Temp_value |= buffer[2] & 0xFF;
 Serial.print("T   Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)Temp_value / (double) 100); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 


/////////////////////////////////////////////////////////////////// 
// Function : double readCO2() 
// Returns  : The current CO2 Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readCO2() {
 int CO2_value = 0;   // We will store the temperature value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); //int K33 == 0x68
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x08); //Two bytes starting from 0x08 (high byte) and 0x09 (low byte). They contain the CO2 data
 Wire.write(0x2A); //Checksum
  
 Wire.endTransmission(); 
 
 delay(50); 
 
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 CO2_value = 0; 
 CO2_value |= buffer[1] & 0xFF;
 CO2_value = CO2_value << 8; 
 CO2_value |= buffer[2] & 0xFF;
 Serial.print("CO2 Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)CO2_value * (double) 1); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 


void setup(void)
{
  Serial.begin(9600);
  Serial.println();
  dht.begin(); //start RH_T_sensor    
  
//#if WAIT_TO_START
//  Serial.println("Type any character to start");
//  while (!Serial.available());
//#endif //WAIT_TO_START

  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");
  
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      break;  // leave the loop!
    }
  }
  
  if (! logfile) {
    error("couldnt create file");
  }
  
  Serial.print("Logging to: ");
  Serial.println(filename);

  // connect to RTC
  Wire.begin();  
  if (!RTC.begin()) {
    logfile.println("RTC failed");
#if ECHO_TO_SERIAL
    Serial.println("RTC failed");
#endif  //ECHO_TO_SERIAL
  }
  //if (! RTC.initialized()) {
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
     RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //RTC.adjust(DateTime(2024, 5, 5, 20, 33, 0));
  }
   
  logfile.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");    
#if ECHO_TO_SERIAL
  Serial.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");
#endif //ECHO_TO_SERIAL
}

char time_to_read_CO2 = 1;
char n_delay_wait = 0;  
void loop(){
  
  DateTime now;
  
  
  if (time_to_read_CO2 == 1) {
    initPoll();
    delay(50);
    CO2Value = readCO2(); 
    delay(20);
    RHValue = readRH();       
    delay(20);
    TempValue = readTemp();   

// if(RHValue >= 0) { 
//       Serial.print("RH: "); 
//       Serial.print(RHValue); 
//       Serial.print("% | Temp: ");
//       Serial.print(TempValue); 
//       Serial.print("C | CO2: ");
//       Serial.print(CO2Value, 0);
//       Serial.println("ppm"); 
//       Serial.println();       
// }     
// else { 
//       Serial.println(" | Checksum failed / Communication failure"); 
// }     
  time_to_read_CO2 = 0;
  }

  // delay for the amount of time we want between readings
  delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
  
  // log milliseconds since starting
  uint32_t m = millis();
  logfile.print(m);           // milliseconds since start
  logfile.print(", ");    
#if ECHO_TO_SERIAL
  Serial.print(m);         // milliseconds since start
  Serial.print(", ");  
#endif

  // fetch the time
  now = RTC.now();
  Serial.println(now.unixtime());
  // log time
  logfile.print(now.unixtime()); // seconds since 1/1/1970
  logfile.print(", ");
  //logfile.print('"');
  logfile.print(now.year(), DEC);
  logfile.print("/");
  logfile.print(now.month(), DEC);
  logfile.print("/");
  logfile.print(now.day(), DEC);
  logfile.print(" ");
  logfile.print(now.hour(), DEC);
  logfile.print(":");
  logfile.print(now.minute(), DEC);
  logfile.print(":");
  logfile.print(now.second(), DEC);
  //logfile.print('"');
#if ECHO_TO_SERIAL
  Serial.print(now.unixtime()); // seconds since 1/1/1970
  Serial.print(", ");
  //Serial.print('"');
  Serial.print(now.year(), DEC);
  Serial.print("/");
  Serial.print(now.month(), DEC);
  Serial.print("/");
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(":");
  Serial.print(now.minute(), DEC);
  Serial.print(":");
  Serial.print(now.second(), DEC);
  //Serial.print('"');
#endif //ECHO_TO_SERIAL

  // Reading temperature or humidity takes about 250 milliseconds.
  // Sensor readings may also be up to 2 seconds 'old' (its a slow sensor)
  dht.readHumidity();
  dht.readTemperature();
    // Check if any reads failed and exit early (to try again).
  if (isnan(dht.humidity) || isnan(dht.temperature_C)) {
    Serial.print("DHT sensor read failure!");
    return;
  }
  CH4s = analogRead(CH4sens); //read CH4 Vout
  CH4smV = CH4s*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  CH4r = analogRead(CH4ref); //read CH4 Vref
  CH4rmV = CH4r*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  Vbat = analogRead(Vb); //read CH4 Vref
  VbatmV = Vbat *(mV/steps); //convert pin reading to mV, NOT YET correcting for the voltage divider.
  delay(10); //delay between reading of different analogue pins adviced.
   
  logfile.print(", ");    
  logfile.print(dht.humidity);
  logfile.print(", ");    
  logfile.print(dht.temperature_C);
  logfile.print(", ");    
  logfile.print(CH4smV);    
  logfile.print(", ");    
  logfile.print(CH4rmV);
  logfile.print(", ");
  logfile.print(VbatmV);    

  logfile.print(", ");
  logfile.print(RHValue);    
  logfile.print(", ");
  logfile.print(TempValue);    
  logfile.print(", ");
  logfile.print(CO2Value);    
  
#if ECHO_TO_SERIAL
  Serial.print(", ");    
  Serial.print(dht.humidity);
  Serial.print(", ");    
  Serial.print(dht.temperature_C);
  Serial.print(", ");    
  Serial.print(CH4smV);    
  Serial.print(", ");    
  Serial.print(CH4rmV);
  Serial.print(", ");
  Serial.print(VbatmV);
  Serial.print(", ");
  Serial.print(RHValue);
  Serial.print(", ");
  Serial.print(TempValue);
  Serial.print(", ");
  Serial.print(CO2Value);
#endif //ECHO_TO_SERIAL

  logfile.println();
#if ECHO_TO_SERIAL
  Serial.println();
#endif // ECHO_TO_SERIAL

if (time_to_read_CO2 == 0 ) {
  if (n_delay_wait < 29)
    n_delay_wait += 1;
    else {  
      time_to_read_CO2 = 1;   
      Serial.print("Time to read K33 sensor: ");
      n_delay_wait = 0;
  }
}
  // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
  // which uses power and takes time
  if ((millis() - syncTime) < SYNC_INTERVAL) return;
  syncTime = millis();
  logfile.flush();

}


Timestamp example for RTC - Real Time Clock

/* Timestamp functions using a DS1307 RTC connected via I2C and Wire lib
**
** Useful for file name
**		` SD.open(time.timestamp()+".log", FILE_WRITE) `
**
**
** Created: 2015-06-01 by AxelTB
** Last Edit:
*/

#include "RTClib.h"

RTC_DS1307 rtc;

void setup() {
   Serial.begin(9600);
  rtc.begin();

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

}

void loop() {
 DateTime time = rtc.now();

 //Full Timestamp
 Serial.println(String("DateTime::TIMESTAMP_FULL:\t")+time.timestamp(DateTime::TIMESTAMP_FULL));

 //Date Only
 Serial.println(String("DateTime::TIMESTAMP_DATE:\t")+time.timestamp(DateTime::TIMESTAMP_DATE));

 //Full Timestamp
 Serial.println(String("DateTime::TIMESTAMP_TIME:\t")+time.timestamp(DateTime::TIMESTAMP_TIME));

 Serial.println("\n");

 //Delay 5s
 delay(5000);
}


Methane and Carbon dioxide sensor sending data to Pi

// A simple CH4, CO2, RH, T data logger for the Arduino analog pins
// By David Bastviken and Nguyen Thanh Duc, Linkoping University, Sweden.
//Thanks to cactus.io and Adafruit for code components. For setup of RTC, see separate logger shield documentation.
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>
//#include "RTClib.h" //RTC library
#include <cactus_io_DHT22.h>
//#include "cactus_io_DHT22.h" //RH_Temp library

#define LOG_INTERVAL 2000 // mills between logging entries (reduce to take more/faster data)
  
  // milliseconds before writing the logged data permanently to disk
  // LOG_INTERVAL write each time (safest)
#define SYNC_INTERVAL 5000 // mills between calls to flush() - to write data to the card

uint32_t syncTime = 0; // time of last sync()
#define ECHO_TO_SERIAL   1 // echo data to serial port
#define WAIT_TO_START    0 // Wait for serial input in setup()

#define DHT22_PIN 7 // DHT22 (RH_T) data pin
DHT22 dht(DHT22_PIN);   // Initialize DHT sensor for normal 16mhz Arduino. 

// The analog pins that connect to the sensors
#define CH4sens A1 //CH4 sensor Vout
#define CH4ref A2 //CH4 sensor Vref
#define Vb A0 //Battery voltage
int CH4s = 0;
int CH4r = 0;
int Vbat = 0;
float CH4smV = 0;
float CH4rmV = 0;
float VbatmV = 0;
float mV = 5000;
float steps = 1024;

//RTC_PCF8523 RTC; // define the Real Time Clock object
RTC_DS1307 RTC;


// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = 10;
// the logging file
File logfile;

void error(char *str) //Halt if error
{
  Serial.print("error: ");
  Serial.println(str);
  //digitalWrite(redLEDpin, HIGH); // red LED indicates error
  while(1); //halt command
}

double RHValue = 0;
double TempValue = 0;
double CO2Value = 0;
// This is the modified address of the CO2 sensor, 7bits shifted left (defaul 0x68, but collide with RTC chip)
int co2Addr = 0x7F;


/////////////////////////////////////////////////////////////////// 
// Function : void initPoll() 
// Executes : Tells sensor to take a measurement. 
// Notes    : A fuller implementation would read the register back and  
//            ensure the flag was set, but in our case we ensure the poll 
//            period is >25s and life is generally good. 
/////////////////////////////////////////////////////////////////// 
void initPoll() { 
 Wire.beginTransmission(co2Addr); 
 Wire.write(0x11); 
 Wire.write(0x00); 
 Wire.write(0x60); 
 Wire.write(0x35); 
 Wire.write(0xA6); 
  
 Wire.endTransmission(); 
 delay(20);  
 Wire.requestFrom(co2Addr, 2); 
   
 byte i = 0; 
 byte buffer[2] = {0, 0}; 

 while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
}

/////////////////////////////////////////////////////////////////// 
// Function : double readRH() 
// Returns  : The current RH Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readRH() {
 int RH_value = 0;   // We will store the RH value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); 
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x14); //Two bytes starting from 0x14 (high byte) and 0x15 (low byte)
 Wire.write(0x36); //Checksum
  
 Wire.endTransmission(); 
 
 delay(20); 
 
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 RH_value = 0; 
 RH_value |= buffer[1] & 0xFF;
 RH_value = RH_value << 8; 
 RH_value |= buffer[2] & 0xFF;
 /*
 Serial.print("RH  Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 */
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)RH_value / (double) 100); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 

/////////////////////////////////////////////////////////////////// 
// Function : double readTemp() 
// Returns  : The current Temperature Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readTemp() {
 int Temp_value = 0;   // We will store the temperature value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); //int K33 == 0x68
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x12); //Two bytes starting from 0x12 (high byte) and 0x13 (low byte)
 Wire.write(0x34); //Checksum
  
 Wire.endTransmission(); 
 
 delay(20); 
 
  
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 Temp_value = 0; 
 Temp_value |= buffer[1] & 0xFF;
 Temp_value = Temp_value << 8; 
 Temp_value |= buffer[2] & 0xFF;
 /*
 Serial.print("T   Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 */
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)Temp_value / (double) 100); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 


/////////////////////////////////////////////////////////////////// 
// Function : double readCO2() 
// Returns  : The current CO2 Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readCO2() {
 int CO2_value = 0;   // We will store the temperature value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); //int K33 == 0x68
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x08); //Two bytes starting from 0x08 (high byte) and 0x09 (low byte). They contain the CO2 data
 Wire.write(0x2A); //Checksum
  
 Wire.endTransmission(); 
 
 delay(50); 
 
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 CO2_value = 0; 
 CO2_value |= buffer[1] & 0xFF;
 CO2_value = CO2_value << 8; 
 CO2_value |= buffer[2] & 0xFF;
 /*
 Serial.print("CO2 Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 */
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)CO2_value * (double) 1); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 


void setup(void)
{
  Serial.begin(9600);
  Serial.println();
  dht.begin(); //start RH_T_sensor    
  
//#if WAIT_TO_START
//  Serial.println("Type any character to start");
//  while (!Serial.available());
//#endif //WAIT_TO_START

  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");
  
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      break;  // leave the loop!
    }
  }
  
  if (! logfile) {
    error("couldnt create file");
  }
  
  Serial.print("Logging to: ");
  Serial.println(filename);

  // connect to RTC
  Wire.begin();  
  if (!RTC.begin()) {
    logfile.println("RTC failed");
#if ECHO_TO_SERIAL
    Serial.println("RTC failed");
#endif  //ECHO_TO_SERIAL
  }
  //if (! RTC.initialized()) {
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
     RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //RTC.adjust(DateTime(2024, 5, 5, 20, 33, 0));
  }
   //Edmond 31 May 2024
  //logfile.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");    
#if ECHO_TO_SERIAL
  Serial.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");
#endif //ECHO_TO_SERIAL
}

char time_to_read_CO2 = 1;
char n_delay_wait = 0;  
void loop(){
  
  DateTime now;
  
  
  if (time_to_read_CO2 == 1) {
    initPoll();
    delay(50);
    CO2Value = readCO2(); 
    delay(20);
    RHValue = readRH();       
    delay(20);
    TempValue = readTemp();   



// if(RHValue >= 0) { 
//       Serial.print("RH: "); 
//       Serial.print(RHValue); 
//       Serial.print("% | Temp: ");
//       Serial.print(TempValue); 
//       Serial.print("C | CO2: ");
//       Serial.print(CO2Value, 0);
//       Serial.println("ppm"); 
//       Serial.println();       
// }     
// else { 
//       Serial.println(" | Checksum failed / Communication failure"); 
// }     
  time_to_read_CO2 = 0;
  }

  // delay for the amount of time we want between readings
  delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
  
  // log milliseconds since starting
  uint32_t m = millis();
  logfile.print(m);           // milliseconds since start
  logfile.print(", ");    
#if ECHO_TO_SERIAL
  //Serial.print(m);         // milliseconds since start
  //Serial.print(", ");  
#endif

  // fetch the time
  now = RTC.now();
  //Serial.println(now.unixtime());
  // log time
  /*
  logfile.print(now.unixtime()); // seconds since 1/1/1970
  logfile.print(", ");
  //logfile.print('"');
  logfile.print(now.year(), DEC);
  logfile.print("/");
  logfile.print(now.month(), DEC);
  logfile.print("/");
  logfile.print(now.day(), DEC);
  logfile.print(" ");
  logfile.print(now.hour(), DEC);
  logfile.print(":");
  logfile.print(now.minute(), DEC);
  logfile.print(":");
  logfile.print(now.second(), DEC);
  //logfile.print('"');
  */
#if ECHO_TO_SERIAL
  Serial.print(now.unixtime()); // seconds since 1/1/1970
  Serial.print(",");
  //Serial.print('"');
  Serial.print(now.year(), DEC);
  Serial.print("/");
  Serial.print(now.month(), DEC);
  Serial.print("/");
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(":");
  Serial.print(now.minute(), DEC);
  Serial.print(":");
  Serial.print(now.second(), DEC);
  //Serial.print('"');
#endif //ECHO_TO_SERIAL

  // Reading temperature or humidity takes about 250 milliseconds.
  // Sensor readings may also be up to 2 seconds 'old' (its a slow sensor)
  dht.readHumidity();
  dht.readTemperature();
    // Check if any reads failed and exit early (to try again).
  if (isnan(dht.humidity) || isnan(dht.temperature_C)) {
    Serial.print("DHT sensor read failure!");
    return;
  }
  CH4s = analogRead(CH4sens); //read CH4 Vout
  CH4smV = CH4s*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  CH4r = analogRead(CH4ref); //read CH4 Vref
  CH4rmV = CH4r*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  Vbat = analogRead(Vb); //read CH4 Vref
  VbatmV = Vbat *(mV/steps); //convert pin reading to mV, NOT YET correcting for the voltage divider.
  delay(10); //delay between reading of different analogue pins adviced.
  /*
  logfile.print(", ");    
  logfile.print(dht.humidity);
  logfile.print(", ");    
  logfile.print(dht.temperature_C);
  logfile.print(", ");    
  logfile.print(CH4smV);    
  logfile.print(", ");    
  logfile.print(CH4rmV);
  logfile.print(", ");
  logfile.print(VbatmV);    

  logfile.print(", ");
  logfile.print(RHValue);    
  logfile.print(", ");
  logfile.print(TempValue);    
  logfile.print(", ");
  logfile.print(CO2Value);    
  */
#if ECHO_TO_SERIAL
  Serial.print(",");    
  Serial.print(dht.humidity);
  Serial.print(",");    
  Serial.print(dht.temperature_C);
  Serial.print(",");    
  Serial.print(CH4smV);    
  Serial.print(",");    
  Serial.print(CH4rmV);
  Serial.print(",");
  Serial.print(VbatmV);
  Serial.print(",");
  Serial.print(RHValue);
  Serial.print(",");
  Serial.print(TempValue);
  Serial.print(",");
  Serial.print(CO2Value);
#endif //ECHO_TO_SERIAL
  /*
  logfile.println();
  */
#if ECHO_TO_SERIAL
  Serial.println();
#endif // ECHO_TO_SERIAL

if (time_to_read_CO2 == 0 ) {
  if (n_delay_wait < 29)
    n_delay_wait += 1;
    else {  
      time_to_read_CO2 = 1;   
      /*
      Serial.print("Time to read K33 sensor: ");
      */
      n_delay_wait = 0;
  }
}
  // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
  // which uses power and takes time
  if ((millis() - syncTime) < SYNC_INTERVAL) return;
  syncTime = millis();
  /*
  logfile.flush();
  */

}

Methane and Carbon dioxide sensor sending data to Pi

Python code

#!/usr/bin/env python3
# dweet data
import serial
import datetime
import time
import requests
import pandas as pd
import plotly.express as px
from water_variables import *

count = 0


if __name__ == '__main__':
    # methane
    ser = serial.Serial('/dev/ttyUSB1', 9600, timeout=1)
    ser.reset_input_buffer()
    

    while True:
        count = count + 1
        time.sleep(0.1)
             
        if ser.in_waiting > 0:
            time.sleep(0.1)
            try:
                line = ser.readline().decode('utf-8').rstrip()
                print(line)
            except:
                line = "0,0,0,0,0,0,0,0,0,0"
            #print(f"Data separated using commas {line.split(',')}")
            mylist = line.split(',')
            print(f'My list {mylist}')
            try:
                # stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2
                stampunix = str(mylist[0])
                date_time_not_used = str(mylist[1])
                RH1 = str(mylist[2])
                temp1 = str(mylist[3])
                CH4smV = str(mylist[4])
                CH4rmV = str(mylist[5])
                VbatmV = str(mylist[6])
                K33_RH = str(mylist[7])
                K33_Temp = str(mylist[8])
                K33_CO2 = str(mylist[9])
                print("data extracted")
                

            except:
                stampunix = "0.0"
                date_time_not_used = "0.0"
                RH1 = "0.0"
                temp1 = "0.0"
                CH4smV = "0.0"
                CH4rmV = "0"
                VbatmV = "0.0"
                K33_RH = "0.0"
                K33_Temp = "0.0"
                K33_CO2 = "0.0"
                
            now = datetime.datetime.now()
            date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")

            print(f'CH4smV - {CH4smV}, K33_CO2 - {K33_CO2}, time - {date_stamp}')
            print(count)
            print()

            time.sleep(0.1)
            

            data = ""
            data = date_stamp + "," + str(RH1) + "," + str(temp1) + "," + str(CH4smV) + "," +\
                   str(CH4rmV) + "," + str(VbatmV) + "," + str(K33_RH) + "," + \
                   str(K33_Temp) + "," + str(K33_CO2) + '\n'
            #print(f'The data is =  {data}')

            if count > 3000:
                #print(count)
                f = open('/home/pi/Aquarium/aquarium_methane.txt','a')
                f.write(data)
                f.close()
                print("Data saved")
      
                try:
                    print("Preparing dweet")
                    dweet_dict = {}
                    dweet_dict.update({"RH1": str(RH1)})
                    dweet_dict.update({"temp1": str(temp1)})
                    dweet_dict.update({"CH4smV": str(CH4smV)})
                    dweet_dict.update({"CH4rmV": str(CH4rmV)})
                    dweet_dict.update({"VbatmV": str(VbatmV)})
                    dweet_dict.update({"K33_RH": str(K33_RH)})
                    dweet_dict.update({"K33_Temp": str(K33_Temp)})
                    dweet_dict.update({"K33_CO2": str(K33_CO2)})
                    dweet_dict.update({"time": str(date_stamp)})
                    url = "https://dweet.io/dweet/for/3083-Bundoora-aquarium_methane1?"
                    #https://dweet.io/get/latest/dweet/for/3083-Bundoora-aquarium_methane1?
                    x = requests.post(url, json=dweet_dict)
                    print(x.text)
                except:
                    print("Dweet failed")
                count = 0
                # check dweet with - https://dweet.io/get/latest/dweet/for/3083-Bundoora-aquarium1
                
                # Step 2: Read the data from the text file into a Pandas DataFrame
                #data = pd.read_csv('/home/pi/Aquarium/aquarium_methane.txt')

                # Step 3: Create a Plotly figure with two scatter plots
                #fig = px.scatter(data, x='datetime', y=['temperature','dissolvedOxygen'],
                                 #labels={'datetime': 'Date and Time', 'value': 'Temperature (°C)'},
                                 #title='Aquarium temperature and DO')

                # Step 4: Customize the plot layout
                #fig.update_layout(xaxis_title='Date and Time', yaxis_title='Temperature (°C)')

                # Step 5: Save the plot as an HTML file
                #fig.write_html('/home/pi/Aquarium/temperature_plot_DO_EC_chem_aquarium.html')

                #print("Aquarium plot saved as temperature_plot.html")

Working Arduino Code 6 June 2024

// A simple CH4, CO2, RH, T data logger for the Arduino analog pins
// By David Bastviken and Nguyen Thanh Duc, Linkoping University, Sweden.
//Thanks to cactus.io and Adafruit for code components. For setup of RTC, see separate logger shield documentation.
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>
//#include "RTClib.h" //RTC library
#include <cactus_io_DHT22.h>
//#include "cactus_io_DHT22.h" //RH_Temp library

#define LOG_INTERVAL 2000 // mills between logging entries (reduce to take more/faster data)
  
  // milliseconds before writing the logged data permanently to disk
  // LOG_INTERVAL write each time (safest)
#define SYNC_INTERVAL 5000 // mills between calls to flush() - to write data to the card

uint32_t syncTime = 0; // time of last sync()
#define ECHO_TO_SERIAL   1 // echo data to serial port
#define WAIT_TO_START    0 // Wait for serial input in setup()

#define DHT22_PIN 7 // DHT22 (RH_T) data pin
DHT22 dht(DHT22_PIN);   // Initialize DHT sensor for normal 16mhz Arduino. 

// The analog pins that connect to the sensors
#define CH4sens A1 //CH4 sensor Vout
#define CH4ref A2 //CH4 sensor Vref
#define Vb A0 //Battery voltage
int CH4s = 0;
int CH4r = 0;
int Vbat = 0;
float CH4smV = 0;
float CH4rmV = 0;
float VbatmV = 0;
float mV = 5000;
float steps = 1024;

//RTC_PCF8523 RTC; // define the Real Time Clock object
RTC_DS1307 RTC;


// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = 10;
// the logging file
File logfile;

void error(char *str) //Halt if error
{
  Serial.print("error: ");
  Serial.println(str);
  //digitalWrite(redLEDpin, HIGH); // red LED indicates error
  while(1); //halt command
}

double RHValue = 0;
double TempValue = 0;
double CO2Value = 0;
// This is the modified address of the CO2 sensor, 7bits shifted left (defaul 0x68, but collide with RTC chip)
int co2Addr = 0x7F;


/////////////////////////////////////////////////////////////////// 
// Function : void initPoll() 
// Executes : Tells sensor to take a measurement. 
// Notes    : A fuller implementation would read the register back and  
//            ensure the flag was set, but in our case we ensure the poll 
//            period is >25s and life is generally good. 
/////////////////////////////////////////////////////////////////// 
void initPoll() { 
 Wire.beginTransmission(co2Addr); 
 Wire.write(0x11); 
 Wire.write(0x00); 
 Wire.write(0x60); 
 Wire.write(0x35); 
 Wire.write(0xA6); 
  
 Wire.endTransmission(); 
 delay(20);  
 Wire.requestFrom(co2Addr, 2); 
   
 byte i = 0; 
 byte buffer[2] = {0, 0}; 

 while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
}

/////////////////////////////////////////////////////////////////// 
// Function : double readRH() 
// Returns  : The current RH Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readRH() {
 int RH_value = 0;   // We will store the RH value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); 
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x14); //Two bytes starting from 0x14 (high byte) and 0x15 (low byte)
 Wire.write(0x36); //Checksum
  
 Wire.endTransmission(); 
 
 delay(20); 
 
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 RH_value = 0; 
 RH_value |= buffer[1] & 0xFF;
 RH_value = RH_value << 8; 
 RH_value |= buffer[2] & 0xFF;
 /*
 Serial.print("RH  Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 */
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)RH_value / (double) 100); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 

/////////////////////////////////////////////////////////////////// 
// Function : double readTemp() 
// Returns  : The current Temperature Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readTemp() {
 int Temp_value = 0;   // We will store the temperature value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); //int K33 == 0x68
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x12); //Two bytes starting from 0x12 (high byte) and 0x13 (low byte)
 Wire.write(0x34); //Checksum
  
 Wire.endTransmission(); 
 
 delay(20); 
 
  
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 Temp_value = 0; 
 Temp_value |= buffer[1] & 0xFF;
 Temp_value = Temp_value << 8; 
 Temp_value |= buffer[2] & 0xFF;
 /*
 Serial.print("T   Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 */
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)Temp_value / (double) 100); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 


/////////////////////////////////////////////////////////////////// 
// Function : double readCO2() 
// Returns  : The current CO2 Value, ?1 if error has occured 
/////////////////////////////////////////////////////////////////// 

double readCO2() {
 int CO2_value = 0;   // We will store the temperature value inside this variable.  
 digitalWrite(13, HIGH);                
 
 ////////////////////////// 
 /* Begin Write Sequence */ 
 ////////////////////////// 
  
 Wire.beginTransmission(co2Addr); //int K33 == 0x68
 Wire.write(0x22); //Command number 2 (Read Ram, 2 bytes)
 Wire.write(0x00); //Sensor address in ?? EEPROM ??
 Wire.write(0x08); //Two bytes starting from 0x08 (high byte) and 0x09 (low byte). They contain the CO2 data
 Wire.write(0x2A); //Checksum
  
 Wire.endTransmission(); 
 
 delay(50); 
 
 /////////////////////////   
 /* Begin Read Sequence */ 
 /////////////////////////  
   
 Wire.requestFrom(co2Addr, 4); 
   
 byte i = 0; 
 byte buffer[4] = {0, 0, 0, 0}; 
 
while(Wire.available()) { 
     buffer[i] = Wire.read(); 
     i++; 
 }   
   
 CO2_value = 0; 
 CO2_value |= buffer[1] & 0xFF;
 CO2_value = CO2_value << 8; 
 CO2_value |= buffer[2] & 0xFF;
 /*
 Serial.print("CO2 Data ");
 Serial.print(buffer[0], HEX);
 Serial.print("|"); 
 Serial.print(buffer[1], HEX);
 Serial.print("|");  
 Serial.print(buffer[2], HEX);
 Serial.print("|"); 
 Serial.println(buffer[3], HEX); 
 */
 
 byte sum = 0;                              //Checksum Byte 
 sum = buffer[0] + buffer[1] + buffer[2];   //Byte addition utilizes overflow 
  
 if(sum == buffer[3]) { 
     // Success! 
     digitalWrite(13, LOW); 
     delay(10); 
     return ((double)CO2_value * (double) 1); 
 }   
 else { 
  // Failure!  
  digitalWrite(13, LOW);
  delay(10);
  return ((double) -1); 
 }   
} 


void setup(void)
{
  Serial.begin(9600);
  Serial.println();
  dht.begin(); //start RH_T_sensor    
  
//#if WAIT_TO_START
//  Serial.println("Type any character to start");
//  while (!Serial.available());
//#endif //WAIT_TO_START

  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");
  
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      break;  // leave the loop!
    }
  }
  
  if (! logfile) {
    error("couldnt create file");
  }
  
  Serial.print("Logging to: ");
  Serial.println(filename);

  // connect to RTC
  Wire.begin();  
  if (!RTC.begin()) {
    logfile.println("RTC failed");
#if ECHO_TO_SERIAL
    Serial.println("RTC failed");
#endif  //ECHO_TO_SERIAL
  }
  //if (! RTC.initialized()) {
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
     RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //RTC.adjust(DateTime(2024, 5, 5, 20, 33, 0));
  }
   //Edmond 31 May 2024
  //logfile.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");    
#if ECHO_TO_SERIAL
  Serial.println("millis,stampunix,datetime,RH%,tempC,CH4smV, CH4rmV, VbatmV, K33_RH, K33_Temp, K33_CO2");
#endif //ECHO_TO_SERIAL
}

char time_to_read_CO2 = 1;
char n_delay_wait = 0;  
void loop(){
  
  DateTime now;
  
  
  if (time_to_read_CO2 == 1) {
    initPoll();
    delay(50);
    CO2Value = readCO2(); 
    delay(20);
    RHValue = readRH();       
    delay(20);
    TempValue = readTemp();   



// if(RHValue >= 0) { 
//       Serial.print("RH: "); 
//       Serial.print(RHValue); 
//       Serial.print("% | Temp: ");
//       Serial.print(TempValue); 
//       Serial.print("C | CO2: ");
//       Serial.print(CO2Value, 0);
//       Serial.println("ppm"); 
//       Serial.println();       
// }     
// else { 
//       Serial.println(" | Checksum failed / Communication failure"); 
// }     
  time_to_read_CO2 = 0;
  }

  // delay for the amount of time we want between readings
  delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
  
  // log milliseconds since starting
  uint32_t m = millis();
  logfile.print(m);           // milliseconds since start
  logfile.print(", ");    
#if ECHO_TO_SERIAL
  //Serial.print(m);         // milliseconds since start
  //Serial.print(", ");  
#endif

  // fetch the time
  now = RTC.now();
  //Serial.println(now.unixtime());
  // log time
  /*
  logfile.print(now.unixtime()); // seconds since 1/1/1970
  logfile.print(", ");
  //logfile.print('"');
  logfile.print(now.year(), DEC);
  logfile.print("/");
  logfile.print(now.month(), DEC);
  logfile.print("/");
  logfile.print(now.day(), DEC);
  logfile.print(" ");
  logfile.print(now.hour(), DEC);
  logfile.print(":");
  logfile.print(now.minute(), DEC);
  logfile.print(":");
  logfile.print(now.second(), DEC);
  //logfile.print('"');
  */
#if ECHO_TO_SERIAL
  Serial.print(now.unixtime()); // seconds since 1/1/1970
  Serial.print(",");
  //Serial.print('"');
  Serial.print(now.year(), DEC);
  Serial.print("/");
  Serial.print(now.month(), DEC);
  Serial.print("/");
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(":");
  Serial.print(now.minute(), DEC);
  Serial.print(":");
  Serial.print(now.second(), DEC);
  //Serial.print('"');
#endif //ECHO_TO_SERIAL

  // Reading temperature or humidity takes about 250 milliseconds.
  // Sensor readings may also be up to 2 seconds 'old' (its a slow sensor)
  dht.readHumidity();
  dht.readTemperature();
    // Check if any reads failed and exit early (to try again).
  if (isnan(dht.humidity) || isnan(dht.temperature_C)) {
    Serial.print("DHT sensor read failure!");
    return;
  }
  CH4s = analogRead(CH4sens); //read CH4 Vout
  CH4smV = CH4s*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  CH4r = analogRead(CH4ref); //read CH4 Vref
  CH4rmV = CH4r*(mV/steps); //convert pin reading to mV
  delay(10); //delay between reading of different analogue pins adviced.
  Vbat = analogRead(Vb); //read CH4 Vref
  VbatmV = Vbat *(mV/steps); //convert pin reading to mV, NOT YET correcting for the voltage divider.
  delay(10); //delay between reading of different analogue pins adviced.
  /*
  logfile.print(", ");    
  logfile.print(dht.humidity);
  logfile.print(", ");    
  logfile.print(dht.temperature_C);
  logfile.print(", ");    
  logfile.print(CH4smV);    
  logfile.print(", ");    
  logfile.print(CH4rmV);
  logfile.print(", ");
  logfile.print(VbatmV);    

  logfile.print(", ");
  logfile.print(RHValue);    
  logfile.print(", ");
  logfile.print(TempValue);    
  logfile.print(", ");
  logfile.print(CO2Value);    
  */
#if ECHO_TO_SERIAL
  Serial.print(",");    
  Serial.print(dht.humidity);
  Serial.print(",");    
  Serial.print(dht.temperature_C);
  Serial.print(",");    
  Serial.print(CH4smV);    
  Serial.print(",");    
  Serial.print(CH4rmV);
  Serial.print(",");
  Serial.print(VbatmV);
  Serial.print(",");
  Serial.print(RHValue);
  Serial.print(",");
  Serial.print(TempValue);
  Serial.print(",");
  Serial.print(CO2Value);
#endif //ECHO_TO_SERIAL
  /*
  logfile.println();
  */
#if ECHO_TO_SERIAL
  Serial.println();
#endif // ECHO_TO_SERIAL

if (time_to_read_CO2 == 0 ) {
  if (n_delay_wait < 29)
    n_delay_wait += 1;
    else {  
      time_to_read_CO2 = 1;   
      /*
      Serial.print("Time to read K33 sensor: ");
      */
      n_delay_wait = 0;
  }
}
  // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
  // which uses power and takes time
  if ((millis() - syncTime) < SYNC_INTERVAL) return;
  syncTime = millis();
  /*
  logfile.flush();
  */

}