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:
The following schematic illustrates the core components and their connections in the air quality monitoring system:
This schematic includes:
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:
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.
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()); }
}