Indoor air: which fan to run
"Air quality" is four different problems that want four different fans. Bringing in outdoor air fixes CO₂ and makes a smoke day worse. A filter fixes smoke and does nothing for CO₂. The outcome is one sentence: breathe well tonight. The controller's job is picking the fan.
Four numbers, four fans
- CO₂ tells you how stale the air is. Under 800 ppm feels fresh; above 1,000 ppm people get slow and sleep worse. The only fix is outdoor air: an energy‑recovery ventilator (ERV) on boost, or the HVAC fan with a fresh‑air damper open.
- PM2.5 is smoke, cooking and dust. The EPA's daily standard is 35 µg/m³, and its annual standard is 9. The fix is a filter: a HEPA purifier in the room, or the HVAC fan through a MERV 13 filter, with the fresh‑air damper closed when the outdoor number is worse than the indoor one.
- Radon is the one you cannot feel. The EPA action level is 4 pCi/L. A mitigation fan under the slab runs all the time; the automation is watching that it does, since a failed fan is silent.
- Humidity above 50% grows mold and below 30% cracks lips and furniture. A bath fan after a shower and a dehumidifier in summer handle the top; the ERV in winter handles the bottom.
Sensors with a local path
- AirGradient ONE. Open hardware and firmware. CO₂, PM2.5, TVOC, NOx, temperature and humidity, served as JSON on the device and published over MQTT every minute. The best single sensor for this job.
-
Awair Element. Turn on Local API in the app and the device answers
/air-data/lateston your network. -
PurpleAir. Indoor or outdoor, each sensor serves
/jsonlocally. The outdoor one is what tells the controller the damper must stay closed. - Aranet4 and Airthings Wave. Bluetooth LE. The Pi reads them directly; the Airthings Wave adds radon.
- IKEA VINDSTYRKA and Aqara TVOC over Zigbee, and any Matter air quality sensor, which reports one AirQuality index the model maps to the same capability as everything above.
Actuators with a local path
- The HVAC fan. Venstar ColorTouch thermostats have a documented local REST API with a fan mode; Honeywell T6 Pro Z‑Wave thermostats expose the same over Z‑Wave. Either lets the controller run the fan through the house filter without touching a setpoint.
- ERV boost and dampers. Most ERVs and HRVs have a dry‑contact boost input meant for a bathroom switch. A relay on the Pi is that switch. Motorised fresh‑air dampers are 24 VAC and wire the same way.
- Purifiers. Dyson machines take commands over local MQTT. IKEA STARKVIND is Zigbee. Matter air purifiers expose fan speed as a standard cluster. Levoit, Coway and Blueair are cloud tier: usable with the cloud layer on, and marked as such.
- Bath fans, whole‑house fans, the radon fan's monitor. A Shelly relay in the box gives local HTTP and MQTT control, and its power reading tells you the radon fan is actually spinning.
The rules, including the one that prevents harm
if outdoor_pm25 > indoor_pm25: damper = closed; erv_boost = off // never pull smoke in
if indoor_pm25 > 12: purifier = high; hvac_fan = on
if co2 > 1000 and damper open ok: erv_boost = on until co2 < 800
if humidity > 60 for 10 min: bath_fan = on until humidity < 50
if radon_fan_power < 10 W: fault "radon fan stopped"
if any sensor age > 15 min: treat its number as Uncertain, do not act on it
The first rule is the whole reason to automate this rather than schedule it. On a clear night, high CO₂ means open up. On a wildfire night, the same reading means filter harder and wait. A timer cannot tell those apart. A controller that sees the outdoor PurpleAir and the indoor AirGradient can.
What this looks like in the capability model
Every sensor above provides CO2, ParticulateMatter,
Radon or Humidity as measured values with an age. The
purifier provides Level with its declared speeds, so asking for 70% on a
three‑speed machine answers with the speed it will actually run. The relay driving the
ERV boost is a Switch that is commanded, not measured: unless a current
sensor confirms it, its state is Uncertain, and the controller says so instead of
assuming the ventilator is running.