Skip to main content

wearable-sync

Wearable device data sync: import health data from Garmin watches (Body Battery, HRV, sleep, heart rate), Apple Health, Huawei, Xiaomi (Gadgetbridge), Zepp devices. Pluggable provider architecture.

Aller à l'installation

Informations de source

Dépôt
ShoumikSaha/agent-skill-security
Dernière activité de la source
12 mai 2026 à 23:24
Langue détectée de SKILL.md
chinois
Étoiles
17
Forks
2

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
15 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
wearable-sync
description
Wearable device data sync: import health data from Garmin watches (Body Battery, HRV, sleep, heart rate), Apple Health, Huawei, Xiaomi (Gadgetbridge), Zepp devices. Pluggable provider architecture.
# Wearable Sync - 可穿戴设备数据同步 从可穿戴设备(手环/手表)采集健康数据并写入 mediwise-health-tracker 的 health_metrics 表。 ## 支持的设备/Provider | Provider | 状态 | 数据来源 | 支持指标 | |----------|------|----------|----------| | Gadgetbridge | ✅ 已实现 | 本地 SQLite 导出文件 | 心率、步数、血氧、睡眠 | | Apple Health | ✅ 已实现 | export.xml / export.zip | 心率、步数、血氧、睡眠、体重、身高、体脂、血糖、血压、卡路里 | | **Garmin Connect** | ✅ 已实现 | Garmin Connect 账号(非官方 API) | 心率、睡眠分期、HRV、身体电量、压力、步数、卡路里、血氧、活动记录 | | 华为 Health Kit | 🔜 Stub | REST API(需企业开发者资质) | — | | Zepp Health | 🔜 Stub | REST API(需开发者账号) | — | | OpenWearables | 🔜 Stub | 统一 API(暂不支持华为/小米) | — | > **强制规则**:每次调用脚本必须携带 `--owner-id`,从会话上下文获取发送者 ID(格式 `<channel>:<user_id>`,如 `feishu:ou_xxx` 或 `qqbot:12345`)。所有设备管理和同步操作均需携带,不得省略。 ## Garmin Connect 接入说明 ### 前置依赖 ```bash pip install garminconnect ``` > Garmin 使用非官方 API(模拟 Web 登录),无需申请开发者账号。需要用户的 Garmin Connect 账号和密码。 ### 绑定流程 ```bash # 1. 添加 Garmin 设备 python3 {baseDir}/scripts/device.py add --member-id <id> --provider garmin --device-name "Garmin Fenix 7" # 2. 配置账号(--prompt-password 交互输入,密码不经过模型) python3 {baseDir}/scripts/device.py auth --device-id <id> \ --username you@example.com \ --prompt-password \ --tokenstore /home/ubuntu/.garmin_tokens # 终端会提示"请输入密码",输入时不回显,密码不出现在命令行/日志/模型上下文中 # 也可通过环境变量传入(适合 CI/cron 无终端场景) # export GARMIN_PASSWORD='yourpass' # python3 device.py auth --device-id <id> --username you@example.com --tokenstore ... # 3. 测试连接 python3 {baseDir}/scripts/device.py test --device-id <id> # 4. 同步数据 python3 {baseDir}/scripts/sync.py run --device-id <id> ``` **Agent 引导规则(重要):** - **禁止在聊天中索要密码**:密码一旦在对话框输入,就会出现在模型上下文和服务端日志中 - 正确做法:先收集邮箱和 tokenstore 路径,然后生成一条 `device.py auth ... --prompt-password` 命令,让用户在自己的终端运行(可用 `! <命令>` 直接在会话执行),密码由终端 `getpass` 读取,全程不经过模型 **Agent 引导步骤(agent 对话中按序询问):** 1. **确认设备名称**:请问你的佳明手表型号是?(如 Fenix 7、Forerunner 965,填写任意名称即可) 2. **收集邮箱**:你的 Garmin Connect 登录邮箱是? 3. **是否保存登录状态**:是否保存登录 token?(推荐,设置后登录一次即可,后续同步无需密码) - 是 → 询问 tokenstore 目录(可用默认值 `~/.garmin_tokens`) 4. **生成命令让用户自行输入密码**(不在聊天里问密码): ``` 请在你的终端运行以下命令,运行后会提示输入密码(不回显,不经过我): ! python3 {baseDir}/scripts/device.py auth --device-id <id> --username <邮箱> --prompt-password --tokenstore ~/.garmin_tokens ``` 5. 命令运行成功后,调用 `device-test` 验证连接,再调用 `sync-device` 拉取近 7 天数据 - 若返回错误含「升级库」提示,告知用户执行 `pip install --upgrade garminconnect` - 若返回错误含「两步验证」提示,告知用户需要在终端完成一次性验证后重试 ### Agent 引导用户配置佳明的对话规则 当用户表达以下意图时,agent 应主动引导完成绑定流程: - "我用佳明"、"我有 Garmin 手表"、"帮我绑定佳明" - "我想同步佳明数据"、"我的 Fenix / Forerunner / Venu / Vivoactive" **同步频率建议**:每小时最多同步一次,可通过 cron 自动定时同步。 ### 支持的 Garmin 指标 | metric_type | 说明 | 数据格式 | |---|---|---| | `heart_rate` | 全天心率(5分钟间隔) | `"72"` | | `sleep` | 睡眠分期汇总 | `{"duration_min":420,"deep_min":80,"light_min":210,"rem_min":100,"awake_min":30,"score":78}` | | `hrv` | 夜间 HRV(RMSSD) | `{"rmssd":45.2,"weekly_avg":43.0,"status":"BALANCED"}` | | `body_battery` | 身体电量(5分钟间隔) | `{"level":72,"charged":5,"drained":2}` | | `stress` | 压力指数(3分钟间隔) | `"28"` | | `steps` | 每日步数汇总 | `{"count":8500,"distance_m":6200,"calories":320}` | | `calories` | 活动卡路里 | `"320"` | | `blood_oxygen` | 血氧(SpO2,小时均值) | `"97"` | | `weight` | 体重(kg,来自 Garmin Connect 体重记录) | `"72.5"`,extra 含 `bmi`/`bodyFat`/`muscleMass` 等(设备支持时) | | `activity` | 运动记录 | `{"activity_type":"running","duration_sec":3600,"distance_m":10000,"avg_hr":152}` | | `respiration` | 呼吸频率(次/分钟,睡眠期间采样,设备支持时) | `"14.5"` | | `training_readiness` | 训练准备度评分(0-100,综合睡眠/HRV/负荷等子项) | `{"score":72,"level":"GOOD","sleep_score":80,"hrv_status":"BALANCED"}` | | `training_status` | 训练状态(VO2 Max、有氧/无氧负荷,需设备支持) | `{"vo2_max":48.2,"status":"PRODUCTIVE","aerobic_load":1.2}` | | `floors` | 爬楼层数(每日累计) | `{"ascended":12,"descended":10}` | | `hydration` | 水分摄入(ml,需在 Garmin Connect App 手动记录) | `{"intake_ml":1800.0,"sweat_loss_ml":650.0}` | ### 注意事项 - Garmin 账号若开启双重验证(2FA),首次登录需要在终端手动输入验证码;配置 `tokenstore` 后后续无需重复验证。 - Garmin Connect 服务器有速率限制,建议同步频率不超过每小时一次。 - 佳明「身体电量」(Body Battery)是 Garmin 专有指标,存储为 `body_battery` 类型,可与饮食数据联合分析恢复趋势。 - 高驰(COROS)、Polar、Suunto 暂无官方 API,可通过 Strava 同步后使用 Strava provider(待实现)间接接入活动记录。 ## 核心工作流 ### 1. 设备绑定 用户需要先绑定设备,指定 Provider 和配置信息: ```bash # 添加 Gadgetbridge 设备 python3 {baseDir}/scripts/device.py add --member-id <id> --provider gadgetbridge --device-name "小米手环 8" # 配置 Gadgetbridge 导出文件路径 python3 {baseDir}/scripts/device.py auth --device-id <id> --export-path /path/to/Gadgetbridge.db # 查看已绑定设备 python3 {baseDir}/scripts/device.py list --member-id <id> # 测试设备连接 python3 {baseDir}/scripts/device.py test --device-id <id> # 移除设备 python3 {baseDir}/scripts/device.py remove --device-id <id> ``` ### 2. 数据同步 ```bash # 同步单个设备 python3 {baseDir}/scripts/sync.py run --device-id <id> # 同步某成员所有设备 python3 {baseDir}/scripts/sync.py run --member-id <id> # 同步所有活跃设备 python3 {baseDir}/scripts/sync.py run-all # 查看同步状态 python3 {baseDir}/scripts/sync.py status --device-id <id> # 查看同步历史 python3 {baseDir}/scripts/sync.py history --device-id <id> --limit 10 ``` ### 3. 定时同步 Skill 本身不运行后台进程。由 OpenClaw agent 每日定时触发,或用户手动请求时触发。 **OpenClaw 定时触发规范(agent 按此执行):** 每日早晨 7:30 前,agent 应自动触发一次全量同步,流程如下: 1. 调用 `sync-all` 同步所有活跃设备 2. 若返回 `synced > 0`,继续触发 health-monitor 检测(见 health-monitor/SKILL.md) 3. 若有告警,合并进当日健康简报推送(见 mediwise-health-tracker/SKILL.md 的「每日简报推送规范」) 4. 若同步失败(认证错误/网络错误),**不静默忽略**,主动通知用户: > "今日佳明手表数据同步失败:{错误原因},请检查网络或重新绑定设备。" **用户手动请求时触发规范:** 当用户说"同步一下手表"、"更新健康数据"、"刷新佳明数据"等时,立即执行 `sync-device` 或 `sync-all`,同步完成后告知结果。 ```bash # 备用:cron 直接调用(不依赖 agent,适合服务器独立部署) # 每小时整点同步一次 0 * * * * cd /path/to/wearable-sync/scripts && python3 sync.py run-all >> ~/mediwise-sync.log 2>&1 ``` ## 数据标准化 不同设备返回的原始数据格式各异,同步时统一转换为 health_metrics 格式: | 设备原始字段 | metric_type | value 格式 | |---|---|---| | Gadgetbridge HEART_RATE | heart_rate | "72" | | Gadgetbridge RAW_INTENSITY (steps) | steps | `{"count":8500,"distance_m":0,"calories":0}` | | Gadgetbridge SpO2 | blood_oxygen | "98" | | Gadgetbridge SLEEP | sleep | `{"duration_min":480,"deep_min":120,...}` | ## 去重策略 同步时按 `(member_id, metric_type, measured_at, source)` 做唯一性检查。已存在的同源同时间点数据会被跳过,并记录到 `wearable_sync_log` 中。 ## Gadgetbridge 导出说明 1. 打开 Gadgetbridge App → 设置 → 数据库管理 → 导出数据库 2. 导出文件为 `Gadgetbridge` 或 `Gadgetbridge.db`(SQLite 格式) 3. 将文件传输到电脑,使用 `device.py auth --export-path` 配置路径 ## Apple Health 导出说明 1. iPhone → 健康 App → 右上角头像 → 导出健康数据 2. 生成 `export.zip`(内含 `export.xml`) 3. 将文件传输到电脑,按以下步骤绑定: ```bash # 添加 Apple Health 设备 python3 {baseDir}/scripts/device.py add --member-id <id> --provider apple_health --device-name "iPhone" # 配置导出文件路径(支持 .xml 或 .zip) python3 {baseDir}/scripts/device.py auth --device-id <id> --export-path /path/to/export.zip # 同步数据 python3 {baseDir}/scripts/sync.py run --device-id <id> ``` 支持指标:心率、静息心率、步数、血氧、睡眠分期、体重、身高、体脂率、血糖、血压、卡路里消耗。 ### Apple Health 持续更新方案 Apple Health 导出是**手动触发的快照**,不是实时流。要实现持续监测,需要定期更新导出文件并重新同步。 **推荐流程(每日自动化):** ``` iPhone 健康 App 导出 → AirDrop / iCloud Drive / USB 传输到 Mac → 覆盖固定路径的 export.zip → cron 定时触发 sync.py → health-monitor check.py 检测异常 ``` **方案一:iCloud Drive 自动同步(推荐,Mac 用户)** 1. iPhone 导出时选择保存到 iCloud Drive 固定目录(如 `iCloud Drive/HealthExports/export.zip`) 2. Mac 上 iCloud Drive 自动同步该文件 3. 配置 `--export-path` 指向本地 iCloud 同步目录: ```bash ~/Library/Mobile\ Documents/com~apple~CloudDocs/HealthExports/export.zip ``` 4. 用户每次在 iPhone 重新导出覆盖该文件,Mac 自动同步,cron 定期执行同步 **方案二:快捷指令(Shortcuts)自动导出** iOS「快捷指令」App 可设置每日定时自动导出健康数据并上传到固定位置: 1. 新建快捷指令 → 添加「导出健康数据」动作 2. 添加「上传文件」动作(保存到 iCloud Drive 或通过 SSH/SFTP 上传到服务器) 3. 设置「自动化」→「每天早上 7:00 运行」 **方案三:手动定期导出(最简单)** 用户每周或每天手动在 iPhone 导出一次,通过 AirDrop 传到 Mac,覆盖固定路径即可。适合数据精度要求不高的场景。 **cron 自动同步配置(配合以上任一方案):** ```bash # 编辑 crontab crontab -e # 每小时同步一次 Apple Health 数据并触发健康检测 0 * * * * cd /path/to/wearable-sync/scripts && python3 sync.py run --device-id <device-id> >> ~/mediwise-sync.log 2>&1 5 * * * * cd /path/to/health-monitor/scripts && python3 check.py run-all --window 2h >> ~/mediwise-check.log 2>&1 ``` > **注意**:Apple Health 导出文件更新频率决定了数据新鲜度上限。iCloud 方案约有 5-15 分钟延迟;手动方案取决于用户导出频率。系统内置去重,重复同步同一文件不会产生重复数据。 ## 反模式 - **不要手动修改 Gadgetbridge 导出数据库** — 直接读取即可 - **不要频繁同步相同时间段** — 系统自动去重,但会浪费 I/O - **不要在同步过程中删除导出文件** — 等同步完成后再操作 - **OAuth Provider(华为/Zepp)当前为 Stub** — 调用会抛出 NotImplementedError ## Apple Health 实现依据与参考文献 ### HealthKit 官方文档 | 文档 | 链接 | 用途 | |------|------|------| | HKQuantityTypeIdentifier 枚举 | https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier | APPLE_TYPE_MAP 中所有类型字符串的权威来源 | | HKCategoryTypeIdentifier 枚举 | https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier | 睡眠分析类型 identifier | | HKCategoryValueSleepAnalysis | https://developer.apple.com/documentation/healthkit/hkcategoryvaluesleepanalysis | SLEEP_VALUE_MAP int→阶段映射依据 | | HKCorrelation(血压关联模型) | https://developer.apple.com/documentation/healthkit/hkcorrelation | 血压收缩压/舒张压配对60秒窗口依据 | | HealthKit 数据类型总览 | https://developer.apple.com/documentation/healthkit/data_types | export.xml Record 元素结构(type/startDate/value/unit) | ### 睡眠分期 int 映射(iOS 16+) `HKCategoryValueSleepAnalysis` 整数值含义(来源:Apple 开发者文档 + WWDC 2022 Session 10005): | 整数值 | 枚举名 | 映射到 | |--------|--------|--------| | 0 | inBed | awake | | 1 | asleepUnspecified | awake | | 2 | awake | awake | | 3 | asleepCore | light_sleep | | 4 | asleepDeep | deep_sleep | | 5 | asleepREM | rem_sleep | 值 0-2 为原始 API,值 3-5 在 iOS 16 引入精细睡眠分期时新增。 ### 单位换算依据 | 换算 | 系数 | 来源 | |------|------|------| | 血糖 mg/dL → mmol/L | ÷ 18.0182 | 葡萄糖摩尔质量 180.182 g/mol(SI 单位标准) | | 身高 m → cm | × 100 | SI 基本单位定义 | | 体重 lbs → kg | × 0.453592 | NIST 磅-千克换算定义值 | | 血氧/体脂 fraction→% | × 100 | iOS 旧版本以小数存储(≤1.0 判断) | ### 步数聚合 Apple Health 的 `HKQuantityTypeIdentifierStepCount` 为**分段采样**(非累计),每条 Record 记录一段时间内的步数增量。日步数总计通过对同一日历日内所有采样求和得到,与 Apple Health App 显示逻辑一致。 ### 大文件流式解析 Apple Health 导出文件可超过 1 GB,采用 `xml.etree.ElementTree.iterparse` + `elem.clear()` 模式以 O(1) 内存处理: - Python 官方文档:https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse
Voir sur GitHub