Robert Korn
Published © Apache-2.0

Environment Air Quality Monitor

An Air Quality monitor to see what happens from day to day.

AdvancedFull instructions provided20 hours2,361
Environment Air Quality Monitor

Things used in this project

Hardware components

bmp180
×1
AM2302
×1
BH1750
×1
MQ2
×1
MQ3
×1
MQ4
×1
MQ5
×1
MQ6
×1
MQ7
×1
MQ8
×1
MQ9
×1
MQ135
×1
TLC1540
×1

Story

Read more

Custom parts and enclosures

GPS Antenna Cover STL

GPS Antenna Case STL

Linkit One Engraving Gcode

Sensors Engraving Gcode

GPS Antenna Cover SCAD

GPS Antenna Case SCAD

Schematics

Schematic

Code

Arduino Sketch

Arduino
//****************************************************************
//*  Name    : Air Quality Monitor                               *
//*  Author  : Robert Joseph Korn                                *
//*  Notice  : Copyright (c) 2015 Open Valley Consulting Corp    *
//*  Date    : 10/18/15                                          *
//*  Version : 1.1                                               *
//*  Notes   :                                                   *
//*          :                                                   *
//****************************************************************
#include <LFlash.h>
#include <LSD.h>
#include <LStorage.h>
#include <LGPS.h>
#include "LDHT.h"
#include <Wire.h>
#include "Barometer.h"
#include <BH1750FVI.h>

//uncomment the storage you want to use
// #define Drv LFlash          // use Internal 10M Flash
#define Drv LSD           // use SD card
#define DEBUG true  // Comment to disable debug
#define DHTPIN 6     // what pin we're connected to

// Uncomment whatever type you're using!
#define DHTTYPE DHT22   // DHT 11 21 22

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

gpsSentenceInfoStruct info; //needed to get GPS data

int da = 5; // Device Address
int ck = 3; // Clock
int di = 4; // Data In
int cs = 2; // Chip Select

int val = 0;
int adcv[12];
int val1 = 0;
int val2 = 0;
int val3 = 0;
int val4 = 0;
int val5 = 0;
int val6 = 0;
int val7 = 0;
int val8 = 0;
int val9 = 0;
int val10 = 0;
int val11 = 0;
int dbl = 0;
int tmp = 0;
byte chn = 0;

float hum = 0;
float tem = 0;
float far = 0;
float hi = 0;
float dew = 0;
float temperature = 0;
float pressure = 0;
float alt;
uint16_t lux = 0;
double latitude = 0.00;
double longitude = 0.00;
float altitude = 0.00;
float dop = 100.00; //dilution of precision
float geoid = 0.00;
float k_speed = 0.00, m_speed = 0.00; //speed in knots and speed in m/s
float track_angle = 0.00;
int fix = 0;
int hour = 0, minute = 0, second = 0;
int sat_num = 0; //number of visible satellites
int day = 0, month = 0, year = 0;
String time_format = "00:00:00", date_format = "00:00:0000";
String lat_format = "0.00000", lon_format = "0.00000";
char file[15] = "";
int pause = 5000; //time in milliseconds between two logs

BH1750FVI LightSensor;

Barometer myBarometer;

LDHT dht(DHTPIN, DHTTYPE);

void getadcval() {

 for(dbl=0;dbl<2;dbl++) { 
    val = 0 ;
    digitalWrite(cs, LOW); 
    pulseck(2);  //Strobe CS 
    dataxfer();   
    digitalWrite(cs, HIGH);   
    pulseck(50); // Conversion Clock 44 cycles needed  
 }
}

void dataxfer(){

 for(tmp=0;tmp<4;tmp++) { 

   if (bitRead(chn, 3 - tmp) ){
      digitalWrite(da, HIGH); 
   } else {  
      digitalWrite(da, LOW);     
   }

   digitalWrite(ck, HIGH);   
   digitalWrite(ck, LOW);   
      if(digitalRead(di) > 0){
     val++;
   }
   val=val<<1; 

 }
 for(tmp=0;tmp<6;tmp++) {  
   digitalWrite(ck, HIGH);   
   digitalWrite(ck, LOW);   
      if(digitalRead(di) > 0){
     val++;
   }
   val=val<<1; 
 }
    val=val>>1; 
}

void pulseck(uint8_t cnt) {
 for(tmp=0;tmp<cnt;tmp++) {  
   digitalWrite(ck, HIGH);   
   digitalWrite(ck, LOW);   
 }
}

void setup()
{

 pinMode(ck, OUTPUT);     
 pinMode(da, OUTPUT);     
 pinMode(cs, OUTPUT);     
 pinMode(di, INPUT);     
 digitalWrite(cs, HIGH);   
 digitalWrite(ck, LOW);   
 digitalWrite(da, LOW);   
 
  Serial1.begin(9600);
  Serial1.println();
  Serial1.print("Initializing...");
  
  Serial.begin(115200);
  
  Serial.print("Initializing memory...");
  
  pinMode(10, OUTPUT); //needed for SD card
  
  if(!Drv.begin())
  {
    Serial.println("Error initalizing memory.");  
    while(true);
  }
  
  Serial.println("OK.");
  
  myBarometer.init();
  
  LightSensor.begin();
  
 /*
 Set the address for this sensor 
 you can use 2 different address
 Device_Address_H "0x5C"
 Device_Address_L "0x23"
 you must connect Addr pin to A3 .
 */
  LightSensor.SetAddress(Device_Address_H);//Address 0x5C
  // lightMeter.SetAddress(Device_Address_L); //Address 0x23
 //-----------------------------------------------
  /*
   set the Working Mode for this sensor 
   Select the following Mode:
    Continuous_H_resolution_Mode
    Continuous_H_resolution_Mode2
    Continuous_L_resolution_Mode
    OneTime_H_resolution_Mode
    OneTime_H_resolution_Mode2
    OneTime_L_resolution_Mode
    
    The data sheet recommanded To use Continuous_H_resolution_Mode
  */

  LightSensor.SetMode(Continuous_H_resolution_Mode);
   
  LGPS.powerOn();
  Serial.println("GPS started.");
    dht.begin();
  Serial.println("Setup Done");
  Serial.println("");

}

void loop()
{
     Serial1.println();
     Serial1.print("Loop");
    
    Serial.println("");
    Serial.println("");
    Serial.println("------------------------------------------------------------------");
    Serial.println("");
    Serial.println("BMP Sensor");

   temperature = myBarometer.bmp085GetTemperature(myBarometer.bmp085ReadUT()); //Get the temperature, bmp085ReadUT MUST be called first
   pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP()) ;//Get the ressure
   alt = myBarometer.calcAltitude(pressure); //Uncompensated caculation - in Meters
   pressure = pressure / 100 ;
   alt = alt + 60 ;
   
  Serial.print("Temperature: ");
  Serial.print(temperature, 2); //display 2 decimal places
  Serial.println(" deg C");

  Serial.print("Pressure: ");
  Serial.print(pressure, 2); //whole number only.
  Serial.println(" KPa");

  Serial.print("Altitude: ");
  Serial.print(alt, 2); //display 2 decimal places
  Serial.println(" m");

  Serial.println();

    Serial.println("");
    Serial.println("DHT Sensor");
   if(dht.read())
    {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  hum = dht.readHumidity();
  // Read temperature as Celsius
  tem = dht.readTemperature();
  // Read temperature as Fahrenheit
  far = dht.readTemperature(false);
  } 
  // Check if any reads failed and exit early (to try again).
  if (isnan(hum) || isnan(tem) || isnan(far)) {
    Serial.println("Failed to read from DHT sensor!");
  }
  else 
  {
  // Compute heat index
  // Must send in temp in Fahrenheit!
  hi = dht.readHeatIndex(tem, hum);

  Serial.print("Humidity: "); 
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temperature: "); 
  Serial.print(tem);
  Serial.println(" *C ");
  Serial.print("Temperature: "); 
  Serial.print(far);
  Serial.println(" *F");
  Serial.print("Heat index: ");
  Serial.print(hi);
  Serial.println(" *C");
  Serial.print("DewPoint = ");
  dew = dht.readDewPoint(tem,hum);
  Serial.print(dew);
  Serial.println("C");
  }
  
  Serial.println("");
  Serial.println("BH1750 Sensor "); 
  lux = LightSensor.GetLightIntensity();// Get Lux value
  Serial.print("Light: ");
  Serial.print(lux);
  Serial.println(" lux");
  Serial.println("");
  Serial.println("");

   for(chn=0;chn<11;chn++) { 
      getadcval();
      getadcval();
      adcv[chn] = val ;
      Serial.print("Channel: ");
      Serial.print(chn);
      Serial.print(" - ");
      Serial.println(val);
      Serial.println();
   }

   Serial.println();
  
  if (getData(&info) > 3)
  {
    String str = "";
    str += date_format;
    str += ",";
    str += time_format;
    str += ",";
    str += lat_format;
    str += ",";
    str += lon_format;
    str += ",";
    str += altitude;
    str += ",";
    str += dop;
    str += ",";
    str += geoid;
    str += ",";
    str += track_angle;
    str += ",";
    str += m_speed;
    str += ",";
    str += k_speed;
    str += ",";
    str += fix;
    str += ",";
    str += sat_num;
    str += ",";
    str += hum;
    str += ",";
    str += tem;
    str += ",";
    str += far;
    str += ",";
    str += hi;
    str += ",";
    str += pressure;
    str += ",";
    str += temperature;
    str += ",";
    str += alt;
    str += ",";
    str += lux;
    str += ",";

    for(chn=0;chn<11;chn++) { 
       str += adcv[chn];
       str += ",";
   }

    Serial1.print(str);
    Serial.println(str);
    String file_name = date_format;
    file_name += ".txt";
    file_name.toCharArray(file, 15);
    Serial.println(file);
    LFile dataFile = Drv.open(file, FILE_WRITE);
    if (dataFile)
    {
      dataFile.println(str);
      dataFile.close();
      Serial.println("File written.");
    }
    else Serial.println("Error opening file.");


  }
  else Serial.println("Less then 4 satelites.");


  delay(pause);
}

/**
*Converts degrees from (d)ddmm.mmmm to (d)dd.mmmmmm
*@param str the string rappresentation of the angle in (d)ddmm.mmmm format
*@param dir if true the direction is south, and the angle is negative.
*@return the given angle in dd.mmmmmm format.
*/
float convert(String str, boolean dir)
{
  double mm, dd;
  int point = str.indexOf('.');
  dd = str.substring(0, (point - 2)).toFloat();
  mm = str.substring(point - 2).toFloat() / 60.00;
  return (dir ? -1 : 1) * (dd + mm);
}

/**
*Gets gps informations
*@param info gpsSentenceInfoStruct is a struct containing NMEA sentence infomation
*@return the number of hooked satellites, or 0 if there was an error getting informations
*/
int getData(gpsSentenceInfoStruct* info)
{
  Serial.println("Collecting GPS data.");
  LGPS.getData(info);
  Serial.println((char*)info->GPGGA);
  if (info->GPGGA[0] == '$')
  {
    Serial.print("Parsing GGA data....");
    String str = (char*)(info->GPGGA);
    str = str.substring(str.indexOf(',') + 1);
    hour = str.substring(0, 2).toInt();
    minute = str.substring(2, 4).toInt();
    second = str.substring(4, 6).toInt();
    time_format = "";
    time_format += hour;
    time_format += ":";
    time_format += minute;
    time_format += ":";
    time_format += second;
    str = str.substring(str.indexOf(',') + 1);
    latitude = convert(str.substring(0, str.indexOf(',')), str.charAt(str.indexOf(',') + 1) == 'S');
    int val = latitude * 1000000;
    String s = String(val);
    lat_format = s.substring(0, (abs(latitude) < 100) ? 2 : 3);
    lat_format += '.';
    lat_format += s.substring((abs(latitude) < 100) ? 2 : 3);
    str = str.substring(str.indexOf(',') + 3);
    longitude = convert(str.substring(0, str.indexOf(',')), str.charAt(str.indexOf(',') + 1) == 'W');
    val = longitude * 1000000;
    s = String(val);
    lon_format = s.substring(0, (abs(longitude) < 100) ? 2 : 3);
    lon_format += '.';
    lon_format += s.substring((abs(longitude) < 100) ? 2 : 3);

    str = str.substring(str.indexOf(',') + 3);
    fix = str.charAt(0) - 48;
    str = str.substring(2);
    sat_num = str.substring(0, 2).toInt();
    str = str.substring(3);
    dop = str.substring(0, str.indexOf(',')).toFloat();
    str = str.substring(str.indexOf(',') + 1);
    altitude = str.substring(0, str.indexOf(',')).toFloat();
    str = str.substring(str.indexOf(',') + 3);
    geoid = str.substring(0, str.indexOf(',')).toFloat();
    Serial.println("done.");
    
    if (info->GPRMC[0] == '$')
    {
      Serial.print("Parsing RMC data....");
      str = (char*)(info->GPRMC);
      int comma = 0;
      for (int i = 0; i < 60; ++i)
      {
        if (info->GPRMC[i] == ',')
        {
          comma++;
          if (comma == 7)
          {
            comma = i + 1;
            break;
          }
        }
      }

      str = str.substring(comma);
      k_speed = str.substring(0, str.indexOf(',')).toFloat();
      m_speed = k_speed * 0.514;
      str = str.substring(str.indexOf(',') + 1);
      track_angle = str.substring(0, str.indexOf(',')).toFloat();
      str = str.substring(str.indexOf(',') + 1);
      day = str.substring(0, 2).toInt();
      month = str.substring(2, 4).toInt();
      year = str.substring(4, 6).toInt();
      date_format = "20";
      date_format += year;
      date_format += "-";
      date_format += month;
      date_format += "-";
      date_format += day;
      Serial.println("done.");
      return sat_num;
    }
  }
  else
  {
    Serial.println("No GGA data");
  }
  return 0;
}

Credits

Robert Korn

Robert Korn

15 projects • 27 followers
I Made the Internet of Things before people had a name for it.

Comments