Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
FHIRでのウェアラブルデータ(Apple Health, Health Connect)
スマートウォッチ、リング、スケールのデータをFHIRレコードに取り込む方法:どのデバイスがどのヘルスストアに到達するか、LOINCマッピングテーブル、日次サマリー、テスト済みのupsertについて説明します。
スマートウォッチ、リング、またはスマートスケールから医療記録にデータを取得するには、オペレーティングシステムのヘルスストア(iOSではApple Health、AndroidではHealth Connect)から電話で読み取り、1日ごとに要約し、各メトリックをLOINCコードとUCUMユニットにマッピングし、デバイスデータとしてマークされたFHIR R4 Observationとして書き込みます。 各ベンダーのクラウドからではなく、電話のヘルスストアから読み取ることで、Apple Watch、Galaxy Watch、Pixel Watch、Garmin、Fitbit、Oura、Withingsを1つの統合でカバーできます。これは、ユーザーがベンダーアプリに共有を許可している限り有効です。このページでは、データパス、再利用可能なマッピングテーブル、検証済みのFHIR例、およびプラットフォームに対して実行されたコードを提供します。
データパス
watch, ring, scale ──► vendor app (Garmin Connect, Fitbit, Oura, Withings, Samsung Health…)
│ shares, with the person's permission
▼
Apple Health (iOS) / Health Connect (Android)
│ your app reads, with the person's permission, on the phone
▼
your app ──► your backend ──► FHIR R4 Observations in the person's record
Apple Health も Health Connect もサーバー API を持っていません。データは、その人の電話上のアプリからのみ読み取ることができます。アプリがデータを読み取り、コンパクトな日次値をバックエンドに送信し、バックエンドがレコードに書き込みます。
どのデバイスがどのヘルスストアに到達するか
各ベンダーが共有する内容はアプリのバージョンによって異なります。ベンダー自身のドキュメントを参照してください。
| デバイスまたはアプリ | Apple Health (iOS) | Health Connect (Android) | 備考 |
|---|---|---|---|
| Apple Watch | はい、ネイティブ | — | ウォッチが測定するすべてのデータはApple Healthに保存されます |
| Samsung Galaxy Watch, Samsung Health | — | 部分的 | Samsung Healthがどのタイプのデータをエクスポートするか、およびその頻度を決定します。 Samsung Health を参照してください。 |
| Pixel Watch, Fitbit | 公式同期なし | はい、Fitbitアプリ経由 (Googleヘルプ) | |
| Garmin | はい、Garmin Connectから各デバイス同期後 | はい、Garmin ConnectはAndroid 14以降でHealth Connectをサポートしています (Android Developers, August 2025) | Body BatteryなどのGarmin固有のスコアは共有されません |
| Oura | はい | はい (Oura) | Readinessおよびその他のOuraスコアはOuraアプリに残ります |
| Withings | はい、Health Mate経由 | はい (Android Developers blog) | スケール、血圧計、ウォッチ |
2つの実践的な結果があります。第一に、あなたのアプリは、ユーザーがベンダーアプリで共有をオンにしていることに依存します。オンボーディングでその旨を伝える必要があります。第二に、ヘルスストアには、2つのソース(電話とウォッチ)からの同じステップデータが含まれる場合があります。サンプルを合計するのではなく、ストア自身の1日の合計値を読み取ってください。これは、Apple HealthとHealth Connectが重複するソースをすでに重複排除しているためです。
マッピングテーブル:ヘルスストアタイプ → FHIR Observation
Anpheros Daily がウェアラブルデータを FHIR レコードに書き込む際に使用するコード:
| メトリック | Apple HealthKit | Health Connect | LOINC | UCUM 単位 | カテゴリ |
|---|---|---|---|---|---|
| 心拍数 | heartRate |
HeartRateRecord |
8867-4 | /min |
vital-signs |
| 安静時心拍数 | restingHeartRate |
RestingHeartRateRecord |
40443-4 | /min |
vital-signs |
| 心拍変動 | heartRateVariabilitySDNN |
HeartRateVariabilityRmssdRecord |
80404-7 (SDNN のみ) | ms |
vital-signs |
| 血液酸素 (SpO₂) | oxygenSaturation |
OxygenSaturationRecord |
59408-5 | % |
vital-signs |
| 呼吸数 | respiratoryRate |
RespiratoryRateRecord |
9279-1 | /min |
vital-signs |
| 1 日あたりの歩数 | stepCount |
StepsRecord |
41950-7 | {steps} |
activity |
| アクティブエネルギー | activeEnergyBurned |
ActiveCaloriesBurnedRecord |
41981-2 | kcal |
activity |
| 睡眠時間 | sleepAnalysis (カテゴリ) |
SleepSessionRecord |
93832-4; ステージ 93831-6 深い、93830-8 浅い、93829-0 REM | min |
activity |
| 体重 | bodyMass |
29463-7 | WeightRecord |
kg |
vital-signs |
| 血圧 | bloodPressure (相関) |
BloodPressureRecord |
85354-9 と 8480-6 および 8462-4 | mm[Hg] |
vital-signs |
| 血糖値 (メーター) | bloodGlucose |
BloodGlucoseRecord |
2339-0 | mg/dL |
vital-signs |
| 体温 | bodyTemperature |
BodyTemperatureRecord |
8310-5 | Cel |
vital-signs |
心拍変動の行に注目してください:Apple Health は SDNN を保存し、Health Connect は RMSSD を保存します。これらは異なる統計情報であり、同じコードの下に書き込まれるべきではありません。LOINC 80404-7 は SDNN です。RMSSD の場合、Anpheros Daily は、2 つが同じであると偽るのではなく、独自のコードシステムを使用します。
要約、すべてのサンプルではない
ウォッチは1日に数千もの心拍数サンプルを生成します。医療記録には、人間や医師が読めるものが必要です。
- メトリックごとに1日1つのObservation を作成し、
effectivePeriodはその日のローカルな日付を、valueQuantityは日次平均または合計を、レートの場合は最小値と最大値をコンポーネントとしてカバーします。 - より細かい系列は、有用な場所に留まります。 Anpheros Daily は、独自のチャートのために4時間ごとの心拍数要約を保持し、日次値を FHIR レコードに書き込みます。
- イベントは別個です。 不規則なリズムの通知や単一の血圧測定値は、日次平均の一部ではなく、それ自体の時間を持つ独自の Observation です。
FHIR R4 としての日次心拍数要約(FHIR R4 バリデーター を通過します):
{
"resourceType": "Observation",
"status": "final",
"identifier": [{"system": "https://your-app.test/fhir/sid/daily-wearable", "value": "p-123:2026-10-01:heart_rate"}],
"category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "vital-signs"}]}],
"code": {"coding": [{"system": "http://loinc.org", "code": "8867-4", "display": "Heart rate"}]},
"subject": {"reference": "Patient/p-123"},
"effectivePeriod": {"start": "2026-10-01T00:00:00-04:00", "end": "2026-10-02T00:00:00-04:00"},
"valueQuantity": {"value": 71.4, "unit": "/min", "system": "http://unitsofmeasure.org", "code": "/min"},
"component": [
{"code": {"text": "minimum"}, "valueQuantity": {"value": 52, "unit": "/min", "system": "http://unitsofmeasure.org", "code": "/min"}},
{"code": {"text": "maximum"}, "valueQuantity": {"value": 138, "unit": "/min", "system": "http://unitsofmeasure.org", "code": "/min"}}
],
"device": {"display": "Apple Watch (via Apple Health)"}
}
重複なしで日次値を記述する
スマートフォンは1日に数回同期され、その日の最後の値は深夜まで変更され続けます。各 Observation には、人、日、メトリックの安定した識別子を与え、新しいものを作成するのではなく更新してください。Anpheros TypeScript SDK を使用して、バックエンドで次のようにします。
import { Anpheros, apiKey } from '@anpheros/sdk';
const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) });
// What the phone sends: one value per metric per local day
type DailyValue = { metric: 'heart_rate' | 'steps'; day: string; value: number; min?: number; max?: number };
const CODES = {
heart_rate: { code: '8867-4', display: 'Heart rate', unit: '/min', category: 'vital-signs' },
steps: { code: '41950-7', display: 'Number of steps in 24 hour Measured', unit: '{steps}', category: 'activity' },
} as const;
// One Observation per person, metric and day: re-sending a day updates it instead of adding a copy.
async function upsertDaily(patientId: string, v: DailyValue, source: string) {
const c = CODES[v.metric];
const identifier = { system: 'https://your-app.test/fhir/sid/daily-wearable', value: `${patientId}:${v.day}:${v.metric}` };
const resource: any = {
resourceType: 'Observation', status: 'final',
identifier: [identifier],
category: [{ coding: [{ system: 'http://terminology.hl7.org/CodeSystem/observation-category', code: c.category }] }],
code: { coding: [{ system: 'http://loinc.org', code: c.code, display: c.display }] },
subject: { reference: `Patient/${patientId}` },
effectivePeriod: { start: `${v.day}T00:00:00Z`, end: `${v.day}T23:59:59Z` },
valueQuantity: { value: v.value, unit: c.unit, system: 'http://unitsofmeasure.org', code: c.unit },
};
if (v.min !== undefined && v.max !== undefined) {
resource.component = [
{ code: { text: 'minimum' }, valueQuantity: { value: v.min, unit: c.unit, system: 'http://unitsofmeasure.org', code: c.unit } },
{ code: { text: 'maximum' }, valueQuantity: { value: v.max, unit: c.unit, system: 'http://unitsofmeasure.org', code: c.unit } },
];
}
const found = await anpheros.fhir.search('Observation', { identifier: `${identifier.system}|${identifier.value}` });
const existing = found.entry?.[0]?.resource;
return existing
? anpheros.fhir.update({ ...resource, id: existing.id }, { author_type: 'device' })
: anpheros.fhir.create(resource, { author_type: 'device', source_system: source });
}
サンドボックスキーを使用してプラットフォームのローカルインスタンスに対して実行すると、2つの日次値の後に同じ日のステップの同期が行われ、2つの Observation が残ります。ステップはバージョン2で新しい値となり、provenance は v1 device apple-health · v2 device です。履歴には以前の値が保持され、すべてのリーダーは、データが臨床医からではなくデバイスから来たことを確認できます。
本番環境では、プラットフォームページの HealthKit および Health Connect コードが示すように、個人のタイムゾーンにおける実際の日の境界を使用してください (上記の例では簡潔にするために UTC を使用しています)。
電話からの読み込み
- iPhone および Apple Watch: Apple Health (HealthKit) から FHIR へ (日々の統計情報に関する Swift コード付き)。
- Android、Wear OS、Fitbit、Garmin、Oura、Withings: Health Connect から FHIR へ (両方のプラットフォームで動作する Flutter コード付き)。
- Samsung Galaxy Watch および Samsung Health: Samsung Health から FHIR へ (Health Connect で取得できるものと、Samsung 独自の SDK が必要なもの)。
従うべきルール
- 使用するものだけを読む。個別のタイプごとにリクエストしてください。ユーザーは部分的な権限を付与します。
- ソースを明記する。コンシューマー向けウェアラブルは診断デバイスではありません。そのデータをデバイスデータ (
author_type: device) として記録し、どのアプリから取得したかを明記してください。これにより、臨床医は適切に評価できます。 - プラットフォームのルールを尊重する。Apple の App Review Guidelines (5.1.3) は、ヘルスデータを広告に使用することや、個人健康情報を iCloud に保存することを禁じています。Google Play は、Health Connect を使用するアプリにヘルスアプリ宣言を要求します。
- ユーザーが切断できるようにする。そして、すでにコピーされたデータがレコードに残るかどうかをユーザーに決定させる。
Anpheros の機能と非機能
Anpheros Platform は、単独で Apple Health、Health Connect、またはベンダーのクラウドに接続しません。お客様のアプリが電話上のデータを読み取り、API を介して書き込みます。Anpheros 自身のアプリである Anpheros Daily は、まさにその機能を実行します。iPhone では Apple Health、Android では Health Connect からデータを読み取り、日次サマリーを保持し、上記のコードを使用して個人の FHIR レコードに書き込みます。デバイスの接続は、Plus および Max プランに含まれています。
よくある質問
Apple WatchのデータをFHIRサーバーに取り込むにはどうすればよいですか?
HealthKitを使用してiPhone上のApple Healthから読み取り(サーバーAPIはありません)、1日ごとに要約し、バックエンドで各メトリックをLOINCコードとUCUM単位を持つObservationとして書き込み、デバイスデータとしてマークします。
Health ConnectまたはApple HealthのクラウドAPIはありますか?
いいえ。どちらもデータを電話機に保存します。電話機にインストールされたアプリが、ユーザーの許可を得てそれを読み取ります。Garmin、Fitbit、Ouraなどのベンダークラウドには独自のAPIがありますが、電話機のヘルスストアを読み取ることで、ほとんどのベンダーを1つの統合でカバーできます。
ステップにはどのLOINCコードを使用すればよいですか?
41950-7、「Number of steps in 24 hour Measured」、1日あたりeffectivePeriodでマークします。心拍数には8867-4、SpO₂には59408-5、睡眠時間には93832-4を使用します。
すべての心拍数サンプルをFHIRに保存すべきですか?
通常はそうではありません。平均、最小、最大を含む日次要約は、ユーザーまたは臨床医が読み取るものです。個々の測定値は、不規則なリズムイベントのように、それ自体で意味がある場合にのみレコードに含めるべきです。
Apple HealthとHealth ConnectからのHRVに1つのコードを使用できますか?
いいえ。Apple HealthはSDNNを報告し、Health ConnectはRMSSDを報告します。これらは異なるものを測定し、異なるコードが必要です。
関連情報
- ウェアラブルAPI:Fitbit、Garmin、Oura、Withings
- ヘルスケアトラッカーAPI:トラッカーデータのサーバーへの保存(同意取得あり)
- 個人健康記録(PHR)アプリの構築方法
- ヘルスケア連携:ラボ、クリニック、アプリと連携するデバイス
- FHIRコードシステム:LOINCおよびUCUM
- 医療データプロベナンス(来歴)の説明
- 医療データの正規化方法
- FHIRによる遠隔患者モニタリング:個々の測定値、Webhook、アラート
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card