The DIY Open-Source Particulate Matter and PM2.5 Air Quality Index Monitor. Inspired by PurpleAir*
CC BY-NC-SA Eric Woo-Shem & Brian Woo-Shem
- Displays the current Particulate Matter levels so you can quickly check if the current conditions are safe.
- Optional SD or Bluetooth logging.
- Same accuracy as commercially available devices.
- Costs $40 to $140 (depending on model) - less than half the cost of commercial sensors.
- No soldering required! Just connect wires.
Particulate Matter (PM) can cause serious health issues including asthma, heart attacks, strokes, and even death [1][2][3]. Smog, wildfires, and industrial pollution can increase PM to unhealthy or dangerous levels, so it is important for the general public to know when this occurs and to move to indoor areas with healthier air [1][3]. The Air Quality Index (AQI) is a numerical conversion used to represent the relative danger of PM and other pollutants [4]. The EPA provides high-quality AQI measurements and AQI forecasts [1], however these are limited to data collected at specific locations and the readings are typically updated only hourly. Low-cost sensors have been used to monitor PM levels at near-instantaneous rates, and at local locations, including in or outside your own home, school, or workplace; and provide fairly good accuracy [5][15]. For example, PurpleAir* supplies air quality monitors in the $200-300 price range [16], and connects them to a publicly available map.
The LavenderAir project is developing an open-source PM/AQI monitor that is low cost, easily customizable, and privacy-respecting. LavenderAir monitors offer the same accuracy to the PurpleAir* monitors, as the identical model of sensors is used. DIY assembly, "modular" features, and removal of the internet-connected components reduce the cost to as low as $40. Your data is easily viewable through an LED indicator, LCD display, and/or Bluetooth connection to your computer, can be stored on an SD card, and is never uploaded to the internet.
NanoPMM-Disp: Single Sensor + View current readings on LCD Display + Serial Output to ArduinoIDE (Working)
NanoPMM-SD-LED: Single Sensor + SD card logging + LED color indicator (Working)
NanoPMM-BT-LED: Single Sensor + Bluetooth logging to a computer + LED color indicator. (Work in progress)
MegaPMM: The most advanced model. Includes Dual Sensor for increased accuracy + LCD Display to show current readings + SD card logging + LCD color indicator + Bluetooth logging to a computer + Serial output to ArduinoIDE. (Work in progress)
This is a frugal AQI sensor so most of the parts can be interchanged with similar ones. See "LavenderAir_Bill_of_Materials.xlsx" for more details. Different sheets show suggestions for products to purchase for the lowest cost for the different models above. The quantities and cost autocompute if you plug in the number of sensors you want to build.
Note: Product suggestions in Bill of Materials are for convenience only. This project does not receive any incentive, financial or otherwise, for suggesting any particular product.
This is a general list of components; see the Bill of Materials for all parts & product suggestions by each PMM model.
Part Description | QTY per Sensor | Which models? |
---|---|---|
Arduino Nano | 1 | All NanoPMM |
Arduino Mega | 1 | MegaPMM |
Plantower PMS5003 Particle Concentration Sensor | 1 | All; need 2 for the MegaPMM |
Plantower PMS5003 Particle Concentration Sensor Wire (often included with sensor) | 1 | All; need 2 for the MegaPMM |
Breadboard: Mini breadboards recommended, but any size can work | 1-2 | All |
Micro SD Card Adapter Module (Or SD Card Adapter Module) | 1 | NanoPMM-SD & MegaPMM |
Micro SD (or SD) Card. Small is fine - 1 GB is overkill | 1 | NanoPMM-SD & MegaPMM |
DS3231 Real Time Clock Module | 1 | NanoPMM-SD & MegaPMM |
CR2032 Battery | 1 | NanoPMM-SD & MegaPMM |
DHT22 Temperature & Humidity Sensor (DHT11 also works but inferior) | 1 | All |
RGB Tri-Color 4-pin LED | 1 | All; optional for NanoPMM-Disp |
Jumper wires | 10-20 | All |
USB Power Bank Battery 5V or USB Power supply | 1 | Optional |
16x2 I2C LCD Display: | 1 | NanoPMM-Disp & MegaPMM |
HC-05 Bluetooth Module | 1 | NanoPMM-BT & MegaPMM |
Small Box: Cardboard, 3D printed, etc. | 1 | All |
Complete connection diagram.
Different models may require some or all of these steps. Model is noted in (parenthesis) at the start of each step.
-
(NanoPMM-SD-LED and MegaPMM) Insert the CR2032 battery into the RTC, and your memory card into your card reader.
-
(NanoPMM) Place and push in the Arduino Nano into one of the breadboards, as shown.
- (For Uno or Mega) The connectors are built in, so this step is not necessary. However, you may need to run a wire from a particular pin to a breadboard row if more than one connection is required.
-
(All) Connect the Ground on the Arduino to an unused row on the breadboard. Connect the 5V on the Arduino to a different unused row. Below is an example for mini-breadboards.
-
(NanoPMM-SD-LED and MegaPMM) Connect the Real Time Clock module using 4 male-to-female wires:
Sensor Wire | Breadboard Row |
---|---|
VCC | 5V row created in step 7 |
GND | the ground row created in step 7 |
SDA | Arduino pin A4 |
SCL | Arduino pin A5 |
- (NanoPMM-SD-LED and MegaPMM) Connect the SD Card Reader using 6 male-to-female wires:
Sensor Wire | Breadboard Row |
---|---|
GND | ground row created in step 7 |
VCC | 5V row created in step 7 |
MISO | Arduino pin D12 |
MOSI | Arduino pin D11 |
SCK | Arduino pin D13 |
CS | Arduino pin D10 |
- (All) Connect the PMS5003 sensor wires. These are tricky because they are not always labeled.
Wire Color | Position (left to right) | Label (if using Adafruit Adapter) | Arduino Pin |
---|---|---|---|
Purple | 1 | VCC | 5V row |
Orange | 2 | GND | Ground row |
White | 3 | SET | D2 |
Green | 5 | TX | D8 |
- (NanoPMM-Disp & MegaPMM) Connect the LCD Wires.
LCD Pin Label | Arduino Pin |
---|---|
GND | Ground row |
VCC | 5V row |
SDA | A4 |
SCL | A5 |
- (NanoPMM-BT-LED & MegaPMM) Connect the Bluetooth module
HC-05 Pin Label | Arduino Pin |
---|---|
+5V | 5V row |
GND | Ground row |
RX | RX0 |
TX | TX1 |
Congratulations! The sensor is fully assembled. Now connect the Arduino to your computer and upload the program to use it.
In each code, there are a series of variables for each feature (Serial, DHT, LCD Display, MulticolorLED, RTC, and Debug mode). Change booleans to false
for features you are not using, and true
for features you want to use.
// Settings: Change to false if not using that component
const bool useSerial = true;
const bool useDHT = true;
const bool useDisplayLCD = false;
const bool useDisplayI2C = true;
//const bool useSeparateLED = false; //not implemented yet
const bool useColorLED = true;
const bool debugMode = false;
bool useRTC = true;
-
Connect the Arduino USB cable between the Arduino and your computer.
-
(If not already installed) Download ArduinoIDE.
-
Go to Tools>Board and select your Arduino type.
-
(Arduino Nano Generic Only) Go to Tools>Processor and select "ATmega328P (Old Bootloader)".
-
Go to Tools>Port, and select the one including the number “x”, equal to the port you plugged the Arduino into. If you are unsure which port, start with the first option and click “Get Board Info". If you get an error, it is the wrong one. Try the next port and repeat until one works. You can also try uploading the code on each port in step 20.
-
Go to Tools>Programmer, and select “AVR ISP”.
-
Install the necessary packages:
-
(If not already set) Follow instructions from Arduino Get Started to automatically set the RTC.
-
Upload the CO₂ sensor code: Download the appropriate Firmware code and open it in Arduino IDE.
-
Upload the program to the Arduino by clicking on the right arrow button next to the check mark button. Warning: Do not touch until it says, "Done uploading."
-
Plug the Arduino into a power supply. Depending on your model choice, the sensor system will display the current PM2.5 on the LED, LCD display, and/or save them to a file on the SD card.
Arduino IDE / Code Upload Issues
Arduino Nano Select Processor
Wiring Intro for Beginners
Alternative Method to Set Date and Time on RTC Note: Use the LCD wiring from this project instead.
- Check Arduino IDE / Code Upload Issues
- Try each port option
- Try each processor option
- Swap the USB cable with another - sometimes the cables break
- Try a Loopback Test
- Most likely this is a wiring issue. Check that the wires leading to that component are matched to the correct pins and firmly attached.
- Re-upload the sensor code.
- Try a different power supply. If the current one is too weak, some components may work but others will not have enough power to operate.
When using the sensor, you can simply read the values from the screen. However, to get a more complete picture of how safe each place is, it is necessary to analyze the data for the entire time you are there. You can upload the data to your computer from the (micro) SD card, put it into a spreadsheet program, and create graphs or analyze it.
- Remove the (Micro) SD card from the adapter module by pressing firmly and releasing until it springs out, then pulling it out gently.
- Connect the (Micro) SD card to your computer, using adapters if necessary.
- Copy the file on the card “PMM_Data.txt” to your computer. The file is structured as follows:
- Typically, we want to import the data to a spreadsheet software like Excel or Google Sheets. We also want the times and the readings separated for so we can plot the values and compare over time. See the instructions below for your specific software.
Date: The day, in form YYYY-MM-DD
. From RTC.
Time: The time of reading, in form HH:MM:SS
. From RTC.
PC <0.3um [/0.1L]: Particle Count or number of particles of size equal to or less than 0.3µm per 0.1 L of air
PC <0.5um [/0.1L]: Particle Count or number of particles of size equal to or less than 0.5µm per 0.1 L of air
PM1.0_Sta: PM1.0 calculation using the "Standard" method from [13]. We suspect this is calculated incorrectly, so use with caution.
PM1.0_Env: PM1.0 calculation using the "Environmental" method [13]. We suspect this is calculated incorrectly.
PC <1.0um [/0.1L]: Particle Count or number of particles of size equal to or less than 1.0µm per 0.1 L of air
PM2.5_Env: PM2.5 calculation - done correctly, using method in [4][6].
PM2.5_Sta: PM2.5 calculation using the "Standard" method [13]. We suspect this is calculated incorrectly.
PM2.5_Env: PM2.5 calculation using the "Environmental" method [13]. We suspect this is calculated incorrectly.
PC <2.5um [/0.1L]: Particle Count or number of particles of size equal to or less than 2.5µm per 0.1 L of air
PC <5.0um [/0.1L]: Particle Count or number of particles of size equal to or less than 5.0µm per 0.1 L of air
PM10.0_Sta: PM10.0 calculation using the "Standard" method from [13]. We suspect this is calculated incorrectly.
PM10.0_Env: PM10.0 calculation using the "Environmental" method [13]. We suspect this is calculated incorrectly.
PC <10.0um [/0.1L]: Particle Count or number of particles of size equal to or less than 10.0µm per 0.1 L of air
Temp [°C]: Temperature, in degrees Celsius. From DHT.
RH [%]: Relative Humidity, in percentage. From DHT.
- Open the .txt file in a text editor.
- Optional: Use Find & Replace to separate the hours, minutes, and seconds into three separate columns for doing calculations like time elapsed from the start or to convert it to another date-time format, in addition Find ":" (colon), and replace with "," (comma).
- Change the file extension to .csv (on Windows see instructions below)
- Open with your favorite spreadsheet software. Example results:
- Open Excel
- Go to the "Data" tab and select "From Text"
- Follow the Text Import Wizard. Make sure to select "Delimited" on the first step. Optional: include "Semicolon" on the list of delimiters on the second step.
- Data will now be in two columns, one for time and one for the sensor readings.
- Change the file extension to .csv (on Windows see instructions below)
- Open with LibreOffice. You may need to right click then select "Open with" and choose your spreadsheet software if the computer defaults to another application.
- Use the defaults in the Text Import window, then click OK. The data will be imported.
- If the file extension (.txt, .csv, etc.) is not visible in File Manager, go to "View" tab and check "File name extensions"
- Rename the file to have .csv at the end instead of .txt
- If you get a warning, select "Yes."
A company called PurpleAir* produces AQI Monitors that are ready to use out of the box. Here's how our DIY PMM device compares. "F" denotes "Future/Planned" features that are in progress but not yet working.
LavenderAir is a work in progress. If you create an improvement to this project or complete some of the planned features before we can, please contact us so we can add your contribution and/or feel free to fork this project.
Currently, a single sensor with SD card logging, LCD display, and LED color indicator modes work independently, but SD and LCD cannot be used simultaneously because the amount of data processing and variables required exceeds the memory available for an Arduino Nano or Uno.
We found these errors when attempting to combine all of the features to a single Arduino Nano device:
Development of the MegaPMM version is in-progress. Currently, there is no working prototype available, and specs are based on theoretical features we expect are possible.
3D printed cases & a weatherproof outdoor housing is coming soon.
Eric Woo-Shem: Project conceptualization, original design, component selection & original BOM, programming: sensor firmware prototype, bluetooth, RTC.
Brian Woo-Shem: Programming: production firmware, SD logging, conversion to AQI readings, debugging; cost comparison analysis for new BOM, research, documentation, data analysis, sensor testing and validation, visualizations.
The structure of this project, resources, and some documentation are taken from the DIY Frugal Arduino CO₂ Sensor Monitor, a sub-$100 system to track and evaluate COVID-19 risk using CO₂ levels to estimate ventilation and occupancy, also by the same development team.
Our projects have been used in the curriculum for engineering courses at a major university.
All text, graphics, and non-code content is licensed CC BY-NC-SA
All code is licensed under the GNU General Public License v3
RTClib and Adafruit_PM25AQI are Copyright (c) Adafruit Industries and used under the open source MIT license.
Arduino IDE and related components are open source and licensed under the GNU GPL v2 and/or CC BY-SA Arduino.
*PurpleAir is a trademark of PurpleAir, Inc. LavenderAir is in no way affiliated nor endorsed by PurpleAir, Inc.. LavenderAir components do not connect to nor interact with the PurpleAir network.
This project “LavenderAir” is a noncommercial, open-source project that seeks to replicate many features of the PurpleAir sensors. LavenderAir monitors are built using off-the-shelf parts and with no knowledge of commercial monitors except for specifications made public on vendor websites. The creators of LavenderAir have no intention of any copyright or patent infringement. We are students and generate no revenue from this project; if we inadvertenly overlooked any legal issues please contact us and we will act in good faith to resolve the issue.
[1] United States Environmental Protection Agency, "Particulate Matter (PM) Basics," www.epa.gov/pm-pollution/particulate-matter-pm-basics
[2] AirNow, "Extremely High Levels of PM2.5: Steps to Reduce Your Exposure," www.airnow.gov/aqi/aqi-basics/extremely-high-levels-of-pm25/
[3] United States Environmental Protection Agency, "Air Quality Guide for Particle Pollution," https://www.airnow.gov/publications/air-quality-index/air-quality-guide-for-particle-pollution/
[4] AirNow, "AQI Calculator," https://www.airnow.gov/aqi/aqi-calculator/
[5] PurpleAir Map: map.purpleair.com
[6] PurpleAir "Using PurpleAir data" Google Doc. https://docs.google.com/document/d/15ijz94dXJ-YAZLi9iZ_RaBwrZ4KtYeCy08goGBwnbCU/edit
[7] Brendon Baumgartner, 2020 "DIY PurpleAir Sensor," BB's Blog https://blog.brendon.net/diy-purpleair-sensor/
[8] Daniel Ross, 2021, "How To Make an Arduino Air Quality Sensor," VueVille https://www.vueville.com/arduino/arduino-air-quality-sensor/
[9] Data types - W3Schools - for reducing memory requirement. https://www.w3schools.com/java/java_data_types.asp
[10] Minuka Thesath Yapa, 2021, "DHT11 & DHT22 Sensors Temperature using Arduino" https://create.arduino.cc/projecthub/MinukaThesathYapa/dht11-dht22-sensors-temperature-using-arduino-b7a8d6
[11] Arduino Get Started "Arduino - LCD I2C" https://arduinogetstarted.com/tutorials/arduino-lcd-i2c
[12] ElectroPeak, 2019 "SD Card Module with Arduino" Arduino Project Hub. https://create.arduino.cc/projecthub/electropeak/sd-card-module-with-arduino-how-to-read-write-data-37f390
[13] Adafruit_PM25AQI library for Arduino, (C) 2012, Adafruit Industries under BSD License. https://github.com/adafruit/Adafruit_PM25AQI
[14] PurpleAir "Map Start-Up Guide" https://community.purpleair.com/t/map-start-up-guide/90
[15] PurpleAir "How do PurpleAir sensors compare to regulatory particulate matter sensors?" https://community.purpleair.com/t/q-how-do-purpleair-sensors-compare-to-regulatory-particulate-matter-sensors/810
[16] PurpleAir. https://www2.purpleair.com/