The flame sensor sees the infrared light given off by flames. In this lesson the ESP32 shows its reading live in the Blynk app, sounds a buzzer when it detects a flame, and sends a notification to your phone. A silence button in the app stops the buzzer while you deal with it. This is a learning project about sensors and alerts, not a certified fire or smoke alarm.
What you'll learn
- How to use a sensor's analog and digital outputs together
- How to show an alarm state with an LED widget
- How to silence an alarm remotely until it clears
- How to test a sensor safely
What you need
- ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
- Flame sensor module (45-in-1 Sensor Kit)
- Active buzzer (ESP32 IoT Starter Kit)
- Breadboard and jumper wires (ESP32 IoT Starter Kit)
- A free Blynk account and the Blynk IoT app on a phone
- A 2.4 GHz Wi-Fi network
Safety first
Only test with a flame if an adult is with you, using a single lighter or candle, well away from paper and the electronics. Many flame sensors also react to the infrared LED in a TV remote: point it at the sensor and hold a button. Try that first.
Wiring

| From | To |
|---|---|
| Flame module AO | ESP32 GPIO 34 |
| Flame module G | GND |
| Flame module + | 3V3 |
| Flame module DO | ESP32 GPIO 35 |
| Buzzer + (long leg) | ESP32 GPIO 26 |
| Buzzer − | GND |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
Set up Blynk
In the Blynk console, create a new template called Flame alarm (hardware ESP32, connection type Wi-Fi) and add these datastreams. Lesson 1 shows each step in detail.
| Virtual pin | Name | Data type | Range | Phone widget |
|---|---|---|---|---|
| V0 | Flame level | Integer | 0 – 100, units % | Gauge |
| V1 | Alarm | Integer | 0 – 1 | LED |
| V2 | Silence | Integer | 0 – 1 | Button (push mode) |
Then open the template's Events & Notifications tab, add an event with the code fire_alert (name: Flame detected) and turn on push notifications for it. The event code must match the sketch exactly.
Save the template, create a new device from it and copy its three BLYNK_… lines. In the phone app, open the device, tap the wrench icon and add a Gauge (V0), an LED widget (V1) and a Button in push mode (V2). Link each widget to its datastream.
Set the threshold
The module has a small knob and a signal LED. In normal room light, turn the knob until the signal LED is just off. Then the TV remote or a flame switches it on.

The sketch
Replace the three BLYNK_… lines at the top with the ones from your device's Device info page, and add your Wi-Fi name and password (2.4 GHz only). The BLYNK_… lines must stay above #include <BlynkSimpleEsp32.h>.
Some versions of this module switch their output to HIGH when they trigger, others to LOW. The sketch reads the output when it starts (keep things still for a moment) and treats any change from that resting state as a trigger, so it works with both.
#define BLYNK_TEMPLATE_ID "YOUR_TEMPLATE_ID"
#define BLYNK_TEMPLATE_NAME "Flame alarm"
#define BLYNK_AUTH_TOKEN "YOUR_AUTH_TOKEN"
#define BLYNK_PRINT Serial // show connection messages in the Serial Monitor
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char ssid[] = "YOUR_WIFI_NAME";
char pass[] = "YOUR_WIFI_PASSWORD";
const int LEVEL_PIN = 34; // analog: how much infrared light
const int FLAME_PIN = 35; // digital: above the knob's threshold?
const int BUZZER_PIN = 26;
BlynkTimer timer;
int restState;
bool alarm = false;
bool silenced = false;
unsigned long lastAlert = 0;
bool alertedOnce = false;
BLYNK_WRITE(V2) {
if (param.asInt() == 1 && alarm) {
silenced = true;
Serial.println("Silenced from the app");
}
}
void sendLevel() {
int raw = analogRead(LEVEL_PIN);
int level = map(raw, 4095, 0, 0, 100); // more infrared = lower reading
Blynk.virtualWrite(V0, constrain(level, 0, 100));
}
void checkFlame() {
bool flame = digitalRead(FLAME_PIN) != restState;
if (flame && !alarm) { // the alarm starts
alarm = true;
silenced = false;
Blynk.virtualWrite(V1, 1);
if (!alertedOnce || millis() - lastAlert > 60000) {
Blynk.logEvent("fire_alert", "Flame detected!");
lastAlert = millis();
alertedOnce = true;
}
}
if (!flame && alarm) { // the flame is gone
alarm = false;
Blynk.virtualWrite(V1, 0);
}
bool beep = alarm && !silenced && (millis() / 250) % 2;
digitalWrite(BUZZER_PIN, beep);
}
void setup() {
Serial.begin(115200);
pinMode(FLAME_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
delay(300);
restState = digitalRead(FLAME_PIN);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
Blynk.virtualWrite(V1, 0);
timer.setInterval(50L, checkFlame);
timer.setInterval(1000L, sendLevel);
}
void loop() {
Blynk.run();
timer.run();
}
How it works
The module gives two signals. AO is analog: the more infrared light reaches the sensor, the lower the voltage, and the sketch turns it into a 0–100 % level for the gauge once per second. DO is digital: the module's comparator switches it when the light passes the threshold you set with the knob. The sketch uses DO for the alarm, checked 20 times a second, because a fixed threshold is easy to tune by hand. The LED widget on V1 shows the alarm state, and Silence only stops the buzzer until the flame is gone. The next flame starts the alarm again.
Try this next
- Add the second relay channel to switch a low-voltage fan or light when the alarm sounds.
- Show the time of the last alarm in a Value Display.
- Use the analog level instead of DO, with a threshold slider in the app.
Troubleshooting
-
The device shows "Offline" in the app: check the Serial Monitor at 115200 baud. "Invalid auth token" means the
BLYNK_AUTH_TOKENline is wrong; if it never connects, check the Wi-Fi name and password, and that your network is 2.4 GHz. - The alarm goes off in sunlight: sunlight contains a lot of infrared. Turn the knob to make the module less sensitive, and keep it out of direct sun.
- Nothing reacts to a flame or remote: turn the knob the other way until the signal LED reacts.
-
The gauge works the wrong way round: swap
4095, 0to0, 4095in themap()line.