A burning candle is cosy, but it should never be forgotten. This candle guard keeps an eye on it. The flame sensor sees the infrared light that every flame gives off, even from 20 cm away. When you light the candle, the green LED comes on and a timer starts. After 30 minutes, the buzzer beeps and the red LED blinks to remind you to blow it out. When the candle goes out, it tells you how long it burned. And if the flame suddenly gets much bigger, the alarm sounds at once. Only light candles with an adult, and never leave a candle alone, even with the guard.
What you'll learn
- How a flame sensor sees the infrared light of a flame
- How to measure the room's light first, so the sensor ignores it
- How to count minutes with millis()
- How to tell three situations apart: no flame, normal flame and flare-up
What you need
- UNO R3 board and USB cable (UNO R3 Starter Kit)
- Flame sensor module (45-in-1 Sensor Kit)
- Active buzzer module (45-in-1 Sensor Kit)
- Red LED, green LED and 2 resistors, 220 Ω (UNO R3 Starter Kit)
- A tea light in a metal or glass holder, matches or a lighter, and an adult
- The printed parts from the 3D printing box below (sensor stand), or the cardboard version described there
- Breadboard and jumper wires (UNO R3 Starter Kit)
Wiring

| From | To |
|---|---|
| Flame sensor AO | UNO pin A0 |
| Flame sensor G and + | GND and 5V |
| Flame sensor DO | Not used |
| Buzzer module S | UNO pin 8 |
| Buzzer module + and − | 5V and GND |
| UNO pin 9 | 220 Ω resistor, then the red LED's long leg |
| UNO pin 10 | 220 Ω resistor, then the green LED's long leg |
| Both LED short legs | GND |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
Sunlight and some lamps also give off infrared light. Use the guard indoors, away from a sunny window.
The sketch
Start the sketch with the candle not lit: for the first two seconds it measures the room.
const int FLAME_PIN = A0;
const int BUZZER_PIN = 8, RED_PIN = 9, GREEN_PIN = 10;
const int LIT = 60; // this much above the room means a flame
const int FLARE = 3; // 3 times the normal flame is a flare-up
const unsigned long REMIND_MINUTES = 30;
int room = 0; // the reading with no flame
bool candleOn = false;
unsigned long litAt = 0, lastSeen = 0, flareSince = 0, lastBeep = 0;
long normal = 0; // the flame's usual strength
// Flame strength: how far the reading is from the room's reading
int flame() {
long sum = 0;
for (int i = 0; i < 10; i++) sum += analogRead(FLAME_PIN);
return abs(sum / 10 - room);
}
void setup() {
Serial.begin(9600);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
long sum = 0;
for (int i = 0; i < 200; i++) { // measure the room for 2 seconds
sum += analogRead(FLAME_PIN);
delay(10);
}
room = sum / 200;
Serial.print("Room level: ");
Serial.println(room);
}
void loop() {
int f = flame();
Serial.println(f); // open the Serial Plotter to see the flame flicker
unsigned long now = millis();
if (f > LIT) {
lastSeen = now;
if (!candleOn) { // the candle has just been lit
candleOn = true;
litAt = now;
normal = f;
}
normal = (normal * 49 + f) / 50; // slow average of the flame's strength
}
if (candleOn && now - lastSeen > 3000) { // no flame for 3 s: it went out
candleOn = false;
Serial.print("The candle burned for ");
Serial.print((now - litAt) / 60000);
Serial.println(" minutes.");
}
bool flare = candleOn && f > normal * FLARE && now - litAt > 10000;
if (flare) {
if (flareSince == 0) flareSince = now;
} else {
flareSince = 0;
}
bool alarm = flareSince != 0 && now - flareSince > 1000; // big for more than 1 s
bool remind = candleOn && now - litAt > REMIND_MINUTES * 60000;
digitalWrite(GREEN_PIN, candleOn && !remind && !alarm);
digitalWrite(RED_PIN, alarm || (remind && (now / 500) % 2));
if (alarm) {
digitalWrite(BUZZER_PIN, (now / 150) % 2); // fast beeping
} else if (remind && now - lastBeep > 10000) { // a short beep every 10 s
digitalWrite(BUZZER_PIN, HIGH);
delay(150);
digitalWrite(BUZZER_PIN, LOW);
lastBeep = now;
} else {
digitalWrite(BUZZER_PIN, LOW);
}
delay(50);
}
Try it
- Upload with the candle unlit. Open the Serial Plotter (Tools menu) at 9600 baud: a flat line near 0.
- Ask an adult to light the tea light 20 cm in front of the sensor. The line jumps up and wobbles as the flame flickers, and the green LED lights.
- To test the reminder without waiting half an hour, change
REMIND_MINUTESto 1 and upload again. - Blow out the candle: after three seconds the green LED goes off and the Serial Monitor says how long it burned.
How it works
Flames give off lots of infrared light, which our eyes can't see. The dark bulb on the module is an infrared receiver, and its AO pin gives a voltage that changes with the amount of infrared it sees. On some modules the number goes up with a flame, on others it goes down. That is why the sketch measures the room first and only looks at the difference with abs(), which is always positive.
A candle flickers, and for a moment the reading can dip. So the candle only counts as "out" when no flame has been seen for three seconds.
The sketch learns how strong the flame normally is with a slow average, normal. If the reading stays three times higher than that for more than a second, something is wrong: a flare-up, or something else that has caught fire. The first ten seconds are ignored, while the match and the new flame settle down.
Try this next
- Show the minutes the candle has burned on the 1602 LCD.
- Measure how the reading changes at 10, 20, 30 and 40 cm, and draw a graph. How does the light get weaker with distance?
- Add a second reminder after 45 minutes with a longer beep.
Troubleshooting
- The green LED lights without a candle: sunlight or a lamp is shining on the sensor. Turn the stand away from windows and restart.
-
It doesn't notice the candle: bring it a little closer, or make
LITsmaller. Watch the Serial Plotter to choose a good value. -
The alarm sounds for a normal flame: the flame was small when it was lit. Raise
FLAREto 4. - A printed part is too tight or too loose: printers differ by a few tenths of a millimetre. Sand or file a tight hole, and fix a loose part with a drop of hot glue or a strip of tape.