Table of Contents

ESP32 Air Quality

Project Description

This project is an air quality monitoring system built using an ESP32 microcontroller, an MQ-135 gas sensor, and a buzzer for audible alerts. The main goal of the system is to continuously monitor the air quality, detect harmful gas levels (such as NH3, NOx, benzene, CO2, and smoke), and:

System Architecture

The following schematic illustrates the core components and their connections in the air quality monitoring system:

This schematic includes:

Components Used

Hardware Specifications

ESP32 Development Board

Description: The ESP32 is a low-cost, low-power microcontroller with integrated Wi-Fi and Bluetooth. It is ideal for IoT projects due to its wireless capabilities and sufficient computing power.

Key Features:

Use in Project:

Important Pins Used:

MQ-135 Gas Sensor

Description: The MQ-135 is a chemical gas sensor capable of detecting a wide range of gases, including ammonia, nitrogen oxides, benzene, smoke, and carbon dioxide. It is commonly used in air quality monitoring.

Key Features:

Use in Project: Provides an analog voltage proportional to air pollution levels. Connected to the ESP32’s analog input (GPIO34) through a voltage divider or level shifter, since it outputs 5V and ESP32 is 3.3V-tolerant.

Pinout:

Pin Function Description
VCC Power Input Connect to 5V
GND Ground Connect to GND
AOUT Analog Output Analog signal to ESP32 (via voltage divider)
DOUT Digital Output Not used in this project

Active Buzzer Module

Description: An active buzzer is a simple sound-emitting component that generates a tone when voltage is applied. Unlike passive buzzers, it does not require PWM control — just a HIGH/LOW signal.

Key Features:

Use in Project:

Pinout:

Pin Function Description
+ VCC Connect to 3.3V or 5V
- GND Connect to Ground
SIG Signal Input Connect to ESP32 digital pin (e.g., GPIO25)

Voltage Divider Resistors

Description:

Use in Project:

Breadboard and Jumper Wires

Description:

Use in Project:

Power Supply

Description:

Use in Project:

How It Works

Software Description

The Air Quality is a web application created to monitor and display air quality data in real time. It retrieves sensor readings such as PPM values from an air quality sensor—and presents them through a clean, user-friendly interface. The application is designed for development and educational use, offering a simple way to test, view, and analyze environmental data either locally or through connection with cloud-based platforms. Its structure is modular and flexible, making it easy to adapt to different use cases and hardware setups.

Code Snippet

This part connects to Wi-Fi and initializes Firebase for anonymous sign-in and Realtime Database communication.

#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"

#define WIFI_SSID "********"
#define WIFI_PASSWORD "**********"
#define API_KEY "********"
#define DATABASE_URL "**********"

FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;

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

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(300);
  }

  config.api_key = API_KEY;
  config.database_url = DATABASE_URL;

  if (Firebase.signUp(&config, &auth, "", "")) {
    Serial.println("Firebase signUp succeeded");
  }

  config.token_status_callback = tokenStatusCallback;
  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
}

Reads the analog value from the MQ-135 sensor, calculates Rs, and then converts that to a PPM (parts per million) estimate using a logarithmic formula.

#define MQ135_PIN 34
#define RZERO 116404.0
#define RL_VALUE 10000.0
#define PARA 116.6020682
#define PARB -2.769034857

void loop() {
  int adcValue = analogRead(MQ135_PIN);
  float sensor_voltage = adcValue * (3.3 / 4095.0);
  float rs = (3.3 - sensor_voltage) * RL_VALUE / sensor_voltage;
  float ratio = rs / RZERO;
  float ppm = PARA * pow(ratio, PARB);
}

Activates a buzzer if the air quality degrades beyond a certain threshold (800 PPM in this case).

#define BUZZER_PIN 25

void setup() {
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, HIGH); // buzzer off
}

void loop() {
  // ...
  if (ppm > 800) {
    digitalWrite(BUZZER_PIN, LOW); // buzzer on
  } else {
    digitalWrite(BUZZER_PIN, HIGH); // buzzer off
  }
}

Uploads the latest calculated PPM value to Firebase Realtime Database under the path /air_quality/ppm.

if (Firebase.RTDB.setFloat(&fbdo, "/air_quality/ppm", ppm)) {
  Serial.println("Data sent to Firebase");
} else {
  Serial.print("Failed to send data: ");
  Serial.println(fbdo.errorReason());
}

}

Web Application

References