Automating my indoor air quality

2020 was a lot of terrible things, and one terrible thing we learned a lot about was wildfires. 2020 was the worst year for wildfires in California history, topping the previous worst-ever year in 2018. We saw the first ever gigafire (1 million acres burned) in California, and facing down one of the driest Januaries on record in 2021, it seems like year-round wildfires are the new reality.

Poor air quality is an insidious thing. You can’t always see it or smell it, and you might not feel sick. But, over time, these small particles build up in your body and have a detrimental effect on your lungs and heart. Population-level studies from polluted cities in China and India make it very clear: breathe a lot of fine particulate matter (PM2.5), die sooner.

Source: Hoodline

So, air quality is a problem, but what can we do about it? The recommendation from the CDC and other health organizations is simple: stay inside. Wildfires and other major sources of air pollution like cars and factories are outside, so by staying inside, you lower your exposure to bad air. This makes sense, but when the skies are literally red because of suspended smoke particles, these basic measures may not be enough.


The first step was measurement. PurpleAir was one of the breakthrough websites of the year: a real-time, crowd-sourced air monitoring platform. We were already in the habit of checking our outdoor AQI on PurpleAir multiple times a day, so I bought one of their indoor air quality sensors. Besides uploading data to PurpleAir, the sensor also glows different colors from green to red to visually indicate its current air quality reading.

This data was a revelation. We made a number of important discoveries:

  • Our indoor air quality was basically the same as outdoors. I think the CDC’s advice to close windows helps if the poor air quality is because of car traffic which peaks during commuting hours, but wildfires burn all day and all night, continually producing fine particulate matter.
  • Cooking is really bad for indoor air quality. Turning on our gas range makes our sensor glow yellow, and using the toaster oven spikes it straight to red. Stir-frying or sauteeing with oil is also an instant red. Fortunately we have a range hood which vents externally, but I wasn’t good about using it. Now, I make sure to turn it on whenever I use the stove.
  • Our existing air filter was not enough. We had a single Coway Mighty air purifier, and it was just barely able to keep one room green/yellow with the door closed.

We quickly bought another Coway so we could each have one with us throughout the day. This sufficed, until there were especially bad days where even a Coway on full blast couldn’t keep the air quality in check.

It was time to upgrade. We went for another Wirecutter pick, the BlueAir 211. This unit has almost twice the filtration capability as the Coway, and is much quieter too. However, unlike the Coway, the BlueAir lacks a smart mode that automatically turns the filter on and off based on the current air quality.

Smartening up my air purifier

This was the perfect application for a little home automation. I had the PurpleAir sensor, which uploaded live data to the PurpleAir website exposed via a JSON API. I had the BlueAir filter. I also had a Kasa smart plug I could use to turn the filter on and off. I logged into my Raspberry Pi home server and wrote a script.

#!/usr/bin/env python3

import asyncio
import os
import requests
from kasa import Discover
import time
import json
from pprint import pprint
import logging

INDOOR_SENSOR_ID=12345 # Enter your PurpleAir sensor ID here

logger = logging.getLogger(__name__)

def turn_on(device):
    if not device.is_on:"Turning filter on")
    else:"Filter is already on")

def turn_off(device):
    if device.is_on:"Turning filter off")
    else:"Filter is already off")

def run():
    devices =
    device = None
    for addr, dev in devices.items():
        if dev.alias == 'Living room air filter':
            device = dev"{addr} >> {dev}")

    assert device

    resp = requests.get(PURPLEAIR_API_PATTERN).json()
    stats = json.loads(resp['results'][0]['Stats'])
    for k,v in stats.items():'Sensor PM2.5 stats: {k}: {v}')
    pm_2_5 = stats['v1'] # 10-min average PM 2.5"PM 2.5 level: {pm_2_5} ug/m3")

    current_hour = time.localtime().tm_hour

    if current_hour < 7:"It's night time")
    elif pm_2_5 > 7:"Air quality is bad!")
    else:"Air quality is good!")

This script took about 20 minutes to write, including looking up the APIs for PurpleAir and the Kasa plug. It’s meant to be invoked periodically (e.g. via watch(2) or cron). It works by hitting PurpleAir to get the current PM2.5 reading. If the reading is too high, it’ll turn the sensor on. Otherwise, it’ll turn the sensor off. Because this is all running on my private home network, the script can talk to the Kasa smart plug directly without any kind of authentication.

Indoor air quality: problem solved?

With the smartened-up BlueAir, our indoor air quality vastly improved. I had to tune the thresholds and cron intervals a bit, but now it’s able to keep our indoor air consistently green throughout the day.

Does this mean we’re ready for next year’s wildfire season? Yes and no. With the extra air filters, I feel good about our indoor PM2.5 levels. However, with all the windows and doors sealed up, high CO2 levels are a real concern. High CO2 levels reduce oxygen levels in the brain and impair mental function. I think it’s also interesting that public health experts are also looking at indoor CO2 levels as a proxy for airborne transmission of the coronavirus. Point being, air circulation is important.

How were you affected by the 2020 wildfires? Have you taken any steps to improve your personal air quality? Let me know in the comments.

Leave a Reply