ESP32墨水屏喂奶计时器:本地接入米家智能家居全流程指南
这次我们来看一个非常实用的物联网DIY项目:用ESP32主控搭配墨水屏,制作一个能接入米家智能家居的喂奶计时器。对于有新生儿的家庭来说,记录喂奶时间是个高频且容易遗忘的任务,这个项目将硬件、固件和智能家居平台打通,提供了一个低成本、低功耗、信息常显的本地化解决方案。
项目的核心思路很清晰:利用ESP32的Wi-Fi和计算能力,运行一个简单的HTTP服务器,并通过Home Assistant(HA)这个开源家庭自动化平台作为桥梁,最终将计时器的状态和控制接入米家App。墨水屏的特性决定了它只在刷新时耗电,显示喂奶间隔时间等信息非常直观且省电。整个方案不依赖复杂的云服务,数据在本地流转,响应快且隐私性好。
本文将带你从零开始,完成这个喂奶计时器的硬件搭建、固件烧录、Home Assistant配置以及米家接入的全过程。无论你是ESP32的初学者,还是想深入了解如何将自制设备融入现有智能家居生态的开发者,这篇文章都能提供一套可落地的操作指南。我们会重点关注ESP32的HTTP服务器实现、Home Assistant的MQTT或RESTful传感器配置,以及通过Xiaomi Miot Auto插件实现米家控制的关键步骤。
1. 核心能力速览
在动手之前,我们先快速了解这个项目的关键特性和要求。
| 能力项 | 说明 |
|---|---|
| 核心功能 | 基于ESP32和墨水屏的本地喂奶计时器,状态通过Home Assistant接入米家App。 |
| 硬件门槛 | 较低。需要ESP32开发板、墨水屏(如1.54英寸或2.9英寸)、杜邦线等。无需高性能GPU/CPU。 |
| 功耗表现 | 极低。ESP32在深度睡眠模式下功耗极低;墨水屏仅在刷新时耗电,显示内容可长期保持。 |
| 通信方式 | ESP32作为HTTP服务器,通过Wi-Fi与家庭内网的Home Assistant通信。 |
| 接入生态 | 通过Home Assistant及其插件,间接接入米家(Xiaomi)智能家居体系。 |
| 数据流 | 本地化。计时数据在ESP32生成,通过HA处理,最终同步至米家App,无需经过第三方云。 |
| 开发环境 | Arduino IDE 或 PlatformIO (VS Code插件),使用Arduino框架进行ESP32开发。 |
| 适合场景 | 家庭育儿智能硬件DIY、ESP32物联网入门项目、Home Assistant与米家生态桥接实践。 |
2. 适用场景与使用边界
这个喂奶计时器项目主要服务于特定场景,明确其边界能帮助你更好地判断是否适合自己。
适用场景:
- 新生儿家庭:父母需要频繁、准确地记录每次喂奶的起始时间,以掌握喂养规律。
- 物联网学习与实践:对于想学习ESP32联网、HTTP服务器、传感器数据上报以及Home Assistant集成的开发者,这是一个功能完整且贴近生活的练手项目。
- 智能家居深度用户:已经部署Home Assistant,并希望将更多自制、非标设备统一管理并接入常用App(如米家)的用户。
- 低功耗显示需求:需要长时间显示固定信息,且不希望频繁充电或更换电池的场景,墨水屏的优势明显。
使用边界与注意事项:
- 非商业产品:这是一个DIY项目,在稳定性、安全性和耐用性上无法与成熟商业产品相比,适合技术爱好者。
- 依赖家庭网络:ESP32和Home Assistant需要处于同一局域网(LAN)下。网络不稳定会导致计时器状态同步延迟或失败。
- 需要基础部署能力:你需要能够烧录ESP32固件、安装配置Home Assistant(通常以HASSOS、Docker等方式部署),并安装第三方插件。
- 功能相对单一:核心是计时和状态显示,不具备视频监控、奶量记录等复杂功能。扩展需要二次开发。
- 隐私与数据安全:项目设计为本地运行,数据不出家门。但需确保Home Assistant实例本身的安全配置(如设置强密码、不随意暴露到公网)。
3. 环境准备与前置条件
开始制作前,请确保你已准备好以下软硬件环境。
硬件清单:
- ESP32开发板:如ESP32 DevKitC、NodeMCU-32S等,任何带有Wi-Fi功能的ESP32模块均可。
- 墨水屏(E-Paper):建议选择与常用驱动库兼容的型号,例如:
- GDEH0154D67 (1.54英寸)
- GDEW029T5 (2.9英寸)
- 购买时请确认其接口(通常是SPI)和电压(3.3V)与ESP32兼容。
- 连接线:杜邦线(母对母或公对母),用于连接ESP32与墨水屏。
- 电源:为ESP32供电,可使用USB线连接电脑或手机充电器,或使用3.7V锂电池配合充放电模块实现便携。
- 可选:按键或触摸传感器,用于本地手动触发计时开始/结束。
软件与环境清单:
- 开发环境:
- 方案一(推荐):Visual Studio Code + PlatformIO IDE插件。它提供了更好的库管理和项目结构。
- 方案二:Arduino IDE。需要安装ESP32开发板支持包。
- Home Assistant (HA):一个已安装并运行在你的家庭网络中的Home Assistant实例。这可以是运行在树莓派、旧电脑、NAS或虚拟机上的HASSOS、Docker容器等。
- 网络:稳定的家庭Wi-Fi网络。你需要知道Wi-Fi的SSID(名称)和密码。
- 米家App:在手机上安装米家App,并已登录账号。
4. 硬件连接与驱动库安装
首先,我们将ESP32与墨水屏连接起来,并配置好开发环境。
4.1 硬件连线(以SPI接口墨水屏为例)
大多数小尺寸墨水屏使用SPI接口。以下是典型的连接方式,请根据你的屏幕具体引脚定义进行调整:
| 墨水屏引脚 | ESP32 GPIO引脚 | 功能说明 |
|---|---|---|
| VCC | 3.3V | 电源正极(务必确认屏幕电压为3.3V) |
| GND | GND | 电源地 |
| DIN (MOSI) | GPIO 23 | SPI数据输入(主出从入) |
| CLK (SCK) | GPIO 18 | SPI时钟信号 |
| CS (片选) | GPIO 5 | 片选信号,低电平有效 |
| DC (数据/命令) | GPIO 17 | 用于区分发送的是数据还是命令 |
| RST (复位) | GPIO 16 | 复位引脚,低电平复位 |
| BUSY | GPIO 4 | 忙状态指示,高电平表示屏幕忙 |
注意:GPIO引脚编号可根据你的板子布局和代码定义进行修改,避免冲突。
4.2 安装开发环境与库
使用 PlatformIO (VS Code):
- 安装VS Code,然后在扩展商店搜索并安装“PlatformIO IDE”。
- 新建一个Project,选择Board为“Espressif ESP32 Dev Module”,Framework为“Arduino”。
- 打开项目根目录下的
platformio.ini文件,在[env]部分添加依赖库。对于常用的GxEPD2墨水屏驱动库,添加如下内容:lib_deps = olikraus/U8g2_for_Adafruit_GFX @ ^1.8.0 zinggjm/GxEPD2 @ ^1.5.6 - PlatformIO会自动下载这些库。
使用 Arduino IDE:
- 安装Arduino IDE。
- 添加ESP32开发板支持:文件 -> 首选项 -> 附加开发板管理器网址,添加
https://espressif.github.io/arduino-esp32/package_esp32_index.json。 - 工具 -> 开发板 -> 开发板管理器,搜索“esp32”并安装。
- 项目 -> 加载库 -> 管理库,搜索并安装“GxEPD2”和“U8g2 for Adafruit GFX”库。
5. ESP32固件开发:HTTP服务器与计时逻辑
这是项目的核心代码部分。ESP32将同时扮演两个角色:一个简单的HTTP服务器,用于接收来自Home Assistant的命令;一个计时器,控制墨水屏的显示。
5.1 代码结构概述
我们将编写一个Arduino Sketch,主要包含以下功能模块:
- Wi-Fi连接:连接家庭Wi-Fi。
- 墨水屏驱动初始化与显示:使用GxEPD2库驱动屏幕,绘制计时界面。
- HTTP服务器:创建一个Web服务器,监听特定端口(如80),提供简单的API端点。
- 计时逻辑:记录“开始喂奶”的时间点,计算距离当前时间的间隔,并格式化显示。
- 与Home Assistant交互:通过HTTP端点,接收HA发来的“开始计时”指令,也可以将当前状态(如“已计时XX分钟”)通过HA暴露给米家。
5.2 核心代码示例
以下是一个高度简化的代码框架,展示了关键逻辑:
#include <WiFi.h> #include <WebServer.h> // 使用ESP32内置的WebServer库 #include <GxEPD2_BW.h> // 假设使用黑白墨水屏 #include <Fonts/FreeMonoBold9pt7b.h> // 1. 定义墨水屏对象(以2.9英寸为例) GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(GxEPD2_290(/*CS=*/5, /*DC=*/17, /*RST=*/16, /*BUSY=*/4)); // 2. 网络配置 const char* ssid = "你的Wi-Fi名称"; const char* password = "你的Wi-Fi密码"; WebServer server(80); // 在80端口创建服务器 // 3. 计时状态变量 unsigned long feedStartTime = 0; // 开始喂奶的时间戳(毫秒) bool isFeeding = false; // 是否正在喂奶 void setup() { Serial.begin(115200); // 初始化墨水屏 display.init(115200); display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); // 连接Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected! IP address: "); Serial.println(WiFi.localIP()); // 定义HTTP API端点 server.on("/start", HTTP_GET, []() { // Home Assistant调用此端点开始计时 feedStartTime = millis(); isFeeding = true; updateDisplay(); server.send(200, "text/plain", "Timer started"); }); server.on("/stop", HTTP_GET, []() { // 停止计时 isFeeding = false; updateDisplay(); server.send(200, "text/plain", "Timer stopped"); }); server.on("/status", HTTP_GET, []() { // 提供当前状态,供HA读取 String status = isFeeding ? "feeding" : "idle"; String timeElapsed = String((millis() - feedStartTime) / 60000); // 转换为分钟 String jsonResponse = "{\"state\":\"" + status + "\", \"duration_minutes\":\"" + timeElapsed + "\"}"; server.send(200, "application/json", jsonResponse); }); server.begin(); Serial.println("HTTP server started"); // 首次显示 updateDisplay(); } void loop() { server.handleClient(); // 处理HTTP请求 // 可以添加定时刷新显示的逻辑,例如每分钟刷新一次时间 static unsigned long lastUpdate = 0; if (millis() - lastUpdate > 60000) { // 每分钟更新一次显示 lastUpdate = millis(); if (isFeeding) { updateDisplay(); } } } void updateDisplay() { display.setFullWindow(); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(10, 30); display.print("Feeding Timer"); display.setCursor(10, 60); if (isFeeding) { unsigned long minutes = (millis() - feedStartTime) / 60000; display.print("Time: "); display.print(minutes); display.print(" min"); } else { display.print("Ready"); } display.setCursor(10, 90); display.print("IP:"); display.print(WiFi.localIP()); } while (display.nextPage()); // 墨水屏进入休眠以省电 display.hibernate(); }代码说明:
- ESP32启动后连接Wi-Fi,并启动一个Web服务器。
- 提供了三个简单的API端点:
/start:GET请求此地址,计时器开始。/stop:停止计时。/status:返回一个JSON,包含当前状态和持续时间。
updateDisplay函数负责在墨水屏上绘制内容,包括计时状态和ESP32的IP地址(便于调试)。- 计时逻辑基于
millis()函数,避免了使用阻塞的delay()。
5.3 烧录固件
- 将上述代码根据你的屏幕型号和引脚定义修改后,保存为
.ino文件。 - 用USB线连接ESP32到电脑。
- 在开发环境(PlatformIO或Arduino IDE)中选择正确的端口和开发板型号。
- 点击上传按钮,编译并烧录固件。
- 打开串口监视器,查看输出日志,确认Wi-Fi连接成功并获取到IP地址(如
192.168.1.100)。记下这个IP。
6. Home Assistant配置:创建传感器与自动化
现在,我们需要让Home Assistant认识这个ESP32计时器,并与之通信。
6.1 添加RESTful传感器
Home Assistant可以通过RESTful传感器(rest)来获取ESP32的状态。编辑HA的configuration.yaml文件,添加如下配置:
# configuration.yaml 示例 sensor: - platform: rest name: "Feeding Timer Status" resource: http://ESP32_IP_ADDRESS/status # 替换为你的ESP32 IP method: GET scan_interval: 30 # 每30秒查询一次状态 value_template: "{{ value_json.state }}" json_attributes: - duration_minutes配置解释:
resource: 指向ESP32的/status端点。value_template: 从返回的JSON中提取state字段的值(“feeding”或“idle”)作为传感器状态。json_attributes: 将duration_minutes字段作为传感器的属性存储,可以在前端显示。
保存并重启Home Assistant。在HA的前端,你应该能看到一个名为“Feeding Timer Status”的传感器实体。
6.2 创建调用服务的开关或按钮
为了向ESP32发送“开始”/“停止”命令,我们可以在HA中创建一个脚本或直接使用“开关”实体。这里以创建一个“开关”为例,它实际上调用的是rest_command服务。
首先,在configuration.yaml中定义rest_command:
rest_command: feeding_timer_start: url: "http://ESP32_IP_ADDRESS/start" method: GET feeding_timer_stop: url: "http://ESP32_IP_ADDRESS/stop" method: GET然后,你可以通过HA的“开发者工具 -> 服务”手动调用rest_command.feeding_timer_start来测试。为了更方便,可以创建一个“虚拟开关”或“按钮”卡片来触发这些服务。
使用“帮助程序”创建开关:
- 进入HA侧边栏“设置” -> “设备与服务” -> “帮助程序”。
- 点击“创建辅助元素”,选择“开关”。
- 设置名称,如“开始喂奶计时”。
- 在开关配置中,为其添加一个自动化:当开关打开时,调用服务
rest_command.feeding_timer_start;当开关关闭时,调用rest_command.feeding_timer_stop。
现在,你在HA仪表盘上就有一个可以控制ESP32计时器的开关了。
7. 接入米家:通过Xiaomi Miot Auto插件
这是实现“通过米家控制”的关键一步。我们将利用Home Assistant强大的集成能力,通过第三方插件将HA中的实体暴露给米家App。
7.1 安装Xiaomi Miot Auto集成
Xiaomi Miot Auto是一个HA社区插件,可以将HA中的任意实体(如开关、传感器)同步到米家App中。
- 在HA中,确保已安装“File editor”或“Samba share”等插件,以便编辑配置文件。
- 通过HACS(Home Assistant Community Store)安装“Xiaomi Miot Auto”集成。如果未安装HACS,需先安装HACS。
- 安装完成后,重启HA。
7.2 配置Xiaomi Miot Auto
- 进入HA侧边栏“设置” -> “设备与服务” -> “集成”。
- 点击“添加集成”,搜索“Xiaomi Miot Auto”。
- 按照提示,选择“账号集成”模式,使用你的小米账号(即米家App账号)登录授权。
- 授权成功后,集成会自动同步你米家账号下的设备。但这还不够,我们需要将HA的实体添加进去。
7.3 将HA实体映射到米家
Xiaomi Miot Auto允许你通过YAML配置,将HA的实体映射为虚拟的米家设备。编辑HA的configuration.yaml文件,添加如下配置:
# configuration.yaml 示例 xiaomi_miot_raw: - host: 127.0.0.1 # 固定为本地 token: auto mapping: switch.feeding_timer_start: # 这是你在HA中创建的辅助开关实体ID siid: 2 # 自定义服务ID,通常2代表开关 piid: 1 # 属性ID aiid: 1 # 动作ID value: true value_off: false value_on: true sensor.feeding_timer_status: # 这是RESTful传感器的实体ID siid: 3 # 自定义服务ID,通常3代表传感器 piid: 1 value: '{{ value }}'注意:siid,piid,aiid的值需要根据米家设备模型的规范来定义,上述示例是一个简化版本。更可靠的做法是参考Xiaomi Miot Auto的官方文档,使用其“自定义模型”功能,或直接复制一个现有米家开关设备的模型进行修改。
配置完成后,重启Home Assistant。
7.4 在米家App中查看和控制
- 重启后,打开米家App。
- 在“我的设备”页面,下拉刷新。通常,稍等片刻后,一个名为“Home Assistant”或类似名称的设备会被自动添加进来。
- 点开这个设备,你应该能看到里面包含了我们在HA中映射的“开关”和“传感器”。
- 现在,你就可以直接在米家App里点击“开关”来远程启动/停止ESP32上的喂奶计时器,并查看计时状态了。
8. 功能测试与效果验证
完成所有配置后,需要进行系统化测试以确保各环节工作正常。
8.1 本地ESP32功能测试
- 基础显示:ESP32启动后,墨水屏应显示初始界面(如“Ready”和IP地址)。
- HTTP API测试:在电脑浏览器或使用
curl命令测试ESP32的API。- 打开浏览器,访问
http://[ESP32_IP]/status,应返回JSON数据。 - 访问
http://[ESP32_IP]/start,屏幕应立即更新,显示计时开始。 - 访问
http://[ESP32_IP]/stop,计时停止,屏幕显示“Ready”。
- 打开浏览器,访问
- 计时准确性:开始计时后,观察屏幕显示的时间增量是否与真实时间基本一致(允许秒级误差)。
8.2 Home Assistant集成测试
- 传感器状态:在HA的“概览”或“开发者工具 -> 状态”中,找到
sensor.feeding_timer_status实体,检查其状态是否随ESP32计时状态变化而更新。 - 服务调用:在“开发者工具 -> 服务”中,调用
rest_command.feeding_timer_start和rest_command.feeding_timer_stop,观察ESP32屏幕和HA传感器状态是否同步变化。 - 辅助开关:操作在HA前端创建的“开始喂奶计时”开关,验证其能否正确控制ESP32。
8.3 米家App端到端测试
- 设备发现:确认米家App中出现了来自Home Assistant的虚拟设备。
- 控制测试:在米家App中,点击虚拟设备里的开关。观察:
- HA中对应的辅助开关状态是否变化。
- ESP32的墨水屏显示是否变化。
- 状态同步测试:在ESP32本地通过HTTP API开始计时,等待片刻(HA的扫描间隔),查看米家App中传感器显示的状态是否变为“feeding”,并看到持续时间更新。
9. 常见问题与排查方法
在部署过程中,你可能会遇到以下问题:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| ESP32无法连接Wi-Fi | SSID/密码错误、信号弱、路由器设置限制 | 检查串口日志输出 | 确认密码正确,将ESP32靠近路由器,检查路由器是否开启了MAC过滤或AP隔离。 |
| 浏览器无法访问ESP32 IP | 防火墙阻止、IP地址错误、ESP32服务器未启动 | 在HA主机或同一网络下电脑ping ESP32的IP;检查串口日志确认服务器启动 | 关闭电脑防火墙临时测试;确认ESP32与测试设备在同一子网;检查代码中server.begin()是否执行。 |
| HA中REST传感器状态为“unavailable” | HA无法访问ESP32的/status端点、网络问题、扫描间隔未到 | 在HA主机上用curl命令测试http://ESP32_IP/status;检查HA日志 | 确保IP正确,网络互通;暂时增大scan_interval;检查ESP32代码确保/status端点正确处理请求并返回有效JSON。 |
| 米家App中找不到HA设备 | Xiaomi Miot Auto配置错误、米家账号未同步、网络延迟 | 检查HA中Xiaomi Miot Auto集成的日志;重启HA和米家App;等待更长时间 | 仔细检查YAML配置中实体ID是否正确;尝试在Xiaomi Miot Auto集成设置中手动“同步设备”。 |
| 米家App能控制但状态不同步 | 传感器映射配置错误、HA传感器本身状态未更新 | 首先在HA前端确认传感器状态是否正确;检查米家映射配置中的value模板 | 确保HA侧的传感器工作正常;检查Xiaomi Miot Auto配置中传感器映射的value字段是否正确引用了状态值。 |
| 墨水屏不显示或显示乱码 | 引脚连接错误、驱动库不匹配、电源问题 | 逐一检查杜邦线连接;确认使用的驱动库(GxEPD2)支持你的屏幕型号;测量VCC电压 | 对照引脚定义表重新接线;在代码中尝试使用库自带的示例程序测试屏幕;确保使用3.3V供电。 |
| 计时不准 | 使用delay()导致阻塞、millis()溢出(约50天后) | 检查代码中是否在loop()里使用了长延时delay() | 使用非阻塞的定时逻辑(如示例代码中millis()差值判断);对于超长运行,需考虑millis()溢出处理,但喂奶计时场景通常无需考虑。 |
10. 优化与扩展思路
基础功能实现后,可以考虑以下优化和扩展,让项目更完善:
低功耗优化:
- ESP32深度睡眠:如果使用电池供电,可以在计时结束后让ESP32进入深度睡眠模式,仅由外部按键(连接到EN或GPIO0)唤醒,极大延长续航。
- 墨水屏局部刷新:如果屏幕支持,在更新计时数字时使用局部刷新(
display.powerRefresh())而非全屏刷新,速度更快、更省电、减少残影。
本地交互:
- 物理按键:增加1-2个物理按键连接到ESP32,实现本地手动开始/停止/重置计时,不依赖网络。
- 触摸感应:使用电容触摸传感器,实现更优雅的交互。
功能扩展:
- 多计时器:管理“左/右”喂奶或“喂奶/换尿布”等多个计时任务。
- 历史记录:ESP32将每次喂奶的起止时间通过HTTP POST发送到HA,HA将其记录在数据库(如InfluxDB)中,并可通过Grafana等工具可视化喂养历史。
- 声音/灯光提醒:增加蜂鸣器或LED,当计时达到一定时长(如30分钟)时发出提醒。
可靠性提升:
- Wi-Fi重连机制:在代码中添加健壮的Wi-Fi断开重连逻辑。
- 看门狗定时器:启用硬件看门狗,防止程序跑飞导致设备死机。
- OTA升级:实现通过网络远程更新ESP32固件,无需插线。
这个项目成功地将一个简单的ESP32设备,通过Home Assistant的桥梁,融入了成熟的米家智能生态。它不仅解决了喂奶计时这个具体问题,更提供了一个经典的物联网设备接入范例。你可以举一反三,将类似的思路应用于其他传感器(如温湿度计、门窗磁)或控制器(如继电器开关),打造完全自定义的智能家居设备。