From a30cfe69ceab00c82c3283514af9a9e811602747 Mon Sep 17 00:00:00 2001 From: Stefano Alberto Russo Date: Fri, 30 May 2025 00:48:39 +0200 Subject: [PATCH] Fixed active insulin (IOB) reporting. Requires the new basalDosingEnd argument in LoopKit's insulinOnBoard(). --- Loop/Managers/LoopDataManager.swift | 4 ++-- .../Store Protocols/DoseStoreProtocol.swift | 2 +- Loop/Managers/WatchDataManager.swift | 2 +- .../InsulinDeliveryTableViewController.swift | 2 +- .../StatusTableViewController.swift | 20 ++++++++++++++----- LoopTests/Mock Stores/MockDoseStore.swift | 2 +- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/Loop/Managers/LoopDataManager.swift b/Loop/Managers/LoopDataManager.swift index 2319f4eceb..065b85f84b 100644 --- a/Loop/Managers/LoopDataManager.swift +++ b/Loop/Managers/LoopDataManager.swift @@ -1106,7 +1106,7 @@ extension LoopDataManager { } } updateGroup.enter() - doseStore.insulinOnBoard(at: now()) { result in + doseStore.insulinOnBoard(at: now(), basalDosingEnd: nil) { result in switch result { case .failure(let error): warnings.append(.fetchDataWarning(.insulinOnBoard(error: error))) @@ -2129,7 +2129,7 @@ extension LoopDataManager { var activeInsulin: Double? = nil let semaphore = DispatchSemaphore(value: 0) - doseStore.insulinOnBoard(at: Date()) { (result) in + doseStore.insulinOnBoard(at: Date(), basalDosingEnd: nil) { (result) in if case .success(let iobValue) = result { activeInsulin = iobValue.value dosingDecision.insulinOnBoard = iobValue diff --git a/Loop/Managers/Store Protocols/DoseStoreProtocol.swift b/Loop/Managers/Store Protocols/DoseStoreProtocol.swift index dd21ea2a1f..0be8a06782 100644 --- a/Loop/Managers/Store Protocols/DoseStoreProtocol.swift +++ b/Loop/Managers/Store Protocols/DoseStoreProtocol.swift @@ -48,7 +48,7 @@ protocol DoseStoreProtocol: AnyObject { func addDoses(_ doses: [DoseEntry], from device: HKDevice?, completion: @escaping (_ error: Error?) -> Void) // MARK: IOB and insulin effect - func insulinOnBoard(at date: Date, completion: @escaping (_ result: DoseStoreResult) -> Void) + func insulinOnBoard(at date: Date, basalDosingEnd: Date?, completion: @escaping (_ result: DoseStoreResult) -> Void) func getGlucoseEffects(start: Date, end: Date?, basalDosingEnd: Date?, completion: @escaping (_ result: DoseStoreResult<[GlucoseEffect]>) -> Void) diff --git a/Loop/Managers/WatchDataManager.swift b/Loop/Managers/WatchDataManager.swift index bac60b71dc..18ebba1987 100644 --- a/Loop/Managers/WatchDataManager.swift +++ b/Loop/Managers/WatchDataManager.swift @@ -296,7 +296,7 @@ final class WatchDataManager: NSObject { var insulinOnBoard: InsulinValue? updateGroup.enter() - self.deviceManager.doseStore.insulinOnBoard(at: Date()) { (result) in + self.deviceManager.doseStore.insulinOnBoard(at: Date(), basalDosingEnd: Date()) { (result) in switch result { case .success(let iobValue): context.iob = iobValue.value diff --git a/Loop/View Controllers/InsulinDeliveryTableViewController.swift b/Loop/View Controllers/InsulinDeliveryTableViewController.swift index c340f8f536..0e5f9f88ea 100644 --- a/Loop/View Controllers/InsulinDeliveryTableViewController.swift +++ b/Loop/View Controllers/InsulinDeliveryTableViewController.swift @@ -314,7 +314,7 @@ public final class InsulinDeliveryTableViewController: UITableViewController { private func updateIOB() { if case .display = state { - doseStore?.insulinOnBoard(at: Date()) { (result) -> Void in + doseStore?.insulinOnBoard(at: Date(), basalDosingEnd: Date()) { (result) -> Void in DispatchQueue.main.async { switch result { case .failure: diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index 0e14f2167c..7067ebe949 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -416,6 +416,7 @@ final class StatusTableViewController: LoopChartsTableViewController { var glucoseSamples: [StoredGlucoseSample]? var predictedGlucoseValues: [GlucoseValue]? var iobValues: [InsulinValue]? + var currentIOBValue: Double? var doseEntries: [DoseEntry]? var totalDelivery: Double? var cobValues: [CarbValue]? @@ -543,6 +544,17 @@ final class StatusTableViewController: LoopChartsTableViewController { workoutMode = deviceManager.loopManager.settings.nonPreMealOverrideEnabled() } + deviceManager.doseStore.insulinOnBoard(at: Date(), basalDosingEnd: Date()) { (result) -> Void in + switch result { + case .failure(let error): + self.log.error("DoseStore failed to get current insulin on board value: %{public}@", String(describing: error)) + retryContext.update(with: .insulin) + currentIOBValue = nil + case .success(let currentIOB): + currentIOBValue = currentIOB.value + } + } + reloadGroup.notify(queue: .main) { /// Update the chart data @@ -579,11 +591,9 @@ final class StatusTableViewController: LoopChartsTableViewController { charts.setIOBValues(iobValues) } - // Show the larger of the value either before or after the current date - if let maxValue = charts.iob.iobPoints.allElementsAdjacent(to: Date()).max(by: { - return $0.y.scalar < $1.y.scalar - }) { - self.currentIOBDescription = String(describing: maxValue.y) + // Current IOB + if let currentIOBValue = currentIOBValue { + self.currentIOBDescription = String(format: "%.2f U", currentIOBValue) } else { self.currentIOBDescription = nil } diff --git a/LoopTests/Mock Stores/MockDoseStore.swift b/LoopTests/Mock Stores/MockDoseStore.swift index 207596f31b..46af3782d0 100644 --- a/LoopTests/Mock Stores/MockDoseStore.swift +++ b/LoopTests/Mock Stores/MockDoseStore.swift @@ -62,7 +62,7 @@ class MockDoseStore: DoseStoreProtocol { completion(nil, nil, false, nil) } - func insulinOnBoard(at date: Date, completion: @escaping (DoseStoreResult) -> Void) { + func insulinOnBoard(at date: Date, basalDosingEnd: Date? = nil, completion: @escaping (DoseStoreResult) -> Void) { completion(.success(.init(startDate: scenario.currentDate, value: 9.5))) }