Alert when CO2 stays high in a space
Sample every CO2 sensor in a meeting room (or floor, or building) every 10 minutes, average the last 15 minutes of readings, and send a Slack DM when the average crosses the threshold you set. The average smooths out brief spikes from a door closing, so the DM only fires when the air actually needs attention. For facilities and FM teams who want a credible CO2 escalation without writing per-sensor workflows.
What this workflow does
- A Schedule trigger runs every 10 minutes.
- A Find Devices condition pulls every device in the chosen space (with descendants on) that reports the CO2 sensor type. Routes none silently when there are no CO2 sensors so the workflow ends on an unmonitored space.
- A Sensor Window Aggregate action computes the average CO2 across those devices over the last 15 minutes and emits the value.
- An If condition routes to true when the average is at or above your threshold (1200 ppm is a common starting point).
- A Cooldown condition stops the alert firing more than once per hour for the same space.
- A Send Direct Message action DMs the FM rota with the space name and the measured average.
![Workflow canvas: Schedule → Find Devices (sensorTypes=[CO2], recurse=on) → Sensor Window Aggregate (aggregator=avg, window=15m) → If (value >= 1200) → Cooldown (1h) → Send DM. Highlight the edge from Find Devices' found port and the true edge out of If.](https://kb.neowit.io/hs-fs/hubfs/image-png-Jun-12-2026-09-48-51-9802-AM.png?width=632&height=316&name=image-png-Jun-12-2026-09-48-51-9802-AM.png)
Prerequisites
- Workflows enabled for your org. See Enable workflows for your org.
- At least one integration reporting CO2 sensors in the space (e.g. Airthings, Disruptive, Vergesense).
- Slack integration connected so the action can DM a recipient.
Build it
1. Create the workflow
Workflows → New workflow → name CO2 — high alert (avg 15m) → Create.
2. Add the schedule trigger
- Add node → Triggers → Schedule.
- Set:
- Schedule type — Every N minutes.
- Timezone — your office's IANA zone, e.g.
Europe/Oslo. - Minutes —
10.
3. Add Find Devices
- Add node → Conditions → Find Devices.
- Settings:
- Space — pick the building (or floor, or room) you want to monitor.
- Include descendants — on so every room under the chosen space is covered.
- Sensor types —
CO2. - Leave Integration, Vendor, Model, and Tag empty unless you want to scope further.
- Connect the Schedule trigger to Find Devices.
4. Add Sensor Window Aggregate
- Add node → Actions → Sensor Window Aggregate.
- Settings:
- Devices — click the data-reference icon and pick
findDevices.deviceIds(the field name uses the node's internal id; the picker shows it). - Sensor type —
CO2. - Aggregator — Average.
- Window —
15m.
- Devices — click the data-reference icon and pick
- Connect Find Devices' found port to this action.
5. Add an If condition for the threshold
- Add node → Conditions → If.
- Add one row:
- Value 1 — data-reference pick
sensorWindowAggregate.value. - Operation — number is greater than or equal to.
- Value 2 —
1200.
- Value 1 — data-reference pick
- Connect Sensor Window Aggregate's main port to the If's input.
6. Add a Cooldown
- Add node → Conditions → Cooldown.
- Settings:
- Duration —
1h. - Key —
co2-{{ .findDevices.devices.[0].id }}(or any field that varies per space — see Stateful conditions for the keying patterns).
- Duration —
- Connect the true port of If to Cooldown's input.
7. Add Send Direct Message
- Add node → Actions → Send Direct Message.
- Settings:
- Recipient — your FM rota's Slack handle.
- Message —
CO2 average is {{ .sensorWindowAggregate.value }} ppm over the last 15 minutes — please check ventilation.
- Connect Cooldown's passed port to the action.
8. Save and enable
Click Save, leave Enabled on, write a commit message, and the workflow takes over.
Variations
- Tighter on a single room. Pick a room as the space, leave Include descendants off, and the workflow watches a single sensor's average.
- Different sensor. Swap CO2 for TEMP (heat alerts) or VOC. Adjust threshold and window accordingly.
- Aggregator choice. Average smooths bursts. Maximum fires on any spike. Minimum is useful for "the air never recovered below X for 15 minutes".
- Different escalation. Replace Send DM with Post To Channel for a public room alert, or chain a Counter for a daily digest.
When it doesn't fire
- No DM arrived. Open Executions. If Find Devices routed to none, the chosen space has no CO2-reporting devices — check the device list in the org. If the If condition routed to false every run, the threshold is too high for current conditions; drop it temporarily to verify the workflow itself works.
- Too many DMs. Tighten the Cooldown duration, or raise the If threshold to
1500so only sustained-high air triggers it. - No data in the window. If the sensor is offline, Sensor Window Aggregate fails the task with
"no data in the window"— visible in Executions on that step. There's no separate "stale" branch yet — pair with a device-health workflow if you need an offline alert.