Capteur de fumée et gaz (En cours de rédaction)

Ce système permet de mesurer les taux de fumées, monoxydes de carbone et dioxyde de carbone dans l'air ainsi que la température et l'humidité.

Cela permet, par exemple, de s'assurer de ma qualité de l'air dans les locaux d'OpenFactory.

Les données sont transimise sur la plateforme ThingSpeak afin de pouvoir visualiser leur évolution dans le temps. Un système d'alertes sur téléphone est également mis en place grâce à l'application IFTTT en plus des alertes visuelles et sonores produitent par le système.

Contexte

Ce projet a été réalisé dans le cadre du stage d'Élisa, une étudiante en BTS Conception et Industrialisation en Microtechniques, à OpenFactory en juin/juillet 2021.

Schéma électronique

image schematique.png (0.1MB)
Schéma électronique
Projet KiCAD (.zip)

Liste du matériel

Nom Description Quantité Prix Unitaire Prix
ESP32 WROOM (Version 30 pins) Microcontrolleur 1
MQ-2 Capteur de fumées 1
MQ-7 Capteur de monoxyde de carbone (CO) 1
MQ-135 Capteur de dioxyde de carbone (CO2) 1
DHT11 Capteur de température et humidité 1
LED 1W Rouge+Bleu+Vert+Blanc """" Alarme visuelle 1
Buzzer Alarme sonore 1
Transistor 2N2222 Transistor NPN (interrupteur électronique) 5
Résistances 5ohm Protection des LEDs 4
Résistances 5.1k Diviseur de tension 3
Résistances 10k Diviseur de tension et bus ""OneWire"" 4
Condensateur 100nF Filtrage d'alimentation 1
Condensateur 100uF Filtrage d'alimentation 1
Il existe différentes versions des ESP32 WROOM avec des nombres de pins différents (30, 36, 38)
** Nous utilisons une puce (Cree XLamp XM-L) incluant 4 LEDs (Rouge, vert, bleu et blanc), elle peut être remplacée par des LEDs de puissance indépendantes.

NodeMCU

Paramètrage de la carte

- Ajouter la bibliothèque des cartes ESP8266 board dans Arduino IDE (http://arduino.esp8266.com/stable/package_esp8266com_index.json)
- Installer le paquet "esp8266 by ESP8266 Community" via le gestionnaire de cartes
- Utiliser la carte nommée "NodeMCU 1.0 (ESP-12E Module)" pendant l'envoi du code

Bibliothèques arduino requises

- DallasTemperature (Version installable via Arduino IDE)
- ThingSpeak (Version installable via Arduino IDE)
- MQUnifiedSensor (Version installable via Arduino IDE)
- ESP32 AnalogWrite (Version installable via Arduino IDE)

Code

// Definition des pins
#define PIN_MQ2 33
#define PIN_MQ7 35
#define PIN_ALIM_MQ7 26
#define PIN_MQ135 34
#define PIN_DHT11 16
#define PIN_LED_R 13
#define PIN_LED_G 12
#define PIN_LED_B 14
#define PIN_LED_W 27
#define PIN_BUZZER 18

// Gestion du capteur DHT11
#include <DHT.h>
#define DHTTYPE DHT11
DHT dht(PIN_DHT11, DHTTYPE);

// Gestion des capteurs MQ
#include <MQUnifiedsensor.h>

#define MQ_BOARD "ESP-32"
#define MQ_VOLT_RES 3.3
#define MQ_ADC_RES 12

#define MQ2_R0 2.85
#define MQ7_R0 7.10
#define MQ135_R0 13.95

unsigned long mq7OldMillis = 0;
int mq7State = 0; // 0 -> Chauffage | 1 -> Lecture

MQUnifiedsensor MQ2(MQ_BOARD, MQ_VOLT_RES, MQ_ADC_RES, PIN_MQ2, "MQ-2");
MQUnifiedsensor MQ7(MQ_BOARD, MQ_VOLT_RES, MQ_ADC_RES, PIN_MQ7, "MQ-7");
MQUnifiedsensor MQ135(MQ_BOARD, MQ_VOLT_RES, MQ_ADC_RES, PIN_MQ135, "MQ-135");

// Gestion du WiFi
#include <WiFi.h>
#define SSID "XXXX"
#define PASSWD "XXXX"

WiFiClient tsClient;
WiFiClient iftttClient;

// Gestion Thingspeak
#include <ThingSpeak.h>
#define TS_API_KEY "XXXX"
#define TS_CHANNEL XXXX
#define TS_FUMEE_FIELD 1
#define TS_CO_FIELD 2
#define TS_CO2_FIELD 3
#define TS_TEMP_FIELD 4
#define TS_HUM_FIELD 5

// Gestion IFTTT
#define IFTTT_HOST "maker.ifttt.com"
#define IFTTT_API_KEY "XXXX"
// Gases
#define IFTTT_FIRE_EVENT "fire"
#define IFTTT_FIRE_THRES 100
#define IFTTT_CO2_EVENT "co2"
#define IFTTT_CO2_THRES 600
#define IFTTT_CO_EVENT "co"
#define IFTTT_CO_THRES 100
// Temp
#define IFTTT_HOT_EVENT "hot"
#define IFTTT_HOT_THRES 35
#define IFTTT_COLD_EVENT "cold"
#define IFTTT_COLD_THRES 15
// Hum
#define IFTTT_DRY_EVENT "dry"
#define IFTTT_DRY_THRES 20
#define IFTTT_WET_EVENT "wet"
#define IFTTT_WET_THRES 80

bool co2EventSent = false;
bool coEventSent = false;
bool fireEventSent = false;
bool hotEventSent = false;
bool coldEventSent = false;
bool wetEventSent = false;
bool dryEventSent = false;

// Gestion PWM
#include <analogWrite.h>

// Valeurs des capteurs
int ppmFumee = 0;
int ppmCO = 0;
int ppmCO2 = 0;
int temp = 0;
int hum = 0;

// Triggers LED et Buzzer
bool fire = false;
bool co = false;
bool co2 = false;

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

    ledInit();

    pinMode(PIN_BUZZER, OUTPUT);

    sensorsInit();

    wifiInit();

    ThingSpeak.begin(tsClient);
    
    ledOff();
}

void loop() {
    bool goodMQ7 = false;
    // Lecture des capteurs
    readMQ2();
    goodMQ7 = readMQ7();
    readMQ135();
    readDHT();

    // Envoi des valeurs sur ThingSpeak
    ThingSpeak.setField(TS_FUMEE_FIELD, ppmFumee);
    if(goodMQ7) {
        ThingSpeak.setField(TS_CO_FIELD, ppmCO);
    }
    ThingSpeak.setField(TS_CO2_FIELD, ppmCO2);
    ThingSpeak.setField(TS_TEMP_FIELD, temp);
    ThingSpeak.setField(TS_HUM_FIELD, hum);
    ThingSpeak.writeFields(TS_CHANNEL, TS_API_KEY);

    // Gestion des events et trigger IFTTT
    if(ppmFumee >= IFTTT_FIRE_THRES) {
        if(!fireEventSent) {
            sendIfttt(IFTTT_FIRE_EVENT);
            fireEventSent = true;
        }
        fire = true;
    } else {
        fireEventSent = false;
        fire = false;
    }

    if(goodMQ7 && ppmCO >= IFTTT_CO_THRES) {
        if(!coEventSent) {
            sendIfttt(IFTTT_CO_EVENT);
            coEventSent = true;
        }
        co = true;
    } else {
        coEventSent = false;
        co = false;
    }

    if(ppmCO2 >= IFTTT_CO2_THRES) {
        if(!co2EventSent) {
            sendIfttt(IFTTT_CO2_EVENT);
            co2EventSent = true;
        }
        co2 = true;
    } else {
        co2EventSent = false;
        co2 = false;
    }

    if(temp >= IFTTT_HOT_THRES) {
        if(!hotEventSent) {
            sendIfttt(IFTTT_HOT_EVENT);
            hotEventSent = true;
        }
    } else {
        hotEventSent = false;
    }

    if(temp <= IFTTT_COLD_THRES) {
        if (!coldEventSent) {
            sendIfttt(IFTTT_COLD_EVENT);
            coldEventSent = true;
        }
    } else {
        coldEventSent = false;
    }

    if(hum >= IFTTT_WET_THRES) {
        if(!wetEventSent) {
            sendIfttt(IFTTT_WET_EVENT);
            wetEventSent = true;
        }
    } else {
        wetEventSent = false;
    }

    if(hum <= IFTTT_DRY_THRES) {
        if(!dryEventSent) {
            sendIfttt(IFTTT_DRY_EVENT);
            dryEventSent = true;
        }
    } else {
        dryEventSent = false;
    }

    // Gestion des LEDs et du buzzer
    if(fire) {
        ledFire();
        fireAlarm();
    } else if (co) {
        ledCO();
        coAlarm();
    } else if (co2) {
        ledCO2();
        co2Alarm();
    } else {
        ledOff();
        noTone(PIN_BUZZER);
    }

    // Delai
    delay(250);
}


// Function LEDs
void ledInit() {
    pinMode(PIN_LED_R, OUTPUT);
    pinMode(PIN_LED_G, OUTPUT);
    pinMode(PIN_LED_B, OUTPUT);
    pinMode(PIN_LED_W, OUTPUT);

    analogWrite(PIN_LED_R, 100);
    analogWrite(PIN_LED_G, 100);
    analogWrite(PIN_LED_B, 100);
    analogWrite(PIN_LED_W, 100);
}

void ledOff() {
    analogWrite(PIN_LED_R, 0);
    analogWrite(PIN_LED_G, 0);
    analogWrite(PIN_LED_B, 0);
    analogWrite(PIN_LED_W, 0);
}

void ledFire() {
    analogWrite(PIN_LED_R, 255);
    analogWrite(PIN_LED_G, 0);
    analogWrite(PIN_LED_B, 0);
    analogWrite(PIN_LED_W, 0);
}

void ledCO() {
    analogWrite(PIN_LED_R, 0);
    analogWrite(PIN_LED_G, 255);
    analogWrite(PIN_LED_B, 0);
    analogWrite(PIN_LED_W, 0);
}

void ledCO2() {
    analogWrite(PIN_LED_R, 0);
    analogWrite(PIN_LED_G, 0);
    analogWrite(PIN_LED_B, 255);
    analogWrite(PIN_LED_W, 0);
}

// Fonctions buzzer
void tone(uint8_t pin, int freq) {
    // On utilise le channel 15 pour eviter les conflits avec analogWrite
    ledcSetup(15, 50000, 13);
    ledcAttachPin(pin, 15);
    ledcWriteTone(15, freq);
}

void noTone(uint8_t pin) {
    tone(pin, 0);
}

void fireAlarm() {
    tone(PIN_BUZZER, 1000);
}

void coAlarm() {
    tone(PIN_BUZZER, 1500);
}

void co2Alarm() {
    tone(PIN_BUZZER, 2000);
}

// Fonctions capteurs
void sensorsInit() {
    // DHT11
    dht.begin();

    // MQ-2 (Courbe CH4)
    MQ2.setRegressionMethod(true);
    MQ2.setA(4301.22);
    MQ2.setB(-2.65);
    MQ2.init();
    MQ2.setR0(MQ2_R0);
    MQ2.setRL(1);

    // MQ-7
    analogWrite(PIN_ALIM_MQ7, 255);
    MQ7.setRegressionMethod(true);
    MQ7.setA(99.042);
    MQ7.setB(-1.518);
    MQ7.init();
    MQ7.setR0(MQ7_R0);
    MQ7.setRL(1);

    // MQ-135
    MQ135.setRegressionMethod(true);
    MQ135.setA(110.47);
    MQ135.setB(-2.862);
    MQ135.init();
    MQ135.setR0(MQ135_R0);
    MQ135.setRL(1);
}

void readMQ2() {
    MQ2.update();
    ppmFumee = MQ2.readSensor();
}

bool readMQ7() {
    // Temps de chauffe écoulé
    if(!mq7State && (millis() - mq7OldMillis) >= (60000UL)) {
        // Passage en mode lecture
        analogWrite(PIN_ALIM_MQ7, 20);

        mq7OldMillis = millis();

        mq7State = 1;

    // Temps de lecture écoulé
    } else if (mq7State && (millis() - mq7OldMillis) >= (90000UL)) {
        // Passage en mode chauffage
        analogWrite(PIN_ALIM_MQ7, 255);

        mq7OldMillis = millis();

        mq7State = 0;
    }
    
    if(mq7State) {
        analogWrite(PIN_ALIM_MQ7, 255);
        delay(5);
        MQ7.update();
        ppmCO = MQ7.readSensor();
        analogWrite(PIN_ALIM_MQ7, 20);
        
        // Valeur mise a jour
        return true;
    }

    // Pas de nouvelle valeur
    return false;
}

void readMQ135() {
    MQ135.update();
    ppmCO2 = MQ135.readSensor() + 400;
}

void readDHT() {
    temp = dht.readTemperature();
    hum = dht.readHumidity();
}

// Fonctions WiFi et IOT
void wifiInit() {
    WiFi.mode(WIFI_STA);

	// Init WiFi
	Serial.println();
	Serial.print("Connexion en cours");

	WiFi.begin(SSID, PASSWD);

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

	Serial.println("Connexion WiFi OK");

	// Gestion MAC
	byte mac[6];
	WiFi.macAddress(mac);

	// Affichage de l'adresse IP
	Serial.print("Adresse IP : ");
	Serial.println(WiFi.localIP());
}

void sendIfttt(String event) {
    Serial.println(iftttClient.connect(IFTTT_HOST, 80));
    iftttClient.println("GET http://maker.ifttt.com/trigger/"+event+"/with/key/"+IFTTT_API_KEY);
}

Constantes à modifier

Il faut remplacer les XXXX dans le code pour configurer les différents services, on les trouve sur les lignes de ce type : #define NOM "XXXX"
Configuration WiFi
SSID (ligne 38) : Nom de la connexion WiFi
PASSWD (ligne 39) : Mot de passe de la connexion WiFi
Configuration ThingSpeak
TS_API_KEY (ligne 46) : Clé API de ThingSpeak
TS_CHANNEL (ligne 47) : Numéro du canal ThingSpeak
Configuration IFTTT
IFTTT_API_KEY (ligne 56) : Clé API de IFTTT

Alarmes

Fumées

Seuil : 100 ppm
Fréquence : 1 kHz
Couleur : Rouge

CO

Seuil : 100 ppm
Fréquence : 1.5 kHz
Couleur : Vert

CO2

Seuil : 600 ppm
Fréquence : 2 kHz
Couleur : Bleu

ThingSpeak

ThingSpeak est une plateforme d'analyse IoT qui vous permet d'agréger, de visualiser et d'analyser des flux de données en direct dans le cloud.
Nous utilisons cette plateforme pour visualiser l'évolution des taux de gaz, de la température et de l'humidité mesurée par le système au cours du temps.

Visualisation des données du système

image thingspeak.png (41.5kB)
Affichage des données sur ThingSpeak

IFTTT

IFTTT est un service web permettant à ses utilisateurs de créer des chaînes d'instruction simples appelées applets. Cela permet de réagir à des évenements en activant d'autres systèmes.
Nous l'utilisons pour envoyé des alertes sur téléphone quand les taux de gaz dépassent les seuils de danger défini dans le système.

Licence Creative Commons
Ce contenu de Zoomacom est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International.
DIY NodeMCU OpenFactory Projets