MH-Z19, mesurer la concentration en CO2. Test avec Domoticz, code Arduino compatible ESP32/ESP8266 • Domotique et objets connectés à faire soi-même

Dans le tutoriel précédent, nous avons découvert et tester le capteur MH-Z19 qui permet de mesurer la concentration en CO2 sans calibration. Nous avons vu comment lire la concentration en CO2 renvoyé sur la broche PWM du capteur en MicroPython pour ensuite la publier sur un serveur Domoticz via l’interface HTTP/JSON. Dans ce nouveau tutoriel, je vous propose de faire la même chose avec du code Arduino. Le code est compatible avec l’ESP8266 et le nouveau ESP32. Pour cela, il faudra installer le SDK d’Espressif en suivant ce tutoriel pour les cartes ESP8266 et celui-ci pour les cartes ESP32.

Si vous n’avez lu l’article précédent, le capteur MH-Z19 de la société Winsen est plus précis que le capteur environnemental MQ135. Il est beaucoup plus cher (environ 20€) mais la mesure du taux de CO2 ne nécessite pas de “bidouille” mathématique. On récupère directement la valeur exprimée en ppm sur la broche PWM ou sur la sortie URT (port série).

Matériel nécessaire

Le code fonctionne indifféremment sur Arduino Uno (ou un clone), un ESP8266 ainsi que un ESP32. Pour ce tutoriel, nous allons utiliser l’interface série (UART) du MH-Z19.

Le MH-Z19 est donc un capteur auto-calibré, c’est à dire que la mesure envoyée par le capteur ne nécessite aucun traitement mathématique. Autrement dit, on récupère le teneur en CO2 exprimée en ppm (partie par million). Le MH-Z19 dispose d’une sortie PWM ainsi qu’une interface numérique UART (port série). Pour ce tutoriel, nous allons déjà commencer par exploiter la sortie PWM.

Plage de mesure 0 – 5000ppm
Précision ± 50ppm+5% de la valeur moyenne
Tension de travail 3.6 ~ 5.5 VDC
Courant moyen < 18 mA
Tension de l’interface 3.3 V
Sorties numériques UART et PWM
Temps de préchauffage 3 minutes
Température de fonctionnement 0 ~ 50 ℃
Humidité de fonctionnement 0 – 95% (sans condensation)
Dimensions 33 mm×20 mm×9 mm (L×W×H)
Poids 21g
Durée de vie annoncée > 5 ans

Le signal PWM est proportionnel à la concentration en CO2.

fafp62rgsa5mdkxujrnd-9511560

On devra donc mesurer le temps durant lequel le signal reste au niveau haut. Ensuite, la formule suivante permet d’un déduire le taux de CO2.

4rljqqdtodt6bb1zlayu-5385368

  • Cppm représente la concentration en CO2 dans l’atmosphère en ppm
  • Th, le temps pendant lequel le signal est resté au niveau haut
  • Tl, le temps pendant lequel le signal est resté au niveau bas

Pour un capteur 0-5000ppm, il suffit de remplacer 2000 par 5000 dans la formule. La documentation complète (en anglais) est disponible ici.

Préparer un appareil virtuel de type qualité de l’air  sur Domoticz

Allez sur le serveur Domoticz pour créer un appareil virtuel de type Qualité de l’Air (Air Quality) et récupérez l’Idx de celui-ci. Suivez ce tutoriel pour apprendre comment faire.

Câblage du port série du MH-Z19 sur un ESP8266

Même si on peut utiliser un Arduino Uno pour réaliser des mesures de concentration en CO2, l’ESP8266 qui intègre un module WiFI est bien mieux adapté pour ce projet. On pourra déplacer la sonde dans la maison et pourquoi pas lui adjoindre un petit écran OLED monochrome SSD1306. Pour que la mesure de concentration en CO2 soit correcte, il faut que le MH-Z19 soit alimenté en permanence. Comme vous avez pu le voir dans les caractéristiques techniques, il faut attendre au moins 2 minutes avant que la mesure soit correcte. Le fonctionnement sur batterie n’est donc pas adapté à ce type de projet.

L’ESP8266 dispose de 2 ports série UART. Le port UART0 (RXD0/TXD0) et réservé à la communication avec l’IDE. Le port numéroté par erreur n°1 (TXD1) est incomplet. Il n’y a que la broche TXD1. Elle est réservée pour flasher la mémoire de l’ESP8266. Ici, nous allons utiliser le port série RXT2/TXD2. La broche RX est située sur la broche D7 de l’ESP8266. La broche TX est sur la broche D6. On va donc câbler le prt série en croisant les broches comme d’habitude. La broche RX du MH-Z19 sur la D6. La broche TX du MH-Z19 sur la D7. Le MH-Z19 peut être alimenté avec une tension comprise entre 3,6 et 5,6V. Connectez la broche Vin du MH-Z19 sur la broche 5V de l’ESP8266. Fermez le circuit en connectant les broches GND.

gbiovcsn6ygofsf4bjct-5103067

Communication série avec le MH-Z19

J’ai adapté le code source du tutoriel précédent qui permettait de lire plusieurs sondes de température Dallas DS18B20. Voici ce qui est particulier. POur communiquer via le port série avec un autre appareils, on doit ouvrir un autre port série. C’est la librairie SoftwareSerial.h qui s’en charge. Pour ouvrir un port série sur les broches RXD2 et TXD2, on doit instancier un objet SoftwareSerial qui prend en paramètre les broches du port série. Dans le setup(), on démarre le port série. Ici, on le port avec une vitesse de 9600 bauds conformément aux spécifications de Wesen :

  • Baud rate :  9600
  • Data byte : 8 byte
  • Stop byte : 1 byte
  • Parity : no

Ici, on a donc 2 ports série ouverts. Le premier à 115200 bauds permet de communiquer avec le moniteur série de l’IDE Arduino (par exemple), le second communique avec le MH-Z19.

#include 
#define MH_Z19_RX D7
#define MH_Z19_TX D6

SoftwareSerial co2Serial(MH_Z19_RX, MH_Z19_TX);

void setup() {
  Serial.begin(115200);
  co2Serial.begin(9600); //Init sensor MH-Z19(14)  
}

Pour lire la mesure de CO2, j’ai utilisé le code développé par Jehy disponible sur GitHub.

int readCO2() {
  // D'après le code original de | From original code https://github.com/jehy/arduino-esp8266-mh-z19-serial
  byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
  // command to ask for data
  byte response[9]; // for answer

  co2Serial.write(cmd, 9); //request PPM CO2

  // The serial stream can get out of sync. The response starts with 0xff, try to resync.
  while (co2Serial.available() > 0 && (unsigned char)co2Serial.peek() != 0xFF) {
    co2Serial.read();
  }

  memset(response, 0, 9);
  co2Serial.readBytes(response, 9);

  if (response[1] != 0x86)
  {
    Serial.println("Invalid response from co2 sensor!");
    return -1;
  }

  byte crc = 0;
  for (int i = 1; i < 8; i++) {
    crc += response[i];
  }
  crc = 255 - crc + 1;

  if (response[8] == crc) {
    int responseHigh = (int) response[2];
    int responseLow = (int) response[3];
    int ppm = (256 * responseHigh) + responseLow;
    return ppm;
  } else {
    Serial.println("CRC error!");
    return -1;
  }
}

Pour le reste du code, c’est du déjà vu.

Publier la concentration de CO2 sur Domoticz via l’interface HTTP/JSON, code Arduino compatible ESP8266 et ESP32

Nous n’allons pas revoir ici comment fonctionne l’envoi de données au serveur Domoticz via l’interface HTTP/JSON. Tout est expliqué en détail dans ce tutoriel. Créer un nouveau croquis et collez le code ci-dessous. Ensuite, modifiez les paramètres suivants dans le code

  • wifi_ssid, réseau WiFi
  • wifi_password, mot de passe WiFi
  • host, adresse IP du serveur Domoticz
  • port, par défaut 8080
  • IDX_mhz19, Idx de l’appareil virtuel Domoticz qui va recevoir la concentration en CO2
/*
 * Read MZ-Z19 CO2 concentration using UART interface and publish value on Domoticz with HTTP request
 * Lecture de la concentration en CO2 d'un capteur MH-Z19 via le port série et plublication de la mesure sur un serveur Domoticz requete HTTP
 * projetsdiy.fr - diyprojects.io (december 2017) 
 */
//#include 
#include 
// Pour un Arduino ou ESP32 (le SDK Espressif doit être installé) | For Arduino or ESP32 (Espressif SDK must be installed) 
//#include 
//#include 
// Pour une carte ESP8266 | For ESP8266 development board
#include 
#include 
#include 

#define INTERVAL 5000
#define MH_Z19_RX D7
#define MH_Z19_TX D6

long previousMillis = 0;

SoftwareSerial co2Serial(MH_Z19_RX, MH_Z19_TX); // define MH-Z19

// Parametres WIFI - WiFi settings
#define wifi_ssid "********"
#define wifi_password "********"

// Paramètres HTTP Domoticz - HTTP Domoticz settings
const char* host = "***.***.***.***";
const int   port = 8080;
#define IDX_mhz19   26

HTTPClient http;

void setup() {
  Serial.begin(115200);

  // Connexion au réseau WiFi, connexion aux sondes
  // Start WiFi connexion and probes
  setup_wifi();           

  // Démarrer la communication série avec le MH-Z19 - Start UART communication with MZ-Z19 sensor
  unsigned long previousMillis = millis();
  co2Serial.begin(9600); //Init sensor MH-Z19(14)
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis < INTERVAL)
    return;
 
  previousMillis = currentMillis;
  Serial.print("Requesting CO2 concentration...");
  int ppm = readCO2();
  Serial.println("  PPM = " + String(ppm));
  
  // Format JSON à respecter pour l'API Domoticz - Domoticz JSON API 
  // /json.htm?type=command&param=udevice&idx=IDX&nvalue=PPM
  // https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Air_quality
  String url = "/json.htm?type=command&param=udevice&idx=";
   url += String(IDX_mhz19);
   url += "&nvalue=";    
   url += String(ppm); 
  sendToDomoticz(url);
  
}

//Connexion au réseau WiFi
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connexion OK ");
  Serial.print("=> Addresse IP : ");
  Serial.print(WiFi.localIP());
}


void sendToDomoticz(String url){
  Serial.print("Connecting to ");
  Serial.println(host);
  Serial.print("Requesting URL: ");
  Serial.println(url);
  http.begin(host,port,url);
  int httpCode = http.GET();
    if (httpCode) {
      if (httpCode == 200) {
        String payload = http.getString();
        Serial.println("Domoticz response "); 
        Serial.println(payload);
      }
    }
  Serial.println("closing connection");
  http.end();
}

int readCO2() {
  // D'après le code original de | From original code https://github.com/jehy/arduino-esp8266-mh-z19-serial
  byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
  // command to ask for data
  byte response[9]; // for answer

  co2Serial.write(cmd, 9); //request PPM CO2

  // The serial stream can get out of sync. The response starts with 0xff, try to resync.
  while (co2Serial.available() > 0 && (unsigned char)co2Serial.peek() != 0xFF) {
    co2Serial.read();
  }

  memset(response, 0, 9);
  co2Serial.readBytes(response, 9);

  if (response[1] != 0x86)
  {
    Serial.println("Invalid response from co2 sensor!");
    return -1;
  }

  byte crc = 0;
  for (int i = 1; i < 8; i++) {
    crc += response[i];
  }
  crc = 255 - crc + 1;

  if (response[8] == crc) {
    int responseHigh = (int) response[2];
    int responseLow = (int) response[3];
    int ppm = (256 * responseHigh) + responseLow;
    return ppm;
  } else {
    Serial.println("CRC error!");
    return -1;
  }
}

Enregistrez le croquis et téléversez-le sur l’ESP8266. Si tout est correct, vous devez recevoir une réponse avec le statut OK à chaque requête HTTP.

Connecting to 192.168.1.24
Requesting URL: /json.htm?type=command&param=udevice&idx=26&nvalue=410
Domoticz response 
{
   "status" : "OK",
   "title" : "Update Device"
}

closing connection

L’appareil virtuel affichant la teneur en CO2 dans la pièce s’actualise après quelques secondes sur Domoticz.

Avez-vous aimé cet article ?