💡 划重点
- 用 ESP8266 做主控,配合磁簧开关,总成本控制在 25 元内。
- 磁簧接 GPIO2 中断,门开合即时触发;LED 接 GPIO0 做本地状态指示。
- MQTT 上报门状态,支持 Home Assistant、Node-RED 等平台。
- 低耗休眠:运行中 GPIO2 中断唤醒,长时间无事件进入深度休眠定时心跳。
- 改造简单,不破坏原车库门结构,适合家庭安防快速部署。
需求洞察
目标用户是已经拥有车库门或卷帘门、并开始使用智能家居的家庭用户。他们通常有手机远程控制需求,但原门控系统不提供状态反馈。真实痛点是:出门后总怀疑车库门没关,返回检查费时费力;或者夜间听到异响,无法确认门是否被打开。市面上成品门磁传感器价格多在 50 元以上,且很多需要专用网关。自己动手用 ESP8266 做一块“远程状态卡片”,成本低、可玩性高,还能直接接入现有 MQTT 生态。对于家庭安防来说,知道门是开是关,比远程开门更重要。这个项目值得做,因为它把“不确定”变成“确定”,用 25 元解决一个高频焦虑。
方案设计
方案分为四层。感知层:磁簧开关安装在门框与门体之间,门关闭时磁铁吸合,GPIO2 读到低电平;门打开时磁簧分离,GPIO2 被上拉为高电平。控制层:ESP8266 负责去抖、状态判断和休眠管理。运行中 GPIO2 下降沿或上升沿触发中断,立即更新状态。执行层:GPIO0 接 LED,用不同闪烁模式表示“关闭”“打开”“配网中”“MQTT 断开”。日志/联网层:通过 MQTT 发布主题 garage/door/state,消息为 open 或 closed,并设置保留消息,方便新订阅者立即获取状态。低耗休眠策略:正常运行时 WiFi 保持连接,GPIO2 中断即时响应;若 5 分钟无事件,进入深度休眠,由 GPIO16 接 RST 定时唤醒,每 2 分钟读一次磁簧并上报心跳。这样兼顾响应速度和功耗。
物料清单
| 物料 | 数量 | 用途 | 估算单价 | 合计 |
|---|---|---|---|---|
| ESP8266-01S 模块 | 1 | 主控与 WiFi | 8 元 | 8 元 |
| 磁簧开关 | 1 | 门开合检测 | 2 元 | 2 元 |
| LED 3mm | 1 | 本地状态指示 | 0.2 元 | 0.2 元 |
| 电阻 10kΩ | 1 | GPIO2 上拉 | 0.1 元 | 0.1 元 |
| 电阻 220Ω | 1 | LED 限流 | 0.1 元 | 0.1 元 |
| 洞洞板 3x7cm | 1 | 焊接固定 | 1.5 元 | 1.5 元 |
| 杜邦线/细导线 | 若干 | 连接 | 2 元 | 2 元 |
| USB 电源 5V1A | 1 | 供电(可复用旧充电头) | 5 元 | 5 元 |
| 塑料外壳 | 1 | 保护电路 | 3 元 | 3 元 |
| 合计 | 21.9 元 |
总成本约 21.9 元,低于 25 元目标。若已有电源和外壳,成本可降至 14 元以内。
接线与结构
- 磁簧开关:一端接 GND,另一端接 GPIO2,同时 GPIO2 通过 10kΩ 电阻上拉到 3.3V。门关闭时磁簧吸合,GPIO2 为低;门打开时 GPIO2 为高。
- LED:正极经 220Ω 电阻接 GPIO0,负极接 GND。GPIO0 输出高电平时点亮,注意 ESP8266 启动时 GPIO0 需为高,LED 接法不会影响启动。
- 深度休眠:GPIO16 接 RST,用于定时唤醒。说明:ESP8266 深度休眠仅 GPIO16 可唤醒,因此增加此跳线。GPIO2 仍保留中断功能,在运行期间实现即时检测。
- 结构:磁簧固定在门框侧,磁铁固定在门体侧,间距小于 15mm。电路板放入塑料外壳,用双面胶或螺丝固定。电源线从车库门控制器旁取 5V,或使用独立 USB 充电头。
核心代码
以下为 Arduino 骨架,基于 ESP8266 库和 PubSubClient。代码包含去抖、MQTT 上报和深度休眠。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#define REED_PIN 2
#define LED_PIN 0
#define WIFI_SSID "your_ssid"
#define WIFI_PASS "your_pass"
#define MQTT_SERVER "192.168.1.100"
#define MQTT_TOPIC "garage/door/state"
WiFiClient espClient;
volatile bool reedChanged = false;
bool lastState = false;
unsigned long lastDebounce = 0;
void ICACHE_RAM_ATTR onReedChange() {
reedChanged = true;
}
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Serial.begin(115200);
while (WiFi.status() != WL_CONNECTED) { delay(500); digitalWrite(LED_PIN, !digitalRead(LED_PIN)); }
lastState = digitalRead(REED_PIN);
}
void publishState() {
bool state = digitalRead(REED_PIN);
const char* msg = state ? "open" : "closed";
digitalWrite(LED_PIN, state ? HIGH : LOW);
}
void loop() {
if (!client.connected()) { client.connect("garage_door"); }
client.loop();
if (reedChanged && millis() - lastDebounce > 50) {
lastDebounce = millis();
reedChanged = false;
bool now = digitalRead(REED_PIN);
if (now != lastState) { lastState = now; publishState(); }
}
if (millis() > 300000) { ESP.deepSleep(120e6); }
}
调试步骤
- 按接线图连接磁簧、LED 和 GPIO16-RST 跳线,检查无短路。
- 烧录固件,打开串口监视器,确认 WiFi 连接成功。
- 手动分开和吸合磁簧,观察 LED 变化和串口输出,确认 MQTT 消息发送。
- 用 MQTT 客户端订阅
garage/door/state,验证保留消息。 - 测试深度休眠:等待 5 分钟,测量电流应降至 20μA 左右,定时唤醒后重新上报。
- 安装到车库门,调整磁簧与磁铁间距,确保开合可靠触发。