Преглед изворни кода

Back out changes. Instead:

- Make sure that we run determineBasal even when we detect an error in Swift

- Fix y scale for treatments forecast chart
Sam King пре 11 месеци
родитељ
комит
bfc8d0458d

+ 9 - 25
Trio.xcodeproj/project.pbxproj

@@ -244,8 +244,6 @@
 		3B4BA78F2D8DC0EC0069D5B8 /* TidepoolServiceKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B4BA7882D8DC0EC0069D5B8 /* TidepoolServiceKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		3B4BA78F2D8DC0EC0069D5B8 /* TidepoolServiceKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B4BA7882D8DC0EC0069D5B8 /* TidepoolServiceKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		3B4BA7902D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B4BA7892D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework */; };
 		3B4BA7902D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B4BA7892D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework */; };
 		3B4BA7912D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B4BA7892D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		3B4BA7912D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B4BA7892D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
-		3B616AD92DE427CD0070C2F7 /* IobResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B616AD82DE427CA0070C2F7 /* IobResult.swift */; };
-		3B616ADB2DE42A740070C2F7 /* IobSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B616ADA2DE42A6F0070C2F7 /* IobSetup.swift */; };
 		3B997DCB2DC00849006B6BB2 /* JSONImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */; };
 		3B997DCB2DC00849006B6BB2 /* JSONImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */; };
 		3B997DCF2DC00A3A006B6BB2 /* JSONImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */; };
 		3B997DCF2DC00A3A006B6BB2 /* JSONImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */; };
 		3B997DD32DC02AEF006B6BB2 /* glucose.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B997DD12DC02AEF006B6BB2 /* glucose.json */; };
 		3B997DD32DC02AEF006B6BB2 /* glucose.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B997DD12DC02AEF006B6BB2 /* glucose.json */; };
@@ -1058,8 +1056,6 @@
 		3B4BA7692D8DBD690069D5B8 /* RileyLinkKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RileyLinkKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		3B4BA7692D8DBD690069D5B8 /* RileyLinkKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RileyLinkKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		3B4BA7882D8DC0EC0069D5B8 /* TidepoolServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TidepoolServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		3B4BA7882D8DC0EC0069D5B8 /* TidepoolServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TidepoolServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		3B4BA7892D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TidepoolServiceKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		3B4BA7892D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TidepoolServiceKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-		3B616AD82DE427CA0070C2F7 /* IobResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IobResult.swift; sourceTree = "<group>"; };
-		3B616ADA2DE42A6F0070C2F7 /* IobSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IobSetup.swift; sourceTree = "<group>"; };
 		3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporter.swift; sourceTree = "<group>"; };
 		3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporter.swift; sourceTree = "<group>"; };
 		3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporterTests.swift; sourceTree = "<group>"; };
 		3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporterTests.swift; sourceTree = "<group>"; };
 		3B997DD12DC02AEF006B6BB2 /* glucose.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = glucose.json; sourceTree = "<group>"; };
 		3B997DD12DC02AEF006B6BB2 /* glucose.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = glucose.json; sourceTree = "<group>"; };
@@ -2135,7 +2131,6 @@
 				38192E06261BA9960094D973 /* FetchTreatmentsManager.swift */,
 				38192E06261BA9960094D973 /* FetchTreatmentsManager.swift */,
 				3856933F270B57A00002C50D /* CGM */,
 				3856933F270B57A00002C50D /* CGM */,
 				38A504F625DDA0E200C5B9E8 /* Extensions */,
 				38A504F625DDA0E200C5B9E8 /* Extensions */,
-				3B616AD72DE427B60070C2F7 /* Models */,
 				388E5A5825B6F0070019842D /* OpenAPS */,
 				388E5A5825B6F0070019842D /* OpenAPS */,
 				38A0362725ECF05300FCBB52 /* Storage */,
 				38A0362725ECF05300FCBB52 /* Storage */,
 			);
 			);
@@ -2584,14 +2579,6 @@
 			path = TrioTests;
 			path = TrioTests;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
-		3B616AD72DE427B60070C2F7 /* Models */ = {
-			isa = PBXGroup;
-			children = (
-				3B616AD82DE427CA0070C2F7 /* IobResult.swift */,
-			);
-			path = Models;
-			sourceTree = "<group>";
-		};
 		3B997DD22DC02AEF006B6BB2 /* JSONImporterData */ = {
 		3B997DD22DC02AEF006B6BB2 /* JSONImporterData */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -2681,19 +2668,18 @@
 		58645B972CA2D16A008AFCE7 /* HomeStateModel+Setup */ = {
 		58645B972CA2D16A008AFCE7 /* HomeStateModel+Setup */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				58645BA22CA2D325008AFCE7 /* BatterySetup.swift */,
-				58645B9A2CA2D24F008AFCE7 /* CarbSetup.swift */,
-				58645BA62CA2D390008AFCE7 /* ChartAxisSetup.swift */,
 				3B2F77872D7E5387005ED9FA /* CurrentTDDSetup.swift */,
 				3B2F77872D7E5387005ED9FA /* CurrentTDDSetup.swift */,
-				58645B9C2CA2D275008AFCE7 /* DeterminationSetup.swift */,
-				58645BA42CA2D347008AFCE7 /* ForecastSetup.swift */,
-				58645B982CA2D1A4008AFCE7 /* GlucoseSetup.swift */,
-				BD4E1A792D3681AD00D21626 /* GlucoseTargetSetup.swift */,
-				3B616ADA2DE42A6F0070C2F7 /* IobSetup.swift */,
-				58645BA02CA2D2F8008AFCE7 /* OverrideSetup.swift */,
-				58645B9E2CA2D2BE008AFCE7 /* PumpHistorySetup.swift */,
 				BD4E1A7B2D3686D400D21626 /* StartEndMarkerSetup.swift */,
 				BD4E1A7B2D3686D400D21626 /* StartEndMarkerSetup.swift */,
+				BD4E1A792D3681AD00D21626 /* GlucoseTargetSetup.swift */,
 				BDA6CC872CAF219800F942F9 /* TempTargetSetup.swift */,
 				BDA6CC872CAF219800F942F9 /* TempTargetSetup.swift */,
+				58645B982CA2D1A4008AFCE7 /* GlucoseSetup.swift */,
+				58645B9A2CA2D24F008AFCE7 /* CarbSetup.swift */,
+				58645B9C2CA2D275008AFCE7 /* DeterminationSetup.swift */,
+				58645B9E2CA2D2BE008AFCE7 /* PumpHistorySetup.swift */,
+				58645BA02CA2D2F8008AFCE7 /* OverrideSetup.swift */,
+				58645BA22CA2D325008AFCE7 /* BatterySetup.swift */,
+				58645BA42CA2D347008AFCE7 /* ForecastSetup.swift */,
+				58645BA62CA2D390008AFCE7 /* ChartAxisSetup.swift */,
 			);
 			);
 			path = "HomeStateModel+Setup";
 			path = "HomeStateModel+Setup";
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -4310,7 +4296,6 @@
 				DDF847E12C5C287F0049BB3B /* LiveActivitySettingsStateModel.swift in Sources */,
 				DDF847E12C5C287F0049BB3B /* LiveActivitySettingsStateModel.swift in Sources */,
 				583684082BD195A700070A60 /* Determination.swift in Sources */,
 				583684082BD195A700070A60 /* Determination.swift in Sources */,
 				DD17451D2C543C5F00211FAC /* ServicesView.swift in Sources */,
 				DD17451D2C543C5F00211FAC /* ServicesView.swift in Sources */,
-				3B616ADB2DE42A740070C2F7 /* IobSetup.swift in Sources */,
 				38BF021B25E7D06400579895 /* PumpSettingsView.swift in Sources */,
 				38BF021B25E7D06400579895 /* PumpSettingsView.swift in Sources */,
 				3811DEEA25CA063400A708ED /* SyncAccess.swift in Sources */,
 				3811DEEA25CA063400A708ED /* SyncAccess.swift in Sources */,
 				190EBCC829FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift in Sources */,
 				190EBCC829FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift in Sources */,
@@ -4445,7 +4430,6 @@
 				6632A0DC746872439A858B44 /* ISFEditorDataFlow.swift in Sources */,
 				6632A0DC746872439A858B44 /* ISFEditorDataFlow.swift in Sources */,
 				DD17454B2C55C62800211FAC /* AutosensSettingsRootView.swift in Sources */,
 				DD17454B2C55C62800211FAC /* AutosensSettingsRootView.swift in Sources */,
 				DDF847DF2C5C28780049BB3B /* LiveActivitySettingsProvider.swift in Sources */,
 				DDF847DF2C5C28780049BB3B /* LiveActivitySettingsProvider.swift in Sources */,
-				3B616AD92DE427CD0070C2F7 /* IobResult.swift in Sources */,
 				DDB37CC52D05048F00D99BF4 /* ContactImageStorage.swift in Sources */,
 				DDB37CC52D05048F00D99BF4 /* ContactImageStorage.swift in Sources */,
 				BD54A95B2D28087C00F9C1EE /* OverridePresetWatch.swift in Sources */,
 				BD54A95B2D28087C00F9C1EE /* OverridePresetWatch.swift in Sources */,
 				3B2F77882D7E5387005ED9FA /* CurrentTDDSetup.swift in Sources */,
 				3B2F77882D7E5387005ED9FA /* CurrentTDDSetup.swift in Sources */,

+ 4 - 12
Trio/Sources/APS/APSManager.swift

@@ -30,7 +30,6 @@ protocol APSManager {
     func roundBolus(amount: Decimal) -> Decimal
     func roundBolus(amount: Decimal) -> Decimal
     var lastError: CurrentValueSubject<Error?, Never> { get }
     var lastError: CurrentValueSubject<Error?, Never> { get }
     func cancelBolus(_ callback: ((Bool, String) -> Void)?) async
     func cancelBolus(_ callback: ((Bool, String) -> Void)?) async
-    func iobForDisplay(at: Date) async throws -> Decimal?
 }
 }
 
 
 enum APSError: LocalizedError {
 enum APSError: LocalizedError {
@@ -416,11 +415,6 @@ final class BaseAPSManager: APSManager, Injectable {
         await tddStorage.storeTDD(tddResult)
         await tddStorage.storeTDD(tddResult)
     }
     }
 
 
-    /// Calculate the iob at a given time using oref
-    func iobForDisplay(at: Date) async throws -> Decimal? {
-        try await openAPS.iobForDisplay(clock: at)
-    }
-
     func determineBasal() async throws {
     func determineBasal() async throws {
         debug(.apsManager, "Start determine basal")
         debug(.apsManager, "Start determine basal")
 
 
@@ -455,12 +449,6 @@ final class BaseAPSManager: APSManager, Injectable {
             return true
             return true
         }
         }
 
 
-        guard isValidGlucoseData else {
-            debug(.apsManager, "Glucose validation failed")
-            processError(APSError.glucoseError(message: "Glucose validation failed"))
-            return
-        }
-
         do {
         do {
             let now = Date()
             let now = Date()
 
 
@@ -472,6 +460,10 @@ final class BaseAPSManager: APSManager, Injectable {
             try await openAPS.createProfiles()
             try await openAPS.createProfiles()
             let determination = try await openAPS.determineBasal(currentTemp: await currentTemp, clock: now)
             let determination = try await openAPS.determineBasal(currentTemp: await currentTemp, clock: now)
 
 
+            guard isValidGlucoseData else {
+                throw APSError.glucoseError(message: "Glucose validation failed")
+            }
+
             if let determination = determination {
             if let determination = determination {
                 // Capture weak self in closure
                 // Capture weak self in closure
                 await MainActor.run { [weak self] in
                 await MainActor.run { [weak self] in

+ 0 - 33
Trio/Sources/APS/Models/IobResult.swift

@@ -1,33 +0,0 @@
-import Foundation
-
-/// A model to represent IoB results returned from the oref `iob` call via JSON
-struct IobResult: Codable {
-    let iob: Decimal
-    let activity: Decimal
-    let basaliob: Decimal
-    let bolusiob: Decimal
-    let netbasalinsulin: Decimal
-    let bolusinsulin: Decimal
-    let time: Date
-    let iobWithZeroTemp: IobWithZeroTemp
-    var lastBolusTime: UInt64?
-    var lastTemp: LastTemp?
-
-    struct IobWithZeroTemp: Codable {
-        let iob: Decimal
-        let activity: Decimal
-        let basaliob: Decimal
-        let bolusiob: Decimal
-        let netbasalinsulin: Decimal
-        let bolusinsulin: Decimal
-        let time: Date
-    }
-
-    struct LastTemp: Codable {
-        let rate: Decimal?
-        let timestamp: Date?
-        let started_at: Date?
-        let date: UInt64
-        let duration: Decimal?
-    }
-}

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

@@ -276,41 +276,6 @@ final class OpenAPS {
         return .bolus(bolusDTO)
         return .bolus(bolusDTO)
     }
     }
 
 
-    /// Calculate IoB
-    ///
-    /// This function will run through the IoB calculation to get the IoB at the given time. We expect
-    /// it to be used for display purposes outside of the tradiation determination code path
-    /// Parameters:
-    /// - clock: the time to use for the IoB calculation (usually Date())
-    func iobForDisplay(clock: Date) async throws -> Decimal? {
-        // Perform asynchronous calls in parallel
-        async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs() ?? []
-        async let profileAsync = loadFileFromStorageAsync(name: Settings.profile)
-        async let autosenseAsync = loadFileFromStorageAsync(name: Settings.autosense)
-
-        // Await the results of asynchronous tasks
-        let (
-            pumpHistoryJSON,
-            profile,
-            autosens
-        ) = await (
-            try parsePumpHistory(await pumpHistoryObjectIDs),
-            profileAsync,
-            autosenseAsync
-        )
-
-        // IOB calculation
-        let iob = try await self.iob(
-            pumphistory: pumpHistoryJSON,
-            profile: profile,
-            clock: clock,
-            autosens: autosens.isEmpty ? .null : autosens
-        )
-        guard let data = iob.data(using: .utf8) else { return nil }
-        let iobResult = try JSONCoding.decoder.decode([IobResult].self, from: data)
-        return iobResult.first?.iob
-    }
-
     func determineBasal(
     func determineBasal(
         currentTemp: TempBasal,
         currentTemp: TempBasal,
         clock: Date = Date(),
         clock: Date = Date(),

+ 0 - 52
Trio/Sources/Modules/Home/HomeStateModel+Setup/IobSetup.swift

@@ -1,52 +0,0 @@
-import Foundation
-
-extension Home.StateModel {
-    /// Fetch the most recent IoB value using the oref `iob` function. Call this function any time
-    /// you want to update the displayed IoB, like on the arrival of a new pump event or at initialization
-    func setupIobForDisplay() {
-        Task {
-            do {
-                let at = Date()
-                guard let iob = try await apsManager.iobForDisplay(at: at) else {
-                    debug(.default, "Could not get iob for display (oref returned nil)")
-                    await updateIobForDisplay(iob: iobForDisplay, at: at)
-                    return
-                }
-                await updateIobForDisplay(iob: iob, at: at)
-            } catch {
-                debug(
-                    .default,
-                    "\(DebuggingIdentifiers.failed) Error setting up iob for display \(error)"
-                )
-            }
-        }
-    }
-
-    /// Update IoB periodically. This function will update the displayed IoB in response
-    /// to timer events. Internally, it has logic to reduce the frequency of updates as it is
-    /// designed to capture typical decay from elapsed time. If there is something that
-    /// changes IoB, like a new pump event, use `setupIobForDisplay` instead
-    func setupIobForDisplayOnTimer() {
-        Task {
-            let lastRun = iobForDisplayUpdatedAt ?? .distantPast
-            // if we don't have an iob value re-run it more often
-            let period = iobForDisplay == nil ? 1.minutes.timeInterval : 5.minutes.timeInterval
-            if Date().timeIntervalSince(lastRun) > period {
-                setupIobForDisplay()
-            }
-        }
-    }
-
-    /// Update the IoB state values. There is a small amount of logic to try to deal with
-    /// updated values that happen concurrently by using the most recent results
-    @MainActor func updateIobForDisplay(iob: Decimal?, at: Date) {
-        // in case we get two calls at around the same time
-        // make sure to only use the most recent result
-        // unless the iobForDisplay isn't set and we have a result
-        let lastRun = iobForDisplayUpdatedAt ?? .distantPast
-        if at > lastRun || (iob != nil && iobForDisplay == nil) {
-            iobForDisplay = iob
-            iobForDisplayUpdatedAt = at
-        }
-    }
-}

+ 0 - 7
Trio/Sources/Modules/Home/HomeStateModel.swift

@@ -106,8 +106,6 @@ extension Home {
         var listOfCGM: [CGMModel] = []
         var listOfCGM: [CGMModel] = []
         var cgmCurrent = cgmDefaultModel
         var cgmCurrent = cgmDefaultModel
         var shouldRunDeleteOnSettingsChange = true
         var shouldRunDeleteOnSettingsChange = true
-        var iobForDisplay: Decimal?
-        var iobForDisplayUpdatedAt: Date?
 
 
         var showCarbsRequiredBadge: Bool = true
         var showCarbsRequiredBadge: Bool = true
         private(set) var setupPumpType: PumpConfig.PumpType = .minimed
         private(set) var setupPumpType: PumpConfig.PumpType = .minimed
@@ -217,9 +215,6 @@ extension Home {
                     group.addTask {
                     group.addTask {
                         self.setupTempTargetsRunStored()
                         self.setupTempTargetsRunStored()
                     }
                     }
-                    group.addTask {
-                        self.setupIobForDisplay()
-                    }
                 }
                 }
             }
             }
         }
         }
@@ -270,7 +265,6 @@ extension Home {
                 self.setupLastBolus()
                 self.setupLastBolus()
                 self.displayPumpStatusHighlightMessage()
                 self.displayPumpStatusHighlightMessage()
                 self.displayPumpStatusBadge()
                 self.displayPumpStatusBadge()
-                self.setupIobForDisplay()
             }.store(in: &subscriptions)
             }.store(in: &subscriptions)
 
 
             coreDataPublisher?.filteredByEntityName("OpenAPS_Battery").sink { [weak self] _ in
             coreDataPublisher?.filteredByEntityName("OpenAPS_Battery").sink { [weak self] _ in
@@ -312,7 +306,6 @@ extension Home {
             timer.eventHandler = {
             timer.eventHandler = {
                 DispatchQueue.main.async { [weak self] in
                 DispatchQueue.main.async { [weak self] in
                     self?.timerDate = Date()
                     self?.timerDate = Date()
-                    self?.setupIobForDisplayOnTimer()
                 }
                 }
             }
             }
             timer.resume()
             timer.resume()

+ 2 - 2
Trio/Sources/Modules/Home/View/HomeRootView.swift

@@ -431,8 +431,8 @@ extension Home {
                         .foregroundColor(Color.insulin)
                         .foregroundColor(Color.insulin)
                     Text(
                     Text(
                         (
                         (
-                            state.iobForDisplay.flatMap({ Formatter.decimalFormatterWithTwoFractionDigits
-                                    .string(from: $0 as NSNumber) }) ?? "??"
+                            Formatter.decimalFormatterWithTwoFractionDigits
+                                .string(from: (state.enactedAndNonEnactedDeterminations.first?.iob ?? 0) as NSNumber) ?? "0"
                         ) +
                         ) +
                             String(localized: " U", comment: "Insulin unit")
                             String(localized: " U", comment: "Insulin unit")
                     )
                     )

+ 1 - 4
Trio/Sources/Modules/Treatments/TreatmentsStateModel.swift

@@ -910,10 +910,7 @@ extension Treatments.StateModel {
             target = (mostRecentDetermination.currentTarget ?? currentBGTarget as NSDecimalNumber) as Decimal
             target = (mostRecentDetermination.currentTarget ?? currentBGTarget as NSDecimalNumber) as Decimal
             isf = (mostRecentDetermination.insulinSensitivity ?? currentISF as NSDecimalNumber) as Decimal
             isf = (mostRecentDetermination.insulinSensitivity ?? currentISF as NSDecimalNumber) as Decimal
             cob = mostRecentDetermination.cob as Int16
             cob = mostRecentDetermination.cob as Int16
-            // FIXME: for now we fall back to determinationIob but we should use
-            // a more formal error state if we can't collect the needed information
-            let determinationIob = (mostRecentDetermination.iob ?? 0) as Decimal
-            iob = (try? await apsManager.iobForDisplay(at: Date())) ?? determinationIob
+            iob = (mostRecentDetermination.iob ?? 0) as Decimal
             basal = (mostRecentDetermination.tempBasal ?? 0) as Decimal
             basal = (mostRecentDetermination.tempBasal ?? 0) as Decimal
             carbRatio = (mostRecentDetermination.carbRatio ?? currentCarbRatio as NSDecimalNumber) as Decimal
             carbRatio = (mostRecentDetermination.carbRatio ?? currentCarbRatio as NSDecimalNumber) as Decimal
             insulinCalculated = await calculateInsulin()
             insulinCalculated = await calculateInsulin()

+ 6 - 1
Trio/Sources/Modules/Treatments/View/ForecastChart.swift

@@ -126,6 +126,11 @@ struct ForecastChart: View {
         }
         }
     }
     }
 
 
+    private var maxGlucoseMgDl: Decimal {
+        let maxGlucose = state.glucoseFromPersistence.map({ Decimal($0.glucose) }).max() ?? 300
+        return maxGlucose > 300 ? 400 : 300
+    }
+
     private var forecastChart: some View {
     private var forecastChart: some View {
         Chart {
         Chart {
             drawGlucose()
             drawGlucose()
@@ -176,7 +181,7 @@ struct ForecastChart: View {
         .chartXAxis { forecastChartXAxis }
         .chartXAxis { forecastChartXAxis }
         .chartXScale(domain: startMarker ... endMarker)
         .chartXScale(domain: startMarker ... endMarker)
         .chartYAxis { forecastChartYAxis }
         .chartYAxis { forecastChartYAxis }
-        .chartYScale(domain: state.units == .mgdL ? 0 ... 300 : 0.asMmolL ... 300.asMmolL)
+        .chartYScale(domain: state.units == .mgdL ? 0 ... maxGlucoseMgDl : 0.asMmolL ... maxGlucoseMgDl.asMmolL)
         .chartLegend {
         .chartLegend {
             if state.forecastDisplayType == ForecastDisplayType.lines {
             if state.forecastDisplayType == ForecastDisplayType.lines {
                 HStack(spacing: 10) {
                 HStack(spacing: 10) {