How to Build an Affordable Air Quality Sensor for Your Home

As a full-stack developer and maker, I‘m always looking for ways to apply my coding and hardware skills to solve real-world problems. One issue that‘s increasingly on my radar is indoor air pollution. Consider these statistics from the EPA:

  • Americans, on average, spend approximately 90 percent of their time indoors, where the concentrations of some pollutants are often 2 to 5 times higher than typical outdoor concentrations.
  • Indoor air pollutants have been ranked among the top five environmental risks to public health.
  • Poor indoor air quality costs the US economy over $10 billion per year in lost productivity and medical expenses.

Some of the most common indoor air pollutants include:

  • Particulate matter (PM2.5 and PM10) from cooking, heating, smoking, and outdoor sources
  • Volatile Organic Compounds (VOCs) emitted by paints, cleaning supplies, personal care products, furniture and building materials
  • Carbon dioxide (CO2) from occupant respiration and combustion appliances
  • Mold and mildew from excess indoor humidity
  • Radon, a radioactive gas that can enter homes through cracks in the foundation

Exposure to these pollutants can cause both short and long-term health effects like headaches, fatigue, allergies, asthma attacks, respiratory illnesses, heart disease, and even cancer. Groups that are especially vulnerable include children, the elderly, and those with pre-existing respiratory conditions.

Clearly, monitoring and controlling indoor air quality should be a priority in any healthy home. But how do you actually measure something invisible like air pollution? That‘s where air quality sensors come in.

Air Quality Sensor Options

There are a few different options when it comes to monitoring indoor air quality:

  1. Hire a professional inspector to test your air quality (~$400-$800)
  2. Purchase an off-the-shelf consumer air quality monitor ($150-$300)
  3. Build your own WiFi-connected air quality sensor using an IoT microcontroller and low-cost sensors ($50-$150)

While professional testing provides the most accurate results, it‘s expensive and only gives you a one-time snapshot unless you pay for continued monitoring. Consumer air quality monitors like the Awair or Foobot are more affordable and provide real-time data and smartphone connectivity.

However, I believe the DIY route provides the best balance of cost, functionality, and flexibility for the tech-savvy home owner. Plus you get the satisfaction and learning experience of building it yourself!

Let‘s dive into the details of selecting components, wiring, programming, and deploying your own air quality sensor.

Hardware Components

The three core components you‘ll need are:

  1. Microcontroller with WiFi – NodeMCU ESP8266 (~$3-8) or Particle Photon (~$19) are good choices. These have built-in WiFi for sending sensor data to the cloud.

  2. Particulate matter sensor – The Honeywell HPM series and Plantower PMS5003 are two of the most popular low-cost sensors. They use laser scattering to detect PM2.5 and PM10 concentrations. Expect to pay $10-40.

  3. VOC sensor – For detecting VOCs and estimating CO2, the Adafruit CCS811 ($20) is an excellent option. It has an onboard microcontroller to handle the measurement algorithms.

Optionally, you may also want to include:

  • Temperature, humidity, and pressure sensor like the Bosch BME680 (~$10-20). Many air quality sensors like the CCS811 require temperature and humidity compensation for accurate readings.

  • OLED display to show readings directly on the device

  • Enclosure to protect the components

I‘ve compiled a full shopping list with product links on GitHub. All in you can expect to spend $50-$100 for high-quality sensors and components.

Putting it Together

With parts in hand, it‘s time to assemble our air quality sensor!

Wiring

Here‘s a basic wiring diagram using the NodeMCU ESP8266 as the microcontroller:

     NodeMCU 
     ┌──────┐
     │ 3.3V ├─── VCC CCS811 
     │      │└── VCC HPM  
     │  GND ├─── GND CCS811
     │      │└── GND HPM
     │  SDA ├─── SDA CCS811
     │  SCL ├─── SCL CCS811
     │   D5 ├─── RX HPM
     │   D6 ├─── TX HPM
     └──────┘

Both the CCS811 and the HPM communicate via UART serial. Connect their VCC to 3.3V, GND to ground, and RX/TX pins to any available GPIO pins on the NodeMCU.

If you‘re including a BME680, it communicates via I2C:

     NodeMCU 
     ┌──────┐
     │ 3.3V ├─── VCC BME680
     │  GND ├─── GND BME680  
     │  SDA ├─── SDA BME680
     │  SCL ├─── SCL BME680
     └──────┘

Double check all your connections and you‘re ready to program.

Programming

We‘ll use the Arduino IDE to program the NodeMCU. Install the following libraries to interface with the sensors:

Here‘s a simplified version of the code:

#include <ESP8266WiFi.h>
#include <Adafruit_CCS811.h>
#include <Adafruit_BME680.h>
#include "PMS.h"

#define PMS_RX D5
#define PMS_TX D6
#define INTERVAL 30000 // Update every 30 sec 

Adafruit_CCS811 ccs811;  
Adafruit_BME680 bme680; 
PMS pms(PMS_RX, PMS_TX);

PMS::DATA data;

void setup() {
  Serial.begin(115200);

  // Connect to WiFi
  WiFi.begin("SSID", "password");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  // Set up sensors  
  ccs811.begin();
  bme680.begin();  
  pms.passiveMode();
}

void loop() {
  // Read from CCS811
  if (ccs811.available()) {
    float temp = ccs811.calculateTemperature();
    ccs811.setEnvironmentalData(bme680.humidity, temp); 

    if (!ccs811.readData()) {
      float CO2 = ccs811.geteCO2();
      float TVOC = ccs811.getTVOC();
    }
  }

  // Read from BME680
  bme680.performReading();
  float temperature = bme680.temperature;
  float humidity = bme680.humidity;
  float pressure = bme680.pressure / 100.0;

  // Read from PMS sensor
  pms.requestRead();
  if (pms.readUntil(data)) {
    float pm1_0 = data.PM_AE_UG_1_0;
    float pm2_5 = data.PM_AE_UG_2_5;
    float pm10_0 = data.PM_AE_UG_10_0;
  }

  // Send data to server
  if (millis() - lastUpdate > INTERVAL) {
    sendToServer();
    lastUpdate = millis(); 
  }
}

In the setup() function, we initialize the sensors and connect to WiFi. In loop() we continuously read from the sensors. If INTERVAL milliseconds have passed since the last update, we call sendToServer() to publish the data.

Note how we use the temperature and humidity from the BME680 to compensate the raw readings from the CCS811. This is essential for getting accurate VOC and CO2 values.

The PMS library handles the details of passive mode reading from the Plantower sensor. We simply check if new data is available and store the PM1.0, PM2.5 and PM10 values.

For publishing data to the cloud, you have many options depending on your needs and expertise:

  • IoT platforms like ThingSpeak, Adafruit IO, Blynk
  • Custom web dashboard using a backend like InfluxDB to store time series data
  • MQTT broker like Mosquitto and a custom MQTT client
  • Data visualization tools like Grafana or Plotly

Refer to the documentation of your chosen service for how to send authenticated POST requests with your sensor data. Most provide Arduino libraries to simplify the process.

Calibration

No sensor is perfectly calibrated out of the box, and low-cost sensors especially may need some tuning for optimal accuracy. Here are some calibration tips:

  • Let the sensors "burn in" by running continuously for at least 48 hours
  • Compare your readings to a "ground truth" reference device. A nearby public air quality monitoring station or professional handheld particle counter are two options.
  • Use statistical analysis to determine and correct for any offset. For example, if your sensor consistently reads 20% lower than the reference, you can multiply all readings by 1.25.
  • Consider environmental factors like high humidity or rapid temperature changes which may skew results
  • Re-calibrate every few months as sensors can drift over time

While you‘ll never achieve lab-grade accuracy with low-cost sensors, you can get "good enough" data to identify trends, hotspots, and changes over time.

Deployment

With your sensor calibrated and sending data, it‘s time to deploy! Find a good spot that‘s representative of your home‘s air. Avoid placing it right next to obvious sources of pollution like the kitchen stove or garage door.

If your sensor has an enclosure, great! If not, you may want to 3D print or DIY a simple case to protect the components but still allow for airflow. A modified plastic food container can work in a pinch.

For power, you can either use a wall outlet or a portable USB battery pack for more flexibility. Just be sure to choose a battery with enough capacity to last your desired measurement interval.

Dashboards & Alerts

Now the fun part – slicing and dicing your data! If you‘re using an IoT platform or custom web app, you should be able to create dashboards with gauges, charts, and thresholds. This lets you see your readings at a glance and monitor changes over time.

For example, a simple HTML gauge for temperature:

<div>

  <svg viewBox="0 0 400 150">
    <path fill="none" stroke="#ccc" stroke-width="5" 
          d="M 39,119 A 80,80 0,0,1 361,119"/>

    <path id="progress" fill="none" stroke="red" stroke-width="5" 
          stroke-linecap="round" stroke-dasharray="251.2,251.2" stroke-dashoffset="251.2"
          d="M 39,119 A 80,80 0,0,1 361,119" />

    <text id="temp" x="200" y="120" font-size="48" fill="#000" font-family="arial" 
          text-anchor="middle" alignment-baseline="baseline">--</text>
  </svg>
</div>

<script>
  function setTemp(temp) {  
    // Clamp temp between 0-30°C
    temp = Math.max(0, Math.min(30, temp));

    // Calculate stroke offset
    const offset = 251.2 * (1 - temp / 30);

    // Update gauge
    const progress = document.getElementById(‘progress‘);
    progress.style.strokeDashoffset = offset;  

    const tempText = document.getElementById(‘temp‘);
    tempText.textContent = temp.toFixed(1);
  } 

  // Example
  setTemp(21.3);
</script>

You can create similar gauges for each sensor reading, as well as line graphs to track changes over time.

In addition to visualizations, you‘ll also want to set up alerts to notify you of any concerning readings. Most platforms support sending emails, SMS, or push notifications when a certain threshold is exceeded.

For example: get an alert if PM2.5 readings are higher than 35 μg/m3 (the EPA standard for "Unhealthy for Sensitive Groups") for more than an hour. Or if TVOC exceeds 500 ppb, indicating it‘s time to open a window or turn on a fan.

By regularly checking your dashboard and responding to alerts, you can take action to improve your home‘s air quality and create a healthier living environment.

Next Steps

Congratulations, you now have a functional and cost-effective indoor air quality monitor! Some possible next steps:

  • Correlate your indoor readings with outdoor air quality data from a service like PurpleAir or AirNow. This can reveal how much outdoor pollution is infiltrating your home.
  • Experiment with ventilation and filtration to see how they affect your readings. Can you get particulate levels to drop by running a HEPA purifier? How much do VOC levels rise after cleaning with harsh chemicals?
  • Add more sensors to your setup like carbon monoxide, radon, or ozone.
  • Contribute your sensor data to a citizen science project like the Air Quality Egg to help map pollution on a global scale
  • Develop a machine learning model to predict changes in air quality based on factors like weather, time of day, and human activity

The field of low-cost air quality monitoring is rapidly evolving and the barriers to entry keep getting lower. With a little know-how and DIY spirit, anyone can become an citizen scientist and take control of the air they breathe.

I hope this guide has inspired you to build your own air quality sensor and take the first step towards a healthier home environment. Remember, the best time to start monitoring your air is yesterday. The next best time is now.

Photo by Paweł Czerwiński on Unsplash

Similar Posts