Skip to content

Commit

Permalink
Merge pull request #114 from itsmojo/pod-setup-resume-retry-prevention
Browse files Browse the repository at this point in the history
Eliminate user retries on pod setup resumes (Loop issue #2117 follow up)
  • Loading branch information
marionbarker authored Apr 2, 2024
2 parents 43a90ff + aa6d276 commit d1cdfac
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 7 deletions.
37 changes: 35 additions & 2 deletions OmniBLE/PumpManager/OmniBLEPumpManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,7 @@ extension OmniBLEPumpManager {
self.podComms.pairAndSetupPod(timeZone: .currentFixed, insulinType: insulinType, messageLogger: self)
{ (result) in

// Have new podState, reset all the per pod pump manager state
self.resetPerPodPumpManagerState()

// Calls completion
Expand All @@ -900,6 +901,9 @@ extension OmniBLEPumpManager {
} else {
self.log.default("Pod already paired. Continuing.")

// Resuming the pod setup, try to ensure pod comms will work right away
self.resumingPodSetup()

self.podComms.runSession(withName: "Prime pod") { (result) in
// Calls completion
primeSession(result)
Expand Down Expand Up @@ -959,6 +963,10 @@ extension OmniBLEPumpManager {
self.podComms.runSession(withName: "Insert cannula") { (result) in
switch result {
case .success(let session):
if self.state.podState?.setupProgress.cannulaInsertionSuccessfullyStarted == true {
// Resuming the pod setup, try to ensure pod comms will work right away
self.resumingPodSetup()
}
do {
if self.state.podState?.setupProgress.needsInitialBasalSchedule == true {
let scheduleOffset = timeZone.scheduleOffset(forDate: Date())
Expand Down Expand Up @@ -1011,6 +1019,33 @@ extension OmniBLEPumpManager {
#endif
}

// Called when resuming a pod setup operation which sometimes can fail on the first pod command in various situations.
// Attempting a getStatus and sleeping a couple of seconds on errors greatly improves the odds for first pod command success.
public func resumingPodSetup() {
let sleepTime:UInt32 = 2

if !isConnected {
self.log.debug("### Pod setup resume pod not connected, sleeping %d seconds", sleepTime)
sleep(sleepTime)
}

podComms.runSession(withName: "Resuming pod setup") { (result) in
switch result {
case .success(let session):
let status = try? session.getStatus()
if status == nil {
self.log.debug("### Pod setup resume getStatus failed, sleeping %d seconds", sleepTime)
sleep(sleepTime)
}
case .failure(let error):
self.log.debug("### Pod setup resume session failure, sleeping %d seconds: %@", sleepTime, error.localizedDescription)
sleep(sleepTime)
}
}
}

// MARK: - Pump Commands

public func getPodStatus(completion: ((_ result: PumpManagerResult<StatusResponse>) -> Void)? = nil) {
guard state.hasActivePod else {
completion?(.failure(PumpManagerError.configuration(OmniBLEPumpManagerError.noPodPaired)))
Expand Down Expand Up @@ -1038,8 +1073,6 @@ extension OmniBLEPumpManager {
}
}

// MARK: - Pump Commands

public func acknowledgePodAlerts(_ alertsToAcknowledge: AlertSet, completion: @escaping (_ alerts: [AlertSlot: PodAlert]?) -> Void) {
guard self.hasActivePod else {
completion(nil)
Expand Down
23 changes: 20 additions & 3 deletions OmniBLE/PumpManagerUI/ViewModels/InsertCannulaViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class InsertCannulaViewModel: ObservableObject, Identifiable {
}

@Published var state: InsertCannulaViewModelState = .ready

public var stateNeedsDeliberateUserAcceptance : Bool {
switch state {
case .ready:
Expand All @@ -143,16 +144,19 @@ class InsertCannulaViewModel: ObservableObject, Identifiable {
var didRequestDeactivation: (() -> Void)?

var cannulaInserter: CannulaInserter


var autoRetryAttempted: Bool

init(cannulaInserter: CannulaInserter) {
self.cannulaInserter = cannulaInserter
self.autoRetryAttempted = false

// If resuming, don't wait for the button action
if cannulaInserter.cannulaInsertionSuccessfullyStarted {
insertCannula()
}
}

private func checkCannulaInsertionFinished() {
state = .checkingInsertion
cannulaInserter.checkCannulaInsertionFinished() { (error) in
Expand All @@ -168,6 +172,7 @@ class InsertCannulaViewModel: ObservableObject, Identifiable {

private func insertCannula() {
state = .startingInsertion

cannulaInserter.insertCannula { (result) in
DispatchQueue.main.async {
switch(result) {
Expand All @@ -182,7 +187,19 @@ class InsertCannulaViewModel: ObservableObject, Identifiable {
self.state = .finished
}
case .failure(let error):
self.state = .error(error)
if self.autoRetryAttempted {
self.autoRetryAttempted = false // allow for an auto retry on the next user attempt
self.state = .error(error)
} else {
self.autoRetryAttempted = true
let autoRetryPauseTime = TimeInterval(seconds: 3)
print("### insertCannula encountered error \(error.localizedDescription), retrying after \(autoRetryPauseTime) seconds")
DispatchQueue.global(qos: .utility).async {
Thread.sleep(forTimeInterval: autoRetryPauseTime)

self.insertCannula()
}
}
}
}
}
Expand Down
19 changes: 17 additions & 2 deletions OmniBLE/PumpManagerUI/ViewModels/PairPodViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,11 @@ class PairPodViewModel: ObservableObject, Identifiable {

var podPairer: PodPairer

var autoRetryAttempted: Bool

init(podPairer: PodPairer) {
self.podPairer = podPairer
self.autoRetryAttempted = false

// If resuming, don't wait for the button action
if podPairer.podCommState == .activating {
Expand All @@ -189,8 +192,20 @@ class PairPodViewModel: ObservableObject, Identifiable {
DispatchQueue.main.async {
switch status {
case .failure(let error):
let pairingError = DashPairingError.pumpManagerError(error)
self.state = .error(pairingError)
if self.autoRetryAttempted {
self.autoRetryAttempted = false // allow for an auto retry on the next user attempt
let pairAndPrimeError = DashPairingError.pumpManagerError(error)
self.state = .error(pairAndPrimeError)
} else {
self.autoRetryAttempted = true
let autoRetryPauseTime = TimeInterval(seconds: 3)
print("### pairAndPrimePod encountered error \(error.localizedDescription), retrying after \(autoRetryPauseTime) seconds")
DispatchQueue.global(qos: .utility).async {
Thread.sleep(forTimeInterval: autoRetryPauseTime)

self.pairAndPrime() // handles both pairing or priming failures
}
}
case .success(let duration):

if duration > 0 {
Expand Down

0 comments on commit d1cdfac

Please sign in to comment.