Apprenez à mesurer la qualité de l’air avec le BME680 Capteur environnemental et un ESP32. Le BME680 est un petit capteur qui peut non seulement mesurer la température, l’humidité, la pression, mais aussi la concentration de composés organiques volatils (COV), nocifs pour la santé.
La BSEC-Arduino-library bibliothèque pour le BME680 facilite particulièrement l’évaluation de la qualité de l’air, car elle renvoie un indice de qualité de l’air (IAQ) avec des valeurs allant de 0 à 400. Le tableau suivant montre comment interpréter ces valeurs d’IAQ :

Nous utiliserons cette fonctionnalité pour construire un mesureur de qualité de l’air.
Pièces requises
Vous trouverez ci-dessous les pièces nécessaires pour ce projet. En plus du capteur BME680, vous aurez besoin d’un microcontrôleur. J’ai choisi un ESP32 lite plus ancien, mais tout autre ESP32 fonctionnera très bien aussi. Notez que la BSEC-Arduino-library bibliothèque que nous allons utiliser supporte également d’autres microcontrôleurs. Consultez sa readme file documentation.

Capteur BME680

ESP32 lite

Câble USB de données

Jeu de fils Dupont

Plaque d’essai (breadboard)
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Présentation du capteur de gaz BME680
Le BME680 est un petit capteur environnemental 4-en-1 puissant qui peut mesurer la température, l’humidité, la pression barométrique et, surtout pour ce projet, la résistance aux gaz, utilisée pour estimer la qualité de l’air intérieur (IAQ). La photo ci-dessous montre le capteur, qui ne mesure que 3x3x1 mm :

Le BME680 utilise un capteur de gaz basé sur la technologie à oxyde métallique (MOX). Il ne détecte pas directement les gaz individuels, mais réagit à une large gamme de composés organiques volatils (COV) et de gaz comme le monoxyde de carbone (CO) présents dans l’air. Ces composés sont couramment émis par :
- Produits de nettoyage et aérosols
- Peintures et vernis
- Meubles et tapis (surtout neufs)
- Cuisine et tabagisme
- Souffle humain et odeurs corporelles
- Appareils de combustion
Bien que le capteur ne mesure pas les concentrations de gaz en parties par million (ppm), la bibliothèque BSEC utilise des modèles d’apprentissage automatique pour traduire les mesures de résistance aux gaz en un score IAQ significatif, ce qui le rend adapté à la surveillance de la qualité de l’air intérieur.
Qu’est-ce que l’IAQ et pourquoi c’est important
La valeur IAQ renvoyée par la bibliothèque logicielle du BME680 donne une estimation numérique de la pollution de l’air intérieur. Elle combine plusieurs mesures environnementales en un seul score, où :
- 0–50 = Qualité d’air excellente
- 51–100 = Bonne
- 101–150 = Légèrement polluée
- 151–200 = Modérément polluée
- 201–300 = Fortement polluée
- 301–500 = Très fortement polluée
Cette valeur est particulièrement utile car elle vous donne un chiffre clair et facile à comprendre, plutôt que des mesures brutes de résistance aux gaz, difficiles à interpréter seules.
Carte breakout pour BME680
Comme le capteur BME680 est très petit, nous utilisons une carte breakout pour le connecter à l’ESP32. Cela présente aussi l’avantage de pouvoir alimenter le capteur en 3,3 V ou 5 V, car la carte intègre un régulateur de tension. La photo ci-dessous montre la carte breakout avec le régulateur et le capteur BME680 :

Le BME680 est la petite boîte métallique carrée, à droite. À gauche se trouvent les broches pour l’interface I2C ou SPI, ainsi que les connexions d’alimentation (VCC, GND).
Nous allons utiliser l’interface I2C, car elle ne nécessite que de connecter SDA et SCL. Notez que la broche SDO détermine l’adresse I2C du capteur. Laisser SDO non connecté fixe l’adresse à 0x77, tandis que la connecter à la masse change l’adresse à 0x76.
Pour plus d’informations sur le capteur BME680, consultez notre BME680 Environmental Sensor with Arduinotutoriel, le BME680 Datasheetet peut-être le Bosch Website for the BME680.
Connexion du BME680 à l’ESP32
Pour connecter le BME680 à un ESP32 lite via I2C, il faut connecter SCL à la broche 23 et SDA à la broche 19. Les broches pour l’I2C matériel dépendent de votre carte et peuvent varier. Consultez le Find I2C and SPI default pins tutoriel pour identifier les broches de votre carte.
Sinon, il suffit de connecter GND à la masse (G) et VCC à la broche 3V (3,3 V) de l’ESP32. La photo ci-dessous montre le câblage complet :

Code pour mesurer les données environnementales avec le BME680
Comme mentionné précédemment, nous allons utiliser la BSEC-Arduino-library pour lire les données du BME680. Vous pouvez l’installer via le LIBRARY MANAGER. Cherchez « bsec » et installez la « BSEC Software Library » comme montré ci-dessous :

Notez qu’il existe aussi la plus récente Bosch-BSEC2-Library, que je n’ai pas testée. J’ai cependant utilisé la plus simple Adafruit BME680 library dans un autre tutoriel (BME680 Environmental Sensor with Arduino). Mais cette bibliothèque ne renvoie pas de mesures facilement interprétables de la qualité de l’air (IAQ), donc nous ne pouvons pas l’utiliser ici.
Le code suivant montre comment capturer des données de qualité de l’air telles que l’IAQ, le pourcentage de gaz, ainsi que des données environnementales simples comme la température, l’humidité et la pression avec le BME680. Je vais décomposer le code et expliquer chaque partie :
#include "bsec.h"
Bsec sensor;
void checkSensor() {
if (sensor.bsecStatus != BSEC_OK) {
Serial.println("BSEC status: " + String(sensor.bsecStatus));
}
if (sensor.bme68xStatus != BME68X_OK) {
Serial.println("BME68X status: " + String(sensor.bme68xStatus));
}
}
void setup(void) {
Serial.begin(115200);
delay(1000);
sensor.begin(BME68X_I2C_ADDR_HIGH, Wire);
checkSensor();
bsec_virtual_sensor_t sensorList[8] = {
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_STATIC_IAQ,
BSEC_OUTPUT_CO2_EQUIVALENT,
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
BSEC_OUTPUT_GAS_PERCENTAGE
};
sensor.updateSubscription(sensorList, 8, BSEC_SAMPLE_RATE_LP);
checkSensor();
}
void loop(void) {
if (sensor.run()) {
Serial.printf("Acc: %d\n", sensor.iaqAccuracy);
Serial.printf("IAQ: %.0f\n", sensor.iaq);
Serial.printf("sIAQ: %.0f\n", sensor.staticIaq);
Serial.printf("gas: %.0f %%\n", sensor.gasPercentage);
Serial.printf("temp: %.1f C\n", sensor.temperature);
Serial.printf("hum: %.0f %%\n", sensor.humidity);
Serial.printf("pres: %.0f hPa\n", sensor.pressure / 100.0);
Serial.println();
}
}
bibliothèques
En haut, le code inclut la BSEC library, abréviation de Bosch Sensortec Environmental Cluster. Cette bibliothèque combine les données brutes du capteur BME680 et applique des algorithmes pour fournir des mesures significatives de la qualité de l’air, comme l’IAQ et le pourcentage de gaz.
#include "bsec.h"
objets
Ensuite, nous créons une instance de la classe Bsecnommée sensor. Cet objet vous donne accès à toutes les fonctions BSEC.
Bsec sensor;
checkSensor
La fonction checkSensor()est une routine simple de vérification d’erreur. Elle contrôle à la fois le statut de l’algorithme BSEC et celui du matériel BME688. En cas de problème, elle affiche les codes d’erreur correspondants dans le moniteur série pour faciliter le débogage.
void checkSensor() {
if (sensor.bsecStatus != BSEC_OK) {
Serial.println("BSEC status: " + String(sensor.bsecStatus));
}
if (sensor.bme68xStatus != BME68X_OK) {
Serial.println("BME68X status: " + String(sensor.bme68xStatus));
}
}
Notez que les codes de statut positifs indiquent un avertissement, tandis que les codes négatifs indiquent une erreur !
setup
Dans la fonction setup(), le code démarre la communication série à 115200 bauds pour pouvoir afficher les résultats dans le moniteur série. Il inclut aussi un court délai pour s’assurer que le port série est prêt avant de continuer.
void setup(void) {
Serial.begin(115200);
delay(1000);
Ensuite, le capteur BME688 est initialisé via I2C avec la fonction sensor.begin(). L’adresse BME68X_I2C_ADDR_HIGH est utilisée, ce qui correspond à 0x77. Après l’initialisation, le code vérifie le statut du capteur.
sensor.begin(BME68X_I2C_ADDR_HIGH, Wire); checkSensor();
La constante s’appelle « HIGH », car si la broche SDO n’est pas connectée, une résistance interne la tire vers le haut. Si vous souhaitez utiliser l’autre adresse I2C (0x76) en connectant SDO à la masse, modifiez cela en conséquence.
Ensuite, le sketch définit à quels capteurs virtuels s’abonner. Cela vous permet de choisir quels capteurs (température, humidité, …) et quelles valeurs dérivées (par ex. température brute ou compensée) utiliser. C’est important pour réduire la consommation d’énergie en désactivant les capteurs inutilisés.
La fonction sensor.updateSubscription() indique à la bibliothèque quelles données de quels capteurs nous voulons et à quelle fréquence :
bsec_virtual_sensor_t sensorList[8] = {
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_STATIC_IAQ,
BSEC_OUTPUT_CO2_EQUIVALENT,
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
BSEC_OUTPUT_GAS_PERCENTAGE
};
sensor.updateSubscription(sensorList, 8, BSEC_SAMPLE_RATE_LP);
checkSensor();
}
La constante BSEC_SAMPLE_RATE_LP signifie un échantillonnage basse consommation (LP). C’est une autre façon de réduire la consommation du capteur. Il existe par exemple un mode BSEC_SAMPLE_RATE_ULP pour une consommation ultra basse (ULP). Vous pouvez même définir des taux d’échantillonnage différents pour différents ensembles de capteurs virtuels. Voir l’exemple basic_config_state_ULP_LP.
loop
La fonction loop()effectue le travail en temps réel. La fonction sensor.run()vérifie si de nouvelles données sont disponibles depuis la bibliothèque BSEC. Si oui, le code affiche diverses mesures dans le moniteur série :
void loop(void) {
if (sensor.run()) {
Serial.printf("Acc: %d\n", sensor.iaqAccuracy);
Serial.printf("IAQ: %.0f\n", sensor.iaq);
Serial.printf("sIAQ: %.0f\n", sensor.staticIaq);
Serial.printf("gas: %.0f %%\n", sensor.gasPercentage);
Serial.printf("temp: %.1f C\n", sensor.temperature);
Serial.printf("hum: %.0f %%\n", sensor.humidity);
Serial.printf("pres: %.0f hPa\n", sensor.pressure / 100.0);
Serial.println();
}
}
Notez que ceci n’est qu’un petit sous-ensemble des mesures et valeurs que la bibliothèque BSEC peut renvoyer. Le tableau suivant liste toutes les valeurs, leur signification et leur plage :
| Valeur | Description | Unité/Plage | Type | Catégorie |
|---|---|---|---|---|
iaq | Indice de qualité de l’air intérieur (temps réel, dynamique) | Indice (0–500) | Traitée | float |
iaqAccuracy | Confiance dans la valeur iaq | 0–3 | Statut | uint8_t |
staticIaq | Valeur IAQ lissée (moins sensible aux fluctuations) | Indice (0–500) | Traitée | float |
staticIaqAccuracy | Confiance dans la valeur staticIaq | 0–3 | Statut | uint8_t |
co2Equivalent | Concentration estimée de CO₂ à partir des COV | ppm | Traitée | float |
co2Accuracy | Confiance dans la valeur co2Equivalent | 0–3 | Statut | uint8_t |
breathVocEquivalent | Estimation équivalente de COV dans l’air expiré | ppm | Traitée | float |
breathVocAccuracy | Confiance dans la valeur breathVocEquivalent | 0–3 | Statut | uint8_t |
compGasValue | Valeur compensée de gaz utilisée en interne | Ohms (normalisé) | Interne | float |
compGasAccuracy | Confiance dans la valeur compGasValue | 0–3 | Statut | uint8_t |
gasPercentage | Pourcentage estimé d’air propre | % | Traitée | float |
gasPercentageAccuracy | Confiance dans la valeur gasPercentage | 0–3 | Statut | uint8_t |
rawTemperature | Température brute du capteur | °C | Brute | float |
temperature | Température compensée (ajustée pour l’auto-chauffage du capteur) | °C | Compensée | float |
rawHumidity | Humidité relative brute | % | Brute | float |
humidity | Humidité relative compensée | % | Compensée | float |
pressure | Pression barométrique | hPa | Brute | float |
gasResistance | Résistance brute du capteur de gaz | Ohms | Brute | float |
stabStatus | Indique si l’échantillon est stabilisé | 0 ou 1 (type booléen) | Statut | float |
runInStatus | Indique si le capteur est encore en phase de rodage | 0 ou 1 | Statut | float |
Dans le code, nous affichons les valeurs iaqAccuracy (Acc), iaq (IAQ), staticIaq (sIAQ), gasPercentage (gas), temperature (temp), humidity (hum) et pressure (pres). La température et l’humidité sont les valeurs compensées (tenant compte du chauffage du capteur de gaz) et la pression est divisée par 100 pour afficher la pression en hectopascal (hPa).
Les valeurs les plus intéressantes sont iaq (IAQ) et staticIaq (sIAQ), cette dernière étant une version plus stable de la première. La valeur IAQ est directement liée à une interprétation exploitable de la qualité de l’air, comme montré dans le tableau suivant :

Sortie
Si vous téléversez et exécutez le code, vous devriez voir les mesures apparaître dans le moniteur série :

Cependant, le capteur de gaz du BME680 nécessite un temps de rodage initial important, allant d’environ 5 à 30 minutes selon les conditions ambiantes et la fréquence d’échantillonnage. Pendant ce temps, la valeur IAQ semble généralement fixée à 25 ou 50.
La valeur iaqAccuracy, affichée comme Acc dans le moniteur série, est un indicateur de confiance pour les mesures IAQ (et autres mesures liées aux gaz).
Au début, vous verrez une valeur de 0, ce qui signifie que les mesures IAQ ne sont pas encore valides (voir l’exemple de sortie ci-dessus). Avec le temps, la valeur iaqAccuracymontera de 0 → 1 → 2 → 3 et une fois qu’elle atteint 3, les mesures IAQ sont considérées comme valides ! Voici un exemple de sortie après le rodage complet du capteur avec un iaqAccuracy (Acc) de 3 :

Évidemment, il est très pénible d’attendre jusqu’à 20 minutes pour obtenir des mesures valides à chaque redémarrage ou coupure de courant du BME680. Heureusement, le rodage peut être raccourci en sauvegardant et restaurant l’état du capteur BME680. La manière de procéder est décrite dans la section suivante.
Code pour sauvegarder et restaurer l’état du BME680
Le code ci-dessous étend notre code précédent avec deux fonctions, saveState et loadState, qui permettent de sauvegarder l’état du capteur BME680 et de réduire le temps avant que les mesures liées aux gaz soient disponibles :
#include <Preferences.h>
#include "bsec.h"
const unsigned long savePeriod = 3600 * 1000; // 1 hour
Bsec sensor;
Preferences prefs;
void checkSensor() {
if (sensor.bsecStatus != BSEC_OK) {
Serial.println("BSEC status: " + String(sensor.bsecStatus));
}
if (sensor.bme68xStatus != BME68X_OK) {
Serial.println("BME68X status: " + String(sensor.bme68xStatus));
}
}
void saveState() {
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
sensor.getState(state);
prefs.begin("bsec", false);
prefs.putBytes("state", state, BSEC_MAX_STATE_BLOB_SIZE);
prefs.end();
Serial.println("Sensor state saved");
}
void loadState() {
prefs.begin("bsec", true);
if (prefs.getBytesLength("state") > 0) {
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
prefs.getBytes("state", state, BSEC_MAX_STATE_BLOB_SIZE);
sensor.setState(state);
Serial.println("Sensor state loaded");
}
prefs.end();
}
void setup(void) {
Serial.begin(115200);
delay(1000);
sensor.begin(BME68X_I2C_ADDR_HIGH, Wire);
checkSensor();
loadState();
bsec_virtual_sensor_t sensorList[8] = {
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_STATIC_IAQ,
BSEC_OUTPUT_CO2_EQUIVALENT,
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
BSEC_OUTPUT_GAS_PERCENTAGE
};
sensor.updateSubscription(sensorList, 8, BSEC_SAMPLE_RATE_LP);
checkSensor();
}
void loop(void) {
static unsigned long lastSave = millis();
if (sensor.run()) {
Serial.printf("Acc: %d\n", sensor.iaqAccuracy);
Serial.printf("IAQ: %.0f\n", sensor.iaq);
Serial.printf("sIAQ: %.0f\n", sensor.staticIaq);
Serial.printf("gas: %.0f %%\n", sensor.gasPercentage);
Serial.printf("temp: %.1f C\n", sensor.temperature);
Serial.printf("hum: %.0f %%\n", sensor.humidity);
Serial.printf("pres: %.0f hPa\n", sensor.pressure / 100.0);
Serial.println();
if (millis() - lastSave > savePeriod && sensor.iaqAccuracy >=3) {
saveState();
lastSave = millis();
}
}
}
saveState
La fonction saveState utilise la bibliothèque Preferences de l’ESP32 pour stocker l’état du BME680 dans la mémoire non volatile (NVS) embarquée de l’ESP32. Ces données sont conservées lors des redémarrages et coupures de courant.
void saveState() {
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
sensor.getState(state);
prefs.begin("bsec", false);
prefs.putBytes("state", state, BSEC_MAX_STATE_BLOB_SIZE);
prefs.end();
Serial.println("Sensor state saved");
}
L’état inclut les bases apprises pour la résistance aux gaz, la température et l’humidité, que le capteur utilise pour calculer des valeurs IAQ précises et autres sorties.
La fonction réserve un bloc mémoire de taille BSEC_MAX_STATE_BLOB_SIZE pour l’état, puis copie l’état du capteur dans ce bloc en appelant getState(state).
Nous commençons ensuite un espace de noms appelé "bsec" dans la NVS de l’ESP32 en appelant prefs.begin("bsec", false), où false indique le mode lecture & écriture.
Ensuite, nous stockons le tableau binaire d’état dans la mémoire flash sous la clé "state" et fermons la session NVS (prefs.end) pour garantir que les données sont bien enregistrées.
loadState
La fonction loadState récupère l’état précédemment sauvegardé, s’il existe :
void loadState() {
prefs.begin("bsec", true);
if (prefs.getBytesLength("state") > 0) {
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
prefs.getBytes("state", state, BSEC_MAX_STATE_BLOB_SIZE);
sensor.setState(state);
Serial.println("Sensor state loaded");
}
prefs.end();
}
Si prefs.getBytesLength("state") renvoie 0, cela signifie que l’état du capteur n’a pas encore été stocké et on saute la lecture de l’état.
Sinon, on appelle prefs.getBytes("state", state, BSEC_MAX_STATE_BLOB_SIZE) pour récupérer l’état et l’écrire dans le capteur via sensor.setState(state).
setup
Dans la fonction setup, nous appelons loadState après avoir initialisé le capteur. Ainsi, si l’ESP32 et donc le capteur BME680 perdent l’alimentation ou sont réinitialisés, setup est appelé et nous restaurons l’état du capteur – à condition qu’il ait été sauvegardé.
void setup(void) {
...
sensor.begin(BME68X_I2C_ADDR_HIGH, Wire);
loadState();
...
}
loop
Dans la fonction loop, nous sauvegardons régulièrement l’état du capteur, par exemple toutes les heures, à condition que iaqAccuracy soit égal ou supérieur à 3 :
void loop(void) {
static unsigned long lastSave = millis();
if (sensor.run()) {
Serial.printf("Acc: %d\n", sensor.iaqAccuracy);
...
if (millis() - lastSave > savePeriod && sensor.iaqAccuracy >=3) {
saveState();
lastSave = millis();
}
}
}
La période de sauvegarde est contrôlée par la constante savePeriod. J’ai choisi une heure, mais vous n’êtes pas obligé de sauvegarder aussi souvent. Même toutes les trois ou quatre heures, c’est suffisant.
const unsigned long savePeriod = 3600 * 1000; // 1 hour
Notez que malgré la sauvegarde et la restauration de l’état du capteur, la valeur iaqAccuracy sera toujours à 0 après un redémarrage du capteur, mais le temps pour atteindre 3 sera plus court.
Conclusion
Dans ce tutoriel, vous avez appris à mesurer la qualité de l’air avec le capteur environnemental BME680, un ESP32 et la bibliothèque BSEC-Arduino-library.
La BSEC-Arduino-library propose plusieurs exemples de code qui valent le coup d’œil. Le code de ce tutoriel est dérivé de l’exemple basic.ino. L’exemple basic_config_state.ino montre comment sauvegarder et restaurer l’état du capteur. Et avec la basic_config_state_ulp_plus.ino, vous pouvez faire fonctionner le capteur en mode ultra-basse consommation (ulp). Enfin, pour le deep-sleep, consultez l’exemple esp32DeepSleep.ino.
Le BME680 mesure aussi la température, l’humidité et la pression, mais si c’est votre principal intérêt et que vous n’avez pas besoin des valeurs IAQ, utilisez le Adafruit BME680 library plutôt que le plus complexe BSEC-Arduino-library. Voir le tutoriel BME680 Environmental Sensor with Arduino pour plus de détails.
Si vous n’avez pas besoin de mesures de gaz du tout, je vous conseille le capteur BME280, qui est plus petit et moins cher. Voir le tutoriel How To Use BME280 Pressure Sensor With Arduino pour plus d’informations.
Si vous avez des questions, n’hésitez pas à les poser dans la section commentaires.
Bon bricolage ; )

