关于 Open Health Sync
Open Health Sync 是可自托管的健康数据接入与标准化层,面向应用开发者和希望在自有设备上汇总健康数据的用户。它将多种来源映射到统一模型,并提供 REST、FHIR R4 和只读 MCP 接口。
主要功能
- 01接入多种健康数据来源
- 02统一单位与数据模型
- 03保留原始载荷并支持重处理
- 04通过 REST 与 FHIR R4 提供数据
- 05支持同步状态与删除数据
适用场景
- 01为健康应用构建数据后端
- 02让 Agent 只读访问个人健康数据
- 03汇总可穿戴设备数据用于研究
- 04归档个人健康数据
MCP 相关
提供只读 MCP 服务,让 AI Agent 读取已同步的健康数据。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm -e OHS_MCP_URL -e OHS_MCP_KEY ghcr.io/soma-intelligence/open-health-sync:0.2.0OHS_MCP_URLBase URL of your Open Health Sync instance. Must be https unless the host is loopback (inside a container, loopback is the container itself).OHS_MCP_KEY密钥A user token with the read scope (ohs_ut_...) or a tenant API key (ohs_sk_...).本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/soma-intelligence/open-health-sync:0.2.0stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Open Health Sync
通过一个开放 API 获取可穿戴设备和健康数据。在自己的服务器上运行。
Apple Health、Withings、Oura、WHOOP、Fitbit、Health Connect、Dexcom、OMRON 等另外五个平台。
统一输出简洁的数据模型,支持 REST、FHIR R4,以及面向 AI Agent 的只读 MCP 服务。
免费,采用一个 Go 二进制文件和 Postgres,可在 Raspberry Pi 上运行。
开源、可自托管,是 Terra 等托管式可穿戴设备 API 的替代方案。
docker pull ghcr.io/soma-intelligence/open-health-sync:0.2.0
不想运行服务? 托管版测试服务提供相同的 API,无需运维:一分钟获取密钥,首次调用即可使用演示数据。
免费开始 → · 登录开发者门户 · ▶ 观看 75 秒介绍
快速入门 · 托管版测试服务 · 比较 · 路线图 · 使用场景 · 为什么 · 功能 · 工作原理 · MCP · 常见问题
如果它能帮你省去再写一个解析器的麻烦,点亮一颗 ⭐ 星标,让更多开发者发现它。问题和想法:讨论区。
v0.2.0,早期预览版。任何 0.x 版本都可能更改 API、配置和架构。
使用合成数据录制的快速入门,版本为 v0.1.0:启动服务栈,从六台设备加载 90 天的数据,然后读取合并视图中的一天数据,以及一条分别以 REST、FHIR R4 和 Open mHealth 格式返回的心率读数,最后读取 MCP 工具。所有内容都不是模拟的;录屏可再次渲染。
Open Health Sync(ohs)是一个可自托管的健康数据摄取与规范化层。它从服务提供商拉取数据,接受手机上传的数据,逐字存储每个负载,将其映射到使用统一单位的规范模型,并通过 REST API 和只读 MCP 服务提供数据。它不是仪表板或健康指导应用,也不是医疗器械或临床软件。你可以自行运行,也可以在托管测试版中让我们代为运行。
|
🔌 十八种来源,一个模型 |
⚡ 始终保持最新 |
🧾 不丢弃任何数据 |
|
🤖 为 AI Agent 做好准备 |
🏥 输出符合标准 |
🔒 数据属于你,也可彻底删除 |
由我们为你运行的同一服务。托管版测试无需你运维 Postgres、原始数据存储或工作进程:登录、创建密钥,即可在首次调用时读取数据。
通过测试数据进行 75 秒导览:创建账户和项目,通过 MCP 连接编码 Agent,加载示例数据,查看图表,在浏览器中调用 API,然后按 Ctrl K。播放视频(MP4,9 MB)。
- 一分钟获取密钥。 创建项目并获取 API 密钥。测试期间:每个账户最多三个项目,每个项目最多五个密钥。
- 首次调用即可获取数据。 单击一次,即可添加一位包含六个来源 30 天数据的合成用户,这样你的首次请求就能返回睡眠、心率和步数数据。
- 支持所有输出格式。 按此处文档所述,支持 REST 和 OpenAPI 文件、FHIR R4、Open mHealth、CSV 和 Parquet、签名 Webhook,以及只读 MCP 服务。
- 使用你的配置快速入门。 curl、TypeScript 和 Python 示例中已填入你的实例地址,还提供示例应用和通过 MCP 连接的 AI Agent。
- 无需迁移。 该服务运行的就是这个开源服务器。为其编写的代码只需更换基础 URL 和密钥,即可迁移到你自己的实例,也可迁回。
Web 示例使用项目密钥读取一位用户的数据:每日步数、静息心率和睡眠阶段,全部为合成数据。
这是一个免费测试版,开放注册并使用共享容量。目前仅接受测试数据:演示用户和合成用户,不接受真实人员的健康数据。自托管仍是首要支持方式,服务器在 AGPL 许可下始终免费。
免费开始 → 使用电子邮件注册并确认。已有账户?登录开发者门户。
路线图一览
✅ 已在 v0.2.0 中推出 · 🛠 计划中
| 输出和集成 | 数据来源 | ||
|---|---|---|---|
| ✅ | REST API(OpenAPI 3.1)、只读 MCP 服务 | ✅ | Apple Health、Withings |
| ✅ | FHIR R4(Observations,已通过 HL7 验证器检查) | ✅ | Oura、WHOOP、Polar、Strava |
| ✅ | Open mHealth 输出(文档) | ✅ | Fitbit、Suunto、Ultrahuman、intervals.icu |
| ✅ | CSV 和 Parquet 导出(文档) | ✅ | Dexcom(CGM)、OMRON |
| ✅ | 外发 Webhook(文档) | ✅ | Health Connect(Android 应用上传) |
| ✅ | 后台同步和 /freshness | ✅ | Health app 导出数据导入 |
| ✅ | Prometheus 指标和 OpenTelemetry 跟踪,默认关闭(文档) | ||
| ✅ | 跨数据源的合并视图,可为每位用户和每项指标设置优先级(文档) | ||
| ✅ | /console 管理控制台:运行管道,并在浏览器中启用数据提供方(文档) | ||
| ✅ | 按用户、数据来源和类别设置同意状态,并提供撤销 Webhook(文档) | ||
| ✅ | 完整的逐用户归档,支持数据可移植性(文档) | ||
| ✅ | 记录每个已认证请求的仅追加审计日志,可通过 GET /v1/audit 读取(文档) | ||
| ✅ | 备份和恢复脚本,已在 CI 中测试(文档) | ||
| ✅ | 通过 Helm chart 部署到 Kubernetes(文档) | ||
| ✅ | Render、Fly.io 和 Railway 的部署模板(文档) | ||
| ✅ | 托管式连接页面:显示你的应用名称和徽标,每个数据来源对应一个按钮(文档) | ||
| ✅ | 断开连接时,删除用户某个数据来源的数据;Apple Health 和 Health Connect 也支持此操作 | ||
| ✅ | 提供 12 个关于训练、睡眠和恢复的 MCP 提示词,以及一项 Agent 技能(文档) | ||
| ✅ | TypeScript 和 Python 服务端 SDK,以及 Postman 集合(文档) | ||
| ✅ | 对面向数据提供方的路由实施速率限制(文档) | ||
| ✅ | 使用 cosign 对镜像和 checksums.txt 进行无密钥签名(验证) | ||
| ✅ | 在线轮换加密密钥(文档) | ||
| ✅ | 通过 REST 和 MCP,按指标类型提供任意时区的小时和每日统计数据(文档) | ||
| ✅ | 首次运行时可在浏览器中通过一次性令牌完成设置,并实施速率限制,因此应用商店无需进行终端操作(文档) | ||
| ✅ | Xiaomi:导入 Mi Fitness 数据,并通过 Health Connect 归因 Xiaomi、Amazfit 和 RingConn 数据(指南) | ||
| ✅ | Garmin:面向拥有自有 Garmin 应用的运营方提供 Health API 连接器(每日摘要、睡眠、活动、HRV、身体成分等)(指南) | ||
| ✅ | 活动文件:FIT、GPX 和 TCX,以及 Garmin、COROS、Wahoo、Suunto、Zwift 和 Strava 的导出文件,可使用 ohs import files 导入(指南) | ||
| ✅ | 通过 REST、FHIR(以 SampledData 表示波形)、MCP 和导出文件处理 ECG 记录(文档) | ||
| ✅ | 自我报告:将个人自行评定(感受、情绪、压力、精力、睡眠质量等)与其同步数据并列显示(文档) | ||
| ✅ | 分享链接(SMART Health Links):为医生或教练生成加密的 FHIR Bundle,并提供过期时间、密码和内置查看器(文档) | ||
| ✅ | 通过 HTTP 和实例管理员密钥管理租户及其 API 密钥,让一个实例为多个团队提供服务(文档) | ||
| ✅ | 个人模式(ohs admin personal setup)以及八个针对自有数据的 Go 小示例 | 🛠 | 通过 SMART on FHIR 接入健康记录(EHR) |
| ✅ | Kotlin、Swift、React Native 和 Flutter SDK及示例应用 | 🛠 | Coros |
| 只有在发布版本发布后,某一行才会向上移动。各数据源的详情见: | |||
| docs/connectors。 |
可以构建什么
- 健康应用后端。 你的 iOS 应用上传 HealthKit 数据,用户连接自己的 Oura、WHOOP 或 Withings 账户(通过带有你品牌标识的托管连接页面),而你的应用只需读取一个 API,而不是十八个。
- 基于你自己的数据运行 AI Agent。 在家中运行它,连接你的设备,并通过 MCP 让桌面 Agent 以只读方式查看你的睡眠、锻炼和心率数据。
- 收集参与者可穿戴设备数据的研究。 保留原始负载以供审计,参与者退出时彻底删除数据,并向分析端提供 FHIR R4 数据。
- 个人数据档案。 通过一条命令导入 Health 应用导出文件中的多年历史数据,并将其保存在自己拥有的机器上。
- 基于自己数据的小工具。
ohs admin personal setup可为你自己创建一个实例,recipes 则提供睡眠报告、心率趋势、每周摘要、仪表盘等更多内容,每项都只需一个 Go 文件,无需依赖。
为什么要用
每个健康数据源都有自己的方言。Apple Health 每个 HealthKit 样本发送一行 JSON,心率单位为 count/min,血氧饱和度则以小数表示。Withings 发送按日期索引的每日活动对象,以及按 Unix 时间戳索引的日内序列。每个数据源对日期、设备和重复数据都有自己的定义。
因此,团队会为每个提供商编写一个脚本:解析器、一张表、一个 cron 任务。第一个提供商能正常运行,但遇到第二个提供商、首次重新发送的上传、需要回填的首个映射错误,或第一个要求删除你持有的所有个人数据的人时,就会出问题。
Open Health Sync 就是这一层:一次编写,并妥善处理那些繁琐的部分。
| 每个提供商自行编写脚本 | Open Health Sync | |
|---|---|---|
| 添加数据源 | 新的解析器、新的表、新的 cron 任务 | 一个映射到同一模型的连接器 |
| 单位 | 各 API 返回什么就用什么 | 每种数量使用一种单位,原始值和单位保存在 metadata 中 |
| “今天” | UTC,或提供商的时钟 | 记录所在时区的本地日历日 |
| 重新发送的上传 | 存储两次 | 返回 200,并带有 "duplicate": true;根据内容哈希对记录去重 |
| 原始负载 | 解析后丢弃 | 原样保存在磁盘或 S3 上,修复后可重新处理用户数据 |
| 是否已完成? | 猜测,或查看日志 | GET /coverage:pending_jobs、parked_jobs、rejected_records |
| 数据是否最新? | 一个 cron 任务,全靠运气 | 由 Webhook 触发拉取,并执行兜底拉取;每个数据源可通过 GET /freshness 查看状态 |
| 提供商处已删除的记录 | 仍留在你的表中 | 提供商报告删除后,这里的记录也会删除 |
| 新数据已到达 | 定时轮询 | 带签名的 Webhook(data.written)会列出用户、提供商和日期 |
| 运行中途崩溃 | 重新运行脚本并祈祷 | Postgres 队列,失败后带退避重试,5 次尝试后搁置 |
| 提供商 OAuth 令牌 | 明文存储在列中或 .env 文件里 | 使用 OHS_ENCRYPTION_KEY 通过 AES-256-GCM 加密 |
| 删除用户 | 在表和存储桶中逐个搜索 | DELETE /v1/users/{id},然后轮询 GET /v1/deletions/{job_id} |
| 删除某个提供商的数据 | 同样的搜索,手动筛选 | DELETE /v1/users/{id}/connections/{provider}?delete_data=true;删除某台设备的数据则使用 DELETE /v1/users/{id}/data/{provider} |
| 让 AI Agent 读取数据 | 自行构建集成 | 只读 MCP 服务;桌面 Agent 使用 ohs mcp |
功能
- 一个规范模型。 数量样本、类别样本、睡眠时段和阶段、锻炼和路线、营养、每日摘要。每条记录都带有其来源信息:
provider、source、device和ingested_at。 - 每种数量只用一个单位。 数量名称附带 UCUM 单位和 LOINC 代码(数据模型)。无论来源如何命名,心率都使用
bpm。 - 保留原始载荷。 每次上传和拉取都会先存入原始数据存储(本地文件夹或任意兼容 S3 的存储桶),然后才进行其他处理,且绝不会被改写。修复映射器后,任何用户都可以从原始文件重新处理(方法)。
- 按本地日期,而非 UTC 日期。 每日摘要按记录所在时区的本地日历日生成。如果提供方未发送每日摘要,则根据样本计算步数、能量和距离总量。
- 幂等上传。 每个 Apple Health 分片都按其日期、批次和分片编号存储。重新发送相同字节时会返回
200和"duplicate": true;已占用的键若对应其他字节则会被拒绝,不会覆盖原数据。记录按内容哈希去重。 - 始终保持最新,无需同步按钮。 提供方 Webhook 会触发拉取,仅获取发生变化的内容,并优先于任何例行任务;每 6 小时执行一次兜底拉取(Webhook 无响应时则每小时一次),以捕获遗漏内容。
GET /v1/users/{id}/freshness会显示每个来源的数据时效(后台同步)。 - 了解处理状态。 覆盖率报告统计各提供方和本地日期的记录数量,还会列出仍在等待的任务、重试后搁置的任务,以及未存储的行。
- 真正删除。
DELETE /v1/users/{id}会移除用户的原始文件和所有数据行,然后删除用户。这不是软删除标记。当提供方报告某条记录已删除时(Oura、WHOOP、Strava),此处也会删除该记录。使用?delete_data=true断开来源连接,会删除该来源为用户发送的所有数据(记录、原始文件、同步历史);DELETE /v1/users/{id}/data/{provider}对 Apple Health 或 Health Connect 也会执行相同操作。OHS_RETENTION_DAYS会删除超过指定期限的原始文件和规范化数据。 - 按类别征求同意。 每位用户都可以按数据类别(睡眠、心脏、位置、血糖等)授权或拒绝每个来源。未获授权的数据会在存储前丢弃;撤销某类别的授权会删除已存储的数据;
consent.granted和consent.revokedWebhook 会通知你的服务端(指南)。 - 一次调用即可导出用户档案。
GET /v1/users/{id}/archive会将有关某人的所有数据打包成一个 ZIP 文件返回,以满足访问和数据可携带性请求(文档)。 - 多租户。 使用租户 API 密钥(
ohs_sk_)供你的服务端使用;使用短时有效、带作用域的用户令牌(ohs_ut_,作用域为upload和read)供某个人的应用或 Agent 使用。密钥和令牌以 SHA-256 哈希形式存储。 - 出站 Webhook。 当同步写入或删除数据、用户被删除,或需要用户重新连接时,你的服务端会收到通知。按照 Standard Webhooks 签名,最多重试约 28 小时,且载荷精简:不会泄露任何健康数值(指南)。
- 供 AI Agent 使用的只读 MCP。 用户可以将自己的 Agent 连接到自己的数据,并使用只能读取数据的令牌。
- 一个二进制文件加 Postgres。 队列存储在 Postgres 中(
FOR UPDATE SKIP LOCKED)。无需消息代理、缓存或工作节点集群。api、collect和etl角色可以在同一进程中运行,也可以分开运行。 - 轻量运行。 配备 4 GB 内存的 Raspberry Pi 5 即可运行完整堆栈,并提供专为其调优的 compose 覆盖配置。超过 30 天的样本会压缩,磁盘占用约缩小至原来的七分之一,向其中重新导入历史数据仍然很快。
- 开放标准。 OpenAPI 3.1 文件描述 API;FHIR R4 Observations 会使用 HL7 官方验证器进行校验(
scripts/fhir-validate.sh);MCP 是开放协议;ohs doctor会在你信任配置前对其进行检查。 - 没有评分,也不内置 AI。 它止步于提供整洁、可追溯的数据。在此基础上构建洞察。
数据来源和输出
v0.2.0 中有 18 个数据来源,其中 5 个是新增的:Garmin、Eight Sleep、Xiaomi、活动文件和 Bluetooth 设备。Amazfit 和 RingConn 通过 Health Connect 接入。 其他数据来源都在计划中:已列入路线图,但尚未构建。 各数据来源的集成路径、厂商计划和跟踪问题: docs/connectors。
| 数据来源 | 状态 | 数据接入方式 |
|---|---|---|
| Apple Health | ✅ 可用 | 你的 iOS 应用通过 Swift SDK 上传 HealthKit 数据,或使用自己的代码(接口约定);ohs import apple-health 可加载 Health 应用导出数据 |
| Withings | ✅ 可用 | OAuth、定时拉取、推送通知(指南) |
| Oura | ✅ 可用 | OAuth、定时拉取、webhook(指南) |
| Whoop | ✅ 可用 | OAuth、定时拉取、webhook(指南) |
| Strava | ✅ 可用 | OAuth、定时拉取、webhook 事件(指南) |
| Polar | ✅ 可用 | OAuth、定时拉取、webhook(指南) |
| Garmin | ✅ 可用 | 合作伙伴计划:OAuth 搭配 PKCE、定时拉取、Garmin 通知;你需要自备 Garmin 应用,且 Garmin 已暂停接受新申请(指南) |
| Fitbit | ✅ 可用 | Google Health API:OAuth、定时拉取、签名 webhook(指南)。未经验证的 Google 项目最多可服务 100 位用户 |
| Suunto | ✅ 可用 | 合作伙伴计划:OAuth、定时拉取、签名通知(指南) |
| Ultrahuman | ✅ 可用 | Partnership API:OAuth、每日拉取;戒指数据和 M1 血糖(指南) |
| intervals.icu | ✅ 可用 | OAuth、定时拉取、webhook;来自 Garmin、Wahoo、Zwift、Coros 等平台的活动,以及每日健康数据(指南) |
| Health Connect | ✅ 可用 | 你的 Android 应用上传 Health Connect 记录(接口约定) |
| Dexcom | ✅ 可用 | CGM 血糖:OAuth、定时拉取(指南) |
| OMRON | ✅ 可用 | 血压和体重:合作伙伴 API、OAuth、定时拉取(指南) |
| Xiaomi | ✅ 可用 | ohs import mi-fitness 可加载 Mi Fitness 数据副本(完整历史记录);后续数据通过 Health Connect 或 Apple Health 接入(指南) |
| Bluetooth 设备 | ✅ 可用 | 通过 ohs-bridge 桌面桥接程序(macOS、Linux、Raspberry Pi、Windows)或 Swift 和 Kotlin SDK,接入采用标准 Bluetooth 健康配置的心率带、血压袖带、体重秤、血糖仪、温度计和脉搏血氧仪;无需厂商账户(指南) |
| 活动文件 | ✅ 可用 | ohs import files 可加载 FIT、GPX 和 TCX 文件,以及 Garmin、COROS、Wahoo、Suunto、Zwift 和 Strava 导出数据(指南) |
| FreeStyle Libre | 无公开 API | 通过 Health Connect 或 Apple Health 接入(说明) |
| Coros | 🛠 计划中 | 云 API、OAuth |
| Zepp / Amazfit、RingConn | ✅ 可用,通过 Health Connect | 其应用会在 Android 上写入 Health Connect;记录保留各自的数据来源(zepp、ringconn)(详情) |
| Samsung Health | 🛠 计划中,通过 Health Connect | 其应用会在 Android 上写入 Health Connect |
| Google Fit | 已被 Google 弃用 | 请使用 Health Connect |
| Eight Sleep | ✅ 可用 | 无公开 API:使用 Eight Sleep 应用所用的登录方式,定时拉取睡眠阶段、心率、HRV、呼吸和床垫温度(指南) |
| 想更快接入?连接器都是独立的:请阅读 | ||
| 编写连接器,并挑选一个 | ||
| 适合新手的议题。 |
| 输出 | 状态 |
|---|---|
| REST JSON,由 api/openapi.yaml 描述 | ✅ 已提供 |
| MCP 服务,只读(docs/mcp.md) | ✅ 已提供 |
| FHIR R4,已通过 HL7 官方验证器检查(docs/fhir.md) | ✅ 已提供(Observations、Patient、Device、Provenance、Patient $everything) |
| 每个心搏序列的 RR 间期和 HRV(RMSSD、SDNN、pNN50、平均 RR 和心率),通过 REST 和 MCP 提供(docs/hrv.md) | ✅ 已提供 |
| 根据记录的经期流量推导月经周期,通过 REST 和 MCP 提供;不作预测(docs/menstrual-cycles.md) | ✅ 已提供 |
| 为数据提供背景信息的时间标签(疾病、受伤、旅行、时差、疫苗接种、用药、饮酒),通过 REST、webhook 和 MCP 提供(docs/time-tags.md) | ✅ 已提供 |
| 已存储 ECG 记录的读取路由 | 🛠 计划中 |
FHIR R4 批量导出($export) | 🛠 计划中 |
| Open mHealth(docs/open-mhealth.md) | ✅ 已提供 |
| CSV 和 Parquet 导出(docs/exports.md) | ✅ 已提供 |
| 根据 Standard Webhooks 进行签名的出站 webhook(docs/webhooks.md) | ✅ 已提供(数据写入或删除、用户数据擦除、连接需要重新授权) |
| 客户端 SDK:Kotlin、Swift(支持 HealthKit 同步)、React Native、Flutter,以及适用于 iOS、Android 和 React Native 的示例应用(docs/sdks) | ✅ 已提供(从此仓库安装;未发布到包注册表) |
| 健康记录(EHR):通过 SMART on FHIR 读取化验结果、病症、药物和过敏信息,并以 FHIR R4 提供 | 🛠 计划中 |
快速入门
你需要安装 Docker 和 Compose v2.24 或更高版本,以及 curl、jq 和 openssl。Compose 会拉取已发布的镜像 ghcr.io/soma-intelligence/open-health-sync(amd64 和 arm64)。
git clone https://github.com/soma-intelligence/open-health-sync.git && cd open-health-sync
cp .env.example .env
sed -i.bak "s|^OHS_ENCRYPTION_KEY=.*|OHS_ENCRYPTION_KEY=$(openssl rand -base64 32)|" .env
docker compose --env-file .env -f deploy/docker-compose.yml up -d --wait
docker compose --env-file .env -f deploy/docker-compose.yml run --rm ohs doctor
docker compose --env-file .env -f deploy/docker-compose.yml exec ohs /ohs admin tenant create --name dev
ohs doctor 会为每项检查(配置、数据库、原始存储、公开 URL、连接器)打印一行 ok 或 fail;每次更改 .env 后都要重新运行。最后一条命令会显示一次租户 API 密钥。请妥善保存:
export OHS=http://localhost:8080
export KEY=ohs_sk_... # the key printed above
API 仅监听 127.0.0.1,因此这些步骤需要在同一台机器上执行。手机应用、提供商 Webhook 或另一台计算机需要访问该 API:在前面配置带 TLS 的反向代理,或者在 .env 中设置 OHS_HTTP_BIND=0.0.0.0,以便在网络中通过普通 HTTP 访问。
还没有设备或提供商密钥?ohs seed --demo 会用来自六个重叠数据源的 90 天合成数据填充实例,并打印一个演示 API 密钥以及可尝试的调用
(docs/demo.md):
docker compose --env-file .env -f deploy/docker-compose.yml exec ohs /ohs seed --demo
8080 端口已被占用?在 .env 中设置 OHS_HTTP_PORT 和相应的 OHS_PUBLIC_URL(参见
自托管)。
创建最终用户以及该用户的应用会持有的令牌:
USER_ID=$(curl -s -X POST $OHS/v1/users -H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' -d '{"external_ref":"demo"}' | jq -r .id)
TOKEN=$(curl -s -X POST $OHS/v1/users/$USER_ID/tokens -H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' -d '{"scopes":["upload"]}' | jq -r .token)
上传一条 Apple Health 数据(一个心率读数,使用 gzip 压缩):
DAY=$(date -u +%Y-%m-%d); NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
printf '{"quantityType":"HKQuantityTypeIdentifierHeartRate","startDate":"%s","endDate":"%s","value":72,"unit":"count/min","sourceName":"Demo Watch","metadata":{"HKTimeZone":"UTC"}}\n' "$NOW" "$NOW" \
| gzip | curl -s -X POST $OHS/v1/ingest/apple-health \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/gzip" \
-H "X-OHS-Type: HKQuantityTypeIdentifierHeartRate" -H "X-OHS-Day: $DAY" \
-H "X-OHS-Batch: demo1" -H "X-OHS-Part: 0" --data-binary @-
等待处理完成(pending_jobs 为 0),然后读取规范化后的样本:
curl -s "$OHS/v1/users/$USER_ID/coverage" -H "Authorization: Bearer $KEY"
curl -s "$OHS/v1/users/$USER_ID/samples?type=heart_rate" -H "Authorization: Bearer $KEY"
在你的机器上安装 ohs 二进制文件。 下面的导入操作和 MCP 设置 都会在容器外运行 ohs。从发布页面下载适用于你系统的归档文件
(ohs_<version>_<os>_<arch>.tar.gz,os 为 linux 或 darwin,arch 为 amd64 或
arm64);解压后会得到一个同名文件夹:
tar xzf ohs_*_linux_amd64.tar.gz
sudo install ohs_*_linux_amd64/ohs /usr/local/bin/ohs
ohs version
在 macOS 上,先清除隔离标记:xattr -d com.apple.quarantine ohs_*_darwin_*/ohs。
导入现有历史数据。
在 iPhone 上,打开“健康”App,轻点你的头像,然后选择导出所有健康数据,即可获得 export.zip。使用用户令牌导入(先用 --dry-run 统计将要发送的数据):
OHS_TOKEN=$TOKEN ohs import apple-health export.zip --url $OHS
记录、带路线的锻炼数据和 ECG 都会通过同一个上传 API 处理,且内存占用恒定。再次运行时不会重复上传。详情请参阅: 导入导出文件。
数据存储在 pgdata 和 raw 卷中;执行 docker compose ... down 会保留这些数据。
工作原理
flowchart LR
AH["Apple Health, Health Connect<br/>app upload, export import"] --> C
CL["Withings, Oura, WHOOP, Fitbit,<br/>Polar, Strava, Suunto, Ultrahuman,<br/>intervals.icu, Dexcom, OMRON<br/>OAuth pull + webhooks"] --> C
C["collect / ingest"] --> R[("raw store<br/>disk or S3")]
R --> E["ETL<br/>normalize, dedup,<br/>units, local-day summaries"]
E --> P[("Postgres<br/>+ TimescaleDB")]
P --> API["REST API<br/>(OpenAPI)"]
P --> MCP["MCP server<br/>(read only)"]
P --> FHIR["FHIR R4<br/>Observations"]
- 收集。 你的 iOS 应用会将 HealthKit 数据作为 gzip NDJSON 分段发送到
POST /v1/ingest/apple-health,并附带具有upload作用域的用户令牌,以及X-OHS-Type、X-OHS-Day、X-OHS-Batch和X-OHS-Part标头。云端提供商(Withings、Oura、WHOOP、Fitbit 等)会在发送 Webhook 时触发拉取(仅拉取变更内容),并按计划执行备用拉取。 - 保存原始负载。 分段会先写入原始存储,然后在 Postgres 中创建任务。响应会包含原始键,以及该分段是否重复。
- 规范化。
etl角色会将每行映射到规范模型、转换单位、去除重复项、标注来源和设备,并按本地日期汇总每日数据。 - 提供数据。 使用租户密钥通过
GET /v1/users/{id}/...读取数据,并通过游标分页。MCP 服务以只读方式读取相同的数据。
启用提供方,然后用户连接
在管理控制台中粘贴 Oura 应用的密钥,Oura 即会启用,无需重启。随后,应用会创建一个连接链接并发送给用户。用户选择 Oura,然后选择 Withings,并分别授权访问。ohs 会交换代码、加密存储授权,在后台拉取历史数据并进行规范化。返回控制台后,管道会显示数据流转情况,用户页面则会显示每个来源均处于活跃且数据最新的状态。
使用合成数据在此代码库中录制。控制台、连接页面、代码交换、加密授权、后台拉取和规范化都是真实实现;提供方一侧(授权页面和 API)由连接器测试的测试服务器模拟。制作方式:docs/demo。
查看运行效果
这些都是真实录屏,并非模型图:从此代码库构建的 ohs 0.0.1,在本机原生运行并连接 TimescaleDB(使用端口 8088,因为该机器上的 8080 已被占用),并将 connectors/applehealth/testdata/e2e 中端到端 Apple Health 固定数据集分六部分上传。该固定数据集中的值均为合成数据。
返回的样本使用规范单位,同时会将提供方发送的内容保存在 metadata 中(count/min 转换为 bpm):
每日摘要按本地日期推导;覆盖率报告会说明处理何时完成:
创建一个仅具有 read 范围的用户令牌(有效期最长可达 30 天):
curl -s -X POST $OHS/v1/users/$USER_ID/tokens -H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' -d '{"scopes":["read"],"ttl_seconds":2592000}'
然后将 ohs mcp(stdio)添加到桌面 Agent 的 mcpServers 中(该二进制文件来自
安装步骤):
{
"mcpServers": {
"open-health-sync": {
"command": "/usr/local/bin/ohs",
"args": ["mcp"],
"env": { "OHS_MCP_URL": "http://localhost:8080", "OHS_MCP_KEY": "ohs_ut_..." }
}
}
}
ohs mcp 不存储任何数据,也不需要数据库:它会将每条消息转发到某个实例的 /mcp 端点。
除非主机是环回地址,否则 OHS_MCP_URL 必须使用 https。支持 Streamable HTTP 的 Agent 可携带持有者令牌直接调用 /mcp。
从 0.2.0 开始,服务还会列出十二个提示词(prompts/list):关于训练、睡眠和恢复的现成
问题,会先读取数据,再展示数值(提示词、提示词库)。相同的指南
也以 Agent 技能的形式提供于 skills/open-health-sync。
工具、参数和分页:docs/mcp.md。
数据模型
每个数据源都会映射为以下记录(字段和单位请参阅 docs/data-model.md):
- QuantitySample:单个标量测量值,例如心率、步数或 SpO2。
- CategorySample:分类事件,例如站立小时或月经流量记录。
月经周期会在读取时根据流量记录,通过
/menstrual-cycles派生 (docs/menstrual-cycles.md)。 - SleepSession 和 SleepPhase:包含时长细分的夜间睡眠,以及其中的各个阶段。
- Workout 和 RoutePoint:包含各项指标的运动记录,以及其 GPS 轨迹。
- NutritionLog:包含营养成分的食物或饮品记录。
- ECGRecording 和 ECGVoltageSample:记录的元数据,以及电压轨迹。 已存储,但尚未提供服务:读取路由仍在规划中。
- HeartbeatSample:单个逐搏(RR)间期。通过
/rr-intervals和/hrv提供服务,并按序列派生 HRV (docs/hrv.md)。 - DailySummary:按本地日期汇总的总量,来自数据提供方或由样本汇总得出。
- Observation:用于长尾数据的通用编码事实。目前还没有连接器会写入此记录。
部署
- 使用已发布的镜像进行 Compose 部署。 与快速入门相同,使用
deploy/docker-compose.yml。使用OHS_VERSION固定标签(在 0.x 期间没有latest)。参见自托管。 - Raspberry Pi 5。 添加 overlay
deploy/docker-compose.pi.yml(更小的 Postgres 缓冲区、内存限制)。参见 Raspberry Pi 5。 - S3 原始数据存储。 添加
deploy/docker-compose.s3.yml,或将OHS_RAW_STORE指向任意兼容 S3 的存储桶。参见 S3。 - 备份与恢复。
scripts/backup.sh会将数据库、原始数据存储和架构版本写入一个归档文件;scripts/restore.sh会将其恢复。CI 会在每个拉取请求中销毁并恢复一个堆栈。参见备份与恢复。 - 发布二进制文件。 Linux 和 macOS,支持 amd64 和 arm64,并附有
checksums.txt,可在发布页面获取。使用自有的 Postgres 和 TimescaleDB,运行ohs doctor,然后运行ohs up(迁移,然后提供服务)。每个归档解压后都会生成ohs_<version>_<os>_<arch>/ohs(安装)。macOS 二进制文件尚未签名:使用xattr -d com.apple.quarantine清除隔离标记。自 0.2.0 起,镜像和checksums.txt均使用 cosign 签名(验证发布版本)。 - 从源代码构建。 Go 1.26:运行
make build可生成bin/ohs。使用 Compose 时,添加deploy/docker-compose.build.yml,这需要docker buildx;若没有,请参见从源代码构建。
Open Health Sync 与 Terra 及其他健康数据 API 的比较
正在寻找 Terra API 的替代方案,或开源健康数据聚合器?以下是 Open Health Sync 与托管式可穿戴设备 API 的比较。其他产品的相关信息来自其官方网站和定价页面,核对日期为 2026-10-17;每一行都链接到完整的比较说明,其中包含迁移方法。
| 开源 | 起始价格 | FHIR R4 | 面向 AI Agent 的 MCP 服务 | 数据存储位置 | |
|---|---|---|---|---|---|
| Open Health Sync | 是,AGPL-3.0 | 免费,服务器费用由你承担 | 是,已使用官方 HL7 验证器核验 | 只读,stdio 和 HTTP | 你的服务器 |
| Terra | 否 | 每月 399 美元,按年计费 | 提供 FHIR 选项,但未注明版本 | 只读 | Terra 的云端,然后是你的目标位置 |
| Junction | 否 | 每月 300 美元,最多支持 500 位用户 | 文档中未提及 | 文档中未提及 | Junction 的云端,美国或欧盟 |
| Thryve | 否 | 每月 499 欧元,最多支持 500 位用户 | 网站上未找到相关信息 | 网站上未找到相关信息 | Thryve 在德国的服务器 |
| Spike API | 否 | 每月 450 美元起 | 文档中未找到相关信息 | 是 | Spike 的云端 |
| Sahha | 否 | 每月 299 美元起,按年计费 | 网站上未找到相关信息 | 是 | Sahha 的云端 |
| ROOK | 否 | 每月 399 美元,最多支持 750 位用户 | 作为附加项提供,Business 版起包含 | 网站上未找到相关信息 | ROOK 的云端 |
如果你现在需要 Garmin 或大量小众设备的数据、不想运行服务器,或需要供应商提供 SOC 2 和 HIPAA 证明,请选择托管式 API。如果数据必须留在你的基础设施中、按用户收费不适合你,或你需要标准化输出(FHIR R4、Open mHealth)并保留每个原始载荷,请选择 Open Health Sync。查看所有选项的并排比较:健康数据聚合器比较。
常见问题
谁能看到我的数据?
只有运行该实例的人才能访问。可自托管,无需在我们这里创建账户;我们不会进行分析,也不会回传数据。服务会与您启用的提供商(即您设置了密钥的提供商)以及您自己的数据库和原始数据存储进行通信。日志中绝不会包含令牌、密钥或健康数据。在[托管版测试阶段](#hosted-beta),实例由我们运行,因此目前仅接受测试数据。数据存储在哪里?
存储在两个由您掌控的位置:Postgres with TimescaleDB(连接和任务存储在 ohs_sync 架构中,标准化记录存储在 ohs_data 中),以及原始数据存储,可使用本地文件夹或兼容 S3 的存储桶。使用 compose 时,这两个位置对应 pgdata 和 raw 卷。请使用 OHS_ENCRYPTION_KEY 同时备份它们。
它是否符合 HIPAA 或 GDPR?
软件本身无法确保合规,Open Health Sync 也未经认证或审计,且不受业务伙伴协议覆盖。它提供的保障包括:数据保留在您选择的基础设施上;DELETE /v1/users/{id} 会彻底删除原始文件和数据行(可用于数据擦除请求);一次调用即可删除某个用户在单一数据源中的数据;按数据源和数据类别保存同意信息,并在每次写入时强制执行;GET /v1/users/{id}/archive 会以 zip 文件的形式提供某人相关的全部数据;OHS_RETENTION_DAYS 会强制执行数据保留期限;每次查询都会限定在特定租户和用户范围内;密钥和令牌均以哈希形式存储;提供商的 OAuth 令牌使用 AES-256-GCM 加密,并由可在线轮换的密钥保护(密钥轮换)。
健康记录本身不会由 ohs 加密:请使用磁盘或数据库加密、在 API 前配置 TLS,并设置您自己的访问控制。部署是否符合 HIPAA、GDPR 或其他法规,取决于您的运行方式。
费用是多少?
免费。该服务免费且开源。您只需支付运行它所需的费用,甚至可以使用配备 4 GB 内存的 Raspberry Pi 5。每个云端提供商(Withings、Oura、WHOOP、Fitbit 等)都需要您向厂商注册自己的开发者应用。托管版在测试阶段免费。
它与 Terra 相比如何?
Terra 是一款托管 API:其宣传支持 500 多种集成(包括 Garmin),年付方案起价为每月 $399,且用户数据会经过其云端。Open Health Sync 免费,并优先采用标准:输出 FHIR R4 和 Open mHealth 数据,并使用官方验证器进行校验;保留每个原始负载;提供一个可在 Raspberry Pi 上运行的 Go 二进制文件。请查看对比表,或查看并列比较:Terra API 替代方案。
它支持哪些设备?
任何会向 Apple Health 写入数据的设备或应用(Apple Watch、iPhone,以及同步到 HealthKit 的应用和设备),都可以通过上传数据的 iOS 应用接入:[Swift SDK](docs/sdks/swift.md#healthkit-sync) 会读取 HealthKit 并上传发生变化的数据;你也可以让自己的应用直接实现[上传约定](docs/connectors/apple-health.md)。如果没有应用,`ohs import apple-health` 会加载“健康”应用生成的导出文件,包括历史数据。Withings 体重秤、手表和睡眠设备可通过用户自己的 Withings 账户接入。Oura 戒指、WHOOP 腕带、Polar 手表、Strava 活动、Suunto 手表、Fitbit 设备(通过 Google Health API)、Ultrahuman 戒指、intervals.icu 账户、Dexcom CGM,以及 OMRON 血压计和体重秤,均可通过各自的用户账户接入。Fitbit、Suunto、Ultrahuman 和 OMRON 需要使用供应商仅提供给获批开发者的密钥。在 Android 上,任何会向 Health Connect 写入数据的设备或应用(例如 Samsung Health、FreeStyle Libre 等 CGM 应用),都需通过上传数据的应用接入([约定](docs/connectors/health-connect.md))。Garmin 手表可通过用户自己的 Garmin Connect 账户接入,所需密钥仅由 Garmin 提供给获批企业([指南](docs/connectors/garmin.md))。我们还[计划支持](docs/connectors/README.md)更多数据源,并开放了[连接器申请表](https://github.com/soma-intelligence/open-health-sync/issues/new/choose)。为什么采用 AGPL?
让这一层保持开源。任何人都可以运行、研究和修改它;如果你将修改后的 Open Health Sync 作为网络服务运行,就必须根据同一许可证公开所做的修改。sdks/ 中的客户端 SDK 也仅采用 AGPL-3.0。
我可以将它用于商业用途吗?
可以。企业可以运行未修改或修改过的版本,为自己的产品提供支持。AGPL 仅要求:通过网络与修改版服务交互的用户能够获取其源代码。本内容不构成法律建议:请阅读 LICENSE,或咨询你的法律顾问。
它是医疗器械吗?
不是。它用于传输和规范化数据,不会进行诊断、评分或提供建议,也不是临床软件。
状态与路线图
v0.2.0 是最新版本。此版本新增了可运行处理管道的管理控制台、用于管理租户及其密钥的管理 API、按租户保存的提供商密钥、Garmin、Eight Sleep 和 Xiaomi 连接器、活动文件导入、通过 ohs-bridge 接入的蓝牙健康设备、ECG 读取、自我报告、分享链接、小时和每日样本统计、加密密钥在线轮换以及签名发布。变更内容:CHANGELOG.md。安装和升级说明及完整的限制列表:发行说明。
已知限制:
- 遭遇强制终止后,正在运行的任务只有在 10 分钟可见性超时后才会重新处理。
- 每个实例只有一个数据库和一个原始数据存储;不支持多区域复制。
- FHIR R4 尚不支持批量导出(
$export)。 - 客户端 SDK 的版本为 0.1.0,尚未发布到软件包注册表;请从此代码库安装。计划在 Kotlin SDK 中支持读取 Health Connect。
托管测试版免费开放注册(容量共享,仅限测试和演示数据):免费注册。
后续计划:增加更多连接器,支持更多标准输出(更多 FHIR R4 资源),然后在 Kotlin SDK 中支持读取 Health Connect,接着通过 SMART on FHIR 接入健康记录(EHR)。欢迎通过 GitHub issue 提交需求,包括使用连接器申请表。
文档
- 自行托管:配置、镜像、Raspberry Pi、S3 和运维说明。
- 安全模型和安全加固清单:保护的内容及保护方式,以及在实例存储真实用户的数据之前需要设置的内容。
- API 指南和 OpenAPI 文件,这是事实来源。
- MCP 服务:工具、提示词、凭据、桌面和远程 Agent。
- FHIR R4 输出:用户的记录如何作为 Observations 输出、映射方式及其限制。
- 出站 Webhook:事件、签名、重试和端点路由。
- 数据模型:所有规范类型和数量名称,以及对应单位。
- 客户端 SDK:Kotlin、Swift、 React Native、Flutter。
- 服务端 SDK:供后端使用的 TypeScript 和 Python 客户端,以及 Postman 集合。
- 示例应用:基于 SDK 构建的 iOS(HealthKit)、Android 和 React Native 示例,以及一个 Next.js Web 应用,可通过服务端 SDK 从首位用户开始使用 Webhook。
- 桌面桥接程序:
ohs-bridge可从电脑或 Raspberry Pi 发送蓝牙健康设备和通过 USB 连接的手表记录的数据。 - 架构:角色、管道、存储和可靠性。
- 连接器:已支持和计划支持的数据源、 Apple Health、 Withings、Oura、 WHOOP、Strava、 Polar、编写自己的连接器。
- 后台同步:Webhook、兜底拉取和数据新鲜度。
- 备份与恢复:将数据库和原始存储打包为一个归档文件,以及如何恢复。
- 连接页面:托管页面,用户可在此连接数据源,然后返回你的应用。
- 管理控制台:在浏览器中运行管道:提供方及其密钥、用户和连接、同步与处理任务、Webhook、API 密钥和审计日志。
- 管理 API:为多个团队运行同一个实例:创建租户、管理其密钥,并通过 HTTP 为演示用户填充数据。
- 配方:在自己的数据上进行个人设置并使用小型工具。
- RR 间期与 HRV:逐次心跳间期及据此计算出的 HRV。
- 月经周期:根据记录的经期推算周期,不作预测。
- 时间标签:为数据提供背景信息的时间区间,例如生病或旅行期间。
- 自我报告:存储在同步数据旁的个人自评。
- 分享链接:内置查看器的 SMART Health Links。
贡献
欢迎提交问题和拉取请求。这里有三种参与方式,耗时从五分钟到一个周末不等:
- 有可穿戴设备? 使用
make record PROVIDER=oura记录你的账户,大约只需五分钟 (也可以使用其他数据源)。记录器会在你的设备上匿名化数据,CI 会在每次变更时重放文件:在 #60 中选择数据源, 并参阅录制连接器。 - 挑选一个适合新手的问题: 文档、配方、CLI 命令或部署模板,范围都限定为一个 PR。
- 添加数据提供商。 连接器彼此独立:从 编写连接器开始。
请先阅读 CONTRIBUTING.md 和行为准则。每位首次贡献者都会在 48 小时内收到审核反馈。
make setup # git hooks
make build # bin/ohs
make test # unit tests
make integration # needs Docker (testcontainers)
贡献者
安全
请按照 SECURITY.md 中的说明,私下报告漏洞。切勿在公开问题中粘贴健康数据、密钥或令牌。
许可证
服务端采用 AGPL-3.0-only 许可证,详见 LICENSE。如果你将修改后的 Open Health Sync 作为服务运行,就必须公开你的修改。sdks/ 中的客户端 SDK 也采用相同的许可证。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。