Jon B.M 3 лет назад
Родитель
Сommit
9b05e859c7

+ 1 - 1
Config.xcconfig

@@ -1,5 +1,5 @@
 APP_DISPLAY_NAME = FreeAPS X
-APP_VERSION = 1.0.3
+APP_VERSION = 1.0.5
 APP_BUILD_NUMBER = 1
 COPYRIGHT_NOTICE = 
 DEVELOPER_TEAM = ##TEAM_ID##

+ 11 - 0
Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22C65" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
+    <entity name="Readings" representedClassName="Readings" syncable="YES" codeGenerationType="class">
+        <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
+        <attribute name="glucose" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
+    </entity>
+    <entity name="TDD" representedClassName="TDD" syncable="YES" codeGenerationType="class">
+        <attribute name="tdd" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
+        <attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
+    </entity>
+</model>

+ 2 - 2
Dependencies/rileylink_ios/RileyLink.xcodeproj/project.pbxproj

@@ -5659,7 +5659,7 @@
 				CODE_SIGN_IDENTITY = "Mac Developer";
 				CODE_SIGN_STYLE = Automatic;
 				DEBUG_INFORMATION_FORMAT = dwarf;
-				DEVELOPMENT_TEAM = UY678SP37Q;
+				DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
 				ENABLE_HARDENED_RUNTIME = YES;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
 				GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -5686,7 +5686,7 @@
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				DEVELOPMENT_TEAM = UY678SP37Q;
+				DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
 				ENABLE_HARDENED_RUNTIME = YES;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
 				GCC_C_LANGUAGE_STANDARD = gnu11;

+ 23 - 8
FreeAPS.xcodeproj/project.pbxproj

@@ -16,13 +16,11 @@
 		19012CDC291D2CB900FB8210 /* LoopStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19012CDB291D2CB900FB8210 /* LoopStats.swift */; };
 		1927C8E62744606D00347C69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1927C8E82744606D00347C69 /* InfoPlist.strings */; };
 		1935364028496F7D001E0B16 /* TDD_averages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1935363F28496F7D001E0B16 /* TDD_averages.swift */; };
-		19788CAF293CE0F0002FC264 /* GlucoseDataForStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19788CAE293CE0F0002FC264 /* GlucoseDataForStats.swift */; };
 		19795118275953E50044850D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 198377D4266BFFF6004DE65E /* Localizable.strings */; };
 		198377D2266BFFF6004DE65E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 198377D4266BFFF6004DE65E /* Localizable.strings */; };
 		19854F492961C3E500941627 /* DurationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19854F482961C3E500941627 /* DurationButton.swift */; };
 		199561C1275E61A50077B976 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 199561C0275E61A50077B976 /* HealthKit.framework */; };
 		19B0EF2128F6D66200069496 /* Statistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B0EF2028F6D66200069496 /* Statistics.swift */; };
-		19F79FA9283AE7E000646323 /* TDD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19F79FA8283AE7E000646323 /* TDD.swift */; };
 		1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */; };
 		1D845DF2E3324130E1D95E67 /* DataTableProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60744C3E9BB3652895C908CC /* DataTableProvider.swift */; };
 		23888883D4EA091C88480FF2 /* BolusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19984D62EFC0035A9E9644D /* BolusProvider.swift */; };
@@ -339,6 +337,8 @@
 		FE41E4D429463C660047FD55 /* NightscoutStatistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE41E4D329463C660047FD55 /* NightscoutStatistics.swift */; };
 		FE41E4D629463EE20047FD55 /* NightscoutPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */; };
 		FE66D16B291F74F8005D6F77 /* Bundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE66D16A291F74F8005D6F77 /* Bundle+Extensions.swift */; };
+		FEFA5C0F299F810B00765C17 /* Core_Data.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FEFA5C0D299F810B00765C17 /* Core_Data.xcdatamodeld */; };
+		FEFA5C11299F814A00765C17 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFA5C10299F814A00765C17 /* CoreDataStack.swift */; };
 		FEFFA7A22929FE49007B8193 /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFFA7A12929FE49007B8193 /* UIDevice+Extensions.swift */; };
 /* End PBXBuildFile section */
 
@@ -446,7 +446,6 @@
 		1927C8FB2744612600347C69 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		1927C8FE274489BA00347C69 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		1935363F28496F7D001E0B16 /* TDD_averages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDD_averages.swift; sourceTree = "<group>"; };
-		19788CAE293CE0F0002FC264 /* GlucoseDataForStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseDataForStats.swift; sourceTree = "<group>"; };
 		198377D3266BFFF6004DE65E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
 		198377D5266C0A05004DE65E /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
 		198377D6266C0A0A004DE65E /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -471,7 +470,6 @@
 		19B0EF2028F6D66200069496 /* Statistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Statistics.swift; sourceTree = "<group>"; };
 		19C166682756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		19C166692756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
-		19F79FA8283AE7E000646323 /* TDD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDD.swift; sourceTree = "<group>"; };
 		1CAE81192B118804DCD23034 /* SnoozeProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeProvider.swift; sourceTree = "<group>"; };
 		212E8BFE6D66EE65AA26A114 /* CalibrationsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsProvider.swift; sourceTree = "<group>"; };
 		223EC0494F55A91E3EA69EF4 /* BolusStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusStateModel.swift; sourceTree = "<group>"; };
@@ -771,6 +769,8 @@
 		FE41E4D329463C660047FD55 /* NightscoutStatistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutStatistics.swift; sourceTree = "<group>"; };
 		FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutPreferences.swift; sourceTree = "<group>"; };
 		FE66D16A291F74F8005D6F77 /* Bundle+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Extensions.swift"; sourceTree = "<group>"; };
+		FEFA5C0E299F810B00765C17 /* Core_Data.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Core_Data.xcdatamodel; sourceTree = "<group>"; };
+		FEFA5C10299F814A00765C17 /* CoreDataStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataStack.swift; sourceTree = "<group>"; };
 		FEFFA7A12929FE49007B8193 /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -1272,6 +1272,7 @@
 		388E594F25AD948C0019842D = {
 			isa = PBXGroup;
 			children = (
+				FEFA5C0D299F810B00765C17 /* Core_Data.xcdatamodeld */,
 				38F3783A2613555C009DB701 /* Config.xcconfig */,
 				3818AA42274BBC1100843DB3 /* ConfigOverride.xcconfig */,
 				388E595A25AD948C0019842D /* FreeAPS */,
@@ -1345,12 +1346,10 @@
 				3871F39B25ED892B0013ECB5 /* TempTarget.swift */,
 				3811DE8E25C9D80400A708ED /* User.swift */,
 				E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */,
-				19F79FA8283AE7E000646323 /* TDD.swift */,
 				1935363F28496F7D001E0B16 /* TDD_averages.swift */,
 				CE82E02628E869DF00473A9C /* AlertEntry.swift */,
 				19B0EF2028F6D66200069496 /* Statistics.swift */,
 				19012CDB291D2CB900FB8210 /* LoopStats.swift */,
-				19788CAE293CE0F0002FC264 /* GlucoseDataForStats.swift */,
 				FE41E4D329463C660047FD55 /* NightscoutStatistics.swift */,
 				FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */,
 			);
@@ -1360,6 +1359,7 @@
 		388E5A5A25B6F05F0019842D /* Helpers */ = {
 			isa = PBXGroup;
 			children = (
+				FEFA5C10299F814A00765C17 /* CoreDataStack.swift */,
 				38F37827261260DC009DB701 /* Color+Extensions.swift */,
 				389ECE042601144100D86C4F /* ConcurrentMap.swift */,
 				38192E0C261BAF980094D973 /* ConvenienceExtensions.swift */,
@@ -2289,6 +2289,7 @@
 				38A9260525F012D8009E3739 /* CarbRatios.swift in Sources */,
 				38FCF3D625E8FDF40078B0D1 /* MD5.swift in Sources */,
 				3871F39C25ED892B0013ECB5 /* TempTarget.swift in Sources */,
+				FEFA5C11299F814A00765C17 /* CoreDataStack.swift in Sources */,
 				3811DEAB25C9D88300A708ED /* HTTPResponseStatus.swift in Sources */,
 				3811DE5F25C9D4D500A708ED /* ProgressBar.swift in Sources */,
 				38E87408274F9AD000975559 /* UserNotificationsManager.swift in Sources */,
@@ -2360,6 +2361,7 @@
 				1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorStateModel.swift in Sources */,
 				F816826028DB441800054060 /* BluetoothTransmitter.swift in Sources */,
 				38192E0D261BAF980094D973 /* ConvenienceExtensions.swift in Sources */,
+				FEFA5C0F299F810B00765C17 /* Core_Data.xcdatamodeld in Sources */,
 				88AB39B23C9552BD6E0C9461 /* ISFEditorRootView.swift in Sources */,
 				F816825E28DB441200054060 /* HeartBeatManager.swift in Sources */,
 				38FEF413273B317A00574A46 /* HKUnit.swift in Sources */,
@@ -2376,7 +2378,6 @@
 				9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */,
 				38E8754F275556FA00975559 /* WatchManager.swift in Sources */,
 				A228DF96647338139F152B15 /* PreferencesEditorDataFlow.swift in Sources */,
-				19F79FA9283AE7E000646323 /* TDD.swift in Sources */,
 				389ECE052601144100D86C4F /* ConcurrentMap.swift in Sources */,
 				E4984C5262A90469788754BB /* PreferencesEditorProvider.swift in Sources */,
 				DD399FB31EACB9343C944C4C /* PreferencesEditorStateModel.swift in Sources */,
@@ -2402,7 +2403,6 @@
 				38E98A2D25F52DC400C0CED0 /* NSLocking+Extensions.swift in Sources */,
 				38569353270B5E350002C50D /* CGMRootView.swift in Sources */,
 				69A31254F2451C20361D172F /* BolusStateModel.swift in Sources */,
-				19788CAF293CE0F0002FC264 /* GlucoseDataForStats.swift in Sources */,
 				0CEA2EA070AB041AF3E3745B /* BolusRootView.swift in Sources */,
 				FEFFA7A22929FE49007B8193 /* UIDevice+Extensions.swift in Sources */,
 				F90692D3274B9A130037068D /* AppleHealthKitRootView.swift in Sources */,
@@ -2845,6 +2845,7 @@
 				PRODUCT_NAME = "${TARGET_NAME}";
 				SDKROOT = watchos;
 				SKIP_INSTALL = YES;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG RUN_STATISTICS";
 				SWIFT_EMIT_LOC_STRINGS = YES;
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = 4;
@@ -2884,6 +2885,7 @@
 				PRODUCT_NAME = "${TARGET_NAME}";
 				SDKROOT = watchos;
 				SKIP_INSTALL = YES;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = RUN_STATISTICS;
 				SWIFT_EMIT_LOC_STRINGS = YES;
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = 4;
@@ -3062,6 +3064,19 @@
 			productName = SwiftCharts;
 		};
 /* End XCSwiftPackageProductDependency section */
+
+/* Begin XCVersionGroup section */
+		FEFA5C0D299F810B00765C17 /* Core_Data.xcdatamodeld */ = {
+			isa = XCVersionGroup;
+			children = (
+				FEFA5C0E299F810B00765C17 /* Core_Data.xcdatamodel */,
+			);
+			currentVersion = FEFA5C0E299F810B00765C17 /* Core_Data.xcdatamodel */;
+			path = Core_Data.xcdatamodeld;
+			sourceTree = "<group>";
+			versionGroupType = wrapper.xcdatamodel;
+		};
+/* End XCVersionGroup section */
 	};
 	rootObject = 388E595025AD948C0019842D /* Project object */;
 }

+ 15 - 0
FreeAPS.xcworkspace/contents.xcworkspacedata

@@ -2,6 +2,21 @@
 <Workspace
    version = "1.0">
    <FileRef
+      location = "group:Readings+CoreDataClass.swift">
+   </FileRef>
+   <FileRef
+      location = "group:Readings+CoreDataProperties.swift">
+   </FileRef>
+   <FileRef
+      location = "group:TDD+CoreDataClass.swift">
+   </FileRef>
+   <FileRef
+      location = "group:TDD+CoreDataProperties.swift">
+   </FileRef>
+   <FileRef
+      location = "group:FreeAPS/Sources/Helpers/CoreDataStack.swift">
+   </FileRef>
+   <FileRef
       location = "group:FreeAPS.xcodeproj">
    </FileRef>
    <FileRef

+ 143 - 200
FreeAPS/Sources/APS/APSManager.swift

@@ -1,4 +1,6 @@
+// import Accelerate
 import Combine
+import CoreData
 import Foundation
 import LoopKit
 import LoopKitUI
@@ -78,6 +80,8 @@ final class BaseAPSManager: APSManager, Injectable {
         }
     }
 
+    let coredataContext = CoreDataStack.shared.persistentContainer.viewContext
+
     private var openAPS: OpenAPS!
 
     private var lifetime = Lifetime()
@@ -239,11 +243,6 @@ final class BaseAPSManager: APSManager, Injectable {
 
         loopStats(loopStatRecord: loopStatRecord)
 
-        // Create a statistics.json. Don't run in backgound
-        if settings.displayStatistics, UIApplication.shared.applicationState != .background {
-            statistics()
-        }
-
         if settings.closedLoop {
             reportEnacted(received: error == nil)
         }
@@ -662,9 +661,6 @@ final class BaseAPSManager: APSManager, Injectable {
 
             storage.save(enacted, as: OpenAPS.Enact.enacted)
 
-            // Create a tdd.json
-            tdd(enacted_: enacted)
-
             debug(.apsManager, "Suggestion enacted. Received: \(received)")
             DispatchQueue.main.async {
                 self.broadcaster.notify(EnactedSuggestionObserver.self, on: .main) {
@@ -672,63 +668,79 @@ final class BaseAPSManager: APSManager, Injectable {
                 }
             }
             nightscout.uploadStatus()
+
+            // Update the tdd.json
+            tdd(enacted_: enacted)
+            // Update statistics.json. Only run if enabled in preferences
+            if settingsManager.settings.displayStatistics {
+                statistics()
+            }
         }
     }
 
     private func tdd(enacted_: Suggestion) {
+        let tddStartedAt = Date()
         // Add to tdd.json:
         let preferences = settingsManager.preferences
         let currentTDD = enacted_.tdd ?? 0
-        let file = OpenAPS.Monitor.tdd
-        let tdd = TDD(
-            TDD: currentTDD,
-            timestamp: Date(),
-            id: UUID().uuidString
-        )
+
+        // MARK: Add new data to Core Data:TDD Entity. TEST:
+        debug(.apsManager, "Writing TDD to CoreData")
+
+        let nTDD = TDD(context: coredataContext)
+        nTDD.timestamp = Date()
+        nTDD.tdd = NSDecimalNumber(decimal: currentTDD)
+        
+        try? coredataContext.save()
+        
+        let twoWeeksAgo = Date().addingTimeInterval(-14.days.timeInterval)
+        let twoHoursAgo = Date().addingTimeInterval(-2.hours.timeInterval)
+        let requestTDD = TDD.fetchRequest() as NSFetchRequest<TDD>
+        requestTDD.predicate = NSPredicate(format: "timestamp > %@ AND tdd > 0", twoWeeksAgo as NSDate)
         var uniqEvents: [TDD] = []
-        storage.transaction { storage in
-            storage.append(tdd, to: file, uniqBy: \.id)
-            uniqEvents = storage.retrieve(file, as: [TDD].self)?
-                .filter { $0.timestamp.addingTimeInterval(14.days.timeInterval) > Date() }
-                .sorted { $0.timestamp > $1.timestamp } ?? []
-            var total: Decimal = 0
-            var indeces: Decimal = 0
-            for uniqEvent in uniqEvents {
-                if uniqEvent.TDD > 0 {
-                    total += uniqEvent.TDD
-                    indeces += 1
-                }
-            }
-            let entriesPast2hours = storage.retrieve(file, as: [TDD].self)?
-                .filter { $0.timestamp.addingTimeInterval(2.hours.timeInterval) > Date() }
-                .sorted { $0.timestamp > $1.timestamp } ?? []
-            var totalAmount: Decimal = 0
-            var nrOfIndeces: Decimal = 0
-            for entry in entriesPast2hours {
-                if entry.TDD > 0 {
-                    totalAmount += entry.TDD
-                    nrOfIndeces += 1
-                }
-            }
-            if indeces == 0 {
-                indeces = 1
-            }
-            if nrOfIndeces == 0 {
-                nrOfIndeces = 1
+
+        try? uniqEvents = coredataContext.fetch(requestTDD)
+
+        var total: Decimal = 0
+        var indeces: Decimal = 0
+        for uniqEvent in uniqEvents {
+            debug(.apsManager, "Read TDD from CoreData: \(uniqEvent.tdd!.decimalValue)")
+            total += uniqEvent.tdd!.decimalValue
+            indeces += 1
+        }
+
+        requestTDD.predicate = NSPredicate(format: "timestamp > %@ AND tdd > 0", twoHoursAgo as NSDate)
+        var entriesPast2hours: [TDD] = []
+
+        try? entriesPast2hours = coredataContext.fetch(requestTDD)
+
+        var totalAmount: Decimal = 0
+        var nrOfIndeces: Decimal = 0
+        for entry in entriesPast2hours {
+            if (entry.tdd?.decimalValue ?? 0) > 0 {
+                totalAmount += entry.tdd?.decimalValue ?? 0
+                nrOfIndeces += 1
             }
-            let average14 = total / indeces
-            let average2hours = totalAmount / nrOfIndeces
-            let weight = preferences.weightPercentage
-            let weighted_average = weight * average2hours + (1 - weight) * average14
-            let averages = TDD_averages(
-                average_total_data: roundDecimal(average14, 1),
-                weightedAverage: roundDecimal(weighted_average, 1),
-                past2hoursAverage: roundDecimal(average2hours, 1),
-                date: Date()
-            )
-            storage.save(averages, as: OpenAPS.Monitor.tdd_averages)
-            storage.save(Array(uniqEvents), as: file)
         }
+
+        if indeces == 0 {
+            indeces = 1
+        }
+        if nrOfIndeces == 0 {
+            nrOfIndeces = 1
+        }
+        let average14 = total / indeces
+        let average2hours = totalAmount / nrOfIndeces
+        let weight = preferences.weightPercentage
+        let weighted_average = weight * average2hours + (1 - weight) * average14
+        let averages = TDD_averages(
+            average_total_data: roundDecimal(average14, 1),
+            weightedAverage: roundDecimal(weighted_average, 1),
+            past2hoursAverage: roundDecimal(average2hours, 1),
+            date: Date()
+        )
+        storage.save(averages, as: OpenAPS.Monitor.tdd_averages)
+        print("Test time of TDD: \(-1 * tddStartedAt.timeIntervalSinceNow) s")
     }
 
     private func roundDecimal(_ decimal: Decimal, _ digits: Double) -> Decimal {
@@ -756,16 +768,15 @@ final class BaseAPSManager: APSManager, Injectable {
 
     // Add to statistics.JSON
     private func statistics() {
+        let statisticsStartedAt = Date()
         var testFile: [Statistics] = []
         var testIfEmpty = 0
         storage.transaction { storage in
             testFile = storage.retrieve(OpenAPS.Monitor.statistics, as: [Statistics].self) ?? []
             testIfEmpty = testFile.count
         }
-
         let updateThisOften = Int(settingsManager.preferences.updateInterval)
-
-        // Only run every 30 minutesl
+        // Only run every 30 minutes of according to setting.
         if testIfEmpty != 0 {
             guard testFile[0].created_at.addingTimeInterval(updateThisOften.minutes.timeInterval) < Date()
             else {
@@ -776,22 +787,23 @@ final class BaseAPSManager: APSManager, Injectable {
         let units = settingsManager.settings.units
         let preferences = settingsManager.preferences
         let carbs = storage.retrieve(OpenAPS.Monitor.carbHistory, as: [CarbsEntry].self)
-        let tdds = storage.retrieve(OpenAPS.Monitor.tdd, as: [TDD].self)
+
+        let requestTDD = TDD.fetchRequest() as NSFetchRequest<TDD>
+        requestTDD.predicate = NSPredicate(format: "tdd > 0")
+        requestTDD.fetchLimit = 1
+        let sort = NSSortDescriptor(key: "timestamp", ascending: false)
+        requestTDD.sortDescriptors = [sort]
+
+        var tdds: [TDD] = []
+        try? tdds = coredataContext.fetch(requestTDD)
+
         var currentTDD: Decimal = 0
-        if tdds?.count ?? 0 > 0 {
-            currentTDD = tdds?[0].TDD ?? 0
-        }
-        let carbs_length = carbs?.count ?? 0
-        var carbTotal: Decimal = 0
-        if carbs_length != 0 {
-            for each in carbs! {
-                if each.carbs != 0 {
-                    carbTotal += each.carbs
-                }
-            }
+        if tdds.count == 1 {
+            currentTDD = tdds[0].tdd?.decimalValue ?? 0
         }
-        var algo_ = "Oref0"
 
+        var algo_ = "Oref0"
+        let carbTotal = carbs?.map({ carbs in carbs.carbs }).reduce(0, +) ?? 0
         if preferences.sigmoid, preferences.enableDynamicCR {
             algo_ = "Dynamic ISF + CR: Sigmoid"
         } else if preferences.sigmoid, !preferences.enableDynamicCR {
@@ -842,11 +854,9 @@ final class BaseAPSManager: APSManager, Injectable {
 
         if !lsData.isEmpty {
             var i = 0.0
-
             if let loopEnd = lsData[0].end {
                 previousTimeLoop = loopEnd
             }
-
             for each in lsData {
                 if let loopEnd = each.end, let loopDuration = each.duration {
                     if each.loopStatus.contains("Success") {
@@ -855,36 +865,30 @@ final class BaseAPSManager: APSManager, Injectable {
                         errorNR += 1
                     }
                     i += 1
-
                     timeIntervalLoops = (previousTimeLoop - each.start).timeInterval / 60
+
                     if timeIntervalLoops > 0.0, i != 1 {
                         timeIntervalLoopArray.append(timeIntervalLoops)
                     }
-
                     if timeIntervalLoops > maximumInt {
                         maximumInt = timeIntervalLoops
                     }
                     if timeIntervalLoops < minimumInt, i != 1 {
                         minimumInt = timeIntervalLoops
                     }
-
                     timeForOneLoop = loopDuration
-
                     timeForOneLoopArray.append(timeForOneLoop)
                     averageLoopTime += timeForOneLoop
 
                     if timeForOneLoop >= maximumLoopTime, timeForOneLoop != 0.0 {
                         maximumLoopTime = timeForOneLoop
                     }
-
                     if timeForOneLoop <= minimumLoopTime, timeForOneLoop != 0.0 {
                         minimumLoopTime = timeForOneLoop
                     }
-
                     previousTimeLoop = loopEnd
                 }
             }
-
             successRate = (successNR / Double(i)) * 100
             averageIntervalLoops = ((lsData[0].end ?? lsData[lsData.count - 1].start) - lsData[lsData.count - 1].start)
                 .timeInterval / 60 / Double(i)
@@ -899,71 +903,73 @@ final class BaseAPSManager: APSManager, Injectable {
         if minimumLoopTime == 9999.0 {
             minimumLoopTime = 0.0
         }
+
+        let requestGFS = Readings.fetchRequest() as NSFetchRequest<Readings>
+        let sortGlucose = NSSortDescriptor(key: "date", ascending: true)
+        requestGFS.sortDescriptors = [sortGlucose]
+
+        var glucose: [Readings] = []
+        try? glucose = coredataContext.fetch(requestGFS)
+
+        let firstElementTime = glucose.first?.date ?? Date()
+        let lastElementTime = glucose.last?.date ?? Date()
+        let numberOfDays = (lastElementTime - firstElementTime).timeInterval / 8.64E4
+        
         // Time In Range (%) and Average Glucose (24 hours). This will be refactored later after some testing.
-        let glucose = storage.retrieve(OpenAPS.Monitor.glucose_data, as: [GlucoseDataForStats].self)
-        let length_ = glucose?.count ?? 0
+        let length_ = glucose.count
         let endIndex = length_ - 1
         var bg: Decimal = 0
+
         var bgArray: [Double] = []
         var bgArray_1_: [Double] = []
         var bgArray_7_: [Double] = []
         var bgArray_30_: [Double] = []
+
         var bgArrayForTIR: [(bg_: Double, date_: Date)] = []
         var bgArray_1: [(bg_: Double, date_: Date)] = []
         var bgArray_7: [(bg_: Double, date_: Date)] = []
         var bgArray_30: [(bg_: Double, date_: Date)] = []
+
         var medianBG = 0.0
         var nr_bgs: Decimal = 0
-        var nr_bgs_1: Decimal = 0
-        var nr_bgs_7: Decimal = 0
-        var nr_bgs_30: Decimal = 0
 
         var startDate = Date("1978-02-22T11:43:54.659Z")
         if endIndex >= 0 {
-            startDate = glucose?[0].date
+            startDate = glucose[0].date
         }
-        var end1 = false
-        var end7 = false
-        var end30 = false
         var bg_1: Decimal = 0
         var bg_7: Decimal = 0
         var bg_30: Decimal = 0
         var bg_total: Decimal = 0
         var j = -1
+        var conversionFactor: Decimal = 1
+        if units == .mmolL {
+            conversionFactor = 0.0555
+        }
 
         // Make arrays for median calculations and calculate averages
         if endIndex >= 0 {
-            for entry in glucose! {
+            for entry in glucose {
                 j += 1
                 if entry.glucose > 0 {
-                    bg += Decimal(entry.glucose)
-                    bgArray.append(Double(entry.glucose))
-                    bgArrayForTIR.append((Double(entry.glucose), entry.date))
+                    bg += Decimal(entry.glucose) * conversionFactor
+                    bgArray.append(Double(entry.glucose) * Double(conversionFactor))
+                    bgArrayForTIR.append((Double(entry.glucose), entry.date!))
                     nr_bgs += 1
-
-                    if (startDate! - entry.date).timeInterval >= 8.64E4, !end1 {
-                        end1 = true
+                    if (startDate! - entry.date!).timeInterval <= 24.hours.timeInterval {
                         bg_1 = bg / nr_bgs
                         bgArray_1 = bgArrayForTIR
                         bgArray_1_ = bgArray
-                        nr_bgs_1 = nr_bgs
-                        // time_1 = ((startDate ?? Date()) - entry.date).timeInterval
                     }
-                    if (startDate! - entry.date).timeInterval >= 6.048E5, !end7 {
-                        end7 = true
+                    if (startDate! - entry.date!).timeInterval <= 7.days.timeInterval {
                         bg_7 = bg / nr_bgs
                         bgArray_7 = bgArrayForTIR
                         bgArray_7_ = bgArray
-                        nr_bgs_7 = nr_bgs
-                        // time_7 = ((startDate ?? Date()) - entry.date).timeInterval
                     }
-                    if (startDate! - entry.date).timeInterval >= 2.592E6, !end30 {
-                        end30 = true
+                    if (startDate! - entry.date!).timeInterval <= 30.days.timeInterval {
                         bg_30 = bg / nr_bgs
                         bgArray_30 = bgArrayForTIR
                         bgArray_30_ = bgArray
-                        nr_bgs_30 = nr_bgs
-                        // time_30 = ((startDate ?? Date()) - entry.date).timeInterval
                     }
                 }
             }
@@ -972,25 +978,10 @@ final class BaseAPSManager: APSManager, Injectable {
         if nr_bgs > 0 {
             // Up to 91 days
             bg_total = bg / nr_bgs
-
-            // If less then 24 hours of glucose data, use total instead
-            if bg_1 == 0 {
-                bg_1 = bg_total
-                bgArray_1 = bgArrayForTIR
-                end1 = true
-                nr_bgs_1 = nr_bgs
-            }
         }
 
         // Total median
         medianBG = medianCalculation(array: bgArray)
-        var daysBG = 0.0
-        var fullTime = 0.0
-
-        if length_ > 0 {
-            fullTime = (startDate! - glucose![endIndex].date).timeInterval
-            daysBG = fullTime / 8.64E4
-        }
 
         func tir(_ array: [(bg_: Double, date_: Date)]) -> (TIR: Double, hypos: Double, hypers: Double) {
             var timeInHypo = 0.0
@@ -1000,24 +991,20 @@ final class BaseAPSManager: APSManager, Injectable {
             var i = -1
             var lastIndex = false
             let endIndex = array.count - 1
-
             var hypoLimit = settingsManager.preferences.low
             var hyperLimit = settingsManager.preferences.high
             if units == .mmolL {
                 hypoLimit = hypoLimit / 0.0555
                 hyperLimit = hyperLimit / 0.0555
             }
-
             var full_time = 0.0
             if endIndex > 0 {
                 full_time = (array[0].date_ - array[endIndex].date_).timeInterval
             }
-
             while i < endIndex {
                 i += 1
                 let currentTime = array[i].date_
                 var previousTime = currentTime
-
                 if i + 1 <= endIndex {
                     previousTime = array[i + 1].date_
                 } else {
@@ -1044,43 +1031,40 @@ final class BaseAPSManager: APSManager, Injectable {
         // HbA1c estimation (%, mmol/mol) 1 day
         var NGSPa1CStatisticValue: Decimal = 0.0
         var IFCCa1CStatisticValue: Decimal = 0.0
-        if end1, bg_1 > 0 {
-            NGSPa1CStatisticValue = (46.7 + bg_1) / 28.7 // NGSP (%)
+        if nr_bgs > 0 {
+            NGSPa1CStatisticValue = ((bg_1 / conversionFactor) + 46.7) / 28.7 // NGSP (%)
             IFCCa1CStatisticValue = 10.929 *
                 (NGSPa1CStatisticValue - 2.152) // IFCC (mmol/mol)  A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
         }
         // 7 days
         var NGSPa1CStatisticValue_7: Decimal = 0.0
         var IFCCa1CStatisticValue_7: Decimal = 0.0
-        if end7 {
-            NGSPa1CStatisticValue_7 = (46.7 + bg_7) / 28.7 // NGSP (%)
-            IFCCa1CStatisticValue_7 = 10.929 *
-                (NGSPa1CStatisticValue_7 - 2.152) // IFCC (mmol/mol)  A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
+        if nr_bgs > 0 {
+            NGSPa1CStatisticValue_7 = ((bg_7 / conversionFactor) + 46.7) / 28.7
+            IFCCa1CStatisticValue_7 = 10.929 * (NGSPa1CStatisticValue_7 - 2.152)
         }
         // 30 days
         var NGSPa1CStatisticValue_30: Decimal = 0.0
         var IFCCa1CStatisticValue_30: Decimal = 0.0
-        if end30 {
-            NGSPa1CStatisticValue_30 = (46.7 + bg_30) / 28.7 // NGSP (%)
-            IFCCa1CStatisticValue_30 = 10.929 *
-                (NGSPa1CStatisticValue_30 - 2.152) // IFCC (mmol/mol)  A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
+        if nr_bgs > 0 {
+            NGSPa1CStatisticValue_30 = ((bg_30 / conversionFactor) + 46.7) / 28.7
+            IFCCa1CStatisticValue_30 = 10.929 * (NGSPa1CStatisticValue_30 - 2.152)
         }
         // Total days
         var NGSPa1CStatisticValue_total: Decimal = 0.0
         var IFCCa1CStatisticValue_total: Decimal = 0.0
         if nr_bgs > 0 {
-            NGSPa1CStatisticValue_total = (46.7 + bg_total) / 28.7 // NGSP (%)
+            NGSPa1CStatisticValue_total = ((bg_total / conversionFactor) + 46.7) / 28.7
             IFCCa1CStatisticValue_total = 10.929 *
-                (NGSPa1CStatisticValue_total - 2.152) // IFCC (mmol/mol)  A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
+                (NGSPa1CStatisticValue_total - 2.152)
         }
 
-        var median = Durations(
-            day: roundDecimal(Decimal(medianCalculation(array: bgArray_1.map(\.bg_))), 1),
-            week: roundDecimal(Decimal(medianCalculation(array: bgArray_7.map(\.bg_))), 1),
-            month: roundDecimal(Decimal(medianCalculation(array: bgArray_30.map(\.bg_))), 1),
+        let median = Durations(
+            day: roundDecimal(Decimal(medianCalculation(array: bgArray_1_)), 1),
+            week: roundDecimal(Decimal(medianCalculation(array: bgArray_7_)), 1),
+            month: roundDecimal(Decimal(medianCalculation(array: bgArray_30_)), 1),
             total: roundDecimal(Decimal(medianBG), 1)
         )
-
         var hbs = Durations(
             day: roundDecimal(NGSPa1CStatisticValue, 1),
             week: roundDecimal(NGSPa1CStatisticValue_7, 1),
@@ -1090,20 +1074,7 @@ final class BaseAPSManager: APSManager, Injectable {
 
         // Convert to user-preferred unit
         let overrideHbA1cUnit = settingsManager.preferences.overrideHbA1cUnit
-
         if units == .mmolL {
-            bg_1 = bg_1.asMmolL
-            bg_7 = bg_7.asMmolL
-            bg_30 = bg_30.asMmolL
-            bg_total = bg_total.asMmolL
-
-            median = Durations(
-                day: roundDecimal(Decimal(medianCalculation(array: bgArray_1.map(\.bg_))).asMmolL, 1),
-                week: roundDecimal(Decimal(medianCalculation(array: bgArray_7.map(\.bg_))).asMmolL, 1),
-                month: roundDecimal(Decimal(medianCalculation(array: bgArray_30.map(\.bg_))).asMmolL, 1),
-                total: roundDecimal(Decimal(medianBG).asMmolL, 1)
-            )
-
             // Override if users sets overrideHbA1cUnit: true
             if !overrideHbA1cUnit {
                 hbs = Durations(
@@ -1122,9 +1093,6 @@ final class BaseAPSManager: APSManager, Injectable {
             )
         }
 
-        // round output values
-        daysBG = roundDouble(daysBG, 1)
-
         let glucose24Hours = storage.retrieve(OpenAPS.Monitor.glucose, as: [BloodGlucose].self)
         let nrOfCGMReadings = glucose24Hours?.count ?? 0
 
@@ -1150,16 +1118,10 @@ final class BaseAPSManager: APSManager, Injectable {
         var totalDays_: (TIR: Double, hypos: Double, hypers: Double) = (0.0, 0.0, 0.0)
 
         // Get all TIR calcs for every case
-        if end1 {
+        if nr_bgs > 0 {
             oneDay_ = tir(bgArray_1)
-        }
-        if end7 {
             sevenDays_ = tir(bgArray_7)
-        }
-        if end30 {
             thirtyDays_ = tir(bgArray_30)
-        }
-        if nr_bgs > 0 {
             totalDays_ = tir(bgArrayForTIR)
         }
 
@@ -1204,8 +1166,6 @@ final class BaseAPSManager: APSManager, Injectable {
             scheduled_basal: suggestion?.insulin?.scheduled_basal ?? 0
         )
 
-        // SD and CV calculations for all durations:
-
         var sumOfSquares: Decimal = 0
         var sumOfSquares_1: Decimal = 0
         var sumOfSquares_7: Decimal = 0
@@ -1213,27 +1173,19 @@ final class BaseAPSManager: APSManager, Injectable {
 
         // Total
         for array in bgArray {
-            if units == .mmolL {
-                sumOfSquares += pow(Decimal(array).asMmolL - bg_total, 2)
-            } else { sumOfSquares += pow(Decimal(array) - bg_total, 2) }
+            sumOfSquares += pow(Decimal(array) - bg_total, 2)
         }
         // One day
         for array_1 in bgArray_1_ {
-            if units == .mmolL {
-                sumOfSquares_1 += pow(Decimal(array_1).asMmolL - bg_1, 2)
-            } else { sumOfSquares_1 += pow(Decimal(array_1) - bg_1, 2) }
+            sumOfSquares_1 += pow(Decimal(array_1) - bg_1, 2)
         }
         // week
         for array_7 in bgArray_7_ {
-            if units == .mmolL {
-                sumOfSquares_7 += pow(Decimal(array_7).asMmolL - bg_7, 2)
-            } else { sumOfSquares_7 += pow(Decimal(array_7) - bg_7, 2) }
+            sumOfSquares_7 += pow(Decimal(array_7) - bg_7, 2)
         }
         // month
         for array_30 in bgArray_30_ {
-            if units == .mmolL {
-                sumOfSquares_30 += pow(Decimal(array_30).asMmolL - bg_30, 2)
-            } else { sumOfSquares_30 += pow(Decimal(array_30) - bg_30, 2) }
+            sumOfSquares_30 += pow(Decimal(array_30) - bg_30, 2)
         }
 
         // Standard deviation and Coefficient of variation
@@ -1247,27 +1199,20 @@ final class BaseAPSManager: APSManager, Injectable {
         var cv_30 = 0.0
 
         // Avoid division by zero
-        if avgs.total < 1 || nr_bgs < 1 { sd_total = 0
-            cv_total = 0 } else {
+        if bg_total > 0 {
             sd_total = sqrt(Double(sumOfSquares / nr_bgs))
             cv_total = sd_total / Double(bg_total) * 100
         }
-        if avgs.day < 1 || nr_bgs_1 < 1 {
-            sd_1 = 0
-            cv_1 = 0
-        } else {
-            sd_1 = sqrt(Double(sumOfSquares_1 / nr_bgs_1))
+        if bg_1 > 0 {
+            sd_1 = sqrt(Double(sumOfSquares_1) / Double(bgArray_1_.count))
             cv_1 = sd_1 / Double(bg_1) * 100
         }
-        if avgs.week < 1 || nr_bgs_7 < 1 {
-            sd_7 = 0
-            cv_7 = 0
-        } else {
-            sd_7 = sqrt(Double(sumOfSquares_7 / nr_bgs_7))
+        if bg_7 > 0 {
+            sd_7 = sqrt(Double(sumOfSquares_7) / Double(bgArray_7_.count))
             cv_7 = sd_7 / Double(bg_7) * 100
         }
-        if avgs.month < 1 || nr_bgs_30 < 1 { sd_30 = 0
-            cv_30 = 0 } else { sd_30 = sqrt(Double(sumOfSquares_30 / nr_bgs_30))
+        if bg_30 > 0 {
+            sd_30 = sqrt(Double(sumOfSquares_30) / Double(bgArray_30_.count))
             cv_30 = sd_30 / Double(bg_30) * 100
         }
 
@@ -1305,7 +1250,7 @@ final class BaseAPSManager: APSManager, Injectable {
             insulinType: insulin_type.rawValue,
             peakActivityTime: iPa,
             Carbs_24h: carbTotal,
-            GlucoseStorage_Days: Decimal(daysBG),
+            GlucoseStorage_Days: Decimal(roundDouble(numberOfDays, 1)),
             Statistics: Stats(
                 Distribution: TimeInRange,
                 Glucose: avg,
@@ -1318,30 +1263,28 @@ final class BaseAPSManager: APSManager, Injectable {
 
         storage.transaction { storage in
             storage.append(dailystat, to: file, uniqBy: \.created_at)
-            var uniqeEvents: [Statistics] = storage.retrieve(file, as: [Statistics].self)?
+            let uniqeEvents: [Statistics] = storage.retrieve(file, as: [Statistics].self)?
                 .filter { $0.created_at.addingTimeInterval(24.hours.timeInterval) > Date() }
                 .sorted { $0.created_at > $1.created_at } ?? []
-
             storage.save(Array(uniqeEvents), as: file)
         }
-
         nightscout.uploadStatistics(dailystat: dailystat)
         nightscout.uploadPreferences()
+        print("Test time of statistics computation: \(-1 * statisticsStartedAt.timeIntervalSinceNow) s")
     }
 
     private func loopStats(loopStatRecord: LoopStats) {
+        let LoopStatsStartedAt = Date()
         let file = OpenAPS.Monitor.loopStats
-
         var uniqEvents: [LoopStats] = []
-
         storage.transaction { storage in
             storage.append(loopStatRecord, to: file, uniqBy: \.start)
             uniqEvents = storage.retrieve(file, as: [LoopStats].self)?
                 .filter { $0.start.addingTimeInterval(24.hours.timeInterval) > Date() }
                 .sorted { $0.start > $1.start } ?? []
-
             storage.save(Array(uniqEvents), as: file)
         }
+        print("Test time of LoopStats computation: \(-1 * LoopStatsStartedAt.timeIntervalSinceNow) s")
     }
 
     private func processError(_ error: Error) {

+ 1 - 1
FreeAPS/Sources/APS/OpenAPS/Constants.swift

@@ -59,7 +59,7 @@ extension OpenAPS {
         static let alertHistory = "monitor/alerthistory.json"
         static let statistics = "monitor/statistics.json"
         static let loopStats = "monitor/loopStats.json"
-        static let glucose_data = "monitor/glucoseForStats.json"
+        static let glucose_data = "monitor/glucose_data.json"
     }
 
     enum Enact {

+ 13 - 8
FreeAPS/Sources/APS/Storage/GlucoseStorage.swift

@@ -1,4 +1,5 @@
 import AVFAudio
+import CoreData
 import Foundation
 import SwiftDate
 import SwiftUI
@@ -24,6 +25,8 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
     @Injected() private var broadcaster: Broadcaster!
     @Injected() private var settingsManager: SettingsManager!
 
+    let coredataContext = CoreDataStack.shared.persistentContainer.viewContext
+
     private enum Config {
         static let filterTime: TimeInterval = 4.5 * 60
     }
@@ -33,10 +36,13 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
     }
 
     func storeGlucose(_ glucose: [BloodGlucose]) {
+        let storeGlucoseStarted = Date()
+
         processQueue.sync {
             let file = OpenAPS.Monitor.glucose
             self.storage.transaction { storage in
                 storage.append(glucose, to: file, uniqBy: \.dateString)
+
                 let uniqEvents = storage.retrieve(file, as: [BloodGlucose].self)?
                     .filter { $0.dateString.addingTimeInterval(24.hours.timeInterval) > Date() }
                     .sorted { $0.dateString > $1.dateString } ?? []
@@ -49,7 +55,8 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
                     }
                 }
 
-                // Save to glucoseForStats also.
+                // MARK: Save to CoreData. TEST
+
                 var bg_ = 0
                 var bgDate = Date()
 
@@ -58,13 +65,10 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
                     bgDate = glucose[0].dateString
                 }
                 if bg_ != 0 {
-                    let dataForStats = GlucoseDataForStats(date: bgDate, glucose: bg_)
-                    storage.append(dataForStats, to: OpenAPS.Monitor.glucose_data, uniqBy: \.date)
-                    let uniqEvents_1 = storage.retrieve(OpenAPS.Monitor.glucose_data, as: [GlucoseDataForStats].self)?
-                        .filter { $0.date.addingTimeInterval(90.days.timeInterval) > Date() }
-                        .sorted { $0.date > $1.date } ?? []
-                    let dataForStats_ = Array(uniqEvents_1)
-                    storage.save(dataForStats_, as: OpenAPS.Monitor.glucose_data)
+                    let dataForStats = Readings(context: coredataContext)
+                    dataForStats.date = bgDate
+                    dataForStats.glucose = Int16(bg_)
+                    try! coredataContext.save()
                 }
             }
 
@@ -122,6 +126,7 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
                 }
             }
         }
+        print("Test time of glucoseStorage: \(-1 * storeGlucoseStarted.timeIntervalSinceNow) s")
     }
 
     func removeGlucose(ids: [String]) {

+ 33 - 0
FreeAPS/Sources/Helpers/CoreDataStack.swift

@@ -0,0 +1,33 @@
+import CoreData
+import Foundation
+
+class CoreDataStack {
+    private init() {}
+
+    static let shared = CoreDataStack()
+
+    lazy var persistentContainer: NSPersistentContainer = {
+        let container = NSPersistentContainer(name: "Core_Data")
+
+        container.loadPersistentStores(completionHandler: { _, error in
+            guard let error = error as NSError? else { return }
+            fatalError("Unresolved error: \(error), \(error.userInfo)")
+        })
+
+        return container
+    }()
+
+    func saveContext() {
+        let context = persistentContainer.viewContext
+        if context.hasChanges {
+            do {
+                try context.save()
+            } catch {
+                // Replace this implementation with code to handle the error appropriately.
+                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
+                let nserror = error as NSError
+                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
+            }
+        }
+    }
+}

+ 0 - 6
FreeAPS/Sources/Models/GlucoseDataForStats.swift

@@ -1,6 +0,0 @@
-import Foundation
-
-struct GlucoseDataForStats: JSON {
-    let date: Date
-    var glucose: Int
-}

+ 0 - 25
FreeAPS/Sources/Models/TDD.swift

@@ -1,25 +0,0 @@
-import Foundation
-
-struct TDD: JSON, Equatable {
-    var TDD: Decimal
-    var timestamp: Date
-    let id: String
-
-    init(
-        TDD: Decimal,
-        timestamp: Date,
-        id: String
-    ) {
-        self.TDD = TDD
-        self.timestamp = timestamp
-        self.id = id
-    }
-}
-
-extension TDD {
-    private enum CodingKeys: String, CodingKey {
-        case TDD
-        case timestamp
-        case id
-    }
-}

+ 0 - 6
FreeAPSWatch WatchKit Extension/Info.plist

@@ -2,12 +2,6 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-	<key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
-	<string>Bla bla Record Health</string>
-	<key>NSHealthShareUsageDescription</key>
-	<string>Bla bla Share Health</string>
-	<key>NSHealthUpdateUsageDescription</key>
-	<string>Bla bla Update Health</string>
 	<key>NSExtension</key>
 	<dict>
 		<key>NSExtensionAttributes</key>

+ 4 - 0
Readings+CoreDataClass.swift

@@ -0,0 +1,4 @@
+import CoreData
+import Foundation
+
+@objc(Readings) public class Readings: NSManagedObject {}

+ 11 - 0
Readings+CoreDataProperties.swift

@@ -0,0 +1,11 @@
+import CoreData
+import Foundation
+
+public extension Readings {
+    @nonobjc class func fetchRequest() -> NSFetchRequest<Readings> {
+        NSFetchRequest<Readings>(entityName: "Readings")
+    }
+
+    @NSManaged var date: Date?
+    @NSManaged var glucose: Int16
+}

+ 4 - 0
TDD+CoreDataClass.swift

@@ -0,0 +1,4 @@
+import CoreData
+import Foundation
+
+@objc(TDD) public class TDD: NSManagedObject {}

+ 11 - 0
TDD+CoreDataProperties.swift

@@ -0,0 +1,11 @@
+import CoreData
+import Foundation
+
+public extension TDD {
+    @nonobjc class func fetchRequest() -> NSFetchRequest<TDD> {
+        NSFetchRequest<TDD>(entityName: "TDD")
+    }
+
+    @NSManaged var tdd: NSDecimalNumber?
+    @NSManaged var timestamp: Date?
+}