Loop share changes : get latest readings with timestamp > latest share. To make sure that's there's always 60 readings shared, the shared readings are stored in userdefaults (as array of dictionary), and will be reused next time that one or more new readings are shared. This will allow to update readings in coredata (due to smoothing algorithms), but still sharing the older values with Loop, and still making sure there's always 60 readings shared

This commit is contained in:
Johan Degraeve 2020-12-27 23:56:13 +01:00
parent efda0d9742
commit e1a9c04eb5
5 changed files with 62 additions and 26 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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<String, Any>]? {
get {
return object(forKey: Key.readingsStoredInSharedUserDefaultsAsDictionary.rawValue) as? [Dictionary<String, Any>]
}
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

View File

@ -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<String, Any>]()
@ -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
}
}

View File

@ -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()
}
}