ESP Projects

Build a CO2 monitor with an SCD40 and ESPHome

A closed bedroom with two people in it can pass 2,000 ppm of CO2 by morning, enough to leave you groggy. A Sensirion SCD40 or SCD41 sensor on an ESP32 measures it accurately and lets Home Assistant turn on ventilation before the air gets stale.

Why a real CO2 sensor matters

Many cheap "air quality" sensors report an estimated CO2 (eCO2) calculated from other gases. They're rough guesses. The SCD40 and SCD41 measure CO2 directly using a photoacoustic method, and they also report temperature and humidity.

  • SCD40: specified for 400–2,000 ppm, which covers normal indoor air.
  • SCD41: specified up to 5,000 ppm and supports low-power single-shot readings. Worth the extra cost for workshops, grow tents or battery builds.

Parts

  • An ESP32 DevKit and USB power supply.
  • An SCD40 or SCD41 breakout board (the bare sensor is tiny; buy it on a board with pins).
  • A case with vent holes. Air has to reach the sensor.

Wiring

The sensor uses I2C, so it's four wires:

SCD40 pinESP32 pin
VIN / VDD3.3V
GNDGND
SDAGPIO21
SCLGPIO22

The ESPHome config

Add this to an ESP32 config (the config generator makes the base):

i2c:
  sda: GPIO21
  scl: GPIO22

sensor:
  - platform: scd4x
    co2:
      name: "CO2"
    temperature:
      name: "Temperature"
    humidity:
      name: "Humidity"
    automatic_self_calibration: true
    altitude_compensation: 200m
    update_interval: 60s

Set altitude_compensation to your home's elevation. CO2 readings depend on air pressure, and the default assumes sea level.

Calibration

With automatic_self_calibration on, the sensor assumes the lowest reading it sees over about a week is fresh outdoor air (roughly 420 ppm) and adjusts itself. That works well as long as the room gets aired out at some point each week — open a window for a few minutes now and then. In a space that's never ventilated, such as a sealed grow tent, turn it off.

Placement

  • At breathing height, 1–1.5 m off the floor.
  • Not right next to where someone sits or sleeps. Your breath will spike the reading.
  • Away from windows and supply vents, which measure the incoming air instead of the room.
  • Keep the ESP32 out of the sensor's airflow if you can. The board warms up, which skews the temperature reading. A short cable between them helps.

What the numbers mean

CO2 (ppm)What it usually means
~420Outdoor air.
400–800Well-ventilated room.
800–1,000Getting stuffy. A common target to stay under.
1,000–2,000Stale. Many people notice drowsiness and trouble concentrating.
Above 2,000Ventilate now.

Automations

  • Ventilate automatically. Turn on a bathroom fan, an ERV or the furnace fan when CO2 stays above 1,000 ppm for 10 minutes, and off below 800. The gap between the two numbers stops it from cycling on and off.
  • Bedroom nudge. If you sleep with the door closed, a morning summary of the night's peak CO2 makes the case for leaving it cracked open.
  • Room-by-room zoning. CO2 is a strong signal that a room is occupied, which makes it useful alongside presence sensors in an HVAC zoning plan.