💡 划重点
- 零接触感知:利用磁簧开关检测车库门的开闭,无需触碰门体,避免机械磨损。
- 极低功耗:ESP8266 通过深度睡眠 + 定时唤醒上报,单颗 18650 电池预计可运行半年。
- 即时通知:门状态变化时立即唤醒并通过 MQTT 推送到手机,延迟低于 2 秒。
- 极致成本:总物料成本控制在 25 元以内,让每个家庭都能低成本实现车库安防升级。
- 隐私安全:数据不经过第三方云端,全部走自建 MQTT Broker,家庭内网闭环。
需求洞察
目标用户
- 普通家庭:尤其是有独立车库的住户,每天进出频繁,经常忘记是否关门。
- 安防敏感人群:需要实时掌握家中入口状态,防止半夜车库门被异常打开。
- 智能家居爱好者:希望用最低成本扩展原有系统,不依赖昂贵成品传感器。
真实痛点
- 记忆负担:匆忙出门或深夜回家后,反复怀疑“车库门关了吗”,被迫返回确认。
- 状态盲区:传统车库门没有任何远程反馈,人不在家时完全无法知晓门的开闭。
- 昂贵方案:品牌安防传感器动辄百元起步,且通常需要网关,整体投入过高。
- 布线困难:车库往往离主屋较远,有线方案施工麻烦,无线电池方案更换频繁。
为什么值得做
- 成本低到可忽略:25 元几乎等同于一杯咖啡的价格,却能解决长期的家庭安防焦虑。
- 技术门槛低:基于 ESP8266 和 MQTT 的开发生态极其成熟,一天内可完成制作。
- 贴近真实场景:磁簧开关的非接触式检测天然适合各种门体,可靠性远高于红外对射。
- 可复制性强:方案稍加改动就能用于窗户、抽屉、保险柜等任何开合结构。
方案设计
感知层
- 磁簧开关:干簧管与永磁体分体安装,门关闭时磁体靠近使干簧管闭合,GPIO2 读到低电平;门打开时磁体远离,干簧管断开,GPIO2 被内部上拉至高电平。
- 消抖处理:硬件上并联 0.1μF 电容过滤簧片抖动,软件上做 50ms 确认窗口,避免单次抖动误报。
- 中断唤醒:GPIO2 配置为下降沿和上升沿双重中断,将 ESP8266 从深度睡眠中唤醒,实现事件驱动上报。
控制层
- 主控 ESP8266:作为数据采集、逻辑判断和无线通信的核心,Arduino IDE 编程。
- 工作模式:90% 时间处于深度睡眠状态(功耗约 20μA),门状态变化通过中断引脚唤醒,同时保留每 60 分钟的定时心跳上报,确保设备在线。
- 状态机:记录上一次门状态,唤醒后比对,只有发生变化才连接 WiFi 并发送 MQTT 消息,进一步减少功耗。
执行层
- LED 指示:GPIO0 连接一颗红色 LED,用 220Ω 限流。唤醒后快闪三次表示准备连接,常亮 2 秒表示上报成功,若失败则慢闪。
- 本地复位:GPIO0 同时复用为按键,长按 5 秒触发恢复出厂设置,清除 WiFi 凭据并重置 MQTT 主题。
日志 / 联网层
- MQTT 通信:Publish 主题
garage/door/state,内容CLOSED或OPEN,Retain 置 1,使任何客户端上线都能立即获取最后状态。 - 心跳保活:每 60 分钟发布一次
garage/device/heartbeat,Payload 为电池电压(通过 ADC 读取内部参考),方便维护。 - 接入 HomeAssistant:通过 MQTT Discovery 自动注册为 Binary Sensor,无需手动配置实体。
物料清单
| 物料名称 | 数量 | 用途 | 估算单价(元) | 小计(元) |
|---|---|---|---|---|
| ESP8266 开发板 (ESP-12F 最小系统) | 1 | 主控及 WiFi 通信 | 9.5 | 9.5 |
| 磁簧开关 (常开型干簧管模块) | 1 | 检测门状态 | 1.8 | 1.8 |
| 18650 锂电池 (2600mAh) | 1 | 系统供电 | 6.0 | 6.0 |
| TP4056 充电保护模块 | 1 | 电池充放电管理 | 1.5 | 1.5 |
| 红色 LED (5mm) | 1 | 状态指示 | 0.2 | 0.2 |
| 220Ω 电阻 | 1 | LED 限流 | 0.1 | 0.1 |
| 洞洞板 (3x7cm) | 1 | 电路焊接载体 | 0.5 | 0.5 |
| 热缩管、排针、导线 | 若干 | 连接与绝缘 | 1.0 | 1.0 |
| 3D 打印外壳 / 亚克力片 | 1 | 保护电路 | 3.0 | 3.0 |
| 合计 | 23.6 |
总物料成本 23.6 元,未包含焊锡、工具折旧,符合 25 元内预算要求。
接线与结构
硬件接线
- 磁簧开关:信号线接 GPIO2 (D4),VCC 与 GND 由开发板 3.3V 引脚供电。GPIO2 内部开启上拉,常态高电平,闭合时为低。
- LED 指示:阳极串联 220Ω 电阻接 GPIO0 (D3),阴极接地。GPIO0 低电平时 LED 点亮。
- 电池与充电:18650 电池正极接 TP4056 的 BAT+,输出分别连到 ESP8266 的 VIN (5V 引脚,板载稳压) 和 GND。注意 ESP8266 的 3.3V 引脚不能反向供电。
接线微调理由:方案中 LED 使用 GPIO0,该引脚启动时为高电平,恰好让 LED 在非控制状态保持熄灭。同时利用其内部已存在的上拉,外部无需额外电阻,简化 BOM。
安装结构
- 将 ESP8266、TP4056、LED、电阻焊接在洞洞板上,电池座与磁簧开关端子引出排针。
- 用热缩管包裹 TP4056 裸露焊点,整板装入 3D 打印外壳,侧壁预留 LED 导光柱和 Micro-USB 充电口。
- 磁簧开关本体用双面胶固定在门框非移动侧,永磁铁粘在门边缘对应位置,间距不超过 5mm。
- 连接磁簧开关与主机的导线沿门框内侧走暗线,末端用排插对接,方便拆卸维护。
核心代码
以下为 Arduino 骨架代码,基于 ESP8266 平台,实现中断唤醒、消抖、MQTT 上报。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
const char* mqtt_server = "192.168.1.100";
const int DOOR_PIN = 2; // GPIO2,磁簧开关
const int LED_PIN = 0; // GPIO0,LED 指示
bool lastDoorState;
bool currentDoorState;
volatile bool doorChanged = false;
WiFiClient espClient;
void IRAM_ATTR doorISR() {
doorChanged = true;
}
void setup() {
pinMode(LED_PIN, OUTPUT);
lastDoorState = digitalRead(DOOR_PIN);
// 根据唤醒原因选择行为
if (doorChanged) {
blinkLED(3, 100); // 快闪三次表示事件唤醒
currentDoorState = digitalRead(DOOR_PIN);
delay(50); // 消抖
if (digitalRead(DOOR_PIN) != currentDoorState) return; // 抖动则放弃
if (currentDoorState != lastDoorState) {
connectAndReport();
lastDoorState = currentDoorState;
}
} else {
// 定时器唤醒,发送心跳
connectAndReportBattery();
}
// 进入深度睡眠,GPIO2 中断唤醒 + 定时器 60 分钟
ESP.deepSleep(3600e6, WAKE_RF_DEFAULT | WAKE_RFCAL);
// 注意:如果由 GPIO 中断唤醒,sleep 立即返回,不影响
}
void connectAndReport() {
digitalWrite(LED_PIN, LOW); // 点亮 LED 表示工作中
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(500);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
if (client.connect("garage_sensor")) {
String state = (currentDoorState == LOW) ? "CLOSED" : "OPEN";
client.publish("garage/door/state", state.c_str(), true);
client.publish("garage/device/heartbeat", String(analogRead(A0) * 4.2 / 1024).c_str());
delay(100);
client.disconnect();
digitalWrite(LED_PIN, HIGH); // 成功,灭灯
}
} else {
blinkLED(5, 500); // 慢闪表示失败
}
}
void connectAndReportBattery() {
WiFi.begin(ssid, password);
// ... 省略重复 Wi-Fi 连接逻辑
if (WiFi.status() == WL_CONNECTED) {
if (client.connect("garage_sensor")) {
float vcc = analogRead(A0) * 4.2 / 1024.0;
client.publish("garage/device/heartbeat", String(vcc).c_str());
delay(100);
client.disconnect();
}
}
}
void blinkLED(int times, int interval) {
for (int i = 0; i < times; i++) {
digitalWrite(LED_PIN, LOW);
delay(interval);
digitalWrite(LED_PIN, HIGH);
delay(interval);
}
}
void loop() {} // 实际不会执行,全部在 setup 内完成
调试步骤
- 独立测试磁簧开关:用万用表蜂鸣档连接干簧管两端,磁铁靠近应导通,远离断开。确认磁体极性正确,最大感应距离不低于 5mm。
- 烧录基础固件:先在 Arduino IDE 中上传一个简单 Blink 测试,确认 ESP8266 工作正常,GPIO0 可控制 LED。
- 中断验证:烧录含串口打印的测试代码,手动触发磁簧开关,观察串口监视器是否实时输出 “CHANGE DETECTED”,并记录电平。
- 休眠功耗测量:将万用表调至电流微安档,串联在电池正极,深度睡眠时电流应小于 30μA。
- MQTT 连接测试:在局域网内用 MQTT 调试工具(如 MQTTX)订阅
garage/door/state,模拟门开关动作,查看主题是否收到 “OPEN”/“CLOSED”。 - 整体安装联调:固定磁体和主板,实际开关车库门,手机端确认状态变化延迟与准确率,必要时微调磁体位置。
- 续航验证:充满电后置于正常安装位置,统计一周耗电量,推算实际使用时间。
设计图
车库门远程状态卡片结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报