From 22dc24239f2b12561a58284bb7bd44d585d313fd Mon Sep 17 00:00:00 2001 From: Mohammad Abdul Sahil <127765312+abdulsaheel@users.noreply.github.com> Date: Tue, 6 Oct 2026 07:22:47 +0530 Subject: [PATCH 1/6] Multi-device: wire new families, drop undecoded ones, verified fixes Devices - Wire Colmi, Ultrahuman, Mi Band 2/3, Pebble, Garmin, health thermometer and Mi scales end to end: pairing, sync, commit-before-ack, storage and display (battery, last synced, device staging switcher). - Remove 21 families that only archived undecoded bytes. Existing rows stay; a paired device from a removed family shows as unsupported and is never synced. - iOS AccessorySetupKit picker list and Info.plist regenerated. Fixes after a field-by-field review of every non-WHOOP family - Discovery: name/service-data matching where devices do not advertise their GATT service (Ultrahuman, Colmi, Garmin, Mi devices). - Ultrahuman: SDNN HRV instead of a stress value, skin-only temperature, quality gating, write-without-response, cursor by record index, failures keep the cursor, streaming pulls, notify bond retry. - Colmi: temperature encodings, stress history, slot intervals, page ends. - Garmin: one reply per request, transaction ids, compact types, pending-auth registration, frame splitting, download retries; the scripted watch now uses a real watch's handle framing. - Mi Band / scales: activity fetch counted in samples and read to its end marker, pairing confirm wait, scale units and history request. - Polar / HRS / thermometer: PP validity and contact bits, measurement window handling. Derivation - A night with no primary-band data takes the device's own night as vendor_staged sleep (kAlgoVersion 109). Tests - Synthetic end-to-end day, device-only night, session devices, removed families. Golden image tests removed. --- .gitignore | 9 - ios/Runner/Info.plist | 37 + lib/ble/accessory_setup.dart | 7 +- lib/ble/adapters/_registry.dart | 1230 +++++------------ lib/ble/adapters/adapter.dart | 10 +- lib/ble/adapters/banglejs.dart | 55 - lib/ble/adapters/casio.dart | 164 --- lib/ble/adapters/colmi.dart | 596 +++++--- lib/ble/adapters/coros.dart | 22 +- lib/ble/adapters/dafit.dart | 173 --- lib/ble/adapters/dt78.dart | 216 --- lib/ble/adapters/garmin.dart | 571 ++++++-- lib/ble/adapters/gatt_link.dart | 42 +- lib/ble/adapters/host.dart | 5 + lib/ble/adapters/hplus.dart | 211 --- lib/ble/adapters/id115.dart | 86 -- lib/ble/adapters/jyou.dart | 77 -- lib/ble/adapters/lefun.dart | 80 -- lib/ble/adapters/makibeshr3.dart | 55 - lib/ble/adapters/miband234.dart | 387 +++++- lib/ble/adapters/miscale.dart | 188 +++ lib/ble/adapters/o2ring.dart | 131 -- lib/ble/adapters/pebble.dart | 322 ++++- lib/ble/adapters/pinetime.dart | 96 -- lib/ble/adapters/polar_pmd.dart | 35 +- lib/ble/adapters/qhybrid.dart | 125 -- lib/ble/adapters/ring11m.dart | 258 ---- lib/ble/adapters/ringconn.dart | 356 ----- lib/ble/adapters/smaq2oss.dart | 49 - lib/ble/adapters/thermometer.dart | 138 ++ lib/ble/adapters/tlw64.dart | 57 - lib/ble/adapters/ultrahuman.dart | 385 ++++-- lib/ble/adapters/watch9.dart | 55 - lib/ble/adapters/wearfit.dart | 69 - lib/ble/adapters/withings_steel_hr.dart | 489 ------- lib/ble/adapters/xwatch.dart | 50 - lib/ble/adapters/zetime.dart | 83 -- lib/ble/banglejs_link.dart | 184 --- lib/ble/ble_state.dart | 4 +- lib/ble/casio_link.dart | 201 --- lib/ble/colmi_link.dart | 57 +- lib/ble/coros_link.dart | 5 +- lib/ble/dafit_link.dart | 245 ---- lib/ble/dt78_link.dart | 157 --- lib/ble/garmin_link.dart | 117 +- lib/ble/hplus_link.dart | 209 --- lib/ble/hrs_link.dart | 255 ++-- lib/ble/id115_link.dart | 171 --- lib/ble/jyou_link.dart | 209 --- lib/ble/lefun_link.dart | 238 ---- lib/ble/makibeshr3_link.dart | 201 --- lib/ble/miband_link.dart | 136 +- lib/ble/o2ring_link.dart | 277 ---- lib/ble/pebble_link.dart | 93 +- lib/ble/pinetime_link.dart | 195 --- lib/ble/polar_pmd_link.dart | 30 +- lib/ble/qhybrid_link.dart | 249 ---- lib/ble/ring11m_link.dart | 191 --- lib/ble/ringconn_link.dart | 256 ---- lib/ble/session_link.dart | 195 +++ lib/ble/smaq2oss_link.dart | 171 --- lib/ble/tlw64_link.dart | 205 --- lib/ble/ultrahuman_link.dart | 130 +- lib/ble/watch9_link.dart | 170 --- lib/ble/wearfit_link.dart | 214 --- lib/ble/withings_steel_hr_link.dart | 350 ----- lib/ble/xwatch_link.dart | 170 --- lib/ble/zetime_link.dart | 227 --- lib/compute/derivation_engine.dart | 13 +- lib/compute/derive_prepare.dart | 34 +- lib/compute/vendor_sleep.dart | 89 +- lib/data/db.dart | 58 + lib/data/local_repository.dart | 6 + lib/data/local_repository_impl.dart | 46 + lib/l10n/app_de.arb | 15 +- lib/l10n/app_en.arb | 52 +- lib/l10n/app_es.arb | 2 - lib/l10n/app_fr.arb | 2 - lib/l10n/app_hi.arb | 2 - lib/l10n/app_zh.arb | 2 - lib/state/app_state.dart | 7 +- lib/sync/background_sync.dart | 202 +-- lib/ui2/README.md | 21 +- lib/ui2/pairing/device_picker.dart | 85 +- lib/ui2/profile/devices.dart | 643 +-------- lib/ui2/profile/gallery.dart | 53 +- lib/ui2/profile/pair_sensor.dart | 21 +- lib/ui2/screens/day_timeline.dart | 20 +- lib/ui2/screens/sleep_detail.dart | 111 +- test/adapter_signals_registry_test.dart | 53 +- test/adapters/banglejs_test.dart | 66 - test/adapters/casio_adapter_test.dart | 156 --- test/adapters/colmi_test.dart | 535 ++++--- test/adapters/coros_adapter_test.dart | 12 + test/adapters/dafit_adapter_test.dart | 213 --- test/adapters/dt78_adapter_test.dart | 162 --- test/adapters/garmin_adapter_test.dart | 503 ++++++- test/adapters/gatt_link_write_test.dart | 16 +- test/adapters/hplus_adapter_test.dart | 126 -- test/adapters/id115_test.dart | 115 -- test/adapters/jyou_test.dart | 93 -- test/adapters/lefun_adapter_test.dart | 96 -- test/adapters/makibeshr3_test.dart | 65 - test/adapters/miband234_test.dart | 126 +- test/adapters/miscale_test.dart | 171 +++ test/adapters/o2ring_adapter_test.dart | 157 --- test/adapters/pebble_adapter_test.dart | 218 ++- test/adapters/pinetime_test.dart | 97 -- test/adapters/polar_pmd_adapter_test.dart | 63 + test/adapters/qhybrid_adapter_test.dart | 92 -- test/adapters/ring11m_adapter_test.dart | 215 --- test/adapters/ringconn_adapter_test.dart | 305 ---- test/adapters/smaq2oss_test.dart | 65 - test/adapters/thermometer_adapter_test.dart | 53 + test/adapters/tlw64_test.dart | 75 - test/adapters/ultrahuman_adapter_test.dart | 457 +++++- test/adapters/watch9_test.dart | 69 - test/adapters/wearfit_adapter_test.dart | 89 -- .../withings_steel_hr_adapter_test.dart | 238 ---- .../withings_steel_hr_auth_crypto_test.dart | 74 - test/adapters/xwatch_test.dart | 65 - test/adapters/zetime_adapter_test.dart | 86 -- ...ackground_sync_banglejs_cooldown_test.dart | 30 - test/band_registry_test.dart | 72 +- test/banglejs_link_test.dart | 59 - test/casio_link_test.dart | 126 -- test/colmi_link_test.dart | 204 ++- test/dafit_link_test.dart | 100 -- test/dt78_link_test.dart | 60 - test/hrs_link_test.dart | 102 +- test/ios_ask_plist_test.dart | 42 +- test/jyou_link_test.dart | 46 - test/lefun_link_test.dart | 108 -- test/makibeshr3_link_test.dart | 140 -- test/miband_link_test.dart | 61 +- test/o2ring_link_test.dart | 17 - test/pebble_link_test.dart | 49 +- test/pinetime_link_test.dart | 62 - test/removed_family_test.dart | 46 + test/ringconn_link_test.dart | 237 ---- test/session_devices_test.dart | 124 ++ test/support/garmin_watch.dart | 135 ++ test/support/synthetic_day.dart | 561 ++++++++ test/synthetic_e2e_test.dart | 273 ++++ test/synthetic_vendor_night_test.dart | 75 + test/tlw64_link_test.dart | 59 - test/ui2_activity_test.dart | 80 +- ...est.dart => ui2_component_sweep_test.dart} | 101 +- test/ui2_gallery_test.dart | 3 - ...en_test.dart => ui2_home_health_test.dart} | 591 +------- ....dart => ui2_onboarding_profile_test.dart} | 59 +- test/ui2_sleep_detail_test.dart | 66 + test/ultrahuman_link_test.dart | 240 ++++ test/vendor_sleep_test.dart | 28 + test/withings_steel_hr_link_test.dart | 216 --- test/zetime_link_test.dart | 89 -- tool/gen_ios_ask_plist.dart | 6 +- 157 files changed, 7501 insertions(+), 15607 deletions(-) delete mode 100644 lib/ble/adapters/banglejs.dart delete mode 100644 lib/ble/adapters/casio.dart delete mode 100644 lib/ble/adapters/dafit.dart delete mode 100644 lib/ble/adapters/dt78.dart delete mode 100644 lib/ble/adapters/hplus.dart delete mode 100644 lib/ble/adapters/id115.dart delete mode 100644 lib/ble/adapters/jyou.dart delete mode 100644 lib/ble/adapters/lefun.dart delete mode 100644 lib/ble/adapters/makibeshr3.dart create mode 100644 lib/ble/adapters/miscale.dart delete mode 100644 lib/ble/adapters/o2ring.dart delete mode 100644 lib/ble/adapters/pinetime.dart delete mode 100644 lib/ble/adapters/qhybrid.dart delete mode 100644 lib/ble/adapters/ring11m.dart delete mode 100644 lib/ble/adapters/ringconn.dart delete mode 100644 lib/ble/adapters/smaq2oss.dart create mode 100644 lib/ble/adapters/thermometer.dart delete mode 100644 lib/ble/adapters/tlw64.dart delete mode 100644 lib/ble/adapters/watch9.dart delete mode 100644 lib/ble/adapters/wearfit.dart delete mode 100644 lib/ble/adapters/withings_steel_hr.dart delete mode 100644 lib/ble/adapters/xwatch.dart delete mode 100644 lib/ble/adapters/zetime.dart delete mode 100644 lib/ble/banglejs_link.dart delete mode 100644 lib/ble/casio_link.dart delete mode 100644 lib/ble/dafit_link.dart delete mode 100644 lib/ble/dt78_link.dart delete mode 100644 lib/ble/hplus_link.dart delete mode 100644 lib/ble/id115_link.dart delete mode 100644 lib/ble/jyou_link.dart delete mode 100644 lib/ble/lefun_link.dart delete mode 100644 lib/ble/makibeshr3_link.dart delete mode 100644 lib/ble/o2ring_link.dart delete mode 100644 lib/ble/pinetime_link.dart delete mode 100644 lib/ble/qhybrid_link.dart delete mode 100644 lib/ble/ring11m_link.dart delete mode 100644 lib/ble/ringconn_link.dart create mode 100644 lib/ble/session_link.dart delete mode 100644 lib/ble/smaq2oss_link.dart delete mode 100644 lib/ble/tlw64_link.dart delete mode 100644 lib/ble/watch9_link.dart delete mode 100644 lib/ble/wearfit_link.dart delete mode 100644 lib/ble/withings_steel_hr_link.dart delete mode 100644 lib/ble/xwatch_link.dart delete mode 100644 lib/ble/zetime_link.dart delete mode 100644 test/adapters/banglejs_test.dart delete mode 100644 test/adapters/casio_adapter_test.dart delete mode 100644 test/adapters/dafit_adapter_test.dart delete mode 100644 test/adapters/dt78_adapter_test.dart delete mode 100644 test/adapters/hplus_adapter_test.dart delete mode 100644 test/adapters/id115_test.dart delete mode 100644 test/adapters/jyou_test.dart delete mode 100644 test/adapters/lefun_adapter_test.dart delete mode 100644 test/adapters/makibeshr3_test.dart create mode 100644 test/adapters/miscale_test.dart delete mode 100644 test/adapters/o2ring_adapter_test.dart delete mode 100644 test/adapters/pinetime_test.dart delete mode 100644 test/adapters/qhybrid_adapter_test.dart delete mode 100644 test/adapters/ring11m_adapter_test.dart delete mode 100644 test/adapters/ringconn_adapter_test.dart delete mode 100644 test/adapters/smaq2oss_test.dart create mode 100644 test/adapters/thermometer_adapter_test.dart delete mode 100644 test/adapters/tlw64_test.dart delete mode 100644 test/adapters/watch9_test.dart delete mode 100644 test/adapters/wearfit_adapter_test.dart delete mode 100644 test/adapters/withings_steel_hr_adapter_test.dart delete mode 100644 test/adapters/withings_steel_hr_auth_crypto_test.dart delete mode 100644 test/adapters/xwatch_test.dart delete mode 100644 test/adapters/zetime_adapter_test.dart delete mode 100644 test/background_sync_banglejs_cooldown_test.dart delete mode 100644 test/banglejs_link_test.dart delete mode 100644 test/casio_link_test.dart delete mode 100644 test/dafit_link_test.dart delete mode 100644 test/dt78_link_test.dart delete mode 100644 test/jyou_link_test.dart delete mode 100644 test/lefun_link_test.dart delete mode 100644 test/makibeshr3_link_test.dart delete mode 100644 test/o2ring_link_test.dart delete mode 100644 test/pinetime_link_test.dart create mode 100644 test/removed_family_test.dart delete mode 100644 test/ringconn_link_test.dart create mode 100644 test/session_devices_test.dart create mode 100644 test/support/garmin_watch.dart create mode 100644 test/support/synthetic_day.dart create mode 100644 test/synthetic_e2e_test.dart create mode 100644 test/synthetic_vendor_night_test.dart delete mode 100644 test/tlw64_link_test.dart rename test/{ui2_golden_test.dart => ui2_component_sweep_test.dart} (52%) rename test/{ui2_home_health_golden_test.dart => ui2_home_health_test.dart} (50%) rename test/{ui2_onboarding_profile_golden_test.dart => ui2_onboarding_profile_test.dart} (75%) create mode 100644 test/ultrahuman_link_test.dart delete mode 100644 test/withings_steel_hr_link_test.dart delete mode 100644 test/zetime_link_test.dart diff --git a/.gitignore b/.gitignore index 57c641269..0b923b807 100644 --- a/.gitignore +++ b/.gitignore @@ -104,9 +104,6 @@ lib/l10n/app_localizations*.dart docs/*.gif docs/*.mp4 -# golden test failure output -test/failures/ - # xcodebuild output from a direct target build ios/build/ @@ -120,10 +117,4 @@ docs/internal/ # HRV/sleep payloads (RMSSD/SDNN/pNN50 tied to a calendar date). Never commit. payload*.json -# Golden images. 416 PNGs, 27 MB, regenerated locally with -# `flutter test --update-goldens`. They are machine- and SDK-specific — the two -# Flutter SDKs on this machine already disagree on antialiasing — so a -# committed set is a diff nobody can review and a merge conflict nobody can -# resolve. The test code stays; the pictures do not. -test/goldens/ MULTIDEVICE_PROGRESS.md diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index b7d08fe70..7150ef408 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -60,7 +60,16 @@ 61080001-8D6D-82B8-614A-1C8CB0F8DCC6 FD4B0001-CCE1-4033-93CE-002D5875F58A + 180D 98ED0001-A541-11E4-B6A0-0002A5D5C51B + 6E40FFF0-B5A3-F393-E0A9-E50E24DCCA9E + 86F65000-F706-58A0-95B2-1FB9261E4DC7 + FEE1 + FED9 + 6A4E2800-667B-11E3-949A-0800200C9A66 + 1809 + 181B + 181D