Просмотр исходного кода

Harden condition; check for suspend-resume-pairs

Deniz Cengiz 4 месяцев назад
Родитель
Сommit
abb3f0eede
2 измененных файлов с 44 добавлено и 18 удалено
  1. 10 0
      Model/Helper/PumpEvent+helper.swift
  2. 34 18
      Trio/Sources/APS/OpenAPS/OpenAPS.swift

+ 10 - 0
Model/Helper/PumpEvent+helper.swift

@@ -213,6 +213,16 @@ enum PumpEventDTO: Encodable {
             try prime.encode(to: encoder)
         }
     }
+
+    var isResume: Bool {
+        if case .resume = self { return true }
+        return false
+    }
+
+    var isSuspend: Bool {
+        if case .suspend = self { return true }
+        return false
+    }
 }
 
 // Extension with helper functions to map pump events to DTO objects via uniform masking enum

+ 34 - 18
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -208,24 +208,40 @@ final class OpenAPS {
                 dtos.insert(simulatedBolusDTO, at: 0)
             }
 
-            /// This condition addresses https://github.com/nightscout/Trio/issues/898
-            /// It inject a mock suspend for fresh installs that are still within the insulin action duration window.
-            /// Trio's onboarding completion time (or shortly thereafter; technically once a pump is added)
-            /// marks the start of pump connectivity; without real history, IOB would otherwise start from a resume-only state
-            /// and can go negative.
-            /// By backdating a suspend one second before onboarding completion, we give oref a safe baseline
-            /// when no prior pump events exist.
-            if let onboardingCompletedAt = PropertyPersistentFlags.shared.onboardingCompletedAt,
-               let pumpSettings = self.storage.retrieve(
-                   OpenAPS.Settings.settings,
-                   as: PumpSettings.self
-               )
-            {
-                let durationOfInsulinActionWindow = (pumpSettings.insulinActionCurve as NSDecimalNumber).doubleValue * 60 * 60
-                if Date().timeIntervalSince(onboardingCompletedAt) <= durationOfInsulinActionWindow {
-                    let suspendDate = onboardingCompletedAt.addingTimeInterval(-1)
-                    let suspendDTO = self.createSimulatedSuspendDTO(at: suspendDate)
-                    dtos.insert(suspendDTO, at: 0)
+            // This condition addresses https://github.com/nightscout/Trio/issues/898
+            // Fresh installs usually do not have any pump history, so the first
+            // event after onboarding is typically a PumpResume. Without a preceding
+            // suspend, oref interprets the time between midnight and onboarding as lacking
+            // scheduled basal, so IOB becomes negative. When onboarding completed within
+            // the insulin action duration window, we now find the earliest PumpResume in the
+            // mapped DTOs; if no suspend precedes it, prepend a simulated suspend one
+            // second before onboarding completion. This backdated entry gives oref a safe
+            // baseline, i.e. it assumes profile basal rate in lieue of lacking history,
+            // so net iob of 0
+            if let onboardingCompletedAt = PropertyPersistentFlags.shared.onboardingCompletedAt {
+                let timeSinceOnboarding = Date().timeIntervalSince(onboardingCompletedAt)
+                let oneDaySeconds: TimeInterval = 24 * 60 * 60
+
+                if timeSinceOnboarding <= oneDaySeconds,
+                   let pumpSettings = self.storage.retrieve(
+                       OpenAPS.Settings.settings,
+                       as: PumpSettings.self
+                   )
+                {
+                    let durationOfInsulinActionWindowSeconds = (pumpSettings.insulinActionCurve as NSDecimalNumber)
+                        .doubleValue * 60 * 60
+
+                    if timeSinceOnboarding <= durationOfInsulinActionWindowSeconds,
+                       let firstResumeIndex = dtos.firstIndex(where: \.isResume)
+                    {
+                        let hasSuspendBeforeResume = dtos[..<firstResumeIndex].contains(where: \.isSuspend)
+
+                        if !hasSuspendBeforeResume {
+                            let suspendDate = onboardingCompletedAt.addingTimeInterval(-1)
+                            let suspendDTO = self.createSimulatedSuspendDTO(at: suspendDate)
+                            dtos.insert(suspendDTO, at: 0)
+                        }
+                    }
                 }
             }