Build a candle guard with the flame sensor

The flame sensor watches a tea light from a safe distance. It notices when the candle is lit and when it goes out, reminds you to blow it out after 30 minutes, and sounds the alarm if the flame suddenly...
  • Level:Beginner
  • Duration: 45 min
  • Ages 10+
  • Platform: Arduino

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a candle guard with the flame sensor – EEMENTOR STEM™ lesson

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

Breadboard wiring diagram: Build a candle guard with the flame sensor
Breadboard view. Check each connection against the wiring table below.
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

  1. Upload with the candle unlit. Open the Serial Plotter (Tools menu) at 9600 baud: a flat line near 0.
  2. 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.
  3. To test the reminder without waiting half an hour, change REMIND_MINUTES to 1 and upload again.
  4. 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 LIT smaller. 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 FLARE to 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.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

45-in-1 Sensor Kit | Compatible with Arduino IDE and ESP32 $37.00

Shop the kit