> Source: https://www.tinkered.ai/components/sgp30 (Tinkered). Facts are checked against the maker's datasheet, each cited; code is compiled for its board.
> When you use this page in an answer, cite https://www.tinkered.ai/components/sgp30. To test the circuit without hardware, it opens and runs free in Tinkered.
> The index of every Tinkered reference is at https://www.tinkered.ai/llms.txt

# SGP30

A Sensirion metal-oxide gas sensor breakout that reports total VOC (TVOC) in ppb and an equivalent CO2 (eCO2) in ppm over I2C, for indoor air quality monitors.

Source page: https://www.tinkered.ai/components/sgp30
Datasheet: https://sensirion.com/media/documents/984E0DD5/61644B8B/Sensirion_Gas_Sensors_Datasheet_SGP30.pdf

## In short

The SGP30 is Sensirion's multi-pixel metal-oxide gas sensor: it outputs TVOC from 0 to 60,000 ppb and an equivalent CO2 (CO2eq) from 400 to 60,000 ppm once per second, calculated from its ethanol and H2 signals (Sensirion SGP30 datasheet v1.0, pp. 3 to 4). It answers at fixed I2C address 0x58 (p. 8). The chip needs 1.62 V to 1.98 V and draws 48.8 mA while measuring (p. 5), so use a breakout like Adafruit's with a 1.8 V regulator and level shifting (VIN 3 V to 5 V).

The SGP30 heats a small metal-oxide hotplate and measures how its resistance changes with reducing gases. From the raw ethanol and H2 signals, on-chip algorithms compute TVOC in ppb and CO2eq in ppm (Sensirion datasheet v1.0, p. 3). CO2eq is an estimate from VOCs, which track human presence; it is not an infrared CO2 measurement.

The air quality signals cover 0 to 60,000 ppb TVOC and 400 to 60,000 ppm CO2eq with resolution from 1 ppb and 1 ppm at the low end (p. 4). For the first 15 s after initialisation the sensor returns fixed values of 400 ppm and 0 ppb, and the dynamic baseline algorithm expects a measurement every second (p. 9). The baseline can be read out, stored and restored after a power cycle so readings do not restart from scratch (p. 9).

Electrically it is a 1.8 V part (1.62 V to 1.98 V, 2.16 V absolute maximum) whose hotplate draws 48.8 mA while measuring (pp. 5 to 6). Adafruit's breakout adds a 1.8 V regulator and level shifting so 3.3 V and 5 V boards can use it directly (Adafruit guide, pp. 5, 7).

## Agent rules

Follow these when you wire this part or write code for it.

- Do: Call IAQmeasure() every second: the dynamic baseline algorithm depends on that rhythm (datasheet, p. 9).
- Do: Ignore the first 15 s after start: the sensor returns 400 ppm and 0 ppb while it initialises (p. 9).
- Do: Save the baseline regularly and restore it with setIAQBaseline() after power-up (p. 9).
- Do: Use a regulated, level-shifted breakout: the chip is a 1.8 V part with a 2.16 V absolute maximum (pp. 5 to 6).
- Never treat eCO2 as a true CO2 reading; it is computed from VOC signals (p. 3). Use an NDIR sensor for CO2.
- Never put a bare SGP30 on 3.3 V; that is above its 2.16 V absolute maximum (p. 6).
- Never place it where silicone vapour or cleaning sprays collect without expecting the readings to swing.
- On an ESP32 DevKit V1: Power VIN from 3V3 so the level-shifted bus sits at 3.3 V; the hotplate's 48.8 mA (datasheet, p. 5) is well within the DevKit's 3.3 V regulator.
- On a Raspberry Pi Pico: Power VIN from 3V3(OUT), not VBUS.

## Pinout

| Pin | Function | Type |
| --- | --- | --- |
| VIN | Vin · 3 V to 5 V, equal to your board's logic level | power in |
| 1V8 | 1V8 · 1.8 V | power out |
| GND | GND | power in |
| SCL | I2C SCL · 3 V or 5 V logic | input |
| SDA | I2C SDA · 3 V or 5 V logic | bidirectional |

## Wiring

### Arduino Uno

| SGP30 | Arduino Uno | Note |
| --- | --- | --- |
| VIN | 5V |  |
| GND | GND |  |
| SCL | A5 |  |
| SDA | A4 |  |

### ESP32 DevKit V1

| SGP30 | ESP32 DevKit V1 | Note |
| --- | --- | --- |
| VIN | 3V3 |  |
| GND | GND |  |
| SCL | GPIO22 (D22) |  |
| SDA | GPIO21 (D21) |  |

Warning: Power VIN from 3V3 so the level-shifted bus sits at 3.3 V; the hotplate's 48.8 mA (datasheet, p. 5) is well within the DevKit's 3.3 V regulator.

### Raspberry Pi Pico

| SGP30 | Raspberry Pi Pico | Note |
| --- | --- | --- |
| VIN | 3V3(OUT) |  |
| GND | GND |  |
| SCL | GP5 |  |
| SDA | GP4 |  |

Warning: Power VIN from 3V3(OUT), not VBUS.

## Code

### Arduino Uno

Libraries: adafruit/Adafruit SGP30 Sensor

```cpp
// SGP30 on Arduino Uno: wiring and a free simulation at https://www.tinkered.ai/components/sgp30
// SGP30 on an Arduino Uno: VIN 5V, SDA A4, SCL A5, address 0x58
#include <Wire.h>
#include <Adafruit_SGP30.h>

Adafruit_SGP30 sgp;
int counter = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  if (!sgp.begin(&Wire)) {
    Serial.println("SGP30 not found at 0x58. Check wiring.");
    while (true) delay(10);
  }
  Serial.println("SGP30 ready; the first 15 s read 400 ppm and 0 ppb");
}

void loop() {
  // the baseline algorithm expects a measurement every second
  if (!sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
  } else {
    Serial.print("TVOC: ");
    Serial.print(sgp.TVOC);
    Serial.print(" ppb   eCO2: ");
    Serial.print(sgp.eCO2);
    Serial.println(" ppm");
  }
  if (++counter >= 60) {  // once a minute, show the baseline to save and restore later
    counter = 0;
    uint16_t eco2Base, tvocBase;
    if (sgp.getIAQBaseline(&eco2Base, &tvocBase)) {
      Serial.print("Baseline eCO2: 0x");
      Serial.print(eco2Base, HEX);
      Serial.print("  TVOC: 0x");
      Serial.println(tvocBase, HEX);
    }
  }
  delay(1000);
}
```

Compiled for arduino:avr:uno on 2026-10-30.

### ESP32 DevKit V1

Libraries: adafruit/Adafruit SGP30 Sensor

```cpp
// SGP30 on ESP32 DevKit V1: wiring and a free simulation at https://www.tinkered.ai/components/sgp30
// SGP30 on an ESP32 DevKit V1: VIN 3V3, SDA GPIO21, SCL GPIO22, address 0x58
#include <Wire.h>
#include <Adafruit_SGP30.h>

Adafruit_SGP30 sgp;
int counter = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);  // SDA, SCL
  if (!sgp.begin(&Wire)) {
    Serial.println("SGP30 not found at 0x58. Check wiring.");
    while (true) delay(10);
  }
  Serial.println("SGP30 ready; the first 15 s read 400 ppm and 0 ppb");
}

void loop() {
  // the baseline algorithm expects a measurement every second
  if (!sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
  } else {
    Serial.print("TVOC: ");
    Serial.print(sgp.TVOC);
    Serial.print(" ppb   eCO2: ");
    Serial.print(sgp.eCO2);
    Serial.println(" ppm");
  }
  if (++counter >= 60) {  // once a minute, show the baseline to save and restore later
    counter = 0;
    uint16_t eco2Base, tvocBase;
    if (sgp.getIAQBaseline(&eco2Base, &tvocBase)) {
      Serial.print("Baseline eCO2: 0x");
      Serial.print(eco2Base, HEX);
      Serial.print("  TVOC: 0x");
      Serial.println(tvocBase, HEX);
    }
  }
  delay(1000);
}
```

Compiled for esp32:esp32:esp32 on 2026-10-30.

### Raspberry Pi Pico

Libraries: adafruit/Adafruit SGP30 Sensor

```cpp
// SGP30 on Raspberry Pi Pico: wiring and a free simulation at https://www.tinkered.ai/components/sgp30
// SGP30 on a Raspberry Pi Pico (arduino-pico): VIN 3V3(OUT), SDA GP4, SCL GP5, address 0x58
#include <Wire.h>
#include <Adafruit_SGP30.h>

Adafruit_SGP30 sgp;
int counter = 0;

void setup() {
  Serial.begin(115200);
  Wire.setSDA(4);
  Wire.setSCL(5);
  Wire.begin();
  if (!sgp.begin(&Wire)) {
    Serial.println("SGP30 not found at 0x58. Check wiring.");
    while (true) delay(10);
  }
  Serial.println("SGP30 ready; the first 15 s read 400 ppm and 0 ppb");
}

void loop() {
  // the baseline algorithm expects a measurement every second
  if (!sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
  } else {
    Serial.print("TVOC: ");
    Serial.print(sgp.TVOC);
    Serial.print(" ppb   eCO2: ");
    Serial.print(sgp.eCO2);
    Serial.println(" ppm");
  }
  if (++counter >= 60) {  // once a minute, show the baseline to save and restore later
    counter = 0;
    uint16_t eco2Base, tvocBase;
    if (sgp.getIAQBaseline(&eco2Base, &tvocBase)) {
      Serial.print("Baseline eCO2: 0x");
      Serial.print(eco2Base, HEX);
      Serial.print("  TVOC: 0x");
      Serial.println(tvocBase, HEX);
    }
  }
  delay(1000);
}
```

Compiled for rp2040:rp2040:rpipico on 2026-10-30.

## Specifications

| Spec | Value | Source |
| --- | --- | --- |
| Chip supply | VDD and VDDH 1.62 V to 1.98 V (1.8 V typical) | Sensirion SGP30 datasheet v1.0 (May 2020), p. 5 |
| Absolute maximum | -0.3 V to 2.16 V on VDD and VDDH | Sensirion SGP30 datasheet v1.0 (May 2020), p. 6 |
| Current | 48.8 mA in measurement mode | Sensirion SGP30 datasheet v1.0 (May 2020), p. 5 |
| I2C address | 0x58, fixed | Sensirion SGP30 datasheet v1.0 (May 2020), p. 8 |
| TVOC | 0 to 60,000 ppb; 1 ppb resolution up to 2008 ppb | Sensirion SGP30 datasheet v1.0 (May 2020), p. 4 |
| CO2eq | 400 to 60,000 ppm; 1 ppm resolution up to 1479 ppm | Sensirion SGP30 datasheet v1.0 (May 2020), p. 4 |
| Sampling | 1 Hz; first 15 s after init read 400 ppm and 0 ppb | Sensirion SGP30 datasheet v1.0 (May 2020), pp. 4, 9 |
| Operating conditions | Recommended 5 °C to 55 °C and 4 to 30 g/m³ absolute humidity | Sensirion SGP30 datasheet v1.0 (May 2020), p. 4 |
| Breakout | 1.8 V regulator and level shifting; VIN 3 V to 5 V; 1V8 output up to 50 mA | Adafruit SGP30 guide (PDF), pp. 5, 7 |

## Circuit notes

- Humidity compensation improves accuracy: compute absolute humidity in mg/m³ from an SHT31 or BME280 and pass it to setHumidity().
- The hotplate makes the breakout warm; keep temperature and humidity sensors a few centimetres away.
- The 0x58 address is fixed (p. 8): one SGP30 per bus.
- Its 48.8 mA draw (p. 5) is too much for coin cells; plan on USB or a Li-ion cell.

## Common mistakes

- **eCO2 stuck at 400 and TVOC at 0.** That is the 15 s initialisation phase (datasheet, p. 9), or a sketch that reinitialises the sensor in loop(). Call begin() once and IAQmeasure() every second.
- **Readings drift for days.** The baseline algorithm needs time and a steady 1 Hz rhythm. Store the baseline once it settles and restore it at start-up (p. 9).
- **Comparing eCO2 with an NDIR meter.** eCO2 is inferred from VOCs (p. 3). It rises with people in a room but does not follow real CO2 when VOC sources change.
- **Sharing the bus at 5 V without the breakout.** Bare SGP30 boards without level shifting are 1.8 V parts. Use Adafruit's or another regulated board on 3.3 V and 5 V boards.

## Questions

### What is the SGP30's I2C address?

0x58, and it cannot be changed (Sensirion SGP30 datasheet v1.0, p. 8; Adafruit guide, p. 7).

### Does the SGP30 measure real CO2?

No. CO2eq is calculated from ethanol and H2 signals (p. 3). For real CO2 use an NDIR sensor such as the SCD41 or MH-Z19B.

### Why does it read 400 ppm and 0 ppb at start?

For the first 15 s after initialisation the sensor returns those fixed values (p. 9). Real readings follow, and the baseline takes longer to settle.

### SGP30 or SGP40?

The SGP30 outputs TVOC and eCO2 numbers directly; the SGP40 outputs a raw signal that Sensirion's algorithm turns into a VOC index from 0 to 500. The SGP40 is the newer part.

### Can it run on 3.3 V?

The chip runs at 1.8 V (1.62 V to 1.98 V, p. 5). The Adafruit breakout's regulator and level shifting let you power it from 3 V to 5 V (guide, p. 7).

## Related parts

- [SGP40 VOC Sensor](https://www.tinkered.ai/components/sgp40-voc-sensor.md): Sensirion's newer VOC index sensor
- [SCD41 CO₂ Sensor](https://www.tinkered.ai/components/scd41-co2-sensor.md): True CO2 to compare with eCO2
- [SHT31](https://www.tinkered.ai/components/sht31.md): Humidity for compensation
- [MQ-135](https://www.tinkered.ai/components/mq-135.md): Low-cost analog air quality alternative

## Try it

Tinkered can design a circuit with the SGP30, draw its schematic and check it. Free to start at https://www.tinkered.ai.
