如何实时掌握用户健康数据:Open Wearables Webhooks 完整配置与调试教程
【免费下载链接】open-wearablesSelf-hosted platform to unify wearable health data through one AI-ready API.项目地址: https://gitcode.com/gh_mirrors/op/open-wearables
Open Wearables 是一个自托管的穿戴设备数据平台,它将 Garmin、Oura、Apple Health 等设备的健康数据统一为一个 AI 友好的 API。本教程带你用 Webhooks 实时接收用户的心率、睡眠、运动等健康数据事件——无需轮询,数据一到就推送,并覆盖从启用、注册端点、签名验收到调试排查的完整流程。
为什么用 Webhooks 而不是轮询
传统做法是让服务器每隔几分钟调用一次拉取接口,检查有没有新数据。而 Open Wearables 的 Outgoing Webhooks 会在每个新运动保存、每段睡眠入库、每批时序数据写入的瞬间,向你的服务器发起一次 HTTP POST 推送。
- ⚡实时性:数据落库即触发,没有轮询间隔带来的延迟
- 🔄零空转:没有新数据就不打扰你的服务器
- 🧩完整载荷:时序事件直接携带
samples数组,无需二次调用 API - 🔁自动重试:基于 Svix 投递,失败事件按指数退避自动重发
📌 注意:自托管部署中 Webhooks默认关闭,需要先启用才能收到事件。
第一步:启用 Outgoing Webhooks
在后端.env中设置开关,然后重启容器即可:
OUTGOING_WEBHOOKS_ENABLED=true配置项位置见 .env.example。如果你使用的是托管 Postgres(AWS RDS / Railway),需要确保应用数据库用户有权创建数据库,或提前建好svix数据库——Svix 服务把它的表结构放在那里。
启用状态的检查逻辑在 outgoing_webhooks.py 中,未启用时 API 会明确返回 403 并提示你设置该环境变量。
第二步:注册一个 Webhook 端点
有两种方式,新手推荐从 Web 控制台入手(对应源码 webhooks.tsx):
- 登录后进入Webhooks页面,点击创建端点
- 填入一个公网可达的 HTTPS 地址,例如
https://yourapp.com/webhooks/health - 可选填描述、事件过滤器和用户过滤器
控制台表单 webhook-form.tsx 支持按事件分组勾选要订阅的事件类型。
也可以用 API 完成同样的事(需先用POST /api/v1/auth/login拿到 Bearer Token):
curl -X POST "http://localhost:8000/api/v1/webhooks/endpoints" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "url": "https://yourapp.com/webhooks/health", "description": "生产环境健康数据处理器" }'响应中会返回端点id(形如ep_xxxx),务必保存,后续获取密钥、查看投递记录都要用它。
第三步:获取签名密钥(Signing Secret)
每个端点都有一个独立的 HMAC 签名密钥,用于验证推送确实来自 Open Wearables:
curl "http://localhost:8000/api/v1/webhooks/endpoints/ep_xxx/secret" \ -H "Authorization: Bearer YOUR_JWT_TOKEN"响应形如{ "key": "whsec_..." }。这个密钥请妥善保管在服务器环境变量里,它是防伪造、防重放攻击的唯一凭证。
理解推送载荷与签名验证
每次投递是标准 JSON,包含type(事件名)和data(业务数据),例如一段新睡眠:
{ "type": "sleep.created", "data": { "user_id": "550e8400-...", "efficiency_percent": 87.0, "stages": { "deep_minutes": 95, "rem_minutes": 80 }, "source": { "provider": "oura", "device": "Oura Ring Gen3" } } }同时每个请求都带三个签名头:
| 请求头 | 作用 |
|---|---|
svix-id | 唯一消息 ID,跨重试保持不变,用于幂等去重 |
svix-timestamp | 发送时间戳,超过 5 分钟的旧消息会被 SDK 自动拒绝 |
svix-signature | v1,<base64_hmac>签名的逗号分隔列表 |
推荐的验证方式(Python / Node 都有官方 SDK):安装svix库后,用Webhook(secret).verify(rawBody, headers)一步完成验签,签名不对或时间戳过旧会抛异常,此时应直接返回 400。先验签、再处理,这是安全底线。
事件类型全览:能收到哪些健康数据
事件命名遵循资源.动作约定,完整清单可通过GET /api/v1/webhooks/event-types获取,源码枚举见 event_types.py。
会话类事件(一次完整记录触发一次)
connection.created/connection.revoked— 用户连接或断开穿戴设备workout.created— 新的运动会话(含卡路里、距离、平均心率)sleep.created— 新的(或合并后的)睡眠会话,含深睡/REM 分期menstrual_cycle.created— 新的月经周期记录
时序类事件(按批推送,携带完整样本)
| 事件 | 覆盖的指标 |
|---|---|
heart_rate.created | 心率、静息心率、行走平均心率 |
steps.created | 步数 |
calories.created | 总能量、基础代谢 |
spo2.created | 血氧饱和度、外周灌注指数 |
body_temperature.created | 体温、皮肤温度 |
blood_glucose.created | 血糖、酒精含量、胰岛素输送 |
recovery_score.created | 恢复分、Garmin 身体电量 |
时序事件比拉取接口更"慷慨"——每条samples数据点结构与GET /api/v1/users/{user_id}/timeseries完全一致,消费端只维护一套 schema 即可。超过 2500 个样本的大批次会自动拆分为带chunk_index/total_chunks的分片事件,方便你重组。
过滤事件:只订阅你要的数据
按事件类型过滤
注册或更新端点时传filter_types,例如只关心运动和睡眠:
{ "url": "https://yourapp.com/hook", "filter_types": ["workout.created", "sleep.created"] }不传该字段则接收全部事件。想移除过滤时发送"filter_types": [](空列表才是清除,null会保留原过滤)。
按用户过滤
传user_id可以把端点限定为只接收某个用户的事件,其他用户的数据在投递前就被丢弃。两个过滤条件可以叠加使用,例如"只接收某用户的运动事件"。
调试:确认你的端点真的在收
这是新手最容易卡住的环节,Open Wearables 提供了三个调试利器:
- 发测试事件(强烈推荐先做)——不等待真实数据,直接触发一个逼真样例载荷:
curl -X POST "http://localhost:8000/api/v1/webhooks/endpoints/ep_xxx/test" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -d '{ "event_type": "workout.created" }' - 查看投递历史——
GET /api/v1/webhooks/endpoints/ep_xxx/attempts返回每一次投递的 HTTP 状态码和时间戳,4xx/5xx 一目了然 - 查看全部消息——
GET /api/v1/webhooks/messages可看到所有已发送消息
对应前端组件为投递记录表格 webhook-attempts-table.tsx 和测试事件对话框 webhook-test-event-dialog.tsx。
常见故障速查
| 症状 | 排查方向 |
|---|---|
| 什么都没收到 | 确认OUTGOING_WEBHOOKS_ENABLED=true并已重启;确认端点是公网 HTTPS |
| 收到但返回 400 | 大概率验签失败——确认用的是原始请求体字节做 HMAC,而非反序列化后的对象 |
| 事件被重复处理 | 用svix-id做幂等存储,重试会携带同一 ID |
| 间歇性丢失 | 检查 attempts 接口的状态码;端点应快速返回 2xx,重活丢进后台队列 |
最佳实践清单
- ✅ 验签通过后立即返回 2xx,把重计算异步化——超时会被视为失败并重试
- ✅ 用
svix-id做幂等键,重试安全 - ✅ 即使是"不感兴趣"的事件也返回 2xx,否则会被反复重投
- ✅ 拉取 API 始终可用,用作补数、对账或丢失恢复
- 🛡️ 数据入库永不因 Webhook 故障而阻塞——投递失败只会排队重试(实现见 events.py)
进阶阅读
- 完整 API 参考与载荷字段说明:webhooks.mdx
- Svix 投递服务封装:svix.py
- Webhook 事件触发助手函数:events.py
- 开发者门户中的 Webhooks 页面:前端路由 webhooks.tsx
照着以上步骤走完,你的应用就能在用户每跑完一次步、每睡完一晚的几分钟内收到推送——这才是"实时健康数据"应有的样子 🏃💤
【免费下载链接】open-wearablesSelf-hosted platform to unify wearable health data through one AI-ready API.项目地址: https://gitcode.com/gh_mirrors/op/open-wearables
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考