零知派ESP32—— 基于ESP32 + ISD1820 远程监控PIR安防告警系统
项目概述
本项目加入了Wi-Fi与MQTT协议,实现了远程状态监控与告警推送。系统以ESP32为主控,通过SR505人体红外传感器(PIR)检测入侵,ISD1820语音模块播放自定义告警语音,ST7789彩色屏幕实时显示本地状态,同时通过MQTT将系统状态、PIR信号、告警事件等实时上报至云端(如EMQX公共代理),用户可使用手机或电脑上的MQTT客户端订阅主题,随时随地掌握现场动态。
核心功能:
-
本地功能:PIR入侵检测、语音告警播放、屏幕状态显示、LED指示、手动录音/测试。
-
新增远程功能:Wi-Fi自动连接,MQTT发布系统状态(online/arming/armed/alarm)、PIR电平变化、告警触发、录音开始/结束、系统启动信息等,实现远程监控与数据收集。
项目亮点
-
本地+远程双模监控:既保留本地实时响应,又支持远程查看状态,适合无人值守场景。
-
全流程MQTT上报:从启动预热、布防完成、入侵告警到录音操作,每个关键事件都会发布主题,便于集成到Home Assistant等智能家居平台。
-
自动重连与离线容错:WiFi连接超时后自动进入离线模式,MQTT断线后定时重试,不影响本地告警功能。
-
低代码扩展性:通过PubSubClient库轻松更换MQTT Broker或增加自定义主题。
-
实时PIR状态推送:PIR电平变化时即时发布主题,可用于远程查看环境活动情况。
项目难点及解决方案
| 难点 | 解决方案 |
|---|---|
| WiFi连接阻塞主循环 | 在setup()中使用10秒超时机制,连接失败则跳过,后续不再重试,保证系统快速启动。 |
| MQTT发布不阻塞告警 | 所有MQTT发布均为非阻塞调用(mqtt.publish立即返回),且mqtt.loop()仅在mqtt.connected()时执行,不影响主循环实时性。 |
| MQTT重连频率控制 | 使用静态变量lastTry,限制重连间隔不低于10秒,避免频繁重连消耗资源。 |
| 状态同步一致性 | 每次屏幕状态变化时,同步调用mqttPub()发布对应状态主题,确保远程与本地一致。 |
| 网络状态变化时界面不卡顿 | 将MQTT维护放在独立计时分支(每200ms执行一次),不影响屏幕刷新(200ms限频)和按键扫描。 |
目录
一、硬件系统部分
1.1 硬件清单
| 组件 | 型号/规格 | 数量 | 作用 |
|---|---|---|---|
| 开发板 | 零知派ESP32 | 1 | 主控,包含Wi-Fi/BLE |
| 扩展板 | 零知派ESP32扩展板 | 1 | 方便接线 |
| 红外传感器 | SR505 | 1 | 探测人体移动 |
| 语音模块 | ISD1820 | 1 | 录音/放音 |
| 显示屏 | ST7789(240×240) | 1 | 本地状态显示 |
1.2 接线方案
| ESP32 GPIO | 连接组件 | 功能说明 |
|---|---|---|
| GPIO 19 | ISD1820 REC |
录音触发 |
| GPIO 14 | ISD1820 PLAYE |
手动放音触发 |
| GPIO 27 | ISD1820 PLAYE |
告警触发输出(低电平脉冲) |
| GPIO 34 | SR505 OUT |
PIR数字信号输入 |
1.3 硬件连接图

1.4 实物连接图

二、软件架构设计
2.1 系统初始化流程
-
串口:115200 bps,调试输出。
-
Wi-Fi连接:尝试连接指定SSID,超时10秒,无论成功与否都继续执行(不影响本地功能)。
-
MQTT客户端:设置Broker地址和端口,连接成功后立即发布
status/online。 -
GPIO与屏幕初始化:配置引脚、启动TFT。
-
PIR预热:记录
warmMs,进入60秒倒计时。 -
LED闪烁:提示启动完成。
-
发布启动信息:
status/arming和info(含预热时长)。
2.2 主循环逻辑
loop():
1. 读取所有输入电平
2. 每200ms执行MQTT维护:
- 尝试重连(若断开且距上次尝试超过10秒)
- 若已连接,调用 mqtt.loop() 处理网络事件
3. 录音处理(边沿检测)—— 增加MQTT发布 record/start 和 record/end
4. 手动放音处理 —— 触发告警并发布 alarm 主题
5. PIR入侵检测(预热完成后):
- 上升沿触发告警,同时发布 status/alarm 和 alarm/1
- 每次PIR电平变化时发布 pir/HIGH 或 pir/LOW(供远程监控)
6. 告警结束处理 —— 恢复状态并发布 status/armed
7. 布防完成 —— 发布 status/armed 和 info/armed
8. 布防倒计时显示(与MQTT无关)
9. 更新按键历史电平,延迟10ms
三、代码拆分讲解
3.1 WiFi与MQTT配置
const char* WIFI_SSID = "zaixinjian";
const char* WIFI_PASS = "2020zaixinjian";
const char* MQTT_BROKER = "broker.emqx.io";
const int MQTT_PORT = 1883;
const char* MQTT_ID = "PIR_Alarm";
const char* MQTT_PREFIX = "pir_alarm";
-
MQTT_PREFIX作为所有主题的前缀,方便统一管理。 -
使用公共Broker
broker.emqx.io,无需注册即可测试。
发布函数:
void mqttPub(const char* subtopic, const char* payload) {
if (!mqtt.connected()) return;
char topic[64];
snprintf(topic, 64, "%s/%s", MQTT_PREFIX, subtopic);
mqtt.publish(topic, payload);
}
-
自动拼接前缀,调用时只需指定子主题和负载。
-
若MQTT未连接,静默跳过,不影响本地操作。
重连函数:
void mqttReconnect() {
if (mqtt.connected()) return;
static unsigned long lastTry = 0;
if (millis() - lastTry < 10000) return;
lastTry = millis();
if (mqtt.connect(MQTT_ID)) {
mqttPub("status", "online");
}
}
-
限制重连频率为10秒,避免Broker拒绝频繁连接。
-
连接成功后立即发布在线状态。
3.2 主循环中的MQTT维护
if (n - lastMqtt >= 200) {
lastMqtt = n;
mqttReconnect();
if (mqtt.connected()) mqtt.loop();
}
-
每200ms执行一次,确保及时处理网络事件,同时不影响主循环响应速度。
3.3 各事件点的MQTT发布
录音:
按下:
mqttPub("record", "start");松开:
mqttPub("record", "end");
告警触发(alarm()函数内):
mqttPub("status", "alarm");
mqttPub("alarm", "1");
PIR电平变化(在调试打印处):
if (ir != pirDbg) {
mqttPub("pir", ir == HIGH ? "HIGH" : "LOW");
}
-
每次电平变化时推送,便于远程了解环境活动。
布防完成:
mqttPub("status", "armed");
mqttPub("info", "armed");
告警结束:
if (warmMs == 0) {
scrNow("Armed", "System OK", ...);
mqttPub("status", "armed");
}
启动信息:
在setup()中发布 status/arming 和 info(含预热时长)。
3.4 屏幕显示与MQTT解耦
屏幕刷新逻辑与之前完全一致,MQTT发布是“附加动作”,不改变原状态机。这样做的好处是即使网络故障,本地功能依旧完好。
四、操作过程及数据展示
4.1 操作步骤
-
连接硬件:按接线图连接所有模块,确保ESP32供电(USB线或电池)。
-
配置WiFi:在代码开头修改
WIFI_SSID和WIFI_PASS为你自己的热点(若使用公共EMQX则无需改Broker)。 -
上传程序:使用零知派编译上传。
-
观察启动:
-
串口打印WiFi连接过程,成功后显示IP。
-
屏幕显示“Security Arming...”然后60秒倒计时。
-
MQTT连接成功后,串口输出“MQTT OK”。
-
-
订阅MQTT主题(使用任意MQTT客户端,如MQTTX、mosquitto_sub):
-
订阅
pir_alarm/#即可收到所有主题。 -
启动后你会看到
status/online,随后status/arming,以及info包含预热秒数。
-
-
录制语音:按住REC键说话,松开后屏幕显示保存,MQTT会收到
record/start和record/end。 -
等待布防:倒计时归零,屏幕显示“Armed System Armed”,同时MQTT收到
status/armed。 -
触发入侵:在PIR前移动,系统立即告警(语音+屏幕+LED),MQTT会收到
status/alarm、alarm/1,以及PIR电平变化pir/HIGH(若之前为LOW)。 -
手动测试:按下PLAY键,同样触发告警,MQTT也会发布相同告警主题。
-
远程监控:在任何地方打开MQTT客户端,即可实时看到系统状态,如是否布防、是否告警、当前PIR高低电平。
4.2 数据展示
| 主题 | 负载示例 | 触发时机 |
|---|---|---|
pir_alarm/status |
online, arming, armed, alarm |
系统启动、预热开始、布防完成、告警触发 |
pir_alarm/pir |
HIGH / LOW |
PIR输出电平每次变化时 |
pir_alarm/alarm |
1 |
告警触发时(仅触发时发布一次) |
pir_alarm/record |
start / end |
录音按键按下/松开 |
pir_alarm/info |
boot warmup=60s, armed 等 |
启动和布防完成时 |
你可以利用这些数据在Node-RED、Home Assistant中建立自动化,例如:当
status/alarm时发送手机通知。
4.3 视频演示
零知派ESP32—— 远程监控PIR安防告警系统
五、技术原理
5.1 工作原理
MQTT协议:轻量级发布/订阅消息协议,适用于低带宽、高延迟或不可靠网络环境。ESP32作为客户端,连接到Broker(如EMQX),发布主题,任何订阅该主题的客户端都能实时收到消息。
系统状态机结合MQTT:
-
系统状态(预热、布防、告警)通过
status主题对外广播。 -
PIR信号实时转发,可用于远程查看是否有活动。
-
告警事件单独使用
alarm主题,便于下游过滤和处理。
5.2 工作模式配置(含网络状态)
| 模式 | 本地表现 | MQTT行为 |
|---|---|---|
| 启动/离线 | 屏幕显示,但WiFi未连接 | 不发布,但定时重试 |
| 预热中 | 倒计时显示 | 发布status/arming和info |
| 布防完成 | 显示“Armed” | 发布status/armed和info/armed |
| 告警中 | 显示“INTRUSION!” | 发布status/alarm和alarm/1 |
| 录音中 | 显示“RECORD” | 发布record/start和record/end |
网络容错:若WiFi连接超时,系统仍然可以独立工作,MQTT发布会被跳过,但不会影响本地告警和屏幕显示,适合无网络环境使用。
六、常见问题指引
Q1:MQTT连接失败怎么办?
-
检查WiFi是否正常(串口会提示IP)。
-
确认MQTT Broker地址和端口正确,本例使用公共Broker
broker.emqx.io,无需账户。 -
若连接失败,系统会每隔10秒重试,不影响本地功能。
-
可在
mqttReconnect()中添加更多调试信息(如打印mqtt.state())。
Q2:如何更换MQTT Broker或添加认证?
-
修改
MQTT_BROKER和MQTT_PORT。 -
若需要用户名密码,使用
mqtt.connect(MQTT_ID, user, pass)重载函数,并在代码中定义相应常量。
Q3:MQTT订阅后收不到消息?
-
确认订阅主题前缀完全匹配(注意大小写)。
-
检查MQTT客户端是否成功连接Broker。
-
可开启EMQX Web管理界面查看实时消息流,或使用
mosquitto_sub -h broker.emqx.io -t "pir_alarm/#" -v测试。
Q4:如何关掉MQTT功能(纯本地模式)?
-
注释掉所有
mqttPub调用和#include <WiFi.h>、#include <PubSubClient.h>,以及setup()中的WiFi/MQTT初始化代码,即可回归纯本地版本。
更多推荐

所有评论(0)