SGP30 Air Quality Sensor

How to measure VOC and CO2 levels with the SGP30 sensor and ESP32

The SGP30 is a digital air quality sensor from Sensirion that measures total volatile organic compounds (TVOC) and equivalent CO2 (eCO2). It communicates over I2C, runs on 3.3V, and provides processed readings -- no analog signal processing or calibration curves needed on your end.

This makes it a great choice for indoor air quality monitoring: detecting stuffy rooms, off-gassing from furniture or paint, cooking fumes, or just tracking how ventilation affects your living space.

🔗Key Specs

ParameterValue
Operating voltage1.8V -- 3.3V
InterfaceI2C
I2C address0x58
eCO2 range400 -- 60,000 ppm
TVOC range0 -- 60,000 ppb
Measurement interval1 second (internally)
Baseline calibration~12 hours for initial accuracy
Sensor lifetime> 10 years (typical)

Important distinction: The SGP30 measures eCO2 (equivalent CO2), which is estimated from TVOC levels using an algorithm -- it is not a direct CO2 measurement. For true CO2 readings, you would need a dedicated NDIR sensor like the SCD30 or SCD40. The eCO2 value is still useful for relative indoor air quality assessment, but do not treat it as a precise CO2 measurement.

🔗What You'll Need

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
SGP30 air quality sensor module1AliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires4AliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

🔗Wiring

SGP30 PinESP32 Pin
VIN / VCC3.3V
GNDGND
SDAGPIO 21
SCLGPIO 22

Board variation note: The default I2C pins on the ESP32-WROOM-32 DevKit are GPIO 21 (SDA) and GPIO 22 (SCL), but this varies between boards. Pin labels, GPIO numbers, and I2C defaults can differ -- always verify your board's pinout diagram.

Most SGP30 breakout boards (Adafruit, SparkFun) include pull-up resistors on the I2C lines, so no external pull-ups are needed.

🔗Required Libraries

Install through the Arduino IDE Library Manager:

  • Adafruit SGP30 -- handles I2C communication, measurement commands, and baseline management.

This library also installs Adafruit BusIO as a dependency.

🔗Code Example

#include <Wire.h>
#include <Adafruit_SGP30.h>

Adafruit_SGP30 sgp;

void setup() {
    Serial.begin(115200);
    Wire.begin();

    if (!sgp.begin()) {
        Serial.println("Failed to initialize SGP30. Check wiring.");
        while (1);
    }

    Serial.println("SGP30 initialized.");
    Serial.println("Note: readings improve over 12+ hours of continuous operation.");
}

void loop() {
    if (!sgp.IAQmeasure()) {
        Serial.println("Measurement failed.");
        return;
    }

    Serial.print("eCO2: ");
    Serial.print(sgp.eCO2);
    Serial.print(" ppm  |  TVOC: ");
    Serial.print(sgp.TVOC);
    Serial.println(" ppb");

    // Simple air quality interpretation
    if (sgp.eCO2 < 800) {
        Serial.println("  Air quality: Good");
    } else if (sgp.eCO2 < 1500) {
        Serial.println("  Air quality: Moderate - consider ventilating");
    } else {
        Serial.println("  Air quality: Poor - open a window");
    }

    delay(1000);  // SGP30 updates internally every 1 second
}

🔗How It Works

  1. Multi-pixel gas sensing -- The SGP30 uses a heated metal-oxide sensor element. Volatile organic compounds in the air change the conductivity of this element. The onboard processor converts the raw signal into calibrated TVOC and eCO2 values.

  2. The 15-second measurement cycle -- After calling IAQmeasure(), the sensor returns fresh data. Internally, the SGP30 performs a measurement every second. You should call IAQmeasure() at least once per second to keep the sensor's internal algorithm running properly. If you read less frequently, the dynamic baseline calibration may not work correctly.

  3. Baseline calibration -- The SGP30 has an internal algorithm that continuously adjusts its baseline to account for sensor drift. For best accuracy, the sensor needs about 12 hours of continuous operation to establish a reliable baseline. After that, you can save the baseline values and restore them on the next power-up to skip the calibration period:

// Reading baseline values (do this after 12+ hours of operation)
uint16_t eCO2_base, TVOC_base;
sgp.getIAQBaseline(&eCO2_base, &TVOC_base);
Serial.print("Baseline eCO2: 0x");
Serial.print(eCO2_base, HEX);
Serial.print("  TVOC: 0x");
Serial.println(TVOC_base, HEX);

// Restoring baseline on next startup (call in setup after sgp.begin())
// sgp.setIAQBaseline(eCO2_base, TVOC_base);
  1. eCO2 estimation -- The sensor does not directly measure CO2 molecules. Instead, it measures VOCs and uses a correlation model to estimate what the CO2 level would be in a typical indoor environment. This works reasonably well in occupied rooms where humans are the primary source of both CO2 and VOCs, but it can be misleading in environments with other VOC sources (cleaning products, paint, cooking) where CO2 is not proportionally elevated.

Tip: For the most accurate eCO2 readings, Sensirion recommends also providing the SGP30 with ambient humidity data using sgp.setHumidity(). If you have a humidity sensor like the BME280 or SHT31, you can feed that data in to improve the compensation algorithm.

🔗Troubleshooting

ProblemPossible CauseSolution
Failed to initialize errorWiring issue or wrong I2C pinsVerify SDA/SCL connections; run an I2C scanner sketch
eCO2 stuck at 400 ppmSensor still calibratingLet it run continuously for at least 12 hours
TVOC always reads 0Sensor still warming up or air is very cleanWait a few minutes; breathe near the sensor to test
Readings seem too highNo baseline calibration, or sensor near VOC sourceMove away from solvents, cleaners, or fresh paint; let baseline stabilize
Readings spike then dropNormal behavior during calibrationThe internal algorithm is adjusting; this settles over hours
Sensor not found on I2C scanWrong address or defective moduleSGP30 uses address 0x58; check for solder bridges or bad connections

🔗Next Steps

  • Store baseline values in EEPROM or SPIFFS so they persist across reboots.
  • Pair with a BME280 or SHT31 humidity sensor and feed humidity data into the SGP30 for more accurate readings.
  • Build an indoor air quality monitor with an OLED display showing eCO2 and TVOC levels.
  • Combine with the MQ-2 gas sensor for a more complete air monitoring station that detects both VOCs and combustible gases.
  • Send readings over WiFi to a dashboard using MQTT for long-term air quality tracking.