Skip to content

feat(vitals): Measure HR/SpO₂ countdown redesign + robust measurement#66

Merged
saksham2001 merged 2 commits into
saksham2001:mainfrom
rgvxsthi:feat/measure-hr-redesign
Jul 16, 2026
Merged

feat(vitals): Measure HR/SpO₂ countdown redesign + robust measurement#66
saksham2001 merged 2 commits into
saksham2001:mainfrom
rgvxsthi:feat/measure-hr-redesign

Conversation

@rgvxsthi

@rgvxsthi rgvxsthi commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Reworks the manual Heart Rate / SpO₂ measurement sheet into a determinate countdown, and hardens the underlying measurement so it reports a trustworthy value.

⚠️ Depends on #62 (Liquid Glass). This branch is stacked on feat/liquid-glass, so until #62 merges this PR's diff also shows the Liquid Glass commits — the Measure HR view uses the shared glass components (GlassCompat.pulseGlass, PulseMotion, etc.) introduced there. Please merge #62 first; the diff here collapses to just the Measure HR changes once it does.

UI (MeasurementModal)

  • 3s instruction hold, then a 30s (HR) / 40s (SpO₂) countdown; the ring fills 0→full driven by TimelineView(.animation) off wall-clock time, so it animates/updates even under Reduce Motion (fixes a prior freeze where the ring stuck at a hardcoded 50% arc).
  • Prominent center countdown timer; live bpm ticks once the reading settles. Only the decorative heartbeat / expanding beat-rings gate behind Reduce Motion.
  • Fixed the error-state "Try again" button rendering as a doubled glass pill (glass button style + a manual accent capsule) → now a single prominent glass capsule.

Measurement robustness (RingSyncCoordinator.measureHR)

  • The Colmi ring echoes its last cached bpm the instant the 0x69 command fires, so the old flow completed in ~2s on a stale value. Now: discard the first ~5s (warm-up echo), sample the full window, and report the median of the samples that cluster within a few bpm (stableHR()).
  • Errors out promptly on: ring removed / disconnected mid-measure, lost contact (>3s gap in samples after readings began), no reading by window end, or a signal that never settles.
  • A disconnected ring now shows an error instead of fabricating a mock reading.

Known limitation — vigorous finger motion is not reliably flagged

The ring exposes no motion / accelerometer / signal-quality data to the app. The accelerometer hardware exists (STK8321 / LIS2DOC) but the firmware never streams it — the app only receives the bpm value plus a worn-incorrectly error code. The firmware also smooths HR internally, so the reported bpm barely scatters even under motion, and a resting HR naturally varies ±5–10 bpm with breathing. As a result, deliberate finger movement (e.g. typing during a measurement) is not reliably detected: the bpm-variance gate cannot separate it from normal breathing variation without false-failing legitimate still readings, so the gate is kept lenient and the 30s median carries minor motion. Future avenue: probe the currently-unparsed 0x69 v[1] HR-frame byte on-device to see if it encodes a quality/motion signal we could hook into.

Tested on-device with a physical ring.

@rgvxsthi
rgvxsthi requested a review from saksham2001 as a code owner July 9, 2026 06:01
@saksham2001
saksham2001 force-pushed the feat/measure-hr-redesign branch from f9b955e to 1bd05e4 Compare July 12, 2026 09:03
@saksham2001
saksham2001 merged commit 4dae095 into saksham2001:main Jul 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants