Reference
SCD4x
True CO2 (photoacoustic NDIR) in ppm plus temperature and humidity: SCD40 / SCD41.
- Connects over
- I²C
- Address
- 0x62
- Made by
- Sensirion
- Datasheet
- sensirion.com
Use it
hardware {
device scd4x: SCD4x
}
every 1s {
let value: int = scd4x.co2()
log("scd4x", "co2={value}")
}
On its own, the declaration puts the SCD4x on the first I²C bus (SDA 21, SCL 22 on the ESP32) at 0x62. To choose the pins or the address, declare the bus and attach the device: device scd4x: SCD4x on i2c0 at 0x62 with i2c i2c0(sda: 21, scl: 22).
Methods
-
scd4x.calibrate(target_ppm: int) -> int
Forced recalibration to a known CO2 level in ppm (e.g. 420 outdoors) after 3 min of stable readings; returns the correction applied in ppm, or -32768 on failure.
-
scd4x.co2() -> int
CO2 concentration in ppm.
-
scd4x.humidity() -> float
Relative humidity %.
-
scd4x.ready() -> bool
True once the first measurement has been read.
-
scd4x.set_auto_calibration(on: bool)
Turn automatic self-calibration on or off (on by default).
-
scd4x.set_pressure(hpa: int)
Ambient pressure in hPa for pressure compensation (e.g. from a BME280); can be called at any time.
-
scd4x.set_temperature_offset(offset: float)
Self-heating offset in °C subtracted from the temperature reading (default 4).
-
scd4x.temperature() -> float
Temperature in °C.
Wiring
| Pin | Connect to |
|---|---|
VDD | 3.3V or 5V; needs a solid supply for the 175 mA peaks |
GND | Ground |
SDA | I2C data, pull-up on most breakouts |
SCL | I2C clock |
Specifications
- Co2
- SCD40: 400 - 2000 ppm ±(50 ppm + 5%); SCD41: 400 - 5000 ppm ±(40 ppm + 5%)
- Current
- ~15 mA average in periodic mode (peaks 175 mA)
- Humidity
- 0 - 100% RH ±6%
- Sample rate
- one measurement every 5 s
- Temp
- -10 to 60 °C ±0.8 °C
- Voltage
- 2.4V - 5.5V
Tips
- A new value arrives every 5 s; reading more often returns the last value. ready() is false until the first one (about 5 s after boot).
- Automatic self-calibration assumes it sees fresh outdoor air (~420 ppm) at least once a week; turn it off with set_auto_calibration(false) in rooms that never get that, and use calibrate(420) outdoors instead.
- calibrate(), set_temperature_offset() and set_auto_calibration() pause measurements for about 1 s and are not kept across power loss.
- Self-heating makes it read 2-4 °C warm in an enclosure; correct it with set_temperature_offset().
Alternatives worth knowing:
- SGP30: Cheaper, but eCO2 is estimated from VOCs, not measured.
- ENS160: VOC-based AQI / eCO2.