The Verdict: Which Sensor Combo Actually Works?
When designing an arduino fire detector, the most common mistake is relying on a single sensor type. Fire is a multi-stage event: it starts with heat, progresses to smoldering smoke, and finally erupts into open flame. No single cheap hobbyist sensor covers all three stages reliably.
Here is the decision path to select the right sensor for your specific hazard profile. Default Recommendation: For general-purpose room monitoring, use the dual-sensor combo (MQ-2 + KY-026) detailed in this guide.
| If your primary hazard is... | And you need to detect... | Then pick this exact sensor module |
|---|---|---|
| Smoldering electrical fires (PVC wire insulation) | Combustible gases and smoke particles | MQ-2 (SnO2 semiconductor with LM393 comparator) |
| Fast flash fires (paper, wood, solvents) | Infrared radiation (760nm - 1100nm) | KY-026 IR Flame Sensor (with LM393 comparator) |
| Ambient thermal runaway (battery packs, server racks) | Rapid ambient temperature rise | MAX6675 K-Type Thermocouple or DHT22 |
| General room safety (kitchen, workshop, garage) | Both smoke and open flame redundancy | Use BOTH MQ-2 and KY-026 (Proceed with this build) |
Parts List & Spec Sheet
This build targets the Arduino Uno R3 (ATmega328P). We use the Uno because its 5V logic and robust onboard voltage regulator can handle the MQ-2's heater current draw without browning out, unlike 3.3V boards (e.g., Arduino Nano 33 IoT or ESP32) which require external level shifting and separate 5V power rails for the MQ-2 heater.
| Component | Exact Variant / Model | Key Specification | Est. Cost (2026) |
|---|---|---|---|
| Microcontroller | Arduino Uno R3 (ATmega328P) | 5V logic, 10-bit ADC, 14 digital I/O | $24.00 |
| Smoke/Gas Sensor | MQ-2 Module (with LM393) | 5V VCC, ~150mA heater current, detects LPG, smoke, CO | $4.50 |
| Flame Sensor | KY-026 IR Flame Module | 3.3V-5V VCC, detects 760-1100nm IR, 60° detection angle | $2.00 |
| Audible Alarm | 5V Active Buzzer (KY-012) | Internal oscillator, requires only DC voltage to sound | $1.50 |
| Visual Alarm | 5mm Red LED + 220Ω Resistor | Standard indicator, 20mA forward current | $0.10 |
| Wiring | Male-to-Male / Male-to-Female Jumpers | 22 AWG stranded, pre-crimped | $5.00 |
Pin Mapping & Wiring Steps
The MQ-2 sensor module has four pins: VCC, GND, DO (Digital Out), and AO (Analog Out). We will use the Analog Out to read actual gas concentration levels. The KY-026 has a similar layout, but we will use its Digital Out (DO) pin, relying on the module's onboard LM393 comparator to act as a clean interrupt trigger.
| Component Pin | Arduino Uno R3 Pin | Wire Color (Suggested) | Notes |
|---|---|---|---|
| MQ-2 VCC | 5V | Red | Do NOT use 3.3V. The heater requires 5V ±0.2V. |
| MQ-2 GND | GND | Black | Share common ground with all modules. |
| MQ-2 AO | A0 | Blue | Analog input for smoke density reading. |
| KY-026 VCC | 5V | Red | Can run on 3.3V, but 5V matches Uno logic. |
| KY-026 GND | GND | Black | Share common ground. |
| KY-026 DO | D2 | Green | Digital trigger from LM393 comparator. |
| Buzzer (+) | D8 | Orange | Positive pin (usually marked with + or longer leg). |
| Buzzer (-) | GND | Black | Ground. |
| LED Anode (+) | D9 (via 220Ω) | Yellow | Resistor prevents drawing >20mA from GPIO. |
| LED Cathode (-) | GND | Black | Short leg / flat side of LED. |
Wiring Procedure
- Power Down: Ensure the Arduino is unplugged from USB before wiring.
- Route Power Rails: Connect the Arduino 5V and GND pins to the red and blue rails on your breadboard.
- Wire the MQ-2: Connect VCC to 5V, GND to GND, and the AO pin directly to A0. Leave the DO pin unconnected.
- Wire the KY-026: Connect VCC to 5V, GND to GND, and the DO pin to D2. Leave the AO pin unconnected.
- Wire the Outputs: Connect the active buzzer's positive leg to D8 and negative to GND. Connect the 220Ω resistor to D9, then to the LED anode, and the LED cathode to GND.
- Verify: Use a multimeter in continuity mode to ensure no 5V lines are shorted to GND before plugging in USB power.
Complete Compilable Code
This C++ code targets the Arduino Uno R3. It includes a mandatory 180-second preheat countdown for the MQ-2 sensor (the SnO2 layer requires heat to stabilize conductivity), software debouncing for the IR flame sensor, and serial error handling to catch disconnected or saturated sensors.
// Target Board: Arduino Uno R3 (ATmega328P)
// Project: Dual-Redundancy Arduino Fire Detector
// Author: ElectricalFlux
// --- PIN DEFINITIONS ---
const int PIN_MQ2_ANALOG = A0;
const int PIN_FLAME_DIGITAL = 2;
const int PIN_BUZZER = 8;
const int PIN_LED = 9;
// --- THRESHOLDS & TIMING ---
const int SMOKE_THRESHOLD = 450; // Adjust based on baseline (0-1023)
const unsigned long PREHEAT_TIME_MS = 180000; // 3 minutes for MQ-2 burn-in
const unsigned long DEBOUNCE_DELAY_MS = 50;
const unsigned long ALARM_DURATION_MS = 5000; // Alarm sounds for 5s per trigger
// --- STATE VARIABLES ---
unsigned long startTime;
bool preheatComplete = false;
unsigned long lastFlameTrigger = 0;
unsigned long alarmEndTime = 0;
void setup() {
Serial.begin(9600);
pinMode(PIN_FLAME_DIGITAL, INPUT);
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_BUZZER, LOW);
digitalWrite(PIN_LED, LOW);
startTime = millis();
Serial.println("SYS: Booting Arduino Fire Detector...");
Serial.println("SYS: MQ-2 Preheat sequence started (180s).");
}
void loop() {
unsigned long currentMillis = millis();
// 1. Handle MQ-2 Preheat Phase
if (!preheatComplete) {
if (currentMillis - startTime >= PREHEAT_TIME_MS) {
preheatComplete = true;
Serial.println("SYS: Preheat complete. Monitoring active.");
} else {
// Blink LED slowly during preheat
digitalWrite(PIN_LED, (currentMillis / 500) % 2);
return; // Skip sensor reads during preheat
}
}
// 2. Error Handling & Sensor Health Checks
int smokeLevel = analogRead(PIN_MQ2_ANALOG);
// Check for ADC saturation or disconnected sensor (floating pin)
if (smokeLevel >= 1020) {
Serial.println("ERR: ADC_SATURATION_1023. Check MQ-2 AO wiring.");
delay(1000);
return;
}
if (smokeLevel <= 5 && preheatComplete) {
// A perfectly clean room usually reads 20-100. 0-5 implies a short to GND.
Serial.println("ERR: MQ2_SHORT_TO_GND. Check wiring.");
}
// 3. Read Flame Sensor (Active LOW on most KY-026 modules)
bool flameDetected = (digitalRead(PIN_FLAME_DIGITAL) == LOW);
// Debounce flame sensor
if (flameDetected && (currentMillis - lastFlameTrigger > DEBOUNCE_DELAY_MS)) {
lastFlameTrigger = currentMillis;
triggerAlarm("FLAME");
}
// 4. Evaluate Smoke Levels
if (smokeLevel > SMOKE_THRESHOLD) {
triggerAlarm("SMOKE");
}
// 5. Manage Alarm State
if (currentMillis < alarmEndTime) {
digitalWrite(PIN_BUZZER, HIGH);
digitalWrite(PIN_LED, HIGH);
} else {
digitalWrite(PIN_BUZZER, LOW);
digitalWrite(PIN_LED, LOW);
}
// 6. Telemetry Output (every 2 seconds)
static unsigned long lastTelemetry = 0;
if (currentMillis - lastTelemetry >= 2000) {
lastTelemetry = currentMillis;
Serial.print("DATA: Smoke=");
Serial.print(smokeLevel);
Serial.print(" | Flame=");
Serial.println(flameDetected ? "YES" : "NO");
}
}
void triggerAlarm(const char* source) {
Serial.print("ALARM: ");
Serial.print(source);
Serial.println(" detected!");
alarmEndTime = millis() + ALARM_DURATION_MS;
}
Debugging: First Three Things to Check When It Fails
When your serial monitor throws an error or the system fails to trigger, follow this ranked troubleshooting path. These are the most common failure modes based on bench testing.
1. Error String: ERR: ADC_SATURATION_1023
Ranked Causes:
- Floating Analog Pin: The jumper wire between the MQ-2 AO pin and Arduino A0 is loose or broken. The internal pull-up or stray capacitance pulls the ADC to max value.
- Wired to 5V instead of AO: You accidentally connected the sensor's VCC pin to A0 instead of the AO pin.
- Dead Sensor Element: The internal SnO2 heater trace has burned out (rare, but happens if powered with >5.5V).
Fix: Disconnect the sensor. Use a multimeter to measure DC voltage between the MQ-2 AO pin and GND while the sensor is powered. It should read between 0.5V and 4.5V depending on air quality. If it reads 0V or 5V exactly, the module's LM393 comparator or voltage divider is faulty.
2. Symptom: Flame Sensor Never Triggers (Even with a Lighter)
Ranked Causes:
- Untuned Potentiometer: The blue 10k trim pot on the KY-026 module is set too high. The LM393 comparator requires the non-inverting input to cross the threshold set by the pot.
- IR LED Reversed: The IR photodiode on the sensor board is soldered backwards by the manufacturer (a common issue with cheap clones).
- Wrong Logic Expectation: Your code expects
HIGHfor a trigger, but the LM393 pulls the DO pinLOWwhen flame is detected.
Fix: Power the module. Point it away from heat sources. Use a small Phillips screwdriver to turn the blue pot counter-clockwise until the module's DO LED turns OFF. Then, strike a lighter 12 inches away; the LED should snap ON. If it doesn't, flip the photodiode polarity.
3. Symptom: Buzzer Clicks but Doesn't Sound / Arduino Resets
Ranked Causes:
- USB Current Limit: The MQ-2 heater draws ~150mA. The Arduino Uno linear regulator and USB bus draw another ~50mA. The buzzer draws ~30mA. If plugged into a 500mA USB 2.0 hub, the voltage sags, causing the ATmega328P brownout detector to reset the board.
- Passive vs. Active Buzzer: You are using a passive buzzer (requires a PWM square wave) but treating it like an active buzzer (applying DC voltage via
digitalWrite).
Fix: Plug the Arduino directly into a wall-mounted 5V/2A USB phone charger. Verify your buzzer is 'active' by touching its pins directly to 5V and GND; if it beeps continuously, it's active. If it just clicks once, it's passive and requires the tone() function.
Extending or Simplifying the Build
Once the baseline Arduino Uno fire detector is stable on your bench, you will likely want to adapt it for a specific environment. Here is how to scale the project up or down.
How to Simplify (For Kiosks or Headless Servers)
- Drop the Buzzer and LED: If this is running inside an enclosed 3D-printed box or a server rack where visual/audible alerts are useless, remove the D8 and D9 wiring.
- Switch to UART Telemetry Only: Modify the code to output strict CSV formatting over Serial (
timestamp,smoke_ppm,flame_bool). Connect the Arduino's TX/RX pins to a Raspberry Pi or a Linux router runningscreen /dev/ttyUSB0 9600to log the data directly to a text file or SQLite database.
How to Extend (For Active Mitigation & Remote Alerts)
- Add a 5V Relay Module for Exhaust Fans: Wire a 5V opto-isolated relay module to D10. When the
triggerAlarm()function fires, set D10 HIGH to close the relay contacts, triggering a 12V or 120V exhaust fan to pull smoke out of the room. Safety Note: Never switch mains voltage without proper enclosures and fusing. - Upgrade to ESP32 for MQTT WiFi Alerts: Migrate the code to an ESP32 DevKit V1. The MQ-2 still requires 5V, so you must power the ESP32 via its 5V VIN pin and use a voltage divider (e.g., 10kΩ and 5.6kΩ) on the MQ-2 analog output to step the 5V signal down to the ESP32's 3.3V ADC limit. Use the
PubSubClientlibrary to publish smoke levels to an MQTT broker like Mosquitto, triggering Home Assistant automations to send push notifications to your phone.






