Calculer l'Indice de Qualité de l'Air (IAQ, IQA) avec un DSM501 (Arduino, ESP8266) • Domotique et objets connectés à faire soi-même

L’indice de qualité de l’air (IAQ ou IQA en anglais) est assez facile a déterminer à l’aide d’un Arduino (ou ESP8266) et un capteur DSM501. Le capteur DSM501A est un détecteur capable de mesurer la présence de fines particules en suspension dans l’atmosphère suivant les normes PM2.5 et PM10. Le DSM501A est un capteur très économique (environ 4,80€) qui pourra servir de base pour fabriquer une station de mesure de la qualité de l’air connectée à l’aide d’un ESP8266. Le DSM501A est capable de réaliser des mesures aux standard PM2.5 et PM10. C’est à dire qu’il est capable de détecter les particules dont le diamètre est inférieur à 2,5µm pour PM2.5 et inférieure à 1µm pour PM1.0.

Principe de fonctionnement du capteur

Le DSM501 est un détecteur optique à Led plus économique à fabriquer que les modèles Laser. Le principe de fonctionnement est similaire aux détecteurs de fumées utilisés dans les détecteurs d’incendie. La led illumine les particules dans une chambre noire. Un photo-détecteur collecte la lumière. Le signal mesuré est alors proportionnel à la taille et à la quantité de particules en suspension.

Attention. Il ne faut pas utiliser ce type de détecteur pour détecter des fumées provenant d’un incendie.

source : http://doc.lijun.li/misc-dust-detector-with-arduino-serial-comm.html

Le DSM501 est capable de classifier et de mesurer les particules en suspension dans l’air dont la taille est inférieure à 1 micromètre (PM1.0) et 2,5 micromètres (PM2,5).

Principe de communication avec l’Arduino / ESP8266

Le DSM501 n’envoi pas directement sa mesure. Il utilise le système PWM. Il va donc falloir mesurer le ratio entre le temps passé à l’état haut (+4.5V) et le temps passé à l’état bas(0V). Ensuite grâce à cette courbe, il est possible de déterminer la quantité de particules dans l’air.

source : http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf

Peut-on utiliser le DSM501 sur un ESP8266 ?

Certains d’entre vous vont certainement hurler en voyant les sorties 4,5V du capteurs branchées sur l’ESP8266. En théorie il ne faut pas dépasser en tension de 3,3V sur les entrées de l’ESP8266. C’est parfaitement exact, mais l’ESP8266 semble tolérer un dépassement de tension si l’intensité reste faible d’après cette étude publiée par Digital Me. On risque surtout de détériorer son ESP en branchant directement le +5V sur la borne 3,3V ou une sortie GPIO par erreur.

Détermination de la concentration en particules

Heureusement, des Makers ont fait le travail pour nous ! Voici la fonction qui permet de récupérer le signal PWM et de déterminer le ratio. Connaissant le ratio, il est possible d’en déduire la concentration en particules en suspension dans l’air en mg/m3.

long getPM(int DUST_SENSOR_DIGITAL_PIN) {
  starttime = millis();
  while (1) {
    duration = pulseIn(DUST_SENSOR_DIGITAL_PIN, LOW);
    lowpulseoccupancy += duration;
    endtime = millis();
    
    if ((endtime-starttime) >= sampletime_ms) {
      ratio = lowpulseoccupancy / (sampletime_ms*10.0);
      //ratio = (lowpulseoccupancy-endtime+starttime)/(sampletime_ms*10.0);  // Integer percentage 0=>100 -> Not working
      long concentration = 1.1 * pow( ratio, 3) - 3.8 *pow(ratio, 2) + 520 * ratio + 0.62; // using spec sheet curve
      Serial.println(ratio);
      lowpulseoccupancy = 0;
      return(concentration);    
    }
  }  
}

Source : https://github.com/mysensors/MySensors/blob/master/examples/DustSensorDSM/DustSensorDSM.ino

Calculer l’Indice de Qualité de l’Air (IQA ou AQI)

l’Indice de Qualité de l’Air en français (IQA) ou Air Quality Indice (AIQ) en anglais est un indicateur qui permet de déterminer un niveau de qualité d’air. Plusieurs polluants sont pris en compte. Dioxyde d’ozone (NO2), oxydes d’azotes (NOx), dioxyde de soufre (SO2), Plomb (Pb), particules fines de moins de 10µm (PM10), moins de 2.5µm (PM2,5), monoxyde de carbone (CO), Benzène (C6H6) et ozone (O3).

Le gros problème, c’est qu’il n’y n’existe pas de standard international. En France, c’est par exemple l’ATMO. La qualité de l’air est déterminée par un indice qui va de 1 (très bon) à 10 (dangereux). L’ATMO est dérivé du système Européen. En Europe, c’est le Common Air Quality Index (CAQI) qui va de 0 à 100 (5 niveaux). Aux USA et en Chine, l’indice AQI comporte 6 niveaux allant 0 à 500 (ou plus).

Pour trouver les seuils qui correspondent à votre pays, allez visiter cette page Wikipedia.

Comment calculer l’indice ATMO français

En France, pour rendre plus visible la qualité de l’air, deux indices ont été élaborés. Tout est expliqué en détail sur cette page Wikipedia :

  • L’indice ATMO pour les agglomérations dont la population dépasse 100 000 habitants. C’est le seuil maximum de quatre polluants. L’indice varie de 1 à 10. 
  • L’indice IQA pour les agglomérations de taille inférieure à 100 000 habitants. C’est un un indice simplifié, qui peut reposer sur la mesure d’un nombre plus réduit de polluants (de 1 à 3). D’après l’article 4 du décret français JORF n°274 du 25 novembre 2004, l’indice de qualité de l’air simplifié (IQA / AQI) est égal au plus grand des sous-indices des substances polluantes effectivement mesurées dans la zone géographique considérée. L’indice comprend 6 niveaux (très bon, bon, moyen, médiocre, mauvais, dangereux).

Pour déterminer l’IQA, il nous suffit donc d’avoir au moins une mesure. Si on a plusieurs capteurs à notre disposition, ce sera le sous-indice le plus défavorable qui sera retenu comme indice IQA. Les seuils sont imposés par la directive 2008/50/CE du 21 mai 2008.

Ce tableau de synthèse (tiré de l’article Wikipedia) permet de déterminer l’indice ATMO. En l’absence de seuils pour PM2.5, j’ai utilisé ceux de l’Angleterre, très proches des niveaux Européens.

Par exemple, si on trouve un PM10 = 15,5, l’indice ATMO simplifié (IQA) sera 3. Si on a plusieurs mesures, c’est le plus mauvais indice (la plus haute note) qui devient l’indice ATMO.

Indice ATMO O3

(moyenne horaire)

SO2

(moyenne horaire)

NO2

(moyenne horaire)

PM2,5

(moyenne journalière)

PM10

(moyenne journalière)

Niveau
1 0 à  29 0 à  39 0 à  29  0 à 11 0 à 6 Très bon
2 30 à  54 40 à  79 30 à 54 12 à 23 7 à 13 Très bon
3 55 à  79 80 à 119 55 à 84 24 à 35 14 à 20 Bon
4 80 à 104 120 à 159 85 à 109 36 à 41 21 à 27 Bon
5 105 à 129 160 à 199 110 à 134 42 à 47 28 à 34 Moyen
6 130 à 149 200 à 249 135 à 164 48 à 53 35 à 41 Médiocre
7 150 à 179 250 à 299 165 à 199 54 à 58 42 à 49 Médiocre
8 180 à 209 300 à 399 200 à 274 59 à 64 50 à 64 Mauvais
9 210 à 239 400 à 499 275 à 399 65 à 69 65 à 79 Mauvais
10 ≥ 240 ≥ 500 ≥ 400 > 70 ≥ 80 Très mauvais

Le calcul est similaire à l’ATMO français. Il est obtenu à l’aide de la grille suivante publiée sur le site airqualitynow.eu. Au minimum, la mesure doit durer 1 heure (PM10 ou PM2,5).

Source : https://www.airqualitynow.eu/about_indices_definition.php

Comment calculer l’AQI en Chine et aux USA

La Chine et les USA ont le même système de calcul. Le niveau de qualité de l’air comporte 6 niveaux (bon, modéré, médiocre, mauvais pour la santé, très mauvais pour la santé, dangereux). Le seuil va donc donc de 0 à 500 (ou plus) au lieu d’aller de 1 à 10 en Europe (ATMO). C’est très souvent la méthode de calcul que l’on retrouve dans les exemples de codes Arduino. Il existe également un calculateur en ligne ici.

Air Quality Index (AQI) Values Levels of Health Concern Colors
0 to 50 Good Green
51 to 100 Moderate Yellow
101 to 150 Unhealthy for Sensitive Groups Orange
151 to 200 Unhealthy Red
201 to 300 Very Unhealthy Purple
301 to 500 Hazardous Maroon

Pour calculer le seuil, il faut utiliser cette formule.

Les constantes sont extraites de ce tableau pour les différents polluants testés.

O3 (ppb) O3 (ppb) PM2.5 (µg/m3) PM10 (µg/m3) CO (ppm) SO2 (ppb) NO2 (ppb) AQI AQI
ClowChigh (avg) ClowChigh (avg) ClowChigh (avg) ClowChigh (avg) ClowChigh (avg) ClowChigh (avg) ClowChigh (avg) IlowIhigh Categorie
0-54 (8-hr) 0.0-12.0 (24-hr) 0-54 (24-hr) 0.0-4.4 (8-hr) 0-35 (1-hr) 0-53 (1-hr) 0-50 Good
55-70 (8-hr) 12.1-35.4 (24-hr) 55-154 (24-hr) 4.5-9.4 (8-hr) 36-75 (1-hr) 54-100 (1-hr) 51-100 Moderate
71-85 (8-hr) 125-164 (1-hr) 35.5-55.4 (24-hr) 155-254 (24-hr) 9.5-12.4 (8-hr) 76-185 (1-hr) 101-360 (1-hr) 101-150 Unhealthy for Sensitive Groups
86-105 (8-hr) 165-204 (1-hr) 55.5-150.4 (24-hr) 255-354 (24-hr) 12.5-15.4 (8-hr) 186-304 (1-hr) 361-649 (1-hr) 151-200 Unhealthy
106-200 (8-hr) 205-404 (1-hr) 150.5-250.4 (24-hr) 355-424 (24-hr) 15.5-30.4 (8-hr) 305-604 (24-hr) 650-1249 (1-hr) 201-300 Very Unhealthy
405-504 (1-hr) 250.5-350.4 (24-hr) 425-504 (24-hr) 30.5-40.4 (8-hr) 605-804 (24-hr) 1250-1649 (1-hr) 301-400 Hazardous
505-604 (1-hr) 350.5-500.4 (24-hr) 505-604 (24-hr) 40.5-50.4 (8-hr) 805-1004 (24-hr) 1650-2049 (1-hr) 401-500

Circuit

Branchez le DSM501 sur un Arduino ou un ESP8266 à l’aide du repérage suivant

Broche DSM501 Couleur Signification
2 (jaune) jaune Vout2 (PM1.0)
3 (blanc) blanc Vcc (+5V de l’Arduino ou ESP8266)
4 (rouge) rouge Vout1 (MP2.5)
5 (noir) noir GND

Source : http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf

Code Arduino / ESP8266 pour le DSM501

Impossible donc de vous proposer une méthode de calcul universelle. Il faudra adapter le code Arduino à votre pays. Voici une base de travail qui permet déjà de calculer l’ATMO français, le CAQI European et l’AQI Américain et Chinois. Le code source sera publié sur GitHub pour permettre à chacun de proposer la méthode de calcul correspondant à son son pays.

Il faut donc réaliser une mesure assez longue pour pouvoir estimer correctement l’AQI. Vous pouvez modifier la durée de mesure à l’aide de la variable sampletime_ms (en millisecondes). La mesure est ensuite extrapolée à 24 heures. Plus le temps de mesure sera long, meilleure sera l’estimation de l’indice AQI. Il faudra être patient au démarrage.

#include 

/* Connect the DSM501 sensor as follow 
 * https://www.elektronik.ropla.eu/pdf/stock/smy/dsm501.pdf
 * 1 green vert - Not used
 * 2 yellow jaune - Vout2 - 1 microns (PM1.0)
 * 3 white blanc - Vcc
 * 4 red rouge - Vout1 - 2.5 microns (PM2.5)
 * 5 black noir - GND
*/
#define DUST_SENSOR_DIGITAL_PIN_PM10  D3        // DSM501 Pin 2 of DSM501 (jaune / Yellow)
#define DUST_SENSOR_DIGITAL_PIN_PM25  D5        // DSM501 Pin 4 (rouge / red) 
#define COUNTRY                       0         // 0. France, 1. Europe, 2. USA/China
#define EXCELLENT                     "Excellent"
#define GOOD                          "Bon"
#define ACCEPTABLE                    "Moyen"
#define MODERATE                      "Mediocre"
#define HEAVY                         "Mauvais"
#define SEVERE                        "Tres mauvais"
#define HAZARDOUS                     "Dangereux"

unsigned long   duration;
unsigned long   starttime;
unsigned long   endtime;
unsigned long   lowpulseoccupancy = 0;
float           ratio = 0;
unsigned long   SLEEP_TIME    = 2 * 1000;       // Sleep time between reads (in milliseconds)
unsigned long   sampletime_ms = 5 * 60 * 1000;  // Durée de mesure - sample time (ms)

struct structAQI{
  // variable enregistreur - recorder variables
  unsigned long   durationPM10;
  unsigned long   lowpulseoccupancyPM10 = 0;
  unsigned long   durationPM25;
  unsigned long   lowpulseoccupancyPM25 = 0;
  unsigned long   starttime;
  unsigned long   endtime;
  // Sensor AQI data
  float         concentrationPM25 = 0;
  float         concentrationPM10  = 0;
  int           AqiPM10            = -1;
  int           AqiPM25            = -1;
  // Indicateurs AQI - AQI display
  int           AQI                = 0;
  String        AqiString          = "";
  int           AqiColor           = 0;
};
struct structAQI AQI;

SimpleTimer timer;

void updateAQILevel(){
  AQI.AQI = AQI.AqiPM10;
}

void updateAQI() {
  // Actualise les mesures - update measurements
  AQI.endtime = millis();
  float ratio = AQI.lowpulseoccupancyPM10 / (sampletime_ms * 10.0);
  float concentration = 1.1 * pow( ratio, 3) - 3.8 *pow(ratio, 2) + 520 * ratio + 0.62; // using spec sheet curve
  if ( sampletime_ms < 3600000 ) { concentration = concentration * ( sampletime_ms / 3600000.0 ); }
  AQI.lowpulseoccupancyPM10 = 0;
  AQI.concentrationPM10 = concentration;
  
  ratio = AQI.lowpulseoccupancyPM25 / (sampletime_ms * 10.0);
  concentration = 1.1 * pow( ratio, 3) - 3.8 *pow(ratio, 2) + 520 * ratio + 0.62;
  if ( sampletime_ms < 3600000 ) { concentration = concentration * ( sampletime_ms / 3600000.0 ); }
  AQI.lowpulseoccupancyPM25 = 0;
  AQI.concentrationPM25 = concentration;

  Serial.print("Concentrations => PM2.5: "); Serial.print(AQI.concentrationPM25); Serial.print(" | PM10: "); Serial.println(AQI.concentrationPM10);
  
  AQI.starttime = millis();
      
  // Actualise l'AQI de chaque capteur - update AQI for each sensor 
  if ( COUNTRY == 0 ) {
    // France
    AQI.AqiPM25 = getATMO( 0, AQI.concentrationPM25 );
    AQI.AqiPM10 = getATMO( 1, AQI.concentrationPM10 );
  } else if ( COUNTRY == 1 ) {
    // Europe
    AQI.AqiPM25 = getACQI( 0, AQI.concentrationPM25 );
    AQI.AqiPM10 = getACQI( 1, AQI.concentrationPM10 );
  } else {
    // USA / China
    AQI.AqiPM25 = getAQI( 0, AQI.concentrationPM25 );
    AQI.AqiPM10 = getAQI( 0, AQI.concentrationPM10 );
  }

  // Actualise l'indice AQI - update AQI index
  updateAQILevel();
  updateAQIDisplay();
  
  Serial.print("AQIs => PM25: "); Serial.print(AQI.AqiPM25); Serial.print(" | PM10: "); Serial.println(AQI.AqiPM10);
  Serial.print(" | AQI: "); Serial.println(AQI.AQI); Serial.print(" | Message: "); Serial.println(AQI.AqiString);
  

}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT);
  pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT);

  // wait 60s for DSM501 to warm up
  for (int i = 1; i