synheart-wear ships a stable adapter layer per vendor. This page is the reference for what each adapter does, what it produces, and how it interacts with cloud streaming.
Adapter matrix
| Vendor | Local source | Cloud / push source | RAMEN delivery hint | Status |
|---|---|---|---|---|
| Apple Watch | HealthKit (apple_healthkit) | — | n/a | Ready |
| Health Connect (Android) | Health Connect API | — | n/a | Ready |
| BLE HRM (any) | GATT 0x180D Heart Rate Profile | — | n/a | Ready |
| WHOOP | Broadcast HR via BLE | OAuth + webhooks | stream (full payload inline) | Ready |
| Garmin (Cloud) | — | OAuth + Connect API webhooks | ping (REST pull required) | Ready |
| Garmin Health SDK (RTS) | Native real-time streaming | — | n/a | On-demand, license-gated |
| Fitbit | — | OAuth via Synheart Wear API | ping | Ready |
| Oura | HealthKit / Health Connect proxy (Flutter) | OAuth via Synheart Wear API (Kotlin / Swift) | ping | Ready |
| Samsung Watch | (planned) | — | n/a | Planned |
DeviceAdapter enum lists platformHealth, fitbit, garmin, whoop, samsungHealth. The Swift and Kotlin enums additionally include bleHrm / BLE_HRM. Across all three platforms, Oura has no enum entry and is reached via OuraProvider; BLE HRM on Dart is reached via BleHrmBridge.
Apple HealthKit
Capabilities:- HR (instantaneous + samples).
- HRV (RMSSD, SDNN; SDNN derived on-device when only RR is exposed).
- Steps, calories, distance.
- RR intervals via the HealthKit RR channel (workout-mode only on most Apple Watch models).
- Health profile snapshot (DOB, sex, height, weight) for personalization context.
- Workout events.
HKObjectType set, requested once via requestPermissions.
source field on WearMetrics: "apple_healthkit".
Health Connect (Android)
Capabilities:- HR, HRV (when the recording app provides it; otherwise SDNN/RMSSD are unavailable).
- Steps, calories, distance.
- Sleep records (sleep stages from compatible apps).
source field: "health_connect".
BLE HRM
Direct connection over BLE GATT Heart Rate Profile (0x180D). No vendor cloud, no OAuth. Compatible devices:- WHOOP (Broadcast HR mode).
- Polar chest straps (H10, OH1).
- Wahoo TICKR family.
- Garmin HRM-Pro / HRM-Dual.
- Any HRM advertising 0x180D Heart Rate Service.
- HR (every second per Bluetooth profile).
- RR intervals when the device advertises the optional RR field.
requestPermissions. See BLE Heart Rate Monitor for the detailed flow.
source field: "ble_hrm".
WHOOP
Two modes:| Mode | Path |
|---|---|
| OAuth + webhooks | Cloud-side handles OAuth + webhook ingest, publishes wear.events, RAMEN delivers to client. DeliveryHint.stream (full payload inline). |
| BLE Broadcast HR | Local-only via BleHrmBridge. No cloud round-trip; no recovery/strain/sleep. |
WhoopProvider exposes:
fetchRawDataForFlux(start, end)— pulls raw vendor data for HSI 1.3 transformation.- Real-time HR via webhooks (mode A) or BLE (mode B).
- Workout events.
source field: "whoop" for the OAuth path. The cloud-vs-BLE distinction lives in meta.source_type ("whoop_cloud"); WHOOP via BLE Broadcast HR uses the shared BLE HRM adapter (source = "ble_hrm").
Garmin (Cloud)
Path: OAuth → Garmin Connect API webhooks → cloud → RAMEN. Delivery hint:ping — vendor only sends a notification; client must pull the full record via REST when needed.
GarminProvider exposes:
fetchRawDataForFlux(start, end)— REST pull for Flux input.- Wellness, sleep, activity data classes (
GarminWellnessData,GarminSleepData,GarminActivityData). - Connection state (
GarminConnectionState) for UI. - Realtime data shape (
GarminRealtimeData) when a session is active.
source field: "garmin" for the OAuth Connect API path; meta.source_type carries the more specific "garmin_cloud".
Garmin Health SDK (Real-Time Streaming)
Native RTS path — direct device pairing without going through Garmin Connect cloud. Requires a separate Garmin license and is bundled on demand for licensed integrations only. The underlying Garmin Health SDK code is proprietary; this SDK exposes aGarminHealth provider façade that wraps it.
source field: "garmin_sdk" (the adapter id from GarminSdkAdapter).
Fitbit
OAuth flow mediated by the Synheart Wear API — the device never sees Fitbit access tokens. Cloud delivers avendor_user_id to the app via deep-link callback (?vendor=fitbit&user_id=...&status=success); pass that as the code argument to connectWithCode(...).
FitbitProvider exposes:
fetchHrv,fetchSleep,fetchActivity— date-range record queries.fetchUserProfile— Fitbit profile snapshot.
source field: "fitbit".
Oura
Two paths depending on platform:- Flutter: data flows through HealthKit (iOS) and Health Connect (Android) when an Oura companion app syncs there.
- Kotlin / Swift: dedicated
OuraProviderwith mediated OAuth via the Synheart Wear API (samevendor_user_id-via-deep-link contract as Fitbit).
OuraProvider exposes fetchReadiness, fetchSleep, fetchHrv, fetchActivity. source field: "oura".
Streaming model
Today, cloud providers (Whoop, Garmin, Fitbit, Oura) are polled:streamHR / streamHRV run a timer (Combine Timer.publish on Swift, kotlinx.coroutines.flow.flow { delay(...) } on Kotlin) that calls readMetrics(isRealTime: true) on each tick. There is no push channel for these vendors yet.
BleHrmProvider is push-based — the BLE characteristic notification feeds a SharedFlow / AsyncStream and streamHR picks up the latest sample.
Future work: a RamenEventDispatcher on Kotlin / Swift (Flutter already has one) will materialize cloud-side ping events into REST pull-backs, replacing the timer-based polling for cloud providers.
Apple Health XML backfill
When a user exportsexport.zip from the iOS Health app:
synheart-core aggregates samples per day and replays them via Synheart.srmPushWearableDaily(...) so the imported data populates the user’s runtime baselines.
RAMEN 🍜 integration
Each cloud adapter participates in the RAMEN stream when Synheart’s cloud ingestion publishes events:RamenEvent.payload_json:
DeliveryHint.stream: parse inline, emit immediately.DeliveryHint.ping: schedule a REST pull (via the adapter’s provider) to fetch the body.DeliveryHint.unknown: treat asstream(best-effort) and log.
Permission flow
SynheartWear.requestPermissions(permissions, reason):
- Maps Synheart
PermissionTypevalues to OS permission scopes. - Routes to the appropriate adapter (HealthKit on iOS, Health Connect on Android, OAuth flow for cloud adapters).
- Returns
Map<PermissionType, ConsentStatus>per type.
Related
- Wear Overview — full SDK surface.
- Data Schema — what each adapter writes into the unified
WearMetrics. - BLE Heart Rate Monitor — direct BLE HRM flow.