Monitor CCS811 CO2 & TVOC on ESP8266/ESP32 Web server

In this project, we will connect the ESP8266 or ESP32 to the CCS811 CO2 TVOC Sensor and monitor the CO2/TVOC Data on a web server. The CCS811 is a digital gas or air quality sensor that can detect a variety of levels of metal oxides (MOX), equivalent carbon dioxide (eCO2), and total volatile organic compounds (TVOC). The sensor’s ability to calculate the Air Quality Index is useful.

Earlier, we displayed the CO2 and TVOC values on an OLED display using an Arduino and a CCS811 sensor. But rather than using an OLED display, we’ll build our own webserver and use any web browser on a PC or smartphone to remotely check the air quality. A web server is a computer system that manages a website or webpage and uses the Hypertext Transfer Protocol for intercommunication (HTTP). It is a program that disseminates web pages in response to requests. The storage, processing, and delivery of online pages to users is the main goal of the web server.

When a certain IP Address of ESP8266 or ESP32 requests it, the web server program for CCS811 is stored in ESP8266 or ESP32 and sent wirelessly.

Hardware Required

1ESP8266NodeMCU ESP8266 12E Boardaf
2ESP32WROOM-32 ESP32 ESP-32S Development Board
3CO2 TVOC SensorCCS811 Gas Sensor
4Connecting WiresJumper Wires

CCS811 Air Quality Gas Sensor Module

The CCS811 Air Quality Sensor Breakout Board is a digital gas sensor that measures a variety of levels of metal oxide (MOX), equivalent carbon dioxide (eCO2), and total volatile organic compounds (TVOCs). The sensor can be used to track the quality of the indoor air. A microcontroller unit (MCU) that has an Analog-to-Digital converter (ADC) and an I2C interface can be utilized with the system.


The sensor can be used with an Arduino/ESP8266/ESP32 3.3V pin because it runs between 1.8V and 3.6V. While some boards have an address of 0X5B, the CCS811’s default I2C address is 0x5A. We can measure TVOC from 0 to 1187ppb and eCO2 from 400 to 8192ppm using the CCS811 sensor. To learn more about this sensor, you can follow the CCS811 Datasheet.

Interfacing CCS811 Air Quality Gas Sensor with ESP8266/ESP32

Working with the I2C communication standard is the CCS811 Sensor. So let’s connect the ESP8266 and ESP32 to the CCS811 sensor. The SCL and SDA pins on the NodeMCU ESP8266 Board are D1 and D2, respectively. Therefore, the below diagram shows how CCS811 and ESP8266 are connected.

CCS811 ESP8266

The connection diagram is shown below if you’re using an ESP32 WiFi Module. The ESP32’s SCL and SDA pins are GPIO22 and GPIO21, respectively.

CCS811 ESP32

Since the sensor can only withstand 3.6V at most, do not power it with 5V. Leaving the WAKE pin unconnected will prevent the controller from reading the I2C Address. Always pull the WAKE pin to ground (GND).

ESP8266 CCS811 Code/Program

I interfaced with the CCS811 with the ESP8266 using Maarten Pennings’ CCS811 library. The following link will allow you to download the library.

Download: CCS811 Library

Below is a link to the ESP8266 CCS811 Webserver’s complete source code. Change your WiFi SSID and password before submitting the code.

#include <WebServer.h>
#include <Wire.h> // I2C library
#include “ccs811.h” // CCS811 library

// Wiring for ESP8266 NodeMCU boards: VDD to 3V3, GND to GND, SDA to D2, SCL to D1, nWAKE to D3 (or GND)
CCS811 ccs811(23); // nWAKE on D3

float val1, val2;

const char* ssid = “Alexahome”; // Enter SSID here
const char* password = “loranthus”; //Enter Password here

WebServer server(80);

void setup()
// Enable serial
Serial.println(“setup: Starting CCS811 basic demo”);
Serial.print(“setup: ccs811 lib version: “);

// Enable I2C

// Enable CCS811
ccs811.set_i2cdelay(50); // Needed for ESP8266 because it doesn’t handle I2C clock stretch correctly
bool ok = ccs811.begin();
if ( !ok ) Serial.println(“setup: CCS811 begin FAILED”);

// Print CCS811 versions
Serial.print(“setup: hardware version: “); Serial.println(ccs811.hardware_version(), HEX);
Serial.print(“setup: bootloader version: “); Serial.println(ccs811.bootloader_version(), HEX);
Serial.print(“setup: application version: “); Serial.println(ccs811.application_version(), HEX);

// Start measuring
ok = ccs811.start(CCS811_MODE_1SEC);
if ( !ok ) Serial.println(“setup: CCS811 start FAILED”);

Serial.println(“Connecting to “);

//connect to your local wi-fi network
WiFi.begin(ssid, password);

//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
Serial.println(“WiFi connected..!”);
Serial.print(“Got IP: “);

server.on(“/”, handle_OnConnect);

Serial.println(“HTTP server started”);

void loop()

// Read
uint16_t eco2, etvoc, errstat, raw;, &etvoc, &errstat, &raw);

// Print measurement results based on status
if ( errstat == CCS811_ERRSTAT_OK )
val1 = eco2;
val2 = etvoc;

Serial.print(“CCS811: “);
Serial.print(” ppm “);

Serial.print(” ppb “);
else if ( errstat == CCS811_ERRSTAT_OK_NODATA )
Serial.println(“CCS811: waiting for (new) data”);
} else if ( errstat & CCS811_ERRSTAT_I2CFAIL )
Serial.println(“CCS811: I2C error”);
Serial.print(“CCS811: errstat=”);
Serial.print(errstat, HEX);
Serial.println( ccs811.errstat_str(errstat) );

// Wait

void handle_OnConnect()

server.send(200, “text/html”, SendHTML(val1, val2));

void handle_NotFound()
server.send(404, “text/plain”, “Not found”);

String SendHTML(float val1, float val2)
String ptr = “<!DOCTYPE html> <html>\n”;
ptr += “<head><meta name=\”viewport\” content=\”width=device-width, initial-scale=1.0, user-scalable=no\”>\n”;
ptr += “<title>Measured Air Quality</title>\n”;
ptr += “<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n”;
ptr += “body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n”;
ptr += “p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n”;
ptr += “</style>\n”;
ptr += “<script>\n”;
ptr += “setInterval(loadDoc,1000);\n”;
ptr += “function loadDoc() {\n”;
ptr += “var xhttp = new XMLHttpRequest();\n”;
ptr += “xhttp.onreadystatechange = function() {\n”;
ptr += “if (this.readyState == 4 && this.status == 200) {\n”;
ptr += “document.body.innerHTML =this.responseText}\n”;
ptr += “};\n”;
ptr += “\”GET\”, \”/\”, true);\n”;
ptr += “xhttp.send();\n”;
ptr += “}\n”;
ptr += “</script>\n”;
ptr += “</head>\n”;
ptr += “<body>\n”;
ptr += “<div id=\”webpage\”>\n”;
ptr += “<h1>Measured Air Quality</h1>\n”;

ptr += “<p>CO2: “;
ptr += val1;
ptr += ” ppm</p>”;

ptr += “<p>TVOC: “;
ptr += val2;
ptr += ” ppb</p>”;

ptr += “</div>\n”;
ptr += “</body>\n”;
ptr += “</html>\n”;
return ptr;

Testing CCS811 ESP8266/ESP32 Webserver

The ESP8266/ESP32 Board will attempt to connect to the WiFi network when you upload the code. You may access the Serial Monitor and view the sensor providing the reading there.

Your ESP8266/ESP32 Board’s reset button is now available for use. Serial Monitor will display the IP Address. Paste it into the web browser while using the same IP address, then press enter. A lovely website will include information about CO2 and TVOC values.

To retrieve the sensor value, you don’t need to repeatedly refresh the website. The AJAX (Asynchronous Javascript and Xml) script is already included in the code, allowing us to asynchronously (in the background) request data from the server without refreshing the browser.

Hope this blog helps you to understand how to design and Monitor CCS811 CO2 & TVOC on ESP8266/ESP32 Webserver. We, MATHA ELECTRONICS  will come back with more informative blogs.

Leave a Reply

Your email address will not be published.