The BME680 doesn't have built-in air quality calcualtion capabilities like other sensors like the SGP30 or CCS811. Instead, you only get temperature, pressure, humidity and gas resistance (the raw resistance value of the sensor in the BME60. So we have to use a separate library from Bosch to perform the conversion to get Air Quality values like the VOC and equivalent CO2.

The Bosch BSEC library is an all-in-one Arduino library that will get you all the values from the sensor and also perform the AQI calculations. It is not an open source library! You can only use it in Arduino and only with the chipsets supported.

Not every chipset is supported by the closed-source BSEC library!

We have tested the Adafruit SAMD21 (M0) series of chips and these work great. You can use an Adafruit QT Py, Trinket M0, Feather M0, etc!

According to Bosch, ESP32 and ESP8266 are also supported. AVR is not recommended - you definitely cannot fit the library into an Uno/ATmega328 or ATmega32u4, you could try using an Arduino Mega but it isnt suggested.

Really we recommend a SAMD21 or ESP board!

Install Library

To install Bosch's BSEC library:

  • Open Arduino Library Manager
  • Search for "bsec" to find the library
  • In the results, find the "BSEC Software Library"
  • Click Install
Do NOT use the 1.7.1492 release version of the BSEC library.

The 1.7.1492 release of the library has a known issue that prevents compilation in the Arduino IDE. Same issue reported here in Bosch's support forum.

Load Example & Adjust

Load up the basic example

We recommend adding

while (!Serial) delay(10); // wait for console

right after Serial.begin so that the console will print output after it's opened. That way any initialization error messages can be seen.

Upload to your board and open up the serial console at 115200 baud. You will see comma-separated values after some heading text:

Note that some of these are calculated values. They will take a few minutes to normalize. Make sure to start your sensor in a clean air environment so it can normalize!

You can check the basic_config_state example if you want to calibrate the sensor, store the state in EEPROM, then re-write it on boot so you don't have to go through the normalization process.

QT Py + OLED Demo

Here's a demo that uses a 1.3" OLED + QT Py for a plug-n-play air quality display

Animation of Adafruit QT Py with onboard NeoPixel in a rainbow swirl.
What a cutie pie! Or is it... a QT Py? This diminutive dev board comes with our favorite lil chip, the SAMD21 (as made famous in our GEMMA M0 and Trinket M0 boards).This time it...
$7.50
In Stock
Monochrome 1.3" OLED module with Adafruit logos falling like snow
These displays are small, only about 1.3" diagonal, but very readable due to the high contrast of an OLED display. This display is made of 128x64 individual white OLED pixels,...
$19.95
In Stock
Angled shot of STEMMA QT / Qwiic JST SH 4-pin Cable.
This 4-wire cable is a little over 100mm / 4" long and fitted with JST-SH female 4-pin connectors on both ends. Compared with the chunkier JST-PH these are 1mm pitch instead of...
$0.95
In Stock
// SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
// SPDX-FileCopyrightText: 2020 Kevin Townsend for Adafruit Industries
//
// SPDX-License-Identifier: MIT

/***************************************************************************
  This is a library for the BME68X gas, humidity, temperature & pressure sensor

  Designed specifically to work with the Adafruit BME68X Breakout
  ----> http://www.adafruit.com/products/3660

  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing products
  from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ***************************************************************************/

#include <Adafruit_SSD1306.h>
#include "bsec.h"

Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);

Bsec iaqSensor;
String output;


void setup() {
  Serial.begin(9600);
  //while (!Serial);
  
  Serial.println(F("BME68X test"));
  
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  Serial.println("OLED begun");

  display.display();
  delay(100);
  display.clearDisplay();
  display.display();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setRotation(0);
  
  iaqSensor.begin(BME68X_I2C_ADDR_LOW, Wire);
  output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix);
  Serial.println(output);
  checkIaqSensorStatus();
  bsec_virtual_sensor_t sensorList[10] = {
    BSEC_OUTPUT_RAW_TEMPERATURE,
    BSEC_OUTPUT_RAW_PRESSURE,
    BSEC_OUTPUT_RAW_HUMIDITY,
    BSEC_OUTPUT_RAW_GAS,
    BSEC_OUTPUT_IAQ,
    BSEC_OUTPUT_STATIC_IAQ,
    BSEC_OUTPUT_CO2_EQUIVALENT,
    BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
  };

  iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
  checkIaqSensorStatus();
  // Print the header
  output = "Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%], Static IAQ, CO2 equivalent, breath VOC equivalent";
  Serial.println(output);
}

void loop() {
  display.setCursor(0,0);
  display.clearDisplay();

  unsigned long time_trigger = millis();
  if (! iaqSensor.run()) { // If no data is available
    checkIaqSensorStatus();
    return;
  }
  
  output = String(time_trigger);
  output += ", " + String(iaqSensor.rawTemperature);
  output += ", " + String(iaqSensor.pressure);
  output += ", " + String(iaqSensor.rawHumidity);
  output += ", " + String(iaqSensor.gasResistance);
  output += ", " + String(iaqSensor.iaq);
  output += ", " + String(iaqSensor.iaqAccuracy);
  output += ", " + String(iaqSensor.temperature);
  output += ", " + String(iaqSensor.humidity);
  output += ", " + String(iaqSensor.staticIaq);
  output += ", " + String(iaqSensor.co2Equivalent);
  output += ", " + String(iaqSensor.breathVocEquivalent);
  Serial.println(output);

  
  Serial.print("Temperature = "); Serial.print(iaqSensor.temperature); Serial.println(" *C");
  display.print("Temperature: "); display.print(iaqSensor.temperature); display.println(" *C");

  Serial.print("Pressure = "); Serial.print(iaqSensor.pressure / 100.0); Serial.println(" hPa");
  display.print("Pressure: "); display.print(iaqSensor.pressure / 100); display.println(" hPa");

  Serial.print("Humidity = "); Serial.print(iaqSensor.humidity); Serial.println(" %");
  display.print("Humidity: "); display.print(iaqSensor.humidity); display.println(" %");

  Serial.print("IAQ = "); Serial.print(iaqSensor.staticIaq); Serial.println("");
  display.print("IAQ: "); display.print(iaqSensor.staticIaq); display.println("");
  
  Serial.print("CO2 equiv = "); Serial.print(iaqSensor.co2Equivalent); Serial.println("");
  display.print("CO2eq: "); display.print(iaqSensor.co2Equivalent); display.println("");
  
  Serial.print("Breath VOC = "); Serial.print(iaqSensor.breathVocEquivalent); Serial.println("");
  display.print("VOC: "); display.print(iaqSensor.breathVocEquivalent); display.println("");
  
  Serial.println();
  display.display();
  delay(2000);
}


// Helper function definitions
void checkIaqSensorStatus(void)
{
  if (iaqSensor.bsecStatus != BSEC_OK) {
    if (iaqSensor.bsecStatus < BSEC_OK) {
      output = "BSEC error code : " + String(iaqSensor.bsecStatus);
      Serial.println(output);
      display.setCursor(0,0);
      display.println(output);
      display.display();
      for (;;)  delay(10);
    } else {
      output = "BSEC warning code : " + String(iaqSensor.bsecStatus);
      Serial.println(output);
    }
  }

  if (iaqSensor.bme68xStatus != BME68X_OK) {
    if (iaqSensor.bme68xStatus < BME68X_OK) {
      output = "BME68X error code : " + String(iaqSensor.bme68xStatus);
      Serial.println(output);
      display.setCursor(0,0);
      display.println(output);
      display.display();
      for (;;)  delay(10);
    } else {
      output = "BME68X warning code : " + String(iaqSensor.bme68xStatus);
      Serial.println(output);
    }
  }
}

This guide was first published on Nov 08, 2017. It was last updated on Dec 08, 2023.

This page (BSEC Air Quality Library) was last updated on Sep 21, 2023.

Text editor powered by tinymce.