I recently watched Jeff Gerling’s video on CO₂ levels, and how to monitor it. My home office is also in the basement, with no windows. So I paid attention to the air quality when setting up down here.
In addition to monitoring the CO₂ level, I’m also automatically ventilating the space when the air quality gets too bad.
Table of contents
CO₂ levels
- 250-400ppm
- Normal background concentration in outdoor ambient air
- 400-1,000ppm
- Concentrations typical of occupied indoor spaces with good air exchange
- 1,000-2,000ppm
- Complaints of drowsiness and poor air.
- 2,000-5,000 ppm
- Headaches, sleepiness and stagnant, stale, stuffy air. Poor concentration, loss of attention, increased heart rate and slight nausea may also be present.
The sensor

I’ve purchased a Netatmo air quality sensor — it seemed to be the cheapest, and easiest way of reliably monitoring temperature, humidity, and CO₂. It sends me a notification if any of the values go above or below the “safe” zone.
It’s also very easy to add to Home Assistant, more on that below.
The fan

The fan is a backward centrifugal extractor (RK 125L), capable of moving 168 m³/hour (99 ft³/min). I have a speed controller for the fan, but I mostly run it at full speed.
Our basement is about 40 m³ (1412 ft³) — so at full speed, the air is replaced 4.2 times per hour, theoretically. Meaning that it takes about 15 minutes to replace the air — again; theoretically.
Home Assistant
I’m using Home Assistant to automate the fan — based on the measured CO₂ level.
Controlling the fan

To control the fan I’m using a TP-Link HS110 smart plug. It also measures the watts used by the fan, and I use that to determine the fan speed step set on the controller.
Defining the smart plug:
tplink:
discovery: false
switch:
- host: 10.x.x.x
Figure out the fan speed step:
template:
- sensor:
- name: "Fan speed"
unit_of_measurement: 'step'
state: >
{%- if states.sensor.office_fan_current_consumption.state | int > 70 %}
5
{%- elif states.sensor.office_fan_current_consumption.state | int > 50 %}
4
{%- elif states.sensor.office_fan_current_consumption.state | int > 40 %}
3
{%- elif states.sensor.office_fan_current_consumption.state | int > 30 %}
2
{%- elif states.sensor.office_fan_current_consumption.state | int > 20 %}
1
{%- elif states.sensor.office_fan_current_consumption.state | int < 20 %}
0
{% else %}
fail
{%- endif %}
icon: >
{%- if states.sensor.office_fan_current_consumption.state | int > 3 %}
mdi:fan
{% else %}
mdi:fan-off
{%- endif %}

Reading the sensor
The Netatmo sensor is added as an integration, and to do that we need to define the API credentials:
netatmo:
client_id: xxxxxxxxxxxxxxxxxxxxxxxx
client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
This gives us access to the sensor data:

Automating the fan
I have a script that runs the fan for 15 minutes, this allows me to “manually” replace the air down here:
script:
vent_office:
alias: Ventilate office
sequence:
- service: switch.turn_on
data:
entity_id: switch.office_fan
- delay:
minutes: 15
- service: switch.turn_off
data:
entity_id: switch.office_fan
And the automation that starts the fan if the CO₂ level rises above 1200ppm:
- alias: Fan on auto
trigger:
platform: numeric_state
entity_id: sensor.netatmo_office_co2
above: 1200
action:
service: switch.turn_on
entity_id: switch.office_fan
- alias: Fan off auto
trigger:
platform: numeric_state
entity_id: sensor.netatmo_office_co2
below: 1200
action:
service: switch.turn_off
entity_id: switch.office_fan

The CO₂ level quickly drops when it hits the 1200ppm threshold, ensuring that the air down here never gets too bad 🙂
Last commit 2024-11-11, with message: Add lots of tags to posts.