Project tutorial

Air Surfer © GPL3+

It is a device that measures CO2 levels, inside and outside temperatures, and humidity.

  • 24,018 views
  • 25 comments
  • 128 respects

Components and supplies

Apps and online services

About this project

As a civil engineer I'm very well aware of how ventilation systems should work at home. So to measure the quality of the air in my apartment I purchased a CO2 monitor and I really liked it because it not only showed CO2 levels but also room temperature.

However, this wasn't enough for me. I wanted to measure more parameters, so I was looking for an appropriate device. I found some that were ridiculously expensive, so I decided to make my own.

At that time I already had experience programming arduino controllers for a pump station with solenoid valves controlling different pipeline branches.

I made a project on paper and than ordered necessary tools and sensors.

Base

I wanted it to have a huge screen 10inch minimum, but it would empty my pockets very fast. I decided to be realistic and chose arduino mega 2560 R3 with tft 3.2 420x380 display. This setup required minimum wiring because the display connects straight to the arduino board.

Unfortunately, display that I ordered from Aliexpress was so cheap that it didn't work very well. There were white small dots appearing with the time and inverted colors. I tried different libraries and different controllers but it didn't help. So I adjusted colors in the code and added screen refreshing at 12.00 pm and 12.00 am.

Sensors

The most expensive part of the project was mh-z19 CO2 sensor. It is relatively cheap among other CO2 sensors while providing reliable measurements and auto calibration function.

And while other modules were relatively easy to install, this sensor didn't have much info at its datasheet so I looked on forums for a code and combined all the information. As a result, now everything works perfect and even better than the previous sensor.

However, it took 24h for it to calibrate itself, so at first its readings were inconsistent. Auto calibration is simple. When I leave my apartment there is no one who consumes oxygen, so CO2 level drops to the outside level, which is 400ppm. If readings are somewhere below this figures sensor calibrates.

It can communicate via UART and PWM. I chose the first one because I think it is more reliable.

Then I used SI7021 temperature and humidity sensor for indoor monitoring that uses I2C protocol and connects to SDA and SCL pins. Not expensive, industrial high precision. I like it because I didn't have any troubles with it at all.

For outside temperatures I used ds18b20 enclosed in a stainless steel capsule. Cheap and accurate readings. However, it requires 4,7k Ohms resistor, so just don't forget about it. Communication is via 1-wire.

For the time I purchased DS 1307 RTC module that used I2C.

Then 3 LEDs for CO2 levels. For 400-800ppm is the green LED, for 800-1200ppm the orange LED and for 1200ppm - and above is the red one.

Plus, 3 stainless steel buttons with LEDs. The left one is for hours adjusting. The middle one is for minutes and the right one is for text color changing.

Additionally, I wired up a photoresistor to adjust LEDs brightness. I didn't want them to shine too bright at nights.

Power

For power supply I drilled a hole in the bottom and placed there a DC connector:

The problem was that I didn't have any suitable power supply sources. I had only 19v and 15v supply adapters while recommended voltage for Arduino is 7-12v. However, I had a bunch of LM2696 DC-DC adjustable voltage regulators.

I put it inside of the box and adjusted it for 7 volts. I found out that my Arduino is heating up very quickly under 12 volts, so I chose the recommended minimum. As a result, now it can be supplied from various power sources.

For outside temperature sensor I used aviator connectors and telephone wires.

Box

This was the major issue for me because I didn't have a 3D printer. I tried to make it from polymer clay at first but it didn't hold its shape well. Plus, I burned it ones in an oven.

The second attempt was with 6mm plywood. it was mostly fine but it was difficult to cut. I had to use an electrical saw and a dremel tool.

The final and the most successful one was from 3mm plywood (which was difficult to find) that I was able to cut without electrical equipment and used only box cutter knife and some sandpaper. Covered it with acrylic paint, and as a result, it looks much better.

Cost

  • Arduino mega 2560 R3 - 8,27$ (480Rub)
  • Display TFT 3.2 480x320 - 8$ (400Rub)
  • RTC DS1307 Module - 0,55$ (32Rub)
  • CO2 mh-z19 sensor - 20$ (1160Rub)
  • Temperature&humidity sensor Si7021 - 2$(118Rub)
  • Temperature sensor DS18b20 in capsule - 1,14$ (66Rub)
  • Photoresistor - 1$/50pieces (65Rub)
  • LEDs - 0,67$/100pieces (39Rub)
  • Stainless steel push buttons - 5,07$/3pcs (294Rub)
  • GX12-3 pin aviation plug (set) - 1,17$ (68Rub)
  • DC connector 1,25$/10pcs (73Rub)
  • LM2596 DC-DC adjustable Voltage regulator - 0,69$ (40Rub)
  • Power adapter 12v - 2,14$ (120Rub)
  • Wires - 1,78$ (100Rub)
  • Plywood 3mm - 1,78$ (100Rub)

Total 55,51$ (3155 Rub)

Code

Air surfer codeArduino
#include <Wire.h>
#include "RTClib.h"
//#include <Arduino.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include <SparkFunHTU21D.h>
#include <OneWire.h> 
#include <DallasTemperature.h>
#include <UTFT.h>

#define ONE_WIRE_BUS 9
#define GREENLED 5
#define YELLOWLED 7
#define REDLED 8
#define BUTTONLED 11

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

UTFT myGLCD(CTE32HR, 38, 39, 40, 41);  

HTU21D myHumidity;
RTC_DS1307 rtc;
 extern uint8_t Ubuntu[];
 
byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; 
unsigned char response[9];
unsigned int ppm;
unsigned long time;
int photocellReading;

int hourupg;
int minupg;

float humd;
float temp;
int tcolor;
int Z; //LED brightness
boolean Reset = false; // for reseting display;

void lamps(void) {

  //CO2
if (ppm<800){  
  myGLCD.setColor(255,140,255); //green
  myGLCD.fillCircle(450, 87, 12);
  analogWrite(GREENLED, Z);
  analogWrite(YELLOWLED, 0);
  analogWrite(REDLED, 0);
  }
   if (ppm>800 & ppm<1200) {  
  myGLCD.setColor(70,70,255); //Yellow
  myGLCD.fillCircle(450, 87, 12);
  analogWrite(GREENLED, 0);
  analogWrite(YELLOWLED, Z);
  analogWrite(REDLED, 0);
} 
  if (ppm>1200){  
  myGLCD.setColor(VGA_AQUA);
  myGLCD.fillCircle(450, 87, 12);
  analogWrite(GREENLED, 0);
  analogWrite(YELLOWLED, 0);
  analogWrite(REDLED, Z);
  } 
  
  //Hum
  if (humd>30 & humd<50)  {
  myGLCD.setColor(255,140,255); //green
  myGLCD.fillCircle(450, 149, 12);
  }
   if (humd>20 & humd<30)  {
  myGLCD.setColor(70,70,255); //Yellow
  myGLCD.fillCircle(450, 149, 12);
  }
  if (humd<20)  {
 myGLCD.setColor(70,70,255); //Yellow
 myGLCD.fillCircle(450, 149, 12);
 }
  if (humd>50 & humd<60)  {
  myGLCD.setColor(70,70,255); //Yellow
  myGLCD.fillCircle(450, 149, 12);
  }
   if (humd>60)  {
 myGLCD.setColor(VGA_AQUA);
 myGLCD.fillCircle(450, 149, 12);
  }
  
  //Temp ins
 
  if (temp>20 & temp<27) {
  myGLCD.setColor(255,140,255); //green
  myGLCD.fillCircle(450, 213, 12);
  } else {
myGLCD.setColor(70,70,255); //Yellow
myGLCD.fillCircle(450, 213, 12);
   }
  //Tempouts
   
  if (sensors.getTempCByIndex(0)<10) {
myGLCD.setColor(70,70,255); //Yellow
myGLCD.fillCircle(450, 278, 12);
} else {
 myGLCD.setColor(255,140,255); //green
 myGLCD.fillCircle(450, 278, 12);
}}

void drawmain(void) {
myGLCD.setFont(Ubuntu);
if (tcolor==0) myGLCD.setColor(VGA_BLACK);
if (tcolor==1) myGLCD.setColor(VGA_SILVER);
if (tcolor==2) myGLCD.setColor(250,10,250);
if (tcolor==3) myGLCD.setColor(200,100,200);
if (tcolor==4) myGLCD.setColor(100,200,200);
if (tcolor==5) myGLCD.setColor(10,200,200);
if (tcolor==6) myGLCD.setColor(200,200,100);
if (tcolor==7) myGLCD.setColor(250,250,10);
if (tcolor==8) myGLCD.setColor(10,10,250);
if (tcolor==9) myGLCD.setColor(10,250,10);
if (tcolor==10) myGLCD.setColor(250,10,10);
if (tcolor==11) myGLCD.setColor(VGA_TEAL);
if (tcolor==12) myGLCD.setColor(VGA_AQUA);
  DateTime now = rtc.now();
   // Time
if (now.hour()<10) 
 { 
myGLCD.print("0", 190, 7);
myGLCD.printNumI(now.hour(), 215, 7);
 }
 else
 {
myGLCD.printNumI(now.hour(), 190, 7);
 }
 myGLCD.print(":", 240, 5);
 if (now.minute()<10) 
 { 
  myGLCD.print("0", 265, 7);
myGLCD.printNumI(now.minute(), 290, 7);
 }
 else
 {
  myGLCD.printNumI(now.minute(), 265, 7);
 }
//myGLCD.setColor(VGA_BLACK);
myGLCD.print("CO2", 18, 74);

  if (ppm > 999)
{
 
myGLCD.printNumI(ppm, 250, 74);
}
else
{
myGLCD.print(" ", 250, 74);
myGLCD.printNumI(ppm, 275, 74);
}
myGLCD.print("ppm", 348, 74);
myGLCD.print("Humidity", 18, 136);
myGLCD.printNumI(humd, 343, 136); //humd
myGLCD.print("%", 398, 136);
myGLCD.print("Temp(in)", 18, 200);
if (temp>=0) {
  
  if (temp<10) {
myGLCD.print(" ", 275, 200);
myGLCD.print("+", 300, 200); //temp
myGLCD.printNumF(temp,1, 325, 200);
}
else
{ 
myGLCD.print("+", 275, 200); //temp
myGLCD.printNumF(temp,1, 300, 200);
}
}

if (temp<0){
  if (temp>-10) {
    myGLCD.print(" ", 275, 200);
myGLCD.printNumF(temp,1, 300, 200);
}
else
{ 
 myGLCD.printNumF(temp,1, 275, 200);
}
}

myGLCD.print("C", 398, 200);
myGLCD.print("Temp(out)", 18, 265);
if (sensors.getTempCByIndex(0)<-100) {
  myGLCD.print("Empty", 300, 265);
}
else{
if (sensors.getTempCByIndex(0)>=0) {
  if (sensors.getTempCByIndex(0)<10) {
myGLCD.print(" ", 275, 200);
myGLCD.print("+", 300, 265);
myGLCD.printNumF(sensors.getTempCByIndex(0),1, 325, 265);
}
else
{ 
myGLCD.print("+", 275, 265);
myGLCD.printNumF(sensors.getTempCByIndex(0),1, 300, 265);
}}
if (sensors.getTempCByIndex(0)<0){
  if (sensors.getTempCByIndex(0)>-10) {
    myGLCD.print(" ", 275, 200);
myGLCD.printNumF(sensors.getTempCByIndex(0),1, 300, 265);
}
else
{ 
 myGLCD.printNumF(sensors.getTempCByIndex(0),1, 275, 265);}}

myGLCD.print("C", 398, 265);

}}
 
 
void dateandtime(void) {
  DateTime now = rtc.now();
hourupg=now.hour();
minupg=now.minute();
   //time adjustment
      if (digitalRead(3) == LOW) {
      if (minupg==59)
    {
      minupg=0;
    }
    else
    {
      minupg=minupg+1;
    }
     rtc.adjust(DateTime(0,0,0,hourupg,minupg,0));
 }

    if (digitalRead(2) == LOW) {
      if(hourupg==23)
    {
      hourupg=0;
    }
    else
    {
      hourupg=hourupg+1;
    }
    rtc.adjust(DateTime(0,0,0,hourupg,minupg,0));
    }}

void co2(void) {
 Serial3.write(cmd, 9);
  memset(response, 0, 9);
  Serial3.readBytes(response, 9);
  int i;
  byte crc = 0;
  for (i = 1; i < 8; i++) crc+=response[i];
  crc = 255 - crc;
  crc++;

  if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) ) {
    } else {
    unsigned int responseHigh = (unsigned int) response[2];
    unsigned int responseLow = (unsigned int) response[3];
    ppm = (256*responseHigh) + responseLow;
  }
}
void th(void) {
  humd = myHumidity.readHumidity();
  temp = myHumidity.readTemperature();
  sensors.requestTemperatures(); // Send the command to get temperature readings
}

void photosensor(void) {
  photocellReading = analogRead(12);
  if (photocellReading < 150) {
  // Serial.println(" - Dark");
     analogWrite(BUTTONLED, 5);
     Z=25;
   } else if (photocellReading < 300) {
  // Serial.println(" - Dim");
    analogWrite(BUTTONLED, 50);
    Z=80;
  } else if (photocellReading < 700) {
   // Serial.println(" - Light");
    analogWrite(BUTTONLED, 100);
    Z=120;
    } else if (photocellReading < 900) {
  // Serial.println(" - Bright");
     analogWrite(BUTTONLED, 150);
     Z=150;
  }  else {
  // Serial.println(" - Very bright");
    analogWrite(BUTTONLED, 200);
    Z=200;
  }
// Serial.print(photocellReading);
}

void screenreset(void) {
 if(((hourupg==0 && minupg==0) || (hourupg==12 && minupg==0)) && Reset==false) {
myGLCD.clrScr();
myGLCD.fillScr(VGA_WHITE);  //due to inverted colors on my display
myGLCD.setBackColor(VGA_WHITE); //due to inverted colors on my display
Reset=true;}
if((hourupg==0 || hourupg==12)&& minupg>0) {
 Reset=false; 
}}

void setup(void) {
myGLCD.InitLCD();
myGLCD.clrScr();
myGLCD.fillScr(VGA_WHITE); //due to inverted colors on my display
myGLCD.setBackColor(VGA_WHITE); //due to inverted colors on my display
Serial3.begin(9600);
//Serial.begin(9600);
  sensors.begin();
  myHumidity.begin();
  tcolor=0;
rtc.begin();
pinMode(GREENLED, OUTPUT);
pinMode(YELLOWLED, OUTPUT);
pinMode(REDLED, OUTPUT);
pinMode(BUTTONLED, OUTPUT);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
Z=0;
}

void loop(void) {

co2(); 
photosensor();
dateandtime();
th();
 
 if (digitalRead(4) == LOW){
 tcolor=tcolor+1;
 }
if (tcolor>=13) tcolor=0;
 
drawmain();
lamps();
screenreset();

}

Schematics

Basic connections
Untitled sketch 2 bb99 hwyffwrql9

Comments

Similar projects you might like

Binary Clock

Project showcase by pdio

  • 100 views
  • 4 comments
  • 1 respect

Central Heating Boiler Control Box

Project tutorial by Peter Groeneveld

  • 2,632 views
  • 6 comments
  • 17 respects

Arduino - Set Schedule via Web

Project tutorial by phpoc_man

  • 404 views
  • 2 comments
  • 13 respects

Protect Your Room with Fingerprints for Under $20

Project tutorial by Srivishnu Piratla

  • 3,137 views
  • 1 comment
  • 11 respects

Sump Pit Alarm

Project showcase by loupalladino

  • 110 views
  • 0 comments
  • 3 respects

Smart Talking Humanoid Robot Just with Arduino!

Project tutorial by ashraf_minhaj

  • 1,079 views
  • 4 comments
  • 10 respects
Add projectSign up / Login