# FHIRにおけるウェアラブルデータ (Apple Health, Health Connect)

> スマートウォッチ、リング、スケールデータをFHIRレコードに取り込む：どのデバイスがどのヘルスストアに到達するか、LOINCマッピングテーブル、日次サマリー、およびテスト済みのupsert。

Source: https://developers.anpheros.com/ja/guides/wearable-data-fhir

**スマートウォッチ、リング、またはスマートスケールから医療記録にデータを取得するには、オペレーティングシステムのヘルスストア（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](https://developers.anpheros.com/ja/guides/samsung-health-fhir) を参照してください。 |
| Pixel Watch, Fitbit | 公式同期なし | はい、Fitbitアプリ経由 ([Googleヘルプ](https://support.google.com/fitbit/answer/14506680)) | |
| Garmin | はい、Garmin Connectから各デバイス同期後 | はい、Garmin ConnectはAndroid 14以降でHealth Connectをサポートしています ([Android Developers, August 2025](https://developer.android.com/health-and-fitness/community/newsletters/2025/08)) | Body BatteryなどのGarmin固有のスコアは共有されません |
| Oura | はい | はい ([Oura](https://ouraring.com/blog/data-sharing-partner-integrations/)) | Readinessおよびその他のOuraスコアはOuraアプリに残ります |
| Withings | はい、Health Mate経由 | はい ([Android Developers blog](https://android-developers.googleblog.com/2023/03/withings-reduces-data-sync-code-with--health-and-fitness-api-health-connect.html)) | スケール、血圧計、ウォッチ |

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 バリデーター](https://developers.anpheros.com/tools/fhir-validator) を通過します）：

```json
{
  "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 を使用して、バックエンドで次のようにします。

```ts
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 へ](https://developers.anpheros.com/ja/guides/apple-health-fhir) (日々の統計情報に関する Swift コード付き)。
- **Android、Wear OS、Fitbit、Garmin、Oura、Withings:** [Health Connect から FHIR へ](https://developers.anpheros.com/ja/guides/health-connect-fhir) (両方のプラットフォームで動作する Flutter コード付き)。
- **Samsung Galaxy Watch および Samsung Health:** [Samsung Health から FHIR へ](https://developers.anpheros.com/ja/guides/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](https://developers.anpheros.com/ja/guides/wearable-apis)
- [ヘルスケアトラッカーAPI](https://developers.anpheros.com/ja/guides/health-tracker-api)：トラッカーデータのサーバーへの保存（同意取得あり）
- [個人健康記録（PHR）アプリの構築方法](https://developers.anpheros.com/ja/guides/personal-health-record-app)
- [ヘルスケア連携](https://developers.anpheros.com/ja/guides/healthcare-integrations)：ラボ、クリニック、アプリと連携するデバイス
- [FHIRコードシステム](https://developers.anpheros.com/ja/guides/fhir-code-systems)：LOINCおよびUCUM
- [医療データプロベナンス（来歴）の説明](https://developers.anpheros.com/guides/medical-data-provenance)
- [医療データの正規化方法](https://developers.anpheros.com/ja/guides/normalize-medical-data)
- [FHIRによる遠隔患者モニタリング](https://developers.anpheros.com/ja/guides/remote-patient-monitoring-fhir)：個々の測定値、Webhook、アラート
