Python & CircuitPython

It's easy to use the PM2.5 air quality sensor with CircuitPython or Python and the example below. No libraries are required. The example uses Python to read environmental data from the sensor.

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.

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!

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

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 USB 5V
  • Sensor GND to USB GND
  • Sensor TX to USB RX (white wire)

Remember: RX does not connect to RX!

For single board computers other than the Raspberry Pi, the serial port may be tied to the console or not be available to the user. Please see the board documentation to see how the serial port may be used

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!

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.

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 code.py on your board, then open up the REPL to see its output.

Linux/Computer/Raspberry Pi with Python

If you're running PMS5003_example.py on the Raspberry Pi (or any computer), you'll have to make some changes.

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

Download: file
import board
import busio
uart = busio.UART(board.TX, board.RX, baudrate=9600)

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

Download: file
# 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:

Download: file
# 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:

Download: file
python3 PMS5003_example.py
try:
    import struct
except ImportError:
    import ustruct as struct

# Connect the sensor TX pin to the board/computer RX pin
# For use with a microcontroller board:
import board
import busio
uart = busio.UART(board.TX, board.RX, baudrate=9600)

# For use with Raspberry Pi/Linux:
# import serial
# uart = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=0.25)

# For use with USB-to-serial cable:
# import serial
# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=0.25)

buffer = []

while True:
    data = uart.read(32)  # read up to 32 bytes
    data = list(data)
    # print("read: ", data)          # this is a bytearray type

    buffer += data

    while buffer and buffer[0] != 0x42:
        buffer.pop(0)

    if len(buffer) > 200:
        buffer = []  # avoid an overrun if all bad data
    if len(buffer) < 32:
        continue

    if buffer[1] != 0x4d:
        buffer.pop(0)
        continue

    frame_len = struct.unpack(">H", bytes(buffer[2:4]))[0]
    if frame_len != 28:
        buffer = []
        continue

    frame = struct.unpack(">HHHHHHHHHHHHHH", bytes(buffer[4:]))

    pm10_standard, pm25_standard, pm100_standard, pm10_env, \
        pm25_env, pm100_env, particles_03um, particles_05um, particles_10um, \
        particles_25um, particles_50um, particles_100um, skip, checksum = frame

    check = sum(buffer[0:30])

    if check != checksum:
        buffer = []
        continue

    print("Concentration Units (standard)")
    print("---------------------------------------")
    print("PM 1.0: %d\tPM2.5: %d\tPM10: %d" %
          (pm10_standard, pm25_standard, pm100_standard))
    print("Concentration Units (environmental)")
    print("---------------------------------------")
    print("PM 1.0: %d\tPM2.5: %d\tPM10: %d" % (pm10_env, pm25_env, pm100_env))
    print("---------------------------------------")
    print("Particles > 0.3um / 0.1L air:", particles_03um)
    print("Particles > 0.5um / 0.1L air:", particles_05um)
    print("Particles > 1.0um / 0.1L air:", particles_10um)
    print("Particles > 2.5um / 0.1L air:", particles_25um)
    print("Particles > 5.0um / 0.1L air:", particles_50um)
    print("Particles > 10 um / 0.1L air:", particles_100um)
    print("---------------------------------------")

    buffer = buffer[32:]
    # print("Buffer ", buffer)

You should see output looking something like the following:

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

This guide was first published on Dec 27, 2017. It was last updated on Dec 27, 2017. This page (Python & CircuitPython) was last updated on Dec 14, 2019.