diff --git a/xDrip4iOS Widget/xDripClient/XDripClient.swift b/xDrip4iOS Widget/xDripClient/XDripClient.swift index e35dd12e..d50a158a 100644 --- a/xDrip4iOS Widget/xDripClient/XDripClient.swift +++ b/xDrip4iOS Widget/xDripClient/XDripClient.swift @@ -30,7 +30,7 @@ public class XDripClient { private func fetchLastWithRetries(_ n: Int, remaining: Int, callback: @escaping (ClientError?, [Glucose]?) -> Void) { do { - guard let sharedData = shared?.data(forKey: "latestReadings-widget") else { + guard let sharedData = shared?.data(forKey: "latestReadings") else { throw ClientError.fetchError } diff --git a/xdrip/Constants/ConstantsShareWithLoop.swift b/xdrip/Constants/ConstantsShareWithLoop.swift index 1bd0bc52..7c93cd5b 100644 --- a/xdrip/Constants/ConstantsShareWithLoop.swift +++ b/xdrip/Constants/ConstantsShareWithLoop.swift @@ -3,9 +3,6 @@ import Foundation enum ConstantsShareWithLoop { /// maximum number of readings to share with Loop - static let maxReadingsToShareWithLoop = 12 + static let maxReadingsToShareWithLoop = 60 - /// if the time between the last and last but one reading is less than minimiumTimeBetweenTwoReadingsInMinutes, then the reading will not be shared with loop - except if there's been a disconnect in between these two readings - static let minimiumTimeBetweenTwoReadingsInMinutes = 4.75 - } diff --git a/xdrip/Extensions/UserDefaults.swift b/xdrip/Extensions/UserDefaults.swift index df3b4071..778e6b71 100644 --- a/xdrip/Extensions/UserDefaults.swift +++ b/xdrip/Extensions/UserDefaults.swift @@ -198,6 +198,13 @@ extension UserDefaults { /// timestamp of latest reading uploaded to Dexcom Share case timeStampLatestDexcomShareUploadedBgReading = "timeStampLatestDexcomShareUploadedBgReading" + // Loop + /// dictionary representation of readings that were shared with Loop. This is not the json representation, it's an array of dictionary + case readingsStoredInSharedUserDefaultsAsDictionary = "readingsStoredInSharedUserDefaultsAsDictionary" + + /// timestamp lastest reading shared with Loop + case timeStampLatestLoopSharedBgReading = "timeStampLatestLoopSharedBgReading" + // Trace /// should debug level logs be added in trace file or not, and also in NSLog case addDebugLevelLogsInTraceFileAndNSLog = "addDebugLevelLogsInTraceFileAndNSLog" @@ -1081,6 +1088,28 @@ extension UserDefaults { } } + // MARK: - ===== Loop Share Settings ====== + + /// dictionary representation of readings that were shared with Loop. This is not the json representation, it's an array of dictionary + var readingsStoredInSharedUserDefaultsAsDictionary: [Dictionary]? { + get { + return object(forKey: Key.readingsStoredInSharedUserDefaultsAsDictionary.rawValue) as? [Dictionary] + } + set { + set(newValue, forKey: Key.readingsStoredInSharedUserDefaultsAsDictionary.rawValue) + } + } + + /// timestamp lastest reading uploaded to NightScout + var timeStampLatestLoopSharedBgReading:Date? { + get { + return object(forKey: Key.timeStampLatestLoopSharedBgReading.rawValue) as? Date + } + set { + set(newValue, forKey: Key.timeStampLatestLoopSharedBgReading.rawValue) + } + } + // MARK: - ===== technical settings for testing ====== /// G6 factor 1 diff --git a/xdrip/Managers/Loop/LoopManager.swift b/xdrip/Managers/Loop/LoopManager.swift index 5ccc8de0..c8c7547a 100644 --- a/xdrip/Managers/Loop/LoopManager.swift +++ b/xdrip/Managers/Loop/LoopManager.swift @@ -37,14 +37,18 @@ public class LoopManager:NSObject { // MARK: - public functions /// share latest readings with Loop - /// - lastConnectionStatusChangeTimeStamp : when was the last transmitter dis/reconnect - if nil then 1 1 1970 is used - public func share(lastConnectionStatusChangeTimeStamp: Date?) { + public func share() { // unwrap sharedUserDefaults guard let sharedUserDefaults = sharedUserDefaults else {return} - // get last readings with calculated value, don't apply yet the filtering, we will first store for the widget unfiltered - var lastReadings = bgReadingsAccessor.getLatestBgReadings(limit: ConstantsShareWithLoop.maxReadingsToShareWithLoop, fromDate: nil, forSensor: nil, ignoreRawData: true, ignoreCalculatedValue: false) + // get last readings with calculated value + let lastReadings = bgReadingsAccessor.getLatestBgReadings(limit: ConstantsShareWithLoop.maxReadingsToShareWithLoop, fromDate: UserDefaults.standard.timeStampLatestLoopSharedBgReading, forSensor: nil, ignoreRawData: true, ignoreCalculatedValue: false) + + // if there's no readings, then no further processing + if lastReadings.count == 0 { + return + } // convert to json Dexcom Share format var dictionary = [Dictionary]() @@ -52,30 +56,36 @@ public class LoopManager:NSObject { dictionary.append(reading.dictionaryRepresentationForDexcomShareUpload) } - // to json - if let data = try? JSONSerialization.data(withJSONObject: dictionary) { - - // share to userDefaults for widget - if lastReadings.count > 0 { - sharedUserDefaults.set(data, forKey: "latestReadings-widget") + // get Dictionary stored in UserDefaults from previous session + // append readings already stored in this storedDictionary so that we get dictionary filled with maxReadingsToShareWithLoop readings, if possible + if let storedDictionary = UserDefaults.standard.readingsStoredInSharedUserDefaultsAsDictionary, storedDictionary.count > 0 { + + let maxAmountsOfReadingsToAppend = ConstantsShareWithLoop.maxReadingsToShareWithLoop - dictionary.count + + if maxAmountsOfReadingsToAppend > 0 { + + let rangeToAppend = 0..<(min(storedDictionary.count, maxAmountsOfReadingsToAppend)) + + for value in storedDictionary[rangeToAppend] { + + dictionary.append(value) + + } + } } - // applying minimumTimeBetweenTwoReadingsInMinutes filter, for loop - lastReadings = lastReadings.filter(minimumTimeBetweenTwoReadingsInMinutes: ConstantsShareWithLoop.minimiumTimeBetweenTwoReadingsInMinutes, lastConnectionStatusChangeTimeStamp: lastConnectionStatusChangeTimeStamp, timeStampLastProcessedBgReading: nil) - - // if there's no readings, then no further processing - if lastReadings.count == 0 { - return - } - guard let data = try? JSONSerialization.data(withJSONObject: dictionary) else { return } sharedUserDefaults.set(data, forKey: "latestReadings") + UserDefaults.standard.timeStampLatestLoopSharedBgReading = lastReadings.first!.timeStamp + + UserDefaults.standard.readingsStoredInSharedUserDefaultsAsDictionary = dictionary + } } diff --git a/xdrip/View Controllers/Root View Controller/RootViewController.swift b/xdrip/View Controllers/Root View Controller/RootViewController.swift index 604f2195..2fb61ec6 100644 --- a/xdrip/View Controllers/Root View Controller/RootViewController.swift +++ b/xdrip/View Controllers/Root View Controller/RootViewController.swift @@ -786,7 +786,7 @@ final class RootViewController: UIViewController { watchManager?.processNewReading(lastConnectionStatusChangeTimeStamp: lastConnectionStatusChangeTimeStamp()) - loopManager?.share(lastConnectionStatusChangeTimeStamp: lastConnectionStatusChangeTimeStamp()) + loopManager?.share() } } @@ -1092,7 +1092,7 @@ final class RootViewController: UIViewController { self.watchManager?.processNewReading(lastConnectionStatusChangeTimeStamp: self.lastConnectionStatusChangeTimeStamp()) // send also to loopmanager, not interesting for loop probably, but the data is also used for today widget - self.loopManager?.share(lastConnectionStatusChangeTimeStamp: self.lastConnectionStatusChangeTimeStamp()) + self.loopManager?.share() } @@ -1817,7 +1817,7 @@ extension RootViewController:NightScoutFollowerDelegate { bluetoothPeripheralManager?.sendLatestReading() // send also to loopmanager, not interesting for loop probably, but the data is also used for today widget - self.loopManager?.share(lastConnectionStatusChangeTimeStamp: lastConnectionStatusChangeTimeStamp()) + self.loopManager?.share() } }