Repository navigation
Scheduled spot SpO2 (#103) + persist background-sync data in a cold process - #132
Closed
foureight84 wants to merge 2 commits into
Closed
foureight84 wants to merge 2 commits into
foureight84 wants to merge 2 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.
Owner
Author
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.
Refs #103. The Estimated label from #129 is confirmed on hardware. This adds the other half the reporter asked for: the app starts a real spot SpO2 on the SpO2 interval. It also fixes a background-sync bug found on the way.
1. Background sync data was dropped in a cold process (
4df27b0)RingSyncWorkerpublishes what it pulls ontoPulseEventBus(replay = 0). The only collector that writes it to Room was started by the UI's startup (PulseLoopApp). In a process Android launched just for the worker, nothing was listening, so every event was dropped. YCBT never deletes ring history, so its data was likely re-fetched on the next open, but I haven't checked other families.EventPersistenceSubscriberis now one per process, started inPulseLoopApplication.onCreate, andAppServicesuses the same instance.2. App-started spot SpO2 (
f4d930c)MANUAL_SPO2while SpO₂ is on. Stored in SharedPreferences (ScheduledSpo2Prefs), so no schema bump that could clash with feat(sleep): extend a sleep record over time the ring missed (#106) #130.ScheduledSpo2Slots): halfway between the ring's own readings, on a grid from local midnight in local wall-clock time: 60 min → :30, 30 → :15/:45. A run that starts withinmin(5 min, interval/4)of a ring reading, or would still be measuring at the next one, is skipped.ScheduledSpo2Worker): one-time work that appends the next slot (APPEND_OR_REPLACE) as it finishes, and always returns success. App start and everyRingSyncWorkerrun callensureScheduled(KEEP) to revive a cancelled chain. Saving settings reschedules it (REPLACE). Best effort: Doze defers runs.04 0e.AppServices.peek()), it usescoordinator.measureSpO2Only(). It skips during a workout, which polls SpO2 itself.RingBLEClientwith its ownRingSyncCoordinator. It runs the normal startup sequence, waits for the history sync to drain (the same waitfactoryResetRinguses), then measures. The reading settles and is stored exactly as the Vitals button stores it.Tests
./gradlew testDebugUnitTest: 1584 pass, including 9 newScheduledSpo2SlotsTestcases: rollover, a 35-min grid restarting at midnight, a DST change, the late-run guard, and every slot passing its own guard.Not checked on a ring. To check: the transient-client path end to end, how many overnight slots Doze skips, and that the stored reading appears as a spot reading, not a duplicate of the ring's own log.
🤖 Generated with Claude Code