Repository navigation
Restore Oura Ring 4 connection, battery, HRV comparison and sleep - #2
Merged
Merged
Conversation
…rity - Move the 13 hardcoded Oura/NOOP HRV comparison strings in HealthScreen into string resources for all shipped locales; reuse existing keys for "ms", "Date", "Oura" and "Oura ring". - Drop OuraRestingWindows.sleepCandidates(); callers use windows().filter(isSleepCandidate). - Add platform_specific parity dispositions for the Android-only Oura restoration and refresh the twin map. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
llmassisted
marked this pull request as ready for review
September 26, 2026 18:48
Port the Swift Test Centre feature-mode experiment (ryanbr#2105, OURA_PROTOCOL.md s7.5) to Android, scoped to SpO2: Enable writes mode automatic, Disable writes mode off, each behind a confirmation and never sent automatically. The write is only sent while the ring is idle-streaming and is followed by a status re-read. Beyond the Swift version: - Route the ring's 2f 03 23 reply for any feature other than daytime HR as a verdict (accepted / NOT_SUPPORTED / NOT_AVAILABLE) and log it, instead of handing the driver a no-op live-HR ack. Outside EnablingLiveHR the triplet behaviour is unchanged. - Log the first raw 0x8b spo2_r_pi payloads per session, the tag a Ring 4 is expected to emit once SpO2 runs, as fixtures for a future decoder. Strings in all shipped locales; platform_specific parity dispositions for the Android-only declarations; versionCode 536. Refs ryanbr#2105 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Synchronize live HR demand with the current Activity lifecycle, including an already-resumed cold launch. Read fallback HRV beats per resting window so older history cannot consume the cap for recent nights. Add lifecycle and multi-night HRV regression coverage. Validation: 54 focused JVM tests, source hygiene, protocol documentation checks, and i18n audit passed.
The 0x50 activity/MET stream was decoded and logged but never stored, and the ring trims its copy after each acknowledged drain. On Android: - Persist each anchored 0x50 record as an OURA_MET event row (met_x10 exact tenths, sec_per_sample, state), the same event-table path as OURA_MOTION. Never scored, never a step count. - Import the pre-existing on-device activity sidecar (oura-activity-*.jsonl, written since ryanbr#676) once into the same rows; the (deviceId, ts, kind) PK dedups it against live writes. Waits for the ring's stable serial id. - Port the Swift OuraActivityEstimator; byte-identity is pinned by an oracle test against the Swift source compiled standalone over 300 inputs. - Health screen card (only when OURA_MET rows exist): today's active minutes (>= 3 MET), MET-minutes and estimated above-resting kcal from the profile weight, plus the last 7 days, labelled as an estimate. Within-record sample order is not pinned (documented); a sample's time is good to within its record's ~13 min span. Strings in all shipped locales; platform_specific parity dispositions; versionCode 538. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Restores the Android Oura Ring 4 integration that was present in the previously shipped fork APK but absent from the upstream-based branch merged in #1. The missing commits removed the native-versus-NOOP HRV comparison, rotating-address connection recovery, paced Bluetooth writes, battery-response handling, and sleep-window fallbacks.
This merges
oura-ring-enhancementsinto current main and resolves the overlaps with the newer upstream implementation:Added: Test Centre SpO2 feature-mode write (Android)
Ports the Swift Test Centre feature-mode experiment (ryanbr#2105, OURA_PROTOCOL.md §7.5) to Android, scoped to SpO2: Enable writes mode automatic (
2f 03 22 04 01), Disable writes mode off. Each is behind a confirmation, is only sent while the ring is idle-streaming, is followed by a status re-read, and is never sent automatically. Beyond the Swift version:2f 03 23 <id> <status>reply for any feature other than daytime HR is routed as a verdict (accepted / NOT_SUPPORTED / NOT_AVAILABLE) and logged, instead of being handed to the driver as a no-op live-HR ack. Live-HR triplet behaviour is unchanged (pinned by tests).0x8bspo2_r_pipayloads per session are logged as fixtures, since a Ring 4 is expected to emit that tag once SpO2 runs and NOOP has never received it.Platform scope: this restores previously shipped Android-only fork behavior. Swift is unchanged; the Oura-specific window/UI additions are not presented as cross-platform parity work. No schema migration or deletion of stored health data is introduced.
Added: live HR lifecycle and HRV comparison fixes (04cd3af)
Added: Oura activity estimate from the ring's MET stream (b44d0a9)
0x50record is persisted as anOURA_METevent row (met_x10exact tenths,sec_per_sample,state); previously it was only logged, and the ring trims its copy after each drain. Never scored, never a step count.oura-activity-*.jsonl, written since Oura: capture Tier-B activity MET stream to a JSONL research corpus (Swift + Android) ryanbr/noop#676) is imported once into the same rows; the(deviceId, ts, kind)PK dedups it against live writes.OuraActivityEstimator; byte-identity pinned by an oracle test against the Swift source compiled standalone over 300 inputs.OURA_METrows exist): today's active minutes (≥ 3 MET), MET-minutes and estimated above-resting kcal, plus the last 7 days, labelled as an estimate. Within-record sample order is unpinned and documented (±~13 min).Type of change
How it was tested
RecoveryDriversTestexact floating-point assertions fail on this Mac/JBR 21 runtime (-0.4999999999999929versus-0.5).OuraSleepRestorationTestcovers native-resting sleep and vitals without gravity, active-owner saved hypnograms, manual-window precedence/separate naps, and rejection of short resting windows as automatic sleep.Hardware validation (Oura Ring 4,
ORE_06, builds 535/536):bytes_left 0) and 14 of 20 nights now score (was 4).feature-mode reply feature=0x8 status=0 (accepted)), and daytime live HR is paused when no live screen is visible (dhr_disable).mode=0 (off)(server-gated, never cloud-enabled),2f 03 22 04 01returnedstatus=0 (accepted)and the re-read showedmode=1 (automatic); the mode persisted across a force-stop and fresh connection. Whether SpO2 records then arrive (and as0x6For0x8b) awaits an overnight capture.Earlier: the supplied diagnostic log was inspected. It records failed writes, repeated saved-address connection failures, and stored HR/R-R streams rejected as
NO-NIGHTwith no motion. No physical-ring test has been performed for this branch; pairing, battery refresh, overnight collection, and the restored screens still need on-device confirmation. No raw diagnostic log or personal health data is committed.Related issues
Refs #1