💡 划重点

  • 低功耗门磁的第一原则是“平时什么都不做”:ESP32 大部分时间 deep sleep,只在门被打开时唤醒。
  • 磁簧开关比摄像头、雷达更适合门/抽屉开合检测,因为它便宜、稳定、状态明确。
  • 真正要调的是唤醒脚、上拉方式、Wi-Fi 超时和电池电压采样,而不是复杂算法。

需求洞察

设备箱、仓库门、抽屉、药品柜和工具柜都需要一个简单的开合记录。持续联网的设备耗电高,普通机械锁又没有记录能力。门磁节点的价值在于把一次“开门事件”变成可记录的数据:什么时候打开、持续多久、电池是否快没电。

这个项目很适合硬件编程入门后进阶,因为它逼你考虑真实设备的生命周期:休眠、唤醒、联网、失败重试、上报、再次休眠。能把这条链路跑稳,比多接几个传感器更有工程价值。

方案设计

感知层使用常闭磁簧开关,门关闭时磁铁靠近,GPIO33 保持稳定电平;门打开时电平变化,把 ESP32 从深度睡眠中唤醒。控制层读取门状态和电池分压,判断这次是开门事件还是误触发。执行层可以选配蜂鸣器,但电池版默认不开启常驻执行器。日志/联网层通过 MQTT 发布事件,也可以先用 HTTP Webhook 或串口替代。

为了省电,Wi-Fi 连接必须有超时。如果 8-10 秒连不上网络,就先把事件写入 RTC 计数或本地缓存,然后重新睡眠,避免电池被失败重试耗光。

物料清单

元件 数量 用途 估算价
ESP32 DevKitC 1 主控与 Wi-Fi 上报 25 元
常闭磁簧开关 1 检测门/抽屉开合 3 元
小磁铁 1 与磁簧开关配合 1 元
18650 电池盒 1 移动供电 6 元
低静态电流稳压模块 1 降低待机损耗 8 元
100kΩ 电阻 2 电池分压采样 0.2 元

接线与结构

GPIO33 属于 ESP32 可用于外部唤醒的 RTC GPIO,适合 deep sleep 唤醒。注意不同开发板的稳压器和电源指示灯会明显影响待机电流,如果追求长续航,后期应换低静态电流板或裸模块。

核心代码


#include <Arduino.h>
#include <WiFi.h>

#define DOOR_PIN GPIO_NUM_33
#define BAT_ADC 35
#define BUZZER_PIN 27

const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";

bool connectWiFi(uint32_t timeoutMs) {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  uint32_t start = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - start < timeoutMs) {
    delay(200);
  }
  return WiFi.status() == WL_CONNECTED;
}

float readBattery() {
  int raw = analogRead(BAT_ADC);
  float v = raw * 3.3f / 4095.0f;
  return v * 2.0f; // 100k + 100k 分压
}

void publishEvent(bool opened, float battery) {
  // 这里可以替换成 PubSubClient MQTT publish。
  Serial.printf("door=%s battery=%.2fV\n", opened ? "open" : "closed", battery);
}

void goSleep() {
  esp_sleep_enable_ext0_wakeup(DOOR_PIN, 0); // GPIO33 被拉低时唤醒
  Serial.flush();
  esp_deep_sleep_start();
}

void setup() {
  Serial.begin(115200);
  pinMode((int)DOOR_PIN, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);
  analogReadResolution(12);
  delay(100);

  bool opened = digitalRead((int)DOOR_PIN) == LOW;
  float battery = readBattery();

  if (opened) {
    digitalWrite(BUZZER_PIN, HIGH);
    delay(80);
    digitalWrite(BUZZER_PIN, LOW);
  }

  if (connectWiFi(8000)) {
    publishEvent(opened, battery);
    WiFi.disconnect(true);
  } else {
    Serial.println("wifi timeout, skip publish");
  }

  delay(200);
  goSleep();
}

void loop() {}

调试步骤

  1. USB 供电调试阶段先不要睡眠,把门磁状态每秒打印一次,确认开关逻辑正确。
  2. 打开 deep sleep 后,用串口观察唤醒原因,确认 GPIO33 能触发启动。
  3. 给 Wi-Fi 连接加 8 秒超时,模拟路由器断电,确认设备不会一直卡住。
  4. 用万用表测电池分压点,校准 readBattery() 的换算系数。
  5. 最后再装外壳,反复开合 50 次,检查磁铁位置是否会误触发。

设计图

ESP32 低功耗门磁告警器结构flow
1
门关闭时进入 deep sleep
2
磁簧开关电平变化唤醒
3
读取门状态和电池电压
4
Wi-Fi 连接并发布事件
5
断网超时后重新睡眠