diff --git a/xdrip/Extensions/Array.swift b/xdrip/Extensions/Array.swift index 61b92498..cfac13d6 100644 --- a/xdrip/Extensions/Array.swift +++ b/xdrip/Extensions/Array.swift @@ -121,56 +121,97 @@ extension Array where Element: GlucoseData { extension Array where Element: BgReading { /// - Filter out readings that are too close to each other - /// - BgReadings array must be sorted by timeStamp of the BgReading, ascending, ie youngest first + /// - BgReadings array must be sorted by timeStamp of the BgReading, ascending, ie most recent reading is at index 0 /// - parameters: /// - minimumTimeBetweenTwoReadingsInMinutes : filter out readings that are to close to each other in time, minimum difference in time between two readings = minimumTimeBetweenTwoReadingsInMinutes - /// - lastConnectionStatusChangeTimeStamp : lastConnectionStatusChangeTimeStamp > timeStampLastProcessedBgReading then the first connection will be returned, even if it's less than minimumTimeBetweenTwoReadingsInMinutes away from timeStampLastProcessedBgReading /// - timeStampLastProcessedBgReading : only readings younger than timeStampLastProcessedBgReading will be returned, if nil then this check is not done + /// - lastConnectionStatusChangeTimeStamp : if lastConnectionStatusChangeTimeStamp > timeStampLastProcessedBgReading then the most recent reading will be returned, even if it's less than minimumTimeBetweenTwoReadingsInMinutes away from timeStampLastProcessedBgReading /// - returns /// filtered array, with readings at least minimumTimeBetweenTwoReadingsInMinutes away from each other func filter(minimumTimeBetweenTwoReadingsInMinutes: Double, lastConnectionStatusChangeTimeStamp: Date?, timeStampLastProcessedBgReading: Date?) -> [BgReading] { - - var didCheckLastConnectionStatusChangeTimeStamp = false - var timeStampLatestCheckedReading = timeStampLastProcessedBgReading + // initialise returnValue with empty array + var returnValue = [BgReading]() - // create a copy of self, reversed, because the filter algorithm assumes the first is the oldest element, while self is order by youngest first - var arrayReversed = Array(self.reversed()) - - // do the required filtering - arrayReversed = arrayReversed.filter({ + // if most recent reading is either the minimum time away from the last processed reading or if there's been a disconnect after the last processed reading then add the most recent reading + // but first let's see if there's at least one reading + if let first = self.first { - if let lastConnectionStatusChangeTimeStamp = lastConnectionStatusChangeTimeStamp, let timeStampLastProcessedBgReading = timeStampLastProcessedBgReading, !didCheckLastConnectionStatusChangeTimeStamp { + if let timeStampLastProcessedBgReading = timeStampLastProcessedBgReading { - // if there was a disconnect or reconnect after the latest processed reading, and $0.timestamp (ie reading being processed) is after lastConnectionStatusChangeTimeStamp then add the reading - if lastConnectionStatusChangeTimeStamp.timeIntervalSince(timeStampLastProcessedBgReading) > 0.0 && lastConnectionStatusChangeTimeStamp.timeIntervalSince($0.timeStamp) < 0.0 { + if first.timeStamp.timeIntervalSince(timeStampLastProcessedBgReading) > minimumTimeBetweenTwoReadingsInMinutes * 60.0 { - timeStampLatestCheckedReading = $0.timeStamp + // most recent reading is more than minimumTimeBetweenTwoReadingsInMinutes later than last processed reading, so let's add it + returnValue.append(first) + + } else { + + // most recent reading is less than minimumTimeBetweenTwoReadingsInMinutes later than last processed reading, but maybe there's been a disconnect/reconnect since the last processed reading + if let lastConnectionStatusChangeTimeStamp = lastConnectionStatusChangeTimeStamp { + if lastConnectionStatusChangeTimeStamp.timeIntervalSince(timeStampLastProcessedBgReading) > 0 { - didCheckLastConnectionStatusChangeTimeStamp = true + // there's been a disconnect/reconnect since the last processed reading + // add the most recent reading + returnValue.append(first) + + } + + } + + } - return true + } else { + + // timeStampLastProcessedBgReading is nil, so this is the first reading being processed ever, let's add it + returnValue.append(first) + + } + + } + + // now let's see if first was added, and also if there's more readings to add + if returnValue.count > 0 { + + // there's one reading in returnValue, it's the most recent reading in the original array + + var timeStampLastAddedReading = returnValue[0].timeStamp + + // iterate through the remaining readings + for reading in self { + + // by checking id , we skip the first in self, because that one is already added + if reading.id != returnValue[0].id { + + // if the reading is earler than timeStampLastProcessedBgReading then no further processing needed, this reading and also the following readings are older readings, older than timeStampLastProcessedBgReading + if let timeStampLastProcessedBgReading = timeStampLastProcessedBgReading { + + if reading.timeStamp.timeIntervalSince(timeStampLastProcessedBgReading) < 0 { + + break + + } + + } + + // add the reading if + // - the reading is more than minimumTimeBetweenTwoReadingsInMinutes earlier than the last added reading + // and + // - the gap between last added reading and timeStampLastProcessedBgReading more than minimumTimeBetweenTwoReadingsInMinutes (otherwise we may be adding a reading in between last processed reading and last added reading even though these two are alrady less than minimumTimeBetweenTwoReadingsInMinutes minutes away from each other + if reading.timeStamp.timeIntervalSince(timeStampLastAddedReading) < -minimumTimeBetweenTwoReadingsInMinutes * 60.0 && abs(timeStampLastAddedReading.timeIntervalSince(timeStampLastProcessedBgReading != nil ? timeStampLastProcessedBgReading! : Date(timeIntervalSince1970: 0))) > minimumTimeBetweenTwoReadingsInMinutes * 60.0 { + + returnValue.append(reading) + + timeStampLastAddedReading = reading.timeStamp + + } } } - var returnValue = true - if let timeStampLatestCheckedReading = timeStampLatestCheckedReading { - - returnValue = $0.timeStamp.timeIntervalSince(timeStampLatestCheckedReading) > minimumTimeBetweenTwoReadingsInMinutes * 60.0 - - } - - if returnValue { - timeStampLatestCheckedReading = $0.timeStamp - } - - return returnValue - - }) + } - return Array(arrayReversed.reversed()) + return returnValue } diff --git a/xdrip/Managers/DexcomShare/DexcomShareUploadManager.swift b/xdrip/Managers/DexcomShare/DexcomShareUploadManager.swift index c7256ab5..6382cb32 100644 --- a/xdrip/Managers/DexcomShare/DexcomShareUploadManager.swift +++ b/xdrip/Managers/DexcomShare/DexcomShareUploadManager.swift @@ -116,7 +116,8 @@ class DexcomShareUploadManager:NSObject { if success { trace("in observeValue, start upload", log: self.log, category: ConstantsLog.categoryDexcomShareUploadManager, type: .info) - self.upload(lastConnectionStatusChangeTimeStamp: nil) + // set lastConnectionStatusChangeTimeStamp to as late as possible, to make sure that the most recent reading is uploaded if user is testing the credentials + self.upload(lastConnectionStatusChangeTimeStamp: Date()) } else { trace("in observeValue, Dexcom Share credential check failed", log: self.log, category: ConstantsLog.categoryDexcomShareUploadManager, type: .error) @@ -145,8 +146,10 @@ class DexcomShareUploadManager:NSObject { if success { trace("in observeValue, start upload", log: self.log, category: ConstantsLog.categoryDexcomShareUploadManager, type: .info) - self.upload(lastConnectionStatusChangeTimeStamp: nil) - + + // set lastConnectionStatusChangeTimeStamp to as late as possible, to make sure that the most recent reading is uploaded if user is testing the credentials + self.upload(lastConnectionStatusChangeTimeStamp: Date()) + } else { trace("in observeValue, Dexcom Share credential check failed", log: self.log, category: ConstantsLog.categoryDexcomShareUploadManager, type: .error) diff --git a/xdrip/Managers/NightScout/NightScoutUploadManager.swift b/xdrip/Managers/NightScout/NightScoutUploadManager.swift index 039d94fe..9a2578fe 100644 --- a/xdrip/Managers/NightScout/NightScoutUploadManager.swift +++ b/xdrip/Managers/NightScout/NightScoutUploadManager.swift @@ -76,7 +76,7 @@ public class NightScoutUploadManager:NSObject { /// uploads latest BgReadings to NightScout, only if nightscout enabled, not master, url and key defined, if schedule enabled then check also schedule /// - parameters: - /// - lastConnectionStatusChangeTimeStamp : when was the last transmitter dis/reconnect - if nil then 1 1 1970 is used + /// - lastConnectionStatusChangeTimeStamp : when was the last transmitter dis/reconnect public func upload(lastConnectionStatusChangeTimeStamp: Date?) { // check if NightScout is enabled @@ -149,7 +149,10 @@ public class NightScoutUploadManager:NSObject { DispatchQueue.main.async { self.callMessageHandler(withCredentialVerificationResult: success, error: error) if success { - self.upload(lastConnectionStatusChangeTimeStamp: nil) + + // set lastConnectionStatusChangeTimeStamp to as late as possible, to make sure that the most recent reading is uploaded if user is testing the credentials + self.upload(lastConnectionStatusChangeTimeStamp: Date()) + } else { trace("in observeValue, NightScout credential check failed", log: self.oslog, category: ConstantsLog.categoryNightScoutUploadManager, type: .info) } @@ -171,7 +174,10 @@ public class NightScoutUploadManager:NSObject { testNightScoutCredentials(apiKey: apiKey, siteURL: siteUrl, { (success, error) in DispatchQueue.main.async { if success { - self.upload(lastConnectionStatusChangeTimeStamp: nil) + + // set lastConnectionStatusChangeTimeStamp to as late as possible, to make sure that the most recent reading is uploaded if user is testing the credentials + self.upload(lastConnectionStatusChangeTimeStamp: Date()) + } else { trace("in observeValue, NightScout credential check failed", log: self.oslog, category: ConstantsLog.categoryNightScoutUploadManager, type: .info) }