← Back to list

Use a CCS811 VOC/CO₂ sensor with a Heltec WiFi LoRa 32 V2 device (ESP32)

The tiny CCS811 sensor is the cheapest way to measure the indoor CO₂ concentration in the room’s air. In this tutorial I’m showing an easy…

AndroidCrypto · 2026-01-20 08:40 · 4 claps · 6.5 min read
#heltec #esp32 #ccs811 #lora #i2c
Open on Medium ↗
Wiki topics: FT · Fine-tuning & Adaptation 🔧 · Data Engineering

Use a CCS811 VOC/CO₂ sensor with a Heltec WiFi LoRa 32 V2 device (ESP32)

The tiny CCS811 sensor is the cheapest way to measure the indoor CO₂ concentration in the room’s air. In this tutorial I’m showing an easy way to connect the sensor with the board and display the measurements on the OLED display.

The connection to a microcontroller is done by a 2-wire I2C interface, so it might be the right sensor for a long-range (“LoRa”) development board like the Heltec WiFi LoRa 32 V2 board for measuring the air quality and sending the data to a remote station.

The Heltec board is based on a “classic” ESP32 processor that is connected to an SX1276 LoRa module and a 128 x 64 pixel OLED display, driven by an SSD1306 chip. To be honest, this device was outphased by its manufacturer, Heltec Automation, but it is still sold on many platforms (like AliExpress) and is one of the cheapest available LoRa boards.

These are the topics of this tutorial:

  • Profile of the CCS811 sensor
  • Profile of the Heltec WiFi LoRa 32 V2 board
  • Development environment
  • Wiring of the sensor
  • Example sketch
  • Summary

Profile of the CCS811 sensor

On the website of Adafruit, you can find this profile of the sensor:

This sensor from AMS is a gas sensor that can detect a wide range of Volatile Organic Compounds (VOCs) and is intended for indoor air quality monitoring. When connected to your microcontroller (running our library code), it will return a Total Volatile Organic Compound (TVOC) reading and an equivalent carbon dioxide reading (eCO2) over I2C.

This means that it is not a real CO₂ sensor but calculates the CO₂ concentration on the “TVOC” reading. It is connected by two signal lines (“SDA” and “SCL”) of the I2C bus of the ESP32 microcontroller. The third wire is the Ground to Ground connection, and finally, the “VCC” terminal connects to the 3.3 volts rail.

As with all other I2C-interfaced devices, the sensor has an I2C address, and the default value is 0x5A; the alternative address is 0x5B. My sensor module has 3 additional terminals, “WAK,” “INT,” and “RST”.

Although it is noticed nowhere, to run the sensor, it is important to bring the “WAK” connection to “LOW” signal level.

There are 2 ways to achieve this:

  • Variant 1 (permanent): connect the “WAK” terminal to “GND”, this forces the sensor to stay alive
  • Variant 2 (controlled): connect the “WAK” terminal with a GPIO pin of the microcontroller and the output level to LOW when measuring and HIGH when the sensor and the device are in a sleep mode—this is more power efficient.

In my example sketch, I’m using the first variant.

The sensor will measure eCO2 (equivalent calculated carbon dioxide) concentration within a range of 400 to 8192 parts per million (ppm) and TVOC (Total Volatile Organic Compound) concentration within a range of 0 to 1187 parts per billion (ppb). According to the fact sheet, it can detect alcohols, aldehydes, ketones, organic acids, amines, aliphatics, and aromatic hydrocarbons.

Please note, this sensor, like all VOC/gas sensors, has variability, and to get precise measurements, you will want to calibrate it against known sources! That said, for general environmental sensors, it will give you a good idea of trends and comparisons.

Burn-in phase

To get the best results from your CCS811 sensor, I’m recommending running a 48-hour-long burn-in phase.

Sensor warm-up phase

When you are starting to use the sensor, you will notice a warm-up phase with a static measurement of “400”. This phase can last up to one minute, and after that phase, it gives an updated value each second.

Profile of the Heltec WiFi LoRa 32 V2 board

I’m writing a tutorial using this (outphased) LoRa board because it may still be available in several stores, and it is the cheapest LoRa board with an ESP32 processor. It is the classic ESP32 microcontroller with 4 MB of flash memory and no PSRAM. Depending on your region, an SX127x LoRa module is mounted on the board, together with a 128 × 64 pixel OLED display that is driven by an SSD1306 chip.

A bright white LED is accessible by a GPIO, and the board comes with a Li-Ion battery interface with power control.

The LoRa module is using the SPI interface, and the OLED is connected by an I2C interface.

Although Heltec removed any information about this board from its store website, some useful (official) information is available on the support/resource pages (e.g., schematic and pin mappings).

Development environment

As a general note, I’m using the regular [Android ESP32 boards](https://github.com/espressif/arduino-esp32) for developing my LoRa applications. I already know that Heltec is providing its framework, but as I own different LoRa devices, I would rather not write different codes for my devices. The sample code is written on Arduino 2.3.6 (Windows) and ESP32 boards version 3.3.5, which is based on Espressif’s IDE 5.5.1.

To control the sensor, I’m using the **Adafruit CCS811 library** in version 1.1.3..

For the OLED display, the most used library on Heltec devices is the **esp8266-oled-ssd1306** library by ThingPulse in version 4.6.2.

Wiring of the sensor

As mentioned before, you need to wire 4 terminals to the ESP32 board (here for a Heltec WiFi LoRa 32 V2 board) and one wiring on the module:

CCS811 to Heltec WiFi LoRa 32 V2 board
CCS811 - Heltec
VCC    - 3.3 volts
GND    - GND
SDA    - 33
SCL    - 32

Don't forget to wire this terminal to GND to enable the sensor:
WAK    - GND

Example sketch

The example sketch is using just the OLED of the Heltec board to display the measurements. The LoRa module is not used by this sketch!

The complete code is published in my GitHub repository; here are the important parts:

#include <Wire.h>

// The Vext controls external power but also internal power to the display
#define VEXT_POWER_CONTROL_PIN 21 // pin controls power to external devices

// OLED display
#define OLED_I2C_ADDRESS 0x3C
#define OLED_I2C_SDA_PIN 4
#define OLED_I2C_SCL_PIN 15
#define OLED_I2C_RST_PIN 16 // set this to -1 if the OLED display has no RST terminal connected

#include "SSD1306.h"  // https://github.com/ThingPulse/esp8266-oled-ssd1306

SSD1306Wire display(OLED_I2C_ADDRESS, OLED_I2C_SDA_PIN, OLED_I2C_SCL_PIN);

As we are using the “Wire” system library, we need to load it. It may be loaded by one of the other libraries as well, but we don’t know. Next we are defining some GPIO pin assignments for the board and including the OLED library. The last step is to initialize the display object with the pin settings.

// CCS811 sensor
#define CCS811_SDA 33
#define CCS811_SCL 32
//#define CCS811_I2C_ADDRESS 0x5B
#define CCS811_I2C_ADDRESS 0x5A

#include "Adafruit_CCS811.h" // https://github.com/adafruit/Adafruit_CCS811/ version 1.1.3
Adafruit_CCS811 ccs;

The same happens with the CCS811 sensor: we define the GPIO pins for the secondary I2C interface and the I2C address of the sensor, include the sensor library, and instantiate the sensor object.

void setVextControl(boolean trueIsOn) {
  if (trueIsOn) {
    pinMode(VEXT_POWER_CONTROL_PIN, OUTPUT);
    digitalWrite(VEXT_POWER_CONTROL_PIN, LOW);
  } else {
    // pulled up, no need to drive it
    pinMode(VEXT_POWER_CONTROL_PIN, INPUT);
  }
}

This is an important method because the internal power supply for the display goes through the Vext circuit. If you miss setting the “VEXT_POWER_CONTROL_PIN” to “LOW”, your display won’t show up.

The next steps are taking place in the setup() part of the sketch:

// power for the display
  setVextControl(true);

This is activating the power supply for the OLED display.

// reset the display
if (OLED_I2C_RST_PIN >= 0) {
  pinMode(OLED_I2C_RST_PIN, OUTPUT);
  digitalWrite(OLED_I2C_RST_PIN, LOW);  // set GPIO16 low to reset OLED
  delay(50);
  digitalWrite(OLED_I2C_RST_PIN, HIGH);
  delay(50);
}

The OLED display needs a RESET sequence (“LOW” -> “HIGH”) on the “OLED_I2C_RST_PIN” to start working.

// init the display
display.init();

The display variable is initialized.

The next steps are important to change the default (primary) I2C address:

Wire1.begin(CCS811_SDA, CCS811_SCL);

We start the new Wire1 object with the I2C pin settings for the second bus.

if (!ccs.begin(CCS811_I2C_ADDRESS, &Wire1)) {
  //if (!ccs.begin()) {
    Serial.println("Could not find a valid CCS811 sensor, check wiring!.");
    while (1);
  }
  while (!ccs.available()); 

The CCS811 sensor object gets initialized by the sensor module I2C address and the new Wire1 object. If no sensor was found, the system is halting. The sensor is blocking the system until it is ready to use (around one second).

The setup is done now; let's move to the measuring that is located within the loop() section.

if (ccs.available()) {       
  if (!ccs.readData()) {   
    co2 = ccs.geteCO2();
    tvoc = ccs.getTVOC();
    Serial.printf("CO2: %3.0f TVOC: %3.0f\n", co2, tvoc);
  }
  else {
    Serial.println("ERROR!"); 
    while (1); 
  }
}

The method is waiting until the sensor is available, reading out the “eCO2” and “TVOC” data of the sensor. If an error occurs, the system is halting.

Note regarding the data

You will notice a “constant” value for the “eCO2“ of “400” units (here: “ppm”). This is because the sensor needs some seconds to calibrate itself. After 20 seconds to a minute, you will notice that the values are rising.

Summary

It is not too difficult to connect an I2C interfaced CCS811 sensor to a Heltec WiFi LoRa 32 V2 development board.

Source code of the app

You find the complete code of the app in my GitHub repository.

Happy coding.


메타데이터
post_id
360c4e65a294
slug
use-a-ccs811-voc-co₂-sensor-with-a-heltec-wifi-lora-32-v2-device-esp32-360c4e65a294
url
https://medium.com/@androidcrypto/use-a-ccs811-voc-co%E2%82%82-sensor-with-a-heltec-wifi-lora-32-v2-device-esp32-360c4e65a294
canonical_url
https://medium.com/@androidcrypto/use-a-ccs811-voc-co%E2%82%82-sensor-with-a-heltec-wifi-lora-32-v2-device-esp32-360c4e65a294
author_url
https://medium.com/@androidcrypto
status
ok
fetched_at
2026-07-13 07:06:27