SGP30 air quality sensor

The Sensirion SGP30 air quality sensor on I2C at 0x58: CO2 equivalent in ppm and TVOC in ppb. Aliases: Adafruit SGP30, eCO2 sensor.

It is the sensor in most home-built air quality monitors. A metal-oxide hot plate reacts to the gases people and paint give off, and the chip turns that into two numbers. The CO2 figure is an estimate from those gases, not a measurement of CO2 itself, which is why the datasheet calls it CO2eq.

Pins

Pin What it does
VIN Supply, 3.3 V or 5 V. The board regulates it down to the chip's 1.8 V.
GND Ground.
SCL I2C clock. The board carries the pull-ups.
SDA I2C data.

Properties

eco2 (ppm, 400 to 60000) and tvoc (ppb, 0 to 60000) are the air. The two sliders on the part change them while the circuit runs; they cover indoor air, 400 to 5000 ppm and 0 to 3000 ppb, and the properties take the sensor's whole range.

How it talks

Sixteen-bit commands, high byte first, and replies of two-byte words, each followed by the same CRC-8 as the SHT31 (polynomial 0x31, starting at 0xFF). While a command runs the sensor does not answer its address at all.

Command Code Time Reply
Init_air_quality 0x2003 10 ms none
Measure_air_quality 0x2008 12 ms CO2eq, TVOC
Get_baseline 0x2015 10 ms CO2eq and TVOC baselines
Set_baseline 0x201E 10 ms none; TVOC first, then CO2eq
Set_humidity 0x2061 10 ms none; absolute humidity in 8.8 g/m³
Measure_test 0x2032 220 ms 0xD400
Get_feature_set_version 0x202F 10 ms 0x0020
Measure_raw_signals 0x2050 25 ms H2 and ethanol raw signals
Get_serial_id 0x3682 0.5 ms three words

The warm-up. For 15 s after Init_air_quality every measurement reads 400 ppm and 0 ppb, the datasheet's fixed start values. The datasheet then asks for a measurement every second, which is what feeds the sensor's baseline algorithm.

The library

Adafruit_SGP30.h works as its tutorial uses it:

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

Adafruit_SGP30 sgp;

void setup() {
  Serial.begin(115200);
  if (!sgp.begin()) {
    Serial.println("Sensor not found :(");
    while (1);
  }
}

void loop() {
  if (!sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
    return;
  }
  Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
  Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");
  delay(1000);
}

IAQmeasureRaw(), getIAQBaseline(), setIAQBaseline(), setHumidity() and serialnumber[] are there too. setHumidity() takes mg/m³. Upstream's example works that out from a temperature and relative humidity with exp(), which does not link on the boards here; the Air quality monitor template does it with a table and integers.

What the model gets right

The command set and each command's execution time, the silence while a command runs, the 15 s warm-up at 400 ppm and 0 ppb, the CRC on every word in both directions (a parameter with a bad CRC is refused), the baseline's reversed write order, and the feature set and self-test replies, all from the SGP30 datasheet (version 1.0).

What it does not model

The baseline algorithm itself: a baseline you set reads back, and a new sensor's baseline is an assumed pair. The humidity compensation is taken and stored but does not change the readings. The raw signals follow the TVOC slider by the datasheet's logarithmic relation, from reference values assumed for clean air. The general call reset, drift and the sensor's slow response are not modeled.

Common mistakes

Believing the first readings. For 15 s they are 400 ppm and 0 ppb whatever the air is doing.

Measuring less often than once a second. The sensor still answers, but on the bench its baseline algorithm needs the regular rhythm.

See it in action

Air quality monitor reads an SGP30 and an SHT31 on the same two wires and shows them on a 16x2 LCD. Open it at /templates.