Adafruit Pm25 Air Quality Sensor
Adafruit Pm25 Air Quality Sensor
Adafruit Pm25 Air Quality Sensor
https://learn.adafruit.com/pm25-air-quality-sensor
Overview 3
Arduino Code 4
• Wiring
Usage Notes 12
• Standard vs. Environmental Concentration
• Analysis Report of Using PM2.5
Downloads 15
• Files:
Breathe easy, knowing that you can track and sense the quality of the air around you
with the PM2.5 Air Quality Sensor with Breadboard Adapter particulate sensor. Mad
Max & Furiosa definitely should have hooked up one of these in their truck while
scavenging the dusty desert wilderness of post-apocalyptic Australia (). And for those
of us not living in an Outback dystopia, this sensor + adapter kit is great for
monitoring air quality, and super easy to use!
• PM1.0, PM2.5 and PM10.0 concentration in both standard & enviromental units
• Particulate matter per 0.1L air, categorized into 0.3um, 0.5um, 1.0um, 2.5um,
5.0um and 10um size bins
As well as checksum, in binary format (its fairly easy to parse the binary format, but it
doesn't come out as pure readable ascii text)
We give you the sensor box as well as the cable and a 0.1" / 2.54mm breakout board
so you can wire it easily. You only need power plus one data pin (for the UART TX).
Power is 5V, logic is 3.3V
Arduino Code
Using the PM2.5 with Arduino is a simple matter of wiring up it to your Arduino-
compatible microcontroller, installing the Adafruit PM25AQI () library we've written,
and running the provided example code.
This code will get you started with any Arduino compatible (e.g. Arduino UNO,
Adafruit Metro, ESP8266, Teensy, etc. As long as you have either a hardware serial or
software serial port that can run at 9600 baud.
To use this example with the PM2.5 sensor, you'll need to make some changes.
#include "Adafruit_PM25AQI.h"
// If your PM2.5 is UART only, for UNO and others (without hardware serial)
// we must use software serial...
// pin #2 is IN from sensor (TX pin on sensor), leave pin #3 disconnected
// comment these two lines if using hardware serial
//#include <SoftwareSerial.h>
//SoftwareSerial pmSerial(2, 3);
void setup() {
// Wait for serial monitor to open
Serial.begin(115200);
while (!Serial) delay(10);
Serial.println("PM25 found!");
}
void loop() {
PM25_AQI_Data data;
if (! aqi.read(&data)) {
Serial.println("Could not read from AQI");
delay(500); // try again in a bit!
return;
}
Serial.println("AQI reading success");
Serial.println();
Serial.println(F("---------------------------------------"));
Serial.println(F("Concentration Units (standard)"));
Serial.println(F("---------------------------------------"));
Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_standard);
Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_standard);
Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_standard);
Serial.println(F("Concentration Units (environmental)"));
Serial.println(F("---------------------------------------"));
Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_env);
Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_env);
Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_env);
Serial.println(F("---------------------------------------"));
Serial.print(F("Particles > 0.3um / 0.1L air:"));
Serial.println(data.particles_03um);
Serial.print(F("Particles > 0.5um / 0.1L air:"));
Serial.println(data.particles_05um);
Serial.print(F("Particles > 1.0um / 0.1L air:"));
Serial.println(data.particles_10um);
Serial.print(F("Particles > 2.5um / 0.1L air:"));
Serial.println(data.particles_25um);
Serial.print(F("Particles > 5.0um / 0.1L air:"));
Serial.println(data.particles_50um);
Serial.print(F("Particles > 10 um / 0.1L air:"));
Serial.println(data.particles_100um);
Serial.println(F("---------------------------------------"));
delay(1000);
}
Comment out the following line by adding " // " before it:
Uncomment the following lines by removing the " // " from the beginning:
//#include <SoftwareSerial.h>
//SoftwareSerial pmSerial(2, 3);
//pmSerial.begin(9600);
If you hold up a smoking soldering iron or something else that creates a lot of dust,
you'll see much higher numbers!
Note that the numbers are very precise looking but we don't believe that they're
going to be perfectly accurate, calibration may be necessary!
Here you have two options: An external USB-to-serial converter, or the built-in UART
on the Pi's RX pin. Here's an example of wiring up the USB-to-serial converter ():
Sensor VCC to Pi 5V
Sensor GND to Pi GND
Sensor TX to Pi RX
Remember: RX does not connect to RX!
If you want to use the built-in UART, you'll need to disable the serial console and
enable the serial port hardware in raspi-config. See the UART/Serial section of the
CircuitPython on Raspberry Pi guide () for detailed instructions on how to do this.
To use the pm25_simpletest.py with the PM2.5 sensor, you'll have to make some
changes.
CircuitPython Microcontroller
With a CircuitPython microcontroller, save this file as code.py on your board. Then
comment out the following lines by inserting a ' # ' before each one:
And uncomment the following lines by removing the ' # ' (hash and space both!)
before each one:
For Raspberry Pi, uncomment the following lines by removing the ' # ' (hash and
space both!) before each one:
# import serial
# uart = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=0.25)
For a USB to serial cable, uncomment the following lines by removing the ' # ' (hash
and space both!) before each one:
# import serial
# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=0.25)
Now you're ready to run the program with the following command:
python3 pm25_simpletest.py
"""
Example sketch to connect to PM2.5 sensor with either I2C or UART.
"""
# pylint: disable=unused-import
import time
import board
import busio
from digitalio import DigitalInOut, Direction, Pull
from adafruit_pm25.i2c import PM25_I2C
while True:
time.sleep(1)
try:
aqdata = pm25.read()
# print(aqdata)
except RuntimeError:
print("Unable to read from sensor, retrying...")
continue
print()
print("Concentration Units (standard)")
print("---------------------------------------")
print(
"PM 1.0: %d\tPM2.5: %d\tPM10: %d"
% (aqdata["pm10 standard"], aqdata["pm25 standard"], aqdata["pm100
standard"])
)
print("Concentration Units (environmental)")
print("---------------------------------------")
print(
"PM 1.0: %d\tPM2.5: %d\tPM10: %d"
% (aqdata["pm10 env"], aqdata["pm25 env"], aqdata["pm100 env"])
)
print("---------------------------------------")
print("Particles > 0.3um / 0.1L air:", aqdata["particles 03um"])
print("Particles > 0.5um / 0.1L air:", aqdata["particles 05um"])
print("Particles > 1.0um / 0.1L air:", aqdata["particles 10um"])
print("Particles > 2.5um / 0.1L air:", aqdata["particles 25um"])
print("Particles > 5.0um / 0.1L air:", aqdata["particles 50um"])
print("Particles > 10 um / 0.1L air:", aqdata["particles 100um"])
print("---------------------------------------")
Usage Notes
Standard vs. Environmental Concentration
The PM2.5 returns two sets of concentrations: standard and environmental.
I've read quite a lot on the PlanTower sensors, although I'm nothing like an
expert :-). The CF readings are 'Calibration Factory' and aren't useful; the
'Environmental' or 'Ambient' concentration readings are the data you want
for air quality measurements. I'm using the PMS5003 for a continuous
check on cleanroom quality, so I only use the raw Particle Counts as that's
the measurement specified in ISO 14644-1 .
amb=[003a 005c 0061] raw=[386a 1160 0325 004c 000b 0001] csum=0542
amb=[003b 005d 0063] raw=[38cd 1175 033c 0054 000e 0004] csum=05ea
amb=[003c 0060 0065] raw=[398a 11ba 033c 0054 000a 0003] csum=05f4
amb=[003c 0060 0066] raw=[3a8c 120f 0340 0050 000d 0003] csum=0555
amb=[003d 0060 0066] raw=[3b04 122e 0333 0050 000d 0003] csum=04e1
amb=[003c 005e 0064] raw=[3b04 122a 0339 0056 000b 0003] csum=04dc
amb=[003c 005e 0064] raw=[3b04 122a 0339 0056 000b 0003] csum=04dc duplicate
amb=[003c 005e 0064] raw=[3b04 122a 0339 0056 000b 0003] csum=04dc duplicate
amb=[003c 005c 0062] raw=[3b22 1232 0330 004b 000a 0003] csum=04e2
amb=[003c 005c 0062] raw=[3b22 1232 0330 004b 000a 0003] csum=04e2 duplicate
amb=[003c 005c 0062] raw=[3b22 1232 0330 004b 000a 0003] csum=04e2 duplicate
amb=[003b 0059 005f] raw=[3a7a 1211 030e 0043 000a 0003] csum=04de
amb=[003a 0058 005e] raw=[3a7a 1211 030e 0043 000a 0003] csum=04d8
amb=[003a 0058 005e] raw=[3a7a 1211 030e 0043 000a 0003] csum=04d8 duplicate
amb=[003a 0058 005e] raw=[3a35 11fa 030c 003b 0009 0003] csum=056e
What you're seeing above is the 1 second data window sliding along the
(typical) 2.3 second sampling window. When the data changes significantly
between samples the sensor shortens the sample window to 200-800ms,
which may be why the first 6 data points show unique numbers (faster
sampling rate).
The readings above are in my home, and I smoke so the particle counts
vary wildly about 1000:1 over time with a decent quality air filter. When I'm
home I run the air handler fan continuously to level out the temperature
over the house, and when I'm away I let the fan cycle with the AC or heat.
You can see the difference below in how rapidly the particle counts fall off
with continuous filtering. The rapid fall off continuous curve is [sleeping],
and the slow fall off is cycling [away from home]. Data points are every 30
minutes.