Skip to content

Update main for Omnipod 5 support using ble-heartbeat method - #143

Merged
marionbarker merged 118 commits into
mainfrom
update/main
Sep 2, 2026
Merged

Update main for Omnipod 5 support using ble-heartbeat method#143
marionbarker merged 118 commits into
mainfrom
update/main

Conversation

@marionbarker

Copy link
Copy Markdown
Contributor

Prior to this PR, Omnipod 5 support was only available in the dev branch of OmnipodKit

  • Now that we have sufficient testing, we want to move this version of Omnipod 5 support with the new Bluetooth connection protocol, nicknamed ble-heartbeat, into the main branch
  • This Bluetooth connection protocol method no longer uses the original keep-connected method brought over from the OmniBLE repository and replaces it with the first version of connect on demand
  • Another method of connect on demand, nicknamed eager-connect, is currently being tested in the next-dev branch of OmnipodKit

Plan:

  • merge the ble-heartbeat into main branch so OS-AID main branches can point to OmnipodKit main branch for their released code
  • backport the new eager-connect method to the OmnipodKit dev branch for additional testing with other OS-AID apps

jwoglom and others added 30 commits May 19, 2026 17:44
* resolve conflict in OmnipodKit/PumpManagerUI/Views/OmniSettingsView.swift;
* build to update Localization/Localizable.xcstrings
itsmojo and others added 22 commits July 17, 2026 07:43
…-RileyLink

Fix for loop-next-dev branch: Remove unneeded reference to release RLs when switching pump types
Three related fixes in the DASH/O5 pairing path:

- pairAndPrime: a failed connectToNewPod invoked the caller completion
  twice (completion + completionFailure). The first call schedules the
  pairing UI's silent auto-retry; the second immediately resets the
  auto-retry latch and shows the error, leaving a hidden retry running
  concurrently with the user's manual Retry. OmniBLE calls the
  completion once here; the second call crept in during the OmnipodKit
  rewrite.

- connectToNewPod: the discovery polling Timer was scheduled on the
  calling thread. On a thread with no running run loop (the pairing
  auto-retry path) the timer never fires, so that discovery attempt
  never completes, never times out, and never calls endPodDiscovery,
  leaving discovery mode enabled and the scan running. Schedule the
  timer on the main run loop, and return after each terminal condition
  so a single tick cannot invoke the completion twice.

- PairPodViewModel: perform the pairing auto-retry via
  DispatchQueue.main.asyncAfter instead of Thread.sleep on a utility
  QoS thread, so the retry attempt runs with a live run loop.

Also fixes a malformed %{public} os_log format specifier in
BluetoothManager.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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
Backport the Omnipod BLE Heartbeat API from next-dev
A stale fresh-discovery cold-connect fallback timer could fire ~4s after a
connection had already succeeded, run freshConnect() → cancelPeripheralConnection()
against the LIVE link, and tear it down. didDisconnect (error == nil, i.e. locally
initiated) then saw commandConnectInFlight still set, logged it as an unintended
"keep-alive — reconnecting after drop", and armed another fresh-discovery cycle —
which repeated. Field logs show this spinning for minutes: thousands of nil (self)
disconnects, ~99% mislabeled as drops, zero CBError Code 6 (RF) and only a handful
of Code 7 (pod-initiated). The pod was reachable and close the whole time.

Two surgical fixes:

1. didConnect clears pendingFreshConnectID for the connected peripheral, so a
   still-pending 4s fallback timer no-ops instead of cancelling the live link.
2. freshConnect returns early if the peripheral is already .connected — it exists
   only to unstick a wedged .connecting state, never to drop a healthy connection.

Leaves for follow-up: fresh-discovery never matching (iOS advertisement coalescing
without allowDuplicates → always the cold-connect fallback), and the "reconnecting
after drop" wording that reports our own cancels as drops.
…d-self-disconnect-loop

Backport to dev: Fix self-inflicted connect→cancel→reconnect loop in connect-on-demand
…vert

surfacePodConditionAndQuiet ran on managerQueue (called from centralManager
didDiscover) and invoked connectionDelegate.omnipodDidDetectAlert synchronously.
The host handles that by driving getPodStatus -> runSession -> bleRunSession ->
peripheralManager(forIdentifier:), which does managerQueue.sync. Being already on
managerQueue, that's a sync-to-self deadlock.

It triggered on a fresh launch when a DASH pod advertised a fault/alert transition
before any connection had established BlePodComms.manager (so bleRunSession took the
peripheralManager(forIdentifier:) branch). Field report: an iAPS user's app
crash-looped on launch until, after enough restarts, a connection happened to
establish first. Introduced in a715d9a.

Dispatch the delegate notification off managerQueue so the downstream
managerQueue.sync is a real cross-queue sync. Quieting the alarm scan stays on
managerQueue.

Fixes #126.
…d-self-disconnect-loop

Fix backport: re-entrant managerQueue deadlock surfacing a pod alert from an advert
* Remove brief pod type name from Pair Pod view title

* Remove unused podType.fullName and add briefName usage comment
Remove brief pod type name from Pair Pod view title
@marionbarker

marionbarker commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Check History

There was a flurry of work in the next-dev branch. Some was to fix/improve various items in OmnipodKit, some was to prepare the ble-heartbeat Bluetooth connection method and later, some to prepare the eager-commit Bluetooth connection method.

When checked the first time, discovered PR #119 and #139 had not been back-ported from next-dev to dev (at commit 8fdf5af).

After commit 65f067b, update the status and the table.
✅ Added the 2 missing PR.
✅ Updated minimum deployment to 17.6

Confirm Correct version for this PR

This PR is intended to have all the various fixes for OmnipodKit plus the latest version of the ble-heartbeat connection method without any of the changes that are associated with eager-commit.

Comparison of Changes

This table provides the list of PR for next-dev, dev along with some updates that were introduced without a PR.

Description next-dev PR dev PR comment
Release RileyLink when switching pumps #111 #113 PR to next-dev, backport to dev
Introduce ble-heartbeaf connect on demand various #118 develop in next-dev, backport to dev
Fix connect, cancel. reconnect loop #123 #124 PR to next-dev, backport to dev
Fix rentrant deadlock #127 #128 PR to next-dev, backport to dev
Update Pair Pod view #134 #135 PR to next-dev, backport to dev
Always Display Information before getting cert #136 PR to dev, added to next-dev via cherry pick
Revamped Pod Keep Alive and another fix #125
#138
#142 Two PR to next-dev, backported to dev
Store updated doses immediately before a pod fault is reported
Improved dose handling on faults for more consistent state
#119
#139
#144 Two PR to next-dev, backported to dev

marionbarker and others added 3 commits September 1, 2026 14:39
* Store updated doses immediately before a pod fault is reported (#119)

* Improved dose handling on faults for more consistent state (#139)

* Improved dose handling on faults for more consistent state

* Nit cleanup

---------

Co-authored-by: Joe Moran <mojo@moranfoundation.org>

@itsmojo itsmojo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The git diff of update/main matches dev. I read through the many changes and it all appears to be good.

@marionbarker
marionbarker merged commit 89dff0a into main Sep 2, 2026
@marionbarker
marionbarker deleted the update/main branch September 2, 2026 01:39
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.

7 participants