💡 划重点
- 今日目标:在 25 元预算内,制作一块可贴在车库内墙上的「车库门远程状态卡片」,通过 MQTT 将门状态推送到手机。
- 主控选型:ESP8266(NodeMCU / D1 Mini 皆可),成本低、自带 Wi-Fi,适合家庭局域网场景。
- 传感原理:磁簧开关固定在门框,磁铁贴在活动门板,门开/合对应开关通断。
- 低耗核心:GPIO2 中断唤醒 + 深度睡眠(Deep Sleep),常态工作电流可降至 uA 级,两节 5 号电池可续航数月。
- 网络协议:MQTT QoS 0 即可(家庭局域网状态提示,丢包影响极小),Broker 可用部署在树莓派或旧路由器上的 Mosquitto。
- 成本控制重点:ESP8266 探针板用裸片模组(ESP-12F)而非完整开发板,可将核心物料压在 25 元内。若选用现成 D1 Mini 开发板(约 10 元),总价也仍在 25 元内。
需求洞察
目标用户:家里有独立车库、经常出门后不确定「到底锁了没」的粗心健忘人群,以及有老人小孩的家庭(担心门没关进猫狗或小孩跑出去)。
真实痛点:
- 车库门不是入户门,没有自动上锁,经常是手动拉下但没确认是否完全合拢。
- 车开出几百米后,心里不安:车库门关了吗?赶回家看一眼,结果发现关了,来回耗油费鞋。
- 市面上智能车库门改造方案(智能锁、摄像头识别)动辄一两百元起步,还依赖云 App 账号,长期用则需要续费或绑设备,对自建家庭的 Homelab 或 Home Assistant 用户不够友好。
为什么值得做:
- 用 25 元成本解决「远程确认一个二值状态」的刚需,不引入视频流、不引入大厂云,数据自持。
- 基于 ESP8266 + MQTT,可直接接入 Home Assistant / Node-RED,后续扩展「离家布防时门未关就手机弹强提醒」这类自动化,生产价值相当可观。
- 低耗休眠 + 电池供电在实践上可行,不是做 demo 半天的教学板,而是能连续运行数月的一件实用装置。
方案设计
整体逻辑为「磁簧感知开合 → 主控中断唤醒 → LED 本地反馈 → MQTT 上报 → 休眠等待下事件」。
感知层(信息采集)
- 磁簧开关作为唯一传感元件,常态为常开(门关合时磁铁靠近,触点闭合)。
- 软件启用 GPIO2 的 CHANGE 中断,并配置 GPIO16 与 RST 连接,配合
ESP.deepSleep()实现外部事件唤醒。
控制层(状态解析与去抖)
- MCU 被中断唤醒后不立即上报,先延时 20ms 读取三遍电平做防抖动,排除门关合瞬间的机械抖动。
- 定义
DOOR_CLOSED/DOOR_OPEN两态,状态变化时才发消息,若唤醒后发现状态与上次一致,则立即返回休眠,避免风暴消息。
执行层(本地反馈)
- LED 接 GPIO0,门状态为 OPEN(磁簧断开)时长亮,CLOSED(磁簧闭合)时熄灭。
- 配合短暂 PWM 闪烁动作做「事件确认」,例如开、合瞬间各闪一次,让用户在现场即可感知装置工作正常。
日志/联网层
- Wi-Fi Station 模式连接家庭 2.4G 网络,MQTT Client ID 使用芯片 MAC 末两字节,Topic:
home/garage/door/state。 - 上报 Payload 采用
{"state":"closed","ts":1893456000}结构,带 Unix 时间戳(用内部 RTC 校准,局域网精度足够),方便日志端留存状态变化历史。 - 为控制休眠功耗,每一次唤醒只在 MQTT 发布完成后连接断开,立即进入 deep-sleep,不保持长连接也不主动订阅。
物料清单
| 物料 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|
| ESP-12F 模组 / D1 Mini 开发板 | 1 | 主控与 Wi-Fi | 8.0(模组)或 10.0(开发板) |
| 磁簧开关(常开型,玻璃管或塑封) | 1 | 门状态感知 | 1.5 |
| 小号钕磁铁(直径10mm) | 1 | 与磁簧配合触发 | 1.0 |
| 5mm 红色 LED | 1 | 状态指示 | 0.1 |
| 1kΩ 电阻 | 2 | LED 限流与保护 | 0.1 |
| 4.7kΩ 上拉电阻 | 1 | GPIO2 中断输入稳定 | 0.05 |
| 1N5819 肖特基二极管 | 1 | 电池防反接 | 0.2 |
| 3.7V 锂电池(或 2xAA 电池盒) | 1 | 供电 | 5.0(锂电池)或 1.0(电池盒) |
| PCB 洞洞板 / 免焊面包板 | 1 | 固定元件 | 2.0 |
| 杜邦线或细导线 | 若干 | 接线 | 1.5 |
| 塑料外壳/热缩管 | 1 | 封装绝缘 | 2.0 |
| 3D 打印门夹支架(可选) | 1 | 固定磁簧与磁铁(可不做,用胶固定) | 0(或 3.0) |
| 合计 | — | — | 约 21.45 元(不含 3D 打印),满足 ≤25 元 |
接线与结构
GPIO 分配如下(基于 ESP8266 D1 Mini 引脚定义):
- 磁簧开关一头接 GPIO2(D4),另一头接 GND。
- GPIO2 内部配置
INPUT_PULLUP,磁簧闭合即拉低,断开即恢复高电平。 - LED 正极串 1kΩ 电阻后接 GPIO0(D3),负极接 GND。
- GPIO16(D0) 用短跳线连接 RST 引脚,以支持
ESP.deepSleep(0)外部唤醒。 - 供电使用锂电池通过板载 3.3V LDO 进入系统。
结构建议:
- 将 ESP8266 与外围电路封装在车库内墙侧的一个塑料小盒中,磁簧开关外引两根导线,另一端固定在门框边缘。
- 钕磁铁用 3M VHB 胶贴在门板边缘,与磁簧对齐(间距≤10mm 保证触发可靠)。
- 天线区域(PCB 上金属屏蔽罩附近)不要被金属遮挡,否则 Wi-Fi 信号衰弱明显。
说明:原任务建议 GPIO0 连接 LED、GPIO2 连接磁簧,未改动。仅在供电上增加了锂电池方案,替代直连 USB,以配合休眠低功耗目标。
核心代码
使用 Arduino 框架,平台选择 esp8266 by ESP8266 Community,可编译运行。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
// 停库门状态卡片 v1.0 —— Low-power MQTT Sensor
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
const char* mqtt_server = "192.168.x.x";
const int mqtt_port = 1883;
const int REED_PIN = 2; // GPIO2 -> D4
const int LED_PIN = 0; // GPIO0 -> D3
bool last_state;
bool current_state;
WiFiClient espClient;
// 简单防抖读取
bool readReedDebounced() {
int counter = 0;
for (int i=0; i<5; i++) {
if (digitalRead(REED_PIN) == LOW) counter++;
delay(2);
}
return (counter >= 3); // true表示门关(磁簧闭合=接地=LOW)
}
void publishState(bool doorClosed) {
if (!client.connected()) {
// 尝试快速连接,若失败则直接休眠,不反复重试
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(100);
attempts++;
}
if (WiFi.status() != WL_CONNECTED) {
ESP.deepSleep(0); // 无法联网则不打扰,等下个事件唤醒再试
delay(100);
}
client.connect("garage_card");
}
if (client.connected()) {
if (doorClosed) {
client.publish("home/garage/door/state", "{\"state\":\"closed\"}");
} else {
client.publish("home/garage/door/state", "{\"state\":\"open\"}");
}
client.disconnect();
}
}
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// 初次上电记录初始状态(首次建议不要直接休眠,稍亮LED提示)
last_state = readReedDebounced();
digitalWrite(LED_PIN, !last_state); // 门开亮灯,门关灭灯
delay(100);
publishState(last_state);
// 第一次刚上电,也同步进休眠等待外部事件
// 设置GPIO2为下降沿和上升沿都唤醒
// Deep sleep等待外部中断唤醒:时间为0表示由外部事件唤醒
ESP.deepSleep(0);
}
void loop() {
// 在中断唤醒后loop会执行,但这里不会再走到,因为setup末尾直接sleep
// 为保证极端情况的兼容性,也加入处理
current_state = readReedDebounced();
if (current_state != last_state) {
last_state = current_state;
digitalWrite(LED_PIN, !last_state);
publishState(last_state);
}
// 处理完成立刻再睡
ESP.deepSleep(0);
}
编译时需在 Board 选项中选择 LOLIN(WEMOS) D1 mini Lite 并禁用 VTABLES_IN_FLASH(无必要,保持默认即可)。
调试步骤
- 静态输入测试:先不焊磁簧,用杜邦线直接短接 GPIO2 到 GND,观察 LED 是否变化(GPIO0输出高亮 / 低灭)。若不能触发,检查上拉是否失效或引脚短路。
- 串口调试(此方案为了省电不加串口台打印,可临时加):可在 setup 中加 2 行
Serial.begin(74880)和Serial.println观察状态解析是否准确。 - MQTT 连通性测试:电脑上用
mosquitto_sub -h 192.168.x.x -t 'home/garage/door/state'订阅,再用磁铁靠近或移开磁簧,几秒内应能看到{"state":"..."}消息,且两次消息之间不会出现重复发送。 - 防抖验证:快速来回摆动磁簧(每秒两三次),看 Topic 是否出现撕裂不清的乱序消息。若出现多次抖动上报,可将防抖循环中的延时调大至 5ms×5 次或改用软件去抖算法。
- 功耗实测:万用表电流档串入电池正极,休眠时电流应低于 20uA(排除 LED 电流);触发后瞬时峰值约 150~300mA(Wi-Fi 发射),持续时间不超过 1s。若休眠电流过大,说明 GPIO 上拉漏电或 LDO 空载耗材。
- 安装距离测试:装到车库后(磁铁离磁簧约 10mm),反复开关门 10 次,确认每次状态变化均能远程收到,中间不能有超过 2 次漏报(低概率可容忍,可通过保证对齐调整)。
- 长时间稳定性:连续跑 48 小时,抽查 Broker 日志看异常掉线或重复连接情况,若有频繁 reconnect,需检查 Wi-Fi 信号强度(ESP 天线朝向和金属门框干扰)。
设计图
车库门远程状态卡片结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报
图中数据流方向为:感知输入(磁簧开合)→ 控制处理(ESP8266 中断唤醒 → 去抖 → 状态变判定)→ 执行反馈(LED 点亮/熄灭) + 数据上报(MQTT Topic 推送至手机/Home Assistant)。休眠模式从控制处理节点回流指向上电启动与低功耗调度,形成事件驱动的节能循环。