Measuring interior air quality

Recent events on the west coast have left us with air that is so dirty as to be considered unhealthy. It is recommended that people at this time stay inside to avoid breathing this dirty air which is dirtier even than the most filthy air in the industrial cities of China. This makes you wonder how much safer it is inside than out. The air that you breathe is coming through the walls and windows of your house that aren’t perfectly sealed. If it wasn’t it stands to reason you might die of CO2 poisoning after a time of not opening your door or window. This is actually possible with modern manufactured homes that are made to more exacting specs, or so I’ve heard.

I coincidentally was reading about the dangers of particulates in the air we breathe several weeks before the fires of the West Coast destroyed everything and decided to buy some sensors to attach to my old fleet of raspberry pi’s that were languishing in a box. The sensor can be purchased from here. It has a little tiny impeller fan that drags air through it and fires a laser through this air to measure particulates. Essentially, “the SDS011 using principle of laser scattering, can get the particle concentration between 0.3 to 10μm in the air“.

A great primer on the use of the SDS011 sensor and how to use it with a raspberry pi is found here. Unfortunately I wasn’t able to get the software from that writeup working so I found a different github account and used their software and got working results.

The results can be saved in a database or csv format. Here is an example from my kitchen:

‘2020-09-12 15:24:12.303115’, ‘11.9’, ‘18.5’, ‘18054’]
[‘2020-09-12 15:29:12.718003’, ‘27.3’, ‘44.6’, ‘18054’]
[‘2020-09-12 15:34:13.122560’, ‘27.1’, ‘44.7’, ‘18054’]
[‘2020-09-12 15:39:13.534483’, ‘29.8’, ‘46.2’, ‘18054’]
[‘2020-09-12 15:44:13.932565’, ‘34.3’, ‘54.3’, ‘18054’]
[‘2020-09-12 15:49:14.345529’, ‘33.7’, ‘54.2’, ‘18054’]
[‘2020-09-12 15:54:14.779727’, ‘34.6’, ‘54.6’, ‘18054’]
[‘2020-09-12 15:59:15.213513’, ‘36.0’, ‘60.4’, ‘18054’]
[‘2020-09-12 16:04:15.638646’, ‘41.6’, ‘69.0’, ‘18054’]
[‘2020-09-12 16:09:16.063939’, ‘40.2’, ‘75.1’, ‘18054’]
[‘2020-09-12 16:14:16.481698’, ‘45.3’, ‘88.6’, ‘18054’]

First is a timestamp, then the aqi measurement of 2.5 micron (pm2.5) followed by 10 micron and then the device id. It is measured every five minutes.

It is pretty easy to install the software to get this to work. You need to be able to ssh into your pi. Then install git, python3, and python3-pip. Then type

git clone

cd sds011

pip3 install .

At this point you will have the program installed. Next you have to change directory to ./sds011/sds011/examples/ and edit I like nano. You have to delete the # in front of the information about five minutes. Here’s my working python file:

from sds011 import SDS011

port = “/dev/ttyUSB0”

sds = SDS011(port=port,use_database=False)
sds.set_working_period(rate=5)#one measurment every 5 minutes offers decent granularity and at least a few years of lifetime to the sensor
import csv
with open(“measurments.csv”,”w”) as csvfile:
log = csv.writer(csvfile, delimiter=” “,quotechar=”|”, quoting=csv.QUOTE_MINIMAL)
logcols = [“timestamp”,”pm2.5″,”pm10″,”devid”]
while True:
meas = sds.read_measurement()
vals = [str(meas.get(k)) for k in logcols]

except KeyboardInterrupt:

To see if it works, type:


If it is working, you will see this:

SDS011 Device ID: 4686
Firmware Date: 2018-11-16
SleepWorkState: sleep
DataReportingMode active

Unfortunately only one of the three sensors I got actually worked correctly. I’ve verified this by plugging all three into the same raspberry pi I got a sensor working on. One of the sensors displays DataReportingMode as query instead of active:

SDS011 Device ID: B118
Firmware Date: 2018-11-16
SleepWorkState: work
DataReportingMode query

Apparently one can change the reporting mode if they know how to program, it is set by default to report in active mode from the factory though and I don’t think I changed it since I don’t know how. The other sensor exhibits a different error. After running the same program on a different sensor, I get the following traceback:

Traceback (most recent call last):
File “”, line 5, in
sds = SDS011(port=port)
File “/home/pi/.local/lib/python3.7/site-packages/sds011/”, line 130, in init
File “/home/pi/.local/lib/python3.7/site-packages/sds011/”, line 138, in probe
fwdata = self.get_firmware_version()
File “/home/pi/.local/lib/python3.7/site-packages/sds011/”, line 223, in get_firmware_version
return self.request(cmd)
File “/home/pi/.local/lib/python3.7/site-packages/sds011/”, line 228, in request
resp = self.rx_cmd_resp_queue.get(timeout=10)
File “/usr/lib/python3.7/”, line 178, in get
raise Empty

The author of the python program I’m using suggested that the raspberry pi3 is at fault, he stopped buying them after raspberry pi 2 because of some technical issues:

Long story short, uart0 is corrupted on PI3 or PI4
if you don’t disable the adaptive CPU frequency scaler. I stopped
purchasing PIs after they screwed this up on the PI3.
On USB everything should work.

>  it never leaves query state
Check if the sensor spins the fan. If that’s the case you have a
communication error on the RX side, e.g. rx_handler() does not receive a
valid frame.

Unless you actively set it to query mode
by calling set_data_reporting(modesel=”query”)
It should not change the data reporting mode to query.


Published by

Bjørn Madsen

I am the Seattle locksmith you've been looking for. High Quality work at a reasonable price delivered in a timely fashion.