Quellcode durchsuchen

Merge branch 'nightscout:dev' into trio-dev-translations

Magnus Reintz vor 1 Jahr
Ursprung
Commit
6fc5c4d77f

+ 0 - 1
Model/Classes+Properties/OrefDetermination+CoreDataProperties.swift

@@ -37,7 +37,6 @@ public extension OrefDetermination {
     @NSManaged var threshold: NSDecimalNumber?
     @NSManaged var timestamp: Date?
     @NSManaged var timestampEnacted: Date?
-    @NSManaged var totalDailyDose: NSDecimalNumber?
     @NSManaged var forecasts: Set<Forecast>?
 }
 

+ 0 - 1
Model/TrioCoreDataPersistentContainer.xcdatamodeld/TrioCoreDataPersistentContainer.xcdatamodel/contents

@@ -138,7 +138,6 @@
         <attribute name="threshold" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
         <attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="timestampEnacted" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
-        <attribute name="totalDailyDose" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
         <relationship name="forecasts" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Forecast" inverseName="orefDetermination" inverseEntity="Forecast"/>
         <fetchIndex name="byDate">
             <fetchIndexElement property="deliverAt" type="Binary" order="descending"/>

+ 8 - 0
Trio.xcodeproj/project.pbxproj

@@ -206,6 +206,8 @@
 		38FEF413273B317A00574A46 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF412273B317A00574A46 /* HKUnit.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
+		49249B1C2D46E45E000F4866 /* CurrentTDDSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49249B1B2D46E45E000F4866 /* CurrentTDDSetup.swift */; };
+		49249B382D46E76A000F4866 /* TDD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49249B372D46E76A000F4866 /* TDD.swift */; };
 		491D6FBD2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */; };
 		491D6FBE2D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */; };
 		491D6FBF2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */; };
@@ -913,6 +915,8 @@
 		3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = "<group>"; };
 		42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = "<group>"; };
 		44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorProvider.swift; sourceTree = "<group>"; };
+		49249B1B2D46E45E000F4866 /* CurrentTDDSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentTDDSetup.swift; sourceTree = "<group>"; };
+		49249B372D46E76A000F4866 /* TDD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDD.swift; sourceTree = "<group>"; };
 		491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataClass.swift"; sourceTree = "<group>"; };
@@ -2059,6 +2063,7 @@
 		388E5A5925B6F0250019842D /* Models */ = {
 			isa = PBXGroup;
 			children = (
+				49249B372D46E76A000F4866 /* TDD.swift */,
 				DD4FFF322D458EE600B6CFF9 /* GarminWatchState.swift */,
 				DD3078692D42F94000DE0490 /* GarminDevice.swift */,
 				DD3078672D42F5CE00DE0490 /* WatchGlucoseObject.swift */,
@@ -2385,6 +2390,7 @@
 				58645B982CA2D1A4008AFCE7 /* GlucoseSetup.swift */,
 				58645B9A2CA2D24F008AFCE7 /* CarbSetup.swift */,
 				58645B9C2CA2D275008AFCE7 /* DeterminationSetup.swift */,
+				49249B1B2D46E45E000F4866 /* CurrentTDDSetup.swift */,
 				58645B9E2CA2D2BE008AFCE7 /* PumpHistorySetup.swift */,
 				58645BA02CA2D2F8008AFCE7 /* OverrideSetup.swift */,
 				58645BA22CA2D325008AFCE7 /* BatterySetup.swift */,
@@ -3935,6 +3941,7 @@
 				38E44538274E411700EC9A94 /* Disk+[Data].swift in Sources */,
 				98641AF4F92123DA668AB931 /* CarbRatioEditorRootView.swift in Sources */,
 				BDF34F902C10CF8C00D51995 /* CoreDataStack.swift in Sources */,
+				49249B1C2D46E45E000F4866 /* CurrentTDDSetup.swift in Sources */,
 				CEE9A65C2BBB41C800EB5194 /* CalibrationService.swift in Sources */,
 				110AEDED2C51A0AE00615CC9 /* ShortcutsConfigProvider.swift in Sources */,
 				38E4453D274E411700EC9A94 /* Disk+Errors.swift in Sources */,
@@ -3951,6 +3958,7 @@
 				9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */,
 				1967DFBE29D052C200759F30 /* Icons.swift in Sources */,
 				DDD163182C4C694000CD525A /* AdjustmentsRootView.swift in Sources */,
+				49249B382D46E76A000F4866 /* TDD.swift in Sources */,
 				389ECE052601144100D86C4F /* ConcurrentMap.swift in Sources */,
 				110AEDEC2C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift in Sources */,
 				CE7CA3562A064973004BE681 /* StateIntentRequest.swift in Sources */,

Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
Trio/Resources/javascript/bundle/determine-basal.js


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

@@ -1116,41 +1116,6 @@ final class BaseAPSManager: APSManager, Injectable {
         }
     }
 
-    private func tddForStats() async -> (currentTDD: Decimal, tddTotalAverage: Decimal) {
-        let requestTDD = OrefDetermination.fetchRequest() as NSFetchRequest<NSFetchRequestResult>
-        let sort = NSSortDescriptor(key: "timestamp", ascending: false)
-        let daysOf14Ago = Date().addingTimeInterval(-14.days.timeInterval)
-        requestTDD.predicate = NSPredicate(format: "timestamp > %@", daysOf14Ago as NSDate)
-        requestTDD.sortDescriptors = [sort]
-        requestTDD.propertiesToFetch = ["timestamp", "totalDailyDose"]
-        requestTDD.resultType = .dictionaryResultType
-
-        var currentTDD: Decimal = 0
-        var tddTotalAverage: Decimal = 0
-
-        let results = await privateContext.perform {
-            do {
-                let fetchedResults = try self.privateContext.fetch(requestTDD) as? [[String: Any]]
-                return fetchedResults ?? []
-            } catch {
-                debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to get TDD Data for Statistics Upload")
-                return []
-            }
-        }
-
-        if !results.isEmpty {
-            if let latestTDD = results.first?["totalDailyDose"] as? NSDecimalNumber {
-                currentTDD = latestTDD.decimalValue
-            }
-            let tddArray = results.compactMap { ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue }
-            if !tddArray.isEmpty {
-                tddTotalAverage = tddArray.reduce(0, +) / Decimal(tddArray.count)
-            }
-        }
-
-        return (currentTDD, tddTotalAverage)
-    }
-
     private func glucoseForStats() async -> (
         oneDayGlucose: (ifcc: Double, ngsp: Double, average: Double, median: Double, sd: Double, cv: Double, readings: Double),
         hbA1cDisplayUnit: HbA1cDisplayUnit,

+ 9 - 12
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -34,7 +34,6 @@ final class OpenAPS {
         await context.perform {
             let newOrefDetermination = OrefDetermination(context: self.context)
             newOrefDetermination.id = UUID()
-            newOrefDetermination.totalDailyDose = self.decimalToNSDecimalNumber(determination.tdd)
             newOrefDetermination.insulinSensitivity = self.decimalToNSDecimalNumber(determination.isf)
             newOrefDetermination.currentTarget = self.decimalToNSDecimalNumber(determination.current_target)
             newOrefDetermination.eventualBG = determination.eventualBG.map(NSDecimalNumber.init)
@@ -55,9 +54,6 @@ final class OpenAPS {
             newOrefDetermination.expectedDelta = self.decimalToNSDecimalNumber(determination.expectedDelta)
             newOrefDetermination.cob = Int16(Int(determination.cob ?? 0))
             newOrefDetermination.manualBolusErrorString = self.decimalToNSDecimalNumber(determination.manualBolusErrorString)
-            newOrefDetermination.tempBasal = determination.insulin?.temp_basal.map { NSDecimalNumber(decimal: $0) }
-            newOrefDetermination.scheduledBasal = determination.insulin?.scheduled_basal.map { NSDecimalNumber(decimal: $0) }
-            newOrefDetermination.bolus = determination.insulin?.bolus.map { NSDecimalNumber(decimal: $0) }
             newOrefDetermination.smbToDeliver = determination.units.map { NSDecimalNumber(decimal: $0) }
             newOrefDetermination.carbsRequired = Int16(Int(determination.carbsReq ?? 0))
             newOrefDetermination.isUploadedToNS = false
@@ -392,16 +388,16 @@ final class OpenAPS {
             let overrideTargetBG = activeOverrides.first?.target?.decimalValue ?? 0
 
             // Calculate averages for Total Daily Dose (TDD)
-            let totalTDD = historicalTDDData.compactMap { ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue }.reduce(0, +)
+            let totalTDD = historicalTDDData.compactMap { ($0["total"] as? NSDecimalNumber)?.decimalValue }.reduce(0, +)
             let totalDaysCount = max(historicalTDDData.count, 1)
 
             // Fetch recent TDD data for the past two hours
-            let recentTDDData = historicalTDDData.filter { ($0["timestamp"] as? Date ?? Date()) >= twoHoursAgo }
+            let recentTDDData = historicalTDDData.filter { ($0["date"] as? Date ?? Date()) >= twoHoursAgo }
             let recentDataCount = max(recentTDDData.count, 1)
-            let recentTotalTDD = recentTDDData.compactMap { ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue }
+            let recentTotalTDD = recentTDDData.compactMap { ($0["total"] as? NSDecimalNumber)?.decimalValue }
                 .reduce(0, +)
 
-            let currentTDD = historicalTDDData.last?["totalDailyDose"] as? Decimal ?? 0
+            let currentTDD = historicalTDDData.last?["total"] as? Decimal ?? 0
             let averageTDDLastTwoHours = recentTotalTDD / Decimal(recentDataCount)
             let averageTDDLastTenDays = totalTDD / Decimal(totalDaysCount)
             let weightedTDD = weightPercentage * averageTDDLastTwoHours + (1 - weightPercentage) * averageTDDLastTenDays
@@ -410,6 +406,7 @@ final class OpenAPS {
             let oref2Data = Oref2_variables(
                 average_total_data: currentTDD > 0 ? averageTDDLastTenDays : 0,
                 weightedAverage: currentTDD > 0 ? weightedTDD : 1,
+                currentTDD: currentTDD,
                 past2hoursAverage: currentTDD > 0 ? averageTDDLastTwoHours : 0,
                 date: Date(),
                 overridePercentage: overridePercentage,
@@ -831,12 +828,12 @@ extension OpenAPS {
 
     func fetchHistoricalTDDData(from date: Date) throws -> [[String: Any]] {
         try CoreDataStack.shared.fetchEntities(
-            ofType: OrefDetermination.self,
+            ofType: TDDStored.self,
             onContext: context,
-            predicate: NSPredicate(format: "timestamp > %@ AND totalDailyDose > 0", date as NSDate),
-            key: "timestamp",
+            predicate: NSPredicate(format: "date > %@ AND total > 0", date as NSDate),
+            key: "date",
             ascending: true,
-            propertiesToFetch: ["timestamp", "totalDailyDose"]
+            propertiesToFetch: ["date", "total"]
         ) as? [[String: Any]] ?? []
     }
 }

+ 0 - 2
Trio/Sources/APS/Storage/DeterminationStorage.swift

@@ -182,8 +182,6 @@ final class BaseDeterminationStorage: DeterminationStorage, Injectable {
                         reservoir: self.decimal(from: orefDetermination.reservoir),
                         isf: self.decimal(from: orefDetermination.insulinSensitivity),
                         timestamp: orefDetermination.timestamp,
-                        tdd: self.decimal(from: orefDetermination.totalDailyDose),
-                        insulin: nil,
                         current_target: self.decimal(from: orefDetermination.currentTarget),
                         insulinForManualBolus: self.decimal(from: orefDetermination.insulinForManualBolus),
                         manualBolusErrorString: self.decimal(from: orefDetermination.manualBolusErrorString),

+ 1 - 1
Trio/Sources/APS/Storage/TDDStorage.swift

@@ -109,7 +109,7 @@ final class BaseTDDStorage: TDDStorage, Injectable {
         let bolusString = String(format: "%.2f", NSDecimalNumber(decimal: bolus.rounded(toPlaces: 2)).doubleValue)
         let tempBasalString = String(format: "%.2f", NSDecimalNumber(decimal: temp.rounded(toPlaces: 2)).doubleValue)
         let scheduledBasalString = String(format: "%.2f", NSDecimalNumber(decimal: scheduled.rounded(toPlaces: 2)).doubleValue)
-        let weightedAvgString = String(format: "%.2f", NSDecimalNumber(decimal: weighted?.rounded(toPlaces: 2) ?? 0))
+        let weightedAvgString = String(format: "%.2f", NSDecimalNumber(decimal: weighted?.rounded(toPlaces: 2) ?? 0).doubleValue)
         let hoursString = String(format: "%.5f", NSDecimalNumber(decimal: Decimal(hours).truncated(toPlaces: 5)).doubleValue)
 
         debug(.apsManager, """

+ 0 - 20
Trio/Sources/Models/Determination.swift

@@ -19,8 +19,6 @@ struct Determination: JSON, Equatable {
     let reservoir: Decimal?
     var isf: Decimal?
     var timestamp: Date?
-    let tdd: Decimal?
-    let insulin: Insulin?
     var current_target: Decimal?
     let insulinForManualBolus: Decimal?
     let manualBolusErrorString: Decimal?
@@ -40,13 +38,6 @@ struct Predictions: JSON, Equatable {
     let uam: [Int]?
 }
 
-struct Insulin: JSON, Equatable {
-    let TDD: Decimal?
-    let bolus: Decimal?
-    let temp_basal: Decimal?
-    let scheduled_basal: Decimal?
-}
-
 extension Determination {
     private enum CodingKeys: String, CodingKey {
         case id
@@ -67,8 +58,6 @@ extension Determination {
         case reservoir
         case timestamp
         case isf = "ISF"
-        case tdd = "TDD"
-        case insulin
         case current_target
         case insulinForManualBolus
         case manualBolusErrorString
@@ -91,15 +80,6 @@ extension Predictions {
     }
 }
 
-extension Insulin {
-    private enum CodingKeys: String, CodingKey {
-        case TDD
-        case bolus
-        case temp_basal
-        case scheduled_basal
-    }
-}
-
 protocol DeterminationObserver {
     func determinationDidUpdate(_ determination: Determination)
 }

+ 4 - 0
Trio/Sources/Models/Oref2_variables.swift

@@ -2,6 +2,7 @@ import Foundation
 
 struct Oref2_variables: JSON, Equatable {
     var average_total_data: Decimal
+    var currentTDD: Decimal
     var weightedAverage: Decimal
     var past2hoursAverage: Decimal
     var date: Date
@@ -24,6 +25,7 @@ struct Oref2_variables: JSON, Equatable {
     init(
         average_total_data: Decimal,
         weightedAverage: Decimal,
+        currentTDD: Decimal,
         past2hoursAverage: Decimal,
         date: Date,
         overridePercentage: Decimal,
@@ -44,6 +46,7 @@ struct Oref2_variables: JSON, Equatable {
     ) {
         self.average_total_data = average_total_data
         self.weightedAverage = weightedAverage
+        self.currentTDD = currentTDD
         self.past2hoursAverage = past2hoursAverage
         self.date = date
         self.overridePercentage = overridePercentage
@@ -68,6 +71,7 @@ extension Oref2_variables {
     private enum CodingKeys: String, CodingKey {
         case average_total_data
         case weightedAverage
+        case currentTDD
         case past2hoursAverage
         case date
         case overridePercentage

+ 6 - 0
Trio/Sources/Models/TDD.swift

@@ -0,0 +1,6 @@
+import Foundation
+
+struct TDD: Codable, Equatable, Sendable {
+    let totalDailyDose: Decimal?
+    let timestamp: Date?
+}

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

@@ -0,0 +1,52 @@
+import CoreData
+import Foundation
+
+extension Home.StateModel {
+    func setupTDDArray() {
+        Task {
+            do {
+                // Get the NSManagedObjectIDs
+                let tddObjectIds = try await fetchTDDIDs()
+
+                // Get the NSManagedObjects and map them to TDD on the Main Thread
+                try await updateTDDArray(with: tddObjectIds, keyPath: \.fetchedTDDs)
+            } catch {
+                debug(.default, "\(DebuggingIdentifiers.failed) failed to fetch TDDs: \(error.localizedDescription)")
+            }
+        }
+    }
+
+    @MainActor private func updateTDDArray(
+        with IDs: [NSManagedObjectID],
+        keyPath: ReferenceWritableKeyPath<Home.StateModel, [TDD]>
+    ) async throws {
+        let tddObjects: [TDD] = try await CoreDataStack.shared
+            .getNSManagedObject(with: IDs, context: viewContext)
+            .compactMap { managedObject in
+                // Safely extract date and total as optional
+                let timestamp = managedObject.value(forKey: "date") as? Date
+                let totalDailyDose = (managedObject.value(forKey: "total") as? NSNumber)?.decimalValue
+                return TDD(totalDailyDose: totalDailyDose, timestamp: timestamp)
+            }
+        self[keyPath: keyPath] = tddObjects
+    }
+
+    private func fetchTDDIDs() async throws -> [NSManagedObjectID] {
+        let results = try await CoreDataStack.shared.fetchEntitiesAsync(
+            ofType: TDDStored.self,
+            onContext: tddFetchContext,
+            predicate: NSPredicate.predicateForOneDayAgo,
+            key: "date",
+            ascending: false,
+            fetchLimit: 1,
+            propertiesToFetch: ["total", "date", "objectID"]
+        )
+
+        return await tddFetchContext.perform {
+            guard let fetchedResults = results as? [[String: Any]] else {
+                return []
+            }
+            return fetchedResults.compactMap { $0["objectID"] as? NSManagedObjectID }
+        }
+    }
+}

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

@@ -86,6 +86,7 @@ extension Home {
         var fpusFromPersistence: [CarbEntryStored] = []
         var determinationsFromPersistence: [OrefDetermination] = []
         var enactedAndNonEnactedDeterminations: [OrefDetermination] = []
+        var fetchedTDDs: [TDD] = []
         var insulinFromPersistence: [PumpEventStored] = []
         var tempBasals: [PumpEventStored] = []
         var suspensions: [PumpEventStored] = []
@@ -125,6 +126,7 @@ extension Home {
         let carbsFetchContext = CoreDataStack.shared.newTaskContext()
         let fpuFetchContext = CoreDataStack.shared.newTaskContext()
         let determinationFetchContext = CoreDataStack.shared.newTaskContext()
+        let tddFetchContext = CoreDataStack.shared.newTaskContext()
         let pumpHistoryFetchContext = CoreDataStack.shared.newTaskContext()
         let overrideFetchContext = CoreDataStack.shared.newTaskContext()
         let tempTargetFetchContext = CoreDataStack.shared.newTaskContext()
@@ -179,6 +181,9 @@ extension Home {
                         self.setupDeterminationsArray()
                     }
                     group.addTask {
+                        self.setupTDDArray()
+                    }
+                    group.addTask {
                         self.setupInsulinArray()
                     }
                     group.addTask {
@@ -237,6 +242,11 @@ extension Home {
                 self.setupDeterminationsArray()
             }.store(in: &subscriptions)
 
+            coreDataPublisher?.filteredByEntityName("TDDStored").sink { [weak self] _ in
+                guard let self = self else { return }
+                self.setupTDDArray()
+            }.store(in: &subscriptions)
+
             coreDataPublisher?.filteredByEntityName("GlucoseStored").sink { [weak self] _ in
                 guard let self = self else { return }
                 self.setupGlucoseArray()

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

@@ -494,7 +494,7 @@ extension Home {
                         "TDD: " +
                             (
                                 Formatter.decimalFormatterWithTwoFractionDigits
-                                    .string(from: (state.determinationsFromPersistence.first?.totalDailyDose ?? 0) as NSNumber) ??
+                                    .string(from: (state.fetchedTDDs.first?.totalDailyDose ?? 0) as NSNumber) ??
                                     "0"
                             ) +
                             String(localized: " U", comment: "Insulin unit")

+ 10 - 18
Trio/Sources/Modules/Treatments/TreatmentsStateModel.swift

@@ -727,14 +727,11 @@ extension Treatments.StateModel {
             let determinationObjects: [OrefDetermination] = try await CoreDataStack.shared
                 .getNSManagedObject(with: determinationObjectIDs, context: determinationFetchContext)
 
-            return await determinationFetchContext.perform {
-                guard let determinationObject = determinationObjects.first else {
-                    return nil
-                }
-
-                let eventualBG = determinationObject.eventualBG?.intValue
+            let determination = await determinationFetchContext.perform {
+                let determinationObject = determinationObjects.first
+                let eventualBG = determinationObject?.eventualBG?.intValue
 
-                let forecastsSet = determinationObject.forecasts ?? []
+                let forecastsSet = determinationObject?.forecasts ?? []
                 let predictions = Predictions(
                     iob: forecastsSet.extractValues(for: "iob"),
                     zt: forecastsSet.extractValues(for: "zt"),
@@ -747,7 +744,6 @@ extension Treatments.StateModel {
                     reason: "",
                     units: 0,
                     insulinReq: 0,
-                    eventualBG: eventualBG,
                     sensitivityRatio: 0,
                     rate: 0,
                     duration: 0,
@@ -756,23 +752,19 @@ extension Treatments.StateModel {
                     predictions: predictions.isEmpty ? nil : predictions,
                     carbsReq: 0,
                     temp: nil,
-                    bg: 0,
                     reservoir: 0,
-                    isf: 0,
-                    tdd: 0,
-                    insulin: nil,
-                    current_target: 0,
                     insulinForManualBolus: 0,
                     manualBolusErrorString: 0,
-                    minDelta: 0,
-                    expectedDelta: 0,
-                    minGuardBG: 0,
-                    minPredBG: 0,
-                    threshold: 0,
                     carbRatio: 0,
                     received: false
                 )
             }
+
+            guard !determinationObjects.isEmpty else {
+                return nil
+            }
+
+            return determination
         } catch {
             debug(
                 .default,

+ 25 - 10
Trio/Sources/Services/LiveActivity/Data/DataManager.swift

@@ -25,6 +25,7 @@ extension LiveActivityManager {
         }
     }
 
+    // TODO: extract logic or at least rename function appropiately
     func fetchAndMapDetermination() async throws -> DeterminationData? {
         let results = try await CoreDataStack.shared.fetchEntitiesAsync(
             ofType: OrefDetermination.self,
@@ -33,23 +34,37 @@ extension LiveActivityManager {
             key: "deliverAt",
             ascending: false,
             fetchLimit: 1,
-            propertiesToFetch: ["iob", "cob", "totalDailyDose", "currentTarget", "deliverAt"]
+            propertiesToFetch: ["iob", "cob", "currentTarget", "deliverAt"]
+        )
+
+        let tddResults = try await CoreDataStack.shared.fetchEntitiesAsync(
+            ofType: TDDStored.self,
+            onContext: context,
+            predicate: NSPredicate.predicateFor30MinAgo,
+            key: "date",
+            ascending: false,
+            fetchLimit: 1,
+            propertiesToFetch: ["total"]
         )
 
         return try await context.perform {
-            guard let determinationResults = results as? [[String: Any]] else {
+            guard let determinationResults = results as? [[String: Any]], let tddResults = tddResults as? [[String: Any]] else {
                 throw CoreDataError.fetchError(function: #function, file: #file)
             }
 
-            return determinationResults.first.map {
-                DeterminationData(
-                    cob: ($0["cob"] as? Int) ?? 0,
-                    iob: ($0["iob"] as? NSDecimalNumber)?.decimalValue ?? 0,
-                    tdd: ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue ?? 0,
-                    target: ($0["currentTarget"] as? NSDecimalNumber)?.decimalValue ?? 0,
-                    date: $0["deliverAt"] as? Date ?? nil
-                )
+            guard let determination = determinationResults.first else {
+                return nil
             }
+
+            let tddValue = (tddResults.first?["total"] as? NSDecimalNumber)?.decimalValue ?? 0
+
+            return DeterminationData(
+                cob: (determination["cob"] as? Int) ?? 0,
+                iob: (determination["iob"] as? NSDecimalNumber)?.decimalValue ?? 0,
+                tdd: tddValue,
+                target: (determination["currentTarget"] as? NSDecimalNumber)?.decimalValue ?? 0,
+                date: determination["deliverAt"] as? Date ?? nil
+            )
         }
     }
 

+ 3 - 1
oref0_source_version.txt

@@ -1,6 +1,8 @@
-oref0 branch: maxAbsorptionTime - git version: a542ed3
+oref0 branch: removeTDDCalc - git version: 73d6d6c
 
 Last commits:
+73d6d6c webpack for Trio-dev
+5c6ce4b remove TDD calculation
 a542ed3 use guarded maxAbsorptionTime
 4c77757 Revert "reduce dynISF logging"
 1567c76 use variable name maxMealAbsorptionTime

+ 2 - 368
trio-oref/lib/determine-basal/determine-basal.js

@@ -154,9 +154,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     const isfAndCr = oref2_variables.isfAndCr;
     const isf = oref2_variables.isf;
     const cr_ = oref2_variables.cr;
-    const smbIsScheduledOff = oref2_variables.smbIsScheduledOff;
-    const start = oref2_variables.start;
-    var end = oref2_variables.end;
     const smbMinutes = oref2_variables.smbMinutes;
     const uamMinutes = oref2_variables.uamMinutes;
 
@@ -172,21 +169,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     }
 
     // tdd past 24 hours
-    var pumpData = 0;
-    var logtdd = "";
-    var logBasal = "";
-    var logBolus = "";
-    var logTempBasal = "";
-    var dataLog = "";
     var logOutPut = "";
     var tddReason = "";
-    var current = 0;
-    var tdd = 0;
-    var insulin = 0;
-    var tempInsulin = 0;
-    var bolusInsulin = 0;
-    var scheduledBasalInsulin = 0;
-    var quota = 0;
+    var tdd = oref2_variables.currentTDD;
+
     const weightedAverage = oref2_variables.weightedAverage;
     var overrideFactor = 1;
     var sensitivity = profile.sens;
@@ -204,55 +190,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     const weightPercentage = profile.weightPercentage;
     const average_total_data = oref2_variables.average_total_data;
 
-    function addTimeToDate(objDate, _hours) {
-        var ms = objDate.getTime();
-        var add_ms = _hours * 36e5;
-        var newDateObj = new Date(ms + add_ms);
-        return newDateObj;
-    }
-
-    function subtractTimeFromDate(date, hours_) {
-        var ms_ = date.getTime();
-        var add_ms_ = hours_ * 36e5;
-        var new_date = new Date(ms_ - add_ms_);
-        return new_date;
-    }
-
-    function accountForIncrements(insulin) {
-        // If you have not set this to.0.1 in Trio settings, this will be set to 0.05 (Omnipods) in code.
-        var minimalDose = profile.bolus_increment;
-        if (minimalDose != 0.1) {
-            minimalDose = 0.05;
-        }
-        var incrementsRaw = insulin / minimalDose;
-        if (incrementsRaw >= 1) {
-            var incrementsRounded = Math.floor(incrementsRaw);
-            return round(incrementsRounded * minimalDose, 5);
-        } else { return 0; }
-    }
-
-    function makeBaseString(base_timeStamp) {
-        function addZero(i) {
-            if (i < 10) { i = "0" + i }
-            return i;
-        }
-        let hour = addZero(base_timeStamp.getHours());
-        let minutes = addZero(base_timeStamp.getMinutes());
-        let seconds = "00";
-        let string = hour + ":" + minutes + ":" + seconds;
-        return string;
-    }
-
-    function timeDifferenceOfString(string1, string2) {
-        //Base time strings are in "00:00:00" format
-        var time1 = new Date("1/1/1999 " + string1);
-        var time2 = new Date("1/1/1999 " + string2);
-        var ms1 = time1.getTime();
-        var ms2 = time2.getTime();
-        var difference = (ms1 - ms2) / 36e5;
-        return difference;
-    }
-
     // In case the autosens.min/max limits are reversed:
     const minLimitChris = Math.min(profile.autosens_min, profile.autosens_max);
     const maxLimitChris = Math.max(profile.autosens_min, profile.autosens_max);
@@ -263,306 +200,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
         console.log("Dynamic ISF disabled due to current autosens settings");
     }
 
-    function calcScheduledBasalInsulin(lastRealTempTime, addedLastTempTime) {
-        var totalInsulin = 0;
-        var old = addedLastTempTime;
-        var totalDuration = (lastRealTempTime - addedLastTempTime) / 36e5;
-        var basDuration = 0;
-        var totalDurationCheck = totalDuration;
-        var durationCurrentSchedule = 0;
-
-        do {
-
-            if (totalDuration > 0) {
-
-                var baseTime_ = makeBaseString(old);
-
-                //Default basalrate in case none is found...
-                var basalScheduledRate_ = basalprofile[0].rate;
-                for (let m = 0; m < basalprofile.length; m++) {
-
-                    var timeToTest = basalprofile[m].start;
-
-                    if (baseTime_ == timeToTest) {
-
-                        if (m + 1 < basalprofile.length) {
-                            let end = basalprofile[m+1].start;
-                            let start = basalprofile[m].start;
-
-                            durationCurrentSchedule = timeDifferenceOfString(end, start);
-
-                            if (totalDuration >= durationCurrentSchedule) {
-                                basDuration = durationCurrentSchedule;
-                            } else if (totalDuration < durationCurrentSchedule) {
-                                basDuration = totalDuration;
-                            }
-
-                        }
-                        else if (m + 1 == basalprofile.length) {
-                            let end = basalprofile[0].start;
-                            let start = basalprofile[m].start;
-                            // First schedule is 00:00:00. Changed places of start and end here.
-                            durationCurrentSchedule = 24 - (timeDifferenceOfString(start, end));
-
-                            if (totalDuration >= durationCurrentSchedule) {
-                                basDuration = durationCurrentSchedule;
-                            } else if (totalDuration < durationCurrentSchedule) {
-                                basDuration = totalDuration;
-                            }
-
-                        }
-                        basalScheduledRate_ = basalprofile[m].rate;
-                        totalInsulin += accountForIncrements(basalScheduledRate_ * basDuration);
-                        totalDuration -= basDuration;
-                        console.log("Dynamic ratios log: scheduled insulin added: " + accountForIncrements(basalScheduledRate_ * basDuration) + " U. Bas duration: " + basDuration.toPrecision(3) + " h. Base Rate: " + basalScheduledRate_ + " U/h" + ". Time :" + baseTime_);
-                        // Move clock to new date
-                        old = addTimeToDate(old, basDuration);
-                    }
-
-                    else if (baseTime_ > timeToTest) {
-
-                        if (m + 1 < basalprofile.length) {
-                            var timeToTest2 = basalprofile[m+1].start
-
-                            if (baseTime_ < timeToTest2) {
-
-                               //  durationCurrentSchedule = timeDifferenceOfString(end, start);
-                               durationCurrentSchedule = timeDifferenceOfString(timeToTest2, baseTime_);
-
-                                if (totalDuration >= durationCurrentSchedule) {
-                                    basDuration = durationCurrentSchedule;
-                                } else if (totalDuration < durationCurrentSchedule) {
-                                    basDuration = totalDuration;
-                                }
-
-                                basalScheduledRate_ = basalprofile[m].rate;
-                                totalInsulin += accountForIncrements(basalScheduledRate_ * basDuration);
-                                totalDuration -= basDuration;
-                                console.log("Dynamic ratios log: scheduled insulin added: " + accountForIncrements(basalScheduledRate_ * basDuration) + " U. Bas duration: " + basDuration.toPrecision(3) + " h. Base Rate: " + basalScheduledRate_ + " U/h" + ". Time :" + baseTime_);
-                                // Move clock to new date
-                                old = addTimeToDate(old, basDuration);
-                            }
-                        }
-
-                        else if (m == basalprofile.length - 1) {
-                            // let start = basalprofile[m].start;
-                            let start = baseTime_;
-                            // First schedule is 00:00:00. Changed places of start and end here.
-                            durationCurrentSchedule = timeDifferenceOfString("23:59:59", start);
-
-                            if (totalDuration >= durationCurrentSchedule) {
-                                basDuration = durationCurrentSchedule;
-                            } else if (totalDuration < durationCurrentSchedule) {
-                                basDuration = totalDuration;
-                            }
-
-                            basalScheduledRate_ = basalprofile[m].rate;
-                            totalInsulin += accountForIncrements(basalScheduledRate_ * basDuration);
-                            totalDuration -= basDuration;
-                            console.log("Dynamic ratios log: scheduled insulin added: " + accountForIncrements(basalScheduledRate_ * basDuration) + " U. Bas duration: " + basDuration.toPrecision(3) + " h. Base Rate: " + basalScheduledRate_ + " U/h" + ". Time :" + baseTime_);
-                            // Move clock to new date
-                            old = addTimeToDate(old, basDuration);
-                        }
-                    }
-                }
-            }
-            //totalDurationCheck to avoid infinite loop
-        } while (totalDuration > 0 && totalDuration < totalDurationCheck);
-
-        // amount of insulin according to pump basal rate schedules
-        return totalInsulin;
-    }
-
-    // Check that there is enough pump history data (>21 hours) for tdd calculation. Estimate the missing hours (24-pumpData) using hours with scheduled basal rates. Not perfect, but sometimes the
-    // pump history in FAX is only 22-23.5 hours, even when you've been looping with FAX for many days. This is to reduce the error from just using pump history as data source as much as possible.
-    // AT basal rates are not used for this estimation, instead the basal rates in pump settings.
-
-    // Check for empty pump history (new FAX loopers). If empty: don't use dynamic settings!
-
-    if (!pumphistory.length) {
-        console.log("Pumphistory is empty!");
-        dynISFenabled = false;
-        enableDynamicCR = false;
-    } else {
-        let phLastEntry = pumphistory.length - 1;
-        var endDate = new Date(pumphistory[phLastEntry].timestamp);
-        var startDate = new Date(pumphistory[0].timestamp);
-
-        // If latest pump event is a temp basal
-        if (pumphistory[0]._type == "TempBasalDuration") {
-            startDate = new Date();
-        }
-        pumpData = (startDate - endDate) / 36e5;
-
-        if (pumpData < 23.9 && pumpData > 21) {
-            var missingHours = 24 - pumpData;
-            // Makes new end date for a total time duration of exakt 24 hour.
-            var endDate_ = subtractTimeFromDate(endDate, missingHours);
-            // endDate - endDate_ = missingHours
-            scheduledBasalInsulin = calcScheduledBasalInsulin(endDate, endDate_);
-            dataLog = "24 hours of data is required for an accurate tdd calculation. Currently only " + pumpData.toPrecision(3) + " hours of pump history data are available. Using your pump scheduled basals to fill in the missing hours. Scheduled basals added: " + scheduledBasalInsulin.toPrecision(5) + " U. ";
-        } else if (pumpData < 21) {
-            dynISFenabled = false;
-            enableDynamicCR = false;
-        } else {  dataLog = ""; }
-    }
-
-    // Calculate tdd ----------------------------------------------------------------------
-
-    //Bolus:
-    for (let i = 0; i < pumphistory.length; i++) {
-        if (pumphistory[i]._type == "Bolus") {
-            bolusInsulin += pumphistory[i].amount;
-        }
-    }
-
-    // Temp basals:
-    for (let j = 1; j < pumphistory.length; j++) {
-        if (pumphistory[j]._type == "TempBasal" && pumphistory[j].rate > 0) {
-            current = j;
-            quota = pumphistory[j].rate;
-            var duration = pumphistory[j-1]['duration (min)'] / 60;
-            var origDur = duration;
-            var pastTime = new Date(pumphistory[j-1].timestamp);
-            var morePresentTime = new Date(pastTime);
-            var substractTimeOfRewind = 0;
-            // If temp basal hasn't yet ended, use now as end date for calculation
-            do {
-                j--;
-                if (j == 0) {
-                    morePresentTime =  new Date();
-                    break;
-                }
-                else if (pumphistory[j]._type == "TempBasal" || pumphistory[j]._type == "PumpSuspend")  {
-                    morePresentTime = new Date(pumphistory[j].timestamp);
-                    break;
-                }
-                // During the time the Medtronic pumps are rewinded and primed, this duration of suspened insulin delivery needs to be accounted for.
-                var pp = j-2;
-                if (pp >= 0) {
-                    if (pumphistory[pp]._type == "Rewind") {
-                        let rewindTimestamp = pumphistory[pp].timestamp;
-                        // There can be several Prime events
-                        while (pp - 1 >= 0) {
-                            pp -= 1;
-                            if (pumphistory[pp]._type == "Prime") {
-                                substractTimeOfRewind = (pumphistory[pp].timestamp - rewindTimestamp) / 36e5;
-                            } else { break }
-                        }
-
-                        // If Medtronic user forgets to insert infusion set
-                        if (substractTimeOfRewind >= duration) {
-                            morePresentTime = new Date(rewindTimestamp);
-                            substractTimeOfRewind = 0;
-                        }
-                    }
-                }
-            } while (j > 0);
-
-            var diff = (morePresentTime - pastTime) / 36e5;
-            if (diff < origDur) {
-                duration = diff;
-            }
-
-            insulin = quota * (duration - substractTimeOfRewind);
-            tempInsulin += accountForIncrements(insulin);
-            j = current;
-        }
-    }
-    //  Check and count for when basals are delivered with a scheduled basal rate.
-    //  1. Check for 0 temp basals with 0 min duration. This is for when ending a manual temp basal and (perhaps) continuing in open loop for a while.
-    //  2. Check for temp basals that completes. This is for when disconnected from link/iphone, or when in open loop.
-    //  3. Account for a punp suspension. This is for when pod screams or when MDT or pod is manually suspended.
-    //  4. Account for a pump resume (in case pump/cgm is disconnected before next loop).
-    //  To do: are there more circumstances when scheduled basal rates are used? Do we need to care about "Prime" and "Rewind" with MDT pumps?
-    //
-    for (let k = 0; k < pumphistory.length; k++) {
-        // Check for 0 temp basals with 0 min duration.
-        insulin = 0;
-        if (pumphistory[k]['duration (min)'] == 0 || pumphistory[k]._type == "PumpResume") {
-            let time1 = new Date(pumphistory[k].timestamp);
-            let time2 = new Date(time1);
-            let l = k;
-            do {
-                if (l > 0) {
-                    --l;
-                    if (pumphistory[l]._type == "TempBasal") {
-                        time2 = new Date(pumphistory[l].timestamp);
-                        break;
-                    }
-                }
-            } while (l > 0);
-            // duration of current scheduled basal in h
-            let basDuration = (time2 - time1) / 36e5;
-
-            if (basDuration > 0) {
-                scheduledBasalInsulin += calcScheduledBasalInsulin(time2, time1);
-            }
-        }
-    }
-
-    // Check for temp basals that completes
-    for (let n = pumphistory.length -1; n > 0; n--) {
-        if (pumphistory[n]._type == "TempBasalDuration") {
-            // duration in hours
-            let oldBasalDuration = pumphistory[n]['duration (min)'] / 60;
-            // time of old temp basal
-            let oldTime = new Date(pumphistory[n].timestamp);
-            var newTime = new Date(oldTime);
-            let o = n;
-            do {
-                --o;
-                if (o >= 0) {
-                    if (pumphistory[o]._type == "TempBasal" || pumphistory[o]._type == "PumpSuspend") {
-                        // time of next (new) temp basal or a pump suspension
-                        newTime = new Date(pumphistory[o].timestamp);
-                        break;
-                    }
-                }
-            } while (o > 0);
-
-            // When latest temp basal is index 0 in pump history
-            if (n == 0 && pumphistory[0]._type == "TempBasalDuration") {
-                newTime = new Date();
-                oldBasalDuration = pumphistory[n]['duration (min)'] / 60;
-            }
-
-            let tempBasalTimeDifference = (newTime - oldTime) / 36e5;
-            let timeOfbasal = tempBasalTimeDifference - oldBasalDuration;
-            // if duration of scheduled basal is more than 0
-            if (timeOfbasal > 0) {
-                // Timestamp after completed temp basal
-                let timeOfScheduledBasal =  addTimeToDate(oldTime, oldBasalDuration);
-                scheduledBasalInsulin += calcScheduledBasalInsulin(newTime, timeOfScheduledBasal);
-            }
-        }
-    }
-
-    tdd = bolusInsulin + tempInsulin + scheduledBasalInsulin;
-
-
-    var insulin_ = {
-        TDD: round(tdd, 5),
-        bolus: round(bolusInsulin, 5),
-        temp_basal: round(tempInsulin, 5),
-        scheduled_basal: round(scheduledBasalInsulin, 5)
-    }
-
-    if (pumpData > 21) {
-        logBolus = ". Bolus insulin: " + bolusInsulin.toPrecision(5) + " U";
-        logTempBasal = ". Temporary basal insulin: " + tempInsulin.toPrecision(5) + " U";
-        logBasal = ". Insulin with scheduled basal rate: " + scheduledBasalInsulin.toPrecision(5) + " U";
-        logtdd = " TDD past 24h is: " + tdd.toPrecision(5) + " U";
-        logOutPut = dataLog + logtdd + logBolus + logTempBasal + logBasal;
-
-        tddReason = ", TDD: " + round(tdd,2) + " U, " + round(bolusInsulin/tdd*100,0) + "% Bolus " + round((tempInsulin+scheduledBasalInsulin)/tdd*100,0) +  "% Basal";
-
-    } else { tddReason = ", TDD: Not enough pumpData (< 21h)"; }
-
-    var tdd_before = tdd;
-
-    // -------------------- END OF TDD ----------------------------------------------------
-
     // Dynamic ratios
     const BG = glucose_status.glucose;
     const useDynamicCR = preferences.enableDynamicCR;
@@ -1136,8 +773,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
         , 'deliverAt' : deliverAt // The time at which the microbolus should be delivered
         , 'sensitivityRatio' : sensitivityRatio
         , 'CR' : round(carbRatio, 1)
-        , 'TDD': tdd_before
-        , 'insulin': insulin_
         , 'current_target': target_bg
         , 'insulinForManualBolus': insulinForManualBolus
         , 'manualBolusErrorString': manualBolusErrorString
@@ -1553,7 +1188,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     rT.ISF=convert_bg(sens, profile);
     rT.CR=round(carbRatio, 1);
     rT.target_bg=convert_bg(target_bg, profile);
-    rT.TDD=round(tdd_before, 2);
     rT.current_target=round(target_bg, 0);
 
     var cr_log = rT.CR;