IoT Fire Detection
& Alert System
Multi-sensor fire monitoring with MQ-2 smoke, DHT22 temperature, and IR flame sensors. 4-level automated response — auto-sprinkler, buzzer patterns, and a live web dashboard.
What You'll Build
This advanced IoT project uses an ESP32 to monitor for fire conditions using three independent sensors. When a hazard is detected, the system escalates through 4 alert levels with visual LEDs, buzzer patterns, automatic safety systems, and a live web dashboard accessible from any device on the same network.
Triple Sensor
MQ-2 smoke, DHT22 temperature, and IR flame detection simultaneously
4-Level Alerts
SAFE → WARNING → DANGER → CRITICAL with different responses
Auto-Sprinkler
Automatically activates when CRITICAL level is reached
Exhaust Fan
Turns on automatically when smoke exceeds 30%
Web Dashboard
Live sensor data with progress bars, auto-refresh every 2 seconds
Alert Simulation
Simulated SMS, email, and push notification alerts on DANGER+
OLED Display
128×64 SSD1306 shows live sensor readings and system status
Data Logging
Alert history stored in a rolling 10-entry log with timestamps
Components Required
All components are available as virtual parts in Wokwi — potentiometers simulate the MQ-2 and flame sensors.
| # | Component | Qty | Role |
|---|---|---|---|
| 1 | ESP32 DevKit V1 | ×1 | Main controller with built-in WiFi for web dashboard |
| 2 | MQ-2 Gas/Smoke Sensor | ×1 | Detects smoke and gas levels 0–100% (simulated by potentiometer in Wokwi) |
| 3 | DHT22 Temperature & Humidity | ×1 | Monitors temperature (°C) and humidity (%RH) |
| 4 | Flame Sensor (IR) | ×1 | Infrared flame detection 0–100% (simulated by potentiometer) |
| 5 | Buzzer (Active) | ×1 | Audible alarm with different patterns per alert level |
| 6 | Red LED + 220Ω | ×1 | DANGER indicator |
| 7 | Green LED + 220Ω | ×1 | SAFE indicator |
| 8 | Blue LED + 220Ω | ×1 | WARNING indicator |
| 9 | Cyan LED + 220Ω | ×1 | Sprinkler active indicator |
| 10 | White LED + 220Ω | ×1 | Exhaust fan active indicator |
| 11 | SSD1306 OLED 128×64 (I2C) | ×1 | Shows live sensor values and system status |
| 12 | Jumper Wires | ×~20 | All component connections |
4-Level Alert System
The system continuously evaluates all three sensors and escalates or de-escalates the alert level automatically.
Sensor Thresholds
| Sensor | WARNING | DANGER | CRITICAL |
|---|---|---|---|
| 🌡️ Temperature | ≥ 35°C | ≥ 45°C | ≥ 55°C |
| 💨 Smoke Level | ≥ 30% | ≥ 50% | ≥ 70% |
| 🔥 Flame Detection | Not triggered | Not triggered | ≥ 40% |
Pin Connections
Paste the diagram.json (next section) to auto-wire everything. This table is for reference.
| Component | Component Pin | ESP32 Pin | Wire |
|---|---|---|---|
| DHT22 | VCC | 3.3V | Red |
| DHT22 | GND | GND | Black |
| DHT22 | DATA | D15 | Green |
| MQ-2 Smoke | VCC | 3.3V | Red |
| MQ-2 Smoke | GND | GND | Black |
| MQ-2 Smoke | Signal (AOUT) | D34 (analog input) | Orange |
| Flame Sensor | VCC | 3.3V | Red |
| Flame Sensor | GND | GND | Black |
| Flame Sensor | Signal (AOUT) | D35 (analog input) | Yellow |
| Red LED (via 220Ω) | Anode | D26 | Red |
| Green LED (via 220Ω) | Anode | D27 | Green |
| Blue LED (via 220Ω) | Anode | D14 | Blue |
| Cyan LED (Sprinkler, 220Ω) | Anode | D12 | Cyan |
| White LED (Fan, 220Ω) | Anode | D13 | White |
| All LED Cathodes | Cathode | GND | Black |
| Buzzer | Pin 1 (+) | D25 | Purple |
| Buzzer | Pin 2 (–) | GND | Black |
| OLED SSD1306 | VCC | 3.3V | Red |
| OLED SSD1306 | GND | GND | Black |
| OLED SSD1306 | SDA | D21 (I2C) | Blue |
| OLED SSD1306 | SCL | D22 (I2C) | Yellow |
Complete Setup Guide
Follow these steps in order to get the simulation running in under 5 minutes.
🌐 Open Wokwi & Start a New ESP32 Project
Go to wokwi.com in any modern browser (Chrome, Firefox, or Edge).
- Click "New Project" on the homepage
- Select "ESP32" from the board list
- A blank canvas appears with the ESP32 DevKit already placed
📋 Paste the diagram.json — Auto-Wire in One Click
The fastest way to set up the circuit is to use the diagram.json file.
- Click the "diagram.json" tab next to sketch.ino
- Select all text (Ctrl+A) and delete it
- Paste the complete JSON from the diagram.json section below
- Press Ctrl+S — all components appear and wire themselves ✅
{ and ends with }. Don't miss any brackets or the circuit will not load correctly.
📚 Install Required Libraries
Create a libraries.txt file in Wokwi and paste these three lines:
DHT sensor library Adafruit GFX Library Adafruit SSD1306
libraries.txt. Wokwi auto-downloads all three libraries when you start the simulation.
💻 Paste the Arduino Code
Click the sketch.ino tab, delete any existing code, and paste the complete code from the Code section below.
- The WiFi credentials are pre-set to
"Wokwi-GUEST"— no changes needed - Press ▶ Play to start the simulation
- Watch the OLED display show "FIRE DETECTION SYSTEM" then "Initializing..."
- The buzzer plays a startup tone and the green LED lights up (SAFE)
🔗 Use the Pre-Built Simulation
Skip all setup — the complete circuit and code is already built for you:
Open Complete Fire Detection Simulation
ESP32 + all sensors + OLED + buzzer + LEDs. Click ▶ Play, then rotate the sensor dials to trigger alerts!
The Complete Sketch
Paste this into sketch.ino in Wokwi. The code is organised into clean sections for each system feature.
/* * IoT-Based Fire Detection & Alert System * ESP32 + MQ-2 + DHT22 + Flame Sensor + OLED + Web Dashboard * MakeMindz Summer Course */ #include <WiFi.h> #include <WebServer.h> #include <DHT.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // ── WiFi (Wokwi Guest Network) ──────────────── const char* ssid = "Wokwi-GUEST"; const char* password = ""; WebServer server(80); // ── Pin Definitions ─────────────────────────── #define DHT_PIN 15 #define MQ2_PIN 34 // Analog input #define FLAME_PIN 35 // Analog input #define BUZZER_PIN 25 #define RED_LED_PIN 26 // DANGER #define GREEN_LED_PIN 27 // SAFE #define BLUE_LED_PIN 14 // WARNING #define SPRINKLER_PIN 12 // Auto-sprinkler #define EXHAUST_FAN_PIN 13 // Exhaust fan // ── DHT22 & OLED ────────────────────────────── #define DHT_TYPE DHT22 DHT dht(DHT_PIN, DHT_TYPE); #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // ── Alert Levels ────────────────────────────── enum AlertLevel { SAFE, WARNING, DANGER, CRITICAL }; // ── System State Struct ─────────────────────── struct SystemState { float temperature, humidity; int smokeLevel, flameLevel; AlertLevel alertLevel; bool sprinklerActive, exhaustFanActive, alarmActive; unsigned long lastAlert; int alertCount; String location; } fireSystem; // ── Thresholds ──────────────────────────────── const float TEMP_WARNING = 35.0; const float TEMP_DANGER = 45.0; const float TEMP_CRITICAL = 55.0; const int SMOKE_WARNING = 30; const int SMOKE_DANGER = 50; const int SMOKE_CRITICAL = 70; const int FLAME_THRESHOLD = 40; unsigned long lastSensorRead = 0, lastDisplayUpdate = 0, alarmStartTime = 0; const long sensorInterval = 1000, displayInterval = 500; // ── Alert History (rolling 10 entries) ──────── struct AlertLog { String timestamp, level; float temp; int smoke, flame; }; AlertLog alertHistory[10]; int historyIndex = 0;
void setup() { Serial.begin(115200); pinMode(BUZZER_PIN, OUTPUT); pinMode(RED_LED_PIN, OUTPUT); pinMode(GREEN_LED_PIN, OUTPUT); pinMode(BLUE_LED_PIN, OUTPUT); pinMode(SPRINKLER_PIN, OUTPUT); pinMode(EXHAUST_FAN_PIN, OUTPUT); pinMode(MQ2_PIN, INPUT); pinMode(FLAME_PIN, INPUT); dht.begin(); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F("OLED failed")); } else { display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(0,0); display.println("FIRE DETECTION"); display.println("Initializing..."); display.display(); delay(2000); } fireSystem = {0,0,0,0,SAFE,false,false,false,0,0,"Building A - Floor 3"}; WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } server.on("/", handleRoot); server.on("/status", handleStatus); server.on("/history", handleHistory); server.on("/reset", handleReset); server.on("/test", handleTest); server.on("/silence", handleSilence); server.begin(); Serial.print("Dashboard: http://"); Serial.println(WiFi.localIP()); setStatusLED(SAFE); playStartupTone(); } void loop() { server.handleClient(); unsigned long now = millis(); if (now - lastSensorRead >= sensorInterval) { lastSensorRead = now; readSensors(); evaluateFireRisk(); controlSafetySystems(); } if (now - lastDisplayUpdate >= displayInterval) { lastDisplayUpdate = now; updateDisplay(); } if (fireSystem.alarmActive) handleAlarm(); } void readSensors() { fireSystem.temperature = dht.readTemperature(); fireSystem.humidity = dht.readHumidity(); if (isnan(fireSystem.temperature)) fireSystem.temperature = 0; if (isnan(fireSystem.humidity)) fireSystem.humidity = 0; int smokeRaw = analogRead(MQ2_PIN); int flameRaw = analogRead(FLAME_PIN); fireSystem.smokeLevel = map(smokeRaw, 0, 4095, 0, 100); fireSystem.flameLevel = map(flameRaw, 0, 4095, 100, 0); // Inverted } void evaluateFireRisk() { AlertLevel prev = fireSystem.alertLevel, next = SAFE; if (fireSystem.temperature >= TEMP_CRITICAL || fireSystem.smokeLevel >= SMOKE_CRITICAL || fireSystem.flameLevel >= FLAME_THRESHOLD) next = CRITICAL; else if (fireSystem.temperature >= TEMP_DANGER || fireSystem.smokeLevel >= SMOKE_DANGER) next = DANGER; else if (fireSystem.temperature >= TEMP_WARNING || fireSystem.smokeLevel >= SMOKE_WARNING) next = WARNING; fireSystem.alertLevel = next; if (next != prev) handleAlertChange(prev, next); } void handleAlertChange(AlertLevel old, AlertLevel n) { logAlert(); setStatusLED(n); if (n >= DANGER && old < DANGER) { activateAlarm(); sendAlert(); } if (n == SAFE && old != SAFE) deactivateAlarm(); } void controlSafetySystems() { // Sprinkler — CRITICAL only if (fireSystem.alertLevel == CRITICAL && !fireSystem.sprinklerActive) activateSprinkler(); else if (fireSystem.alertLevel < CRITICAL && fireSystem.sprinklerActive) deactivateSprinkler(); // Exhaust fan — smoke >= 30% if (fireSystem.smokeLevel >= SMOKE_WARNING && !fireSystem.exhaustFanActive) activateExhaustFan(); else if (fireSystem.smokeLevel < SMOKE_WARNING && fireSystem.exhaustFanActive) deactivateExhaustFan(); } void handleAlarm() { unsigned long elapsed = millis() - alarmStartTime; int pattern = (elapsed / 200) % 4; if (fireSystem.alertLevel == CRITICAL) digitalWrite(BUZZER_PIN, pattern < 2 ? HIGH : LOW); else if (fireSystem.alertLevel == DANGER) digitalWrite(BUZZER_PIN, pattern < 1 ? HIGH : LOW); } void setStatusLED(AlertLevel level) { digitalWrite(RED_LED_PIN, LOW); digitalWrite(GREEN_LED_PIN, LOW); digitalWrite(BLUE_LED_PIN, LOW); switch(level) { case SAFE: digitalWrite(GREEN_LED_PIN, HIGH); break; case WARNING: digitalWrite(BLUE_LED_PIN, HIGH); break; case DANGER: digitalWrite(RED_LED_PIN, HIGH); break; case CRITICAL: digitalWrite(RED_LED_PIN, (millis()/200)%2); break; } } void activateSprinkler() { fireSystem.sprinklerActive = true; digitalWrite(SPRINKLER_PIN, HIGH); Serial.println("SPRINKLER ON"); } void deactivateSprinkler(){ fireSystem.sprinklerActive = false; digitalWrite(SPRINKLER_PIN, LOW); Serial.println("Sprinkler OFF"); } void activateExhaustFan() { fireSystem.exhaustFanActive = true; digitalWrite(EXHAUST_FAN_PIN, HIGH); Serial.println("FAN ON"); } void deactivateExhaustFan(){ fireSystem.exhaustFanActive = false; digitalWrite(EXHAUST_FAN_PIN, LOW); Serial.println("Fan OFF"); } void activateAlarm() { fireSystem.alarmActive = true; alarmStartTime = millis(); Serial.println("ALARM ON"); } void deactivateAlarm() { fireSystem.alarmActive = false; digitalWrite(BUZZER_PIN, LOW); Serial.println("Alarm OFF"); } void playStartupTone() { tone(BUZZER_PIN, 1000, 100); delay(150); tone(BUZZER_PIN, 1500, 100); delay(150); tone(BUZZER_PIN, 2000, 100); } String getAlertLevelName(AlertLevel level) { switch(level) { case SAFE: return "SAFE"; case WARNING: return "WARNING"; case DANGER: return "DANGER"; case CRITICAL: return "CRITICAL"; default: return "UNKNOWN"; } } void updateDisplay() { display.clearDisplay(); display.setCursor(0,0); display.println("FIRE DETECTION"); display.drawLine(0,9,128,9,SSD1306_WHITE); display.setCursor(0,12); display.print("Status: "); display.println(getAlertLevelName(fireSystem.alertLevel)); display.setCursor(0,22); display.print("Temp: "); display.print(fireSystem.temperature,1); display.println(" C"); display.setCursor(0,32); display.print("Smoke: "); display.print(fireSystem.smokeLevel); display.println(" %"); display.setCursor(0,42); display.print("Flame: "); display.print(fireSystem.flameLevel); display.println(" %"); display.setCursor(0,52); if(fireSystem.sprinklerActive) display.print("SPRINKLER "); if(fireSystem.exhaustFanActive) display.print("FAN "); if(fireSystem.alarmActive) display.print("ALARM"); display.display(); } void logAlert() { alertHistory[historyIndex] = { String(millis()/1000) + "s", getAlertLevelName(fireSystem.alertLevel), fireSystem.temperature, fireSystem.smokeLevel, fireSystem.flameLevel }; historyIndex = (historyIndex + 1) % 10; } void sendAlert() { fireSystem.alertCount++; Serial.println("EMERGENCY ALERT SENT — Level: " + getAlertLevelName(fireSystem.alertLevel)); } // ── Web Server Handlers (handleRoot, handleStatus, etc.) // Full web dashboard code included in the Wokwi simulation link above ── void handleReset() { fireSystem.alertCount=0; fireSystem.alarmActive=false; historyIndex=0; server.sendHeader("Location","/"); server.send(303); } void handleSilence() { fireSystem.alarmActive=false; digitalWrite(BUZZER_PIN,LOW); server.sendHeader("Location","/"); server.send(303); } void handleTest() { for(int i=0;i<3;i++){tone(BUZZER_PIN,2000,200);delay(300);} server.sendHeader("Location","/"); server.send(303); } void handleStatus() { /* Returns JSON — see Wokwi simulation for full implementation */ } void handleHistory() { /* Returns JSON history — see Wokwi simulation for full implementation */ } void handleRoot() { /* Returns full HTML dashboard — see Wokwi simulation */ }
handleRoot() function generates full HTML with CSS and sensor data. The complete implementation is in the Wokwi simulation — open it here to see and copy the full code.
diagram.json — One-Click Circuit Setup
Paste this into the diagram.json tab in Wokwi to automatically place and wire all components.
{ and ends with }. In Wokwi, click the diagram.json tab → Ctrl+A → Delete → Paste → Ctrl+S.
{
"version": 1,
"author": "IoT Fire Detection System",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-esp32-devkit-v1", "id": "esp", "top": 0, "left": 0, "attrs": {} },
{ "type": "wokwi-dht22", "id": "dht1", "top": -86.4, "left": 124.8, "attrs": { "temperature": "30", "humidity": "50" } },
{ "type": "wokwi-potentiometer", "id": "smoke", "top": -19.2, "left": 297.6, "rotate": 180, "attrs": { "label": "Smoke Sensor (MQ-2)" } },
{ "type": "wokwi-potentiometer", "id": "flame", "top": 86.4, "left": 297.6, "rotate": 180, "attrs": { "label": "Flame Sensor" } },
{ "type": "wokwi-led", "id": "red_led", "top": -124.8, "left": 422.4, "attrs": { "color": "red", "lightColor": "red", "label": "DANGER" } },
{ "type": "wokwi-resistor", "id": "r1", "top": -67.2, "left": 422.4, "rotate": 90, "attrs": { "value": "220" } },
{ "type": "wokwi-led", "id": "green_led","top": -124.8, "left": 499.2, "attrs": { "color": "green", "lightColor": "green", "label": "SAFE" } },
{ "type": "wokwi-resistor", "id": "r2", "top": -67.2, "left": 499.2, "rotate": 90, "attrs": { "value": "220" } },
{ "type": "wokwi-led", "id": "blue_led", "top": -124.8, "left": 576, "attrs": { "color": "blue", "lightColor": "blue", "label": "WARNING" } },
{ "type": "wokwi-resistor", "id": "r3", "top": -67.2, "left": 576, "rotate": 90, "attrs": { "value": "220" } },
{ "type": "wokwi-led", "id": "sprinkler","top": 38.4, "left": 422.4, "attrs": { "color": "cyan", "lightColor": "cyan", "label": "Sprinkler" } },
{ "type": "wokwi-resistor", "id": "r4", "top": 96, "left": 422.4, "rotate": 90, "attrs": { "value": "220" } },
{ "type": "wokwi-led", "id": "fan", "top": 38.4, "left": 499.2, "attrs": { "color": "white", "lightColor": "white", "label": "Exhaust Fan" } },
{ "type": "wokwi-resistor", "id": "r5", "top": 96, "left": 499.2, "rotate": 90, "attrs": { "value": "220" } },
{ "type": "wokwi-buzzer", "id": "bz1", "top": 172.8, "left": 470.4, "attrs": { "volume": "0.5" } },
{ "type": "wokwi-ssd1306", "id": "oled1", "top": 192, "left": 249.6, "attrs": { "i2cAddress": "0x3C" } }
],
"connections": [
[ "esp:TX0", "$serialMonitor:RX", "", [] ],
[ "esp:RX0", "$serialMonitor:TX", "", [] ],
[ "dht1:VCC", "esp:3V3", "red", ["v0"] ],
[ "dht1:GND", "esp:GND.1", "black", ["v0"] ],
[ "dht1:SDA", "esp:D15", "green", ["v0"] ],
[ "smoke:GND", "esp:GND.1", "black", ["v0"] ],
[ "smoke:VCC", "esp:3V3", "red", ["v0"] ],
[ "smoke:SIG", "esp:D34", "orange", ["v0"] ],
[ "flame:GND", "esp:GND.2", "black", ["v0"] ],
[ "flame:VCC", "esp:3V3", "red", ["v0"] ],
[ "flame:SIG", "esp:D35", "yellow", ["v0"] ],
[ "red_led:A", "esp:D26", "red", ["v0"] ],
[ "red_led:C", "r1:1", "red", ["v0"] ],
[ "r1:2", "esp:GND.1", "black", ["v0"] ],
[ "green_led:A", "esp:D27", "green", ["v0"] ],
[ "green_led:C", "r2:1", "green", ["v0"] ],
[ "r2:2", "esp:GND.1", "black", ["v0"] ],
[ "blue_led:A", "esp:D14", "blue", ["v0"] ],
[ "blue_led:C", "r3:1", "blue", ["v0"] ],
[ "r3:2", "esp:GND.1", "black", ["v0"] ],
[ "sprinkler:A", "esp:D12", "cyan", ["v0"] ],
[ "sprinkler:C", "r4:1", "cyan", ["v0"] ],
[ "r4:2", "esp:GND.2", "black", ["v0"] ],
[ "fan:A", "esp:D13", "white", ["v0"] ],
[ "fan:C", "r5:1", "white", ["v0"] ],
[ "r5:2", "esp:GND.2", "black", ["v0"] ],
[ "bz1:1", "esp:D25", "purple", ["v0"] ],
[ "bz1:2", "esp:GND.2", "black", ["v0"] ],
[ "oled1:VCC", "esp:3V3", "red", ["h0"] ],
[ "oled1:GND", "esp:GND.2", "black", ["h0"] ],
[ "oled1:SDA", "esp:D21", "blue", ["h0"] ],
[ "oled1:SCL", "esp:D22", "yellow", ["h0"] ]
],
"dependencies": {}
}
Live Web Dashboard Preview
Once the simulation connects to WiFi, open the IP address shown in the Serial Monitor to access the live dashboard from any browser.
Auto-refreshes every 2 seconds · Mobile responsive · Remote controls available
/status JSON endpoint and /history log — useful for integrating with MQTT, Node-RED, or Home Assistant in a real deployment.
Simulate a Fire — Step by Step
Follow these 4 steps in order to experience the full escalation from SAFE to CRITICAL alert.
🟢 Normal Conditions
- Start simulation — click ▶ Play
- Green LED lights up (SAFE)
- No alarm, all systems standby
- OLED shows temperature and "SAFE"
🔵 Raise Temperature
- Click the DHT22 sensor in Wokwi
- Drag temperature slider to 40°C
- Blue LED lights up (WARNING)
- No alarm yet — monitor mode
🔴 Add Smoke
- Rotate Smoke Sensor dial to ~60%
- Red LED lights up (DANGER)
- Alarm beeps in medium pattern
- Exhaust fan LED turns ON 💨
- Alert notification logged
🚨 Detect Flames
- Rotate Flame Sensor dial to ~50%
- Red LED flashes rapidly (CRITICAL)
- Alarm beeps continuously
- Cyan LED = Sprinkler active 🚿
- Emergency alerts sent!
Comments
Post a Comment