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)에서 휴대폰으로 읽어온 다음, 이를 일별로 요약하고 각 측정 항목을 LOINC 코드 및 UCUM 단위에 매핑한 후, 기기 데이터로 표시된 FHIR R4 Observations로 작성해야 합니다. 각 공급업체의 클라우드 대신 휴대폰의 건강 스토어에서 읽어오면, 해당 사용자가 공급업체 앱의 공유를 허용한 한 Apple Watch, Galaxy Watch, Pixel Watch, Garmin, Fitbit, Oura 및 Withings를 하나의 통합으로 지원할 수 있습니다. 이 페이지에서는 데이터 경로, 재사용 가능한 매핑 테이블, 검증된 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, 2025년 8월) | Body Battery와 같은 Garmin 고유 점수는 공유되지 않습니다. |
| Oura | 예 | 예 (Oura) | Readiness 및 기타 Oura 점수는 Oura 앱에 유지됩니다. |
| Withings | 예, Health Mate를 통해 | 예 (Android Developers 블로그) | 체중계, 혈압계, 시계 |
두 가지 실질적인 결과가 있습니다. 첫째, 사용자가 자신의 공급업체 앱에서 공유를 활성화했는지 여부에 따라 앱이 달라집니다. 온보딩 시 이를 명시해야 합니다. 둘째, 건강 스토어에는 두 개의 소스(휴대폰 및 시계)에서 동일한 걸음 수가 포함될 수 있습니다. Apple Health 및 Health Connect는 이미 중복되는 소스를 중복 제거하므로, 샘플을 합산하는 대신 스토어 자체의 일일 총계를 읽으십시오.
매핑 테이블: 건강 저장소 유형 → FHIR Observation
Anpheros Daily가 웨어러블 데이터를 FHIR 레코드로 작성할 때 사용하는 코드:
| Metric | Apple HealthKit | Health Connect | LOINC | UCUM unit | Category |
|---|---|---|---|---|---|
| Heart rate | heartRate |
HeartRateRecord |
8867-4 | /min |
vital-signs |
| Resting heart rate | restingHeartRate |
RestingHeartRateRecord |
40443-4 | /min |
vital-signs |
| Heart rate variability | heartRateVariabilitySDNN |
HeartRateVariabilityRmssdRecord |
80404-7 (SDNN only) | ms |
vital-signs |
| Blood oxygen (SpO₂) | oxygenSaturation |
OxygenSaturationRecord |
59408-5 | % |
vital-signs |
| Respiratory rate | respiratoryRate |
RespiratoryRateRecord |
9279-1 | /min |
vital-signs |
| Steps per day | stepCount |
StepsRecord |
41950-7 | {steps} |
activity |
| Active energy | activeEnergyBurned |
ActiveCaloriesBurnedRecord |
41981-2 | kcal |
activity |
| Sleep duration | sleepAnalysis (category) |
SleepSessionRecord |
93832-4; stages 93831-6 deep, 93830-8 light, 93829-0 REM | min |
activity |
| Body weight | bodyMass |
WeightRecord |
29463-7 | kg |
vital-signs |
| Blood pressure | bloodPressure (correlation) |
BloodPressureRecord |
85354-9 with 8480-6 and 8462-4 | mm[Hg] |
vital-signs |
| Blood glucose (meter) | bloodGlucose |
BloodGlucoseRecord |
2339-0 | mg/dL |
vital-signs |
| Body temperature | bodyTemperature |
BodyTemperatureRecord |
8310-5 | Cel |
vital-signs |
심박 변이율 행을 확인하세요: Apple Health는 SDNN을 저장하고, Health Connect는 RMSSD를 저장합니다. 이들은 서로 다른 통계이며 동일한 코드 아래 작성되어서는 안 됩니다. LOINC 80404-7은 SDNN입니다. RMSSD의 경우, Anpheros Daily는 두 가지가 동일하다고 가정하는 대신 자체 코드 시스템을 사용합니다.
요약, 모든 샘플은 아님
시계는 하루에 수천 개의 심박수 샘플을 생성합니다. 의료 기록에는 사람이나 의사가 읽을 수 있는 무언가가 필요합니다.
- 일일 메트릭당 하나의 관찰(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)"}
}
중복 없이 일일 값 작성
휴대폰은 하루에 여러 번 동기화되며, 하루의 마지막 값은 자정까지 계속 변경됩니다. 각 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 });
}
샌드박스 키가 있는 플랫폼의 로컬 인스턴스에서 실행하면, 두 개의 일일 값이 기록된 후 같은 날의 단계 동기화가 두 개의 Observation을 남겼습니다. 단계 항목은 버전 2에서 새 값을 가지며, 출처는 v1 device apple-health · v2 device입니다. 기록은 이전 값을 유지하며, 모든 독자는 데이터가 임상의가 아닌 장치에서 왔음을 알 수 있습니다.
운영 환경에서는 플랫폼 페이지의 HealthKit 및 Health Connect 코드와 같이 실제 날짜 경계를 사용자의 시간대에서 사용하십시오(위 예시에서는 간결성을 위해 UTC 사용).
전화기에서 읽기
- iPhone 및 Apple Watch: Apple Health (HealthKit) to FHIR, 일별 통계를 위한 Swift 코드 포함.
- Android, Wear OS, Fitbit, Garmin, Oura, Withings: Health Connect to FHIR, 두 플랫폼 모두에서 작동하는 Flutter 코드 포함.
- Samsung Galaxy Watch 및 Samsung Health: Samsung Health to FHIR: Health Connect에 도달하는 내용과 Samsung 자체 SDK가 필요한 내용.
따라야 할 규칙
- 사용하는 것만 읽으세요. 각 유형별로 따로 요청하세요. 사람들은 부분적인 권한을 부여합니다.
- 출처를 명시하세요. 소비자 웨어러블 기기는 진단 장치가 아닙니다. 해당 데이터를 기기 데이터(
author_type: device)로 작성하고 어떤 앱에서 왔는지 명시하여 임상의가 적절하게 판단할 수 있도록 하세요. - 플랫폼 규칙을 존중하세요. Apple의 앱 심사 지침(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는 없음), 하루 단위로 요약한 다음, 백엔드에서 각 측정값을 LOINC 코드 및 UCUM 단위와 함께 Observation으로 작성하고 장치 데이터로 표시합니다.
Health Connect 또는 Apple Health에 대한 클라우드 API가 있나요?
아니요. 둘 다 데이터를 휴대폰에 저장하며, 휴대폰에 설치된 앱이 사용자의 허가를 받아 데이터를 읽습니다. Garmin, Fitbit 또는 Oura와 같은 공급업체 클라우드는 자체 API를 가지고 있지만, 휴대폰의 건강 저장소에서 데이터를 읽는 것이 대부분의 경우 하나의 통합으로 처리됩니다.
걸음 수에 어떤 LOINC 코드를 사용해야 하나요?
41950-7, "Number of steps in 24 hour Measured", 일일 effectivePeriod와 함께 사용합니다. 심박수의 경우 8867-4, SpO₂의 경우 59408-5, 수면 시간의 경우 93832-4를 사용합니다.
모든 심박수 샘플을 FHIR에 저장해야 하나요?
일반적으로 그렇지 않습니다. 평균, 최소 및 최대값을 포함한 일일 요약이 사용자와 임상의가 읽는 내용이며, 개별 측정값은 불규칙한 리듬 이벤트와 같이 자체적으로 중요한 경우에만 기록에 포함되어야 합니다.
Apple Health 및 Health Connect의 HRV에 대해 하나의 코드를 사용할 수 있나요?
아니요. Apple Health는 SDNN을 보고하고 Health Connect는 RMSSD를 보고합니다. 이들은 다른 것을 측정하며 다른 코드가 필요합니다.
관련 자료
- 웨어러블 API: Fitbit, Garmin, Oura 및 Withings
- 건강 추적기 API: 동의를 얻어 추적기 데이터 서버에 저장하기
- 개인 건강 기록 앱 구축 방법
- 의료 통합: 실험실, 클리닉 및 앱과 함께하는 기기
- FHIR 코드 시스템: LOINC 및 UCUM
- 의료 데이터 출처 설명
- 의료 데이터 정규화 방법
- FHIR을 이용한 원격 환자 모니터링: 개별 측정값, 웹훅 및 알림
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card