Un capteur de qualité de l'air intérieur qui mesure le CO2 et les particules fines vous indique quand une pièce a besoin d'air frais ou de filtration, bien avant que les occupants ne se sentent fatigués ou ne commencent à tousser. Dans ce tutoriel, vous allez en construire un avec un ESP32, un capteur de CO2 Sensirion SCD41 et un capteur de particules Plantower PMS5003, publier les mesures en JSON via MQTT et définir des alertes de ventilation sur un broker ConnectMQ.
Ce que mesurent les capteurs
- CO2 (ppm) est le meilleur indicateur de la ventilation dans les pièces occupées. L'air extérieur se situe environ entre 400 et 450 ppm. Les recommandations de ventilation des bâtiments retiennent souvent des valeurs autour de 800 à 1 000 ppm comme signe que l'apport d'air frais est insuffisant pour le nombre de personnes présentes. Le SCD41 est un véritable capteur NDIR photoacoustique, et non une estimation à partir de mesures de COV.
- PM2.5 (microgrammes par mètre cube) mesure les particules fines issues de la cuisine, des bougies, de la pollution extérieure ou de la poussière de chantier. Le PMS5003 utilise la diffusion laser et fournit les valeurs PM1.0, PM2.5 et PM10.
- La température et l'humidité sont fournies gratuitement par le SCD41 et donnent un contexte de confort.
La mesure des COV est une extension utile. Un Sensirion SGP41 ou un Bosch BME680 ajoute un indice COV qui réagit aux produits d'entretien et aux émanations des matériaux. Elle est laissée de côté dans le montage principal pour garder un code court.
Composants et câblage
| Composant | Broche | Broche ESP32 | Remarques |
|---|---|---|---|
| SCD41 | VDD | 3V3 | Les cartes breakout incluent généralement des résistances de pull-up |
| SCD41 | GND | GND | |
| SCD41 | SDA | GPIO 21 | Données I2C |
| SCD41 | SCL | GPIO 22 | Horloge I2C |
| PMS5003 | VCC | 5V (VIN) | Le ventilateur a besoin de 5 V |
| PMS5003 | GND | GND | |
| PMS5003 | TX | GPIO 16 (RX2) | Le niveau logique des données du capteur est de 3,3 V |
| PMS5003 | RX | GPIO 17 (TX2) | Facultatif, uniquement pour les commandes |
Utilisez l'IDE Arduino 2.x avec le paquet de cartes esp32 (core 3.x), et installez Sensirion I2C SCD4x (version 1.x) et PubSubClient depuis le gestionnaire de bibliothèques. La trame du PMS5003 est analysée directement dans le sketch, aucune bibliothèque supplémentaire n'est donc nécessaire.
Placez le capteur à hauteur de respiration, loin des fenêtres, des portes et des bouches de soufflage, et laissez l'entrée d'air du PMS5003 dégagée. Un capteur placé à côté d'une fenêtre ouverte mesure l'extérieur, pas la pièce.
Le sketch complet
#include <WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <SensirionI2cScd4x.h>
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
// Broker public de test. En production, utilisez 8883 + WiFiClientSecure et les identifiants du portail.
const char* BROKER = "broker.connectmq.com";
const int PORT = 1883;
const char* TOPIC = "connectmq/demo/iaq-3hv9/office-201/air";
const unsigned long PUBLISH_MS = 30000;
WiFiClient net;
PubSubClient mqtt(net);
SensirionI2cScd4x scd4x;
HardwareSerial pmsSerial(2);
uint16_t co2 = 0;
float tempC = NAN, rh = NAN;
uint16_t pm1 = 0, pm25 = 0, pm10 = 0;
bool pmValid = false;
unsigned long lastPublish = 0;
// Lire une trame PMS5003 de 32 octets : 0x42 0x4D, longueur, 13 mots de données, somme de contrôle
bool readPms() {
static uint8_t buf[32];
while (pmsSerial.available() >= 32) {
if (pmsSerial.peek() != 0x42) { pmsSerial.read(); continue; }
pmsSerial.readBytes(buf, 32);
if (buf[1] != 0x4D) continue;
uint16_t sum = 0;
for (int i = 0; i < 30; i++) sum += buf[i];
uint16_t check = (buf[30] << 8) | buf[31];
if (sum != check) continue;
// valeurs "environnement atmosphérique"
pm1 = (buf[10] << 8) | buf[11];
pm25 = (buf[12] << 8) | buf[13];
pm10 = (buf[14] << 8) | buf[15];
return true;
}
return false;
}
void connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(250);
}
void connectMqtt() {
while (!mqtt.connected()) {
String id = "iaq-" + String((uint32_t)ESP.getEfuseMac(), HEX);
if (!mqtt.connect(id.c_str())) delay(3000);
}
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
pmsSerial.begin(9600, SERIAL_8N1, 16, 17);
scd4x.begin(Wire, SCD41_I2C_ADDR_62);
scd4x.stopPeriodicMeasurement(); // au cas où la mesure tournait encore après un redémarrage logiciel
delay(500);
if (scd4x.startPeriodicMeasurement() != 0) {
Serial.println("SCD41 not found, check wiring");
}
connectWifi();
mqtt.setServer(BROKER, PORT);
mqtt.setBufferSize(512);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWifi();
if (!mqtt.connected()) connectMqtt();
mqtt.loop();
if (readPms()) pmValid = true;
bool ready = false;
if (scd4x.getDataReadyStatus(ready) == 0 && ready) {
uint16_t c; float t, h;
if (scd4x.readMeasurement(c, t, h) == 0 && c != 0) {
co2 = c; tempC = t; rh = h;
}
}
if (millis() - lastPublish >= PUBLISH_MS && co2 > 0) {
lastPublish = millis();
char msg[256];
snprintf(msg, sizeof(msg),
"{\"co2_ppm\":%u,\"temp_c\":%.1f,\"rh\":%.1f,\"pm1\":%u,\"pm25\":%u,\"pm10\":%u,\"pm_valid\":%s,\"rssi\":%d}",
co2, tempC, rh, pm1, pm25, pm10, pmValid ? "true" : "false", WiFi.RSSI());
mqtt.publish(TOPIC, msg);
Serial.println(msg);
}
}
En mode périodique, le SCD41 produit une nouvelle mesure toutes les cinq secondes, et le PMS5003 envoie des trames environ une fois par seconde. Le sketch conserve les dernières valeurs et publie toutes les 30 secondes, ce qui est largement suffisant pour la qualité de l'air d'une pièce.
Observer l'arrivée des données
Abonnez-vous depuis un terminal :
mosquitto_sub -h broker.connectmq.com -p 1883 -i iaq-view-3hv9 -t "connectmq/demo/iaq-3hv9/#" -v
Vous devriez voir des messages comme :
connectmq/demo/iaq-3hv9/office-201/air {"co2_ppm":742,"temp_c":23.4,"rh":41.8,"pm1":3,"pm25":6,"pm10":7,"pm_valid":true,"rssi":-58}
Soufflez doucement près du SCD41 et la valeur de CO2 grimpe en moins d'une minute. Allumez une allumette à proximité puis éteignez-la : le PM2.5 bondit. Ce sont deux vérifications rapides que les capteurs et l'analyseur fonctionnent. Le serveur MQTT public gratuit est idéal à ce stade, car aucun compte n'est nécessaire ; il reste réservé aux tests et aux prototypes, pas aux données de production.
Passer à un broker privé en TLS
Les données d'air d'une pièce révèlent la présence de personnes : les capteurs en production doivent donc utiliser un broker privé. Créez un broker dans le portail ConnectMQ et modifiez le code de connexion :
#include <WiFiClientSecure.h>
WiFiClientSecure net; // remplace WiFiClient
const int PORT = 8883;
// dans setup(), avant mqtt.setServer() :
// Charger le certificat ISRG Root X1 (Let's Encrypt) pour une validation complète :
// net.setCACert(ISRG_ROOT_X1_PEM);
// dans connectMqtt() :
// mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD");
Utilisez le client ID exactement tel qu'il a été délivré, car ConnectMQ associe les client IDs aux identifiants. Notre tutoriel ESP32 MQTT détaille la gestion des certificats sur l'ESP32.
Alertes de ventilation
Définissez des règles d'alerte à seuil dans le portail ConnectMQ sur les champs co2_ppm et pm25. Voici des points de départ suggérés, à adapter aux recommandations locales et à l'usage de la pièce :
| Niveau | CO2 | PM2.5 | Action suggérée |
|---|---|---|---|
| Bon | moins de 800 ppm | moins de 12 | Rien à faire |
| Moyen | 800 à 1 200 ppm | 12 à 35 | Augmenter la ventilation, vérifier le filtre |
| Mauvais | plus de 1 200 ppm | plus de 35 | Ouvrir les fenêtres ou renforcer la ventilation, trouver la source de particules |
Les règles se déclenchent à chaque valeur qui franchit le seuil, et le journal des alertes conserve l'historique pour que vous voyiez quelles pièces sont régulièrement confinées à certaines heures. Pour piloter automatiquement un ventilateur ou un registre, abonnez-vous au topic d'air depuis un flow Node-RED ou une automatisation Home Assistant et commutez l'actionneur via son propre topic de commande MQTT. L'intégration MQTT de Home Assistant fait apparaître le capteur sous forme d'entités sensor en quelques lignes de YAML, ce qui l'intègre naturellement à une maison connectée ; Jeedom et Domoticz savent aussi communiquer en MQTT.
Lire les données dans la durée
Les mesures isolées sont moins parlantes que les tendances quotidiennes. Dans une salle de réunion typique, le CO2 monte régulièrement pendant chaque réunion et redescend une fois la salle vidée ; la vitesse de cette baisse indique la qualité de la ventilation. Une salle encore au-dessus de 1 000 ppm une heure après le départ de tous a un problème de ventilation, pas d'occupation. Les PM2.5, en revanche, restent généralement bas en intérieur et présentent de courts pics liés à la cuisine, à l'impression, au ménage ou à des événements extérieurs comme les pics de trafic et la fumée.
Pour conserver cet historique, exécutez un abonné qui écrit chaque message dans une base de séries temporelles, ou laissez Telegraf s'abonner aux topics d'air. Comparez les pièces côte à côte et regardez la pire heure de chaque journée plutôt que la moyenne, car les moyennes masquent les moments où les gens trouvent réellement l'air confiné. Partager un simple graphique hebdomadaire avec l'équipe des services généraux suffit souvent à faire modifier un planning de ventilation.
Si vous exploitez plusieurs capteurs, nommez chaque topic d'après la pièce plutôt que d'après l'appareil, afin qu'une carte remplacée publie au même endroit et que l'historique reste continu.
Conseils d'étalonnage et de précision
- Auto-étalonnage du CO2. Le SCD41 a l'auto-étalonnage automatique activé par défaut, ce qui suppose que le capteur voit régulièrement un air frais de niveau extérieur. Dans les pièces jamais entièrement ventilées, désactivez-le et effectuez plutôt un recalibrage forcé à l'extérieur.
- Préchauffage. Ignorez les premières minutes de mesures après la mise sous tension.
- Auto-échauffement. Éloignez l'ESP32 et tout régulateur de tension du SCD41, sinon la température mesurée sera trop élevée.
- Durée de vie du capteur de particules. Le ventilateur et le laser du PMS5003 s'usent. Pour les déploiements longs, mettez-le en veille entre les mesures grâce à sa broche SET.
- Humidité et PM. Les capteurs optiques de particules surestiment en air très humide, car les gouttelettes d'eau diffusent la lumière. Traitez avec prudence les mesures de PM au-delà d'environ 80 % d'humidité relative.
Passer à l'échelle d'un bâtiment entier
Un capteur par salle de réunion ou par zone d'open space est une bonne densité. Chaque appareil a besoin de ses propres identifiants et d'un topic dans la hiérarchie du bâtiment, par exemple acme/ist01/hq/f03/meeting-301/air. Un pilote d'une douzaine de capteurs plus un tableau de bord tient dans les 25 connexions du plan Serverless gratuit. Combiner la qualité de l'air avec des capteurs d'occupation de bureau et la surveillance CVC montre si l'air confiné vient d'un trop grand nombre de personnes ou d'une ventilation insuffisante. Ces mêmes topics peuvent alimenter un jumeau numérique du bâtiment. Un broker MQTT managé évite d'exploiter un serveur dans le bâtiment, et le guide de l'automatisation IoT recense d'autres projets à construire sur le même broker.
Démarrer avec ConnectMQ
Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire. Flashez le sketch avec vos identifiants, ouvrez l'explorateur de topics en direct et définissez votre première alerte CO2. ConnectMQ s'occupe du TLS, de l'authentification et de la disponibilité.
Questions fréquentes
À partir de quel niveau de CO2 une pièce a-t-elle besoin de plus de ventilation ?
De nombreuses recommandations de ventilation considèrent des valeurs durablement supérieures à environ 1 000 ppm comme le signe d'un apport d'air frais insuffisant pour l'occupation. Suivez les recommandations locales et observez les tendances plutôt que les mesures isolées.
Un capteur de COV peut-il remplacer un vrai capteur de CO2 ?
Non. Les capteurs qui annoncent un « CO2 équivalent » l'estiment à partir des COV et peuvent être très éloignés de la réalité. Utilisez un capteur NDIR ou photoacoustique comme le SCD41 pour mesurer le vrai CO2.
À quelle fréquence le capteur de qualité de l'air intérieur doit-il publier ?
Toutes les 30 à 60 secondes, c'est largement suffisant. La qualité de l'air évolue sur plusieurs minutes, et publier moins souvent économise de l'énergie et du trafic sur le broker.
Le PMS5003 a-t-il besoin de 5 V ?
Son ventilateur nécessite une alimentation de 5 V, mais sa sortie série est en logique 3,3 V : la broche TX peut donc être reliée directement à une entrée de l'ESP32.



