You ever wonder what's actually in the air you breathe every day? I've lived in Beijing for a few years now and I'm always running a couple of air purifiers in my home, but how well do they actually work? Sure some have built in sensors, but how accurate are they? Well with a little Python, a Raspberry Pi, and some moxie, we can find our own answers.
This will focus primarily on measuring PM2.5 and PM10 in the air and converting the values to an Air Quality Index (AQI). For measuring other harmful chemicals like Nitrogen Dioxide (NO2) or Carbon Monoxide (CO), see the "Adding Sensors" section at the end of the article
Prerequisites
- Raspberry Pi Configured, Headless (I used a 3b, but anything with a USB port should do just fine, though built in wifi is recommended for portability) (~$35)
- SDS011 PM Sensor (~$15)
- Adafruit IO Account (free)
Setting up Adafruit IO
Create an account on Adafruit IO. This is a great site to collect data streams and display them on custom dashboards. After you've created an account, let's create a couple of feeds. We'll need three: a pm2.5, a pm10, and a log feed (I named mine "beijing-twofive", "beijing-ten", and "logs" respectively). After that, you can either create a dashboard now or later and play around with how you want to display the data. This is how I have mine set up.
Configure your Raspberry Pi
Configure your Raspberry Pi with the installers on the product website. Once configured with either Raspbian or a Linux distribution of your choice (this project should be compatible with most distributions, but it's only been tested on Debian, Raspbian, and MacOS), install the following dependencies:
Download the Code and Install Dependencies
SSH into your Raspberry Pi (or login if GUI is installed and open your terminal) and download the repo in your home directory:
git clone git@github.com:HoukasaurusRex/RaspberryPi-AQIPi.git
Then install the python dependencies:
pip3 install -r requirements.txt
Configure ENV with Adafruit Keys and Feed Names
Retrieve your AdafruitIO username and key from the dashboard and add them to you env.
echo 'AIO_USERNAME="Hackerman"
AIO_KEY="aio_xXxXx"
CITY="beijing"
AIO_LOGS="logs"' > .env
Both CITY
and AIO_LOGS
are feed names created in the AdafruitIO dashboard.
Run the Code
Now you can run the code. I like to use screen to save my terminal process to be accessible later, but you can just run it in your main shell as well.
screen -S aqipi
cd ~/RaspberryPi-AQIPi
chmod +x run.sh
sh run.sh
There won't be any output in your terminal, but you should be able to go to your AdafruitIO feeds and start seeing results!
Sensor Placement
Standard advice for locating your sensor is that it should be outside and four metres above ground level. That’s good advice for general environmental monitoring; however, we’re not necessarily interested in general environmental monitoring – we’re interested in knowing what we’re breathing in.
Choose a location where you spend most of your time or where you might be particularly interested in the general air quality (e.g. in the kitchen or garage) and place your sensor in a safe place where it won't be affected by excessive moisture or humidity.
Understanding the Code
def read_data():
pm_twofive_data = []
pm_ten_data = []
readings = 0
# This will take 11 data samples and use the built in `statistics` module to upload a median value
# to filter out excessive data spikes in the readings
while readings < 11:
data = []
for index in range(0, 10):
datum = ser.read()
data.append(datum)
# Convert the readings from bytes to ints and append to the array of data samples
pm_twofive = int.from_bytes(b''.join(data[2:4]), byteorder='little') / 10
pm_twofive_data.append(pm_twofive)
pm_ten = int.from_bytes(b''.join(data[4:6]), byteorder='little') / 10
pm_ten_data.append(pm_ten)
readings += 1
# Take a little break ☕️
sleep(1)
# Calculate the AQI from ppm^2 using the US EPA API table detailed in the section below
# then upload to your AdafruitIO feeds using the Adafruit_IO SDK
pm_twofive_aqi = calc_aqi('pm_twofive', median(pm_twofive_data))
send_data('twofive', pm_twofive_aqi)
pm_ten_aqi = calc_aqi('pm_ten', median(pm_ten_data))
send_data('ten', pm_ten_aqi)
return [pm_twofive_aqi, pm_ten_aqi]
Converting PPM^2 to AQI
This is converting to the US EPA AQI, in order to use a different standard, you might need to tweak the formula to fit your country's AQI model.
Exponential Backoff
This repo implements an exponential backoff policy to retry connections after an exponentially longer period to account for common network errors or connection issues with your sensor.
def exponential_backoff(n):
return (2 ** n) + (random.randint(0, 1000) / 1000)
Results
First testing against the air quality outside, make sure it seems to match up with IQ Air's Air Quality Index.
After a few weeks of running the sensor, it seems the sensors on my air purifiers would often underreport pm2.5 values by as much as 50% and were seldom correlated with each other. The Raspberry Pi on the other hand, filtering out for data spikes, seems to respond very reasonably to real world phenomena such as rising with the outdoor AQI and falling linearly when the purifiers are all left on high for a few hours. I have also learned how much barometric pressure differences will also increase the penetration of outdoor pollution to my home. Interestingly, poor kitchen ventilation also causes quite noticeable spikes in indoor air pollution!
I've been using this sensor a few months now and have since felt much more empowered with managing the quality of the air I breathe each day.
Adding Sensors
This project can be easily extended by adding additional sensors, such as an Ozone (O3), Carbon Monoxide (CO), Nitrogen Dioxide (NO2), or any other harmful air pollutants that might be more relevant to your area. If you do, please let me know and I'd like to compare your findings and update the AQIPi repository to extend the project.
Acknowledgements
Big thanks to Andrew Gregory from raspberrypi.org on his work providing the inspiration for this project.
You can view this article and more like it as well as sign up to my newsletter to get the latest posts on https://jt.houk.space
Top comments (1)
Hi guys, for the newbies like me, a few steps that were missing maybe because they were too obvious.
You also have to install adafruit in your Raspberry Pi: pip3 install adafruit-io
python-dotenv needs to be added: python3.9 -m pip install python-dotenv
And also open the port you gonna use to ingest the data, this part I am still trying to figure it out :)
It is a cool project!