# PM2.5 Air Quality Sensor

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/049/707/medium800/adafruit_products_3686_iso_ORIG.jpg?1514416807)

Breathe easy, knowing that you can track and sense the quality of the air around you with the **PM2.5&nbsp;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&nbsp;post-apocalyptic Australia](https://en.wikipedia.org/wiki/Mad_Max). 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!

_WITNESS&nbsp;_real-time, reliable measurement of PM2.5&nbsp;dust concentrations!&nbsp;(PM2.5 refers to particles that are 2.5 microns or smaller in diameter.) This sensor uses laser scattering to radiate suspending particles in the air, then collects scattering light to obtain the curve of scattering light change with time. The microprocessor calculates equivalent particle diameter and the number of particles with different diameter per unit volume.

![](https://cdn-learn.adafruit.com/assets/assets/000/049/708/medium800/adafruit_products_3686_kit_ORIG_2017_12.jpg?1514416836)

You'll need to hook this up to a microcontroller with UART input ([or you could theoretically wire it up to a USB-Serial converter and parse the data on a computer](https://www.adafruit.com/product/3309)) - we have code for both Arduino and CircuitPython. 9600 baud data streams out once per second, you'll get:

- 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

# PM2.5 Air Quality Sensor

## 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](https://github.com/adafruit/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.

# Wiring

Wiring is simple! Power the sensor with **+5V** and **GND** and then connect the data out pin (3.3V logic) to the serial input pin you'll use. Whether or not you are using hardware or software UART/serial may affect the pin, so adjust that as necessary. This wiring works for ATMega328P-based boards for sure, with Digital #2 as the data pin:

![](https://cdn-learn.adafruit.com/assets/assets/000/049/704/medium800/adafruit_products_wiring_bb.png?1514415726)

Warning: 

https://github.com/adafruit/Adafruit_PM25AQI/blob/master/examples/PM25_test/PM25_test.ino

Comment out the following line by adding "`//`" before it:

```cpp
if (! aqi.begin_I2C()) {      // connect to the sensor over I2C
```

Uncomment the following lines by removing the "`//`" from the beginning:

```cpp
//#include <SoftwareSerial.h>
//SoftwareSerial pmSerial(2, 3);

  //pmSerial.begin(9600);

  //if (! aqi.begin_UART(&pmSerial)) { // connect to the sensor over software serial
```

Once the changes are made, upload this code to your board, and open up the serial console at **115200** baud. You'll see data printed out once a second, with all the measurements. For a clean-air indoor room you'll see something like this:

![](https://cdn-learn.adafruit.com/assets/assets/000/049/705/medium800/adafruit_products_pms_clean.png?1514415856)

If you hold up a smoking soldering iron or something else that creates a lot of dust, you'll see much higher numbers!

![](https://cdn-learn.adafruit.com/assets/assets/000/049/706/medium800/adafruit_products_pms_dirty.png?1514415899)

Note that the numbers are very precise looking but we don't believe that they're going to be perfectly&nbsp; accurate, calibration may be necessary!

# PM2.5 Air Quality Sensor

## Python & CircuitPython

It's easy to use the **PM2.5** and the [Adafruit CircuitPython PM25](https://github.com/adafruit/Adafruit_CircuitPython_PM25) module. This library allows you to easily write Python code that reads particle concentrations, and particle diameter and the number of particles with different diameters per unit volume.

You can use this sensor with any CircuitPython microcontroller board or with a computer that has GPIO and Python [thanks to Adafruit\_Blinka, our CircuitPython-for-Python compatibility library](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).

# CircuitPython Microcontroller Wiring

First, connect the sensor to your microcontroller board using UART (a serial port).

Here is an example of it connected to a Feather M0 using UART:

- **Sensor VCC** to **board 5V**
- **Sensor GND** to **board GND**
- **Sensor TX** to **board RX**

Remember: **RX does not connect to RX!**

![adafruit_products_wiring_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/049/960/medium640/adafruit_products_wiring_bb.png?1573062170)

# Python Computer Wiring

Since there's _dozens_ of Linux computers/boards you can use we will show wiring for Raspberry Pi. For other platforms, [please visit the guide for CircuitPython on Linux to see whether your platform is supported](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).&nbsp;

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](https://www.adafruit.com/product/954):

- **Sensor VCC** to **USB 5V**
- **Sensor GND** to **USB GND**
- **Sensor TX** to **USB RX (white wire)**

Remember: **RX does not connect to RX!**

![adafruit_products_PM2-5_usbserial_UART_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/083/708/medium640/adafruit_products_PM2-5_usbserial_UART_bb.png?1573066731)

Warning: 

Here's an example using the Pi's built-in UART:

- **Sensor VCC** to **Pi 5V**
- **Sensor GND** to **Pi GND**
- **Sensor TX** to **Pi RX**  

Remember: **RX does not connect to RX!**

![adafruit_products_PM2-5_Raspi_UART_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/083/709/medium640/adafruit_products_PM2-5_Raspi_UART_bb.png?1573067313)

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](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/uart-serial) for detailed instructions on how to do this.

Warning: 

# CircuitPython & Python Usage
To demonstrate the PM2.5 in CircuitPython and Python, let's look at a complete program example.

## CircuitPython Microcontroller

With a CircuitPython microcontroller, save this file as&nbsp; **code.py** on your board. Then comment out the following lines by inserting a '`#`' before each one:

```python
i2c = busio.I2C(board.SCL, board.SDA, frequency=100000)

pm25 = adafruit_pm25.i2c.PM25_I2C(i2c, reset_pin)
```

And uncomment the following lines by removing the '`# `' (hash and space both!) before each one:

```python
# uart = busio.UART(board.TX, board.RX, baudrate=9600)

# pm25 = adafruit_pm25.uart.PM25_UART(uart, reset_pin)
```

Then,&nbsp; [open up the serial console](https://learn.adafruit.com/welcome-to-circuitpython/kattni-connecting-to-the-serial-console) to see its output.

## Linux/Computer/Raspberry Pi with Python
When using a USB to serial cable or a Raspberry Pi, comment out the following lines by inserting a '`#`' before each one:

```python
i2c = busio.I2C(board.SCL, board.SDA, frequency=100000)

pm25 = adafruit_pm25.i2c.PM25_I2C(i2c, reset_pin)
```

For Raspberry Pi, uncomment the following lines by removing the '`# `' (hash and space both!) before each one:

```python
# 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:

```python
# import serial
# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=0.25)
```

Install the python `serial` with library with

`pip3 install pyserial`

Now you're ready to run the program with the following command:

```python
python3 pm25_simpletest.py
```

https://github.com/adafruit/Adafruit_CircuitPython_PM25/blob/main/examples/pm25_simpletest.py

You should see output looking something like the following:

![](https://cdn-learn.adafruit.com/assets/assets/000/093/229/medium800/adafruit_products_Pm2-5_serial_output.png?1594936305)

That's all there is to using the PM2.5 air quality sensor with CircuitPython!

# PM2.5 Air Quality Sensor

## WipperSnapper

Warning: 

![](https://cdn-learn.adafruit.com/assets/assets/000/128/434/medium800/adafruit_products_01_DeviceList.png?1709312586)

## What is WipperSnapper

WipperSnapper is a firmware designed to turn any WiFi-capable board into an Internet-of-Things device without programming a single line of code. WipperSnapper connects to&nbsp;[Adafruit IO](https://io.adafruit.com/), a web&nbsp;platform designed ([by Adafruit!](https://www.adafruit.com/about)) to&nbsp;_display_,&nbsp;_respond_, and&nbsp;_interact_&nbsp;with your project's data.

Simply load the WipperSnapper firmware onto your board, add credentials, and plug it into power. Your board will automatically register itself with your Adafruit IO account.

From there, you can add&nbsp;_components_&nbsp;to your board such as buttons, switches, potentiometers, sensors, and more! Components are&nbsp;_dynamically&nbsp;_added to hardware, so you can&nbsp;immediately start interacting, logging, and streaming the data your projects produce without writing code.

If you've never used WipperSnapper, click below to read through the quick start guide before continuing.

[Quickstart: Adafruit IO WipperSnapper](https://learn.adafruit.com/quickstart-adafruit-io-wippersnapper)
## Wiring

First, wire up a PM2.5 sensor to your board exactly as follows using UART (a serial port). Here is an example of the PM2.5 sensor wired to an&nbsp;[Adafruit ESP32 Feather V2](https://www.adafruit.com/product/5400)&nbsp;using UART:

- **Board 5V/VUSB** &nbsp;to&nbsp; **sensor VCC**  
- **Board GND** &nbsp;to&nbsp; **sensor GND**  
- **Board RX** &nbsp;to&nbsp; **sensor TX**

![adafruit_products_featherV2_PM2.5_Breadboard_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/128/583/medium640/adafruit_products_featherV2_PM2.5_Breadboard_bb.png?1709652891)

## Usage

Connect your board to Adafruit IO Wippersnapper and&nbsp;**[navigate to the WipperSnapper board list](https://io.adafruit.com/wippersnapper).**

On this page,&nbsp; **select the WipperSnapper board you're using** &nbsp;to be brought to the board's interface page.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/436/medium800/adafruit_products_02_DeviceSelection_croppped.png?1709312817)

If you do not see your board listed here - you need&nbsp;[to connect your board to Adafruit IO](https://learn.adafruit.com/quickstart-adafruit-io-wippersnapper)&nbsp;first.

On the device page, quickly&nbsp; **check that you're running the latest version of the WipperSnapper firmware**.

The device tile on the left indicates the version number of the firmware running on the connected board.

- **If the firmware version is green with a checkmark -** &nbsp;continue with this guide.
- **If the firmware version is red with an exclamation mark "!" -** &nbsp;[update to the latest WipperSnapper firmware](https://learn.adafruit.com/quickstart-adafruit-io-wippersnapper)&nbsp;on your board before continuing.

![adafruit_products_04_LatestVersion.png](https://cdn-learn.adafruit.com/assets/assets/000/128/437/medium640/adafruit_products_04_LatestVersion.png?1709312857)

![adafruit_products_04_UpdateRequired.png](https://cdn-learn.adafruit.com/assets/assets/000/128/438/medium640/adafruit_products_04_UpdateRequired.png?1709312873)

Now you're ready to add your sensor component to your device.

**Click the New Component button or the + button&nbsp;** to bring up the component picker.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/442/medium800/adafruit_products_sensor_page_temperature___humidity_06_AddComponent.png?1709312944)

Adafruit IO supports a large amount of components. To quickly find your sensor, type&nbsp;`PMS5003` into the search bar, then select the **PMS5003**** &nbsp;**component.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/445/medium800/adafruit_products_llr4gdkxeq.png?1709313371)

On the component configuration page, the PMS5003's sensor settings should be listed.

The&nbsp; **Send Every** &nbsp;option is specific to each sensor's measurements. This option will tell the Feather how often it should read from the PMS5003 sensor and send the data to Adafruit IO. Measurements can range from every 30 seconds to every 24 hours.

For this example, set the&nbsp; **Send Every&nbsp;** interval to every 30 seconds.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/446/medium800/adafruit_products_ry5JQFNUsA.png?1709313462)

Your device interface should now show the sensor components you created. After the interval you configured elapses, WipperSnapper will automatically read values from the sensor(s) and send them to Adafruit IO.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/447/medium800/adafruit_products_Screenshot_2024-03-01_172842.png?1709314132)

To view the data that has been logged from the sensor, click on the graph next to the sensor name.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/448/medium800/adafruit_products_FGupd5ZVGq.png?1709314191)

Here you can see the feed history and edit things about the feed such as the name, privacy, webhooks associated with the feed and more. If you want to learn more about how feeds work,&nbsp;[check out this page](https://learn.adafruit.com/all-the-internet-of-things-episode-four-adafruit-io/advanced-feeds).

![](https://cdn-learn.adafruit.com/assets/assets/000/128/454/medium800/adafruit_products_Screenshot_2024-03-01_174113.png?1709314894)

# PM2.5 Air Quality Sensor

## Usage Notes

## Standard vs. Environmental Concentration

The PM2.5 returns two sets of concentrations: _standard_ and _environmental_.

_Standard_ refers to the concentration at standard pressure (i.e. sea level).

_Environmental_ refers to the concentration that depends on ambient pressure.

## Analysis Report of Using PM2.5

[**StanJ** wrote up an amazing analysis report of using the PM2.5 sensor in their lab](https://forums.adafruit.com/viewtopic.php?f=48&t=136528&p=767725#p767725), and we think its helpful for others to understand what and how the sensor works and what to expect from it! We've duplicated it here as well:

> 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 .  
>   
> As Solaria123 noted in [viewtopic.php?f=19&t=135496](https://forums.adafruit.com/viewtopic.php?f=19&t=135496), the sensor estimates particles \> 2.5um and doesn't (or can't) measure them. The article at ResearchGate showed that a concentration composed solely of larger particles wasn't seen by the sensor. For our cleanroom use that's OK as the HEPA filters are more efficient as the particle size increases. For non-filtered air it's a bit more of concern as the different particle sizes are composed of different pollutants, so you might be missing a pollutant if it's composed primarily of larger particles like pollen.

![](https://cdn-learn.adafruit.com/assets/assets/000/079/918/medium800/adafruit_products_5iDzZfi.png?1566755077)

> One amusing note in the translated PlanTower datasheet is "Only the consistency among the PM sensors of PLANTOWER is promised and ensured. And the sensor should not be checked with any third party equipment." Several groups including AQICN.org have done exactly that, and we have as well. The PlanTower sensor compares favorably with the readings from our calibrated Beckman Particle Counter, although the 30-50% uncertainty on the PlanTower 0.3 and 0.5 um bins means you can't get an exact comparison. We're only using the sensor for a rough check on current air quality, not to verify compliance with ISO 14644.  
>   
> A frustrating artifact of the PlanTower sensor is the sampling rate versus data output. With small change between readings the sensor only updates the counts every 2.3 seconds, although it outputs data every second. That means it may duplicate over half of the data, with no way to verify whether any reading is a duplicate. For a normal home or outdoor setting you could simply discard any reading when the checksum is identical to the previous data, as you're highly unlikely to have two successive samples with the same values. In a cleanroom we're looking at very low particle counts, and two successive samples might well be identical. The only way I could get around that is by throwing away 2 of every 3 data packets to insure I'm getting real counts, which increases the total sample time. I add the results from 100 unique 0.1 liter samples to get a reading of particles in 10 liters of air for my measurement, which means 300 samples with 2/3rds of the data thrown away.

```auto
    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.

![](https://cdn-learn.adafruit.com/assets/assets/000/079/919/medium800/adafruit_products_zY1H5NW.jpg?1566755130)

# PM2.5 Air Quality Sensor

## Downloads

# Files:

- [PMS5003 Datasheet / Manual](https://cdn-shop.adafruit.com/product-files/3686/plantower-pms5003-manual_v2-3.pdf)


## Related Guides

- [Multi-Sensor IoT Environmental Sensor Box With CircuitPython](https://learn.adafruit.com/remote-iot-environmental-sensor.md)
- [Air Quality Sensor 3D Printed Enclosure](https://learn.adafruit.com/air-quality-sensor-silo-house.md)
- [IoT Air Quality Sensor with Adafruit IO](https://learn.adafruit.com/diy-air-quality-monitor.md)
- [NeoPixel Light Slate](https://learn.adafruit.com/neopixel-light-slate.md)
- [3D Printed Camera Case for MEMENTO](https://learn.adafruit.com/memento-3d-case.md)
- [Adafruit CH9328 UART to HID Keyboard Breakout](https://learn.adafruit.com/adafruit-ch9328-uart-to-hid-keyboard-breakout.md)
- [Submitting an open-source project to OSHWA](https://learn.adafruit.com/submitting-an-open-source-project-to-oshwa.md)
- [Adafruit 2.2" PiTFT HAT - 320x240 Display](https://learn.adafruit.com/adafruit-2-2-pitft-hat-320-240-primary-display-for-raspberry-pi.md)
- [Adafruit IoT Button with NeoPixel BFF](https://learn.adafruit.com/adafruit-iot-button-with-neopixel-bff.md)
- [MagTag Twitter Display](https://learn.adafruit.com/magtag-twitter-display.md)
- [Snow Globe with Circuit Playground Bluefruit](https://learn.adafruit.com/snow-globe-bluefruit-cpb.md)
- [AS5600 Super Smooth Rotary Encoder](https://learn.adafruit.com/as5600-smooth-rotary-encoder.md)
- [Adafruit Feather M4 Express](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51.md)
- [Adafruit Feather RP2040 ThinkInk](https://learn.adafruit.com/adafruit-rp2040-feather-thinkink.md)
- [Adding a WiFi Co-Processor to CircuitPython](https://learn.adafruit.com/adding-a-wifi-co-processor-to-circuitpython-esp8266-esp32.md)
