synheart_wear 0.5.1
synheart_wear: ^0.5.1 copied to clipboard
Flutter SDK for wearable signals — Apple HealthKit, Health Connect, WHOOP, Garmin, Oura, and Fitbit. Unified HR, HRV, steps, calories, distance, stress.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased #
0.5.1 - 2026-10-07 #
Added #
- BLE: accelerometer stream from Polar chest straps.
connect(enableMotion: true, motionSampleRateHz: 50)brings up the measurement-data service beside the heart-rate service on both platforms;PolarPmdAccelparses plain and delta-compressed frames into m/s² samples andBleHrmProvider.onMotionemits the batches. Devices without the service are unaffected. On Android the set-up requests a 512-byte MTU first (Polar rejects the start command over the default MTU). - Garmin: raw real-time stream.
GarminHealth.rawRealTimeStreamexposes the device's real-time data as delivered.GarminAccelerometerDatanow carries every sample of a batch with its own timestamp and the sampling rate;x/y/z/timestampstill mirror the last sample.
Fixed #
- HealthKit: real-time reads no longer query 30 days of data every tick
(iOS). A streaming read (
isRealTime: true, no explicit range) fell through to the 30-day default, so a 1 s heart-rate stream ran one HealthKit query per metric type over 30 days plus a 30-minute heartbeat-series query every second, and reported the 30-day mean heart rate as the current one. Streaming reads now cover the last 2 minutes and run at most every 10 s; ticks in between return null, as Android's real-time reads already do. Explicit-range reads are unchanged. - BLE HRM: request a low-latency connection before subscribing to heart-rate
notifications (Android). Straps that report RR intervals notify once per
beat; on the default connection interval the link falls behind above ~70 bpm
and the strap drops the beats it cannot send, leaving an RR series that is
short by 10–40% while the HR value looks normal. Requesting
CONNECTION_PRIORITY_HIGHat subscribe time keeps the link ahead of any human heart rate. Applied on both the initial connect and the reconnect path. - Garmin: clearer pairing-failure message. Both platform pairing failure
codes now map to
GarminPairingErrorwith actionable guidance instead of a raw SDK message; the original error stays onoriginalException.
0.5.0 - 2026-07-01 #
Added #
- Optional per-request auth-header signer for the cloud providers.
GarminProvider,WhoopProvider,OuraProvider, andFitbitProvidernow accept an optionalsignRequestcallback (WearRequestSigner). When supplied, every backend request (OAuth initiate, data fetch, backfill, disconnect) uses the returned headers in place of the default app credentials; when omitted, behaviour is unchanged. This lets a host app attach device-attested headers to satisfy a backend that requires per-request authentication.
0.4.6 - 2026-06-25 #
Fixed #
- BLE heart-rate handler: two native crash fixes.
- Bounds-check the HR Measurement parser (iOS + Android) before reading the
flags byte, the 16-bit BPM, and each RR interval — a malformed/truncated
notification no longer traps (Swift) / throws
ArrayIndexOutOfBoundsException(Android). - Android scan now answers the result channel at most once: a single-fire
guard shared between
onScanFailedand the scan timeout prevents theIllegalStateException: Reply already submittedcrash.
- Bounds-check the HR Measurement parser (iOS + Android) before reading the
flags byte, the 16-bit BPM, and each RR interval — a malformed/truncated
notification no longer traps (Swift) / throws
0.4.5 - 2026-06-18 #
Fixed #
- Android: the licensed Garmin
companion-sdk:4.7.0dependency (and its transitive stack — guava, slf4j, logback, SQLCipher, Room) is now wired in only when the AAR is actually present atandroid/repo/.../companion-sdk-4.7.0.aar. The AAR is gitignored and absent from the published package, so previously any consumer of the published package failed to build withCould not find com.garmin.health:companion-sdk. Garmin is genuinely optional: without the AAR the OSS bridge stub ships and Garmin calls returnUNAVAILABLE; with it (local dev aftermake garmin, or a provisioned CI) the full RTS stack is included. Dart API is unchanged.
0.4.4 - 2026-06-18 #
Added #
SleepNightSummary.sleepLatencyMinutes: sleep onset latency derived from stage timing.HealthAdapter.fetchSleepNightstracks the in-bed start and the first non-awake stage start; latency = first sleep − in-bed, ornullwhen it can't be derived. Additive and backward-compatible.- Android: a foreground service keeps generic BLE HRM streaming alive when the app is backgrounded, so heart-rate sessions no longer drop on screen-off.
Fixed #
- BLE: auto-reconnect the HR monitor on a mid-session link drop instead of ending the session.
0.4.3 - 2026-05-26 #
Fixed #
- iOS: BLE HRM auto-reconnect on cold start no longer fails with
DEVICE_NOT_FOUND.BleHrmHandler.connect(deviceId:)used to rely on an optional chain overCBCentralManager, which isnilon the first BLE call after a process launch —retrievePeripheralsandretrieveConnectedPeripheralsthen returned nothing and the connect short-circuited before the radio came up. The fix mirrors whatscan()already does: lazily instantiate the central manager, and if the state is still.unknown/.resetting, stash the request in a newpendingConnectslot and finish it fromcentralManagerDidUpdateStateonce.poweredOnis reached. On.poweredOff/.unauthorizedthe pending request is failed with the same error codes the scan path already returns. Hosts that drive auto-reconnect viaBleHrmService.ensureConnected()at app startup now reconnect to a previously paired strap without a manual "Re-scan" tap.
0.4.2 - 2026-05-19 #
Changed #
- Logging hygiene pass across the four wearable adapters (WHOOP, Garmin, Fitbit, Oura). Default log level demoted so a live debug run no longer drowns the operator in init dumps and full-payload request / response logs. Multi-line emoji-prefixed init blocks collapsed to one summary line each. Full URIs, full third-party response bodies, and user identifiers are no longer logged at INFO level — they're DEBUG-only or redacted to suffix-only at INFO. Errors and lifecycle events still emit at WARN/ERROR.
Privacy #
- User identifiers and OAuth state nonces are no longer logged in full at INFO. Full URIs and full third-party API response bodies are DEBUG-only.
0.4.1 - 2026-05-08 #
Fixed #
- iOS: Auto-detect
Frameworks/Companion.xcframeworkatpod installtime. When the licensed Garmin Companion XCFramework is present, the podspec now wires upvendored_frameworksand-weak_framework Companionautomatically (previously this required hand-uncommenting two lines, and licensed users hitUnable to resolve module dependency: 'Companion'if they forgot). OSS consumers without the framework continue to get a cleanpod install; Garmin methods surfaceGarminSDKErrorat runtime as before.
0.4.0 - 2026-05-07 #
The SDK collects normalized wearable signals from the device's platform
health store (Apple HealthKit on iOS, Health Connect on Android) and
from supported third-party vendors (WHOOP, Garmin, Oura, Fitbit) via
their public APIs. Normalization happens in the SDK; HSI generation
happens upstream in synheart_core.
Public surface #
SynheartWearfacade,SynheartWearConfig.withAdapters({...}).DeviceAdapterenum —platformHealth,whoop,garmin,oura,fitbit. (platformHealthcovers both Apple HealthKit and Health Connect; the legacy nameappleHealthKitwas renamed to make the cross-platform behavior obvious.)MetricType(hr,hrvRmssd,hrvSdnn,steps,calories,distance,stress),WearMetrics,PermissionType,ConsentStatus.RamenEventtyped event surface with aDeliveryHintenum (stream/ping/unknown) andRamenEventDispatcherthat materializes aRamenEventinto a payload map regardless of delivery flavor.- Garmin Dart layer (platform channel, device manager, SDK adapter,
error types, all data models —
GarminDevice,GarminConnectionState,GarminRealTimeData,GarminWellnessData,GarminSleepData,GarminActivityData) ships open-source. Only the native Kotlin/Swift wrapper that calls Garmin SDK symbols requires a Garmin license; without it, Garmin methods surfaceGarminSDKError. - BLE Heart Rate Monitor adapter for direct BLE sensor access.
Platform support #
- iOS 16.0+
- Android API 26+ (Android 8.0+)
- Flutter 3.10.0+