Whole-flat CO₂ purge with a 9-minute cross-ventilation window
Four CO₂ sensors across the flat trigger a 9-minute cross-ventilation on the two opposite windows when the mean reading passes 1 100 ppm, then re-check and repeat up to three times. Air changes measured at 4.1 ACH during the open phase.
# HearthNodes recipe 13 - whole flat CO2 purge
alias: "Climate - whole flat cross ventilation purge"
id: hn_climate_co2_purge
description: "9 minute full-opening cross purge, re-check and repeat up to 3x"
mode: single
max_exceeded: silent
trigger:
- platform: numeric_state
entity_id: sensor.flat_mean_co2
above: 1100
for: "00:05:00"
variables:
purge_windows:
- cover.living_window
- cover.bedroom_window
purge_seconds: 540
settle_seconds: 240
max_rounds: 3
reporting_sensors: >-
{{ states.sensor
| selectattr('entity_id','search','^sensor\.co2_')
| selectattr('state','ne','unavailable') | list | count }}
condition:
- condition: template
value_template: "{{ reporting_sensors | int(0) >= 3 }}"
- condition: numeric_state
entity_id: sensor.indoor_outdoor_delta_t
below: 8
- condition: state
entity_id: input_boolean.window_lockout
state: "off"
- condition: numeric_state
entity_id: sensor.outdoor_pm25
below: 35
action:
- repeat:
count: "{{ max_rounds }}"
sequence:
- service: climate.turn_off
target:
entity_id: climate.mvhr
- service: cover.set_cover_position
target:
entity_id: "{{ purge_windows }}"
data:
position: 100
- delay: "00:09:00"
- service: cover.set_cover_position
target:
entity_id: "{{ purge_windows }}"
data:
position: 0
- delay: "00:04:00"
- if:
- condition: numeric_state
entity_id: sensor.flat_mean_co2
below: 800
then:
- service: climate.turn_on
target:
entity_id: climate.mvhr
- stop: "CO2 cleared"
# Kitchen sensor is excluded from the mean for 45 minutes after the hob exceeds
# 200 W. Fewer than three reporting sensors -> no purge at all, plus a fault
# notification. A window that fails to close trips the local lockout button.
Trigger · numeric_state
sensor.flat_mean_co2
Mean CO₂ across all reporting sensors exceeds 1 100 ppm for 5 minutes.
Step-by-step
- cover.living_window · cover.bedroom_windowOpen both opposite windows fully for 9 minutes — full opening, not a crack, is what gets 4 ACH instead of 1.2.
set_cover_position · 100 for 9 minutes - climate.mvhrStop the mechanical ventilation during the purge; running both wastes heat and fights the stack effect.
turn_off during purge · restore after - timer.purge_recheckClose, wait 4 minutes for the sensors to settle, then re-read; repeat the cycle at most three times before giving up and notifying.
wait 9 min · close · wait 4 min · re-read - sensor.co2_historyRecord each purge's starting and ending CO₂ so the ventilation strategy can be judged on data, not on comfort complaints.
record purge count and duration
Purge in one 9-minute burst, not two short ones
A 4-minute purge barely moves the reading because it has to flush the room's volume first; you then need a second purge 20 minutes later. One 9-minute burst reaches 4.1 ACH and leaves the flat at 620 ppm, which buys about two and a half hours. Short pulses feel better and work worse.
Exclude the kitchen sensor while cooking
A gas hob produces CO₂ that has nothing to do with ventilation need. Suppress the kitchen sensor's contribution to the mean for 45 minutes after the hob's power draw exceeds 200 W, otherwise every dinner triggers two purges in winter.
Ask for a ΔT limit, and mean it
A purge on a very cold morning dumps the flat's heat in nine minutes and costs more to reheat than the CO₂ reduction is worth. An 8 °C limit keeps the practice sensible; below that, boost mechanical ventilation instead.
Hardware
| Model | Protocol | Link | Role in this chain |
|---|---|---|---|
| NDIR CO₂ sensors (e.g. Aqara or Aranet-class) on Thread where possible | thread |
wireless | Four units: living room, main bedroom, second bedroom, kitchen. Kitchen readings are excluded from the mean during cooking. |
| Thread window actuators | thread |
wired | Chain actuators on the two opposing windows; these are the only two that produce useful cross-flow in this flat. |
| Indoor/outdoor temperature pair | thread |
wireless | Provides the ΔT condition that keeps the purge from running on a -10 °C January morning. |
When it fails
If fewer than three CO₂ sensors report, the purge does not run at all and a sensor-fault notification is raised — a purge driven by one sensor can over-ventilate a flat for hours. If a window fails to close at the end of a cycle, the automation retries twice and then trips the local lockout button so nobody is left with an open window they did not ask for.