Skip to content

OmniBLE API Guide

This document summarizes the OmniBLE module API surface and how to use it within this repo. It is based on the local source code under OmniBLE/OmniBLE/ and the integration patterns used by LoopKit.

Overview

  • OmniBLE is a LoopKit PumpManager implementation for Omnipod DASH over BLE.
  • The primary integration point is OmniBLEPumpManager.
  • UI integration is provided via OmniBLEPlugin (LoopKitUI plugin).
  • State is persisted using OmniBLEPumpManagerState (RawRepresentable).

Key modules: - OmniBLE/OmniBLE/PumpManager/: pump manager, state, comms session. - OmniBLE/OmniBLE/Bluetooth/: BLE session, pairing, encryption. - OmniBLE/OmniBLE/OmnipodCommon/: pod models, dosing tables, commands. - OmniBLE/OmniBLEPlugin/: LoopKit UI plugin. - OmniBLE/Docs/InsulinDosingIntegration.md: dosing flow safety notes.

Core Types

OmniBLEPumpManager

Primary API for pairing, setup, status, and dosing. It conforms to LoopKit DeviceManager and PumpManager interfaces.

Initialization and persistence: - init(state: OmniBLEPumpManagerState) - init?(rawState: PumpManager.RawStateValue) - rawState: PumpManager.RawStateValue for persistence.

Delegates and queues: - pumpManagerDelegate (LoopKit PumpManagerDelegate) - delegateQueue (DispatchQueue)

State and status: - state: OmniBLEPumpManagerState - status: PumpManagerStatus - lastSync: Date? - deviceBLEName: String?

Observers: - addPodStateObserver(_:queue:) / removePodStateObserver(_:) - addStatusObserver(_:queue:) / removeStatusObserver(_:)

Setup lifecycle: - pairAndPrime(completion:) - insertCannula(completion:) - checkCannulaInsertionFinished(completion:) - resumingPodSetup() - completeOnboard() - forgetPod(completion:) - deactivatePod(completion:)

Status and alerts: - getPodStatus(completion:) - getDetailedStatus() async throws - acknowledgePodAlerts(_:completion:) - setTime(completion:) - updateExpirationReminder(_:completion:) - updateLowReservoirReminder(_:completion:)

Dosing: - enactBolus(units:activationType:completion:) - cancelBolus(completion:) - enactTempBasal(unitsPerHour:for:completion:) - runTemporaryBasalProgram(unitsPerHour:for:automatic:completion:) - suspendDelivery(completion:) - suspendDelivery(withSuspendReminders:completion:) - resumeDelivery(completion:)

Dose rounding and estimates: - roundToSupportedBolusVolume(units:) - roundToSupportedBasalRate(unitsPerHour:) - estimatedDuration(toBolus:)

Diagnostics: - playTestBeeps() async throws - readPulseLog() async throws - readPulseLogPlus() async throws - readActivationTime() async throws - readTriggeredAlerts() async throws

OmniBLEPumpManagerState

Persistent state container. - Stores pod state, basal schedule, insulin type, reminders, controllerId, podId, active alerts, and other pump configuration. - Use rawValue to persist and init?(rawValue:) to restore.

OmniBLEPlugin (LoopKitUI)

  • OmniBLEPlugin exposes OmniBLEPumpManager to LoopKitUI via PumpManagerUIPlugin.
  • The plugin is the entry point if you are using LoopKitUI discovery.

Typical Integration Flow

1) Create or restore pump manager

import OmniBLE
import LoopKit

let basalSchedule = BasalSchedule(entries: [])
let state = OmniBLEPumpManagerState(
    podState: nil,
    timeZone: TimeZone.current,
    basalSchedule: basalSchedule,
    insulinType: .novolog,
    maximumTempBasalRate: 0
)

let pumpManager = OmniBLEPumpManager(state: state)

If restoring from persistence:

if let pumpManager = OmniBLEPumpManager(rawState: savedRawState) {
    // use pumpManager
}

2) Set delegate and queue

pumpManager.delegateQueue = DispatchQueue(label: "PumpManager")
pumpManager.pumpManagerDelegate = self

3) Pair and prime a pod

pumpManager.pairAndPrime { result in
    switch result {
    case .success(let primeDuration):
        // show countdown, then insert cannula
        pumpManager.insertCannula { insertResult in
            // handle insertResult
        }
    case .failure(let error):
        // handle error
    }
}

4) Configure time and basal schedule

pumpManager.setTime { error in
    // handle error
}

pumpManager.setBasalSchedule(basalSchedule) { error in
    // handle error
}

5) Dosing

pumpManager.enactBolus(units: 1.0, activationType: .manual) { error in
    // handle error
}

pumpManager.enactTempBasal(unitsPerHour: 0.8, for: 30 * 60) { error in
    // handle error
}

pumpManager.suspendDelivery { error in
    // handle error
}

pumpManager.resumeDelivery { error in
    // handle error
}

6) Status and alerts

pumpManager.getPodStatus { result in
    // StatusResponse
}

Task {
    let detailed = try await pumpManager.getDetailedStatus()
}

pumpManager.acknowledgePodAlerts(alertsToAcknowledge) { alerts in
    // acknowledged alerts
}

Error Handling Notes

  • Public errors are surfaced as OmniBLEPumpManagerError or LoopKit PumpManagerError depending on the operation.
  • Common errors include noPodPaired, podAlreadyPaired, and insulinTypeNotConfigured.

Expected BLE Connection Behavior

OmniPod DASH does not maintain a continuous BLE connection. The expected pattern is short, on-demand sessions for status and delivery commands, followed by disconnects.

  • getPodStatus and dosing commands will connect, perform a session, then allow the pod to disconnect.
  • Auto-reconnects are normal and managed via cached pod BLE identifiers.
  • Frequent connect/disconnect cycles are expected, not necessarily an error.
  • Use ensureCurrentPumpData to avoid unnecessary status fetches when data is fresh.

Safety and Validation

  • See OmniBLE/Docs/InsulinDosingIntegration.md for validation gates and safety requirements before issuing dosing commands.
  • Always round bolus and basal values using the provided rounding helpers.
  • Validate pod state, reservoir, and setup progress before dosing.

Offline Basal Fallback Proposal

If algorithm runs fail for a defined window (e.g., no valid CGM + algorithm run for

= 15 minutes), switch the pod to a predefined offline basal schedule so the user continues receiving insulin. This is a safety fallback, not a primary control mode.

Proposed behavior: - Start offline mode after the threshold is reached and no algorithm output is available. - Set a conservative basal schedule derived from the algorithm’s projected basal needs or the last known safe rate. - Notify the user that the system is in offline mode. - Cap offline mode duration; require user action if it persists. - When a valid CGM arrives and the algorithm runs, cancel offline basal and resume explicit 5-minute dosing.

Reconciliation when returning online: - Use PodCommsSession.dosesForStorage() to retrieve missing delivery events. - Store events via NewPumpEvent to update core state and audit logs.

Where to Look in Code

  • Pump manager API: OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManager.swift
  • State: OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManagerState.swift
  • Pod comms: OmniBLE/OmniBLE/PumpManager/PodComms.swift
  • BLE session: OmniBLE/OmniBLE/Bluetooth/
  • UI plugin: OmniBLE/OmniBLEPlugin/OmniBLEPlugin.swift