Browse Source

Recompute IOB when pump events change

dnzxy 4 days ago
parent
commit
3530dcf40b

+ 10 - 0
Trio/Sources/APS/APSManager.swift

@@ -30,6 +30,7 @@ protocol APSManager {
     func enactTempBasal(rate: Double, duration: TimeInterval) async
     func determineBasal() async throws
     func determineBasalSync() async throws
+    func updateIob() async
     func simulateDetermineBasal(
         simulatedCarbsAmount: Decimal,
         simulatedBolusAmount: Decimal,
@@ -545,6 +546,15 @@ final class BaseAPSManager: APSManager, Injectable {
         _ = try await determineBasal()
     }
 
+    func updateIob() async {
+        do {
+            try await openAPS.updateIobFile(useJavascriptOref: settings.useJavascriptOref)
+            iobFileDidUpdate.send(())
+        } catch {
+            warning(.apsManager, "IOB-only update failed: \(error.localizedDescription)")
+        }
+    }
+
     func simulateDetermineBasal(
         simulatedCarbsAmount: Decimal,
         simulatedBolusAmount: Decimal,

+ 23 - 0
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -729,6 +729,29 @@ final class OpenAPS {
         }
     }
 
+    /// Recomputes only the IOB file from current pump history, reusing the
+    /// profile and autosens saved by the last loop cycle. Cheap enough to run
+    /// whenever insulin lands in pump history (SMBs, syncs), keeping IOB
+    /// fresh between cycles without a full determination.
+    func updateIobFile(useJavascriptOref: Bool, clock: Date = Date()) async throws {
+        let pumpHistoryObjectIDs = try await fetchPumpHistoryObjectIDs() ?? []
+        let pumpHistoryJSON = try await parsePumpHistory(pumpHistoryObjectIDs)
+        let profile = await loadFileFromStorageAsync(name: Settings.profile)
+        // No profile yet means no loop has ever run; nothing to compute against.
+        guard !profile.isEmpty, profile != RawJSON.null else { return }
+        let autosens = await loadFileFromStorageAsync(name: Settings.autosense)
+
+        let iob = try await iob(
+            pumphistory: pumpHistoryJSON,
+            profile: profile,
+            clock: clock,
+            autosens: autosens.isEmpty ? .null : autosens,
+            useJavascriptOref: useJavascriptOref
+        )
+        await storage.saveAsync(iob, as: Monitor.iob)
+        debug(.openAPS, "IOB-only update complete")
+    }
+
     private func iob(
         pumphistory: JSON,
         profile: JSON,

+ 10 - 0
Trio/Sources/Services/IOB/IOBService.swift

@@ -52,6 +52,16 @@ final class BaseIOBService: IOBService, Injectable {
             self?.updateIOB()
         }.store(in: &subscriptions)
 
+        // Recompute IOB whenever insulin lands in pump history (SMB
+        // enactment, manual boluses, history syncs, deletions). Debounced:
+        // dose syncs and upload-flag updates write events in bursts.
+        coreDataPublisher?.filteredByEntityName("PumpEventStored")
+            .debounce(for: .seconds(2), scheduler: queue)
+            .sink { [weak self] _ in
+                guard let self else { return }
+                Task { await self.apsManager.updateIob() }
+            }.store(in: &subscriptions)
+
         // Trigger update when the iob file is updated
         apsManager.iobFileDidUpdate
             .sink { [weak self] _ in