Repository navigation
Scheduled spot SpO2, longer intervals, 120m HR, and reliability fixes (#103) - #134
Open
foureight84 wants to merge 7 commits into
Open
foureight84 wants to merge 7 commits into
foureight84 wants to merge 7 commits into
Conversation
…rted RingSyncWorker publishes what it pulls from the ring onto PulseEventBus, which keeps no backlog (replay = 0). The only collector that writes it to Room was built and started by the UI's startup (AppServices / PulseLoopApp), so in a process Android launched just for the worker, every event was published to no one and dropped. The subscriber is now one per process and started from PulseLoopApplication.onCreate; AppServices uses the same instance. Groundwork for #103's scheduled spot SpO2, which runs from the background too.
On YCBT rings the hourly SpO2 is computed from heart rate. The ring's manual measurement is real, so the app can now run it on the SpO2 interval: Measurement Frequency -> "Measure SpO2 from the app", off by default, offered for YCBT rings with manual SpO2. - Slots sit halfway between the ring's own readings on a grid from local midnight (60 min -> :30, 30 -> :15/:45). A run WorkManager starts within 5 min of a ring reading, or that would still be measuring at the next one, is skipped. - ScheduledSpo2Worker is one-time work that appends the next slot as it finishes; app start and RingSyncWorker revive the chain if a run was cancelled. - The ring stops the measurement when the link drops, so the run holds the connection until 04 0e: through the app's link when it has one, otherwise a private client with its own RingSyncCoordinator, which runs the normal startup sync first and stores the reading exactly as the Vitals button does.
…#103) The measurement-frequency sliders stopped at 60 min because that is the vendor app's own menu. Two things go past it now, each on its own evidence: - Measure SpO2 from the app gets an interval of its own (60/120/180 min), independent of the ring's SpO2 setting — the app starts these runs, so the ring's limits don't apply, and each run is ~50 s of red LED that 2-3 h spacing spares at night. The slots keep their half-interval offset from the ring's grid; isClear still skips a run that lands near a ring reading. - The heart-rate slider goes to 120 min for the YCBT family: the ring ACKed 01 0c 01 78 with the app off and read at 10:00 and 12:00 (issue #103, 2026-10-22). That is the only value tested, so nothing longer and no other family. The other monitor commands keep the 60-min ceiling their bytes always carried — 120 is not evidenced on their keys, and the blood-oxygen key's grid is what the scheduled spot has to stay between. Slots at 120/180 min: unit tests against a 60- and a 30-min ring grid; 1591 tests, 0 failures.
Albabit's ring (issue #103, 2026-10-23) is catalogued COLMI_SMART_HEALTH (model colmi-smarthealth) — same YCBT driver, but its own RingDeviceType, so the == YCBT checks hid the scheduled spot SpO2 toggle and capped the HR slider at 5-60. Gate the scheduled-SpO2 support check and the raised measurement bounds (min 30, HR max 120) on both YCBT-protocol families; same for the stress-toggle exclusion, since YCBTEncoder.monitorCommands carries no stress key for either family. Manual-SpO2 capability still required, and the worker path shares the one gate.
… estimated filtering (#103) - Fix app SpO2 slider stops with steps=1 (60, 120, 180 min). - Retry GATT connection in ScheduledSpo2Worker to wait out background sync. - Base slot scheduling and isClear on HR interval for YCBT rings. - Allow scheduling app spot SpO2 even if ring SpO2 toggle is disabled. - Add toggle to hide estimated SpO2 from vitals card and detail chart. - Display Estimated tag on individual reading rows in detail screen. - Exclude estimated SpO2 and derived respiratory rate from Health Connect export.
… and prefs (#103) - Verify computeRingIntervalMinutes uses HR interval on YCBT even when SpO2 is off. - Verify 180 min app SpO2 on 120 min ring grid stays clear over repeated cycles. - Verify VitalsExporter excludes estimated SpO2 and YCBT respiratory rate. - Verify ScheduledSpo2Prefs hideEstimated and interval settings round-trip.
foureight84
force-pushed
the
feat/103-longer-spo2-intervals
branch
from
October 24, 2026 06:51
7458bff to
4f7c380
Compare
foureight84
changed the base branch from
feat/103-scheduled-spot-spo2
to
main
October 24, 2026 07:48
…chart (#103) - Feed displayedSpo2 into spo2Series so Today/Vitals cards and widgets filter estimated readings. - Coordinate GATT access: pause ScheduledSpo2Worker timeout while RingSyncWorker syncs; yield sync when measuring. - Scale day-view chart maxGapMs with sample interval (max(90m, interval * 1.5)) so 120m HR/SpO2 readings connect.
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.
Consolidated PR folding #132 and #134 together, retargeted to
mainwith all fixes from RC3/RC4 hardware testing on #103.What is included
App-started spot SpO2 (Hourly SpO2 on this YCBT ring looks computed from heart rate #103):
ScheduledSpo2Worker) that runs real spot SpO2 measurements between the ring's background readings.ScheduledSpo2Prefs).steps = 1) for 1h, 2h, and 3h under Measurement Frequency.Longer Heart-Rate Intervals (YCBT):
01 0c 01 78verified on hardware).isClearcollision checks anchor to the active HR interval, preventing phantom 30m skips when runs are delayed by Doze.BLE GATT Contention Resilience:
ScheduledSpo2Workernow retries and waits up to 45s for background sync to release the GATT lock when Android Doze wakes both workers simultaneously.Real vs. Estimated SpO2 UI:
Estimatedtag when derived from HR.Health Connect Filtering:
~0.2 × HR, and greyed out in settings.Cold Process Sync Fix:
EventPersistenceSubscriberis started inPulseLoopApplication.onCreateso background sync data isn't dropped when Android launches the process without UI.Release Candidate Testing
v2.11.1+79-rc4(versionCode 79) for hardware verification with @Albabit on Hourly SpO2 on this YCBT ring looks computed from heart rate #103 before merging to main.