PMSA003I Air Quality Sensor Issues

Breakout boards, sensors, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

This sensor seemed to work well for the first week, then the AQI values started reading unnaturally high.
Screen Shot 2022-04-26 at 10.10.26 AM.png
Screen Shot 2022-04-26 at 10.10.26 AM.png (38.6 KiB) Viewed 880 times
I ran it alongside a neighbor's Purple outdoor air sensor (which looks to use two of the PMS5003 sensors - https://www.adafruit.com/product/3686), which returned low to zero AQI at the same time this was reading "Unhealthy" levels (the zero reading was indoors next to an air purifier). I didn't expect them to match, but they should be much closer.

The numbers below are with the sensor sealed in a case for a few days. I still expect some very small particles (as seen there) and no larger particles (still seen there), but then why is it coming back with a high AQI and concentration units?
image.png
image.png (27.44 KiB) Viewed 880 times
Is there a way to "reset" the sensor or do I have a defective unit?

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by adafruit_support_carter »

Are you seeing the same behavior if your run the example from the library? Are you using Arduino or CircuitPython?
https://learn.adafruit.com/pmsa003i/overview

User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

I'm using Circuit Python.
The sample code provides almost identical values (just about 2 minutes apart).

Example from Library:
Screen Shot 2022-04-26 at 2.08.09 PM.png
Screen Shot 2022-04-26 at 2.08.09 PM.png (22.34 KiB) Viewed 865 times
My code (which leverages the Example code):
Screen Shot 2022-04-26 at 2.13.26 PM.png
Screen Shot 2022-04-26 at 2.13.26 PM.png (25.32 KiB) Viewed 865 times

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by adafruit_support_carter »

What kind of environment was the sensor being used in for the week it was in operation?

What happened between March 14th and March 17th?

User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

There had been some times it stopped feeding to IO and had to be rebooted (I haven't figured that issue out yet). During the 14-17th it was just unplugged and off.

It has spent most of its time indoors, with a few hours outside (day 2). Tested things like the fireplace and an air filter to see the data. It's been in the same room the rest of the time.

User avatar
thzinc
 
Posts: 3
Joined: Sat May 22, 2021 11:35 pm

Re: PMSA003I Air Quality Sensor Issues

Post by thzinc »

@mriesenberg, what are you using to calculate AQI?

I'm also working on a device that uses the PMS5003 and I'm seeing values for PM1 and PM10 concentrations that seem like they're transposed: viewtopic.php?f=19&t=190859

User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

thzinc wrote:@mriesenberg, what are you using to calculate AQI?

I'm also working on a device that uses the PMS5003 and I'm seeing values for PM1 and PM10 concentrations that seem like they're transposed: viewtopic.php?f=19&t=190859
I used the code from this guide: https://learn.adafruit.com/air-quality- ... thon-setup

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by adafruit_support_carter »

During the 14-17th it was just unplugged and off.
And used in the same location / environment between each time it used in this time frame? Is it known and expected that the environment's AQI should *not* have actually changed?

User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

adafruit_support_carter wrote:
During the 14-17th it was just unplugged and off.
And used in the same location / environment between each time it used in this time frame? Is it known and expected that the environment's AQI should *not* have actually changed?
Correct. And the delta between the Purple air sensor (it was reading 0-20 AQI) and mine increased when they were side-by-side.

Additionally, March 28th is when I tried sealing the case and it still read high for those last days.

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by adafruit_support_carter »

Can you link to your full code that is reporting the AQI values.

Did you happen to look at the other values to see if any of those had similar jumps?

User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

This is the AQI calc function:

Code: Select all

def calculate_aqi(pm_sensor_reading):
    """Returns a calculated air quality index (AQI)
    and category as a tuple.
    NOTE: The AQI returned by this function should ideally be measured
    using the 24-hour concentration average. Calculating a AQI without
    averaging will result in higher AQI values than expected.
    :param float pm_sensor_reading: Particulate matter sensor value.

    """
    # Check sensor reading using EPA breakpoint (Clow-Chigh)
    if 0.0 <= pm_sensor_reading <= 12.0:
        # AQI calculation using EPA breakpoints (Ilow-IHigh)
        aqi_val = map_range(int(pm_sensor_reading), 0, 12, 0, 50)
        aqi_cat = "Good"
    elif 12.1 <= pm_sensor_reading <= 35.4:
        aqi_val = map_range(int(pm_sensor_reading), 12, 35, 51, 100)
        aqi_cat = "Moderate"
    elif 35.5 <= pm_sensor_reading <= 55.4:
        aqi_val = map_range(int(pm_sensor_reading), 36, 55, 101, 150)
        aqi_cat = "Unhealthy for Sensitive Groups"
    elif 55.5 <= pm_sensor_reading <= 150.4:
        aqi_val = map_range(int(pm_sensor_reading), 56, 150, 151, 200)
        aqi_cat = "Unhealthy"
    elif 150.5 <= pm_sensor_reading <= 250.4:
        aqi_val = map_range(int(pm_sensor_reading), 151, 250, 201, 300)
        aqi_cat = "Very Unhealthy"
    elif 250.5 <= pm_sensor_reading <= 350.4:
        aqi_val = map_range(int(pm_sensor_reading), 251, 350, 301, 400)
        aqi_cat = "Hazardous"
    elif 350.5 <= pm_sensor_reading <= 500.4:
        aqi_val = map_range(int(pm_sensor_reading), 351, 500, 401, 500)
        aqi_cat = "Hazardous"
    else:
        print("Invalid PM2.5 concentration")
        aqi_val = -1
        aqi_cat = "None"
    return aqi_val, aqi_cat

And here's the full code:

Code: Select all

# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
import board
import busio
from digitalio import DigitalInOut
import neopixel
from adafruit_esp32spi import adafruit_esp32spi, adafruit_esp32spi_wifimanager
from adafruit_io.adafruit_io import IO_HTTP
from simpleio import map_range
from adafruit_pm25.uart import PM25_UART
from analogio import AnalogIn

# Uncomment below for PMSA003I Air Quality Breakout
from adafruit_pm25.i2c import PM25_I2C
import adafruit_bme280

### Configure Sensor ###
# Return environmental sensor readings in degrees Celsius
USE_CELSIUS = False
# Interval the sensor publishes to Adafruit IO, in minutes
PUBLISH_INTERVAL = 1


### WiFi ###

# Get wifi details and more from a secrets.py file
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

# AirLift FeatherWing
esp32_cs = DigitalInOut(board.D13)
esp32_reset = DigitalInOut(board.D12)
esp32_ready = DigitalInOut(board.D11)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)

# Connect to a PM2.5 sensor over UART
reset_pin = None
# uart = busio.UART(board.TX, board.RX, baudrate=9600)
# pm25 = PM25_UART(uart, reset_pin)

# Create i2c object
i2c = busio.I2C(board.SCL, board.SDA, frequency=100000)

# Connect to a BME280 over I2C
# bme_sensor = adafruit_bme280.Adafruit_BME280_I2C(i2c)

# Uncomment below for PMSA003I Air Quality Breakout
pm25 = PM25_I2C(i2c, reset_pin)

# Uncomment below for BME680
import adafruit_bme680
bme_sensor = adafruit_bme680.Adafruit_BME680_I2C(i2c)

### Sensor Functions ###
def calculate_aqi(pm_sensor_reading):
    """Returns a calculated air quality index (AQI)
    and category as a tuple.
    NOTE: The AQI returned by this function should ideally be measured
    using the 24-hour concentration average. Calculating a AQI without
    averaging will result in higher AQI values than expected.
    :param float pm_sensor_reading: Particulate matter sensor value.

    """
    # Check sensor reading using EPA breakpoint (Clow-Chigh)
    if 0.0 <= pm_sensor_reading <= 12.0:
        # AQI calculation using EPA breakpoints (Ilow-IHigh)
        aqi_val = map_range(int(pm_sensor_reading), 0, 12, 0, 50)
        aqi_cat = "Good"
    elif 12.1 <= pm_sensor_reading <= 35.4:
        aqi_val = map_range(int(pm_sensor_reading), 12, 35, 51, 100)
        aqi_cat = "Moderate"
    elif 35.5 <= pm_sensor_reading <= 55.4:
        aqi_val = map_range(int(pm_sensor_reading), 36, 55, 101, 150)
        aqi_cat = "Unhealthy for Sensitive Groups"
    elif 55.5 <= pm_sensor_reading <= 150.4:
        aqi_val = map_range(int(pm_sensor_reading), 56, 150, 151, 200)
        aqi_cat = "Unhealthy"
    elif 150.5 <= pm_sensor_reading <= 250.4:
        aqi_val = map_range(int(pm_sensor_reading), 151, 250, 201, 300)
        aqi_cat = "Very Unhealthy"
    elif 250.5 <= pm_sensor_reading <= 350.4:
        aqi_val = map_range(int(pm_sensor_reading), 251, 350, 301, 400)
        aqi_cat = "Hazardous"
    elif 350.5 <= pm_sensor_reading <= 500.4:
        aqi_val = map_range(int(pm_sensor_reading), 351, 500, 401, 500)
        aqi_cat = "Hazardous"
    else:
        print("Invalid PM2.5 concentration")
        aqi_val = -1
        aqi_cat = "None"
    return aqi_val, aqi_cat


def sample_aq_sensor():
    """Samples PM2.5 sensor
    over a 2.3 second sample rate.

    """
    aq_reading = 0
    aq_samples = []

    # initial timestamp
    time_start = time.monotonic()
    # sample pm2.5 sensor over 2.3 sec sample rate
    while time.monotonic() - time_start <= 2.3:
        try:
            aqdata = pm25.read()
            aq_samples.append(aqdata["pm25 env"])
        except RuntimeError:
            print("Unable to read from sensor, retrying...")
            continue
        # pm sensor output rate of 1s
        time.sleep(1)
    # average sample reading / # samples
    for sample in range(len(aq_samples)):
        aq_reading += aq_samples[sample]
    aq_reading = aq_reading / len(aq_samples)
    aq_samples.clear()
    return aq_reading


def read_bme(is_celsius=False):
    """Returns temperature, gag, pressure, and humidity
    from BME280/BME680 environmental sensor, as a tuple.

    :param bool is_celsius: Returns temperature in degrees celsius
                            if True, otherwise fahrenheit.
    """
    humid = bme_sensor.humidity
    temp = bme_sensor.temperature
    gas = bme_sensor.gas
    pressure = bme_sensor.pressure
    if not is_celsius:
        temp = temp * 1.8 + 32
    return temp, humid, gas, pressure

# Get current voltage reading
vbat_voltage = AnalogIn(board.VOLTAGE_MONITOR)

def get_voltage(pin):
    return (pin.value * 3.3) / 65536 * 2

battery_voltage = get_voltage(vbat_voltage)



# Create an instance of the Adafruit IO HTTP client
io = IO_HTTP(secrets["aio_username"], secrets["aio_key"], wifi)

# Describes feeds used to hold Adafruit IO data
feed_aqi = io.get_feed("air-quality.aqi")
feed_aqi_category = io.get_feed("air-quality.category")
feed_humidity = io.get_feed("air-quality.humidity")
feed_temperature = io.get_feed("air-quality.temperature")
feed_pressure = io.get_feed("air-quality.pressure")
feed_gas = io.get_feed("air-quality.voc")
feed_pm10 = io.get_feed("air-quality.pm10")
feed_pm25 = io.get_feed("air-quality.pm25")
feed_pm100 = io.get_feed("air-quality.pm100")


# Set up location metadata from secrets.py file
location_metadata = {
    "lat": secrets["latitude"],
    "lon": secrets["longitude"],
    "ele": secrets["elevation"],
}

elapsed_minutes = 0
prv_mins = 0

while True:
    try:
        print("Fetching time...")
        cur_time = io.receive_time()
        print("Time fetched OK!")
        # Hourly reset
        if cur_time.tm_min == 0:
            prv_mins = 0
    except (ValueError, RuntimeError) as e:
        print("Failed to fetch time, retrying\n", e)
        wifi.reset()
        wifi.connect()
        continue

    if cur_time.tm_min >= prv_mins:
        print("%d min elapsed.." % elapsed_minutes)
        prv_mins = cur_time.tm_min
        elapsed_minutes += 1

    if elapsed_minutes >= PUBLISH_INTERVAL:
        print("Sampling AQI...")
        aqi_reading = sample_aq_sensor()
        aqi, aqi_category = calculate_aqi(aqi_reading)
        print("AQI: %d" % aqi)
        print("Category: %s" % aqi_category)

        aqdata = pm25.read()
        print()
        print("---------------------------------------")
        print("Concentration Units (standard)")
        print(
            "PM 1.0: %d\tPM2.5: %d\tPM10: %d"
            % (aqdata["pm10 standard"], aqdata["pm25 standard"], aqdata["pm100 standard"])
        )
        print("---------------------------------------")
        print("Concentration Units (environmental)")
        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("---------------------------------------")

        # temp and humidity
        print("Sampling environmental sensor...")
        temperature, humidity, gas, pressure  = read_bme(USE_CELSIUS)
        print("Temperature: %0.1f F" % temperature)
        print("Humidity: %0.1f %%" % humidity)
        print("VOC: %d ohm" % gas)
        print("Pressure: %0.3f hPa" % pressure)
        print("Battery V: {:.2f}V".format(battery_voltage))

        # Publish all values to Adafruit IO
        print("Publishing to Adafruit IO...")
        try:
            io.send_data(feed_aqi["key"], str(aqi), location_metadata)
            io.send_data(feed_aqi_category["key"], aqi_category)
            io.send_data(feed_temperature["key"], str(temperature))
            io.send_data(feed_humidity["key"], str(humidity))
            io.send_data(feed_pressure["key"], str(pressure))
            io.send_data(feed_gas["key"], str(gas))

            io.send_data(feed_pm10["key"], str(aqdata["pm10 env"]))
            io.send_data(feed_pm25["key"], str(aqdata["pm25 env"]))
            io.send_data(feed_pm100["key"], str(aqdata["pm100 env"]))
            print("Published!")
        except (ValueError, RuntimeError) as e:
            print("Failed to send data to IO, retrying\n", e)
            wifi.reset()
            wifi.connect()
            continue
        # Reset timer
        elapsed_minutes = 0
    time.sleep(30)

User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

adafruit_support_carter wrote:Did you happen to look at the other values to see if any of those had similar jumps?
I didn't log the PM values before I started troubleshooting, but the PM2.5 and PM10 values have been high since I started doing so and in a sealed case they should be 0 (especially PM10, which are large particles).

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by adafruit_support_carter »

I still expect some very small particles (as seen there) and no larger particles (still seen there), but then why is it coming back with a high AQI and concentration units?
You are basing everything on the "pm25 env" value returned from the sensor.

Code: Select all

                aqdata = pm25.read()
                aq_samples.append(aqdata["pm25 env"])
so is including all particles below 2.5um.

It could be that there are residual particles from the previous use. Like in the fireplace and air filter uses. Were those test environments fairly dirty?

User avatar
mriesenberg
 
Posts: 10
Joined: Sun Mar 06, 2022 1:45 pm

Re: PMSA003I Air Quality Sensor Issues

Post by mriesenberg »

I did test it with the fireplace going, but that was just a short time during the first day or two. The AQI went up and down as expected in the environment until it was turned back on later. I tried lightly blowing compressed air around it just to see if something got gunked up, but that didn't seem to do anything,

User avatar
adafruit2
 
Posts: 22148
Joined: Fri Mar 11, 2005 7:36 pm

Re: PMSA003I Air Quality Sensor Issues

Post by adafruit2 »

you could try opening it up and cleaning it out, could be the area where the air travels through got dirty enough the particles are stuck to the sensor - in fact thats pretty likely what happened.

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Products from Adafruit”