Air Quality Sensors and IoT Systems Monitoring
2017 was a bad year for fires in California. The Tubbs Fire in Sonoma County in October destroyed whole neighborhoods and sent toxic smoke south through most of the San Francisco Bay Area. The Air Quality Index (AQI) for parts of that area went up past the unhealthy level (101–150) to the hazardous level (301–500) at certain points during the fire. Once word got out that N99 dust masks were needed to keep the harmful particles out of the lungs, they became a common sight.
The EPA maintains the AirNow website, which displays the AQI for the entire US. The weather app on my Pixel phone conveniently displays a summary of the local air quality from the EPA’s source. This was my goto source for information about the outdoor air quality once the fires started. However, I started to notice that the observed air quality often didn’t match that of the app. I realized that the data reported on the app was often delayed by an hour or more, and the local air quality could change much more quickly than was reported by the AirNow resource.
I started to look into how often the data was updated, and where the sensors that collected it were located. Unfortunately, I wasn’t able to find a lot of details. However, I did come across a link to PurpleAir.com while browsing a local news site. PurpleAir reports on the same air quality metrics as the EPA source, but uses sensors that were hosted by individuals. They have a network of over a thousand sensors across the planet, and the sensor density in the SF Bay Area is quite good, as can be seen from their map. Best of all, the data was reported in real-time. They had one hour averages, last twenty four hours average, particle counts, and so on. This made it easy to check the air quality reported in real-time from a sensor close by, letting us know when it was okay to go out, and when things had gotten bad in our area.
I considered obtaining one of these sensors for myself at the time, but as the Tubbs fire faded, I stopped checking the site as often. However, shortly after the Thomas fire in December, I decided to purchase a Purple Air PA-II sensor. The sensor was easy to setup. I connected it to my WiFi network, gave it a name, location, and some other metadata. It also allowed me to give the sensor a custom url (KEY3) to PUT sensor data. KEY4 allowed me to set a custom HTTP header.
Circonus allows you to post data to it as a JSON object using an HTTPTrap endpoint. I didn’t know what format the PA-II would use to send the data, but I thought this was a good guess. So I created an HTTPTrap, grabbed the data submission URL, and put it into the sensor configuration. About thirty seconds later, metrics started flowing into Circonus. PurpleAir shared a helpful document that described each of these data points.
I wanted to create my own dashboard, but first I needed to understand the data. It turns out that AQI is calculated from the concentration of 2.5 micron and 10 micron particles in micrograms per cubic meter. I wasn’t able to find an equation that allows AQI calculation from these concentrations; it appears that AQI is linearly interpolated between different particulate concentration ranges.
In addition to PM2.5 and PM10, the PA-II provided a number of other particle measurements from its dual laser sensors; in particular, particles per deciliter for particles ranging from 0.3 to 10 microns. It seems that the small particles under 1 micron are exhaled, whereas the 1–10 micron particles are the ones that become lodged in the lungs. The PA-II sensor also provides other metrics such as humidity, barometric pressure, dewpoint, temperature, RSSI signal strength to the WiFi access point, and free heap memory. I put together a dashboard to track these metrics.
Now that I had a dashboard up and running, I could keep a good watch on local air quality, for my neighborhood specifically, in addition to some simple weather measurements. This was quite useful, but I wanted to get a handle on when the air quality started to go bad. So I created a rule to send an alert whenever the PM 2.5 count went over 12, from Good to Moderate.
It took a bit of digging, but I was able to find the AQI breakpoints which correlates air quality index values to PM 2.5 µg/m3. The relation between AQI and particle concentration wasn’t linear across the categories, so I couldn’t apply a formula to calculate the conversion directly. I settled on adding threshold lines to the graphs for each different AQI category. However, I was able to easily set alerts for each threshold for the particulate count boundaries.
If the air quality changed, I got a text message. I created several rules with varying levels of severity, so that I could get an idea of how fast the air quality was changing.
At this point I had a pretty good setup; if the air got bad, I got a text message. The air sensor itself was pretty sensitive to local air quality fluctuations; if I fired up the meat smoker, I’d get an alert. Overall the system was fairly stable, but I did run into some issues where data wasn’t sent to the HTTPTrap at certain times. As a former WiFi firmware engineer, I decided to use tcpdump to look at the traffic directly. To do this, I had to get a host between the sensor and the internet, so I shared my iMac internet connection over WiFi and connected the air sensor to it. The air sensor has a basic web interface that you can use to specify the WiFi connection, and also get a real time readout of the laser air sensors.
Once I had the sensor bridged through my iMac I was able to take a look at the network traffic. The sensor used HTTP GET requests to update the PurpleAir map, and as I had specified in the configuration interface, PUT requests to the Circonus HTTPTrap. Oddly enough, things worked just fine when requests were being routed through the iMac. I came to the conclusion that the Airport Extreme that the sensor was normally associated with might be the source of the failed PUT requests at the TCP level somehow. This is something I need to put some more energy into at some point, but these types of network level issues can be tricky to debug.
Overall, I’m pleased with the result. There are a couple more things I want to try with the sensor, such as putting a second order derivative alert on the air pressure metric to tell when a low pressure region is moving in. The folks at PurpleAir.com were kind and helpful in responding to any questions I had. I’m looking forward to trying out some other sensors that I can plug into a monitoring system. Amazon has a C02 sensor, so that might be next on my list.