Backport the Omnipod BLE Heartbeat API from next-dev - #118
Conversation
…ests
UnfinalizedDose's bolus initializer gained a required decisionId: UUID?
parameter; the source call sites were updated but
testBolusFinishedEarlyOnPodIsMarkedNonMutable was missed, so the
OmniTests target failed to compile ("missing argument for parameter
'decisionId'"). Passes decisionId: nil, matching the other test/source
call sites.
CryptoSwift 1.9.0 removed its `Data.bytes -> [UInt8]` extension (renamed to `byteArray`). On the Xcode 26 SDK, `data.bytes` then resolves to Foundation's new native `Data.bytes`, which returns a `RawSpan` - breaking every crypto call site with errors like: Cannot convert value of type 'RawSpan' to expected argument type 'Array<UInt8>' Value of type 'RawSpan' has no member 'toHexString' Builds pinned to CryptoSwift <= 1.8.5 are unaffected, so this only bites users whose package resolution floats up to 1.9.0/1.10.0 (e.g. after 'Update to Latest Package Versions'). Replace `<data>.bytes` with `Array(<data>)`, which yields the same [UInt8] and compiles against every CryptoSwift version (and doesn't depend on CryptoSwift at all). Verified building OmnipodKit against CryptoSwift 1.10.0 on Xcode 26.5.
CryptoSwift 1.9.0 removed its `Data.bytes -> [UInt8]` extension (renamed to `byteArray`). On the Xcode 26 SDK, `data.bytes` then resolves to Foundation's new native `Data.bytes`, which returns a `RawSpan` - breaking every crypto call site with errors like: Cannot convert value of type 'RawSpan' to expected argument type 'Array<UInt8>' Value of type 'RawSpan' has no member 'toHexString' Builds pinned to CryptoSwift <= 1.8.5 are unaffected, so this only bites users whose package resolution floats up to 1.9.0/1.10.0 (e.g. after 'Update to Latest Package Versions'). Replace `<data>.bytes` with `Array(<data>)`, which yields the same [UInt8] and compiles against every CryptoSwift version (and doesn't depend on CryptoSwift at all). Verified building OmnipodKit against CryptoSwift 1.10.0 on Xcode 26.5.
Use Array(data) instead of Data.bytes for CryptoSwift 1.9+ compatibility
Fix OmniTests: pass decisionId to UnfinalizedDose
hotfix loop-next-dev: Disable TBR enforcement as a workaround with mismatched basal limits
Update loop-next-dev to support Omnipod 5 Pods with token
fix for loop-next-dev: Properly handle and display times for DASH reset type pod faults
Commit f6d56f9 made DetailedStatus return nil (not 0.0) when the fault time is 0x0000, since that is a DASH reset-fault sentinel rather than a valid time. Update the two tests that still asserted 0.0 (testPodInfoNoFaultAlerts, testPodInfoDuringPriming) to XCTAssertNil, matching the intended behavior. Fixes the OmniTests failures blocking LoopWorkspace next-dev CI.
f6d56f9 made DetailedStatus return nil (not 0.0) when the fault time is 0x0000, a DASH reset-fault sentinel rather than a valid time. Update the two tests still asserting 0.0 (testPodInfoNoFaultAlerts, testPodInfoDuringPriming) to XCTAssertNil, matching the intended behavior.
OmniTests: faultEventTimeSinceActivation is nil for 0x0000 fault time
…-RileyLink Fix for loop-next-dev branch: Remove unneeded reference to release RLs when switching pump types
…, connectionless fault detection
When no host refreshes the reading schedule — an app that only calls the legacy setMustProvideBLEHeartbeat sets the heartbeat target once and never updates it — the fixed target goes chronically overdue, so every StartDelay probe pins to heartbeatMinDelaySeconds (the 60s floor). That ~60s background wake cadence is ~5x the intended ~interval cadence, burns the iOS background execution budget, and gets the app suspended for long stretches (Trio field report on LoopKit/LoopKit#599: 99% of heartbeat intervals were 61s, with six 16–128 min suspension gaps). Track the reading interval and when the target was last set. When the target hasn't been refreshed within ~1.5 reading intervals, advance it by whole intervals in issueDelayedConnectProbe so we hold the expected ~interval cadence. A host that refreshes the schedule every reading (Loop) keeps the set-at timestamp fresh, so its floor-based late-reading retry is unaffected. Scheduler simulation: set-once host 60s -> 300s; per-reading-refresh host 300s unchanged; a single late reading still retries at the floor.
Heartbeat: advance a stale target instead of collapsing to the 60s floor
Test✅ successful continuation of Loop dev with BLE backport on SE 2nd gen phone Use LoopWorkspace branch update_dev_to_3.14.4, commit 2bf6a99.
Build to the SE 2nd gen phone which is connected to an Omnipod 5 pod and is using Nightscout as a CGM.
✅ It continues to loop while locked.
But- had issues on the SE 3rd gen phone - write those up as another comment. |
Test with Trio and Loop next-dev on SE 3rd gen phone❌ there were frequent times when Trio stopped looping while locked - we need to look into those. Is there another modification needed for Trio? Trio timelineI don't have the timeline down 100%. But I was running a backport version of Trio, test case 3 from this comment: #117 (comment) Around 12:30, I happened to notice a Trio not looping alert and unlocked the phone.
Several other times during the afternoon I noticed Trio not looping message on the lock screen.
I captured a few notes with time stamps after this - transcribing here: Note at 17:40 I just confirmed I have all the right branches and built again to the phone: SE 3rd gen running iOS 26, Omnipod 5 Pod, Nightscout as a CGM At 17:35, disabled auto-lock and leave phone unlocked with Trio in foreground for at least half and hour Note at 18:15 Note at 20:10 I'm looking to see if there are app limits anywhere on the phone - not finding them. Locked phone again to wait for the 80 hour fault to hit. Note at 20:44
Trio log20260728_2106_Trio_ble-heartbeat_o5_log.txt.zip Trio csv filepodState_Marion_backport-ble_20260728_1.csv Loop next-dev testingA few times when I unlocked the phone to check on the Trio app, I noticed the Loop next-dev app was also showing not looping. I noticed this a few times and it can be seen in the csv file. There were 3 instances of > 1000 sec today and there was one yesterday too. The recovery times are:
Loop Reportcsv file |
Test Status for Loop BLE Backport✅ This test instance behaves nominally with no loss of signal wrt the Pod while phone was locked. Check the results for the Loop BLE Backport test (test case 1 from this comment: #117 (comment))
There are no instances of gaps in deltaSec > 1000 sec between commands. Spot check:
Statistics Table:
Data filesI'll wait until this pod completes before uploading final data files to this PR. Data is saved locally.
|
Test Status for Loop next-dev with new BLE heartbeat method✅ This test instance had no new anomalies since yesterday Check the results for the Loop next-dev with new BLE heartbeattest (test case 2 from this comment: #117 (comment))
There were no new instances of gaps in deltaSec > 1000 sec between commands after UTC 2026-07-29 03:07:49. Statistics Table:
Data filesI'll wait until this pod completes before uploading final data files to this PR. Data is saved locally.
|
Statistics check for iAPS test case 4✅ This test instance behaves nominally with no loss of signal wrt the Pod while phone was locked. DetailsCheck the results for the iAPS dev 2nd gen iOS 18 phone with new BLE heartbeat, Omnipod 5 pod, Nightscout as a CGM (test case 4 from this comment: #117 (comment)) Data harvested this morning with file name: 20260729-0535_iAPS_dev-backport-o5.txt (concatenated all log files so contains all Omnipod 5 results). There are no times when the app stopped looping while locked. Statistics Table:
Histogram of intervals between phone-pod message exchanges
Data filesI'll wait until this pod completes before uploading final data files to this PR. Data is saved locally. |
Final Reports Loop: test cases 1 and 2When each pod reached 80 hours, Issue the Loop Report and parse the messages. Test Case 1: Loop dev backport:The Loop backport: Omnipod 5, SE 2nd gen, iOS 18, test 1 Pod hit 80 hours first.
Test Case 2: Loop next-dev, with last 8 hours running dev backportThe Loop next-dev phone, final configuration was dev backport Configuration for test case 1Omnipod 5, SE 2nd gen, iOS 18, Nightscout as a CGM Final config (rebuild after PR 117 was merged):
Configuration for test case 2Atlas DASH, SE 3rd gen, iOS 26, Nightscout as a CGM For the first 72 hours, the configuration was LoopWorkspace next-dev (before and after merging OmnipodKit PR 117) Statistics for case 1 and 2 (both Loop)Statistics Table:
test case 1: Details for deltaSec > 1000Look at the one outlier for case 1, was at UTC 2026-07-29 16:05:39 Examine lines just before in the log: test case 2: Details for deltaSec > 1000There was one additional time, in addition to the 4 previously noted in earlier comments. Consolidate the list here. 2026-07-28 21:32:45 Log files:
csv files:
|
Status for personal phone testing✅ Using
This was an inadvertent test. I forgot that I set PKA to Silent Tune and left it on for a previous Atlas DASH pod and an entire SAW DASH pod
Keep Alive statisticsThe Loop Report was processed and statistics obtained. Using the same table format as before, the results are shown. The expected cadence between Phone-Pod communications with PKA set to Silent Tunes is 160 sec (2m 40s).
|
UpdateA modification was needed for Trio to take advantage of the new BLE heartbeat.
Modification DetailsThe Trio code under test is a combination of a PR that needs to be tested plus the changes needed for using the BLE heartbeat. ConfigurationSE 3rd gen phone running iOS 26.5.2
Download the code for PR 1300 (branch is finalized-pump-events)Merge most recent dev at the time to test-pr1300_plus_ble_backportPoint to the latest LoopKit and OmnipodKit code with the heartbeat modificationsLoopKit SHA is a5beee96 OmnipodKit SHA is 0d1bb36 commit changes to new branch and push to docs-testAt this point, paired Omnipod 5, but this does not loop while locked. Bring in changes to Trio and push to docs-testThese updates were made around 2026-07-30 13:00 PDT Link for the version under test:https://github.com/docs-test/Trio/tree/test-pr1300_plus_ble_backport |
Last Configuration✅ Last configuration (with modification of Trio) works as expected Used the configuration in #118 (comment) with Trio requesting OmnipodKit provide a heartbeat
|
Test Summary✅ Successful Initial test:
Test of PR 121
ConfigurationThere is a new PR that does not require the changes to Trio to work with the phone locked. Putting the test case here to keep the configuration changes in one place. Revert the changes to Trio and add the changes from PR #121 to the Trio test phone. DetailsStart with Build on to the same test phone: Trio, SE 3rd gen, iOS 26, Omnipod 5 Pod, Nightscout as a CGM
|
Final Harvest of the iAPS test case 4✅ This one appears to have looped while locked for the 80 hours except for two short instances Initial configuration 2026-07-27iAPS dev commit 350617185 (fix: in DeviceDataManager - receive events from
Paired pod at 2026-07-27 17:32:46 (PDT) Updated configuration 2026-07-30IAPS dev commit c19413189 (commits were update POD activation/expiry, pr 1980; translations)
Log of entire history of podiaps-logs-20260731_full_o5_ble-backport.txt.zip csv of entire history of podNote - I need to tweak the parser a bit - it did not put the very first exchange into the csv file. podState_Marion_test-iAPS_20260727_1.csv StatisticsThere were 2 instances when these was delay in the communication groupings between phone and pod; note the time stamps for any deltaSec > 1000; need to examine these in detail (that was at a time when I was moving pods and phones around and testing an rPi Omnipod 5 simulator that is not working)
Statistics results
|
Summary of different Trio ConfigurationsSorry to keep switching between 121 and 118, but setting up for a longer term 118 test using updated version of Trio code. Summary - the Trio updates (commit 386200087) were sufficient to get looping while locked to work. Doing a longer term test of this. The Trio changes and PR 121 changes came in about the same time. Build at 2026-08-01 14:33
✅ Looping while locked - leave it like this for a long term test Trio Truth TableThe Truth Table Below is what I think our tests showed, go back and confirm each state
Note that the loops while locked might be a most-of-the-time ✅ . There were intervals in earlier testing when things would stop looping (>1000 sec). Each alternate configuration was built at the indicated time.
Truth Table
Switch to Middle row at 2026-08-01 14:33
Looping while locked - leave it like this for a long term test Trio and OmnipodKit Commit DetailsUse https://github.com/docs-test/Trio/tree/test-pr1300_plus_ble_backport as the build for Trio. Trio commitslatest Trio commit for this branch is 3862000
OmnipodKit commitsList of OmnipodKit commits for PR 121
List of OmnipodKit commits for PR 118
|

Purpose
Backport to the dev branch the new BLE management scheme developed under the loopkitdev GitHub user name for next-dev branch.
This requires updates to LoopKit, which are merged to LoopKit/LoopKit dev and works best with updates to Loop, which are merged to LoopKit/Loop dev.
This was extensively tested by a few users and several test configurations.
Tests
There will be additional tests while this is a PR.
Prior History
There were extensive tests found in the following PR.
initial next-dev code changes and testing are found in these PR
code changes and testing of the backport to dev from next-dev are found in these PR
Commit history
There were several hot fixes that were applied to multiple open testing branches. The commit history is rather tortuous, but the code changes are clean.