ESP8266 - SCD40 CO2 Sensor

This tutorial instructs you how to use ESP8266 to measure the CO2 level of a room with the Sensirion SCD40 sensor. In detail, we will learn:

We suggest:

ESP8266 NodeMCU SCD40 CO2 sensor

Hardware Preparation

1×ESP8266 NodeMCU ESP-12F
1×Alternatively, ESP8266 D1 Mini NodeMCU ESP-12F
1×Alternatively, ESP8266 NodeMCU ESP-12E (Uno-form)
1×Micro USB Cable
1×Alternatively, ESP8266 NodeMCU ESP-12F (SMD-form)
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×SCD40 CO2 Sensor Module
1×Breadboard
1×Jumper Wires
1×Recommended: Screw Terminal Expansion Board for ESP8266

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Overview of SCD40 CO2 Sensor

Many cheap "air quality" sensors only guess the CO2 level (they give an "eCO2" value). The SCD40 from Sensirion really measures CO2. It uses photoacoustic NDIR sensing: a tiny infrared light pulses inside the sensor chamber, CO2 molecules absorb some of that light and create a very small pressure "sound", and a built-in microphone measures it. More CO2 means a stronger signal. The module also has a temperature and humidity sensor inside, which it uses to correct the CO2 value.

SCD40
Supply voltage 2.4V to 5.5V
Interface I2C, address 0x62
CO2 output range 0 to 40,000 ppm
CO2 accuracy ±(50 ppm + 5% of reading), from 400 to 2,000 ppm
Reading rate one new value every 5 seconds (low-power mode every 30 seconds)
Temperature accuracy ±0.8°C (15°C to 35°C)
Humidity accuracy ±6 %RH (15°C to 35°C, 20 to 65 %RH)
Average current about 15 mA at 3.3V

The SCD40 CO2 Sensor Pinout

SCD40 CO2 sensor pinout

The SCD40 module has four pins:

  • VCC pin: must be connected to 3.3V of the ESP8266 (the module accepts 2.4V to 5.5V)
  • GND pin: must be connected to GND (0V)
  • SCL pin: the I2C clock line, must be connected to the SCL pin of the ESP8266
  • SDA pin: the I2C data line, must be connected to the SDA pin of the ESP8266

Most SCD40 breakout modules already have pull-up resistors on SCL and SDA, so no extra resistor is needed.

※ NOTE THAT:

The order of the pins is not the same on every module. Some boards print VIN instead of VCC. Always look at the labels on your own module before wiring.

What Does the CO2 Value Mean?

CO2 is measured in ppm (parts per million). Fresh outdoor air is around 400 ppm. In a closed room, every person breathes out CO2, so the number climbs.

CO2 level Air quality What to do
around 400 ppm Outdoor air nothing
400 - 1000 ppm Good indoor air nothing
1000 - 2000 ppm Stuffy open a window
above 2000 ppm Poor ventilate now, headache and drowsiness are possible

Calibration and Warm-up

Automatic self-calibration (ASC) is ON by default. It assumes the sensor sees fresh, outdoor-level air (about 400 ppm) at least once a week, ideally for an hour or more. So place the sensor where fresh air reaches it from time to time, for example near a window you open every day. Also, the first few readings after power-up can be less accurate. This is normal.

Wiring Diagram

The ESP8266 is a 3.3V board, so power the SCD40 from the 3V3 pin. Connect the I2C lines to the default I2C pins of the NodeMCU: D2 (GPIO4) is SDA and D1 (GPIO5) is SCL.

The wiring diagram between ESP8266 NodeMCU and SCD40 CO2 sensor

This image is created using Fritzing. Click to enlarge image

See more in ESP8266's pinout and how to supply power to the ESP8266 and other components.

SCD40 Module ESP8266 NodeMCU
VCC 3.3V
GND GND
SDA D2 (GPIO4)
SCL D1 (GPIO5)

How To Program For SCD40 CO2 Sensor

  • The first step is to include the libraries:
#include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h>
  • Create the sensor object:
SensirionI2cScd4x scd4x;
  • Start the I2C bus on the default ESP8266 pins and tell the library where the sensor is:
Wire.begin(); // SDA = D2, SCL = D1 scd4x.begin(Wire, SCD40_I2C_ADDR_62);
  • Make a clean start, then begin periodic measurement (one reading every 5 seconds):
scd4x.wakeUp(); scd4x.stopPeriodicMeasurement(); scd4x.reinit(); scd4x.startPeriodicMeasurement();
  • In loop(), check if a new reading is ready, then read it:
bool dataReady = false; scd4x.getDataReadyStatus(dataReady); if (dataReady) { uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; scd4x.readMeasurement(co2, temperature, humidity); }

Every function returns an error code. If it is not 0, errorToString() turns it into a readable message, as you will see in the full code.

ESP8266 Code for SCD40 - Read CO2

This code prints only the CO2 value and a short word about the air quality: Good, Moderate or Poor.

/* * This ESP8266 NodeMCU code was developed by newbiely.com * * This ESP8266 NodeMCU code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp8266/esp8266-scd40-co2-sensor */ /* * ESP8266 NodeMCU - read CO2 (ppm) from the Sensirion SCD40 sensor * * Wiring (default I2C pins of the NodeMCU): * SCD40 VCC -> 3.3V * SCD40 GND -> GND * SCD40 SDA -> D2 (GPIO4) * SCD40 SCL -> D1 (GPIO5) * * Library: "Sensirion I2C SCD4x" by Sensirion (+ dependency "Sensirion Core") */ #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> SensirionI2cScd4x scd4x; char errorMessage[64]; int16_t error; void setup() { Serial.begin(9600); delay(100); Wire.begin(); // ESP8266 default I2C: SDA = D2, SCL = D1 scd4x.begin(Wire, SCD40_I2C_ADDR_62); // Clean start: wake up the sensor, stop any old measurement, reload settings scd4x.wakeUp(); // may return an error if the sensor is already awake - ignore it scd4x.stopPeriodicMeasurement(); scd4x.reinit(); // Start periodic mode: one new reading every 5 seconds error = scd4x.startPeriodicMeasurement(); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start measurement: "); Serial.println(errorMessage); return; } Serial.println("SCD40 started. The first reading arrives in about 5 seconds..."); } void loop() { delay(1000); // check about once per second // Is a new reading ready? bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Data-ready check failed: "); Serial.println(errorMessage); return; } if (!dataReady) { return; // not yet, try again in the next loop } // Read the measurement (CO2, temperature and humidity come together) uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; error = scd4x.readMeasurement(co2, temperature, humidity); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read failed: "); Serial.println(errorMessage); return; } // Only CO2 is printed in this example Serial.print("CO2: "); Serial.print(co2); Serial.print(" ppm -> "); Serial.println(airQuality(co2)); } // Turn a CO2 value into a simple word const char* airQuality(uint16_t ppm) { if (ppm < 1000) return "Good"; if (ppm < 2000) return "Moderate - open a window"; return "Poor - ventilate now"; }

Detailed Instructions

To get started with ESP8266 on Arduino IDE, follow these steps:

  • Check out the how to setup environment for ESP8266 on Arduino IDE tutorial if this is your first time using ESP8266.
  • Wire the components as shown in the diagram.
  • Connect the ESP8266 board to your computer using a USB cable.
  • Open Arduino IDE on your computer.
  • Choose the correct ESP8266 board, such as (e.g. NodeMCU 1.0 (ESP-12E Module)), and its respective COM port.
  • Click to the Libraries icon on the left bar of the Arduino IDE.
  • Search for "SCD4x", and then locate the Sensirion I2C SCD4x library by Sensirion.
  • Press the Install button. When you are asked to install the dependency Sensirion Core, click Install All.
  • Search for Sensirion I2C SCD4x created by Sensirion and click the Install button.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Nodemcu 1.0 (ESP-12E Module)
Library Manager
Type:
All
Topic:
All
Sensirion I2C SCD4x by Sensirion
Enables you to use the SCD4X sensor family via I2C. More info
1.1.0
INSTALL
Newbiely.ino
···
1 void setup() {
Output
Serial Monitor
Ln 1, Col 1
Nodemcu 1.0 (ESP-12E Module) on COM15
1
  • Copy the code above and open it with the Arduino IDE.
  • Click the Upload button in the Arduino IDE to compile and upload the code to the ESP8266.
  • Open the Serial Monitor and wait about 5 seconds for the first value.
  • Breathe gently toward the sensor, or close the door of a small room, and watch the CO2 value rise.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Nodemcu 1.0 (ESP-12E Module)
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Nodemcu 1.0 (ESP-12E Module)' on 'COM15')
New Line
9600 baud
SCD40 started. The first reading arrives in about 5 seconds... CO2: 538 ppm -> Good CO2: 541 ppm -> Good CO2: 547 ppm -> Good CO2: 812 ppm -> Good CO2: 1164 ppm -> Moderate - open a window CO2: 1097 ppm -> Moderate - open a window CO2: 873 ppm -> Good CO2: 702 ppm -> Good
Ln 11, Col 1
Nodemcu 1.0 (ESP-12E Module) on COM15
2

※ NOTE THAT:

If you see an error message instead of numbers, check that SDA goes to D2 and SCL goes to D1. Swapping these two wires is the most common mistake.

Reading Temperature and Humidity from the SCD40

The SCD40 gives three values in every reading: CO2, temperature and humidity. In the code above, readMeasurement() already fills the temperature and humidity variables, we just did not print them. The code below prints all three values. Note that the sensor sits on a warm board, so its temperature can be a little higher than the real room temperature.

/* * This ESP8266 NodeMCU code was developed by newbiely.com * * This ESP8266 NodeMCU code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp8266/esp8266-scd40-co2-sensor */ /* * ESP8266 NodeMCU - read CO2, temperature and humidity from the SCD40 * * Wiring (default I2C pins of the NodeMCU): * SCD40 VCC -> 3.3V * SCD40 GND -> GND * SCD40 SDA -> D2 (GPIO4) * SCD40 SCL -> D1 (GPIO5) * * Library: "Sensirion I2C SCD4x" by Sensirion (+ dependency "Sensirion Core") */ #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> SensirionI2cScd4x scd4x; char errorMessage[64]; int16_t error; void setup() { Serial.begin(9600); delay(100); Wire.begin(); // SDA = D2, SCL = D1 scd4x.begin(Wire, SCD40_I2C_ADDR_62); scd4x.wakeUp(); // an error here is normal if the sensor is already awake scd4x.stopPeriodicMeasurement(); scd4x.reinit(); error = scd4x.startPeriodicMeasurement(); // new data every 5 seconds if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start measurement: "); Serial.println(errorMessage); } } void loop() { delay(1000); bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error || !dataReady) { return; // no new data yet } uint16_t co2 = 0; float temperature = 0.0f; // in degrees Celsius float humidity = 0.0f; // in %RH error = scd4x.readMeasurement(co2, temperature, humidity); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read failed: "); Serial.println(errorMessage); return; } // Print all three values on one line Serial.print("CO2: "); Serial.print(co2); Serial.print(" ppm | Temperature: "); Serial.print(temperature, 1); Serial.print("\xC2\xB0"); // degree symbol Serial.print("C | Humidity: "); Serial.print(humidity, 1); Serial.println(" %"); }

Upload it in the same way and open the Serial Monitor:

∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Nodemcu 1.0 (ESP-12E Module)
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Nodemcu 1.0 (ESP-12E Module)' on 'COM15')
New Line
9600 baud
CO2: 623 ppm | Temperature: 26.4°C | Humidity: 47.2 % CO2: 629 ppm | Temperature: 26.4°C | Humidity: 47.0 % CO2: 634 ppm | Temperature: 26.5°C | Humidity: 46.9 % CO2: 641 ppm | Temperature: 26.5°C | Humidity: 46.8 %
Ln 11, Col 1
Nodemcu 1.0 (ESP-12E Module) on COM15
2

Video Tutorial

Additional Knowledge

Let's compare the SCD40 with the MQ2 gas sensor used in the ESP8266 - Gas Sensor tutorial.

SCD40 MQ2
What it measures real CO2 in ppm a mix of gases (LPG, smoke, methane...)
Output digital I2C value analog voltage + digital threshold
Unit ppm no unit (raw value)
Extra data temperature and humidity none
Warm-up a few readings several minutes (24 - 48 hours when new)
Best for room ventilation, classrooms, offices gas leak and smoke alarms

It is evident that the SCD40 is the right choice when you need a true CO2 number to know when to open a window, while the MQ2 is better for detecting dangerous gas or smoke.

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!