Skip to main content

ESP32 air quality monitoring

I hope by now we all realise the importance of proper ventilation in your house. High CO2 levels may induce headaches and drowsiness.
As such, as I was interested in monitoring the CO2 level inside my house. A quick look online reveals even the most basic off the shelf product that measures and displays this data costs upwards of NZ$150 ($90 USD). Apart from the high price, using an off the shelve sensor has multiple issues:

  • I don’t want or need a built-in display
  • These devices don’t have built in smarthome connectivity such as Wifi, bluetooth or Zigby
  • If the device breaks, I have no idea how to repair it
  • I don’t learn any new skills from plopping one in the corner of my living room

Therefore, I decided to build one from scratch using cheap and easy to source components. I want this DIY solution to do and have everything that an off the shelve sensor doesn’t.

The final result: SCD30 (left) connected to ESP32 (middle) connected to homelab for power using USB C (right).
The final result: SCD30 (left) connected to ESP32 (middle) connected to homelab for power using USB C (right).

I chose to use an ESP32 microcontroller with an SCD30 sensor. This sensor measures CO2 in parts per million (ppm) as well as temperature and humidity. Initially, I tried the more expensive SCD41, but that was either a DOA or I broke it in the first minute of using it. This is the list of parts ordered from AliExpress (prices including shipping):

  • ESP32 with USB C: NZ$12.20
  • Sensiron SCD30: NZ$33.07
  • Jumper wires: NZ$0.50
  • Board pin headers: NZ$0.50
  • Soldering iron borrowed from a friend: NZ$0.00

In total, the cost is about NZ$45, more than three times cheaper than an off the shelve solution. When subtracting shipping costs, it’s only NZ$31!

Now for the fun part, the assembly and software. The wiring is straight forward. First, as the sensor doesn’t have preinstalled pin headers, solder the headers onto the sensor board. Connect the 5V output from the ESP32 to VDD on the SCD30. Connect GND on the sensor to ground on the ESP32. The sensor sends data through the I2C bus, so connect the sensor’s SDA and SDL to programmable pins on the ESP32. I chose pin 21 for SDA and pin 22 for SDL. Finally, the SEL pin on the sensor should be pulled to ground to enable I2C, so connect the pin to ground on the ESP32.

Wiring of the ESP32 (left, upside down) and SCD30 (right, upside down).
Wiring of the ESP32 (left, upside down) and SCD30 (right, upside down).
Top view of the SCD30 with a sketchy soldering job.
Top view of the SCD30 with a sketchy soldering job.

For the software, I used ESPHome to flash the firmware onto the ESP32 and have built in integration with Home Assistant. The configuration is defined as a yaml file. The full yaml file can be found on my GitHub. To get the ESP32 to detect and interact with the SCD30, we need to set the i2c and sensor sections of the ESPHome yaml as follows:

i2c:
  sda: GPIO21
  scl: GPIO22
  scan: True
  id: bus_a

sensor:
  - platform: scd30
    co2:
      name: "CO2"
      accuracy_decimals: 1
    temperature:
      name: "Temperature"
      accuracy_decimals: 2
    humidity:
      name: "Humidity"
      accuracy_decimals: 1
    address: 0x61
    i2c_id: bus_a
    update_interval: 30s

This configuration takes a reading every 30 seconds using the I2C bus.

To store and display a timeseries of the data, I used Home Assistant. As the ESP32 has Wifi and is connected to the home network, it’ll be automagically detected by Home Assistant when trying to add a new ESPHome device. Enter the encryption key (if set), and connect. The CO2, temperature and humidity data should now show up on your Home Assistant dashboard.

CO2, temperature and humidity readings in Home Assistant.
CO2, temperature and humidity readings in Home Assistant.

The readings are saved to Home Assistant’s built in time series database and can be displayed as time series on a graph.

CO2 (ppm) timeseries of a week displayed in Home Assistant.
CO2 (ppm) timeseries of a week displayed in Home Assistant.
Temperature (°C) timeseries of a week displayed in Home Assistant.
Temperature (°C) timeseries of a week displayed in Home Assistant.
Humidity (%) timeseries of a week displayed in Home Assistant.
Humidity (%) timeseries of a week displayed in Home Assistant.

This setup is simply powered by USB C and can therefore be plugged in to any outlet in the house and still provide readings to home assistant. It can easily be extended with more sensors (e.g. a BME280 for air pressure and tempreature and humidity redundancy or a BH1750 for measuring ambient light). To completely finish this project, I’d have to design and 3D print an enclosure. Who knows, maybe in a few years from now…