💡 划重点
- 一句话:给独居长辈一个“按键就能打卡”的吃药提醒盒,4 个按键分别对应“已服药、稍后提醒、跳过、呼叫子女”,OLED 显示状态,飞书实时通知。
- 主控:ESP32-C3,成本控制在 50 元内。
- 核心价值:把复杂的手机提醒变成实体按钮,降低漏服、重复服药风险,让异地子女心里有数。
需求洞察
目标用户是独居老人、慢性病患者,以及在外地工作的子女。真实痛点有三个:第一,老人容易忘记吃药,或者记不清“刚才到底吃没吃”,导致漏服或重复服药;第二,手机 App 提醒对长辈不友好,弹窗一划就没了,反而造成困扰;第三,子女打电话问“吃药了吗”,老人常常凭感觉回答,无法确认。为什么值得做?因为吃药是高频、刚需、容错率低的事,而一个带按键和联网功能的实体盒子,操作门槛极低,按一下就能完成记录和通知,成本也不高,适合家庭场景快速落地。
方案设计
- 感知层:4 个轻触按键接在 GPIO0、GPIO1、GPIO2、GPIO3,分别定义为“已服药”“稍后 10 分钟”“跳过”“呼叫子女”。软件做 20ms 消抖,避免误触。
- 控制层:ESP32-C3 作为主控,运行状态机。每次按键后更新今日服药状态,记录时间戳,判断是否重复打卡。
- 执行层:0.96 寸 OLED 显示当前时间、今日服药状态和提示语;LED 在联网成功或打卡成功时闪烁;可选有源蜂鸣器做按键反馈。
- 日志/联网层:ESP32-C3 连接 Wi-Fi,通过 HTTP POST 把打卡记录发送到飞书机器人 Webhook。飞书消息包含“已服药/稍后/跳过/呼叫”和时间。日志可同时输出到串口,方便排查。
物料清单
| 物料 | 数量 | 用途 | 估算单价 | 合计 |
|---|---|---|---|---|
| ESP32-C3 开发板 | 1 | 主控、Wi-Fi 联网 | 15 元 | 15 元 |
| 0.96 寸 OLED I2C | 1 | 显示时间与状态 | 9 元 | 9 元 |
| 轻触按键 | 4 | 打卡、稍后、跳过、呼叫 | 0.25 元 | 1 元 |
| LED 及电阻 | 1 套 | 联网/打卡指示 | 0.3 元 | 0.3 元 |
| 有源蜂鸣器 | 1 | 按键反馈 | 1.5 元 | 1.5 元 |
| 洞洞板、杜邦线、外壳 | 1 套 | 固定与接线 | 8 元 | 8 元 |
| USB 数据线 | 1 | 供电与烧录 | 3 元 | 3 元 |
| 合计 | 37.8 元 |
接线与结构
按键一端接 GPIO0/1/2/3,另一端接 GND,使用内部上拉,按下为低电平。OLED 使用 I2C:SDA 接 GPIO8,SCL 接 GPIO9,VCC 接 3.3V,GND 接 GND。LED 正极经 220Ω 电阻接 GPIO10,负极接 GND。蜂鸣器正极接 3.3V,负极接 GPIO10 需加三极管,为简化可省略蜂鸣器或用 LED 代替。
说明:GPIO2 和 GPIO9 属于 ESP32-C3 的 strapping 引脚,上电时若被拉低可能进入下载模式。OLED 模块的 I2C 上拉通常不会拉低,正常上电不受影响。若遇到启动异常,可将 SDA/SCL 改到 GPIO6/7,其他接线不变。按键平时为高电平,只有按下才拉低,不会影响启动。
核心代码
以下为 Arduino 骨架,可编译上传。需安装 Adafruit SSD1306、Adafruit GFX、ArduinoJson 库。
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define BTN_TAKEN 0
#define BTN_LATER 1
#define BTN_SKIP 2
#define BTN_CALL 3
#define LED_PIN 10
Adafruit_SSD1306 oled(128, 64, &Wire;, -1);
const char* ssid = "你家WiFi";
const char* pass = "WiFi密码";
const char* feishu = "https://open.feishu.cn/open-apis/bot/v2/hook/你的token";
unsigned long lastMs = 0;
bool lastState[4] = {HIGH, HIGH, HIGH, HIGH};
void sendFeishu(String text) {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin(feishu);
http.addHeader("Content-Type", "application/json");
String body = "{\"msg_type\":\"text\",\"content\":{\"text\":\"" + text + "\"}}";
http.POST(body);
http.end();
}
void show(String line1, String line2) {
oled.clearDisplay();
oled.setTextSize(1);
oled.setCursor(0, 0);
oled.println(line1);
oled.setCursor(0, 20);
oled.println(line2);
oled.display();
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
for (int i = 0; i < 4; i++) pinMode(i, INPUT_PULLUP);
Wire.begin(8, 9);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) delay(500);
show("药品打卡盒", "WiFi已连接");
}
void loop() {
for (int i = 0; i < 4; i++) {
bool now = digitalRead(i);
if (lastState[i] == HIGH && now == LOW && millis() - lastMs > 200) {
lastMs = millis();
digitalWrite(LED_PIN, HIGH);
String msg;
if (i == BTN_TAKEN) msg = "已服药 " + String(millis() / 1000) + "秒";
if (i == BTN_LATER) msg = "稍后提醒";
if (i == BTN_SKIP) msg = "跳过本次";
if (i == BTN_CALL) msg = "呼叫子女";
sendFeishu(msg);
show("操作成功", msg);
delay(200);
digitalWrite(LED_PIN, LOW);
}
lastState[i] = now;
}
}
调试步骤
- 按接线图连接按键、OLED、LED,检查无短路。
- 烧录程序,观察 OLED 是否显示“WiFi已连接”。
- 按下一个按键,串口应输出对应消息,LED 闪烁。
- 在飞书群中添加机器人,获取 Webhook 地址,替换代码中的 token,测试消息是否到达。
- 测试四个按键,确认“已服药”“稍后”“跳过”“呼叫”均能发送不同通知。
- 装入外壳,贴上按键标签,放在长辈床头或餐桌固定位置。
设计图
药品服用打卡按钮盒结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报