Project tutorial

Measuring CO2 Levels aka "The Sleepiness Multiplier" © Apache-2.0

Dozing off in class and meetings? Prove why! Measure CO2 levels and publish to the cloud using anduinoWiFi and Adafruit IO.

  • 4,468 views
  • 8 comments
  • 8 respects

Components and supplies

Apps and online services

About this project

Motivation

Have you ever struggled to make it through an afternoon meeting? Can't stop yawning? Sleeping through your 3 hour lectures? No, I'm not selling you an energy supplement. You probably didn't get enough sleep last night, most of us don't. But, your drowsiness might not be completely your fault! Poor ventilation and high levels of carbon dioxide could be causing you to feel sleepy!

Using this NDIR CO2 sensor you can accurately measure the CO2 levels and read the values using a simple UART serial interface. Conventional CO2 sensors used to draw a lot of power and took time to warm up the lamp before they were primed to take a reading. Now using an LED and infrared detector you can accurately measure gasses using this 3.3v sensor which pulls less than 1.5ma on average. It uses optical dispersion and some other witchcraft, check out Cozir's datasheet for some more details, it's impressive.

Getting Started

Right so what do I need to start measuring the 'sleepiness factor' of my office cubicle?

  • Arduino Due or Zero
  • AnduinoWiFi shield
  • Cozir CO2 sensor
  • A few jumpers to connect and power up the sensor.

Connections for this one are simple, the sensor has 10 pins but you'll only need to wire up 4.

Using the Due connect 3.3v to 3V3, GND to Ground, Rx(DIO19) to Tx, and Tx(DIO18) to Rx. Be sure you've "crossed" the UART wires and remember you can't use Tx(DIO1) and Rx(DIO0) unless you'd like to forgo using the serial term to monitor your readings. I've used Serial1 for the sensor although you could use any of the three remaining UARTs.

** If you'd like to bypass the Arduino for now and test sending commands directly to the sensor just open up putty or your favorite serial term and connect at 9600 baud, 8bits, no parity, 1 stop bit. You may need to enable sending '/r/n' on each submission of ascii.**

***This sensor is 3.3v TTL so be sure to use a logic shifter if coms originate on a 5v source***

Calibrating the sensor

There are a few ways to calibrate the CO2 sensor. One of the best ways is saturating the sensor in a known gas (Nitrogen) which contains no Carbon Dioxide. This will generate a known zero reading. If you don't have any Nitrogen laying around you can also fairly accurately calibrate using fresh air. So grab your sunglasses, we're going on a field trip.

When you're outside you're going to want to run the example sketch below and uncomment

 calibrateFreshAir(); 

in the Setup() routine. This sends the 'G' command over serial to the sensor requesting...

calibration! Now this isn't perfect, since I don't know exactly what the current CO2 concentration conditions really are on the 14th floor here in NYC (possibly a bit higher here than "Earth's" average in Hawaii). But since our thresholds for actually physically sensing differences in the environment are in the 1,000's of ppm I think we're pretty safe to use this 450ppm fresh air reading as our calibration point for measuring our conference rooms and classrooms.

char buffer[20] = {0}; 
int c = 0; 
void setup() { 
 Serial.begin(9600); 
 while(!Serial){}; 
 Serial1.begin(9600); 
 while(!Serial){}; 
 Serial.println("Begin reading CO2 Levels"); 
 //setOperatingMode(CZR_STREAMING); 
 //setOperatingMode(CZR_POLLING); 
 //calibrateFreshAir(); 
} 
void loop() { 
delay(10000); 
c = Request("Z"); 
Serial.print("CO2 : ");Serial.println(c); 
Serial.println(""); 
} 
int Request(char* s) 
{ 
 buffer[0] = '\0'; 
 int idx = 0; 
 Command(s); 
 delay(250);   
 while(Serial1.available()) 
 { 
 buffer[idx++] = Serial1.read(); 
 } 
 buffer[idx] = '\0'; 
 uint16_t rv = 0; 
 switch(buffer[1]) 
 { 
   case 'T' : 
           rv = atoi(&buffer[5]); 
           if (buffer[4] == 1) rv += 1000; 
           break; 
   default : 
           rv = atoi(&buffer[2]); 
           break; 
 } 
 return rv; 
} 
void Command(char* s) 
{ 
 Serial1.print(s); 
 Serial1.print("\r\n"); 
} 
uint16_t calibrateFreshAir() 
{ 
 return Request("G"); 
} 
void setOperatingMode(uint8_t mode) 
{ 
 sprintf(buffer, "K %u", mode); 
 Command(buffer); 
} 

Also take quick note of the two #define statements at the top of the sketch. When you first unbox your sensor you may need to configure it using setOperatingMode(). This sketch is designed to work in polling mode. If you've successfully calibrated and are reading CO2 levels to the terminal you're ready to move on to publishing this to the cloud. Let's connect to Adafruit IO and start visualizing the data.

Publishing CO2 metrics to the cloud

If you haven't connected to Adafruit IO using anduinoWiFi yet, check out this project writeup that will get started. It covers all the details I'm going to gloss over here. Here's the sketch to get you started publishing your CO2 levels every minute.

#include <WiFi101.h>  
#include "Adafruit_MQTT.h"  
#include "Adafruit_MQTT_Client.h"  
#include "AnduinoLCD.h"  
// WiFi parameters  
#define WLAN_SSID       "YOUR_SSID"  
#define WLAN_PASS       "YOUR_PASSWD"  
// Adafruit IO  
#define AIO_SERVER      "io.adafruit.com"  
#define AIO_SERVERPORT  1883  
#define AIO_USERNAME    "YOUR_AIO_USERNAME"  
#define AIO_KEY         "YOUR_AIO_KEY"  
WiFiClient client;  
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);  
/****************************** Feeds ***************************************/  
// Setup feed for co2   
Adafruit_MQTT_Publish carbonDioxide = Adafruit_MQTT_Publish(&mqtt,  AIO_USERNAME "/feeds/co2");  
/*Create an instance of the AnduinoLCD */  
AnduinoLCD LCD = AnduinoLCD(ST7735_CS_PIN, ST7735_DC_PIN, 13);  
static int co2 = 0;  
static int co2Prev = 0;  
#define CZR_STREAMING   0x01 
#define CZR_POLLING     0x02 
char buffer[20] = {0}; 
void setup() {  
Serial.begin(115200);  
delay(3000);  
Serial1.begin(9600); 
//Connect to WiFi & Adafruit.IO  
connectToWiFi();  
connectToAdafruit();  
//Initialize LCD  
LCD.begin();  
LCDinit();  
//CO2 Calibration and initial setup  
//setOperatingMode(CZR_STREAMING); 
//setOperatingMode(CZR_POLLING); 
//calibrateFreshAir(); 
}  
void loop() {  
  // ping adafruit io a few times to make sure we remain connected  
if(! mqtt.ping(3)) {  
  // reconnect to adafruit io  
  if(! mqtt.connected())  
    connect();  
}  
  // Grab the current co2 reading 
  co2 = Request("Z"); 
  //convert int temp to char array  
  char b[20];  
  String str;  
  str=String(co2);  
  for(int i=0; i<str.length(); i++)  
  {  
    b[i]=str.charAt(i);  
  }  
  b[(str.length())+1]=0;  
// Publish data  
if (!carbonDioxide.publish((char*)b)) {  
  Serial.println(F("Failed to publish co2"));  
} else {  
  Serial.print(F("co2 published: "));  
  Serial.println(co2);  
  displayCo2(co2, co2Prev);  
}  
Serial.print("CO2 : ");Serial.println(co2); 
Serial.println(""); 
//prev val stored for LCD  
co2Prev = co2;  
//repeat every 1min  
delay(60000);  
}  
// connect to adafruit io via MQTT  
void connect() {  
Serial.print(F("Connecting to Adafruit IO... "));  
int8_t ret;  
while ((ret = mqtt.connect()) != 0) {  
  switch (ret) {  
    case 1: Serial.println(F("Wrong protocol")); break;  
    case 2: Serial.println(F("ID rejected")); break;  
    case 3: Serial.println(F("Server unavail")); break;  
    case 4: Serial.println(F("Bad user/pass")); break;  
    case 5: Serial.println(F("Not authed")); break;  
    case 6: Serial.println(F("Failed to subscribe")); break;  
    default: Serial.println(F("Connection failed")); break;  
  }  
  if(ret >= 0)  
    mqtt.disconnect();  
  Serial.println(F("Retrying connection..."));  
  delay(5000);  
}  
Serial.println(F("Adafruit IO Connected!"));  
}  
void displayCo2(int co2, int co2Prev)  
{  
  //clear the stale value  
  LCD.setTextColor(ST7735_BLACK);   
  LCD.setTextSize(2);  
  LCD.setTextWrap(true);  
  LCD.setCursor(40,60);  
  LCD.setTextSize(3);  
  LCD.print(co2Prev);  
  LCD.setTextSize(1);  
  LCD.print("ppm");   
  //Print new value  
  LCD.setTextColor(ST7735_WHITE);   
  LCD.setTextSize(2);  
  LCD.setTextWrap(true);  
  LCD.setCursor(40,60);  
  LCD.setTextSize(3);  
  LCD.print(co2);  
  LCD.setTextSize(1);  
  LCD.print("ppm");   
}  
void connectToWiFi()  
{  
// Connect to WiFi access point.  
delay(10);  
Serial.print(F("Connecting to "));  
Serial.println(WLAN_SSID);  
WiFi.begin(WLAN_SSID, WLAN_PASS);  
while (WiFi.status() != WL_CONNECTED) {  
  delay(500);  
  Serial.print(F("."));  
}  
Serial.println(F("WiFi connected!"));  
}  
void connectToAdafruit()  
{  
  // connect to adafruit io  
connect();  
}  
void LCDinit()  
{  
LCD.setBacklight(ON);  
LCD.fillScreen(ST7735_BLACK);  //clear the screen     
LCD.showBanner();              //load Andium Banner  
LCD.setTextColor(ST7735_WHITE);   
LCD.setTextSize(2);  
LCD.setTextWrap(true);  
LCD.setCursor(0,40);  
LCD.print("CO2: ");  
}  
uint16_t Request(char* s) 
{ 
 buffer[0] = '\0';  
 int idx = 0; 
 //send command request 'Z' for CO2 
 Command(s); 
 delay(250);   
 while(Serial1.available()) 
 { 
   buffer[idx++] = Serial1.read(); 
 } 
 buffer[idx] = '\0'; 
 uint16_t rv = 0; 
 rv = atoi(&buffer[2]); 
 return rv; 
} 
void Command(char* s) 
{ 
 Serial1.print(s); 
 Serial1.print("\r\n"); 
} 
uint16_t calibrateFreshAir() 
{ 
 return Request("G"); 
} 
void setOperatingMode(uint8_t mode) 
{ 
 sprintf(buffer, "K %u", mode); 
 Command(buffer); 
} 

That's it!

This thing is super sensitive, you can nearly track room occupancy levels based off the concentration of CO2 in even a well vented room. Time to prove to your professor that it isn't 'diff eq' getting you down, it's the poor ventilation! Time to move class to the beach!

Code

Anduino
An Arduino library for the Andium(Anduino) shield. Transform your Arduino into an AndiumNode.

Comments

Similar projects you might like

Control LED Using Your Voice Command

by IoTBoys

  • 141 views
  • 0 comments
  • 5 respects

Version 2.0 Advanced Attendance System (Without Ethernet)

Project tutorial by GadgetProgrammers

  • 2,166 views
  • 5 comments
  • 40 respects

Get The Arduino Dice

by Ingo Lohs

  • 162 views
  • 0 comments
  • 4 respects

Musical Fairy Lights

Project tutorial by Ian Cumming

  • 249 views
  • 0 comments
  • 4 respects

Fluid Level Indicator and Controller

Project tutorial by Rushabh Jain

  • 525 views
  • 2 comments
  • 7 respects

Critter: Crawling Arduino Robot

Project showcase by Slant Concepts

  • 4,271 views
  • 7 comments
  • 27 respects
Add projectSign up / Login