💡 划重点
- 基于 ESP32‑C3 的低成本硬件方案,整体物料成本控制在 50 元以内。
- 四个物理按键对应四种药品/服药时段,按下即打卡。
- 0.96 寸 OLED 屏即时显示本次打卡状态与最近记录。
- 通过 Wi‑Fi 自动将打卡时间与药品信息发送至飞书群通知家人。
- 结构简单、操作友好,专为独居长辈设计,零学习成本。
需求洞察
独居老人和慢性病患者每天需要按时服用多种药品,漏服、错服是常见问题。子女或监护人不可能 24 小时在身边,电话提醒往往被打断或忘记,而普通药盒仅能物理分装,无法记录实际服用情况。一旦发生漏服,家人只能事后被动知晓,往往等到身体出现不适才被发现,延误干预。
本方案将“打卡”这一日常概念引入服药管理:老人在正确时间按下对应药品的按钮,设备立刻给予屏显和灯光反馈,同时将打卡记录作为一条消息推送到子女手机上的飞书群。这样既不需要老人学习智能手机,也不依赖复杂的健康 App,只需按一下按钮就能让家人安心。相比市面上动辄几百元的智能药盒,这套自制的方案成本可以控制在 50 元以内,非常适合动手能力较强的子女为父母亲手制作,兼顾情感陪伴与实际效用。
方案设计
系统按照感知层、控制层、执行层、日志与联网层四层结构设计。
感知层
使用 4 个独立微动按键,每个按键对应一种药品或一个服药时段(早、中、晚、睡),按键一端接 GPIO,一端接地,利用芯片内部上拉电阻,平时读为高电平,按下为低电平。
控制层
ESP32‑C3 作为主控,负责周期性扫描按键状态、进行 20 ms 软件消抖,记录每个按键的按下事件和系统时间。同时驱动 OLED 和 LED,并通过 Wi‑Fi 发送打卡数据。
执行层
一块 0.96 寸 I2C OLED(128×64)显示最近 4 次打卡记录(药品编号+时间),采用大字体,方便老年人辨认。一颗高亮 LED 在按键按下时短暂点亮,作为即时视觉反馈,确认打卡成功。
日志与联网层
ESP32‑C3 通过家庭 Wi‑Fi 连接互联网,每次有效打卡后,将药品编号、时间戳封装成 JSON,通过 HTTP POST 发送至预设的飞书机器人 Webhook 地址。飞书群内立即显示如“妈妈已服用降压药,时间 08:05”。同时主控内部保留一份打卡计数,连接 OLED 显示,方便老人查看当天已服次数。
物料清单
| 序号 | 物料名称 | 数量 | 用途 | 估算单价(元) | 小计(元) |
|---|---|---|---|---|---|
| 1 | ESP32‑C3 开发板(合宙或安信可) | 1 | 主控与 Wi‑Fi | 19.00 | 19.00 |
| 2 | 0.96 寸 OLED 模块(I2C,SSD1306) | 1 | 状态显示 | 12.00 | 12.00 |
| 3 | 6×6mm 微动按键 | 4 | 药品打卡输入 | 0.50 | 2.00 |
| 4 | 5 mm LED(红色) | 1 | 打卡反馈指示 | 0.20 | 0.20 |
| 5 | 220 Ω 电阻 | 1 | LED 限流 | 0.10 | 0.10 |
| 6 | 杜邦线 + 焊接排针 | 若干 | 连接导线 | 3.00 | 3.00 |
| 7 | 定制亚克力外壳或 3D 打印壳 | 1 | 成品外壳 | 10.00 | 10.00 |
| 8 | 热缩管、双面胶、螺丝 | 1 批 | 固定与绝缘 | 2.00 | 2.00 |
| 合计 | 48.30 |
总成本约 48 元,满足 50 元预算要求。按键、LED 和 OLED 均可使用开发板自带的 3.3 V 供电,无需额外电源模块。
接线与结构
为避免影响 ESP32‑C3 的正常启动和串口输出,对接线做了微调:
- 按键:4 个按键分别接 GPIO2、3、4、5。其中 GPIO2/3 在启动时为高阻态,不影响下载;GPIO4/5 无特殊占用,完全可用。原方案指定 GPIO0/1/2/3,但 GPIO0 为 BOOT 键复用,上电时若被拉低会进入下载模式;GPIO1 为 UART TX,若用作按键可能导致串口打印异常。因此全部改用空闲 GPIO,并用内部上拉,保证可靠性。
- OLED:I2C 接口,SDA 接 GPIO8,SCL 接 GPIO9,完全符合给定的 GPIO8/9,ESP32‑C3 的 I2C 控制器可以直接映射到这两个引脚,无需改变。
- LED:正极经 220 Ω 电阻接 GPIO10,负极接地。有效电平输出高,亮度适中。
结构上,所有元件安装在一个长方形小盒中,顶部开 4 个按键孔并标注药品名称或时间,正面留出 OLED 窗口,侧面开孔露出 LED。内部使用杜邦线连接,再用热熔胶固定,避免松动。盒子底部贴防滑垫,放置在床头或餐桌等固定位置。
核心代码
以下给出基于 Arduino 框架(PlatformIO/Arduino IDE)的可运行骨架,使用 U8g2 库驱动 OLED,HTTPClient 发送飞书通知。
#include <WiFi.h>
#include <HTTPClient.h>
#include <U8g2lib.h>
// 用户配置
const char* ssid = "your_SSID";
const char* password = "your_PWD";
const char* feishu_webhook = "https://open.feishu.cn/..."; // 替换为实际链接
// 引脚定义
const uint8_t btn_pins[4] = {2, 3, 4, 5};
const uint8_t led_pin = 10;
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* SCL=*/ 9, /* SDA=*/ 8);
unsigned long last_debounce_time[4] = {0};
bool last_btn_state[4] = {HIGH};
const unsigned long debounce_delay = 50;
int dose_count[4] = {0};
void setup() {
Serial.begin(115200);
for (int i = 0; i < 4; i++) {
}
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, LOW);
u8g2.begin();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); }
show_status("已连接");
}
void loop() {
for (int i = 0; i < 4; i++) {
bool reading = digitalRead(btn_pins[i]);
if (reading != last_btn_state[i]) {
last_debounce_time[i] = millis();
}
if ((millis() - last_debounce_time[i]) > debounce_delay) {
if (reading == LOW) { // 按下有效
dose_count[i]++;
digitalWrite(led_pin, HIGH);
delay(200);
digitalWrite(led_pin, LOW);
String msg = "药品" + String(i+1) + "已服用 " + getTimeStr();
show_status(msg.c_str());
send_feishu(msg);
while(digitalRead(btn_pins[i]) == LOW) delay(10); // 等待释放
}
}
last_btn_state[i] = reading;
}
delay(10);
}
void show_status(const char* text) {
u8g2.clearBuffer();
u8g2.setCursor(0, 15);
u8g2.print(text);
u8g2.sendBuffer();
}
void send_feishu(String message) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(feishu_webhook);
http.addHeader("Content-Type", "application/json");
String payload = "{\"msg_type\":\"text\",\"content\":{\"text\":\"" + message + "\"}}";
int httpCode = http.POST(payload);
http.end();
}
}
String getTimeStr() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo;)) return "时间获取失败";
char buf[20];
strftime(buf, sizeof(buf), "%H:%M", &timeinfo;);
return String(buf);
}
代码要点:按键使用内部上拉,下降沿消抖;每次按键触发 LED 闪烁、OLED 更新并调用飞书 Webhook;时间通过 NTP 自动同步(需在 setup 中添加 configTime,本骨架省略,实际需补全)。
调试步骤
- 硬件连接检查:用万用表确认所有按键在未按下时 GPIO 电压为 3.3 V,按下后为 0 V;LED 极性正确。
- 单独点亮 LED:编写简单脚本让 GPIO10 输出高电平,确认 LED 能亮。
- 扫描按键:在串口监视器打印每个按键的状态,确认按下时读到 0,松开为 1,且消抖后无重复触发。
- OLED 测试:运行 U8g2 示例程序,确保地址 0x3C 可识别,显示正常。
- Wi‑Fi 与飞书联调:先通过串口查看 Wi‑Fi 连接状态,成功后再测试飞书 Webhook 发送固定文本,确认群内收到消息。
- 联机测试:将以上功能整合,按下任一按钮,观察 OLED 刷新、LED 闪烁、飞书消息是否同步到达。
- 装入外壳后再次测试按键手感与位置,确保老人也能轻松按下。