If you are building a flame detector Arduino project, the direct answer for a basic prototyping sensor is the KY-026 IR Flame Sensor module. It detects infrared light in the 760nm to 1100nm wavelength emitted by fire. However, because sunlight and incandescent bulbs also blast this exact IR spectrum, the KY-026 will false-trigger outdoors or near 60W lamps. For a reliable indoor node, you must pair it with software filtering and hysteresis. For life-safety or outdoor deployment, you must upgrade to a UV-specific sensor like the GUVA-S12SD.
The Verdict: Which Flame Sensor Module to Buy
Not all flame sensors are created equal. The right choice depends entirely on your deployment environment and the heat source you are tracking. Use this decision path to select your hardware.
| Use Case | Sensor Type | Specific Module | Wavelength | Est. Cost |
|---|---|---|---|---|
| School project, candle/lighter detection indoors | IR Phototransistor | KY-026 (with LM393) | 760nm - 1100nm | $2.00 |
| Room fire detection, immune to sunlight/incandescent | UV Photodiode | GUVA-S12SD Module | 240nm - 320nm | $12.00 |
| Industrial hotspot mapping, smoldering fires | Thermal Array | MLX90640 (I2C) | Far-IR (Heat) | $45.00 |
Default Pick for this Guide: We are using the KY-026. It is the most common, cheapest, and easiest to wire for beginners. If your project requires ignoring ambient sunlight, terminate this path and buy the GUVA-S12SD instead.
Parts List & Spec Sheet
This build targets the Arduino Nano V3 (ATmega328P, USB-C variant). The Nano is chosen over the Uno for its compact breadboard footprint, making it ideal for taping inside a project enclosure. The CH340G USB-C variant is recommended over the older Mini-USB FTDI boards for modern cable compatibility and reliable driver support on Windows 11 and macOS.
- Microcontroller: Arduino Nano V3 (ATmega328P, CH340G USB-C) — $6.00
- Sensor: KY-026 Flame Sensor Module (includes LM393 comparator & potentiometer) — $2.00
- Alert: 5V Active Buzzer (KY-012 or generic 5V piezo with internal oscillator) — $1.50
- Power/Logic: 10kΩ resistor (for optional digital pin pull-up if bypassing LM393) — $0.10
- Wiring: 22 AWG solid core jumper wires, half-size solderless breadboard — $5.00
Pin Mapping & Wiring Steps
The KY-026 has four pins: GND, VCC, DO (Digital Output), and AO (Analog Output). We will use the Analog Output to read the actual intensity of the flame, allowing our code to filter out noise. The Digital Output is tied to the onboard LM393 comparator and is less useful for software filtering.
| KY-026 Pin | Arduino Nano Pin | Wire Color | Notes |
|---|---|---|---|
| VCC | 5V | Red | Do not use 3.3V; the LM393 needs 5V for full swing. |
| GND | GND | Black | Ensure common ground with the buzzer. |
| AO | A0 | Blue | Analog input for raw IR intensity reading. |
| DO | D2 | Green | Optional: Used for hardware interrupt fallback. |
Buzzer Wiring: Connect the Buzzer VCC (Red) to Nano Pin D8, and Buzzer GND (Black) to Nano GND. Ensure you are using an active buzzer (which has an internal oscillator). If you use a passive buzzer, it will only click faintly unless you write a PWM tone-generation loop.
Compilable Arduino Code with Hysteresis
Cheap IR sensors suffer from 120Hz ripple caused by the flicker of AC-powered indoor lighting. If you just use a simple if (val < threshold) statement, your buzzer will chatter rapidly. The code below implements an Exponential Moving Average (EMA) low-pass filter to smooth out light flicker, and a hysteresis loop to prevent the alarm from toggling on and off when hovering near the threshold edge.
// Flame Detector Arduino Project - Arduino Nano V3 (ATmega328P)
// Target Board: Arduino Nano (Old Bootloader or standard depending on CH340 clone)
#define SENSOR_PIN A0
#define BUZZER_PIN 8
#define DIGITAL_PIN 2 // Fallback hardware interrupt pin
// Thresholds (0-1023). Lower value = MORE IR light (closer flame).
// Adjust these based your serial monitor readings with a lighter.
const int TRIGGER_THRESHOLD = 450;
const int RESET_THRESHOLD = 650; // Hysteresis gap to prevent chatter
// EMA Filter parameters
float filteredValue = 1023.0;
const float ALPHA = 0.15; // Lower = smoother but slower response
bool alarmState = false;
int stuckHighCounter = 0;
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(DIGITAL_PIN, INPUT);
digitalWrite(BUZZER_PIN, LOW);
// Prime the filter with 50 rapid reads
for(int i=0; i<50; i++) {
filteredValue = (ALPHA * analogRead(SENSOR_PIN)) + ((1 - ALPHA) * filteredValue);
delay(2);
}
Serial.println("[SYS] Flame detector initialized. EMA filter primed.");
}
void loop() {
int rawValue = analogRead(SENSOR_PIN);
// Error Handling: Check for disconnected sensor (pull-ups drag pin to 1023)
if (rawValue >= 1020) {
stuckHighCounter++;
if (stuckHighCounter > 50) {
Serial.println("[ERR] A0 Stuck HIGH (1023). Check VCC wire or sensor phototransistor.");
delay(1000); // Throttle error messages
}
} else {
stuckHighCounter = 0;
}
// Apply Exponential Moving Average (EMA) to kill 120Hz AC light ripple
filteredValue = (ALPHA * rawValue) + ((1 - ALPHA) * filteredValue);
// Hysteresis Logic
if (!alarmState && filteredValue < TRIGGER_THRESHOLD) {
alarmState = true;
digitalWrite(BUZZER_PIN, HIGH);
Serial.print("[ALARM] Flame detected! Filtered Val: ");
Serial.println(filteredValue);
}
else if (alarmState && filteredValue > RESET_THRESHOLD) {
alarmState = false;
digitalWrite(BUZZER_PIN, LOW);
Serial.println("[SYS] Flame cleared. Alarm reset.");
}
// Debug output (throttled)
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 250) {
Serial.print("Raw: "); Serial.print(rawValue);
Serial.print(" | Filtered: "); Serial.println(filteredValue);
lastPrint = millis();
}
delay(10); // 10ms loop delay for stable ADC sampling
}
Debugging: First Three Things to Check When It Fails
When your serial monitor misbehaves or the hardware triggers falsely, follow this ranked decision path. These are the most common failure modes for IR flame sensors on the bench.
1. Symptom: Serial prints [ERR] A0 Stuck HIGH (1023)
This exact error string means the microcontroller's ADC is reading maximum voltage continuously. The flame sensor's phototransistor acts as a variable resistor to ground; if it's missing, the internal pull-up or floating noise maxes out the reading.
- Cause A (Most Likely): The red VCC wire to the KY-026 is loose or disconnected. The sensor isn't powering the LM393 or the phototransistor bias.
- Cause B: The analog pin A0 is accidentally shorted to the 5V rail on your breadboard.
- Cause C: The IR phototransistor was destroyed by wiring VCC and GND backward, frying the silicon junction.
2. Symptom: False Triggers in Daylight or Near Desk Lamps
The alarm sounds when there is no fire, but the sun is shining through the window or a 60W incandescent bulb is turned on.
- Cause A: The 760-1100nm IR spectrum is heavily emitted by the sun and hot tungsten filaments. Fix: Add a physical bandpass filter (a piece of dark red acrylic) over the sensor, or lower the
TRIGGER_THRESHOLDto 200 so only intense, close-proximity IR triggers it. - Cause B: The EMA filter
ALPHAvalue is too high (e.g., 0.8), allowing 120Hz light flicker to spike the filtered value momentarily. Fix: DropALPHAto 0.05.
3. Symptom: Buzzer is Silent or Just Clicking Faintly
- Cause A: You bought a passive buzzer instead of an active buzzer. Passive buzzers require an AC square wave (using the
tone()function) to make sound. Active buzzers only need DC HIGH. Fix: Swap the hardware, or replacedigitalWrite(BUZZER_PIN, HIGH)withtone(BUZZER_PIN, 2000). - Cause B: The Nano's 5V rail is sagging under the buzzer's current draw (some cheap piezos draw 30mA+). Power the buzzer via a 2N2222 transistor if the Nano resets during alarms.
Extending or Simplifying the Build
Depending on your end goal, you can strip this project down to its bare minimum or scale it up into a supervised IoT node.
How to Simplify (The Bare-Metal Approach)
If you don't care about light flicker or exact intensity and just want a binary 'fire/no-fire' toggle, ditch the analog pin entirely. Wire only the DO (Digital Output) pin from the KY-026 to Nano Pin D2. Use a small flathead screwdriver to turn the blue trimpot on the KY-026 module until the onboard LED turns off, then back it off slightly. When a flame appears, the LM393 comparator pulls D2 LOW. You can replace the entire code loop with a simple attachInterrupt() routine, saving memory and processing overhead.
How to Extend (The IoT Supervised Node)
To make this a practical home-monitoring tool, upgrade the microcontroller to an ESP32-WROOM-32 DevKit V1. The ESP32's 12-bit ADC (0-4095) provides much finer resolution for flame distance estimation than the Nano's 10-bit ADC.
Add a MQTT publishing block to the code to push the filteredValue to a local Home Assistant broker every 5 seconds. More importantly, implement a supervised heartbeat. In life-safety systems, a silent failure (like a dead sensor) is as dangerous as a fire. Program the ESP32 to send an MQTT 'Online' payload every 60 seconds. If Home Assistant misses two consecutive heartbeats, it triggers a 'Sensor Fault' automation, alerting you that the hardware has gone offline before a fire actually starts.






