Components · 17 min read

Flame Sensor Arduino Tutorial: Wiring, Code and Fire Alarm

Flame sensor Arduino guide: wiring, DO vs AO output, sensitivity, range and angle, buzzer fire alarm, use with MQ-2, avoiding false alarms, ESP32 and Pico code.

A flame sensor is a cheap module that detects the infrared light given off by a lighter, candle or burning paper, and you can use it with an Arduino in just a few lines of code. Using a flame sensor with Arduino needs no library: the module's DO pin changes state when it sees a flame, and the AO pin on 4-pin versions gives a voltage that changes with the flame's intensity. It is one of the most popular sensors for fire alarms, firefighting robots, kitchen safety systems and school projects.

In this guide you will learn what is inside a flame sensor and why it only responds to light between 760 and 1100 nm, how the digital and analog outputs differ, how to set the sensitivity potentiometer correctly, and what its detection range and angle are. Then you will build a fire alarm with a buzzer and an LED, combine the sensor with an MQ-2 gas sensor, reduce false alarms from sources such as sunlight and remote controls in software, send a Telegram notification to your phone with an ESP32, and run the same circuit on a Raspberry Pi Pico with MicroPython.

Flame sensor module (LM393, 3-pin)
3-pin flame sensor module: the black infrared receiver on the left, the blue sensitivity potentiometer and LM393 comparator in the middle, and the VCC, GND and DO pins with the power and alarm LEDs on the right.

What is a flame sensor and how does it work?

The black, LED-like part at the end of the module is actually an infrared phototransistor (a photodiode on some boards); a common example is the YG1006. Its black epoxy body filters out most visible light and only lets through near-infrared light between roughly 760 and 1100 nm, with peak sensitivity around 940 nm. The upper limit comes from silicon itself: with a band gap of 1.12 eV, silicon cannot absorb photons with wavelengths longer than about 1100 nm. Because the hot soot particles in a flame also radiate in this band, the current through the phototransistor rises as a flame gets closer. A voltage divider on the board turns that current into a voltage, and the LM393 comparator compares it with the threshold you set on the potentiometer to decide the state of the DO pin.

PropertyValue
Detected wavelength760–1100 nm (peak sensitivity ~940 nm)
Detection angleAbout 60° (~30° either side of the axis)
Detection distanceTypically up to 80 cm for a lighter flame; more for bigger flames
Supply voltage3.3–5 V
ComparatorLM393; threshold set with a multi-turn potentiometer
OutputsDO (digital, on every model), AO (analog, on 4-pin models)
DO logicCommon blue modules: flame = LOW and the DO LED lights; KY-026: usually flame = HIGH
Response timeWell under a millisecond; the phototransistor reacts within microseconds
Receiver operating temperatureAbout −25 to +85 °C

Several different flame sensor boards do the same job. 3-pin modules like the one in the photo above only have a digital output; 4-pin modules add an analog output. The KY-026 you may know from sensor kits works the same way, but its DO output is usually inverted. Firefighting robots use multi-channel boards with five receivers arranged in a fan. A flame sensor is passive, meaning it emits no light of its own; that sets it apart from the TCRT5000 infrared sensor, which has both an emitter and a receiver.

ModelPinsFeatureWhen to choose it
3-pin moduleVCC, GND, DOFlame yes/no onlySimple fire alarm, first experiments
4-pin moduleVCC, GND, DO, AOThreshold output + flame intensityMulti-level alarm, false alarm filtering
KY-026A0, G, +, D0Same as the 4-pin module; DO usually HIGH on flameProjects that come with sensor kits
5-channel moduleVCC, GND and a separate output per receiverWide field of view of about 120°Robots that find the flame's direction

Digital (DO) vs analog (AO) output

The DO pin is a yes/no answer: it changes state when the infrared light exceeds the threshold you set on the potentiometer. On common blue boards this pin is normally HIGH, goes LOW when it sees a flame, and the DO LED lights up; on some boards such as the KY-026 it is the other way round. So the first thing to do is test your own module with a lighter and check what the Serial Monitor shows. The AO pin gives the raw signal. On most modules this value falls as a flame gets closer: an analogRead value of 900–1020 in a room without a flame can drop to a few hundred with a lighter nearby. The potentiometer only changes the DO threshold and has no effect on AO.

PropertyDO (digital)AO (analog)
Value readHIGH or LOW0–1023 on an Arduino Uno
ThresholdPotentiometer on the boardYou set it in code
InformationIs there a flame or notFlame intensity, rough distance and flicker
Pin to useAny digital pinAnalog pin (ADC)
Best forSimple alarm, instant response via interruptMulti-level alarm, false alarm filtering, finding direction

How to adjust the sensitivity potentiometer

  1. Power the module and place the sensor where it will work, facing the direction it will watch; always make this adjustment in the real environment.
  2. With no flame present, turn the blue potentiometer with a small screwdriver and find the point where the DO LED switches between on and off.
  3. From that point, turn it another half to full turn in the direction where the LED stays off. This way small changes in ambient light will not trigger the alarm.
  4. Hold a lighter towards the sensor at the farthest distance you want to detect and check that the LED lights up. If it does not, make the setting slightly more sensitive and try again.
  5. Make sure the sensor is not facing a sunny window or an incandescent lamp, and check the setting again a few hours later under different lighting.
The blue potentiometer on these modules is usually a 3296-type multi-turn trimmer that takes about 25 turns from one end to the other. If you turn it a few times and nothing changes, it is not broken; you simply need to keep turning. An LM393 set very close to its threshold can switch on and off rapidly as the flame flickers; you will fix that with a hold time in the code shortly. You can read how a potentiometer works in what is a potentiometer.

Detection range and angle

Figures such as 80 cm given by manufacturers refer to a standard lighter flame; the real range depends on the size of the flame, the potentiometer setting and the ambient light. A simple law of physics applies here: the intensity of light from a small source falls with the square of the distance. Double the distance and the infrared light reaching the sensor drops to a quarter. Looking at it the other way, you can detect a flame that emits four times as much light from twice as far away, and one a hundred times stronger from ten times as far. That is why a candle flame is detected at a shorter distance than a lighter, while a burning pile of paper can be detected from several metres.

DistanceLight reaching the sensor (20 cm = 100%)
20 cm100%
40 cm25%
60 cm11%
80 cm6%
1 m4%

The detection angle is about 60 degrees, so the sensor sees flames inside a cone of roughly 30 degrees on either side of its axis, and the signal weakens quickly as the flame moves towards the edge of that cone. The receiver has long legs, so you can gently bend it to face any direction, but repeatedly bending the point where the legs enter the body will break it. To narrow the field of view, slide a matt black tube over the receiver: a tube with a 6 mm inner diameter and 2 cm length cuts the angle to roughly 30 degrees and blocks sunlight or lamplight coming from the side. The field of view should be just wide enough to cover the area you want to watch; anything wider only adds new sources of false alarms.

Flame sensor wiring: Arduino Uno, ESP32 and Pico

ConnectionArduino UnoESP32Raspberry Pi Pico
Module VCC5V3V33V3(OUT), pin 36
Module GNDGNDGNDGND, pin 38
Module DOD2GPIO 27GP15, pin 20
Module AO (4-pin)A0GPIO 34 (ADC1)GP26 / ADC0, pin 31
Active buzzer (+)D8GPIO 25GP14, pin 19
Red LED (with 220 Ω)D7GPIO 26GP13, pin 17
ESP32 and Pico pins are designed for 3.3 V. On these boards, power the flame sensor from the 3V3 pin, not from 5V, VIN or VBUS; if the module runs on 5 V, its DO and AO outputs can reach 5 V and damage the input pin. This is an important difference from the MQ-2: the flame sensor works fine on 3.3 V, so no voltage divider is needed. Always read the VCC and GND labels on the board before wiring; the pin order differs between models, and reversing the supply can destroy the LM393.

Step by step: a flame sensor fire alarm with Arduino

  1. Connect the module's VCC pin to the Arduino's 5V pin, GND to GND and DO to D2.
  2. Connect the long (+) leg of the active buzzer to D8 and the short leg to GND.
  3. Connect the long leg of the red LED to D7 through a 220 Ω resistor and the short leg to GND. If you use a different LED, you can work out the resistor value with the LED resistor calculator.
  4. Upload the code below, open the Serial Monitor at 9600 baud and briefly hold a lighter towards the sensor from 20–30 cm away.
  5. If the buzzer sounds and the LED lights up, the circuit works; if the alarm sounds with no flame and goes quiet when there is one, change FLAME_ACTIVE in the code to HIGH.
Arduino (C++)
1// Alev sensörü ile basit yangın alarmı / Simple fire alarm with a flame sensor
2const int FLAME_DO = 2;          // modülün DO pini / module DO pin
3const int BUZZER = 8;            // aktif buzzer / active buzzer
4const int LED = 7;               // kırmızı LED (220 Ω ile) / red LED (with 220 Ω)
5const int FLAME_ACTIVE = LOW;    // çoğu modülde alev = LOW, KY-026'da HIGH / most modules: flame = LOW, KY-026: HIGH
6
7void setup() {
8  Serial.begin(9600);
9  pinMode(FLAME_DO, INPUT);
10  pinMode(BUZZER, OUTPUT);
11  pinMode(LED, OUTPUT);
12}
13
14void loop() {
15  bool flame = digitalRead(FLAME_DO) == FLAME_ACTIVE;
16
17  if (flame) {
18    Serial.println(F("ALEV ALGILANDI! / FLAME DETECTED!"));
19    digitalWrite(LED, HIGH);
20    digitalWrite(BUZZER, HIGH);  // kesik kesik alarm sesi / beeping alarm
21    delay(150);
22    digitalWrite(BUZZER, LOW);
23    delay(150);
24  } else {
25    digitalWrite(LED, LOW);
26    digitalWrite(BUZZER, LOW);
27    delay(50);
28  }
29}

On every pass the code reads the DO pin and compares the result with the FLAME_ACTIVE constant. Thanks to this constant, the same code works with blue modules that go LOW on a flame and with the KY-026 that goes HIGH. As long as a flame is visible the LED stays on, while the buzzer switches on and off every 150 ms to make an attention-grabbing, beeping sound. An active buzzer has its own oscillator, so it only needs HIGH and LOW; if you have a passive buzzer, use tone() instead of digitalWrite, as explained in what is a buzzer. There is another reason we chose D2 for the DO pin: on the Uno, D2 is one of the two pins that support interrupts, so with attachInterrupt you can catch a flame without waiting for the rest of the loop.

Analog reading: flame intensity and rough distance

If you have a 4-pin module, the AO output lets you do much more. Because the raw value differs in every environment, use this method instead of a fixed threshold: at start-up, with no flame present, measure a baseline value, then look at how far each new reading moves away from it. The code below averages 16 readings to reduce noise, calculates the deviation as flame strength and tells you roughly whether the flame is near or far. If your module's AO value rises with a flame, simply set DROPS_WITH_FLAME to false.

Arduino (C++)
1// AO ile alev gücü ve yaklaşık mesafe / Flame strength and rough distance via AO
2const int FLAME_AO = A0;             // 4 pinli modülün AO pini / AO pin of the 4-pin module
3const bool DROPS_WITH_FLAME = true;  // çoğu modülde alev yaklaşınca değer düşer / on most modules the value falls as the flame approaches
4int baseline;                        // alevsiz ortam değeri / flame-free ambient value
5
6int readAverage() {
7  long sum = 0;
8  for (int i = 0; i < 16; i++) {     // 16 ölçümün ortalaması / average of 16 readings
9    sum += analogRead(FLAME_AO);
10    delay(2);
11  }
12  return sum / 16;
13}
14
15void setup() {
16  Serial.begin(9600);
17  delay(1000);                       // açılışta ortamda alev olmamalı / no flame at start-up
18  baseline = readAverage();
19  Serial.print(F("Taban / Baseline: "));
20  Serial.println(baseline);
21}
22
23void loop() {
24  int value = readAverage();
25  int strength = DROPS_WITH_FLAME ? baseline - value : value - baseline;  // alev gücü / flame strength
26  if (strength < 0) strength = 0;
27
28  Serial.print(F("AO: "));
29  Serial.print(value);
30  Serial.print(F("  Guc / Strength: "));
31  Serial.print(strength);
32
33  if (strength > 400) {
34    Serial.println(F("  -> YAKIN ALEV / CLOSE FLAME"));
35  } else if (strength > 100) {
36    Serial.println(F("  -> UZAK ALEV / DISTANT FLAME"));
37  } else {
38    Serial.println(F("  -> alev yok / no flame"));
39  }
40  delay(250);
41}

The thresholds of 100 and 400 in the code are only a starting point. To tune them for your own sensor, upload the code, open the Serial Monitor and note the flame strength while holding a lighter at 10, 30 and 60 cm; because of the inverse square law you will see the value change very quickly up close and slowly far away. That is why you cannot work out an exact distance in centimetres from the analog value: the same value can come from a small flame nearby or a large flame far away. You can learn how the ADC produces the raw value in analog-to-digital conversion and the finer points of the Serial Monitor in Arduino Serial Monitor.

Sunlight and other sources of false alarms

A flame sensor does not see fire; it sees infrared light in a certain band, and anything that emits light in that band can trigger it. Wien's law explains which sources cause trouble: the wavelength at which a hot object radiates most is about 2898 / T micrometres (T being the temperature in kelvin). The sun and incandescent bulbs radiate strongly right in the sensor's band, whereas the human body is far too cool, so the sensor cannot see you at all. That is why detecting motion needs a PIR sensor, which looks at much longer wavelengths.

SourceApproximate temperaturePeak wavelengthEffect on the flame sensor
Sun5800 K0.5 µmVery strong; direct sunlight or a reflection from glass can blind the sensor
Incandescent and halogen bulbs2700–3000 K~1 µmStrong; much of their light falls right in the sensor's band
Candle and lighter flame (soot particles)~1500 K~1.9 µmThe source you want to detect; part of its radiation falls in the band
Glowing heater element, stove~1100 K~2.6 µmCan trigger it at close range
TV remote control-0.94 µm (narrow band)Triggers it with short pulses
LED and fluorescent lamps-Visible bandAlmost no infrared, usually no problem
Human body310 K~9.3 µmInvisible to the sensor

You can prevent most false alarms with hardware: place the sensor so it does not face a window, a sunlit wall or an incandescent lamp, ideally pointing downwards and into the room, narrow its field of view with a black tube, and set the potentiometer under real ambient lighting. Remember that strong sunlight does not only cause false alarms, it can also blind the sensor by saturating it: if the AO value has already dropped to its minimum in the sun, there is nothing left to change when a real flame appears. Professional infrared flame detectors solve this by looking at the 4.3 µm band, where hot carbon dioxide radiates and sunlight is largely absorbed by the atmosphere, by comparing several wavelengths and by analysing the flame's flicker. Your module cannot do the first two, but you can imitate flicker analysis and time confirmation in software.

Reducing false alarms in software: time confirmation and flicker analysis

A real flame never burns steadily; air currents and rising hot gases make its brightness fluctuate roughly 1 to 20 times per second. Sunlight and the light of an incandescent bulb, on the other hand, are almost constant over short periods, and the pulses from a remote control last only milliseconds. The code below uses these differences with three rules: the flame strength must be clearly above the baseline, the value must have fluctuated by more than a set amount in the last second, and both conditions must hold without interruption for at least two seconds. In addition, each reading is the average of 20 samples taken over 10 ms. On a 50 Hz mains supply, lamps flicker slightly 100 times per second; averaging over 10 ms, exactly one flicker period, cancels this ripple so a lamp is not mistaken for a flickering flame.

Arduino (C++)
1// Süre doğrulamalı ve titreşim analizli alev alarmı / Flame alarm with time confirmation and flicker analysis
2const int FLAME_AO = A0;
3const int BUZZER = 8;
4const int LED = 7;
5const int STRENGTH_LIMIT = 150;          // tabandan en az bu kadar sapma / minimum deviation from the baseline
6const int FLICKER_LIMIT = 20;            // 1 sn içindeki en az dalgalanma / minimum swing within 1 s
7const unsigned long CONFIRM_MS = 2000;   // koşul bu kadar kesintisiz sürmeli / condition must hold this long
8
9float baseline;
10int winMin = 1023, winMax = 0;
11bool flickering = false;
12unsigned long windowStart = 0;
13unsigned long candidateSince = 0;
14
15// 10 ms boyunca 20 ölçüm: 100 Hz lamba titreşimini siler / 20 samples over 10 ms: cancels 100 Hz lamp flicker
16int readFiltered() {
17  long sum = 0;
18  for (int i = 0; i < 20; i++) {
19    sum += analogRead(FLAME_AO);         // yaklaşık 0,11 ms sürer / takes about 0.11 ms
20    delayMicroseconds(390);
21  }
22  return sum / 20;
23}
24
25void setup() {
26  Serial.begin(9600);
27  pinMode(BUZZER, OUTPUT);
28  pinMode(LED, OUTPUT);
29  baseline = readFiltered();             // açılışta ortamda alev olmamalı / no flame at start-up
30}
31
32void loop() {
33  int value = readFiltered();
34  int strength = (int)baseline - value;  // AO alevle artıyorsa: value - baseline / if AO rises with flame: value - baseline
35  unsigned long now = millis();
36
37  if (value < winMin) winMin = value;
38  if (value > winMax) winMax = value;
39
40  if (now - windowStart >= 1000) {       // her saniye pencereyi değerlendir / evaluate the window every second
41    int swing = winMax - winMin;
42    flickering = swing > FLICKER_LIMIT;  // alev titrer, güneş sabittir / flames flicker, sunlight is steady
43    if (strength < STRENGTH_LIMIT / 2) {
44      baseline += (value - baseline) * 0.05;  // ortam ışığını yavaşça izle / slowly follow ambient light
45    }
46    Serial.print(F("Guc / Strength: "));
47    Serial.print(strength);
48    Serial.print(F("  Dalgalanma / Swing: "));
49    Serial.println(swing);
50    winMin = 1023;
51    winMax = 0;
52    windowStart = now;
53  }
54
55  bool candidate = strength > STRENGTH_LIMIT && flickering;
56  if (!candidate) candidateSince = now;  // koşul bozulunca sayaç sıfırlanır / timer resets when the condition breaks
57  bool alarm = now - candidateSince >= CONFIRM_MS;
58
59  digitalWrite(LED, alarm ? HIGH : LOW);
60  digitalWrite(BUZZER, (alarm && (now / 200) % 2) ? HIGH : LOW);  // kesik siren / beeping siren
61}

Because the code keeps time with millis() instead of delay(), it keeps measuring even while the alarm is sounding; the details of this approach are in millis vs delay. The baseline does not stay fixed either: when there is no flame, it moves 5 percent towards the latest reading once per second and slowly follows ambient light as it changes during the day. To find a good FLICKER_LIMIT, watch the one-second swing of a steady light source in the Serial Monitor, then that of a candle flame, and set the threshold between the two. This method is not perfect; sunlight shining through leaves moving in the wind flickers too. You can find other techniques such as moving average and median filters in filtering sensor data.

Using it together with an MQ-2 gas sensor

A flame sensor and an MQ-2 gas sensor cover each other's weaknesses. The flame sensor is very fast, but it only sees flames in its field of view and can be fooled by the sun. The MQ-2 detects smoke and flammable gases and can notice a fire around a corner or a smouldering fire with no flame, but smoke takes time to reach it and it needs to warm up every time it is powered on. When you use both, you can treat a signal from one sensor as a warning and a signal from both at once as a fire.

MQ-2 gaz ve duman sensörü
MQ-2 gaz ve duman sensörü
Buzzer
Buzzer
Flame sensorMQ-2DecisionResponse
NoNormalNormalLED and buzzer off
YesNormalWarning: could be sunlight, a lamp or a fire just startingLED blinks, short beep every 2 seconds
NoHighWarning: smoke, a gas leak or a fire outside the field of viewLED blinks, short beep every 2 seconds
YesHighFireLED stays on, fast beeping siren
Arduino (C++)
1// Alev sensörü + MQ-2 ile iki kademeli yangın alarmı / Two-level fire alarm with a flame sensor + MQ-2
2const int FLAME_DO = 2;
3const int MQ2_AO = A1;                   // MQ-2 analog çıkışı / MQ-2 analog output
4const int BUZZER = 8;
5const int LED = 7;
6const int FLAME_ACTIVE = LOW;            // KY-026 kullanıyorsan HIGH / HIGH if you use a KY-026
7const int SMOKE_LIMIT = 400;             // temiz hava değerinin belirgin üstü / well above the clean-air value
8const unsigned long WARMUP_MS = 60000;   // MQ-2 ön ısıtma süresi / MQ-2 warm-up time
9const unsigned long HOLD_MS = 300;       // DO'daki kısa kesintileri yok say / ignore short gaps on DO
10
11unsigned long lastFlame = 0;
12unsigned long lastPrint = 0;
13
14void setup() {
15  Serial.begin(9600);
16  pinMode(FLAME_DO, INPUT);
17  pinMode(BUZZER, OUTPUT);
18  pinMode(LED, OUTPUT);
19}
20
21void loop() {
22  unsigned long now = millis();
23  if (digitalRead(FLAME_DO) == FLAME_ACTIVE) lastFlame = now;
24  bool flame = lastFlame > 0 && now - lastFlame < HOLD_MS;
25
26  int gas = analogRead(MQ2_AO);
27  bool smoke = now > WARMUP_MS && gas > SMOKE_LIMIT;  // ısınana kadar dumanı yok say / ignore smoke until warmed up
28
29  int level = 0;                         // 0 normal, 1 uyarı / warning, 2 yangın / fire
30  if (flame && smoke) level = 2;
31  else if (flame || smoke) level = 1;
32
33  if (level == 2) {
34    digitalWrite(LED, HIGH);
35    digitalWrite(BUZZER, (now / 150) % 2 ? HIGH : LOW);     // hızlı siren / fast siren
36  } else if (level == 1) {
37    digitalWrite(LED, (now / 500) % 2 ? HIGH : LOW);        // yanıp sönen LED / blinking LED
38    digitalWrite(BUZZER, (now % 2000) < 100 ? HIGH : LOW);  // 2 sn'de bir kısa bip / short beep every 2 s
39  } else {
40    digitalWrite(LED, LOW);
41    digitalWrite(BUZZER, LOW);
42  }
43
44  if (now - lastPrint >= 1000) {
45    lastPrint = now;
46    Serial.print(F("Alev / Flame: "));
47    Serial.print(flame ? 1 : 0);
48    Serial.print(F("  MQ-2: "));
49    Serial.print(gas);
50    Serial.print(F("  Seviye / Level: "));
51    Serial.println(level);
52  }
53}

Connect the MQ-2's AO output to A1 and power the module from 5V; the flame sensor can stay on D2. Set SMOKE_LIMIT clearly above the value you read after running the sensor in clean air for a few minutes, as described in the MQ-2 guide. The smoke condition is ignored for the first 60 seconds because a cold MQ-2 starts with a high reading. The 300 ms hold time on the flame signal (HOLD_MS) turns the brief on-off switching of the DO output, caused by the flickering flame, into one continuous detection. If you move this combination to an ESP32, be careful: the MQ-2 needs 5 V and its AO output can reach 5 V, so you must put a voltage divider on its output, while the flame sensor runs directly on 3V3.

Fire notifications to your phone with an ESP32 (Telegram)

To make the alarm warn not only the people in the room but also you when you are away, you can use an ESP32. Telegram bots are the easiest way to do this: they are free, need no server of your own, and the message arrives on your phone instantly as a notification. The code below sounds the buzzer and sends a Telegram message once a flame has been seen for 1.5 seconds, and waits at least one minute between messages so your phone is not flooded for the same fire. We cover setting up the bot and two-way control with commands in detail in ESP32 Telegram bot.

  1. In Telegram, chat with @BotFather, send the /newbot command, give your bot a name and copy the token it gives you.
  2. Open an ID bot such as @userinfobot and tap Start; it replies with your own chat ID.
  3. Find your new bot in Telegram and tap Start; if you skip this, the bot cannot send you messages.
  4. In the Arduino IDE, install the UniversalTelegramBot and ArduinoJson libraries from the Library Manager.
  5. Replace the Wi-Fi name, password, token and chat ID in the code with your own, select ESP32 as the board and upload the code.
Arduino (C++)
1// ESP32 alev alarmı + Telegram bildirimi / ESP32 flame alarm + Telegram notification
2#include <WiFi.h>
3#include <WiFiClientSecure.h>
4#include <UniversalTelegramBot.h>        // ArduinoJson kütüphanesi de gerekir / also needs the ArduinoJson library
5
6const char* WIFI_SSID = "WIFI_ADI";      // Wi-Fi ağının adı / your Wi-Fi name
7const char* WIFI_PASS = "WIFI_SIFRESI";  // Wi-Fi şifren / your Wi-Fi password
8#define BOT_TOKEN "1234567890:ABCdefGhIJKlmNoPQRstuVWXyz"  // BotFather'dan / from BotFather
9#define CHAT_ID "123456789"              // senin chat ID'n / your chat ID
10
11const int FLAME_DO = 27;                 // modülün DO pini / module DO pin
12const int BUZZER = 25;                   // aktif buzzer / active buzzer
13const int LED = 26;                      // kırmızı LED (220 Ω ile) / red LED (with 220 Ω)
14const int FLAME_ACTIVE = LOW;
15const unsigned long HOLD_MS = 300;       // DO'daki kısa kesintileri yok say / ignore short gaps on DO
16const unsigned long CONFIRM_MS = 1500;   // alev bu kadar sürmeli / flame must last this long
17const unsigned long COOLDOWN_MS = 60000; // iki mesaj arası en az 1 dk / at least 1 min between messages
18
19WiFiClientSecure client;
20UniversalTelegramBot bot(BOT_TOKEN, client);
21
22unsigned long lastFlame = 0;
23unsigned long flameStart = 0;
24unsigned long lastMessage = 0;
25bool messageSent = false;
26
27void setup() {
28  Serial.begin(115200);
29  pinMode(FLAME_DO, INPUT);
30  pinMode(BUZZER, OUTPUT);
31  pinMode(LED, OUTPUT);
32
33  WiFi.mode(WIFI_STA);
34  WiFi.begin(WIFI_SSID, WIFI_PASS);
35  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);  // api.telegram.org kök sertifikası / root certificate
36  unsigned long start = millis();
37  while (WiFi.status() != WL_CONNECTED && millis() - start < 15000) {  // en fazla 15 sn bekle / wait up to 15 s
38    delay(500);
39    Serial.print(".");
40  }
41  if (WiFi.status() == WL_CONNECTED) {
42    Serial.println(WiFi.localIP());
43    bot.sendMessage(CHAT_ID, "Yangin alarmi devrede / Fire alarm is online", "");
44  }
45}
46
47void loop() {
48  unsigned long now = millis();
49  if (digitalRead(FLAME_DO) == FLAME_ACTIVE) lastFlame = now;
50  bool flame = lastFlame > 0 && now - lastFlame < HOLD_MS;
51  if (!flame) flameStart = now;          // alev yoksa sayaç sıfırlanır / timer resets without flame
52  bool alarm = now - flameStart >= CONFIRM_MS;
53
54  digitalWrite(LED, alarm ? HIGH : LOW);
55  digitalWrite(BUZZER, (alarm && (now / 200) % 2) ? HIGH : LOW);  // kesik siren / beeping siren
56
57  if (alarm && (!messageSent || now - lastMessage >= COOLDOWN_MS)) {
58    if (WiFi.status() == WL_CONNECTED) {
59      bool ok = bot.sendMessage(CHAT_ID, "ALEV ALGILANDI! / FLAME DETECTED!", "");
60      Serial.println(ok ? "Mesaj gitti / Message sent" : "Gonderilemedi / Send failed");
61    } else {
62      WiFi.reconnect();                  // bağlantı koptuysa yeniden dene / reconnect if the link dropped
63    }
64    lastMessage = now;                   // başarısızsa 1 dk sonra yeniden dener / retries after 1 min if it failed
65    messageSent = true;
66  }
67  delay(10);
68}

The sendMessage() call opens a secure HTTPS connection, so it can take a second or two; the buzzer pattern briefly freezes during that time, which is normal. At start-up the code tries to connect to Wi-Fi for up to 15 seconds; if there is no connection it keeps running the alarm locally and retries an unsent message a minute later, so the buzzer keeps sounding even without internet. If you also want to read the AO output on an ESP32, always connect it to an ADC1 pin (GPIO 32–39), because ADC2 pins cannot be used while Wi-Fi is on; that is why GPIO 34 was chosen in the table. You can see your board's safe pins in the Pinout tool. If a 5 V active buzzer sounds weak on a 3.3 V pin, drive it from 5 V with a transistor. For a shed or holiday home without Wi-Fi, you can build the same alarm to send an SMS with a SIM800L GSM module.

Flame sensor with Raspberry Pi Pico and MicroPython

The same logic applies on the Raspberry Pi Pico. Power the module from the 3V3(OUT) pin, connect DO to GP15 and, if you have it, AO to GP26. The module has its own pull-up resistor on the DO line, so you do not need the Pico's internal pull-up. The Pico's ADC is 12-bit, but read_u16() in MicroPython scales the result to 0–65535, so the equivalent of the Arduino's 1023 is about 65535 here. The code uses a 300 ms hold time that tolerates brief gaps on DO and a 1.5-second confirmation:

MicroPython
1# Raspberry Pi Pico alev alarmı / Raspberry Pi Pico flame alarm
2from machine import Pin, ADC
3import time
4
5flame_do = Pin(15, Pin.IN)      # modülün DO pini / module DO pin
6flame_ao = ADC(26)              # GP26 = ADC0, 4 pinli modülde AO / AO on the 4-pin module
7buzzer = Pin(14, Pin.OUT)       # aktif buzzer / active buzzer
8led = Pin(13, Pin.OUT)          # kırmızı LED (220 Ω ile) / red LED (with 220 Ω)
9
10FLAME_ACTIVE = 0                # çoğu modülde alev = 0, KY-026'da 1 / most modules: flame = 0, KY-026: 1
11HOLD_MS = 300                   # DO'daki kısa kesintileri yok say / ignore short gaps on DO
12CONFIRM_MS = 1500               # alev bu kadar sürmeli / flame must last this long
13
14last_flame = None
15flame_start = time.ticks_ms()
16last_print = time.ticks_ms()
17
18while True:
19    now = time.ticks_ms()
20    if flame_do.value() == FLAME_ACTIVE:
21        last_flame = now
22    flame = last_flame is not None and time.ticks_diff(now, last_flame) < HOLD_MS
23    if not flame:
24        flame_start = now       # alev yoksa sayaç sıfırlanır / timer resets without flame
25    alarm = time.ticks_diff(now, flame_start) >= CONFIRM_MS
26
27    led.value(1 if alarm else 0)
28    buzzer.value(1 if alarm and (now // 200) % 2 else 0)   # kesik siren / beeping siren
29
30    if time.ticks_diff(now, last_print) >= 500:   # yarım saniyede bir yaz / print every half second
31        last_print = now
32        print(flame_ao.read_u16(), "ALARM" if alarm else "-")
33    time.sleep_ms(10)

When you run the code in Thonny, you will see the AO value and the alarm state in the Shell window; open the Plotter from the View menu to follow the values as a graph. To make the program start automatically when the Pico is powered, save the file to the Pico as main.py. Using time.ticks_diff() for timing matters, because the ticks_ms() counter wraps around after a certain value and a plain subtraction gives the wrong result at that moment.

Flame sensor project ideas

  • Kitchen fire alarm: Build an alarm with a flame sensor facing the hob and an MQ-2, using the two-level logic above.
  • Forgotten hob reminder: If a flame is seen continuously for more than 30 minutes, sound the buzzer and send a message to your phone.
  • Firefighting robot: Find the flame's direction with a 5-channel sensor, drive the robot towards it with an L298N and DC motors and put out the candle with a mini water pump.
  • Flame direction scanner: Mount a single sensor on a servo motor, sweep from 0 to 180 degrees and display the angle with the strongest signal.
  • Smart home safety panel: Combine flame, gas and motion sensors on one board; see Arduino smart home project for details.
  • Workshop guard: When an unexpected flame appears near the soldering station, switch on a warning light through a relay.
  • Candle extinguishing contest: As in school robotics competitions, build a robot that finds and puts out a candle in a maze as fast as possible; a flame sensor is all you need to get started.

Common mistakes and how to fix them

SymptomLikely causeFix
The DO LED is always on and the alarm never stopsThe threshold is too sensitive, or the sensor faces the sun or an incandescent lampTurn the potentiometer with no flame present until the LED goes off, and point the sensor away from the light source
Nothing happens when you show it a lighterThe threshold is too high, or the flame is outside the 60-degree field of view or too far awayTurn the potentiometer a few turns towards more sensitivity and bring the flame directly in front of the sensor and closer
The alarm sounds with no flame and stops when there is oneThe module's DO output is active-HIGH (e.g. KY-026)Change FLAME_ACTIVE in the code to HIGH
The DO LED flickers in front of a flameThe comparator is very close to its threshold and the flame's flicker toggles the outputUse a hold time (HOLD_MS) in code or make the threshold slightly more sensitive
The analog value never changesThe 3-pin module has no AO, or the DO pin is wired to the analog inputUse a 4-pin module and connect its AO pin to the analog input
Pressing a remote control triggers the alarmThe 940 nm infrared LED of the TV remoteOnly raise the alarm after a time confirmation of at least 1–2 seconds
By a window in daytime it gives false alarms or cannot see the flame at allSunlight triggers or saturates the sensorPosition the sensor away from the sun, use a black tube and add flicker analysis
On the ESP32 the AO value goes wrong once Wi-Fi startsAO is wired to an ADC2 pinConnect AO to an ADC1 pin between GPIO 32 and 39
The buzzer is very weak on an ESP32 or PicoA 5 V active buzzer is driven by a 3.3 V pinUse a 3.3 V buzzer or drive the buzzer from 5 V through a transistor
There is a safe way to test the sensor without lighting a flame: point a TV remote at it from a few centimetres away and press a button. If the remote's 940 nm infrared LED makes the DO LED blink, the sensor and wiring are working. Do not confuse this module with an IR receiver that decodes remote control signals: an IR receiver only responds to a signal modulated at 38 kHz, whereas a flame sensor measures the raw amount of infrared light.
An alarm built with a flame sensor is a learning project, not a certified fire detector. For life safety at home, use a smoke alarm that complies with EN 14604 and treat your own circuit as an extra system alongside it. When testing, only use a small, controlled flame such as a lighter or a candle, keep flammable materials away, never leave the flame unattended, and if you are young, do the experiment with an adult. Do not place the sensor right next to the flame: the receiver's operating temperature is limited to about 85 °C, and an overheated body can be permanently damaged.

A flame sensor is a cheap but instructive part that teaches the physics of infrared light, comparator circuits and how to fight false alarms all at once. Start with a simple DO alarm, then strengthen your system step by step with analog readings, flicker analysis and an MQ-2; for a more complete security system, take a look at Arduino alarm system. In the BlueGrays app you will find flame sensor, flame and gas sensor alarm, ESP32 MQ-2 smoke detector and ESP32 alarm system with Telegram notification projects, each with step-by-step circuit diagrams and ready-to-use code.

Frequently asked questions

How far can a flame sensor detect a flame?

Most modules detect a standard lighter flame up to about 80 cm; for a candle flame the distance is shorter. Because light intensity falls with the square of the distance, a flame four times stronger is seen from twice as far, so a large paper or wood fire can be detected from several metres. The potentiometer setting and the ambient light also have a direct effect on range.

Is a flame sensor affected by sunlight?

Yes. Sunlight is very strong in the 760–1100 nm band the sensor responds to; direct sunlight or a reflection from glass causes false alarms and can blind the sensor so it misses a real flame. Position the sensor away from the sun, narrow its field of view with a black tube and use time confirmation and flicker analysis in software.

Does a flame sensor output LOW or HIGH when it detects a flame?

On common blue LM393 modules the DO pin is normally HIGH, goes LOW when it sees a flame, and the DO LED lights up. On some boards such as the KY-026, the output goes HIGH when a flame is detected. Test your own module with a lighter and set the comparison in your code according to the value shown in the Serial Monitor.

Does a flame sensor work on 3.3 V?

Yes, these modules work from 3.3 to 5 V. On an ESP32 or Raspberry Pi Pico, powering the module from the 3V3 pin keeps the DO and AO outputs below 3.3 V, so you can connect them directly to the pins. If you power the module from 5 V, you need voltage dividers on the outputs for these boards.

How do you adjust the sensitivity of a flame sensor?

With no flame present, turn the blue multi-turn potentiometer on the board to the point where the DO LED just goes off, then turn it another half turn towards less sensitivity. Next, test it with a lighter at the farthest distance you want to detect. The potentiometer only changes the DO threshold; for AO you set the threshold yourself in code.

Can a flame sensor replace a fire detector?

No. A hobby flame sensor can be fooled by sunlight, incandescent lamps and remote controls, cannot see a fire outside its field of view or one smouldering without a flame, and has not been tested to any standard. For life safety use a smoke alarm that complies with EN 14604, and treat your own circuit as an additional warning system.

See all projects
Using a Buzzer
#13Beginner

Using a Buzzer

Ever wondered how a doorbell or an alarm makes its sound? The Arduino makes a small buzzer beep at short intervals: beep, pause, beep, pause. You see how sound is made with electricity and take the fi

4.7(89)
158
Measuring Light Intensity with an LDR
#11Beginner

Measuring Light Intensity with an LDR

Want to see how bright your room is as a number? The LDR, a small part that reacts to light, measures the light around it, and the Arduino writes the value to your computer screen every half second. C

4.6(79)
130
Using a Flame Sensor
#50Intermediate
Premium

Using a Flame Sensor

A little guard that spots fire before you do, in the kitchen or the workshop. The flame sensor picks up the invisible light that fire gives off; while all is well the green LED is on, and when it sees

4.6(33)
44
Flame and Gas Sensor Alarm
#52Advanced
Premium

Flame and Gas Sensor Alarm

A little guard that warns you right away when gas leaks or a flame appears somewhere. The gas sensor watches the air for gas and the flame sensor watches for the light of a fire; while everything is f

4.8(52)
67
Using a Gas Sensor
#51Beginner
Premium

Using a Gas Sensor

A little guard that notices a gas leak in the kitchen before you do. The gas sensor keeps sniffing the air; while everything is fine the green LED stays on, and when the gas in the air passes a certai

4.6(37)
50
ESP32 MQ-2 Gas/Smoke Detector Alarm
#122Intermediate

ESP32 MQ-2 Gas/Smoke Detector Alarm

In this project, combustible gas (LPG, methane, propane) and smoke detection is performed using an MQ-2 gas sensor module, and a siren-like alarm is played through a passive buzzer upon detection. The sensor's digital threshold output (DO) is connected to GPIO 4 on the ESP32; when gas or smoke exceeds the threshold, DO goes LOW and the alarm is triggered. Sensitivity is adjusted via the module's potentiometer. The passive buzzer is driven using `tone()` to produce a two-frequency siren effect.

4.7(27)
40
ESP32 Motion Alarm System (PIR + Buzzer + LED + Telegram)
#145Advanced
Premium

ESP32 Motion Alarm System (PIR + Buzzer + LED + Telegram)

A smart security alarm system that activates the buzzer and LED when the PIR sensor detects motion, while simultaneously sending an instant notification to the owner via Telegram. It includes a 30-second cooldown to limit the frequency of repeated alarms; this mechanism does not validate PIR detections or eliminate false triggers. Suitable for home security, garage monitoring, warehouses, or workrooms. With ESP32-CAM, photo notifications can be added; with the classic ESP32 DevKit V1, text notif

0.0(0)
8
ESP32 Motion Detection Alarm
#140Intermediate
Premium

ESP32 Motion Detection Alarm

In this project, which uses an ESP32 and a PIR sensor, a buzzer sounds an audible alarm when motion is detected. It is a simple and low-cost security system application. (The images are for illustrative purposes only; please refer to the text for details.)

4.4(10)
15