polscm32 2 лет назад
Родитель
Сommit
c4b34dc8e1

+ 8 - 8
FreeAPS.xcodeproj/project.pbxproj

@@ -320,8 +320,6 @@
 		585E2CAE2BE7BF46006ECF1A /* PumpEvent+helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E2CAD2BE7BF46006ECF1A /* PumpEvent+helper.swift */; };
 		585E2CB32BE7DA03006ECF1A /* TempBasalStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E2CAF2BE7DA03006ECF1A /* TempBasalStored+CoreDataClass.swift */; };
 		585E2CB42BE7DA03006ECF1A /* TempBasalStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E2CB02BE7DA03006ECF1A /* TempBasalStored+CoreDataProperties.swift */; };
-		585E2CB52BE7DA03006ECF1A /* PumpEventStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E2CB12BE7DA03006ECF1A /* PumpEventStored+CoreDataClass.swift */; };
-		585E2CB62BE7DA03006ECF1A /* PumpEventStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E2CB22BE7DA03006ECF1A /* PumpEventStored+CoreDataProperties.swift */; };
 		587DA1F62B77F3DD00B28F8A /* SettingsRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587DA1F52B77F3DD00B28F8A /* SettingsRowView.swift */; };
 		5887527C2BD986E1008B081D /* OpenAPSBattery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5887527B2BD986E1008B081D /* OpenAPSBattery.swift */; };
 		588752842BD9986A008B081D /* OpenAPS_Battery+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 588752822BD9986A008B081D /* OpenAPS_Battery+CoreDataClass.swift */; };
@@ -378,6 +376,8 @@
 		BD2B464E0745FBE7B79913F4 /* NightscoutConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */; };
 		BD2FF1A02AE29D43005D1C5D /* CheckboxToggleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD2FF19F2AE29D43005D1C5D /* CheckboxToggleStyle.swift */; };
 		BD3CC0722B0B89D50013189E /* MainChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD3CC0712B0B89D50013189E /* MainChartView.swift */; };
+		BD6B5DE12C032A8200F703D8 /* PumpEventStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD6B5DDF2C032A8200F703D8 /* PumpEventStored+CoreDataClass.swift */; };
+		BD6B5DE22C032A8200F703D8 /* PumpEventStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD6B5DE02C032A8200F703D8 /* PumpEventStored+CoreDataProperties.swift */; };
 		BD7DA9A52AE06DFC00601B20 /* BolusCalculatorConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7DA9A42AE06DFC00601B20 /* BolusCalculatorConfigDataFlow.swift */; };
 		BD7DA9A72AE06E2B00601B20 /* BolusCalculatorConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7DA9A62AE06E2B00601B20 /* BolusCalculatorConfigProvider.swift */; };
 		BD7DA9A92AE06E9200601B20 /* BolusCalculatorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7DA9A82AE06E9200601B20 /* BolusCalculatorStateModel.swift */; };
@@ -945,8 +945,6 @@
 		585E2CAD2BE7BF46006ECF1A /* PumpEvent+helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PumpEvent+helper.swift"; sourceTree = "<group>"; };
 		585E2CAF2BE7DA03006ECF1A /* TempBasalStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempBasalStored+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
 		585E2CB02BE7DA03006ECF1A /* TempBasalStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempBasalStored+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
-		585E2CB12BE7DA03006ECF1A /* PumpEventStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PumpEventStored+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
-		585E2CB22BE7DA03006ECF1A /* PumpEventStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PumpEventStored+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
 		587DA1F52B77F3DD00B28F8A /* SettingsRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRowView.swift; sourceTree = "<group>"; };
 		5887527B2BD986E1008B081D /* OpenAPSBattery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenAPSBattery.swift; sourceTree = "<group>"; };
 		588752822BD9986A008B081D /* OpenAPS_Battery+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenAPS_Battery+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
@@ -1002,6 +1000,8 @@
 		BD188BEB2B1B805A00B183BF /* WidgetBobble.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetBobble.swift; sourceTree = "<group>"; };
 		BD2FF19F2AE29D43005D1C5D /* CheckboxToggleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxToggleStyle.swift; sourceTree = "<group>"; };
 		BD3CC0712B0B89D50013189E /* MainChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainChartView.swift; sourceTree = "<group>"; };
+		BD6B5DDF2C032A8200F703D8 /* PumpEventStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PumpEventStored+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
+		BD6B5DE02C032A8200F703D8 /* PumpEventStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PumpEventStored+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
 		BD7DA9A42AE06DFC00601B20 /* BolusCalculatorConfigDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusCalculatorConfigDataFlow.swift; sourceTree = "<group>"; };
 		BD7DA9A62AE06E2B00601B20 /* BolusCalculatorConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusCalculatorConfigProvider.swift; sourceTree = "<group>"; };
 		BD7DA9A82AE06E9200601B20 /* BolusCalculatorStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusCalculatorStateModel.swift; sourceTree = "<group>"; };
@@ -2158,10 +2158,10 @@
 		5825D1052BD4056700F36E9B /* Classes+Properties */ = {
 			isa = PBXGroup;
 			children = (
+				BD6B5DDF2C032A8200F703D8 /* PumpEventStored+CoreDataClass.swift */,
+				BD6B5DE02C032A8200F703D8 /* PumpEventStored+CoreDataProperties.swift */,
 				585E2CAF2BE7DA03006ECF1A /* TempBasalStored+CoreDataClass.swift */,
 				585E2CB02BE7DA03006ECF1A /* TempBasalStored+CoreDataProperties.swift */,
-				585E2CB12BE7DA03006ECF1A /* PumpEventStored+CoreDataClass.swift */,
-				585E2CB22BE7DA03006ECF1A /* PumpEventStored+CoreDataProperties.swift */,
 				581F7FB12BE7B2A0005A5F89 /* BolusStored+CoreDataClass.swift */,
 				581F7FB22BE7B2A0005A5F89 /* BolusStored+CoreDataProperties.swift */,
 				CC76E9482BD471BA008BEB61 /* Forecast+CoreDataClass.swift */,
@@ -2922,7 +2922,6 @@
 				CEA4F62329BE10F70011ADF7 /* SavitzkyGolayFilter.swift in Sources */,
 				38B4F3C325E2A20B00E76A18 /* PumpSetupView.swift in Sources */,
 				38E4453C274E411700EC9A94 /* Disk+Codable.swift in Sources */,
-				585E2CB52BE7DA03006ECF1A /* PumpEventStored+CoreDataClass.swift in Sources */,
 				19E1F7EF29D08EBA005C8D20 /* IconConfigRootWiew.swift in Sources */,
 				1967DFC229D053D300759F30 /* IconImage.swift in Sources */,
 				382C134B25F14E3700715CE1 /* BGTargets.swift in Sources */,
@@ -3026,6 +3025,8 @@
 				3811DE5D25C9D4D500A708ED /* Publisher.swift in Sources */,
 				E00EEC0727368630002FF094 /* APSAssembly.swift in Sources */,
 				5825D1482BD4058F00F36E9B /* Override+CoreDataClass.swift in Sources */,
+				BD6B5DE12C032A8200F703D8 /* PumpEventStored+CoreDataClass.swift in Sources */,
+				BD6B5DE22C032A8200F703D8 /* PumpEventStored+CoreDataProperties.swift in Sources */,
 				38B4F3AF25E2979F00E76A18 /* IndexedCollection.swift in Sources */,
 				3811DEAE25C9D88300A708ED /* Cache.swift in Sources */,
 				383420D625FFE38C002D46C1 /* LoopView.swift in Sources */,
@@ -3246,7 +3247,6 @@
 				891DECF7BC20968D7F566161 /* AutotuneConfigProvider.swift in Sources */,
 				5825D15C2BD4058F00F36E9B /* Target+CoreDataClass.swift in Sources */,
 				D76333C9256787610B3B4875 /* AutotuneConfigStateModel.swift in Sources */,
-				585E2CB62BE7DA03006ECF1A /* PumpEventStored+CoreDataProperties.swift in Sources */,
 				A05235B9112E677ED03B6E8E /* AutotuneConfigRootView.swift in Sources */,
 				5825D14F2BD4058F00F36E9B /* HbA1c+CoreDataProperties.swift in Sources */,
 				7F7B756BE8543965D9FDF1A2 /* DataTableDataFlow.swift in Sources */,

+ 375 - 167
FreeAPS/Sources/APS/Storage/PumpHistoryStorage.swift

@@ -1,3 +1,4 @@
+import CoreData
 import Foundation
 import LoopKit
 import SwiftDate
@@ -33,208 +34,415 @@ final class BasePumpHistoryStorage: PumpHistoryStorage, Injectable {
 
     func storePumpEvents(_ events: [NewPumpEvent]) {
         processQueue.async {
-            let eventsToStore = events.flatMap { event -> [PumpHistoryEvent] in
-                let id = event.raw.md5String
-                switch event.type {
-                case .bolus:
-                    guard let dose = event.dose else { return [] }
-                    let amount = Decimal(string: dose.unitsInDeliverableIncrements.description)
-                    let minutes = Int((dose.endDate - dose.startDate).timeInterval / 60)
-
-                    self.context.perform {
-                        // create pump event
+            self.context.perform {
+                for event in events {
+                    let id = UUID().uuidString
+
+                    switch event.type {
+                    case .bolus:
+                        guard let dose = event.dose else { continue }
+                        let amount = Decimal(string: dose.unitsInDeliverableIncrements.description)
+
                         let newPumpEvent = PumpEventStored(context: self.context)
-                        newPumpEvent.id = id
+//                        newPumpEvent.id = id
                         newPumpEvent.timestamp = event.date
                         newPumpEvent.type = PumpEvent.bolus.rawValue
 
-                        // create bolus entry and specify relationship to pump event
                         let newBolusEntry = BolusStored(context: self.context)
                         newBolusEntry.pumpEvent = newPumpEvent
                         newBolusEntry.amount = amount as? NSDecimalNumber
                         newBolusEntry.isExternal = dose.manuallyEntered
                         newBolusEntry.isSMB = dose.automatic ?? true
 
-                        do {
-                            guard self.context.hasChanges else { return }
-                            try self.context.save()
-                        } catch {
-                            print(error.localizedDescription)
-                        }
-                    }
+                    case .tempBasal:
+                        guard let dose = event.dose else { continue }
+
+                        let rate = Decimal(dose.unitsPerHour)
+                        let minutes = (dose.endDate - dose.startDate).timeInterval / 60
+                        let delivered = dose.deliveredUnits
+                        let date = event.date
+
+                        let isCancel = delivered != nil
+                        guard !isCancel else { continue }
 
-                    return [PumpHistoryEvent(
-                        id: id,
-                        type: .bolus,
-                        timestamp: event.date,
-                        amount: amount,
-                        duration: minutes,
-                        durationMin: nil,
-                        rate: nil,
-                        temp: nil,
-                        carbInput: nil,
-                        isSMB: dose.automatic,
-                        isExternal: dose.manuallyEntered
-                    )]
-                case .tempBasal:
-                    guard let dose = event.dose else { return [] }
-
-                    let rate = Decimal(dose.unitsPerHour)
-                    let minutes = (dose.endDate - dose.startDate).timeInterval / 60
-                    let delivered = dose.deliveredUnits
-                    let date = event.date
-
-                    let isCancel = delivered != nil //! event.isMutable && delivered != nil
-                    guard !isCancel else { return [] }
-
-                    self.context.perform {
-                        // create pump event
                         let newPumpEvent = PumpEventStored(context: self.context)
-                        newPumpEvent.id = id
+//                        newPumpEvent.id = id
                         newPumpEvent.timestamp = date
                         newPumpEvent.type = PumpEvent.tempBasal.rawValue
 
-                        // create temp basal and specify relationship
                         let newTempBasal = TempBasalStored(context: self.context)
                         newTempBasal.pumpEvent = newPumpEvent
                         newTempBasal.duration = Int16(round(minutes))
                         newTempBasal.rate = rate as NSDecimalNumber
                         newTempBasal.tempType = TempType.absolute.rawValue
 
-                        do {
-                            guard self.context.hasChanges else { return }
-                            try self.context.save()
-                        } catch {
-                            print(error.localizedDescription)
-                        }
-                    }
-
-                    return [
-                        PumpHistoryEvent(
-                            id: id,
-                            type: .tempBasalDuration,
-                            timestamp: date,
-                            amount: nil,
-                            duration: nil,
-                            durationMin: Int(round(minutes)),
-                            rate: nil,
-                            temp: nil,
-                            carbInput: nil
-                        ),
-                        PumpHistoryEvent(
-                            id: "_" + id,
-                            type: .tempBasal,
-                            timestamp: date,
-                            amount: nil,
-                            duration: nil,
-                            durationMin: nil,
-                            rate: rate,
-                            temp: .absolute,
-                            carbInput: nil
-                        )
-                    ]
-                case .suspend:
-                    self.context.perform {
-                        // create pump event
+                    case .suspend:
                         let newPumpEvent = PumpEventStored(context: self.context)
-                        newPumpEvent.id = id
+//                        newPumpEvent.id = id
                         newPumpEvent.timestamp = event.date
                         newPumpEvent.type = PumpEvent.pumpSuspend.rawValue
 
-                        do {
-                            guard self.context.hasChanges else { return }
-                            try self.context.save()
-                        } catch {
-                            print(error.localizedDescription)
-                        }
-                    }
-                    return [
-                        PumpHistoryEvent(
-                            id: id,
-                            type: .pumpSuspend,
-                            timestamp: event.date,
-                            amount: nil,
-                            duration: nil,
-                            durationMin: nil,
-                            rate: nil,
-                            temp: nil,
-                            carbInput: nil
-                        )
-                    ]
-                case .resume:
-                    self.context.perform {
-                        // create pump event
+                    case .resume:
                         let newPumpEvent = PumpEventStored(context: self.context)
-                        newPumpEvent.id = id
+//                        newPumpEvent.id = id
                         newPumpEvent.timestamp = event.date
                         newPumpEvent.type = PumpEvent.pumpResume.rawValue
 
-                        do {
-                            guard self.context.hasChanges else { return }
-                            try self.context.save()
-                        } catch {
-                            print(error.localizedDescription)
-                        }
+                    case .rewind:
+                        let newPumpEvent = PumpEventStored(context: self.context)
+//                        newPumpEvent.id = id
+                        newPumpEvent.timestamp = event.date
+                        newPumpEvent.type = PumpEvent.rewind.rawValue
+
+                    case .prime:
+                        let newPumpEvent = PumpEventStored(context: self.context)
+//                        newPumpEvent.id = id
+                        newPumpEvent.timestamp = event.date
+                        newPumpEvent.type = PumpEvent.prime.rawValue
+
+                    case .alarm:
+                        let newPumpEvent = PumpEventStored(context: self.context)
+//                        newPumpEvent.id = id
+                        newPumpEvent.timestamp = event.date
+                        newPumpEvent.type = PumpEvent.pumpAlarm.rawValue
+
+                    default:
+                        continue
                     }
-                    return [
-                        PumpHistoryEvent(
-                            id: id,
-                            type: .pumpResume,
-                            timestamp: event.date,
-                            amount: nil,
-                            duration: nil,
-                            durationMin: nil,
-                            rate: nil,
-                            temp: nil,
-                            carbInput: nil
-                        )
-                    ]
-                case .rewind:
-                    return [
-                        PumpHistoryEvent(
-                            id: id,
-                            type: .rewind,
-                            timestamp: event.date,
-                            amount: nil,
-                            duration: nil,
-                            durationMin: nil,
-                            rate: nil,
-                            temp: nil,
-                            carbInput: nil
-                        )
-                    ]
-                case .prime:
-                    return [
-                        PumpHistoryEvent(
-                            id: id,
-                            type: .prime,
-                            timestamp: event.date,
-                            amount: nil,
-                            duration: nil,
-                            durationMin: nil,
-                            rate: nil,
-                            temp: nil,
-                            carbInput: nil
-                        )
-                    ]
-                case .alarm:
-                    return [
-                        PumpHistoryEvent(
-                            id: id,
-                            type: .pumpAlarm,
-                            timestamp: event.date,
-                            note: event.title
-                        )
-                    ]
-                default:
-                    return []
                 }
-            }
 
-            self.storeEvents(eventsToStore)
+                do {
+                    guard self.context.hasChanges else { return }
+                    try self.context.save()
+                    debugPrint("\(DebuggingIdentifiers.succeeded) stored pump events in Core Data")
+                } catch let error as NSError {
+                    debugPrint("\(DebuggingIdentifiers.failed) failed to store pump events with error: \(error.userInfo)")
+                }
+            }
         }
     }
 
+//    func storePumpEvents(_ events: [NewPumpEvent]) {
+//        processQueue.async {
+//            self.context.perform {
+//                for event in events {
+//                    let id = UUID().uuidString
+//
+//                    switch event.type {
+//                    case .bolus:
+//                        guard let dose = event.dose else { continue }
+//                        let amount = Decimal(string: dose.unitsInDeliverableIncrements.description)
+//
+//                        let newPumpEvent = NSEntityDescription.insertNewObject(
+//                            forEntityName: "PumpEventStored",
+//                            into: self.context
+//                        ) as! PumpEventStored
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.bolus.rawValue
+//
+//                        let newBolusEntry = NSEntityDescription.insertNewObject(
+//                            forEntityName: "BolusStored",
+//                            into: self.context
+//                        ) as! BolusStored
+//                        newBolusEntry.pumpEvent = newPumpEvent
+//                        newBolusEntry.amount = amount as? NSDecimalNumber
+//                        newBolusEntry.isExternal = dose.manuallyEntered
+//                        newBolusEntry.isSMB = dose.automatic ?? true
+//
+//                    case .tempBasal:
+//                        guard let dose = event.dose else { continue }
+//
+//                        let rate = Decimal(dose.unitsPerHour)
+//                        let minutes = (dose.endDate - dose.startDate).timeInterval / 60
+//                        let delivered = dose.deliveredUnits
+//                        let date = event.date
+//
+//                        let isCancel = delivered != nil
+//                        guard !isCancel else { continue }
+//
+//                        let newPumpEvent = NSEntityDescription.insertNewObject(
+//                            forEntityName: "PumpEventStored",
+//                            into: self.context
+//                        ) as! PumpEventStored
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = date
+//                        newPumpEvent.type = PumpEvent.tempBasal.rawValue
+//
+//                        let newTempBasal = NSEntityDescription.insertNewObject(
+//                            forEntityName: "TempBasalStored",
+//                            into: self.context
+//                        ) as! TempBasalStored
+//                        newTempBasal.pumpEvent = newPumpEvent
+//                        newTempBasal.duration = Int16(round(minutes))
+//                        newTempBasal.rate = rate as NSDecimalNumber
+//                        newTempBasal.tempType = TempType.absolute.rawValue
+//
+//                    case .suspend:
+//                        let newPumpEvent = NSEntityDescription.insertNewObject(
+//                            forEntityName: "PumpEventStored",
+//                            into: self.context
+//                        ) as! PumpEventStored
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.pumpSuspend.rawValue
+//
+//                    case .resume:
+//                        let newPumpEvent = NSEntityDescription.insertNewObject(
+//                            forEntityName: "PumpEventStored",
+//                            into: self.context
+//                        ) as! PumpEventStored
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.pumpResume.rawValue
+//
+//                    case .rewind:
+//                        let newPumpEvent = NSEntityDescription.insertNewObject(
+//                            forEntityName: "PumpEventStored",
+//                            into: self.context
+//                        ) as! PumpEventStored
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.rewind.rawValue
+//
+//                    case .prime:
+//                        let newPumpEvent = NSEntityDescription.insertNewObject(
+//                            forEntityName: "PumpEventStored",
+//                            into: self.context
+//                        ) as! PumpEventStored
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.prime.rawValue
+//
+//                    case .alarm:
+//                        let newPumpEvent = NSEntityDescription.insertNewObject(
+//                            forEntityName: "PumpEventStored",
+//                            into: self.context
+//                        ) as! PumpEventStored
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.pumpAlarm.rawValue
+//
+//                    default:
+//                        continue
+//                    }
+//                }
+//
+//                do {
+//                    if self.context.hasChanges {
+//                        try self.context.save()
+//                    }
+//                } catch {
+//                    print(error.localizedDescription)
+//                }
+//            }
+//        }
+//    }
+
+//    func storePumpEvents(_ events: [NewPumpEvent]) {
+//        processQueue.async {
+//            let eventsToStore = events.flatMap { event -> [PumpHistoryEvent] in
+//                let id = event.raw.md5String
+//                switch event.type {
+//                case .bolus:
+//                    guard let dose = event.dose else { return [] }
+//                    let amount = Decimal(string: dose.unitsInDeliverableIncrements.description)
+//                    let minutes = Int((dose.endDate - dose.startDate).timeInterval / 60)
+//
+//                    self.context.perform {
+//                        // create pump event
+//                        let newPumpEvent = PumpEventStored(context: self.context)
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.bolus.rawValue
+//
+//                        // create bolus entry and specify relationship to pump event
+//                        let newBolusEntry = BolusStored(context: self.context)
+//                        newBolusEntry.pumpEvent = newPumpEvent
+//                        newBolusEntry.amount = amount as? NSDecimalNumber
+//                        newBolusEntry.isExternal = dose.manuallyEntered
+//                        newBolusEntry.isSMB = dose.automatic ?? true
+//
+//                        do {
+//                            guard self.context.hasChanges else { return }
+//                            try self.context.save()
+//                        } catch {
+//                            print(error.localizedDescription)
+//                        }
+//                    }
+//
+//                    return [PumpHistoryEvent(
+//                        id: id,
+//                        type: .bolus,
+//                        timestamp: event.date,
+//                        amount: amount,
+//                        duration: minutes,
+//                        durationMin: nil,
+//                        rate: nil,
+//                        temp: nil,
+//                        carbInput: nil,
+//                        isSMB: dose.automatic,
+//                        isExternal: dose.manuallyEntered
+//                    )]
+//                case .tempBasal:
+//                    guard let dose = event.dose else { return [] }
+//
+//                    let rate = Decimal(dose.unitsPerHour)
+//                    let minutes = (dose.endDate - dose.startDate).timeInterval / 60
+//                    let delivered = dose.deliveredUnits
+//                    let date = event.date
+//
+//                    let isCancel = delivered != nil //! event.isMutable && delivered != nil
+//                    guard !isCancel else { return [] }
+//
+//                    self.context.perform {
+//                        // create pump event
+//                        let newPumpEvent = PumpEventStored(context: self.context)
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = date
+//                        newPumpEvent.type = PumpEvent.tempBasal.rawValue
+//
+//                        // create temp basal and specify relationship
+//                        let newTempBasal = TempBasalStored(context: self.context)
+//                        newTempBasal.pumpEvent = newPumpEvent
+//                        newTempBasal.duration = Int16(round(minutes))
+//                        newTempBasal.rate = rate as NSDecimalNumber
+//                        newTempBasal.tempType = TempType.absolute.rawValue
+//
+//                        do {
+//                            guard self.context.hasChanges else { return }
+//                            try self.context.save()
+//                        } catch {
+//                            print(error.localizedDescription)
+//                        }
+//                    }
+//
+//                    return [
+//                        PumpHistoryEvent(
+//                            id: id,
+//                            type: .tempBasalDuration,
+//                            timestamp: date,
+//                            amount: nil,
+//                            duration: nil,
+//                            durationMin: Int(round(minutes)),
+//                            rate: nil,
+//                            temp: nil,
+//                            carbInput: nil
+//                        ),
+//                        PumpHistoryEvent(
+//                            id: "_" + id,
+//                            type: .tempBasal,
+//                            timestamp: date,
+//                            amount: nil,
+//                            duration: nil,
+//                            durationMin: nil,
+//                            rate: rate,
+//                            temp: .absolute,
+//                            carbInput: nil
+//                        )
+//                    ]
+//                case .suspend:
+//                    self.context.perform {
+//                        // create pump event
+//                        let newPumpEvent = PumpEventStored(context: self.context)
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.pumpSuspend.rawValue
+//
+//                        do {
+//                            guard self.context.hasChanges else { return }
+//                            try self.context.save()
+//                        } catch {
+//                            print(error.localizedDescription)
+//                        }
+//                    }
+//                    return [
+//                        PumpHistoryEvent(
+//                            id: id,
+//                            type: .pumpSuspend,
+//                            timestamp: event.date,
+//                            amount: nil,
+//                            duration: nil,
+//                            durationMin: nil,
+//                            rate: nil,
+//                            temp: nil,
+//                            carbInput: nil
+//                        )
+//                    ]
+//                case .resume:
+//                    self.context.perform {
+//                        // create pump event
+//                        let newPumpEvent = PumpEventStored(context: self.context)
+//                        newPumpEvent.id = id
+//                        newPumpEvent.timestamp = event.date
+//                        newPumpEvent.type = PumpEvent.pumpResume.rawValue
+//
+//                        do {
+//                            guard self.context.hasChanges else { return }
+//                            try self.context.save()
+//                        } catch {
+//                            print(error.localizedDescription)
+//                        }
+//                    }
+//                    return [
+//                        PumpHistoryEvent(
+//                            id: id,
+//                            type: .pumpResume,
+//                            timestamp: event.date,
+//                            amount: nil,
+//                            duration: nil,
+//                            durationMin: nil,
+//                            rate: nil,
+//                            temp: nil,
+//                            carbInput: nil
+//                        )
+//                    ]
+//                case .rewind:
+//                    return [
+//                        PumpHistoryEvent(
+//                            id: id,
+//                            type: .rewind,
+//                            timestamp: event.date,
+//                            amount: nil,
+//                            duration: nil,
+//                            durationMin: nil,
+//                            rate: nil,
+//                            temp: nil,
+//                            carbInput: nil
+//                        )
+//                    ]
+//                case .prime:
+//                    return [
+//                        PumpHistoryEvent(
+//                            id: id,
+//                            type: .prime,
+//                            timestamp: event.date,
+//                            amount: nil,
+//                            duration: nil,
+//                            durationMin: nil,
+//                            rate: nil,
+//                            temp: nil,
+//                            carbInput: nil
+//                        )
+//                    ]
+//                case .alarm:
+//                    return [
+//                        PumpHistoryEvent(
+//                            id: id,
+//                            type: .pumpAlarm,
+//                            timestamp: event.date,
+//                            note: event.title
+//                        )
+//                    ]
+//                default:
+//                    return []
+//                }
+//            }
+//
+//            self.storeEvents(eventsToStore)
+//        }
+//    }
+
     func storeJournalCarbs(_ carbs: Int) {
         processQueue.async {
             let eventsToStore = [

+ 2 - 2
FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift

@@ -396,7 +396,7 @@ extension Bolus {
             context.perform {
                 // create pump event
                 let newPumpEvent = PumpEventStored(context: self.context)
-                newPumpEvent.id = UUID().uuidString
+//                newPumpEvent.id = UUID().uuidString
                 newPumpEvent.timestamp = Date()
                 newPumpEvent.type = PumpEvent.bolus.rawValue
 
@@ -466,7 +466,7 @@ extension Bolus {
             context.perform {
                 // create pump event
                 let newPumpEvent = PumpEventStored(context: self.context)
-                newPumpEvent.id = UUID().uuidString
+//                newPumpEvent.id = UUID().uuidString
                 newPumpEvent.timestamp = self.date
                 newPumpEvent.type = PumpEvent.bolus.rawValue
 

+ 2 - 3
FreeAPS/Sources/Modules/DataTable/DataTableProvider.swift

@@ -18,9 +18,8 @@ extension DataTable {
 
         func deleteInsulin(_ treatment: PumpEventStored) {
             nightscoutManager.deleteInsulin(at: treatment.timestamp ?? Date())
-            if let id = treatment.id {
-                healthkitManager.deleteInsulin(syncID: id)
-            }
+            let id = treatment.id
+            healthkitManager.deleteInsulin(syncID: id)
         }
 
         func deleteManualGlucose(date: Date?) {

+ 80 - 72
FreeAPS/Sources/Services/WatchManager/WatchManager.swift

@@ -54,22 +54,28 @@ final class BaseWatchManager: NSObject, WatchManager, Injectable {
     }
 
     private func fetchLastDeterminationDate() -> Date? {
-        var date: Date?
         let predicate = NSPredicate.enactedDetermination
 
-        // fetch and update on date on the main thread
-        CoreDataStack.shared.fetchEntitiesAndUpdateUI(
+        return CoreDataStack.shared.fetchEntities2(
             ofType: OrefDetermination.self,
+            onContext: context,
             predicate: predicate,
             key: "deliverAt",
             ascending: false,
             fetchLimit: 1,
             propertiesToFetch: ["deliverAt"]
-        ) { fetchedDetermination in
-            guard let mostRecentDetermination = fetchedDetermination.first else { return }
-            date = mostRecentDetermination.deliverAt
-        }
-        return date
+        ).first?.deliverAt
+    }
+
+    private func fetchLatestOverride() -> Override? {
+        CoreDataStack.shared.fetchEntities2(
+            ofType: Override.self,
+            onContext: context,
+            predicate: NSPredicate.predicateForOneDayAgo,
+            key: "date",
+            ascending: false,
+            fetchLimit: 1
+        ).first
     }
 
     func fetchAndProcessGlucose() -> (ids: [NSManagedObjectID], glucose: String, trend: String, delta: String, date: Date) {
@@ -125,80 +131,82 @@ final class BaseWatchManager: NSObject, WatchManager, Injectable {
 
     private func configureState() {
         processQueue.async {
-            let glucoseValues = self.fetchAndProcessGlucose()
-
-            self.state.glucose = glucoseValues.glucose
-            self.state.trend = glucoseValues.trend
-            self.state.delta = glucoseValues.delta
-            self.state.trendRaw = glucoseValues.trend
-            self.state.glucoseDate = glucoseValues.date
-            self.state.lastLoopDate = self.fetchLastDeterminationDate()
-            self.state.lastLoopDateInterval = self.state.lastLoopDate.map {
-                guard $0.timeIntervalSince1970 > 0 else { return 0 }
-                return UInt64($0.timeIntervalSince1970)
-            }
-            self.state.bolusIncrement = self.settingsManager.preferences.bolusIncrement
-            self.state.maxCOB = self.settingsManager.preferences.maxCOB
-            self.state.maxBolus = self.settingsManager.pumpSettings.maxBolus
-            self.state.carbsRequired = self.suggestion?.carbsReq
-
-            var insulinRequired = self.suggestion?.insulinReq ?? 0
+            self.context.performAndWait {
+                let glucoseValues = self.fetchAndProcessGlucose()
+
+                self.state.glucose = glucoseValues.glucose
+                self.state.trend = glucoseValues.trend
+                self.state.delta = glucoseValues.delta
+                self.state.trendRaw = glucoseValues.trend
+                self.state.glucoseDate = glucoseValues.date
+                self.state.lastLoopDate = self.fetchLastDeterminationDate()
+                self.state.lastLoopDateInterval = self.state.lastLoopDate.map {
+                    guard $0.timeIntervalSince1970 > 0 else { return 0 }
+                    return UInt64($0.timeIntervalSince1970)
+                }
+                self.state.bolusIncrement = self.settingsManager.preferences.bolusIncrement
+                self.state.maxCOB = self.settingsManager.preferences.maxCOB
+                self.state.maxBolus = self.settingsManager.pumpSettings.maxBolus
+                self.state.carbsRequired = self.suggestion?.carbsReq
 
-            var double: Decimal = 2
-            if self.suggestion?.manualBolusErrorString == 0 {
-                insulinRequired = self.suggestion?.insulinForManualBolus ?? 0
-                double = 1
-            }
+                var insulinRequired = self.suggestion?.insulinReq ?? 0
 
-            self.state.useNewCalc = self.settingsManager.settings.useCalc
+                var double: Decimal = 2
+                if self.suggestion?.manualBolusErrorString == 0 {
+                    insulinRequired = self.suggestion?.insulinForManualBolus ?? 0
+                    double = 1
+                }
 
-            if !(self.state.useNewCalc ?? false) {
-                self.state.bolusRecommended = self.apsManager
-                    .roundBolus(amount: max(
-                        insulinRequired * (self.settingsManager.settings.insulinReqPercentage / 100) * double,
-                        0
-                    ))
-            } else {
-                let recommended = self.newBolusCalc(ids: glucoseValues.ids, suggestion: self.suggestion)
-                self.state.bolusRecommended = self.apsManager
-                    .roundBolus(amount: max(recommended, 0))
-            }
+                self.state.useNewCalc = self.settingsManager.settings.useCalc
+
+                if !(self.state.useNewCalc ?? false) {
+                    self.state.bolusRecommended = self.apsManager
+                        .roundBolus(amount: max(
+                            insulinRequired * (self.settingsManager.settings.insulinReqPercentage / 100) * double,
+                            0
+                        ))
+                } else {
+                    let recommended = self.newBolusCalc(ids: glucoseValues.ids, suggestion: self.suggestion)
+                    self.state.bolusRecommended = self.apsManager
+                        .roundBolus(amount: max(recommended, 0))
+                }
 
-            self.state.iob = self.suggestion?.iob
-            self.state.cob = self.suggestion?.cob
-            self.state.tempTargets = self.tempTargetsStorage.presets()
-                .map { target -> TempTargetWatchPreset in
-                    let untilDate = self.tempTargetsStorage.current().flatMap { currentTarget -> Date? in
-                        guard currentTarget.id == target.id else { return nil }
-                        let date = currentTarget.createdAt.addingTimeInterval(TimeInterval(currentTarget.duration * 60))
-                        return date > Date() ? date : nil
+                self.state.iob = self.suggestion?.iob
+                self.state.cob = self.suggestion?.cob
+                self.state.tempTargets = self.tempTargetsStorage.presets()
+                    .map { target -> TempTargetWatchPreset in
+                        let untilDate = self.tempTargetsStorage.current().flatMap { currentTarget -> Date? in
+                            guard currentTarget.id == target.id else { return nil }
+                            let date = currentTarget.createdAt.addingTimeInterval(TimeInterval(currentTarget.duration * 60))
+                            return date > Date() ? date : nil
+                        }
+                        return TempTargetWatchPreset(
+                            name: target.displayName,
+                            id: target.id,
+                            description: self.descriptionForTarget(target),
+                            until: untilDate
+                        )
                     }
-                    return TempTargetWatchPreset(
-                        name: target.displayName,
-                        id: target.id,
-                        description: self.descriptionForTarget(target),
-                        until: untilDate
-                    )
-                }
-            self.state.bolusAfterCarbs = !self.settingsManager.settings.skipBolusScreenAfterCarbs
-            self.state.displayOnWatch = self.settingsManager.settings.displayOnWatch
-            self.state.displayFatAndProteinOnWatch = self.settingsManager.settings.displayFatAndProteinOnWatch
-            self.state.confirmBolusFaster = self.settingsManager.settings.confirmBolusFaster
+                self.state.bolusAfterCarbs = !self.settingsManager.settings.skipBolusScreenAfterCarbs
+                self.state.displayOnWatch = self.settingsManager.settings.displayOnWatch
+                self.state.displayFatAndProteinOnWatch = self.settingsManager.settings.displayFatAndProteinOnWatch
+                self.state.confirmBolusFaster = self.settingsManager.settings.confirmBolusFaster
 
-            let eBG = self.evetualBGStraing()
-            self.state.eventualBG = eBG.map { "⇢ " + $0 }
-            self.state.eventualBGRaw = eBG
+                let eBG = self.evetualBGStraing()
+                self.state.eventualBG = eBG.map { "⇢ " + $0 }
+                self.state.eventualBGRaw = eBG
 
-            self.state.isf = self.suggestion?.isf
+                self.state.isf = self.suggestion?.isf
 
-            let overrideArray = self.coreDataStorage.fetchLatestOverride()
+                let latestOverride = self.fetchLatestOverride()
 
-            if overrideArray.first?.enabled ?? false {
-                let percentString = "\((overrideArray.first?.percentage ?? 100).formatted(.number)) %"
-                self.state.override = percentString
+                if latestOverride?.enabled ?? false {
+                    let percentString = "\((latestOverride?.percentage ?? 100).formatted(.number)) %"
+                    self.state.override = percentString
 
-            } else {
-                self.state.override = "100 %"
+                } else {
+                    self.state.override = "100 %"
+                }
             }
 
             self.sendState()

+ 3 - 2
Model/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents

@@ -210,7 +210,7 @@
         <attribute name="protein" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
     </entity>
     <entity name="PumpEventStored" representedClassName="PumpEventStored" syncable="YES">
-        <attribute name="id" optional="YES" attributeType="String"/>
+        <attribute name="id_" optional="YES" attributeType="String"/>
         <attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="type" optional="YES" attributeType="String"/>
         <relationship name="bolus" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BolusStored" inverseName="pumpEvent" inverseEntity="BolusStored"/>
@@ -220,8 +220,9 @@
         </fetchIndex>
         <uniquenessConstraints>
             <uniquenessConstraint>
-                <constraint value="id"/>
+                <constraint value="id_"/>
             </uniquenessConstraint>
+            <uniquenessConstraint/>
         </uniquenessConstraints>
     </entity>
     <entity name="StatsData" representedClassName="StatsData" syncable="YES">

+ 3 - 3
Model/Helper/PumpEvent+helper.swift

@@ -122,7 +122,7 @@ extension PumpEventStored {
     }()
 
     func toBolusDTOEnum() -> PumpEventDTO? {
-        guard let id = id, let timestamp = timestamp, let bolus = bolus, let amount = bolus.amount else {
+        guard let timestamp = timestamp, let bolus = bolus, let amount = bolus.amount else {
             return nil
         }
 
@@ -138,7 +138,7 @@ extension PumpEventStored {
     }
 
     func toTempBasalDTOEnum() -> PumpEventDTO? {
-        guard let id = id, let timestamp = timestamp, let tempBasal = tempBasal, let rate = tempBasal.rate else {
+        guard let timestamp = timestamp, let tempBasal = tempBasal, let rate = tempBasal.rate else {
             return nil
         }
 
@@ -152,7 +152,7 @@ extension PumpEventStored {
     }
 
     func toTempBasalDurationDTOEnum() -> PumpEventDTO? {
-        guard let id = id, let timestamp = timestamp, let tempBasal = tempBasal else {
+        guard let timestamp = timestamp, let tempBasal = tempBasal else {
             return nil
         }
 

+ 15 - 1
PumpEventStored+CoreDataProperties.swift

@@ -6,11 +6,25 @@ public extension PumpEventStored {
         NSFetchRequest<PumpEventStored>(entityName: "PumpEventStored")
     }
 
-    @NSManaged var id: String?
+    @NSManaged var id_: String!
     @NSManaged var timestamp: Date?
     @NSManaged var type: String?
     @NSManaged var bolus: BolusStored?
     @NSManaged var tempBasal: TempBasalStored?
+
+    override func awakeFromInsert() {
+        id_ = UUID().uuidString
+    }
 }
 
 extension PumpEventStored: Identifiable {}
+
+public extension PumpEventStored {
+    var id: String {
+        #if DEBUG
+            return id_!
+        #else
+            return id_ ?? UUID().uuidString
+        #endif
+    }
+}