SGP30 with ESP32: TVOC, eCO2 & Baseline Setup
Read the Grove SGP30 at one-second intervals, understand estimated CO2, and plan humidity compensation and baseline handling.
On this page
TVOC and eCO2 are different outputsPrepare Arduino and the driverConnect the Grove I2C moduleMaintain one measurement per secondTreat compensation and baseline as separate stepsValidate trends rather than a room CO2 claimTroubleshootingSoftware versions and validationDownloads and referencesRelated products
Use the Grove SGP30 to read TVOC and CO2-equivalent values with an ESP32. The tutorial separates sensor initialization, regular sampling and baseline management so a startup number is not mistaken for a calibrated CO2 measurement.
TVOC and eCO2 are different outputs
SGP30 is a metal-oxide gas sensor. TVOC is reported in ppb and eCO2/CO2eq in ppm; the latter is inferred from gas-sensor signals, not directly measured CO2. This module is not an NDIR CO2 instrument. For direct CO2 measurement use an appropriate sensor such as the SCD40/SCD41.
Prepare Arduino and the driver
Install esp32 by Espressif Systems in Arduino Boards Manager. The C3 examples use ESP32C3 Dev Module with USB CDC On Boot enabled and Serial Monitor at 115200 baud. Start with a working Arduino upload setup, then disconnect power before changing wires.
Install Adafruit SGP30 and Adafruit BusIO. The example uses the Grove module with its board-level power circuitry, not an unmounted 1.8 V SGP30 chip.
Connect the Grove I2C module
| Grove signal | ESP32-C3 example | Purpose |
|---|---|---|
| VCC | 3V3 | 3.3 V module supply for this example |
| GND | GND | Common reference |
| SDA | GPIO6 | I2C data |
| SCL | GPIO7 | I2C clock |
These are GPIO numbers on the ESP32-C3 Supermini, not physical header numbers. Identify the Grove contacts from the module labels; cable color is only an aid. For another ESP32 board select free pins using its pinout and change the code. Keep I2C pull-ups at 3.3 V.
SGP30 normally uses I2C address 0x58. Keep the module’s air opening exposed and separate it from solvents, soldering fumes or a direct breath stream when recording ordinary room conditions.
Maintain one measurement per second
The driver begins the IAQ algorithm during initialization. Read it at the required one-second cadence, even if a later application publishes results less often. The first initialization period can return fixed 400 ppm eCO2 and 0 ppb TVOC; that alone does not mean a broken sensor.
#include <Wire.h>
#include <Adafruit_SGP30.h>
Adafruit_SGP30 sgp;
uint32_t nextRead;
void setup() {
Serial.begin(115200); delay(1500);
Wire.begin(6, 7); Wire.setClock(100000);
if (!sgp.begin(&Wire)) {
Serial.println("SGP30 initialization failed at 0x58.");
while (true) delay(1000);
}
Serial.println("TVOC ppb, eCO2 ppm (estimated CO2, not direct measurement)");
Serial.println("Initial fixed readings during startup are expected.");
nextRead = millis() + 1000;
}
void loop() {
if ((int32_t)(millis() - nextRead) < 0) { delay(5); return; }
nextRead += 1000;
if (!sgp.IAQmeasure()) { Serial.println("IAQ read failed"); return; }
Serial.printf("TVOC=%u ppb; eCO2=%u ppm\n", sgp.TVOC, sgp.eCO2);
}
Treat compensation and baseline as separate steps
The minimal example does not write a fabricated baseline or humidity value. For long-running use, supply absolute humidity through the library’s setHumidity() API using a real temperature/humidity measurement and the correct units. A relative-humidity percentage is not an absolute-humidity input.
Follow Sensirion’s integration guidance for baseline timing and restoration. Store a baseline only after the required operating period, pair it with the sensor identity and time, and restore it only when still applicable. Do not copy a baseline from another unit or overwrite it every second.
Validate trends rather than a room CO2 claim
Check that I2C communication remains stable and the program continues sampling. Record startup duration, ambient temperature/humidity and any baseline operations when comparing sessions. A response to a nearby VOC source does not establish accurate room CO2. Avoid exposing the module to concentrated chemicals as a demonstration.
Troubleshooting
| Symptom | Check next |
|---|---|
| Not found | Check 0x58, Grove supply, data/clock and common ground. |
| 400 ppm and zero TVOC at startup | Allow algorithm initialization while continuing one-second measurements. |
| Large changes after restart | Check run duration, baseline restoration and humidity compensation. |
| Values differ from a CO2 instrument | eCO2 is an estimate; compare the intended measurement principle. |
| Baseline code gives implausible results | Check sensor identity, baseline age, units and documented API order. |
Software versions and validation
Documentation reviewed on October 21, 2026. The included minimal sketch was compile-checked with Arduino-ESP32 3.3.0; library versions are listed below. Compilation does not replace a test on your physical module.
Adafruit SGP30 2.0.3, Adafruit BusIO 1.17.4
Downloads and references
- Sensirion SGP30 product and integration resources
- Seeed Grove SGP30 module documentation
- Adafruit SGP30 API and examples
- Espressif Arduino-ESP32 documentation
Download the minimal Arduino sketch (.zip)
Related products
Share the product link, hardware revision, software version and any error messages.
Contact ESP32S support →