ESP32 Gas Detection Alarm with MQ-135 & DFPlayer Mini (PCB Project)

This project demonstrates a simple yet effective gas detection alarm system built using an ESP32 microcontroller. The system uses the MQ-135 gas sensor to detect harmful gases in the environment and responds instantly when a certain threshold is reached.

When gas is detected, the ESP32 triggers a DFPlayer Mini module to play a police siren sound through a speaker, while an OLED display shows the system status in real time. Everything is assembled on a custom PCB board, making the project compact and reliable.

This project is perfect for learning about sensor-based automation, embedded systems, and real-time monitoring.

Components Used

PCB Board – Custom board used to mount and connect all components

ESP32 – Main microcontroller that processes sensor data and controls the system

MQ-135 Gas Sensor – Detects harmful gases in the air

DFPlayer Mini Module – Plays the alarm (police siren sound)

3 Ohm Speaker – Outputs the alarm sound

OLED Display (SSD1306) – Displays system status such as “GAS DETEC” or “NO GAS”

Gas Detection (Alarm Triggered)

When the MQ-135 sensor detects gas above the defined threshold:

  • The OLED display shows “GAS DETEC”
  • The DFPlayer Mini plays a police siren sound
  • The system continuously monitors the environment while alerting the user

No Gas Detected (Normal State)

When no gas is detected:

  • The OLED display shows “NO GAS”
  • No sound is played
  • The system remains in standby mode, continuously checking for gas presence

Arduino Code

#include <Wire.h> // Include the I2C communication library
#include <Adafruit_GFX.h> // Include the Adafruit GFX library for graphics functions
#include <Adafruit_SSD1306.h> // Include the Adafruit SSD1306 library for the OLED display
#include "Arduino.h" // Include the core Arduino library
#include "DFRobotDFPlayerMini.h" // Include the DFRobot DFPlayer Mini library

#ifdef ESP32
  #define FPSerial Serial1  // For ESP32, use hardware serial port 1
#else
  #include <SoftwareSerial.h> // Include SoftwareSerial library for non-ESP32 boards
  SoftwareSerial FPSerial(19, 18); // Define SoftwareSerial on pins 19 (RX) and 18 (TX)
#endif

DFRobotDFPlayerMini myDFPlayer; // Create an instance of the DFRobotDFPlayerMini class

// OLED display configuration
#define SCREEN_WIDTH 128 // Define the OLED display width in pixels
#define SCREEN_HEIGHT 64 // Define the OLED display height in pixels
#define OLED_RESET -1 // Define the reset pin for the OLED display (-1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT); // Create an instance of the display object

// Digtial pin for sensor input
#define mQ135 32 // Define the digital  pin for sensor input

// Timing variables
unsigned long previousMillis = 0; // Store the last time the DFPlayer was checked
const long interval = 4400; // Interval to wait for song playback in milliseconds
bool isPlaying = false; // Boolean to track if the DFPlayer is currently playing

void setup() {
  pinMode(mQ135, INPUT);
 #ifdef ESP32
  FPSerial.begin(9600, SERIAL_8N1, 19, 18); // Start serial communication for ESP32 with 9600 baud rate, 8 data bits, no parity, and 1 stop bit
#else
  FPSerial.begin(9600); // Start serial communication for other boards with 9600 baud rate
#endif

  Serial.begin(115200); // Start the Serial monitor communication with 115200 baud rate

  Serial.println(F("DFRobot DFPlayer Mini Demo")); // Print a demo start message
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)")); // Print initialization message
  
  if (!myDFPlayer.begin(FPSerial)) { // Initialize the DFPlayer Mini with the defined serial interface
    Serial.println(F("Unable to begin:")); // If initialization fails, print an error message
    Serial.println(F("1.Please recheck the connection!")); // Suggest rechecking the connection
    Serial.println(F("2.Please insert the SD card!")); // Suggest checking for an inserted SD card
    while(true); // Stay in an infinite loop if initialization fails
  }
  Serial.println(F("DFPlayer Mini online.")); // Print a success message if initialization succeeds
  
  myDFPlayer.volume(30);  // Set the DFPlayer Mini volume to 30 (max is 30)
  myDFPlayer.play(1);  // Start playing the first track on the SD card
  // Initialize OLED display
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Check if the display initializes correctly with I2C address 0x3C
    Serial.println(F("SSD1306 allocation failed")); // Print error message if initialization fails
    while (true); // Stay in an infinite loop if initialization fails
  }
  
  display.clearDisplay(); // Clear the display buffer
  display.setTextSize(2); // Set text size to 2
  display.setTextColor(SSD1306_WHITE); // Set text color to white
  display.setCursor(0, 10); // Set cursor position at (0, 10)
  display.println(F("Initializing...")); // Print "Initializing..." on the display
  display.display(); // Update the display with the above settings
  delay(2000); // Wait for 2 seconds
}

void loop() {
  unsigned long currentMillis = millis(); // Get the current time in milliseconds

  // Read the input on digital  GPIO  32
  int mQ135State = digitalRead(mQ135); // Read the digital sensor value from pin 32

  // Update OLED display based on sensor value
  display.clearDisplay(); // Clear the display buffer
  display.setTextSize(2); // Set text size to 2
  
  if (mQ135State == 0) { // Check if sensor value is greater than 500
    // If sensor value is greater than 500, display "Cough"
    int16_t x1, y1; // Variables to store text bounds
    uint16_t w, h; // Variables to store text width and height
    display.getTextBounds("GAS DETEC", 0, 0, &x1, &y1, &w, &h); // Get the bounds of the text "Cough"
    display.setCursor((SCREEN_WIDTH - w) / 2, (SCREEN_HEIGHT - h) / 2); // Center the text on the display
    display.println(F("GAS DETEC")); // Print "Cough" on the display
    
    if (!isPlaying) { // Check if the DFPlayer is not already playing
      // Play sound if not already playing
      myDFPlayer.play(1); // Play the first track on the DFPlayer
      isPlaying = true; // Set isPlaying to true
      previousMillis = currentMillis; // Update the previousMillis with the current time
    }
  } else { // If sensor value is less than or equal to 500
    // If sensor value is less than or equal to 500, display "No cough"
    int16_t x1, y1; // Variables to store text bounds
    uint16_t w, h; // Variables to store text width and height
    display.getTextBounds("NO GAS", 0, 0, &x1, &y1, &w, &h); // Get the bounds of the text "No cough"
    display.setCursor((SCREEN_WIDTH - w) / 2, (SCREEN_HEIGHT - h) / 2); // Center the text on the display
    display.println(F("NO GAS")); // Print "No cough" on the display
    isPlaying = false; // Reset isPlaying to false if no cough is detected
  }

  // Reset the playing status after the song has finished playing
  if (isPlaying && currentMillis - previousMillis >= interval) { // Check if the song playback interval has passed
    isPlaying = false; // Reset isPlaying to false
  }

  display.display(); // Update the display with the above settings
  delay(100); // Short delay to avoid rapid updates
}

Conclusion & Applications

This ESP32-based gas detection system is a practical and low-cost solution for monitoring air quality and detecting harmful gases in real time. By combining a gas sensor, sound alert system, and display feedback, it provides both visual and audio warnings.

Applications:

  • Home gas leak detection
  • Industrial safety systems
  • Laboratories and workshops
  • Smart home automation projects
  • Educational and STEM learning projects

Overall, this project is a great example of how simple electronic components can be integrated to create a useful and life-saving system.

Leave a Reply