James Yu
Published © GPL3+

Personal Air Monitor

An air monitor that you can connect to using Cayenne, accessible anywhere in the world!

IntermediateFull instructions provided2 hours1,170
Personal Air Monitor

Things used in this project

Hardware components

SparkFun ESP8266 Thing - Dev Board
SparkFun ESP8266 Thing - Dev Board
×1
DHT22 Temperature Sensor
DHT22 Temperature Sensor
×1
Adafruit BMP180 Barometric Pressure/Temperature/Altitude Sensor- 5V ready
You can use the newer barometric pressure sensor, the BMP280, but it will require changes to the library inclusions, as well as calls to the sensor.
×1
Resistor 10k ohm
This is used to pull up the DHT22 data line to power.
×1
Craft Basket
Used as a case for the Sensor Station. The open slots around the exterior allow air to flow into the case, allowing sensor readings to be accurate.
×1
USB-Micro - USB-A M-M Cable
Simple cable, used for charging and programming.
×2
Jumper wires (generic)
Jumper wires (generic)
I used solid-core jumpers of various sizes.
×23
Breadboard (generic)
Breadboard (generic)
×1

Software apps and online services

Cayenne
myDevices Cayenne
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Electrical Tape
Generic electrical tape. I also used clear tape for the enclosure.
Scissors
Thin Screwdriver
This was really useful for bending wires into holes.

Story

Read more

Schematics

Personal Air Monitor Fritzing Diagram

Schematic for the Sensor Station. Note that you need to put leads underneath the Thing Dev and BMP180 in certain places; these are indicated by the file.

Code

Personal Air Monitor Sensor Station Code

Arduino
This is code for the SparkFun ESP8266 Thing Dev Personal Air Monitor Sensor Station. To upload, replace the five credentials needed for Cayenne with your own. See the in-code comments as well as the project information on how to do this.
/*
   This is a code for the Personal Air Monitor Sensor Station (SparkFun Thing Dev with ESP8266 that allows sensor data to be posted to Cayenne.
   Every 5 seconds, the board checks the onboard BMP180 Barometric Pressure Sensor and DHT22 Temperature and Humidity Sensor for data.
   This data is then uploaded over 4 "channels":
     1. Humidity, in %. Read from the DHT22.
     2. Temperature, in degrees celsius. Can be converted to Fahrenheit using T(Celsius)*1.8 + 32 = T(Fahrenheit).
       This value is either measured from the DHT22, BMP180, or an average of both, depending on availability.
     3. Pressure, in hPa. This pressure value, taken from the BMP180, is dependent on a reference sea level pressure. You can either use a default 1013 hPa value (mean sea level pressure),
       or find your local pressure online.
     4. Altitude, in metres. Read from the BMP180, calculated from pressure.
*/

// Libraries necessary for operating the sensors. Adafruit provides unified libraries that use Adafruit_Sensor.h to create common functions across different libraries.
#include <Adafruit_Sensor.h>
#include <DHT.h> // DHT22 library. Can also be used with DHT11, if you'd like.
#include <DHT_U.h>
DHT_Unified dht(12, DHT22); // An instance of the sensor, defined as a DHT22 and using pin 12. Object created as "dht" to be referred to in the code.
#include <Wire.h> // I2C library, used for the BMP180.
#include <Adafruit_BMP085_U.h> // Compatible with BOTH BMP085 AND BMP180.
Adafruit_BMP085_Unified BMP180 = Adafruit_BMP085_Unified(18001); // An instance of the BMP180, designated as BMP180 and identified with an arbitrary ID number.

// Cayenne information. WiFi SSID and password are those of your WiFi network, which should be on your router. The Cayenne username, password and clientID are available on the dashboard when you log in.
// Upon logging in, you should be able to add "SparkFun Thing Dev" as a device. It will then give you the information you need and wait for the board to connect.
#include <CayenneMQTTESP8266.h>
char ssid[] = "SSID"; // Your network name.
char wifiPassword[] = "password"; // Your network password.

char username[] = "username";
char password[] = "password";
char clientID[] = "clientID";

void setup() { // This runs once, initializing the sensors and Cayenne.
  BMP180.begin();
  dht.begin();
  Cayenne.begin(username, password, clientID, ssid, wifiPassword);
}

// These variables are used to hold data from the sensors. Status variables are boolean; that is, they are either true or false. They are used to tell whether a sensor is active or not.
// Value variables are floats; they are floating-point integers that return integers with two decimal places. These hold actual data.
boolean humidityStatus;
boolean temperatureStatus;
float humidityValue;
float temperatureValue;
float bmpTempValue;
float pressureValue;
float altitudeValue;
boolean bmpStatus;
float temperature;

void loop() { // Runs infinitely.
  Cayenne.loop(); // Loop function for using Cayenne.

  // Make a sensor event object for the BMP180 and get data using it.
  sensors_event_t event;
  BMP180.getEvent(&event);
  if (event.pressure) // If data is available:
  {
    // Get values and save.
    bmpStatus = true;
    pressureValue = event.pressure;
    BMP180.getTemperature(&temperature);
    float seaLevelPressure = 1013; // Replace this with your local sea level pressure if you wish.
    altitudeValue = BMP180.pressureToAltitude(seaLevelPressure, event.pressure);
  }
  else
  {
    bmpStatus = false; // If sensor is not available, return "false".
  }

  // Make another sensor event for the DHT22 and use it to get data as well.
  sensors_event_t event1;
  dht.temperature().getEvent(&event1);
  if (isnan(event1.temperature)) { // If nothing returned:
    temperatureStatus = false;
  }
  else { // If we have data, get it.
    temperatureStatus = true;
    temperatureValue = event1.temperature;
  }
  dht.humidity().getEvent(&event1);
  if (isnan(event1.relative_humidity)) { // Return false if no data.
    humidityStatus = false;
  }
  else { // Get data and save it.
    humidityStatus = true;
    humidityValue = event1.relative_humidity;
  }

  // Functions to write to Cayenne.
  if (humidityStatus == true) // If humidity data was available:
  {
    Cayenne.virtualWrite(0, humidityValue); // Channel 0, the first channel. Used for humidity.
  }
  if (temperatureStatus == true) // If DHT22 temperature data was available:
  {
    if (bmpStatus == true) // If the BMP180 temperature was also available, make an average.
    {
      float averageTemp = (temperature + temperatureValue) / 2;
      Cayenne.virtualWrite(1, averageTemp); // Channel 1, the second channel, is used for temperature.
    }
    else
    {
      Cayenne.virtualWrite(1, temperatureValue); // If the BMP180 data wasn't available, just use the DHT22 data.
    }
  }
  else if (bmpStatus == true) // If the DHT22 temperature data was not available but the BMP180 data was, use that.
  {
    Cayenne.virtualWrite(1, temperature);
  }
  if (bmpStatus == true) // If the BMP180 pressure and altitude values are available, send them.
  {
    Cayenne.virtualWrite(2, pressureValue); // Channel 2, the third channel. Used for pressure.
    Cayenne.virtualWrite(3, altitudeValue); // Channel 3, the fourth channel. Used for altitude.
  }
  delay(5000); // Wait 5 seconds to allow Cayenne to process information in time.
}

Credits

James Yu

James Yu

2 projects • 13 followers
Hobbyist fascinated with technology and Arduino, currently studying at UBC.

Comments