💡 划重点

  • 一句话:给独居长辈一个“按键就能打卡”的吃药提醒盒,4 个按键分别对应“已服药、稍后提醒、跳过、呼叫子女”,OLED 显示状态,飞书实时通知。
  • 主控:ESP32-C3,成本控制在 50 元内。
  • 核心价值:把复杂的手机提醒变成实体按钮,降低漏服、重复服药风险,让异地子女心里有数。

需求洞察

目标用户是独居老人、慢性病患者,以及在外地工作的子女。真实痛点有三个:第一,老人容易忘记吃药,或者记不清“刚才到底吃没吃”,导致漏服或重复服药;第二,手机 App 提醒对长辈不友好,弹窗一划就没了,反而造成困扰;第三,子女打电话问“吃药了吗”,老人常常凭感觉回答,无法确认。为什么值得做?因为吃药是高频、刚需、容错率低的事,而一个带按键和联网功能的实体盒子,操作门槛极低,按一下就能完成记录和通知,成本也不高,适合家庭场景快速落地。

方案设计

物料清单

物料 数量 用途 估算单价 合计
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;
  }
}

调试步骤

  1. 按接线图连接按键、OLED、LED,检查无短路。
  2. 烧录程序,观察 OLED 是否显示“WiFi已连接”。
  3. 按下一个按键,串口应输出对应消息,LED 闪烁。
  4. 在飞书群中添加机器人,获取 Webhook 地址,替换代码中的 token,测试消息是否到达。
  5. 测试四个按键,确认“已服药”“稍后”“跳过”“呼叫”均能发送不同通知。
  6. 装入外壳,贴上按键标签,放在长辈床头或餐桌固定位置。

设计图

药品服用打卡按钮盒结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报