Skip to content

Show glucose predictions and allow bolus recommendations without pod#2446

Open
Chris-Almond wants to merge 1 commit into
LoopKit:devfrom
Chris-Almond:predictWithoutPod
Open

Show glucose predictions and allow bolus recommendations without pod#2446
Chris-Almond wants to merge 1 commit into
LoopKit:devfrom
Chris-Almond:predictWithoutPod

Conversation

@Chris-Almond
Copy link
Copy Markdown
Contributor

@Chris-Almond Chris-Almond commented Jun 4, 2026

Show predicted glucose and bolus recommendation when no active delivery device is paired

Closes #2445

Overview

When no active pod is paired, for example during a pod change or after a pod fault, Loop suppresses both the predicted glucose curve and the bolus recommendation entirely. This happens because the pump data recency check throws an error when no pod is active, since doseStore.lastAddedPumpData returns .distantPast, which always exceeds inputDataRecencyInterval.

This PR decouples the visualization and bolus recommendation paths from the pump recency check when no active delivery device is detected, while preserving the original conservative behavior when a pod is paired but temporarily out of communication.

Approach

A new computed property shouldModelAsNoDelivery is added as an extension on PumpManagerStatus in LoopKit. This property returns true when basalDeliveryState == .active(.distantPast), which is the sentinel value used by both OmniBLEPumpManager and OmnipodPumpManager to indicate no active pod is paired. I chose this approach to keep the detection logic in one place, close to the data it depends on, and avoid scattering pump-specific logic across the codebase. This was the least disruptive way I found to introduce this change.

For pump types that do not use this sentinel (.active(.distantPast)) (e.g. Medtronic/RileyLink), shouldModelAsNoDelivery will never return true as long as those pumps have a pumpManager with any pumpStatus. When no pump manager is present at all, the property defaults to true which treats the state of an unconfigured pump as no delivery.

Changes

PumpManagerStatus extension

  • Adds shouldModelAsNoDelivery: Bool computed property based on basalDeliveryState

Prediction curve

  • Adds requireRecentPumpData parameter (default true) to predictGlucose in LoopDataManager, preserving existing behavior for all other call sites. (Not sure if this was necessary but it felt safest).
  • When shouldModelAsNoDelivery is true, the suspension of insulin delivery effect is automatically included in the prediction, since no basal is being delivered
  • The main status chart, bolus entry chart, manual dose chart, and predicted glucose chart all reflect this updated prediction
  • Automated dosing recommendations remain fully gated on pump data recency. updatePredictedGlucoseAndRecommendedDose returns early before computing a dose recommendation when pump data is stale

Bolus recommendation

  • When shouldModelAsNoDelivery is true, the full prediction-based bolus recommendation algorithm runs using the suspension-adjusted prediction curve, bypassing the pump recency check
  • When a pod is paired but data is stale (temporary communication gap), the original conservative behavior is preserved. The recommendation is blocked and the existing "No Recent Pump Data" warning is shown
  • A new noPumpConnected notice is surfaced on the bolus screen, distinct from stalePumpData, to clearly communicate the context to the user

Predicted Glucose chart

  • When shouldModelAsNoDelivery is true, the Suspension of Insulin Delivery row in the prediction modification selection picker is shown as active, grayed out, non-interactive, and checked, since it reflects reality rather than a hypothetical
  • The subtitle message is updated on the row to explain why it is applied automatically
  • The alternate prediction line is hidden when it would be identical to the base prediction to avoid rendering a redundant overlapping line

Warning text

  • Updated the stalePumpData warning caption to no longer claim a recommendation cannot be made
  • Added a new noPumpConnected warning case distinct from stalePumpData

Affected files

  • Loop/Managers/LoopDataManager.swift
  • Loop/View Models/BolusEntryViewModel.swift
  • Loop/View Models/ManualEntryDoseViewModel.swift
  • Loop/View Controllers/PredictionTableViewController.swift
  • Loop/Views/BolusEntryView.swift
  • Loop/Extensions/DeviceDataManager+BolusEntryViewModelDelegate.swift
  • LoopTests/ViewModels/BolusEntryViewModelTests.swift

Testing

  • Tested with no pod paired (between pod changes)
  • Tested with pod faulted prior to expiry
  • Tested with pod paired and data stale (temporary communication gap)
  • Tested with pod paired and data fresh
  • Existing automated dosing behavior verified unchanged in all states
  • Only tested on Omnipod Dash. See RFC section below

RFC / Acknowledgements

Detection mechanism

As mentioned above, the shouldModelAsNoDelivery property relies on the .active(.distantPast) sentinel value used by OmniBLEPumpManager and OmnipodPumpManager to signal no active pod. This is an implementation detail rather than a formally documented contract, and could theoretically change without warning. It is also specific to pod-based pump managers. Tube pumps that do not use this sentinel should be unaffected by this change.

A cleaner long-term solution would be to add shouldModelAsNoDelivery directly to the PumpManager protocol in LoopKit with a default implementation of false, allowing each pump manager to explicitly opt in based on its own internal state. This was considered but deferred to keep the scope of this PR contained to the Loop repo. Feedback on whether that approach is preferred is requested and more than welcome.

Default behavior when no pump manager is present

When pumpManagerStatus is nil (no pump configured at all), shouldModelAsNoDelivery defaults to true. This means the feature also activates in the fully unconfigured state, which I felt to be a more useful default, though I honestly can't envision users commonly using Loop without a configured pump/pumpManager. Therefore a user with no pump configured still benefits from seeing a prediction. If the reviewers prefer false in this case, I'm open to that, as it is a one-line modification to adjust the behavior on what I think is an edge-case, but please let me know!

Non-Omnipod pump testing

This change has only been tested live with Omnipod Dash. Contributions from users of other pump types, particularly those that might use or be aware of other causes of .active(.distantPast) in unexpected ways, are welcome, as the codebase only has 2 (now 3) references to that combination.

Screenshots

Note: some of the below screenshots include 2 visual-only modifications to the prediction line color (signaling above/below ranges) and a thin red vertical bar that shows the current time across all charts. Those changes are from some of my very old personal features and they are not included in this PR.

dashboardActualStandardWithPodState
dashboardActualStandardWithPodState
dashboardNoInsulinActual
(disregard hidden video marker)
dashboardNoInsulinActual
dashboardNoPodActual_predictionsReflectingUpdates
dashboardNoPodActual_predictionsReflectingUpdates
dashboardNoPodActual
dashboardNoPodActual
dashboardPredictionLineSimulatorNoPumpConfigured
dashboardPredictionLineSimulatorNoPumpConfigured
predictionsActual
predictionsActual

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.

Feature Request: Show predicted glucose and bolus recommendation when no active pod is paired

1 participant