Aller au contenu

Détecteur de gaz

370

📄 Description

Créer un détecteur de gaz (méthane, propane, butane) utilisant une carte ESP32-C3 avec un affichage OLED 0.42" et un capteur MQ-4.

https://youtu.be/ZZDhtIJAU3A

💰 Coût
estimation
📊 Difficulté ⚖️ Licence ⏱️ Durée
~ € 🟠🟠🟠⚪⚪ Moyen CC-BY 2 heures

Outils & Matériaux

Matériaux Outils
- ESP32-C3 avec affichage OLED intégré - IDE
- Capteur MQ-4 (détection de méthane, propane, butane)
- Bibliothèques : U8g2 (pour l’OLED), Arduino IDE

Étapes clés

  1. Câblage : Connexion du MQ-4 et de l’OLED à l’ESP32.
  2. Programmation : Lecture des données du MQ-4, affichage sur l’OLED, et déclenchement d’une alerte en cas de détection.
  3. Calibration : Mesure de la résistance du capteur en air propre (R0) et calcul de la concentration en PPM.
  4. Test : Vérification du bon fonctionnement via le moniteur série et l’affichage OLED.

📌 Introduction

  • Objectif du projet : Dans le cadre de l’OpenLab, au fil de nos digressions créatives, nous avons abouti à une idée aussi farfelue qu’amusante : concevoir un “Mesureur de Pet” — un projet qui, sous couvert d’humour, pourra être légitimé comme un véritable détecteur de gaz.
  • Matériel nécessaire (liens Amazon, fiches techniques)
    • ESP32 C3 Carte de développement avec Affichage OLED 0.42inch (amazon)
  • Schéma de principe

🔧 Matériel et câblage

  • Liste des composants

  • Schéma de câblage (ESP32 ↔ MQ-4 ↔ OLED)

  • connections: "gas1:VCC", "esp:5V.1", "red" "gas1:GND", "esp:GND.4", "black" "gas1:DOUT", "esp:2", "yellow" "gas1:AOUT", "esp:1", "cyan" "oled1:SDA", "esp:5", "green" "oled1:SCL", "esp:6", "blue" "oled1:VCC", "esp:5V.2", "red" "oled1:GND", "esp:GND.5", "black"

💻 Programmation - Test et calibration

  • Installation des bibliothèques (U8g2, MQ-4)
  • Code Arduino pour lire le MQ-4 et afficher sur l’OLED
  • Exemple de calibration et calcul des PPM

Vérification du bon fonctionnement de la carte

Test d’upload et de retour dans le moniteur série

✅ Configuration complète pour ESP32-C3 sur Arduino IDE 2.3.6 (Ubuntu)

1. Vérifie que tu as bien installé les cartes ESP32

  • Va dans Fichier → Préférences
  • Dans URL de gestionnaire de cartes supplémentaires, ajoute https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  • Puis va dans Outils → Type de carte → Gestionnaire de cartes
    • Recherche ESP32
    • Installe ou mets à jour esp32 by Espressif Systems (version ≥ 2.0.14 recommandée)

2. Sélectionne les bons paramètres

Dans Outils, choisis :

  • Carte : ESP32C3 Dev Module
  • Port : /dev/ttyACM0
  • Vitesse de téléversement : 115200 ou 921600
  • Flash Mode : QIO
  • Flash Size : 4MB
  • USB CDC On Boot : Enabled ✅ (important pour le port série)

3. Code de test série minimal

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("✅ Série OK !");
}

void loop() {
  Serial.println("🌀 Boucle active...");
  delay(1000);
}
  • Téléverse ce code
  • Ouvre le Moniteur Série (Ctrl+Maj+M)
  • Régle le baudrate sur 115200

4. Si toujours rien : appuie sur RESET

Après le message :

Hard resetting via RTS pin...

➡️ Appuie manuellement sur le bouton RESET de la carte si besoin.

Tu devrais voir une ligne comme :

[12345.6789] cdc_acm 1-1:1.0: ttyACM0: USB ACM device

Test vérification câblage écran

#include <Wire.h>

TwoWire testBus(0); // Bus I2C personnalisé

void scanBus(uint8_t sda, uint8_t scl) {
  Serial.print("Test SDA=");
  Serial.print(sda);
  Serial.print(" SCL=");
  Serial.println(scl);

  testBus.begin(sda, scl);
  delay(100);

  bool found = false;
  for (uint8_t addr = 1; addr < 127; addr++) {
    testBus.beginTransmission(addr);
    if (testBus.endTransmission() == 0) {
      Serial.print("  ✅ Adresse I2C trouvée : 0x");
      Serial.println(addr, HEX);
      found = true;
    }
  }

  if (!found) {
    Serial.println("  ❌ Aucun périphérique I2C détecté.");
  }

  testBus.end();
  delay(500);
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("🔍 Scan I2C multi-broches...");

  // Liste de paires SDA/SCL à tester
  uint8_t sdaPins[] = {4, 5, 6, 7, 8, 9, 10};
  uint8_t sclPins[] = {4, 5, 6, 7, 8, 9, 10};

  for (uint8_t i = 0; i < sizeof(sdaPins); i++) {
    for (uint8_t j = 0; j < sizeof(sclPins); j++) {
      if (sdaPins[i] != sclPins[j]) {
        scanBus(sdaPins[i], sclPins[j]);
      }
    }
  }

  Serial.println("✅ Scan terminé.");
}

void loop() {}

Résultat :

12:46:51.123 ->  Aucun périphérique I2C détecté. 
12:46:51.638 -> Test SDA=4 SCL=9 
12:46:51.734 ->  Aucun périphérique I2C détecté. 
12:46:52.249 -> Test SDA=4 SCL=10 
12:46:52.377 >  Aucun périphérique I2C détecté. 
12:46:52.862 -> Test SDA=5 SCL=4 
12:46:52.991 ->  Aucun périphérique I2C détecté. 
12:46:53.474 -> Test SDA=5 SCL=6 
12:46:53.571 ->  Adresse I2C trouvée : 0x3C

Vérification écran + calibrage

#include <U8g2lib.h>

U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 6, /* data=*/ 5, /* reset=*/ U8X8_PIN_NONE);

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("✅ Série OK - Texte centré");

  u8g2.begin();
  u8g2.setContrast(255);
  u8g2.clearBuffer();

  const int xOffset = 28;
  const int yOffset = 24;

  // Dessin du cadre
  u8g2.drawFrame(xOffset, yOffset, 72, 40);

  // Police et texte centré
  u8g2.setFont(u8g2_font_5x8_tr);
  int textWidth = 9 * 5; // "OLED OK !" = 9 caractères × 5px
  int textX = xOffset + (72 - textWidth) / 2;
  int textY = yOffset + (40 + 8) / 2; // centré verticalement

  u8g2.drawStr(textX, textY, "OLED OK !");
  u8g2.sendBuffer();
}

void loop() {
  Serial.println("🌀 Boucle active...");
  delay(1000);
}

📌 Fiche technique : ESP32-C3 HW675 + OLED 0.42"

  • Résolution réelle : 72×40 pixels
  • Broches I2C confirmées : SDA = GPIO5, SCL = GPIO6
  • Adresse I2C : 0x3C
  • Orientation correcte : U8G2_R0 (USB en bas = texte à l’endroit)
  • Décalage visuel : xOffset = 28, yOffset = 24
  • Texte centré : "OLED OK !" avec police u8g2_font_5x8_tr

🧪 Le sketch utilisé affiche un cadre complet et centre le texte dans la zone visible. Parfait pour valider l’écran avant d’ajouter des pictos ou des capteurs.

🧠 Guide de test OLED – ESP32-C3 HW675

🎯 Objectif

Valider l’affichage d’un écran OLED 0.42" soudé sur la carte HW675, en corrigeant les broches, l’orientation et la zone d’affichage pour un rendu centré et lisible.

🧰 Matériel

  • Carte ESP32-C3 HW675
  • Écran OLED 0.42" SSD1306 (soudé)
  • Câble USB-C
  • Arduino IDE avec bibliothèque U8g2 installée

🔌 Connexions I2C confirmées

Fonction GPIO
SDA 5
SCL 6
Adresse 0x3C

🧪 Sketch de test OLED centré

cpp

`#include U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 6, 5, U8X8_PIN_NONE);

void setup() { Serial.begin(115200); delay(1000); Serial.println("✅ Série OK - Texte centré");

u8g2.begin(); u8g2.setContrast(255); u8g2.clearBuffer();

const int xOffset = 28; const int yOffset = 24;

u8g2.drawFrame(xOffset, yOffset, 72, 40); // cadre visible

u8g2.setFont(u8g2_font_5x8_tr); int textWidth = 9 * 5; // "OLED OK !" = 9 caractères × 5px int textX = xOffset + (72 - textWidth) / 2; int textY = yOffset + (40 + 8) / 2;

u8g2.drawStr(textX, textY, "OLED OK !"); u8g2.sendBuffer(); }

void loop() { Serial.println("🌀 Boucle active..."); delay(1000); }`

🧭 Orientation confirmée

  • Tenir la carte USB en bas
  • Utiliser U8G2_R0 pour un affichage à l’endroit
  • Décalage horizontal : xOffset = 28
  • Décalage vertical : yOffset = 24

✅ Résultat attendu

  • Moniteur série : “✅ Série OK - Texte centré”
  • Écran OLED : cadre complet 72×40 pixels avec texte “OLED OK !” centré

📎 Ressources visuelles

  • Fiche visuelle disponible ci-dessus (image)
  • Peut être intégrée dans Notion, Canva, Genially ou imprimée

Ajout du capteur MQ4

🔌 Câblage du capteur MQ-4 vers ESP32-C3 HW675

Broche MQ-4 Fonction Connexion ESP32-C3 HW675
VCC Alimentation 3.3V ou 5V (si disponible)
GND Masse GND
AOUT Sortie analogique GPIO1 ou autre broche ADC
DOUT Seuil numérique (optionnel) GPIO2 ou autre digital

🔎 Recommandation : utilise AOUT pour une lecture analogique plus précise du taux de méthane (CH₄). Le MQ-4 est un capteur à oxyde métallique (SnO₂) dont la résistance varie selon la concentration de gaz.

⚙️ Exemple de lecture analogique dans Arduino

const int mq4Pin = 1; // GPIO1 = broche ADC

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("MQ-4 prêt !");
}

void loop() {
  int valeur = analogRead(mq4Pin);
  Serial.print("Lecture MQ-4 : ");
  Serial.println(valeur);
  delay(1000);
}

✅ Sketch MQ-4 + OLED avec 5 niveaux d’alerte

#include <U8g2lib.h>const int mq4Pin = 1; // GPIO1 = entrée analogique

// OLED calibré : orientation normale, décalage visuel
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 6, 5, U8X8_PIN_NONE);

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("MQ-4 + OLED avec 5 niveaux ✅");

  u8g2.begin();
  u8g2.setContrast(255);
}

void loop() {
  int valeur = analogRead(mq4Pin); // lecture brute (0–4095)
  Serial.print("MQ-4 : ");
  Serial.println(valeur);

  // Message d’état selon seuils
  const char* etat;
  if (valeur < 300) {
    etat = "Tres faible";
  } else if (valeur < 700) {
    etat = "Faible";
  } else if (valeur < 1000) {
    etat = "Normal";
  } else if (valeur < 2000) {
    etat = "Attention";
  } else {
    etat = "Mortel";
  }

  // Conversion en texte
  char ligne1[16];
  snprintf(ligne1, sizeof(ligne1), "MQ4: %d", valeur);

  // Affichage OLED calibré
  u8g2.clearBuffer();

  const int xOffset = 28;
  const int yOffset = 24;

  u8g2.drawFrame(xOffset, yOffset, 72, 40); // cadre visible
  u8g2.setFont(u8g2_font_5x8_tr);

  // Ligne 1 : valeur
  int textWidth1 = strlen(ligne1) * 5;
  int textX1 = xOffset + (72 - textWidth1) / 2;
  int textY1 = yOffset + 14;

  // Ligne 2 : état
  int textWidth2 = strlen(etat) * 5;
  int textX2 = xOffset + (72 - textWidth2) / 2;
  int textY2 = textY1 + 12;

  u8g2.drawStr(textX1, textY1, ligne1);
  u8g2.drawStr(textX2, textY2, etat);
  u8g2.sendBuffer();

  delay(1000); // mise à jour toutes les secondes
}

🧪 Résultat attendu

Valeur MQ-4 Message affiché
150 Très faible
450 Faible
850 Normal
1450 Attention
2300 Mortel

Code final commenté

#include <U8g2lib.h> // Bibliothèque U8g2 pour gérer l’écran OLED

// Déclaration de la broche analogique utilisée pour le capteur MQ-4
const int mq4Pin = 1; // GPIO1 = entrée analogique sur ESP32-C3

// Initialisation de l’écran OLED avec les bons paramètres
// - Type d’écran : SSD1306 128x64
// - Mode logiciel I2C
// - Orientation : U8G2_R0 (texte à l’endroit quand USB en bas)
// - Broches I2C : SCL = GPIO6, SDA = GPIO5
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 6, 5, U8X8_PIN_NONE);

void setup() {
  Serial.begin(115200); // Initialisation du port série pour affichage dans le moniteur
  delay(1000);          // Petite pause pour stabiliser
  Serial.println("MQ-4 + OLED avec 5 niveaux ✅");

  u8g2.begin();         // Démarrage de l’écran OLED
  u8g2.setContrast(255); // Contraste maximal pour une bonne lisibilité
}

void loop() {
  // Lecture de la valeur analogique brute du capteur MQ-4 (entre 0 et 4095)
  int valeur = analogRead(mq4Pin);
  Serial.print("MQ-4 : ");
  Serial.println(valeur);

  // Détermination du message d’alerte selon la valeur lue
  const char* etat;
  if (valeur < 300) {
    etat = "Tres faible";   // Air ambiant, pas de gaz détecté
  } else if (valeur < 700) {
    etat = "Faible";        // Présence résiduelle possible
  } else if (valeur < 1000) {
    etat = "Normal";        // Niveau tolérable
  } else if (valeur < 2000) {
    etat = "Attention";     // Concentration significative
  } else {
    etat = "Mortel";        // Risque élevé, danger potentiel
  }

  // Conversion de la valeur en texte affichable
  char ligne1[16];
  snprintf(ligne1, sizeof(ligne1), "MQ4: %d", valeur);

  // Nettoyage du tampon d’affichage
  u8g2.clearBuffer();

  // Décalage visuel confirmé pour la zone 72×40 pixels
  const int xOffset = 28;
  const int yOffset = 24;

  // Dessin du cadre visible
  u8g2.drawFrame(xOffset, yOffset, 72, 40);

  // Choix de la police
  u8g2.setFont(u8g2_font_5x8_tr);

  // Calcul de la position horizontale pour centrer la ligne 1
  int textWidth1 = strlen(ligne1) * 5;
  int textX1 = xOffset + (72 - textWidth1) / 2;
  int textY1 = yOffset + 14; // Ligne du haut

  // Calcul de la position pour la ligne 2 (message d’alerte)
  int textWidth2 = strlen(etat) * 5;
  int textX2 = xOffset + (72 - textWidth2) / 2;
  int textY2 = textY1 + 12; // Ligne du bas

  // Affichage des deux lignes
  u8g2.drawStr(textX1, textY1, ligne1);
  u8g2.drawStr(textX2, textY2, etat);

  // Envoi du tampon à l’écran
  u8g2.sendBuffer();

  delay(1000); // Mise à jour toutes les secondes
}

Code corrigé avec barre de niveau

#include <U8g2lib.h>

// 🧪 MQ-4 sur GPIO2
const int mq4Pin = 2;

// 🖥️ OLED SSD1306 (I2C logiciel : SCL = GPIO6, SDA = GPIO5)
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 6, 5, U8X8_PIN_NONE);

// ⏱️ Alternance d’affichage
unsigned long lastSwitch = 0;
const unsigned long switchInterval = 5000;
bool afficherTexte = true;

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("MQ-4 + OLED + Affichage alterné ✅");

  u8g2.begin();
  u8g2.setContrast(255);
}

void drawBatteryBar(int valeur) {
  const int xOffset = 28;
  const int yOffset = 24;
  int largeur = 72;
  int hauteur = 40;

  // Cadre
  u8g2.drawFrame(xOffset, yOffset, largeur, hauteur);

  // Barre horizontale centrée
  int barWidth = map(valeur, 0, 4095, 0, largeur - 4);
  int barHeight = 10;
  int barX = xOffset + 2;
  int barY = yOffset + (hauteur - barHeight) / 2;

  u8g2.drawBox(barX, barY, barWidth, barHeight);
}

void loop() {
  int valeur = analogRead(mq4Pin);
  Serial.print("MQ-4 : ");
  Serial.println(valeur);

  const char* etat;
  if (valeur < 300) {
    etat = "Tres faible";
  } else if (valeur < 700) {
    etat = "Faible";
  } else if (valeur < 1600) { // ✅ seuil corrigé : 1500 = "Normal"
    etat = "Normal";
  } else if (valeur < 2500) {
    etat = "Attention";
  } else {
    etat = "Mortel";
  }

  // Alternance d’affichage toutes les 5 secondes
  if (millis() - lastSwitch > switchInterval) {
    afficherTexte = !afficherTexte;
    lastSwitch = millis();
  }

  u8g2.clearBuffer();

  const int xOffset = 28;
  const int yOffset = 24;
  u8g2.drawFrame(xOffset, yOffset, 72, 40);
  u8g2.setFont(u8g2_font_5x8_tr);

  if (afficherTexte) {
    // Texte centré dans le cadre
    char ligne1[16];
    snprintf(ligne1, sizeof(ligne1), "MQ4: %d", valeur);
    int textWidth1 = strlen(ligne1) * 5;
    int textX1 = xOffset + (72 - textWidth1) / 2;
    int textY1 = yOffset + 14;

    int textWidth2 = strlen(etat) * 5;
    int textX2 = xOffset + (72 - textWidth2) / 2;
    int textY2 = textY1 + 12;

    u8g2.drawStr(textX1, textY1, ligne1);
    u8g2.drawStr(textX2, textY2, etat);
  } else {
    drawBatteryBar(valeur);
  }

  u8g2.sendBuffer();
  delay(1000);
}

Code commenté avec 3 écrans d’affichage en boucle

#include <U8g2lib.h>  
// 📚 Bibliothèque U8g2 pour gérer l’écran OLED SSD1306 via I2C logiciel

const int mq4Pin = 2;  
// 🧪 MQ-4 branché sur GPIO2 (entrée analogique)

// 🖥️ Déclaration de l’écran OLED SSD1306 (128x64 pixels)
// Utilisation d’I2C logiciel : SCL = GPIO6, SDA = GPIO5
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 6, 5, U8X8_PIN_NONE);

unsigned long lastSwitch = 0;              // ⏱️ Dernier changement d’écran
const unsigned long switchInterval = 5000; // ⏱️ Intervalle entre écrans (5s)
int modeAffichage = 0;                     // 0 = valeur+texte, 1 = barre, 2 = icône ASCII
bool startupDone = false;                  // ⚡ Pour afficher l’écran d’accueil une seule fois

void setup() {
  Serial.begin(115200);
  delay(1000);
  u8g2.begin();
  u8g2.setContrast(255); // Luminosité maximale

  // === Écran d’accueil ===
  const int xOffset = 28;   // Position X du cadre
  const int yOffset = 24;   // Position Y du cadre
  const int largeur = 72;   // Largeur du cadre
  const int hauteur = 40;   // Hauteur du cadre

  u8g2.clearBuffer();
  u8g2.drawFrame(xOffset, yOffset, largeur, hauteur); // Dessin du cadre

  u8g2.setFont(u8g2_font_6x12_tr); // Police compacte pour 3 lignes

  // Texte à afficher
  const char* l1 = "Gaz";
  const char* l2 = "Detector";
  const char* l3 = "v1.0";

  // 📐 Calcul typographique pour centrer verticalement les 3 lignes
  int ascent = u8g2.getAscent();
  int descent = u8g2.getDescent(); // négatif
  int fontH = ascent - descent;
  int lineSpacing = 2; // espace entre lignes
  int blockH = 3 * fontH + 2 * lineSpacing; // hauteur totale du bloc texte

  // Baseline de chaque ligne
  int baseY1 = yOffset + (hauteur - blockH) / 2 + ascent;
  int baseY2 = baseY1 + fontH + lineSpacing;
  int baseY3 = baseY2 + fontH + lineSpacing;

  // Centrage horizontal par ligne
  int w1 = u8g2.getStrWidth(l1);
  int w2 = u8g2.getStrWidth(l2);
  int w3 = u8g2.getStrWidth(l3);
  int x1 = xOffset + (largeur - w1) / 2;
  int x2 = xOffset + (largeur - w2) / 2;
  int x3 = xOffset + (largeur - w3) / 2;

  // ✍️ Dessin des 3 lignes
  u8g2.drawStr(x1, baseY1, l1);
  u8g2.drawStr(x2, baseY2, l2);
  u8g2.drawStr(x3, baseY3, l3);

  u8g2.sendBuffer();
  delay(3000); // Affichage pendant 3 secondes
  startupDone = true; // ⚡ Ensuite on passe au cycle normal
}

// 🔲 Fonction pour dessiner une barre horizontale (écran 2)
void drawBatteryBar(int valeur) {
  const int xOffset = 28;
  const int yOffset = 24;
  int largeur = 72;
  int hauteur = 40;

  u8g2.drawFrame(xOffset, yOffset, largeur, hauteur);

  int barWidth = map(valeur, 0, 4095, 0, largeur - 4);
  int barHeight = 10;
  int barX = xOffset + 2;
  int barY = yOffset + (hauteur - barHeight) / 2;

  u8g2.drawBox(barX, barY, barWidth, barHeight);
}

void loop() {
  if (!startupDone) return; // ⏸️ Ne rien faire tant que l’écran d’accueil n’est pas passé

  // 📥 Lecture du capteur MQ-4
  int valeur = analogRead(mq4Pin);

  // Détermination du niveau
  const char* etat;
  int niveau;
  if (valeur < 500) { etat = "Tres faible"; niveau = 1; }
  else if (valeur < 2000) { etat = "Faible"; niveau = 2; }
  else if (valeur < 5000) { etat = "Moyen"; niveau = 3; }
  else if (valeur < 8000) { etat = "Eleve"; niveau = 4; }
  else { etat = "Critique"; niveau = 5; }

  // ⏱️ Alternance d’écran toutes les 5 secondes
  if (millis() - lastSwitch > switchInterval) {
    modeAffichage = (modeAffichage + 1) % 3;
    lastSwitch = millis();
  }

  u8g2.clearBuffer();

  if (modeAffichage == 0) {
    // === Écran 1 : valeur MQ4 + niveau ===
    const int xOffset = 28;
    const int yOffset = 24;
    int largeur = 72;
    int hauteur = 40;

    u8g2.drawFrame(xOffset, yOffset, largeur, hauteur);
    u8g2.setFont(u8g2_font_7x14_tr);

    // Ligne 1 : valeur brute
    char ligne1[20];
    snprintf(ligne1, sizeof(ligne1), "MQ4:%d", valeur);
    int w1 = u8g2.getStrWidth(ligne1);
    int x1 = xOffset + (largeur - w1) / 2;
    int y1 = yOffset + 16;

    // Ligne 2 : texte du niveau
    int w2 = u8g2.getStrWidth(etat);
    int x2 = xOffset + (largeur - w2) / 2;
    int y2 = yOffset + 32;

    u8g2.drawStr(x1, y1, ligne1);
    u8g2.drawStr(x2, y2, etat);
  } 
  else if (modeAffichage == 1) {
    // === Écran 2 : barre horizontale ===
    drawBatteryBar(valeur);
  } 
  else {
    // === Écran 3 : icône ASCII centrée ===
    const int xOffset = 28;
    const int yOffset = 24;
    int largeur = 72;
    int hauteur = 40;

    u8g2.drawFrame(xOffset, yOffset, largeur, hauteur);
    u8g2.setFont(u8g2_font_10x20_tr);

    // Choix du symbole ASCII selon le niveau
    const char* symbole;
    switch (niveau) {
      case 1: symbole = "OK";   break;
      case 2: symbole = ":)";   break;
      case 3: symbole = ":|";   break;
      case 4: symbole = "!!";   break;
      case 5: symbole = "!!!";  break;
    }

    // Centrage horizontal
    int w = u8g2.getStrWidth(symbole);
    int x = xOffset + (largeur - w) / 2;

    // Centrage vertical avec ascent/descent
    int ascent = u8g2.getAscent();
    int descent = u8g2.getDescent();
    int fontH = ascent - descent;
    int y = yOffset + (hauteur - fontH) / 2 + ascent;

    u8g2.drawStr(x, y, symbole);
  }

  u8g2.sendBuffer();
  delay(1000); // Pause entre deux mesures
}

📂 Ressources

  • PDF du datasheet MQ-4

https://components101.com/sites/default/files/component_datasheet/MQ-4%20Methane%20Gas%20Sensor%20Datasheet.pdf

Fichiers

gaz-detector.ino gaz-detector-w-comments.ino

Amélioration

  • Ajouter une alerte sonore, une connexion Wi-Fi pour des notifications, ou une interface web.