Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eliminate user retries on pod setup resumes (Loop issue #2117 follow up) #114

Merged
merged 3 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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