💡 划重点
- 双重感知:MQ-2烟雾传感器 + 火焰传感器同采,防止单点漏报。
- 本地蜂鸣告警:高分贝蜂鸣器直接警示,不受WiFi断连影响。
- Server-Sent Events (SSE):ESP32作为HTTP服务器推送实时状态,手机/PC无需刷新即可看到报警信息。
- 硬件成本严控:总物料开销≤55元,内置状态灯,不需要额外网关。
需求洞察
目标用户:老旧小区厨房、小餐饮后厨、独居老人及厨房临时离人家庭。
真实痛点:厨房火灾多数源于油锅过热起火或燃气泄漏,但很多人炒菜时临时接电话、拿快递而离开灶台,回来时火已窜起。传统烟雾报警器安装在客厅,距离厨房远,且无法区分油烟与火灾烟雾,误报率高,极易被断电丢弃。
为什么值得做:直接用ESP32搭建近火源报警节点,双传感器互相校验:火焰传感器先于烟雾检测到骤亮与红外变化,MQ-2再验证可燃气体或浓烟浓度,只有两者同时触发才鸣响蜂鸣器,大幅降低炒菜油烟误报。同时以SSE推送到家人手机,即便在卧室也能立即得知险情,真正实现“灶台级”防护,用极低成本弥补市场产品短板。
方案设计
感知层
- MQ-2半导体烟雾传感器:对液化气、丙烷、氢气及烟雾敏感,模拟输出接入ESP32 ADC。预热后,输出0~3.3V对应洁净空气到高浓度烟雾。
- 火焰传感器(红外接收模块):检测760nm~1100nm红外光,输出模拟量,有火源时电压明显下降。通过35脚采集。
- 两个模拟量持续采集,每200ms一次,滑动窗口滤波排除瞬时抖动。
控制层
ESP32主控运行FreeRTOS双任务:采样任务读取两个ADC,进行阈值比较;通信任务维持WiFi连接并运行SSE服务器。当火焰传感器读数超过阈值(例如<1.5V)且MQ-2超过阈值(>2.0V),判定为真实火情,触发报警标志。报警标志自锁,只有通过板载按钮清零或重新上电。
执行层
- 蜂鸣器由GPIO27驱动,NPN三极管扩流,输出3.3kHz~4kHz脉冲音频,声压级≥85dB。
- 状态灯(GPIO2):待机时慢闪(1秒周期),报警时快闪(200ms周期),便于视觉确认。
日志/联网层
ESP32工作在AP+STA或纯STA模式,连接家中路由器。建立一个HTTP服务器,提供/events路由,每次有状态变化(正常→报警)时推送JSON事件。手机浏览器访问ESP32 IP即可看到实时报警页面,无需安装APP。事件格式:data: {"smoke": 2.8, "flame": 0.9, "alarm": true}\n\n。同时可通过串口打印日志,用于调试。
物料清单
| 名称 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|
| ESP32-WROOM-32D开发板 | 1 | 主控+WiFi | 18 |
| MQ-2烟雾传感器模块 | 1 | 烟雾/可燃气体检测 | 8 |
| 火焰传感器模块(红外) | 1 | 明火探测 | 5 |
| 有源蜂鸣器模块(5V) | 1 | 报警音 | 3 |
| 红色LED(5mm) + 220Ω电阻 | 1 | 状态指示 | 0.5 |
| NPN三极管S8050 + 1kΩ基极电阻 | 1 | 蜂鸣器驱动 | 0.5 |
| 面包板 + 公母杜邦线 | 1套 | 免焊接线 | 10 |
| Micro USB数据线+5V充电头 | 1 | 供电 | 8 |
| 合计 | 53 |
剩余预算2元可用于外壳或热缩管,满足55元内要求。
接线与结构
使用给定IO完全可行,无需修改。
- MQ-2 A0 → GPIO34(ADC1_CH6),VCC接5V,GND共地。注意模块必须5V供电以保证加热电压,但模拟输出兼容3.3V。
- 火焰传感器 A0 → GPIO35(ADC1_CH7),VCC接3.3V,GND共地。
- 蜂鸣器正极 → 通过S8050驱动接GPIO27:GPIO27→1kΩ→三极管基极;三极管集电极接蜂鸣器负,蜂鸣器正直接5V;发射极接地。模块自带震荡的则跳过三极管直接接IO,但建议加三极管以增大音量。
- 状态灯LED阳极 → GPIO2,串联220Ω→GND。因为GPIO2内部LED可能复用,用外接更亮。
- 共同GND:所有模块地线与ESP32 GND可靠连接。
- 上电前检查ADC输入电压不得超过3.3V,MQ-2模块一般有分压电阻输出,安全。
结构上,传感器模块尽量贴近烟源,可用铜柱固定面包板,阻燃外壳开窗,保证气流与红外穿透。
核心代码
以下给出简化但可编译的PlatformIO骨架,使用Arduino框架。滤除了SSE细部路由以突出重点逻辑,完整代码可在绑定异步TCP库后补充。
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
const int SMOKE_PIN = 34;
const int FLAME_PIN = 35;
const int BUZZER_PIN = 27;
const int LED_PIN = 2;
const float SMOKE_THRESH = 2.0; // 电压阈值(V)
const float FLAME_THRESH = 1.5; // 电压低于此表示有火
AsyncWebServer server(80);
AsyncEventSource events("/events");
bool alarmActive = false;
unsigned long lastSample = 0;
void setup() {
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
Serial.begin(115200);
WiFi.begin("SSID", "PASS");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // 连接中快闪
}
digitalWrite(LED_PIN, LOW);
events.onConnect([](AsyncEventSourceClient *client){
client->send("{\"status\":\"connected\"}",NULL,millis());
});
server.addHandler(&events);
server.begin();
}
void loop() {
if (millis() - lastSample > 200) {
lastSample = millis();
float smokeV = analogRead(SMOKE_PIN) * 3.3 / 4095.0;
float flameV = analogRead(FLAME_PIN) * 3.3 / 4095.0;
bool fireDetected = (smokeV > SMOKE_THRESH) && (flameV < FLAME_THRESH);
if (fireDetected && !alarmActive) {
alarmActive = true;
String json = "{\"smoke\":" + String(smokeV,2) +
",\"flame\":" + String(flameV,2) +
",\"alarm\":true}";
}
if (alarmActive) {
digitalWrite(LED_PIN, millis() % 200 < 100 ? HIGH : LOW); // 快闪
} else {
digitalWrite(LED_PIN, millis() % 1000 < 500 ? HIGH : LOW); // 慢闪
}
}
delay(1);
}
注:实际部署需将SSID/PASS填入,并安装ESPAsyncWebServer与AsyncTCP库。events.send保证浏览器SSE客户端实时展示报警数据。
调试步骤
- 供电检查:用USB线供电,测量面包板上5V与3.3V,确保无短路。MQ-2模块加热灯渐亮至稳定。
- ADC零值校准:上电后打开串口监视,观察未点火时烟雾电压常值(通常0.3~1V),火焰传感器电压在3.0V左右。若MQ-2读数高于1.5V,传感器需要预热3分钟。
- 模拟报警:用打火机火焰靠近火焰传感器2cm,火焰电压应快速降至1V以下;同时用灭烟产生的烟雾接近MQ-2,烟雾电压升高至2.5V以上。两者同时满足时蜂鸣器必须响,串口打印ALARM TRIGGERED。
- SSE连通性:手机连接同一WiFi,浏览器访问
http://esp32_ip/,需看到初始连接数据。触发报警时页面应自动更新JSON并变红提示。 - 阈值微调:根据实测数据修改SMOKE_THRESH与FLAME_THRESH,保留一定裕度,避免油烟触发烟雾阈值。建议烟雾阈值设为平常值的2.5倍。