Blog

Air Quality Sensor Using ESP32 (CO2, Humidity, Temperature)

9/16/2025 2 min read
Air Quality Sensor Using ESP32 (CO2, Humidity, Temperature)

Simple CO₂ Monitor with Arduino, SCD30, and OLED

In this blog post, I will show you how to create a simple yet effective CO₂ monitor using an Arduino, the Sensirion SCD30 CO₂ sensor, and a small, stylish OLED display.


Wiring

Both the display and the sensor support I2C communication and can be operated with a voltage between 3 and 5 volts.

When using an ESP32, the usual pins are:

  • SDA: Pin 21
  • SCL: Pin 22

The pins on both the display and the sensor are labeled, so you just need to connect them correctly.

I2C is a bus system, which means:

  • SDA lines of all I2C devices are connected together to pin 21
  • SCL lines of all I2C devices are connected together to pin 22

I used a Wago connector, but you can also solder the connections.


Code

Make sure you have installed all necessary libraries in your Arduino IDE.

Required Libraries

  • Wire.h – I2C communication
  • SparkFun_SCD30_Arduino_Library – SCD30 sensor
  • Adafruit_GFX – graphics library
  • Adafruit_SH110X – OLED display

Arduino Sketch

#include <Wire.h>
#include "SparkFun_SCD30_Arduino_Library.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

SCD30 airSensor;
Adafruit_SH1106G display(128, 64, &Wire, -1);

unsigned long previousMillis = 0;  // Timestamp of last update
const long interval = 180000;      // Interval period (3 minutes)
int offsetX = 0;                   // Initial offset values
int offsetY = 0;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  airSensor.begin();

  display.begin(0x3C, true); 
  display.clearDisplay(); 
  display.setTextSize(2);
  display.setTextColor(SH110X_WHITE);
}

void loop() {
  unsigned long currentMillis = millis();

  // Check if interval has elapsed
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    // Slightly shift cursor position
    offsetX = (offsetX + 1) % 5;
    offsetY = (offsetY + 1) % 5;
  }

  if (airSensor.dataAvailable()) {
    display.clearDisplay(); 

    // CO2 value in ppm
    display.setCursor(offsetX, offsetY);
    display.print(airSensor.getCO2());
    display.println(" ppm");

    // Temperature in degrees Celsius
    display.setCursor(offsetX, 20 + offsetY);
    display.print(airSensor.getTemperature(), 1);
    display.println(" C");

    // Relative Humidity in percent
    display.setCursor(offsetX, 40 + offsetY);
    display.print(airSensor.getHumidity(), 1);
    display.println(" %");

    display.display(); 
  }

  delay(500);
}

Setup

First, initialize the components:

  • Wire.begin() starts I2C communication
  • Serial.begin(9600) opens the serial port
  • airSensor.begin() initializes the SCD30 sensor
  • Prepare the display (address, resolution, text size, and color)

This ensures all components start correctly and display data cleanly.


Main Loop

In the loop() function, the main work happens:

  • Time-controlled shift of the display position
  • Query new sensor data
  • Update the OLED display

Display Output

Measurements are shown with a slight positional offset. This not only creates a more dynamic image but also reliably protects the OLED from burn-in.


3D Printed Case

Printing requires no special settings.

Recommendations:

  • Use support material at the front to hold the structure above the display
  • Print the lid with Tree Support

3D print files will be provided separately.


Conclusion

With this project, you have built a compact and powerful CO₂ monitor. A Home Assistant integration will follow in a few days.