What's new
Attempt at many-device support — a bunch of new bands/watches/rings can pair now, sync depth varies by device.
WHOOP MG heart screener — capture + history for the ECG reading, hook into AI coach analysis.
Alarms that actually work — weekly schedule, safety notification if it doesn't latch, smart wake window.
Misc bug fixes and other small stuff.
What's Changed
- readme: cleanup + discord link by @abdulsaheel in #318
- docs: SEO/GEO fixes for the marketing page by @abdulsaheel in #319
- readme: stop framing the whole app as WHOOP-only by @abdulsaheel in #320
- i18n(es): translate the 29 strings missing from app_es.arb by @Nico-Ferrero in #323
- fix ASK picker crash + iOS 17 launch crash by @abdulsaheel in #326
- fix iOS 17 launch crash from AccessorySetupKit by @abdulsaheel in #327
- feat(alarm): weekly schedule + latch-failure & 7pm no-alarm safety notifications by @RiffRaff4469 in #329
- Any-wearable multi-device support by @abdulsaheel in #330
- casio: pairs-only adapter for the 2C/2D all-features watches by @abdulsaheel in #335
- colmi ring: pairs-only support by @abdulsaheel in #336
- fossil/skagen q hybrid: pair and bank raw bytes, pairs-only by @abdulsaheel in #337
- pinetime: pairs and banks raw data by @abdulsaheel in #338
- jyou band: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #339
- hplus generic hr band, pairs-only by @abdulsaheel in #340
- lefun ring/band: pairs and connects, reports nothing yet by @abdulsaheel in #341
- dt78/dt92/dt66: pairs-only support by @abdulsaheel in #343
- ringconn: pair + drain, raw archive only by @abdulsaheel in #344
- wearfit band support (howear hk8 ultra / hk8 pro max) by @abdulsaheel in #345
- mykronoz zetime: pairs and connects, battery only by @abdulsaheel in #346
- o2ring: pair, connect, bank raw bytes by @abdulsaheel in #347
- dafit/moyoung support: pairs and banks raw bytes, no decode by @abdulsaheel in #348
- tlw64/no1 f1: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #349
- watch9: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #350
- xwatch: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #351
- smaq2oss: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #352
- id115: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #353
- makibeshr3: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #354
- pebble 2/2se: pairs-only support by @abdulsaheel in #355
- mi band 2/3/4: pairs-only support by @abdulsaheel in #356
- withings steel hr: pairs-only support by @abdulsaheel in #357
- bangle.js: pairs-only support by @abdulsaheel in #358
- ultrahuman ring air: pair + drain, raw archive only by @abdulsaheel in #359
- garmin sports watch pairing by @abdulsaheel in #361
- add coros sports watch support by @abdulsaheel in #362
- add r11m/r10m smart ring support by @abdulsaheel in #363
- polar pmd: pair + stream ppi from a verity sense or oh1 by @abdulsaheel in #342
- feat: show selected chart slot with a vertical cursor by @highdeftant in #373
- fix: hold the beat axis non-decreasing (sleep staging threw on 6 of 8 days), bump kAlgoVersion to 88; quiesce ingest during a data reset by @DropTabl in #365
- Improve AI coach reliability: configurable timeouts, Keychain recovery, and in-flight request survival by @gentbot in #374
- Live HR/IMU stream ownership reconciler (#287) by @DropTabl in #334
- Fix movement-floor DST bug and coach API-key reuse across endpoint changes by @gentbot in #375
- fix gen4-default ratchet count (drifted from retired sites) by @abdulsaheel in #387
- show band battery on home by @abdulsaheel in #377
- gpx export for recorded routes (manual strava upload) by @abdulsaheel in #378
- make interval work/rest/rounds configurable by @abdulsaheel in #379
- steps: phone confirmed-zero hours veto wrist false positives by @abdulsaheel in #380
- add day switcher to home screen by @abdulsaheel in #382
- add altstore source for ios sideload update checks by @abdulsaheel in #383
- hr zone crossing buzz in live workouts by @abdulsaheel in #384
- add lab-results csv import by @abdulsaheel in #385
- respect imperial units for strength weight by @abdulsaheel in #386
- fix oura link test's real-time flake under full-suite CI by @abdulsaheel in #389
- smart wake window by @abdulsaheel in #390
- gate the live event write behind resetgate by @abdulsaheel in #388
- fix strain/calories/zone minutes resetting to 0 after a hard-kill relaunch mid-workout by @abdulsaheel in #381
- sleep detail: link to naps, fix stale comment by @abdulsaheel in #391
- add siri/shortcuts intent to enable tomorrow's alarm by @abdulsaheel in #392
- let you set your own hr zones (#304) by @abdulsaheel in #393
- add an honest vo2max estimate by @abdulsaheel in #394
- fix cold-launch race in the alarm siri intent (#392 follow-up) by @abdulsaheel in #396
- fix manual hr zone crash (double.infinity.round()) by @abdulsaheel in #395
- gate _onEngineState behind resetgate too by @abdulsaheel in #397
- fix Typed.of accepting Infinity/NaN as valid numbers by @abdulsaheel in #398
- fix fabricated resting-hr note on manual zones by @abdulsaheel in #400
- fix manual hr zone floor check by @abdulsaheel in #401
- fix skin_temp_z missing quantum floor by @abdulsaheel in #402
- smart wake: cover the armed alarm's own window, not just habitual wake by @abdulsaheel in #403
- mirror the alarm-confirm self-heal in headless sync by @abdulsaheel in #406
- fix exportWorkout/exportAll workout export race by @abdulsaheel in #404
- fix: signal priority resolver drops devices paired after custom ranking by @abdulsaheel in #405
- high freq wake window: fix DST-unsafe next-day arithmetic by @abdulsaheel in #408
- fix: NaN lat/lng slip past healthkit route import guard by @abdulsaheel in #409
- ios: stop re-arming forgotten bands on restore by @abdulsaheel in #410
- coach: validate date in log_journal/log_period too by @abdulsaheel in #411
- fix: whoop import stops clobbering same-day csv files by @abdulsaheel in #412
- fix: workouts list distance ignores imperial unit setting by @abdulsaheel in #413
- fix: theme toggle never synced to watch by @abdulsaheel in #414
- fix: atomic db-backed slot allocation for notification ids by @abdulsaheel in #415
- fix: widget push() race can interleave two snapshots by @abdulsaheel in #416
- fix: guard against NaN/out-of-range lat-lng in gpx export by @abdulsaheel in #417
- fix: smart wake silently no-ops on null accel rows by @abdulsaheel in #418
- coach: close recursive-CTE DoS in the SQL guard by @abdulsaheel in #419
- fix: live workout invisible to overlap check, could double-book by @abdulsaheel in #420
- fix: cycle-day math off by one across DST by @abdulsaheel in #421
- fix: stopWorkout leaves stale workout suggestions behind by @abdulsaheel in #422
- fix cloud importer overcounting already-measured days by @abdulsaheel in #424
- fix controller leak in add-lab-result dialog by @abdulsaheel in #425
- coach: reject calendar-invalid dates in day() by @abdulsaheel in #423
- stress index: gap-aware nnTimesMs wiring, kAlgoVersion 92 by @abdulsaheel in #427
- fix: metric detail preferred device caption misses coverage-only devices by @abdulsaheel in #426
- gps: route zoneForHr through the shared HeartRateZoneSet by @abdulsaheel in #428
- fix: workout import reports deleted workouts as brought in by @abdulsaheel in #429
- repin analytics for hrv-freq welch gap guard, kAlgoVersion 92->93 by @abdulsaheel in #430
- ai reminders: cap/refuse evening and morning slots inside quiet hours by @abdulsaheel in #433
- bump kAlgoVersion 93, repin analytics for overreaching rhr guard by @abdulsaheel in #431
- fix telemetry flush dropping unsent records on outbox trim race by @abdulsaheel in #435
- fix notif id mirror never pruned on healthy DB path by @abdulsaheel in #434
- fix: oura_link_test flakes under CI load, use deterministic wait instead of wall-clock margin by @abdulsaheel in #436
- fix torch state desync on failed hardware toggle by @abdulsaheel in #437
- fix: keyless local endpoints were sending Bearer null by @abdulsaheel in #438
- fix: route tracker can silently drop gps tail on stop() by @abdulsaheel in #439
- fix live activity restart race by @abdulsaheel in #440
- wire up the journal ai chat, nobody could reach it by @abdulsaheel in #442
- crossday: guard glassbox SWC gate against quantized rhr/temp by @abdulsaheel in #441
- fix medSlotInstant DST drift by @abdulsaheel in #443
- fix: accel1Hz/ppgRedIr/skinTempRaw priority never applied at derive time by @abdulsaheel in #444
- fix: BLE notify exceptions, cycle_screen mounted guards, O(n^2) baseline scan by @abdulsaheel in #446
- Add a Home entry point to the AI briefing screen by @gentbot in #447
- WHOOP MG Heart Screener: ECG capture, store, history and coach reading by @DropTabl in #367
- ios: wake on band prompts instead of holding a 1 Hz HR stream in background by @OsamaMahmood in #445
- repin analytics for temp_circadian zero-variance fix, kAlgoVersion 96->97 by @abdulsaheel in #451
- bump version to 0.10.0+66 for next release by @abdulsaheel in #452
New Contributors
- @Nico-Ferrero made their first contribution in #323
- @RiffRaff4469 made their first contribution in #329
- @highdeftant made their first contribution in #373
- @gentbot made their first contribution in #374
- @OsamaMahmood made their first contribution in #445
Full Changelog: v0.9.29...v0.10.0
What's Changed
- readme: cleanup + discord link by @abdulsaheel in #318
- docs: SEO/GEO fixes for the marketing page by @abdulsaheel in #319
- readme: stop framing the whole app as WHOOP-only by @abdulsaheel in #320
- i18n(es): translate the 29 strings missing from app_es.arb by @Nico-Ferrero in #323
- fix ASK picker crash + iOS 17 launch crash by @abdulsaheel in #326
- fix iOS 17 launch crash from AccessorySetupKit by @abdulsaheel in #327
- feat(alarm): weekly schedule + latch-failure & 7pm no-alarm safety notifications by @RiffRaff4469 in #329
- Any-wearable multi-device support by @abdulsaheel in #330
- casio: pairs-only adapter for the 2C/2D all-features watches by @abdulsaheel in #335
- colmi ring: pairs-only support by @abdulsaheel in #336
- fossil/skagen q hybrid: pair and bank raw bytes, pairs-only by @abdulsaheel in #337
- pinetime: pairs and banks raw data by @abdulsaheel in #338
- jyou band: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #339
- hplus generic hr band, pairs-only by @abdulsaheel in #340
- lefun ring/band: pairs and connects, reports nothing yet by @abdulsaheel in #341
- dt78/dt92/dt66: pairs-only support by @abdulsaheel in #343
- ringconn: pair + drain, raw archive only by @abdulsaheel in #344
- wearfit band support (howear hk8 ultra / hk8 pro max) by @abdulsaheel in #345
- mykronoz zetime: pairs and connects, battery only by @abdulsaheel in #346
- o2ring: pair, connect, bank raw bytes by @abdulsaheel in #347
- dafit/moyoung support: pairs and banks raw bytes, no decode by @abdulsaheel in #348
- tlw64/no1 f1: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #349
- watch9: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #350
- xwatch: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #351
- smaq2oss: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #352
- id115: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #353
- makibeshr3: pairs and banks raw data, decodes nothing yet by @abdulsaheel in #354
- pebble 2/2se: pairs-only support by @abdulsaheel in #355
- mi band 2/3/4: pairs-only support by @abdulsaheel in #356
- withings steel hr: pairs-only support by @abdulsaheel in #357
- bangle.js: pairs-only support by @abdulsaheel in #358
- ultrahuman ring air: pair + drain, raw archive only by @abdulsaheel in #359
- garmin sports watch pairing by @abdulsaheel in #361
- add coros sports watch support by @abdulsaheel in #362
- add r11m/r10m smart ring support by @abdulsaheel in #363
- polar pmd: pair + stream ppi from a verity sense or oh1 by @abdulsaheel in #342
- feat: show selected chart slot with a vertical cursor by @highdeftant in #373
- fix: hold the beat axis non-decreasing (sleep staging threw on 6 of 8 days), bump kAlgoVersion to 88; quiesce ingest during a data reset by @DropTabl in #365
- Improve AI coach reliability: configurable timeouts, Keychain recovery, and in-flight request survival by @gentbot in #374
- Live HR/IMU stream ownership reconciler (#287) by @DropTabl in #334
- Fix movement-floor DST bug and coach API-key reuse across endpoint changes by @gentbot in #375
- fix gen4-default ratchet count (drifted from retired sites) by @abdulsaheel in #387
- show band battery on home by @abdulsaheel in #377
- gpx export for recorded routes (manual strava upload) by @abdulsaheel in #378
- make interval work/rest/rounds configurable by @abdulsaheel in #379
- steps: phone confirmed-zero hours veto wrist false positives by @abdulsaheel in #380
- add day switcher to home screen by @abdulsaheel in #382
- add altstore source for ios sideload update checks by @abdulsaheel in #383
- hr zone crossing buzz in live workouts by @abdulsaheel in #384
- add lab-results csv import by @abdulsaheel in #385
- respect imperial units for strength weight by @abdulsaheel in #386
- fix oura link test's real-time flake under full-suite CI by @abdulsaheel in #389
- smart wake window by @abdulsaheel in #390
- gate the live event write behind resetgate by @abdulsaheel in #388
- fix strain/calories/zone minutes resetting to 0 after a hard-kill relaunch mid-workout by @abdulsaheel in #381
- sleep detail: link to naps, fix stale comment by @abdulsaheel in #391
- add siri/shortcuts intent to enable tomorrow's alarm by @abdulsaheel in #392
- let you set your own hr zones (#304) by @abdulsaheel in #393
- add an honest vo2max estimate by @abdulsaheel in #394
- fix cold-launch race in the alarm siri intent (#392 follow-up) by @abdulsaheel in #396
- fix manual hr zone crash (double.infinity.round()) by @abdulsaheel in #395
- gate _onEngineState behind resetgate too by @abdulsaheel in #397
- fix Typed.of accepting Infinity/NaN as valid numbers by @abdulsaheel in #398
- fix fabricated resting-hr note on manual zones by @abdulsaheel in #400
- fix manual hr zone floor check by @abdulsaheel in #401
- fix skin_temp_z missing quantum floor by @abdulsaheel in #402
- smart wake: cover the armed alarm's own window, not just habitual wake by @abdulsaheel in #403
- mirror the alarm-confirm self-heal in headless sync by @abdulsaheel in #406
- fix exportWorkout/exportAll workout export race by @abdulsaheel in #404
- fix: signal priority resolver drops devices paired after custom ranking by @abdulsaheel in #405
- high freq wake window: fix DST-unsafe next-day arithmetic by @abdulsaheel in #408
- fix: NaN lat/lng slip past healthkit route import guard by @abdulsaheel in #409
- ios: stop re-arming forgotten bands on restore by @abdulsaheel in #410
- coach: validate date in log_journal/log_period too by @abdulsaheel in #411
- fix: whoop import stops clobbering same-day csv files by @abdulsaheel in #412
- fix: workouts list distance ignores imperial unit setting by @abdulsaheel in #413
- fix: theme toggle never synced to watch by @abdulsaheel in #414
- fix: atomic db-backed slot allocation for notification ids by @abdulsaheel in #415
- fix: widget push() race can interleave two snapshots by @abdulsaheel in #416
- fix: guard against NaN/out-of-range lat-lng in gpx export by @abdulsaheel in #417
- fix: smart wake silently no-ops on null accel rows by @abdulsaheel in #418
- coach: close recursive-CTE DoS in the SQL guard by @abdulsaheel in #419
- fix: live workout invisible to overlap check, could double-book by @abdulsaheel in #420
- fix: cycle-day math off by one across DST by @abdulsaheel in #421
- fix: stopWorkout leaves stale workout suggestions behind by @abdulsaheel in #422
- fix cloud importer overcounting already-measured days by @abdulsaheel in #424
- fix controller leak in add-lab-result dialog by @abdulsaheel in #425
- coach: reject calendar-invalid dates in day() by @abdulsaheel in #423
- stress index: gap-aware nnTimesMs wiring, kAlgoVersion 92 by @abdulsaheel in #427
- fix: metric detail preferred device caption misses coverage-only devices by @abdulsaheel in #426
- gps: route zoneForHr through the shared HeartRateZoneSet by @abdulsaheel in #428
- fix: workout import reports deleted workouts as brought in by @abdulsaheel in #429
- repin analytics for hrv-freq welch gap guard, kAlgoVersion 92->93 by @abdulsaheel in #430
- ai reminders: cap/refuse evening and morning slots inside quiet hours by @abdulsaheel in #433
- bump kAlgoVersion 93, repin analytics for overreaching rhr guard by @abdulsaheel in #431
- fix telemetry flush dropping unsent records on outbox trim race by @abdulsaheel in #435
- fix notif id mirror never pruned on healthy DB path by @abdulsaheel in #434
- fix: oura_link_test flakes under CI load, use deterministic wait instead of wall-clock margin by @abdulsaheel in #436
- fix torch state desync on failed hardware toggle by @abdulsaheel in #437
- fix: keyless local endpoints were sending Bearer null by @abdulsaheel in #438
- fix: route tracker can silently drop gps tail on stop() by @abdulsaheel in #439
- fix live activity restart race by @abdulsaheel in #440
- wire up the journal ai chat, nobody could reach it by @abdulsaheel in #442
- crossday: guard glassbox SWC gate against quantized rhr/temp by @abdulsaheel in #441
- fix medSlotInstant DST drift by @abdulsaheel in #443
- fix: accel1Hz/ppgRedIr/skinTempRaw priority never applied at derive time by @abdulsaheel in #444
- fix: BLE notify exceptions, cycle_screen mounted guards, O(n^2) baseline scan by @abdulsaheel in #446
- Add a Home entry point to the AI briefing screen by @gentbot in #447
- WHOOP MG Heart Screener: ECG capture, store, history and coach reading by @DropTabl in #367
- ios: wake on band prompts instead of holding a 1 Hz HR stream in background by @OsamaMahmood in #445
- repin analytics for temp_circadian zero-variance fix, kAlgoVersion 96->97 by @abdulsaheel in #451
- bump version to 0.10.0+66 for next release by @abdulsaheel in #452
New Contributors
- @Nico-Ferrero made their first contribution in #323
- @RiffRaff4469 made their first contribution in #329
- @highdeftant made their first contribution in #373
- @gentbot made their first contribution in #374
- @OsamaMahmood made their first contribution in #445
Full Changelog: v0.9.29...v0.10.0