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

Merge branch 'core-data-sync-trio' of github.com:dnzxy/Trio-dev into add-watch-contact

Deniz Cengiz 1 год назад
Родитель
Сommit
dc908c3358

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
FreeAPS/Resources/javascript/bundle/determine-basal.js


+ 1 - 1
FreeAPS/Sources/APS/FetchGlucoseManager.swift

@@ -198,7 +198,7 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
             key: "date",
             ascending: false,
             fetchLimit: 6
-        )
+        ) as? [GlucoseStored]
     }
 
     private func processGlucose() -> [BloodGlucose] {

+ 2 - 2
FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift

@@ -915,7 +915,7 @@ extension OpenAPS {
             key: "date",
             ascending: false,
             fetchLimit: 1
-        )
+        ) as? [TempTargetStored] ?? []
     }
 
     func fetchActiveOverrides() -> [OverrideStored] {
@@ -926,7 +926,7 @@ extension OpenAPS {
             key: "date",
             ascending: false,
             fetchLimit: 1
-        )
+        ) as? [OverrideStored] ?? []
     }
 
     func fetchHistoricalTDDData(from date: Date) -> [[String: Any]] {

+ 2 - 2
FreeAPS/Sources/APS/Storage/GlucoseStorage.swift

@@ -264,14 +264,14 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
 
     func fetchLatestGlucose() -> GlucoseStored? {
         let predicate = NSPredicate.predicateFor20MinAgo
-        return CoreDataStack.shared.fetchEntities(
+        return (CoreDataStack.shared.fetchEntities(
             ofType: GlucoseStored.self,
             onContext: coredataContext,
             predicate: predicate,
             key: "date",
             ascending: false,
             fetchLimit: 1
-        ).first
+        ) as? [GlucoseStored] ?? []).first
     }
 
     // Fetch glucose that is not uploaded to Nightscout yet

+ 1 - 1
FreeAPS/Sources/APS/Storage/PumpHistoryStorage.swift

@@ -60,7 +60,7 @@ final class BasePumpHistoryStorage: PumpHistoryStorage, Injectable {
                         key: "timestamp",
                         ascending: false,
                         batchSize: 50
-                    )
+                    ) as? [PumpEventStored] ?? []
 
                     switch event.type {
                     case .bolus:

+ 24 - 23
FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift

@@ -199,6 +199,7 @@ extension CGM {
                 .onAppear(perform: configureView)
                 .navigationTitle("CGM")
                 .navigationBarTitleDisplayMode(.automatic)
+                .navigationBarItems(leading: displayClose ? Button("Close", action: state.hideModal) : nil)
                 .sheet(isPresented: $shouldDisplayHint) {
                     SettingInputHintView(
                         hintDetent: $hintDetent,
@@ -208,29 +209,6 @@ extension CGM {
                         sheetTitle: "Help"
                     )
                 }
-                .sheet(isPresented: $setupCGM) {
-                    if let cgmFetchManager = state.cgmManager,
-                       let cgmManager = cgmFetchManager.cgmManager,
-                       state.cgmCurrent.type == cgmFetchManager.cgmGlucoseSourceType,
-                       state.cgmCurrent.id == cgmFetchManager.cgmGlucosePluginId
-                    {
-                        CGMSettingsView(
-                            cgmManager: cgmManager,
-                            bluetoothManager: state.provider.apsManager.bluetoothManager!,
-                            unit: state.settingsManager.settings.units,
-                            completionDelegate: state
-                        )
-                    } else {
-                        CGMSetupView(
-                            CGMType: state.cgmCurrent,
-                            bluetoothManager: state.provider.apsManager.bluetoothManager!,
-                            unit: state.settingsManager.settings.units,
-                            completionDelegate: state,
-                            setupDelegate: state,
-                            pluginCGMManager: self.state.pluginCGMManager
-                        )
-                    }
-                }
                 .onChange(of: setupCGM) { _, setupCGM in
                     state.setupCGM = setupCGM
                 }
@@ -239,6 +217,29 @@ extension CGM {
                 }
                 .screenNavigation(self)
             }
+            .sheet(isPresented: $setupCGM) {
+                if let cgmFetchManager = state.cgmManager,
+                   let cgmManager = cgmFetchManager.cgmManager,
+                   state.cgmCurrent.type == cgmFetchManager.cgmGlucoseSourceType,
+                   state.cgmCurrent.id == cgmFetchManager.cgmGlucosePluginId
+                {
+                    CGMSettingsView(
+                        cgmManager: cgmManager,
+                        bluetoothManager: state.provider.apsManager.bluetoothManager!,
+                        unit: state.settingsManager.settings.units,
+                        completionDelegate: state
+                    )
+                } else {
+                    CGMSetupView(
+                        CGMType: state.cgmCurrent,
+                        bluetoothManager: state.provider.apsManager.bluetoothManager!,
+                        unit: state.settingsManager.settings.units,
+                        completionDelegate: state,
+                        setupDelegate: state,
+                        pluginCGMManager: self.state.pluginCGMManager
+                    )
+                }
+            }
         }
     }
 }

+ 18 - 18
FreeAPS/Sources/Modules/PumpConfig/View/PumpConfigRootView.swift

@@ -81,24 +81,6 @@ extension PumpConfig {
                 .navigationTitle("Insulin Pump")
                 .navigationBarTitleDisplayMode(.automatic)
                 .navigationBarItems(leading: displayClose ? Button("Close", action: state.hideModal) : nil)
-                .sheet(isPresented: $state.setupPump) {
-                    if let pumpManager = state.provider.apsManager.pumpManager {
-                        PumpSettingsView(
-                            pumpManager: pumpManager,
-                            bluetoothManager: state.provider.apsManager.bluetoothManager!,
-                            completionDelegate: state,
-                            setupDelegate: state
-                        )
-                    } else {
-                        PumpSetupView(
-                            pumpType: state.setupPumpType,
-                            pumpInitialSettings: state.initialSettings,
-                            bluetoothManager: state.provider.apsManager.bluetoothManager!,
-                            completionDelegate: state,
-                            setupDelegate: state
-                        )
-                    }
-                }
                 .sheet(isPresented: $shouldDisplayHint) {
                     SettingInputHintView(
                         hintDetent: $hintDetent,
@@ -115,6 +97,24 @@ extension PumpConfig {
                     Button("Pump Simulator") { state.addPump(.simulator) }
                 } message: { Text("Select Pump Model") }
             }
+            .sheet(isPresented: $state.setupPump) {
+                if let pumpManager = state.provider.apsManager.pumpManager {
+                    PumpSettingsView(
+                        pumpManager: pumpManager,
+                        bluetoothManager: state.provider.apsManager.bluetoothManager!,
+                        completionDelegate: state,
+                        setupDelegate: state
+                    )
+                } else {
+                    PumpSetupView(
+                        pumpType: state.setupPumpType,
+                        pumpInitialSettings: state.initialSettings,
+                        bluetoothManager: state.provider.apsManager.bluetoothManager!,
+                        completionDelegate: state,
+                        setupDelegate: state
+                    )
+                }
+            }
         }
     }
 }

+ 72 - 54
FreeAPS/Sources/Modules/Stat/View/ChartsView.swift

@@ -23,15 +23,15 @@ struct ChartsView: View {
         Rectangle().fill(.cyan.opacity(0.2)).frame(maxHeight: 3)
         if standing {
             VStack {
-                tirChart
+                tirChartLaying
                 Rectangle().fill(.cyan.opacity(0.2)).frame(maxHeight: 3)
                 groupedGlucoseStatsLaying
             }
         } else {
             HStack(spacing: 20) {
-                standingTIRchart
-                groupedGlucose
-            }
+                tirChartStanding
+                groupedGlucoseStatsStanding
+            }.padding(.horizontal, 10)
         }
     }
 
@@ -90,17 +90,18 @@ struct ChartsView: View {
         }
     }
 
-    var tirChart: some View {
+    var tirChartLaying: some View {
         let fetched = tir()
         let low = lowLimit * conversionFactor
         let high = highLimit * conversionFactor
+        let fraction = units == .mgdL ? 0 : 1
 
         let data: [ShapeModel] = [
             .init(
                 type: NSLocalizedString(
                     "Low",
                     comment: ""
-                ) + " (<\(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))",
+                ) + " (<\(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))",
                 percent: fetched[0].decimal
             ),
             .init(type: NSLocalizedString("In Range", comment: ""), percent: fetched[1].decimal),
@@ -108,36 +109,40 @@ struct ChartsView: View {
                 type: NSLocalizedString(
                     "High",
                     comment: ""
-                ) + " (>\(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))",
+                ) + " (>\(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))",
                 percent: fetched[2].decimal
             )
         ]
-        return Chart(data) { shape in
-            BarMark(
-                x: .value("TIR", shape.percent)
-            )
-            .foregroundStyle(by: .value("Group", shape.type))
-            .annotation(position: .top, alignment: .center) {
-                Text(
-                    "\(shape.percent, format: .number.precision(.fractionLength(0))) %"
-                ).font(.footnote).foregroundColor(.secondary)
+        return VStack {
+            Chart(data) { shape in
+                BarMark(
+                    x: .value("TIR", shape.percent)
+                )
+                .foregroundStyle(by: .value("Group", shape.type))
+                .annotation(position: .top, alignment: .center) {
+                    Text(
+                        "\(shape.percent, format: .number.precision(.fractionLength(0 ... 1))) %"
+                    ).font(.footnote).foregroundColor(.secondary)
+                }
             }
+            .chartXAxis(.hidden)
+            .chartForegroundStyleScale([
+                NSLocalizedString(
+                    "Low",
+                    comment: ""
+                ) + " (<\(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))": .red,
+                NSLocalizedString("In Range", comment: ""): .green,
+                NSLocalizedString(
+                    "High",
+                    comment: ""
+                ) + " (>\(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))": .orange
+            ]).frame(maxHeight: 25)
         }
-        .chartXAxis(.hidden)
-        .chartForegroundStyleScale([
-            NSLocalizedString(
-                "Low",
-                comment: ""
-            ) + " (<\(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))": .red,
-            NSLocalizedString("In Range", comment: ""): .green,
-            NSLocalizedString(
-                "High",
-                comment: ""
-            ) + " (>\(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))": .orange
-        ]).frame(maxHeight: 25)
+        .frame(maxWidth: .infinity, alignment: .center) // Align the entire VStack to center
+        .padding(.horizontal, 5)
     }
 
-    var standingTIRchart: some View {
+    var tirChartStanding: some View {
         let fetched = tir()
         let low = lowLimit * conversionFactor
         let high = highLimit * conversionFactor
@@ -147,7 +152,7 @@ struct ChartsView: View {
                 type: NSLocalizedString(
                     "Low",
                     comment: ""
-                ) + " (< \(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))",
+                ) + " (< \(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))",
                 percent: fetched[0].decimal
             ),
             .init(
@@ -158,7 +163,7 @@ struct ChartsView: View {
                 type: NSLocalizedString(
                     "High",
                     comment: ""
-                ) + " (> \(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))",
+                ) + " (> \(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))",
                 percent: fetched[2].decimal
             )
         ]
@@ -169,7 +174,7 @@ struct ChartsView: View {
             )
             .foregroundStyle(by: .value("Group", shape.type))
             .annotation(position: shape.percent > 19 ? .overlay : .automatic, alignment: .center) {
-                Text(shape.percent == 0 ? "" : "\(shape.percent, format: .number.precision(.fractionLength(0)))")
+                Text(shape.percent == 0 ? "" : "\(shape.percent, format: .number.precision(.fractionLength(0 ... 1)))")
             }
         }
         .chartXAxis(.hidden)
@@ -182,39 +187,48 @@ struct ChartsView: View {
             NSLocalizedString(
                 "Low",
                 comment: ""
-            ) + " (< \(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))": .red,
+            ) + " (< \(low.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))": .red,
             "\(low.formatted(.number.precision(.fractionLength(fraction)))) - \(high.formatted(.number.precision(.fractionLength(fraction))))": .green,
             NSLocalizedString(
                 "High",
                 comment: ""
-            ) + " (> \(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))))": .orange
+            ) + " (> \(high.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fraction)))))": .orange
         ])
     }
 
-    var groupedGlucose: some View {
-        VStack(alignment: .leading, spacing: 20) {
+    var groupedGlucoseStatsStanding: some View {
+        VStack(alignment: .leading, spacing: 15) {
             let mapGlucose = glucose.compactMap({ each in each.glucose })
             if !mapGlucose.isEmpty {
                 let mapGlucoseAcuteLow = mapGlucose.filter({ $0 < Int16(3.3 / 0.0555) })
                 let mapGlucoseHigh = mapGlucose.filter({ $0 > Int16(11 / 0.0555) })
                 let mapGlucoseNormal = mapGlucose.filter({ $0 > Int16(3.8 / 0.0555) && $0 < Int16(7.9 / 0.0555) })
                 HStack {
-                    let value = Double(mapGlucoseHigh.count * 100 / mapGlucose.count)
-                    Text(units == .mmolL ? ">  11  " : ">  198 ").foregroundColor(.secondary)
-                    Text(value.formatted()).foregroundColor(.orange)
-                    Text("%").foregroundColor(.secondary)
+                    let value = 100.0 * Double(mapGlucoseHigh.count) / Double(mapGlucose.count)
+                    Text(units == .mmolL ? ">  11  " : ">  198 ")
+                        .frame(width: 45, alignment: .leading)
+                        .foregroundColor(.secondary)
+                    Text("\(value.formatted(.number.precision(.fractionLength(0 ... 1)))) %")
+                        .frame(width: 45, alignment: .trailing)
+                        .foregroundColor(.orange)
                 }.font(.caption)
                 HStack {
-                    let value = Double(mapGlucoseNormal.count * 100 / mapGlucose.count)
-                    Text(units == .mmolL ? "3.9-7.8" : "70-140").foregroundColor(.secondary)
-                    Text(value.formatted()).foregroundColor(.green)
-                    Text("%").foregroundColor(.secondary)
+                    let value = 100.0 * Double(mapGlucoseNormal.count) / Double(mapGlucose.count)
+                    Text(units == .mmolL ? "3.9-7.8" : "70-140")
+                        .frame(width: 45, alignment: .leading)
+                        .foregroundColor(.secondary)
+                    Text("\(value.formatted(.number.precision(.fractionLength(0 ... 1)))) %")
+                        .frame(width: 45, alignment: .trailing)
+                        .foregroundColor(.green)
                 }.font(.caption)
                 HStack {
-                    let value = Double(mapGlucoseAcuteLow.count * 100 / mapGlucose.count)
-                    Text(units == .mmolL ? "<  3.3 " : "<  59  ").foregroundColor(.secondary)
-                    Text(value.formatted()).foregroundColor(.red)
-                    Text("%").foregroundColor(.secondary)
+                    let value = 100.0 * Double(mapGlucoseAcuteLow.count) / Double(mapGlucose.count)
+                    Text(units == .mmolL ? "<  3.3 " : "<  59  ")
+                        .frame(width: 45, alignment: .leading)
+                        .foregroundColor(.secondary)
+                    Text("\(value.formatted(.number.precision(.fractionLength(0 ... 1)))) %")
+                        .frame(width: 45, alignment: .trailing)
+                        .foregroundColor(.red)
                 }.font(.caption)
             }
         }
@@ -227,26 +241,30 @@ struct ChartsView: View {
                 let mapGlucoseLow = mapGlucose.filter({ $0 < Int16(3.3 / 0.0555) })
                 let mapGlucoseNormal = mapGlucose.filter({ $0 > Int16(3.8 / 0.0555) && $0 < Int16(7.9 / 0.0555) })
                 let mapGlucoseAcuteHigh = mapGlucose.filter({ $0 > Int16(11 / 0.0555) })
+                Spacer()
                 HStack {
-                    let value = Double(mapGlucoseLow.count * 100 / mapGlucose.count)
+                    let value = 100.0 * Double(mapGlucoseLow.count) / Double(mapGlucose.count)
                     Text(units == .mmolL ? "< 3.3" : "< 59").font(.caption2).foregroundColor(.secondary)
-                    Text(value.formatted()).font(.caption).foregroundColor(value == 0 ? .green : .red)
+                    Text(value.formatted(.number.precision(.fractionLength(0 ... 1)))).font(.caption)
+                        .foregroundColor(value == 0 ? .green : .red)
                     Text("%").font(.caption)
                 }
                 Spacer()
                 HStack {
-                    let value = Double(mapGlucoseNormal.count * 100 / mapGlucose.count)
+                    let value = 100.0 * Double(mapGlucoseNormal.count) / Double(mapGlucose.count)
                     Text(units == .mmolL ? "3.9-7.8" : "70-140").foregroundColor(.secondary)
-                    Text(value.formatted()).foregroundColor(.green)
+                    Text(value.formatted(.number.precision(.fractionLength(0 ... 1)))).foregroundColor(.green)
                     Text("%").foregroundColor(.secondary)
                 }.font(.caption)
                 Spacer()
                 HStack {
-                    let value = Double(mapGlucoseAcuteHigh.count * 100 / mapGlucose.count)
+                    let value = 100.0 * Double(mapGlucoseAcuteHigh.count) / Double(mapGlucose.count)
                     Text(units == .mmolL ? "> 11.0" : "> 198").font(.caption).foregroundColor(.secondary)
-                    Text(value.formatted()).font(.caption).foregroundColor(value == 0 ? .green : .orange)
+                    Text(value.formatted(.number.precision(.fractionLength(0 ... 1)))).font(.caption)
+                        .foregroundColor(value == 0 ? .green : .orange)
                     Text("%").font(.caption)
                 }
+                Spacer()
             }
         }
     }

+ 1 - 1
FreeAPS/Sources/Services/Network/Nightscout/NightscoutManager.swift

@@ -192,7 +192,7 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
             .sink { [weak self] _ in
                 guard let self = self else { return }
                 Task {
-                    await self.uploadOverrides()
+                    await self.uploadTempTargets()
 
                     // Post a notification indicating that the upload has finished and that we can end the background task in the TempTargetPresetsIntentRequest
                     Foundation.NotificationCenter.default.post(name: .didUpdateTempTargetConfiguration, object: nil)

+ 3 - 2
FreeAPS/Sources/Shortcuts/State/StateIntentRequest.swift

@@ -68,7 +68,7 @@ final class StateIntentRequest: BaseIntentsRequest {
                 key: "date",
                 ascending: false,
                 fetchLimit: 2
-            )
+            ) as? [GlucoseStored] ?? []
 
             guard let lastValue = results.first else { throw StateIntentError.NoBG }
 
@@ -109,7 +109,8 @@ final class StateIntentRequest: BaseIntentsRequest {
             key: "deliverAt",
             ascending: false,
             fetchLimit: 1
-        )
+        ) as? [OrefDetermination] ?? []
+
         let iobAsDouble = Double(truncating: (results.first?.iob ?? 0.0) as NSNumber)
         let cobAsDouble = Double(truncating: (results.first?.cob ?? 0) as NSNumber)
 

+ 3 - 3
FreeAPS/Sources/Shortcuts/TempPresets/ApplyTempPresetIntent.swift

@@ -54,7 +54,7 @@ struct ApplyTempPresetIntent: AppIntent {
             let displayName: String = presetToApply.name
             if confirmBeforeApplying {
                 try await requestConfirmation(
-                    result: .result(dialog: "Confirm to apply temporary target '\(displayName)'")
+                    result: .result(dialog: "Confirm to apply Temporary Target '\(displayName)'")
                 )
             }
 
@@ -62,7 +62,7 @@ struct ApplyTempPresetIntent: AppIntent {
                 return .result(
                     dialog: IntentDialog(
                         LocalizedStringResource(
-                            "TempTarget '\(presetToApply.name)' applied",
+                            "Temporary Target '\(presetToApply.name)' applied",
                             table: "ShortcutsDetail"
                         )
                     )
@@ -71,7 +71,7 @@ struct ApplyTempPresetIntent: AppIntent {
                 return .result(
                     dialog: IntentDialog(
                         LocalizedStringResource(
-                            "TempTarget '\(presetToApply.name)' failed",
+                            "Temporary Target '\(presetToApply.name)' failed",
                             table: "ShortcutsDetail"
                         )
                     )

+ 20 - 0
FreeAPS/Sources/Shortcuts/TempPresets/TempPresetsIntentRequest.swift

@@ -132,6 +132,26 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
 
                 // Await the notification
                 print("Waiting for notification...")
+
+                guard let tempTargetDate = tempTargetObject.date, let tempTarget = tempTargetObject.target,
+                      let tempTargetDuration = tempTargetObject.duration else { return false }
+
+                let tempTargetToStoreAsJSON = TempTarget(
+                    name: tempTargetObject.name,
+                    createdAt: tempTargetDate,
+                    targetTop: tempTarget as Decimal,
+                    targetBottom: tempTarget as Decimal,
+                    duration: tempTargetDuration as Decimal,
+                    enteredBy: TempTarget.local,
+                    reason: TempTarget.custom,
+                    isPreset: tempTargetObject.isPreset,
+                    enabled: tempTargetObject.enabled,
+                    halfBasalTarget: tempTargetObject.halfBasalTarget as Decimal?
+                )
+
+                // Save the temp targets to JSON so that they get used by oref
+                tempTargetsStorage.saveTempTargetsToStorage([tempTargetToStoreAsJSON])
+
                 await awaitNotification(.didUpdateTempTargetConfiguration)
                 print("Notification received, continuing...")
 

+ 13 - 17
Model/CoreDataStack.swift

@@ -313,8 +313,8 @@ extension CoreDataStack {
         propertiesToFetch: [String]? = nil,
         callingFunction: String = #function,
         callingClass: String = #fileID
-    ) -> [T] {
-        let request = NSFetchRequest<T>(entityName: String(describing: type))
+    ) -> [Any] {
+        let request = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: type))
         request.sortDescriptors = [NSSortDescriptor(key: key, ascending: ascending)]
         request.predicate = predicate
         if let limit = fetchLimit {
@@ -323,9 +323,9 @@ extension CoreDataStack {
         if let batchSize = batchSize {
             request.fetchBatchSize = batchSize
         }
-        if let propertiesTofetch = propertiesToFetch {
-            request.propertiesToFetch = propertiesTofetch
-            request.resultType = .managedObjectResultType
+        if let propertiesToFetch = propertiesToFetch {
+            request.propertiesToFetch = propertiesToFetch
+            request.resultType = .dictionaryResultType
         } else {
             request.resultType = .managedObjectResultType
         }
@@ -333,23 +333,22 @@ extension CoreDataStack {
         context.name = "fetchContext"
         context.transactionAuthor = "fetchEntities"
 
-        var result: [T]?
-
         /// we need to ensure that the fetch immediately returns a value as long as the whole app does not use the async await pattern, otherwise we could perform this asynchronously with backgroundContext.perform and not block the thread
-        context.performAndWait {
+        return context.performAndWait {
             do {
-//                debugPrint(
-//                    "Fetching \(T.self) in \(callingFunction) from \(callingClass): \(DebuggingIdentifiers.succeeded) on Thread: \(Thread.current)"
-//                )
-                result = try context.fetch(request)
+                if propertiesToFetch != nil {
+                    return try context.fetch(request) as? [[String: Any]] ?? []
+                } else {
+                    return try context.fetch(request) as? [T] ?? []
+                }
             } catch let error as NSError {
                 debugPrint(
                     "Fetching \(T.self) in \(callingFunction) from \(callingClass): \(DebuggingIdentifiers.failed) \(error) on Thread: \(Thread.current)"
                 )
+
+                return []
             }
         }
-
-        return result ?? []
     }
 
     // Fetch Async
@@ -386,9 +385,6 @@ extension CoreDataStack {
 
         return await context.perform {
             do {
-//                debugPrint(
-//                    "Fetching \(T.self) in \(callingFunction) from \(callingClass): \(DebuggingIdentifiers.succeeded) on Thread: \(Thread.current)"
-//                )
                 if propertiesToFetch != nil {
                     return try context.fetch(request) as? [[String: Any]] ?? []
                 } else {

+ 1 - 1
OmniBLE

@@ -1 +1 @@
-Subproject commit 4ad811774c09cae208678552dbc20ee6cc9d4f59
+Subproject commit fee22b34644a6c349db92b55ce835114c377e4d7

+ 1 - 1
OmniKit

@@ -1 +1 @@
-Subproject commit 01bc59889b9216737942ea3f0cab22f6a6c4a0e8
+Subproject commit 0857ad8d71d4d588ff7f5470e78fe8d6b5055924

+ 3 - 2
oref0_source_version.txt

@@ -1,7 +1,8 @@
-oref0 branch: TToref-reset - git version: e0caaa0
+oref0 branch: dev - git version: 0ff47a3
 
 Last commits:
-e0caaa0 revert to standard HBT calculation
+0ff47a3 fix weightedAverage, always calculate TDD
+e274bb0 revert to standard HBT calculation
 363fd11 Merge pull request #28 from bjornoleh/harmonise_defaults
 2d695e1 index.js: set enableUAM to false, and remove whitespace in L11
 8f5f820 Harmonise profile defaults with openaps/oref0

+ 126 - 127
trio-oref/lib/determine-basal/determine-basal.js

@@ -409,157 +409,156 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
 
     // Calculate tdd ----------------------------------------------------------------------
 
-    if (dynISFenabled) {
-        //Bolus:
-        for (let i = 0; i < pumphistory.length; i++) {
-            if (pumphistory[i]._type == "Bolus") {
-                bolusInsulin += pumphistory[i].amount;
-            }
+    //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 }
-                            }
+    // 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;
-                            }
+                        // 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;
                 }
+            } while (j > 0);
 
-                insulin = quota * (duration - substractTimeOfRewind);
-                tempInsulin += accountForIncrements(insulin);
-                j = current;
+            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;
-                        }
+    }
+    //  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);
                 }
+            } 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;
-                        }
+    // 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;
                 }
+            } while (o > 0);
 
-                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);
-                }
+            // 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;
+    tdd = bolusInsulin + tempInsulin + scheduledBasalInsulin;
 
 
-        var insulin_ = {
-            TDD: round(tdd, 5),
-            bolus: round(bolusInsulin, 5),
-            temp_basal: round(tempInsulin, 5),
-            scheduled_basal: round(scheduledBasalInsulin, 5)
-        }
+    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;
+    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";
+        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)"; }
 
-        } else { tddReason = ", TDD: Not enough pumpData (< 21h)"; }
-    }
 
     var tdd_before = tdd;
 
@@ -643,7 +642,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
 
     // Use weighted TDD average
     tdd_before = tdd;
-    if (weightPercentage < 1 && weightedAverage > 0) {
+    if (weightPercentage < 1 && weightedAverage > 1) {
         tdd = weightedAverage;
         console.log("Using weighted TDD average: " + round(tdd,2) + " U, instead of past 24 h (" + round(tdd_before,2) + " U), weight: " + weightPercentage);
         weightLog = ", Weighted TDD: " + round(tdd,2) + " U";