@@ -38,6 +38,15 @@ final class DeviceDataManager {
3838
3939 var latestPumpStatus : RileyLinkKit . PumpStatus ?
4040
41+ private( set) var lastError : ( date: Date , error: Error ) ?
42+
43+ fileprivate func setLastError( error: Error ) {
44+ DispatchQueue . main. async { // Synchronize writes
45+ self . lastError = ( date: Date ( ) , error: error)
46+ // TODO: Notify observers of change
47+ }
48+ }
49+
4150 // Returns a value in the range 0 - 1
4251 var pumpBatteryChargeRemaining : Double ? {
4352 get {
@@ -159,8 +168,7 @@ final class DeviceDataManager {
159168
160169 // Gather PumpStatus from MySentry packet
161170 let pumpStatus : NightscoutUploadKit . PumpStatus ?
162- if let pumpDate = pumpDateComponents. date, let pumpID = pumpID {
163-
171+ if let pumpID = pumpID {
164172 let batteryStatus = BatteryStatus ( percent: status. batteryRemainingPercent)
165173 let iobStatus = IOBStatus ( timestamp: pumpDate, iob: status. iob)
166174
@@ -189,7 +197,10 @@ final class DeviceDataManager {
189197 switch result {
190198 case . newData( let values) :
191199 self . loopManager. addGlucose ( values, from: self . cgmManager? . device)
192- case . noData, . error:
200+ case . noData:
201+ break
202+ case . error( let error) :
203+ self . setLastError ( error: error)
193204 break
194205 }
195206 }
@@ -217,11 +228,16 @@ final class DeviceDataManager {
217228 loopManager. addReservoirValue ( units, at: date) { ( result) in
218229 switch result {
219230 case . failure( let error) :
231+ self . setLastError ( error: error)
220232 self . logger. addError ( error, fromSource: " DoseStore " )
221233 case . success( let ( newValue, lastValue, areStoredValuesContinuous) ) :
222234 // Run a loop as long as we have fresh, reliable pump data.
223235 if self . preferredInsulinDataSource == . pumpHistory || !areStoredValuesContinuous {
224236 self . fetchPumpHistory { ( error) in
237+ if let error = error {
238+ self . setLastError ( error: error)
239+ }
240+
225241 if error == nil || areStoredValuesContinuous {
226242 self . loopManager. loop ( )
227243 }
@@ -258,8 +274,9 @@ final class DeviceDataManager {
258274 /// - Parameters:
259275 /// - completion: A closure called once upon completion
260276 /// - error: An error describing why the fetch and/or store failed
261- private func fetchPumpHistory( _ completion: @escaping ( _ error: Error ? ) -> Void ) {
277+ fileprivate func fetchPumpHistory( _ completion: @escaping ( _ error: Error ? ) -> Void ) {
262278 guard let device = rileyLinkManager. firstConnectedDevice else {
279+ completion ( LoopError . connectionError)
263280 return
264281 }
265282
@@ -284,39 +301,6 @@ final class DeviceDataManager {
284301 }
285302 }
286303
287- /**
288- Read the pump's current state, including reservoir and clock
289-
290- - parameter completion: A closure called after the command is complete. This closure takes a single Result argument:
291- - Success(status, date): The pump status, and the resolved date according to the pump's clock
292- - Failure(error): An error describing why the command failed
293- */
294- private func readPumpData( _ completion: @escaping ( RileyLinkKit . Either < ( status: RileyLinkKit . PumpStatus , date: Date ) , Error > ) -> Void ) {
295- guard let device = rileyLinkManager. firstConnectedDevice, let ops = device. ops else {
296- completion ( . failure( LoopError . connectionError) )
297- return
298- }
299-
300- ops. readPumpStatus { ( result) in
301- switch result {
302- case . success( let status) :
303- var clock = status. clock
304- clock. timeZone = ops. pumpState. timeZone
305-
306- guard let date = clock. date else {
307- let errorStr = " Could not interpret pump clock: \( clock) "
308- self . logger. addError ( errorStr, fromSource: " RileyLink " )
309- completion ( . failure( LoopError . invalidData ( details: errorStr) ) )
310- return
311- }
312- completion ( . success( ( status: status, date: date) ) )
313- case . failure( let error) :
314- self . logger. addError ( " Failed to fetch pump status: \( error) " , fromSource: " RileyLink " )
315- completion ( . failure( error) )
316- }
317- }
318- }
319-
320304 private func pumpDataIsStale( ) -> Bool {
321305 // How long should we wait before we poll for new pump data?
322306 let pumpStatusAgeTolerance = rileyLinkManager. idleListeningEnabled ? TimeInterval ( minutes: 11 ) : TimeInterval ( minutes: 4 )
@@ -330,6 +314,7 @@ final class DeviceDataManager {
330314 */
331315 fileprivate func assertCurrentPumpData( ) {
332316 guard let device = rileyLinkManager. firstConnectedDevice else {
317+ self . setLastError ( error: LoopError . connectionError)
333318 return
334319 }
335320
@@ -339,7 +324,7 @@ final class DeviceDataManager {
339324 return
340325 }
341326
342- readPumpData { ( result) in
327+ rileyLinkManager . readPumpData { ( result) in
343328 let nsPumpStatus : NightscoutUploadKit . PumpStatus ?
344329 switch result {
345330 case . success( let ( status, date) ) :
@@ -352,6 +337,8 @@ final class DeviceDataManager {
352337
353338 nsPumpStatus = NightscoutUploadKit . PumpStatus ( clock: date, pumpID: status. pumpID, iob: nil , battery: battery, suspended: status. suspended, bolusing: status. bolusing, reservoir: status. reservoir)
354339 case . failure( let error) :
340+ self . logger. addError ( " Failed to fetch pump status: \( error) " , fromSource: " RileyLink " )
341+ self . setLastError ( error: error)
355342 self . troubleshootPumpComms ( using: device)
356343 self . nightscoutDataManager. uploadLoopStatus ( loopError: error)
357344 nsPumpStatus = nil
@@ -406,7 +393,7 @@ final class DeviceDataManager {
406393 loopManager. doseStore. lastReservoirVolumeDrop < 0 ||
407394 loopManager. doseStore. lastReservoirValue!. startDate. timeIntervalSinceNow <= TimeInterval ( minutes: - 6 )
408395 {
409- readPumpData { ( result) in
396+ rileyLinkManager . readPumpData { ( result) in
410397 switch result {
411398 case . success( let ( status, date) ) :
412399 self . loopManager. addReservoirValue ( status. reservoir, at: date) { ( result) in
@@ -425,6 +412,8 @@ final class DeviceDataManager {
425412 default :
426413 notify ( error)
427414 }
415+
416+ self . logger. addError ( " Failed to fetch pump status: \( error) " , fromSource: " RileyLink " )
428417 }
429418 }
430419 } else {
@@ -449,6 +438,7 @@ final class DeviceDataManager {
449438 case . failure( let error) :
450439 self . logger. addError ( " Device \( device. name ?? " " ) auto-tune failed with error: \( error) " , fromSource: " RileyLink " )
451440 self . rileyLinkManager. deprioritizeDevice ( device: device)
441+ self . setLastError ( error: error)
452442 }
453443 }
454444 } else {
@@ -660,7 +650,10 @@ extension DeviceDataManager: CGMManagerDelegate {
660650 loopManager. addGlucose ( values, from: manager. device) { _ in
661651 self . assertCurrentPumpData ( )
662652 }
663- case . noData, . error:
653+ case . noData:
654+ break
655+ case . error( let error) :
656+ self . setLastError ( error: error)
664657 self . assertCurrentPumpData ( )
665658 }
666659 }
@@ -721,6 +714,12 @@ extension DeviceDataManager: LoopDataManagerDelegate {
721714 value: body. rate,
722715 unit: . unitsPerHour
723716 ) ) )
717+
718+ // If we haven't fetched history in a while (preferredInsulinDataSource == .reservoir),
719+ // let's try to do so while the pump radio is on.
720+ if self . loopManager. doseStore. lastAddedPumpEvents. timeIntervalSinceNow < . minutes( - 4 ) {
721+ self . fetchPumpHistory { ( _) in }
722+ }
724723 case . failure( let error) :
725724 completion ( . failure( error) )
726725 }
@@ -736,15 +735,13 @@ extension DeviceDataManager: CustomDebugStringConvertible {
736735 " ## DeviceDataManager " ,
737736 " launchDate: \( launchDate) " ,
738737 " cgm: \( String ( describing: cgm) ) " ,
738+ " lastError: \( String ( describing: lastError) ) " ,
739739 " latestPumpStatusFromMySentry: \( String ( describing: latestPumpStatusFromMySentry) ) " ,
740740 " pumpState: \( String ( reflecting: pumpState) ) " ,
741741 " preferredInsulinDataSource: \( preferredInsulinDataSource) " ,
742742 cgmManager != nil ? String ( reflecting: cgmManager!) : " " ,
743743 String ( reflecting: rileyLinkManager) ,
744744 String ( reflecting: statusExtensionManager!) ,
745- " " ,
746- " ## NSUserDefaults " ,
747- String ( reflecting: UserDefaults . standard. dictionaryRepresentation ( ) )
748745 ] . joined ( separator: " \n " )
749746 }
750747}
0 commit comments