From 446016ee00d842c391d55df9d9a9f8591ba95847 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 26 Jul 2016 23:25:57 -0500 Subject: [PATCH 01/35] reworking device status uploads to make way for loop status uploads --- NightscoutUploadKit/DeviceStatus.swift | 17 ++++ NightscoutUploadKit/LoopStatus.swift | 19 ++++ NightscoutUploadKit/NightscoutUploader.swift | 98 +++++++++++--------- NightscoutUploadKit/PumpStatus.swift | 16 ++++ NightscoutUploadKit/UploaderStatus.swift | 15 +++ RileyLink.xcodeproj/project.pbxproj | 16 ++++ RileyLink/DeviceDataManager.swift | 29 ++++++ 7 files changed, 167 insertions(+), 43 deletions(-) create mode 100644 NightscoutUploadKit/DeviceStatus.swift create mode 100644 NightscoutUploadKit/LoopStatus.swift create mode 100644 NightscoutUploadKit/PumpStatus.swift create mode 100644 NightscoutUploadKit/UploaderStatus.swift diff --git a/NightscoutUploadKit/DeviceStatus.swift b/NightscoutUploadKit/DeviceStatus.swift new file mode 100644 index 000000000..ac6c30b3a --- /dev/null +++ b/NightscoutUploadKit/DeviceStatus.swift @@ -0,0 +1,17 @@ +// +// DeviceStatus.swift +// RileyLink +// +// Created by Pete Schwamb on 7/26/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class DeviceStatus { + var loopStatus: LoopStatus? = nil + var uploaderStatus: UploaderStatus? = nil + var pumpStatus: PumpStatus? = nil + let device: String? = nil +} + diff --git a/NightscoutUploadKit/LoopStatus.swift b/NightscoutUploadKit/LoopStatus.swift new file mode 100644 index 000000000..28d4fab86 --- /dev/null +++ b/NightscoutUploadKit/LoopStatus.swift @@ -0,0 +1,19 @@ +// +// LoopStatus.swift +// RileyLink +// +// Created by Pete Schwamb on 7/26/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class LoopStatus { + var glucose: Int? = nil + var timestamp: NSDate? = nil + var eventualBG: Int? = nil + var suggestedRate: Double? = nil + var duration: NSTimeInterval? = nil + var suggestedBolus: Double? = nil +} + diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 1d3daf196..1ba924b70 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -98,57 +98,40 @@ public class NightscoutUploader { } self.flushAll() } - - // Entries [ { sgv: 375, - // date: 1432421525000, - // dateString: '2015-05-23T22:52:05.000Z', - // trend: 1, - // direction: 'DoubleUp', - // device: 'share2', - // type: 'sgv' } ] - - public func handlePumpStatus(status: MySentryPumpStatusMessageBody, device: String) { - - var recordSGV = true - - let glucose: Int = { - switch status.glucose { - case .Active(glucose: let glucose): - return glucose - case .HighBG: - return 401 - case .WeakSignal: - return DexcomSensorError.BadRF.rawValue - case .MeterBGNow, .CalError: - return DexcomSensorError.SensorNotCalibrated.rawValue - case .Lost, .Missing, .Ended, .Unknown, .Off, .Warmup: - recordSGV = false - return DexcomSensorError.SensorNotActive.rawValue - } - }() - + + public func getPumpStatusFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody) -> PumpStatus { + + let pumpDate = status.pumpDateComponents.date + + if pumpDate == nil { + self.errorHandler?(error: UploadError.MissingTimezone, context: "Unable to get status.pumpDateComponents.date from \(status.pumpDateComponents)") + } + + let pumpStatus = PumpStatus() + pumpStatus.batteryPct = status.batteryRemainingPercent + pumpStatus.iob = status.iob + pumpStatus.timestamp = pumpDate + return pumpStatus + } + + public func uploadDeviceStatus(status: DeviceStatus) { // Create deviceStatus record from this mysentry packet - + var nsStatus = [String: AnyObject]() - + nsStatus["device"] = device + nsStatus["created_at"] = TimeFormat.timestampStrFromDate(NSDate()) - - // TODO: use battery monitoring to post updates if we're not hearing from pump? - - let uploaderDevice = UIDevice.currentDevice() - - if uploaderDevice.batteryMonitoringEnabled { - nsStatus["uploader"] = ["battery":uploaderDevice.batteryLevel * 100] - } - + + nsStatus["uploader"] = uploaderStatus + guard let pumpDate = status.pumpDateComponents.date else { self.errorHandler?(error: UploadError.MissingTimezone, context: "Unable to get status.pumpDateComponents.date") return } - + let pumpDateStr = TimeFormat.timestampStrFromDate(pumpDate) - + nsStatus["pump"] = [ "clock": pumpDateStr, "iob": [ @@ -160,7 +143,7 @@ public class NightscoutUploader { "percent": status.batteryRemainingPercent ] ] - + switch status.glucose { case .Active(glucose: _): nsStatus["sensor"] = [ @@ -171,8 +154,37 @@ public class NightscoutUploader { nsStatus["sensorNotActive"] = true } deviceStatuses.append(nsStatus) + } + + // Entries [ { sgv: 375, + // date: 1432421525000, + // dateString: '2015-05-23T22:52:05.000Z', + // trend: 1, + // direction: 'DoubleUp', + // device: 'share2', + // type: 'sgv' } ] + + public func uploadSGVFromMySentryStatus(status: MySentryPumpStatusMessageBody, device: String) { + var recordSGV = true + + let glucose: Int = { + switch status.glucose { + case .Active(glucose: let glucose): + return glucose + case .HighBG: + return 401 + case .WeakSignal: + return DexcomSensorError.BadRF.rawValue + case .MeterBGNow, .CalError: + return DexcomSensorError.SensorNotCalibrated.rawValue + case .Lost, .Missing, .Ended, .Unknown, .Off, .Warmup: + recordSGV = false + return DexcomSensorError.SensorNotActive.rawValue + } + }() + // Create SGV entry from this mysentry packet if (recordSGV) { var entry: [String: AnyObject] = [ diff --git a/NightscoutUploadKit/PumpStatus.swift b/NightscoutUploadKit/PumpStatus.swift new file mode 100644 index 000000000..fed8a489b --- /dev/null +++ b/NightscoutUploadKit/PumpStatus.swift @@ -0,0 +1,16 @@ +// +// PumpStatus.swift +// RileyLink +// +// Created by Pete Schwamb on 7/26/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class PumpStatus { + var batteryPct: Int? = nil + var timestamp: NSDate? = nil + var iob: Double? = nil + var reservoirRemainingUnits: Double? = nil +} \ No newline at end of file diff --git a/NightscoutUploadKit/UploaderStatus.swift b/NightscoutUploadKit/UploaderStatus.swift new file mode 100644 index 000000000..c3f4d0b55 --- /dev/null +++ b/NightscoutUploadKit/UploaderStatus.swift @@ -0,0 +1,15 @@ +// +// UploaderStatus.swift +// RileyLink +// +// Created by Pete Schwamb on 7/26/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class UploaderStatus { + var batteryPct: Int? = nil + var name: String? = nil + var timestamp: NSDate? = nil +} \ No newline at end of file diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 7ce5e3968..e3c4fd9f9 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -207,6 +207,10 @@ C1842C251C8FA45100DB42AC /* AlarmSensorPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */; }; C1AA39941AB6804000BC9E33 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */; }; C1AACC6B1CECD5F500C07049 /* RileyLinkListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AACC6A1CECD5F500C07049 /* RileyLinkListTableViewController.swift */; }; + C1AF21E21D4838C90088C41D /* DeviceStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E11D4838C90088C41D /* DeviceStatus.swift */; }; + C1AF21E41D4865320088C41D /* LoopStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E31D4865320088C41D /* LoopStatus.swift */; }; + C1AF21E61D48667F0088C41D /* UploaderStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E51D48667F0088C41D /* UploaderStatus.swift */; }; + C1AF21E81D4866960088C41D /* PumpStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E71D4866960088C41D /* PumpStatus.swift */; }; C1B3830E1CD0665D00CE7782 /* NightscoutUploadKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C1B3830D1CD0665D00CE7782 /* NightscoutUploadKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; C1B383151CD0665D00CE7782 /* NightscoutUploadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1B3830B1CD0665D00CE7782 /* NightscoutUploadKit.framework */; }; C1B3831C1CD0665D00CE7782 /* NightscoutUploadKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B3831B1CD0665D00CE7782 /* NightscoutUploadKitTests.swift */; }; @@ -576,6 +580,10 @@ C1AA39921AB6804000BC9E33 /* UIAlertView+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+Blocks.h"; sourceTree = ""; }; C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+Blocks.m"; sourceTree = ""; }; C1AACC6A1CECD5F500C07049 /* RileyLinkListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkListTableViewController.swift; sourceTree = ""; }; + C1AF21E11D4838C90088C41D /* DeviceStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceStatus.swift; sourceTree = ""; }; + C1AF21E31D4865320088C41D /* LoopStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopStatus.swift; sourceTree = ""; }; + C1AF21E51D48667F0088C41D /* UploaderStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderStatus.swift; sourceTree = ""; }; + C1AF21E71D4866960088C41D /* PumpStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpStatus.swift; sourceTree = ""; }; C1B3830B1CD0665D00CE7782 /* NightscoutUploadKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NightscoutUploadKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C1B3830D1CD0665D00CE7782 /* NightscoutUploadKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NightscoutUploadKit.h; sourceTree = ""; }; C1B3830F1CD0665D00CE7782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -1108,6 +1116,10 @@ C12FB2751CC5893C00879B80 /* TempBasalNightscoutTreatment.swift */, 43B0ADC81D1268B300AAD278 /* TimeFormat.swift */, C1B4A94D1D1C423D003B8985 /* NSUserDefaults.swift */, + C1AF21E11D4838C90088C41D /* DeviceStatus.swift */, + C1AF21E31D4865320088C41D /* LoopStatus.swift */, + C1AF21E51D48667F0088C41D /* UploaderStatus.swift */, + C1AF21E71D4866960088C41D /* PumpStatus.swift */, ); path = NightscoutUploadKit; sourceTree = ""; @@ -1842,11 +1854,15 @@ C1B3832B1CD0668600CE7782 /* BGCheckNightscoutTreatment.swift in Sources */, C1B383291CD0668600CE7782 /* NightscoutPumpEvents.swift in Sources */, 43B0ADCC1D126E3000AAD278 /* NSDateFormatter.swift in Sources */, + C1AF21E81D4866960088C41D /* PumpStatus.swift in Sources */, C1B4A94E1D1C423D003B8985 /* NSUserDefaults.swift in Sources */, + C1AF21E61D48667F0088C41D /* UploaderStatus.swift in Sources */, C1B3832D1CD0668600CE7782 /* BolusNightscoutTreatment.swift in Sources */, 43D657461D0CF38F00216E20 /* NSTimeInterval.swift in Sources */, C1B3832C1CD0668600CE7782 /* MealBolusNightscoutTreatment.swift in Sources */, + C1AF21E41D4865320088C41D /* LoopStatus.swift in Sources */, 43B0ADC91D1268B300AAD278 /* TimeFormat.swift in Sources */, + C1AF21E21D4838C90088C41D /* DeviceStatus.swift in Sources */, C1B383281CD0668600CE7782 /* NightscoutUploader.swift in Sources */, C1B3832A1CD0668600CE7782 /* NightscoutTreatment.swift in Sources */, ); diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index c501daf00..91d4cfa2d 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -154,6 +154,35 @@ class DeviceDataManager { if status.batteryRemainingPercent == 0 { //NotificationManager.sendPumpBatteryLowNotification() } + + // Gather UploaderStatus + let uploaderStatus = UploaderStatus() + let uploaderDevice = UIDevice.currentDevice() + uploaderStatus.name = uploaderDevice.name + if uploaderDevice.batteryMonitoringEnabled { + uploaderStatus.battery = uploaderDevice.batteryLevel * 100 + } + + // Gather PumpStatus + let pumpStatus = remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status, device: device.deviceURI) + + // Send DeviceStatus + let deviceStatus = DeviceStatus() + deviceStatus.uploaderStatus = uploaderStatus + deviceStatus.pumpStatus = pumpStatus + deviceStatus.device = device.deviceURI + //deviceStatus.loopStatus = ? + if Config.sharedInstance().uploadEnabled { + remoteDataManager.nightscoutUploader?.uploadDeviceStatus(deviceStatus) + } + + + + // Send SGVs + if Config.sharedInstance().uploadEnabled { + remoteDataManager.nightscoutUploader?.uploadSGVFromMySentryStatus(status, device: device.deviceURI) + } + if Config.sharedInstance().uploadEnabled { remoteDataManager.nightscoutUploader?.handlePumpStatus(status, device: device.deviceURI) } From efd2c43dfc2831614a1d2abc10aabe67a3af79ae Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Wed, 27 Jul 2016 10:11:25 -0500 Subject: [PATCH 02/35] group files --- .../{ => DeviceStatus}/DeviceStatus.swift | 0 .../{ => DeviceStatus}/LoopStatus.swift | 0 .../{ => DeviceStatus}/PumpStatus.swift | 0 .../{ => DeviceStatus}/UploaderStatus.swift | 0 .../BGCheckNightscoutTreatment.swift | 0 .../BolusNightscoutTreatment.swift | 0 .../MealBolusNightscoutTreatment.swift | 0 .../NightscoutTreatment.swift | 0 .../TempBasalNightscoutTreatment.swift | 0 RileyLink.xcodeproj/project.pbxproj | 66 ++++++++++++------- 10 files changed, 41 insertions(+), 25 deletions(-) rename NightscoutUploadKit/{ => DeviceStatus}/DeviceStatus.swift (100%) rename NightscoutUploadKit/{ => DeviceStatus}/LoopStatus.swift (100%) rename NightscoutUploadKit/{ => DeviceStatus}/PumpStatus.swift (100%) rename NightscoutUploadKit/{ => DeviceStatus}/UploaderStatus.swift (100%) rename NightscoutUploadKit/{ => Treatments}/BGCheckNightscoutTreatment.swift (100%) rename NightscoutUploadKit/{ => Treatments}/BolusNightscoutTreatment.swift (100%) rename NightscoutUploadKit/{ => Treatments}/MealBolusNightscoutTreatment.swift (100%) rename NightscoutUploadKit/{ => Treatments}/NightscoutTreatment.swift (100%) rename NightscoutUploadKit/{ => Treatments}/TempBasalNightscoutTreatment.swift (100%) diff --git a/NightscoutUploadKit/DeviceStatus.swift b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift similarity index 100% rename from NightscoutUploadKit/DeviceStatus.swift rename to NightscoutUploadKit/DeviceStatus/DeviceStatus.swift diff --git a/NightscoutUploadKit/LoopStatus.swift b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift similarity index 100% rename from NightscoutUploadKit/LoopStatus.swift rename to NightscoutUploadKit/DeviceStatus/LoopStatus.swift diff --git a/NightscoutUploadKit/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift similarity index 100% rename from NightscoutUploadKit/PumpStatus.swift rename to NightscoutUploadKit/DeviceStatus/PumpStatus.swift diff --git a/NightscoutUploadKit/UploaderStatus.swift b/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift similarity index 100% rename from NightscoutUploadKit/UploaderStatus.swift rename to NightscoutUploadKit/DeviceStatus/UploaderStatus.swift diff --git a/NightscoutUploadKit/BGCheckNightscoutTreatment.swift b/NightscoutUploadKit/Treatments/BGCheckNightscoutTreatment.swift similarity index 100% rename from NightscoutUploadKit/BGCheckNightscoutTreatment.swift rename to NightscoutUploadKit/Treatments/BGCheckNightscoutTreatment.swift diff --git a/NightscoutUploadKit/BolusNightscoutTreatment.swift b/NightscoutUploadKit/Treatments/BolusNightscoutTreatment.swift similarity index 100% rename from NightscoutUploadKit/BolusNightscoutTreatment.swift rename to NightscoutUploadKit/Treatments/BolusNightscoutTreatment.swift diff --git a/NightscoutUploadKit/MealBolusNightscoutTreatment.swift b/NightscoutUploadKit/Treatments/MealBolusNightscoutTreatment.swift similarity index 100% rename from NightscoutUploadKit/MealBolusNightscoutTreatment.swift rename to NightscoutUploadKit/Treatments/MealBolusNightscoutTreatment.swift diff --git a/NightscoutUploadKit/NightscoutTreatment.swift b/NightscoutUploadKit/Treatments/NightscoutTreatment.swift similarity index 100% rename from NightscoutUploadKit/NightscoutTreatment.swift rename to NightscoutUploadKit/Treatments/NightscoutTreatment.swift diff --git a/NightscoutUploadKit/TempBasalNightscoutTreatment.swift b/NightscoutUploadKit/Treatments/TempBasalNightscoutTreatment.swift similarity index 100% rename from NightscoutUploadKit/TempBasalNightscoutTreatment.swift rename to NightscoutUploadKit/Treatments/TempBasalNightscoutTreatment.swift diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index e3c4fd9f9..e8e474fb9 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -211,6 +211,11 @@ C1AF21E41D4865320088C41D /* LoopStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E31D4865320088C41D /* LoopStatus.swift */; }; C1AF21E61D48667F0088C41D /* UploaderStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E51D48667F0088C41D /* UploaderStatus.swift */; }; C1AF21E81D4866960088C41D /* PumpStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E71D4866960088C41D /* PumpStatus.swift */; }; + C1AF21F01D4901220088C41D /* BolusNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21EB1D4901220088C41D /* BolusNightscoutTreatment.swift */; }; + C1AF21F11D4901220088C41D /* NightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21EC1D4901220088C41D /* NightscoutTreatment.swift */; }; + C1AF21F21D4901220088C41D /* BGCheckNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21ED1D4901220088C41D /* BGCheckNightscoutTreatment.swift */; }; + C1AF21F31D4901220088C41D /* MealBolusNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21EE1D4901220088C41D /* MealBolusNightscoutTreatment.swift */; }; + C1AF21F41D4901220088C41D /* TempBasalNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21EF1D4901220088C41D /* TempBasalNightscoutTreatment.swift */; }; C1B3830E1CD0665D00CE7782 /* NightscoutUploadKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C1B3830D1CD0665D00CE7782 /* NightscoutUploadKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; C1B383151CD0665D00CE7782 /* NightscoutUploadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1B3830B1CD0665D00CE7782 /* NightscoutUploadKit.framework */; }; C1B3831C1CD0665D00CE7782 /* NightscoutUploadKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B3831B1CD0665D00CE7782 /* NightscoutUploadKitTests.swift */; }; @@ -218,11 +223,6 @@ C1B383211CD0665D00CE7782 /* NightscoutUploadKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C1B3830B1CD0665D00CE7782 /* NightscoutUploadKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C1B383281CD0668600CE7782 /* NightscoutUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */; }; C1B383291CD0668600CE7782 /* NightscoutPumpEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */; }; - C1B3832A1CD0668600CE7782 /* NightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C2E1C90F6D900DB42AC /* NightscoutTreatment.swift */; }; - C1B3832B1CD0668600CE7782 /* BGCheckNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C301C91D56400DB42AC /* BGCheckNightscoutTreatment.swift */; }; - C1B3832C1CD0668600CE7782 /* MealBolusNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C321C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift */; }; - C1B3832D1CD0668600CE7782 /* BolusNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19F94AA1C91DF6E00018F7D /* BolusNightscoutTreatment.swift */; }; - C1B3832E1CD0668600CE7782 /* TempBasalNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12FB2751CC5893C00879B80 /* TempBasalNightscoutTreatment.swift */; }; C1B383301CD0680800CE7782 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C10D9BC11C8269D500378342 /* MinimedKit.framework */; }; C1B383311CD068C300CE7782 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */; }; C1B383361CD1BA8100CE7782 /* DeviceDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B383351CD1BA8100CE7782 /* DeviceDataManager.swift */; }; @@ -477,7 +477,6 @@ C12EA25D198B436900309FA4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; C12EA25F198B436900309FA4 /* RileyLinkTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RileyLinkTests.m; sourceTree = ""; }; C12EA269198B442100309FA4 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; }; - C12FB2751CC5893C00879B80 /* TempBasalNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalNightscoutTreatment.swift; sourceTree = ""; }; C139AC221BFD84B500B0518F /* RuntimeUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeUtils.h; sourceTree = ""; }; C139AC231BFD84B500B0518F /* RuntimeUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuntimeUtils.m; sourceTree = ""; }; C14303151C97C98000A40450 /* PumpAckMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpAckMessageBody.swift; sourceTree = ""; }; @@ -573,10 +572,6 @@ C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AlarmSensorPumpEvent.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutUploader.swift; sourceTree = ""; }; C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutPumpEvents.swift; sourceTree = ""; }; - C1842C2E1C90F6D900DB42AC /* NightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutTreatment.swift; sourceTree = ""; }; - C1842C301C91D56400DB42AC /* BGCheckNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BGCheckNightscoutTreatment.swift; sourceTree = ""; }; - C1842C321C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MealBolusNightscoutTreatment.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - C19F94AA1C91DF6E00018F7D /* BolusNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusNightscoutTreatment.swift; sourceTree = ""; }; C1AA39921AB6804000BC9E33 /* UIAlertView+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+Blocks.h"; sourceTree = ""; }; C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+Blocks.m"; sourceTree = ""; }; C1AACC6A1CECD5F500C07049 /* RileyLinkListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkListTableViewController.swift; sourceTree = ""; }; @@ -584,6 +579,11 @@ C1AF21E31D4865320088C41D /* LoopStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopStatus.swift; sourceTree = ""; }; C1AF21E51D48667F0088C41D /* UploaderStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderStatus.swift; sourceTree = ""; }; C1AF21E71D4866960088C41D /* PumpStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpStatus.swift; sourceTree = ""; }; + C1AF21EB1D4901220088C41D /* BolusNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusNightscoutTreatment.swift; sourceTree = ""; }; + C1AF21EC1D4901220088C41D /* NightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutTreatment.swift; sourceTree = ""; }; + C1AF21ED1D4901220088C41D /* BGCheckNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BGCheckNightscoutTreatment.swift; sourceTree = ""; }; + C1AF21EE1D4901220088C41D /* MealBolusNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MealBolusNightscoutTreatment.swift; sourceTree = ""; }; + C1AF21EF1D4901220088C41D /* TempBasalNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalNightscoutTreatment.swift; sourceTree = ""; }; C1B3830B1CD0665D00CE7782 /* NightscoutUploadKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NightscoutUploadKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C1B3830D1CD0665D00CE7782 /* NightscoutUploadKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NightscoutUploadKit.h; sourceTree = ""; }; C1B3830F1CD0665D00CE7782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -1102,24 +1102,40 @@ name = Extensions; sourceTree = ""; }; + C1AF21E91D4900300088C41D /* DeviceStatus */ = { + isa = PBXGroup; + children = ( + C1AF21E11D4838C90088C41D /* DeviceStatus.swift */, + C1AF21E31D4865320088C41D /* LoopStatus.swift */, + C1AF21E51D48667F0088C41D /* UploaderStatus.swift */, + C1AF21E71D4866960088C41D /* PumpStatus.swift */, + ); + path = DeviceStatus; + sourceTree = ""; + }; + C1AF21EA1D4900880088C41D /* Treatments */ = { + isa = PBXGroup; + children = ( + C1AF21EB1D4901220088C41D /* BolusNightscoutTreatment.swift */, + C1AF21EC1D4901220088C41D /* NightscoutTreatment.swift */, + C1AF21ED1D4901220088C41D /* BGCheckNightscoutTreatment.swift */, + C1AF21EE1D4901220088C41D /* MealBolusNightscoutTreatment.swift */, + C1AF21EF1D4901220088C41D /* TempBasalNightscoutTreatment.swift */, + ); + path = Treatments; + sourceTree = ""; + }; C1B3830C1CD0665D00CE7782 /* NightscoutUploadKit */ = { isa = PBXGroup; children = ( + C1AF21EA1D4900880088C41D /* Treatments */, + C1AF21E91D4900300088C41D /* DeviceStatus */, C1B3830D1CD0665D00CE7782 /* NightscoutUploadKit.h */, C1B3830F1CD0665D00CE7782 /* Info.plist */, - C1842C301C91D56400DB42AC /* BGCheckNightscoutTreatment.swift */, - C19F94AA1C91DF6E00018F7D /* BolusNightscoutTreatment.swift */, - C1842C321C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift */, - C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */, - C1842C2E1C90F6D900DB42AC /* NightscoutTreatment.swift */, C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */, - C12FB2751CC5893C00879B80 /* TempBasalNightscoutTreatment.swift */, + C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */, 43B0ADC81D1268B300AAD278 /* TimeFormat.swift */, C1B4A94D1D1C423D003B8985 /* NSUserDefaults.swift */, - C1AF21E11D4838C90088C41D /* DeviceStatus.swift */, - C1AF21E31D4865320088C41D /* LoopStatus.swift */, - C1AF21E51D48667F0088C41D /* UploaderStatus.swift */, - C1AF21E71D4866960088C41D /* PumpStatus.swift */, ); path = NightscoutUploadKit; sourceTree = ""; @@ -1850,21 +1866,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C1B3832E1CD0668600CE7782 /* TempBasalNightscoutTreatment.swift in Sources */, - C1B3832B1CD0668600CE7782 /* BGCheckNightscoutTreatment.swift in Sources */, C1B383291CD0668600CE7782 /* NightscoutPumpEvents.swift in Sources */, 43B0ADCC1D126E3000AAD278 /* NSDateFormatter.swift in Sources */, C1AF21E81D4866960088C41D /* PumpStatus.swift in Sources */, C1B4A94E1D1C423D003B8985 /* NSUserDefaults.swift in Sources */, + C1AF21F01D4901220088C41D /* BolusNightscoutTreatment.swift in Sources */, + C1AF21F21D4901220088C41D /* BGCheckNightscoutTreatment.swift in Sources */, C1AF21E61D48667F0088C41D /* UploaderStatus.swift in Sources */, - C1B3832D1CD0668600CE7782 /* BolusNightscoutTreatment.swift in Sources */, + C1AF21F31D4901220088C41D /* MealBolusNightscoutTreatment.swift in Sources */, 43D657461D0CF38F00216E20 /* NSTimeInterval.swift in Sources */, - C1B3832C1CD0668600CE7782 /* MealBolusNightscoutTreatment.swift in Sources */, C1AF21E41D4865320088C41D /* LoopStatus.swift in Sources */, + C1AF21F11D4901220088C41D /* NightscoutTreatment.swift in Sources */, 43B0ADC91D1268B300AAD278 /* TimeFormat.swift in Sources */, C1AF21E21D4838C90088C41D /* DeviceStatus.swift in Sources */, C1B383281CD0668600CE7782 /* NightscoutUploader.swift in Sources */, - C1B3832A1CD0668600CE7782 /* NightscoutTreatment.swift in Sources */, + C1AF21F41D4901220088C41D /* TempBasalNightscoutTreatment.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 859d780d3fe1bd84079265de1f5b923807e2aaa3 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Wed, 27 Jul 2016 15:33:17 -0500 Subject: [PATCH 03/35] dictionary reps for json --- .../DeviceStatus/DeviceStatus.swift | 26 +++++++++- .../DeviceStatus/LoopStatus.swift | 42 +++++++++++++++- .../DeviceStatus/PumpStatus.swift | 48 ++++++++++++++++++- .../DeviceStatus/UploaderStatus.swift | 22 ++++++++- NightscoutUploadKit/NightscoutUploader.swift | 44 ++--------------- 5 files changed, 135 insertions(+), 47 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift index ac6c30b3a..4a76461a4 100644 --- a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift @@ -12,6 +12,30 @@ public class DeviceStatus { var loopStatus: LoopStatus? = nil var uploaderStatus: UploaderStatus? = nil var pumpStatus: PumpStatus? = nil - let device: String? = nil + let device: String + + init(device: String) { + self.device = device + } + + public var dictionaryRepresentation: [String: AnyObject] { + var rval = [String: AnyObject]() + + rval["device"] = device + + if let pump = pumpStatus { + rval["pump"] = pump + } + + if let uploader = uploaderStatus { + rval["uploader"] = uploader + } + + if let loop = loopStatus { + rval["loop"] = loop + } + + return rval + } } diff --git a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift index 28d4fab86..9b551ad33 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift @@ -9,11 +9,49 @@ import Foundation public class LoopStatus { + var name: String + var timestamp: NSDate + var glucose: Int? = nil - var timestamp: NSDate? = nil + var iob: Double? = nil var eventualBG: Int? = nil var suggestedRate: Double? = nil - var duration: NSTimeInterval? = nil + var suggestedDuration: NSTimeInterval? = nil + var enactedRate: Double? = nil + var enactedDuration: NSTimeInterval? = nil var suggestedBolus: Double? = nil + var reason: String? = nil + + init(name: String, timestamp: NSDate) { + self.name = name + self.timestamp = timestamp + } + + public var dictionaryRepresentation: [String: AnyObject] { + var rval = [String: AnyObject]() + + rval["timestamp"] = timestamp + rval["name"] = name + + if let iob = iob { + rval["iob"] = ["iob": iob] + } + + var suggested = [String: AnyObject]() + + if let glucose = glucose { + suggested["bg"] = glucose + } + + if let rate = suggestedRate { + suggested["rate"] = rate + } + + + rval["suggested"] = suggested + + + return rval + } } diff --git a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift index fed8a489b..2e71d17a5 100644 --- a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift @@ -10,7 +10,53 @@ import Foundation public class PumpStatus { var batteryPct: Int? = nil + var batteryStatus: String? = nil + var batteryVoltage: Double? = nil var timestamp: NSDate? = nil - var iob: Double? = nil + var status: String? = nil + var suspended: Bool? = nil + var bolusIOB: Double? = nil var reservoirRemainingUnits: Double? = nil + + public var dictionaryRepresentation: [String: AnyObject] { + var rval = [String: AnyObject]() + + var batteryDict = [String: AnyObject]() + + if let batteryPct = batteryPct { + batteryDict["percent"] = batteryPct + } + if let batteryStatus = batteryStatus { + batteryDict["status"] = batteryStatus + } + if let batteryVoltage = batteryVoltage { + batteryDict["voltage"] = batteryVoltage + } + + rval["battery"] = batteryDict + + let pumpDateStr: String? + + if let timestamp = timestamp { + pumpDateStr = TimeFormat.timestampStrFromDate(timestamp) + rval["clock"] = pumpDateStr + } else { + pumpDateStr = nil + } + + if let reservoir = reservoirRemainingUnits { + rval["reservoir"] = reservoir + } + + // Pump's idea of IOB + if let iob = bolusIOB { + var iobDict = [String: AnyObject]() + iobDict["timestamp"] = pumpDateStr + iobDict["bolusiob"] = iob + rval["iob"] = iobDict + } + + return rval + } + } \ No newline at end of file diff --git a/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift b/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift index c3f4d0b55..7e141a8ef 100644 --- a/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift @@ -10,6 +10,24 @@ import Foundation public class UploaderStatus { var batteryPct: Int? = nil - var name: String? = nil - var timestamp: NSDate? = nil + var name: String + var timestamp: NSDate + + init(name: String, timestamp: NSDate) { + self.name = name + self.timestamp = timestamp + } + + public var dictionaryRepresentation: [String: AnyObject] { + var rval = [String: AnyObject]() + + rval["name"] = name + rval["timestamp"] = timestamp + + if let battery = batteryPct { + rval["battery"] = battery + } + + return rval + } } \ No newline at end of file diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 1ba924b70..10d9248cb 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -109,51 +109,14 @@ public class NightscoutUploader { let pumpStatus = PumpStatus() pumpStatus.batteryPct = status.batteryRemainingPercent - pumpStatus.iob = status.iob + pumpStatus.bolusIOB = status.iob pumpStatus.timestamp = pumpDate return pumpStatus } public func uploadDeviceStatus(status: DeviceStatus) { - // Create deviceStatus record from this mysentry packet - - var nsStatus = [String: AnyObject]() - - nsStatus["device"] = device - - nsStatus["created_at"] = TimeFormat.timestampStrFromDate(NSDate()) - - nsStatus["uploader"] = uploaderStatus - - guard let pumpDate = status.pumpDateComponents.date else { - self.errorHandler?(error: UploadError.MissingTimezone, context: "Unable to get status.pumpDateComponents.date") - return - } - - let pumpDateStr = TimeFormat.timestampStrFromDate(pumpDate) - - nsStatus["pump"] = [ - "clock": pumpDateStr, - "iob": [ - "timestamp": pumpDateStr, - "bolusiob": status.iob, - ], - "reservoir": status.reservoirRemainingUnits, - "battery": [ - "percent": status.batteryRemainingPercent - ] - ] - - switch status.glucose { - case .Active(glucose: _): - nsStatus["sensor"] = [ - "sensorAge": status.sensorAgeHours, - "sensorRemaining": status.sensorRemainingHours, - ] - default: - nsStatus["sensorNotActive"] = true - } - deviceStatuses.append(nsStatus) + deviceStatuses.append(status.dictionaryRepresentation) + flushAll() } // Entries [ { sgv: 375, @@ -167,7 +130,6 @@ public class NightscoutUploader { public func uploadSGVFromMySentryStatus(status: MySentryPumpStatusMessageBody, device: String) { var recordSGV = true - let glucose: Int = { switch status.glucose { case .Active(glucose: let glucose): From 978a5313464917dac8f9aba55f0355569f55b82c Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Wed, 27 Jul 2016 19:20:21 -0500 Subject: [PATCH 04/35] Stop processing history events if we get to a pump alarm that indicates the pump lost track of time --- .../PumpEvents/ChangeTimePumpEvent.swift | 2 +- .../PumpEvents/PumpAlarmPumpEvent.swift | 29 ++++++++++++++++++- RileyLinkKit/PumpOpsSynchronous.swift | 10 +++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift b/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift index 8126dbf5a..99ebb210a 100644 --- a/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift +++ b/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift @@ -30,7 +30,7 @@ public struct ChangeTimePumpEvent: TimestampedPumpEvent { oldTimestamp = NSDateComponents(pumpEventData: availableData, offset: 2) timestamp = NSDateComponents(pumpEventData: availableData, offset: 9) } - + public var dictionaryRepresentation: [String: AnyObject] { return [ "_type": "ChangeTime", diff --git a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift index b4d47f5e7..5fc9a8ef8 100644 --- a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift +++ b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift @@ -8,11 +8,22 @@ import Foundation +public enum PumpAlarmType: Int { + case BatteryOutLimitExceeded = 3 + case NoDelivery = 4 + case BatteryDepleted = 5 + case DeviceReset = 16 + case ReprogramError = 61 + case EmptyReservoir = 62 + case UnknownType = -1 +} + public struct PumpAlarmPumpEvent: TimestampedPumpEvent { public let length: Int public let rawData: NSData public let timestamp: NSDateComponents - let rawType: Int + public let alarmType: PumpAlarmType + public let rawType: Int public init?(availableData: NSData, pumpModel: PumpModel) { length = 9 @@ -24,13 +35,29 @@ public struct PumpAlarmPumpEvent: TimestampedPumpEvent { rawData = availableData[0.. Date: Thu, 28 Jul 2016 09:53:32 -0500 Subject: [PATCH 05/35] uploader and pump status working with new structures --- .../DeviceStatus/DeviceStatus.swift | 19 +++++++----- .../DeviceStatus/LoopStatus.swift | 30 ++++++++++++++----- .../DeviceStatus/PumpStatus.swift | 2 -- .../DeviceStatus/UploaderStatus.swift | 11 +++---- NightscoutUploadKit/NightscoutUploader.swift | 9 +++++- RileyLink/DeviceDataManager.swift | 20 ++++--------- 6 files changed, 54 insertions(+), 37 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift index 4a76461a4..768a70145 100644 --- a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift @@ -9,30 +9,33 @@ import Foundation public class DeviceStatus { - var loopStatus: LoopStatus? = nil - var uploaderStatus: UploaderStatus? = nil - var pumpStatus: PumpStatus? = nil - let device: String + public var loopStatus: LoopStatus? = nil + public var uploaderStatus: UploaderStatus? = nil + public var pumpStatus: PumpStatus? = nil + public let device: String + public let timestamp: NSDate - init(device: String) { + public init(device: String, timestamp: NSDate) { self.device = device + self.timestamp = timestamp } public var dictionaryRepresentation: [String: AnyObject] { var rval = [String: AnyObject]() rval["device"] = device + rval["created_at"] = TimeFormat.timestampStrFromDate(timestamp) if let pump = pumpStatus { - rval["pump"] = pump + rval["pump"] = pump.dictionaryRepresentation } if let uploader = uploaderStatus { - rval["uploader"] = uploader + rval["uploader"] = uploader.dictionaryRepresentation } if let loop = loopStatus { - rval["loop"] = loop + rval["loop"] = loop.dictionaryRepresentation } return rval diff --git a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift index 9b551ad33..746d65d73 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift @@ -14,6 +14,7 @@ public class LoopStatus { var glucose: Int? = nil var iob: Double? = nil + var iobTimestamp: NSDate? = nil var eventualBG: Int? = nil var suggestedRate: Double? = nil var suggestedDuration: NSTimeInterval? = nil @@ -30,27 +31,42 @@ public class LoopStatus { public var dictionaryRepresentation: [String: AnyObject] { var rval = [String: AnyObject]() - rval["timestamp"] = timestamp + rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) rval["name"] = name + // IOB + var iobDict = [String: AnyObject]() if let iob = iob { - rval["iob"] = ["iob": iob] + iobDict["iob"] = iob } + if let iobTimestamp = iobTimestamp { + iobDict["timestamp"] = TimeFormat.timestampStrFromDate(iobTimestamp) + } + rval["iob"] = iobDict - var suggested = [String: AnyObject]() + // Suggested + var suggested = [String: AnyObject]() if let glucose = glucose { suggested["bg"] = glucose } - if let rate = suggestedRate { suggested["rate"] = rate } - - + if let eventualBG = eventualBG { + suggested["eventualBG"] = eventualBG + } rval["suggested"] = suggested - + // Enacted + var enacted = [String: AnyObject]() + if let rate = enactedRate { + enacted["rate"] = rate + } + if let duration = enactedDuration { + enacted["duration"] = duration + } + rval["enacted"] = enacted return rval } } diff --git a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift index 2e71d17a5..db0998fc1 100644 --- a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift @@ -13,7 +13,6 @@ public class PumpStatus { var batteryStatus: String? = nil var batteryVoltage: Double? = nil var timestamp: NSDate? = nil - var status: String? = nil var suspended: Bool? = nil var bolusIOB: Double? = nil var reservoirRemainingUnits: Double? = nil @@ -58,5 +57,4 @@ public class PumpStatus { return rval } - } \ No newline at end of file diff --git a/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift b/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift index 7e141a8ef..0cddd9358 100644 --- a/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift @@ -9,11 +9,12 @@ import Foundation public class UploaderStatus { - var batteryPct: Int? = nil - var name: String - var timestamp: NSDate + public var batteryPct: Int? = nil - init(name: String, timestamp: NSDate) { + public let name: String + public let timestamp: NSDate + + public init(name: String, timestamp: NSDate) { self.name = name self.timestamp = timestamp } @@ -22,7 +23,7 @@ public class UploaderStatus { var rval = [String: AnyObject]() rval["name"] = name - rval["timestamp"] = timestamp + rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) if let battery = batteryPct { rval["battery"] = battery diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 10d9248cb..06c9cd0d8 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -111,6 +111,13 @@ public class NightscoutUploader { pumpStatus.batteryPct = status.batteryRemainingPercent pumpStatus.bolusIOB = status.iob pumpStatus.timestamp = pumpDate + pumpStatus.reservoirRemainingUnits = status.reservoirRemainingUnits + + // TODO: + // pumpStatus.batteryVoltage + // pumpStatus.batteryStatus + // pumpStatus.suspended + return pumpStatus } @@ -127,7 +134,7 @@ public class NightscoutUploader { // device: 'share2', // type: 'sgv' } ] - public func uploadSGVFromMySentryStatus(status: MySentryPumpStatusMessageBody, device: String) { + public func uploadSGVFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody, device: String) { var recordSGV = true let glucose: Int = { diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 91d4cfa2d..992ae80ef 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -156,37 +156,29 @@ class DeviceDataManager { } // Gather UploaderStatus - let uploaderStatus = UploaderStatus() let uploaderDevice = UIDevice.currentDevice() - uploaderStatus.name = uploaderDevice.name + let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate()) if uploaderDevice.batteryMonitoringEnabled { - uploaderStatus.battery = uploaderDevice.batteryLevel * 100 + uploaderStatus.batteryPct = Int(uploaderDevice.batteryLevel * 100) } - // Gather PumpStatus - let pumpStatus = remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status, device: device.deviceURI) + // Gather PumpStatus from MySentry packet + let pumpStatus = remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) // Send DeviceStatus - let deviceStatus = DeviceStatus() + let deviceStatus = DeviceStatus(device: device.deviceURI, timestamp: NSDate()) deviceStatus.uploaderStatus = uploaderStatus deviceStatus.pumpStatus = pumpStatus - deviceStatus.device = device.deviceURI //deviceStatus.loopStatus = ? if Config.sharedInstance().uploadEnabled { remoteDataManager.nightscoutUploader?.uploadDeviceStatus(deviceStatus) } - - // Send SGVs if Config.sharedInstance().uploadEnabled { - remoteDataManager.nightscoutUploader?.uploadSGVFromMySentryStatus(status, device: device.deviceURI) + remoteDataManager.nightscoutUploader?.uploadSGVFromMySentryPumpStatus(status, device: device.deviceURI) } - if Config.sharedInstance().uploadEnabled { - remoteDataManager.nightscoutUploader?.handlePumpStatus(status, device: device.deviceURI) - } - // Sentry packets are sent in groups of 3, 5s apart. Wait 11s to avoid conflicting comms. let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(11 * NSEC_PER_SEC)) dispatch_after(delay, dispatch_get_main_queue()) { From d084ebcb3c60bdc13394d49524a908687b3066f5 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Thu, 28 Jul 2016 13:31:53 -0500 Subject: [PATCH 06/35] aligning structures to match NS layout more closely --- .../DeviceStatus/BatteryStatus.swift | 35 +++++++++++ .../DeviceStatus/IOBStatus.swift | 29 +++++++++ .../DeviceStatus/LoopEnacted.swift | 32 ++++++++++ .../DeviceStatus/LoopStatus.swift | 62 ++++++------------- .../DeviceStatus/LoopSuggested.swift | 54 ++++++++++++++++ .../DeviceStatus/PumpStatus.swift | 49 +++++---------- NightscoutUploadKit/NightscoutUploader.swift | 22 +++---- RileyLink.xcodeproj/project.pbxproj | 18 +++++- RileyLink/DeviceDataManager.swift | 25 +++++--- 9 files changed, 228 insertions(+), 98 deletions(-) create mode 100644 NightscoutUploadKit/DeviceStatus/BatteryStatus.swift create mode 100644 NightscoutUploadKit/DeviceStatus/IOBStatus.swift create mode 100644 NightscoutUploadKit/DeviceStatus/LoopEnacted.swift create mode 100644 NightscoutUploadKit/DeviceStatus/LoopSuggested.swift diff --git a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift new file mode 100644 index 000000000..f289f2bf9 --- /dev/null +++ b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift @@ -0,0 +1,35 @@ +// +// BatteryStatus.swift +// RileyLink +// +// Created by Pete Schwamb on 7/28/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BatteryStatus { + let percent: Int? + let voltage: Double? + let status: String + + public init(percent: Int? = nil, voltage: Double? = nil, status: String = "normal") { + self.percent = percent + self.voltage = voltage + self.status = status + } + + public var dictionaryRepresentation: [String: AnyObject] { + var rval = [String: AnyObject]() + + if let percent = percent { + rval["percent"] = percent + } + if let voltage = voltage { + rval["voltage"] = voltage + } + rval["status"] = status + + return rval + } +} \ No newline at end of file diff --git a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift new file mode 100644 index 000000000..8402c38ea --- /dev/null +++ b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift @@ -0,0 +1,29 @@ +// +// IOBStatus.swift +// RileyLink +// +// Created by Pete Schwamb on 7/28/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class IOBStatus { + let iob: Double // basal iob + bolus iob: can be negative + let basaliob: Double + let timestamp: NSDate + + public init(iob: Double, basaliob: Double, timestamp: NSDate) { + self.iob = iob + self.basaliob = basaliob + self.timestamp = timestamp + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "iob": iob, + "basaliob": basaliob, + "timestamp": TimeFormat.timestampStrFromDate(timestamp), + ] + } +} \ No newline at end of file diff --git a/NightscoutUploadKit/DeviceStatus/LoopEnacted.swift b/NightscoutUploadKit/DeviceStatus/LoopEnacted.swift new file mode 100644 index 000000000..1fe6e931b --- /dev/null +++ b/NightscoutUploadKit/DeviceStatus/LoopEnacted.swift @@ -0,0 +1,32 @@ +// +// LoopEnacted.swift +// RileyLink +// +// Created by Pete Schwamb on 7/28/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class LoopEnacted { + let rate: Double + let duration: NSTimeInterval + let timestamp: NSDate + let received: Bool + + public init(rate: Double, duration: NSTimeInterval, timestamp: NSDate, received: Bool) { + self.rate = rate + self.duration = duration + self.timestamp = timestamp + self.received = received + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "rate": rate, + "duration": duration / 60.0, + "timestamp": TimeFormat.timestampStrFromDate(timestamp), + "recieved": received // [sic] + ] + } +} \ No newline at end of file diff --git a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift index 746d65d73..e81ba519f 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift @@ -9,64 +9,42 @@ import Foundation public class LoopStatus { - var name: String - var timestamp: NSDate + let name: String + let timestamp: NSDate - var glucose: Int? = nil - var iob: Double? = nil - var iobTimestamp: NSDate? = nil - var eventualBG: Int? = nil - var suggestedRate: Double? = nil - var suggestedDuration: NSTimeInterval? = nil - var enactedRate: Double? = nil - var enactedDuration: NSTimeInterval? = nil - var suggestedBolus: Double? = nil - var reason: String? = nil + let iob: IOBStatus? + let suggested: LoopSuggested? + let enacted: LoopEnacted? - init(name: String, timestamp: NSDate) { + let failureReason: String? + + public init(name: String, timestamp: NSDate, glucose: Int? = nil, iob: IOBStatus? = nil, suggested: LoopSuggested? = nil, enacted: LoopEnacted?, failureReason: String? = nil) { self.name = name self.timestamp = timestamp + self.suggested = suggested + self.enacted = enacted + self.iob = iob + self.failureReason = failureReason } public var dictionaryRepresentation: [String: AnyObject] { var rval = [String: AnyObject]() - rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) rval["name"] = name + rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) - // IOB - var iobDict = [String: AnyObject]() - if let iob = iob { - iobDict["iob"] = iob - } - if let iobTimestamp = iobTimestamp { - iobDict["timestamp"] = TimeFormat.timestampStrFromDate(iobTimestamp) + if let suggested = suggested { + rval["suggested"] = suggested.dictionaryRepresentation } - rval["iob"] = iobDict - - // Suggested - var suggested = [String: AnyObject]() - if let glucose = glucose { - suggested["bg"] = glucose + if let enacted = enacted { + rval["enacted"] = enacted.dictionaryRepresentation } - if let rate = suggestedRate { - suggested["rate"] = rate - } - if let eventualBG = eventualBG { - suggested["eventualBG"] = eventualBG - } - rval["suggested"] = suggested - // Enacted - var enacted = [String: AnyObject]() - if let rate = enactedRate { - enacted["rate"] = rate - } - if let duration = enactedDuration { - enacted["duration"] = duration + if let iob = iob { + rval["iob"] = iob.dictionaryRepresentation } - rval["enacted"] = enacted + return rval } } diff --git a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift new file mode 100644 index 000000000..bef59586d --- /dev/null +++ b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift @@ -0,0 +1,54 @@ +// +// LoopSuggested.swift +// RileyLink +// +// Created by Pete Schwamb on 7/28/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class LoopSuggested { + let timestamp: NSDate + let rate: Double + let duration: NSTimeInterval + let correction: Double + let eventualBG: Int + let reason: String + let bg: Int + let tick: Int + + public init(timestamp: NSDate, rate: Double, duration: NSTimeInterval, correction: Double = 0, eventualBG: Int, reason: String, bg: Int, tick: Int) { + self.timestamp = timestamp + self.rate = rate + self.duration = duration + self.correction = correction + self.eventualBG = eventualBG + self.reason = reason + self.bg = bg + self.tick = tick + } + + public var dictionaryRepresentation: [String: AnyObject] { + let tickStr: String + + if tick > 0 { + tickStr = "+\(tick)" + } else if tick < 0 { + tickStr = "-\(tick)" + } else { + tickStr = "0" + } + + return [ + "timestamp": TimeFormat.timestampStrFromDate(timestamp), + "rate": rate, + "duration": duration / 60.0, + "bg": bg, + "correction": correction, + "eventualBG": eventualBG, + "reason": reason, + "tick": tickStr, + ] + } +} diff --git a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift index db0998fc1..ef5419aee 100644 --- a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift @@ -9,50 +9,33 @@ import Foundation public class PumpStatus { - var batteryPct: Int? = nil - var batteryStatus: String? = nil - var batteryVoltage: Double? = nil - var timestamp: NSDate? = nil + let clock: NSDate + let iob: IOBStatus? + let battery: BatteryStatus? var suspended: Bool? = nil - var bolusIOB: Double? = nil - var reservoirRemainingUnits: Double? = nil + var reservoir: Double? = nil + + public init(clock: NSDate, iob: IOBStatus? = nil, battery: BatteryStatus? = nil, suspended: Bool? = nil, reservoir: Double? = nil) { + self.clock = clock + self.iob = iob + self.battery = battery + } public var dictionaryRepresentation: [String: AnyObject] { var rval = [String: AnyObject]() - var batteryDict = [String: AnyObject]() - - if let batteryPct = batteryPct { - batteryDict["percent"] = batteryPct - } - if let batteryStatus = batteryStatus { - batteryDict["status"] = batteryStatus - } - if let batteryVoltage = batteryVoltage { - batteryDict["voltage"] = batteryVoltage - } - - rval["battery"] = batteryDict - - let pumpDateStr: String? + rval["clock"] = TimeFormat.timestampStrFromDate(clock) - if let timestamp = timestamp { - pumpDateStr = TimeFormat.timestampStrFromDate(timestamp) - rval["clock"] = pumpDateStr - } else { - pumpDateStr = nil + if let battery = battery { + rval["battery"] = battery.dictionaryRepresentation } - if let reservoir = reservoirRemainingUnits { + if let reservoir = reservoir { rval["reservoir"] = reservoir } - // Pump's idea of IOB - if let iob = bolusIOB { - var iobDict = [String: AnyObject]() - iobDict["timestamp"] = pumpDateStr - iobDict["bolusiob"] = iob - rval["iob"] = iobDict + if let iob = iob { + rval["iob"] = iob.dictionaryRepresentation } return rval diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 06c9cd0d8..3cd6d3853 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -99,24 +99,16 @@ public class NightscoutUploader { self.flushAll() } - public func getPumpStatusFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody) -> PumpStatus { + public func getPumpStatusFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody) throws -> PumpStatus { - let pumpDate = status.pumpDateComponents.date - - if pumpDate == nil { - self.errorHandler?(error: UploadError.MissingTimezone, context: "Unable to get status.pumpDateComponents.date from \(status.pumpDateComponents)") + guard let pumpDate = status.pumpDateComponents.date else { + throw UploadError.MissingTimezone } - - let pumpStatus = PumpStatus() - pumpStatus.batteryPct = status.batteryRemainingPercent - pumpStatus.bolusIOB = status.iob - pumpStatus.timestamp = pumpDate - pumpStatus.reservoirRemainingUnits = status.reservoirRemainingUnits - // TODO: - // pumpStatus.batteryVoltage - // pumpStatus.batteryStatus - // pumpStatus.suspended + let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") + let iobStatus = IOBStatus(iob: status.iob, basaliob: 0, timestamp: pumpDate) + + let pumpStatus = PumpStatus(clock: pumpDate, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) return pumpStatus } diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index e8e474fb9..444365f6b 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -205,6 +205,10 @@ C1842C231C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF91C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift */; }; C1842C241C8FA45100DB42AC /* BatteryPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BFA1C8FA45100DB42AC /* BatteryPumpEvent.swift */; }; C1842C251C8FA45100DB42AC /* AlarmSensorPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */; }; + C1A492631D4A5A19008964FF /* IOBStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A492621D4A5A19008964FF /* IOBStatus.swift */; }; + C1A492651D4A5DEB008964FF /* BatteryStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A492641D4A5DEB008964FF /* BatteryStatus.swift */; }; + C1A492671D4A65D9008964FF /* LoopSuggested.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A492661D4A65D9008964FF /* LoopSuggested.swift */; }; + C1A492691D4A66C0008964FF /* LoopEnacted.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A492681D4A66C0008964FF /* LoopEnacted.swift */; }; C1AA39941AB6804000BC9E33 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */; }; C1AACC6B1CECD5F500C07049 /* RileyLinkListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AACC6A1CECD5F500C07049 /* RileyLinkListTableViewController.swift */; }; C1AF21E21D4838C90088C41D /* DeviceStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AF21E11D4838C90088C41D /* DeviceStatus.swift */; }; @@ -572,6 +576,10 @@ C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AlarmSensorPumpEvent.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutUploader.swift; sourceTree = ""; }; C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutPumpEvents.swift; sourceTree = ""; }; + C1A492621D4A5A19008964FF /* IOBStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IOBStatus.swift; sourceTree = ""; }; + C1A492641D4A5DEB008964FF /* BatteryStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryStatus.swift; sourceTree = ""; }; + C1A492661D4A65D9008964FF /* LoopSuggested.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopSuggested.swift; sourceTree = ""; }; + C1A492681D4A66C0008964FF /* LoopEnacted.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopEnacted.swift; sourceTree = ""; }; C1AA39921AB6804000BC9E33 /* UIAlertView+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+Blocks.h"; sourceTree = ""; }; C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+Blocks.m"; sourceTree = ""; }; C1AACC6A1CECD5F500C07049 /* RileyLinkListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkListTableViewController.swift; sourceTree = ""; }; @@ -1106,9 +1114,13 @@ isa = PBXGroup; children = ( C1AF21E11D4838C90088C41D /* DeviceStatus.swift */, - C1AF21E31D4865320088C41D /* LoopStatus.swift */, C1AF21E51D48667F0088C41D /* UploaderStatus.swift */, C1AF21E71D4866960088C41D /* PumpStatus.swift */, + C1A492621D4A5A19008964FF /* IOBStatus.swift */, + C1A492641D4A5DEB008964FF /* BatteryStatus.swift */, + C1AF21E31D4865320088C41D /* LoopStatus.swift */, + C1A492661D4A65D9008964FF /* LoopSuggested.swift */, + C1A492681D4A66C0008964FF /* LoopEnacted.swift */, ); path = DeviceStatus; sourceTree = ""; @@ -1874,9 +1886,13 @@ C1AF21F21D4901220088C41D /* BGCheckNightscoutTreatment.swift in Sources */, C1AF21E61D48667F0088C41D /* UploaderStatus.swift in Sources */, C1AF21F31D4901220088C41D /* MealBolusNightscoutTreatment.swift in Sources */, + C1A492691D4A66C0008964FF /* LoopEnacted.swift in Sources */, + C1A492651D4A5DEB008964FF /* BatteryStatus.swift in Sources */, + C1A492631D4A5A19008964FF /* IOBStatus.swift in Sources */, 43D657461D0CF38F00216E20 /* NSTimeInterval.swift in Sources */, C1AF21E41D4865320088C41D /* LoopStatus.swift in Sources */, C1AF21F11D4901220088C41D /* NightscoutTreatment.swift in Sources */, + C1A492671D4A65D9008964FF /* LoopSuggested.swift in Sources */, 43B0ADC91D1268B300AAD278 /* TimeFormat.swift in Sources */, C1AF21E21D4838C90088C41D /* DeviceStatus.swift in Sources */, C1B383281CD0668600CE7782 /* NightscoutUploader.swift in Sources */, diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 992ae80ef..3918c2609 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -161,15 +161,26 @@ class DeviceDataManager { if uploaderDevice.batteryMonitoringEnabled { uploaderStatus.batteryPct = Int(uploaderDevice.batteryLevel * 100) } - - // Gather PumpStatus from MySentry packet - let pumpStatus = remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) - - // Send DeviceStatus + + // Build DeviceStatus let deviceStatus = DeviceStatus(device: device.deviceURI, timestamp: NSDate()) deviceStatus.uploaderStatus = uploaderStatus - deviceStatus.pumpStatus = pumpStatus - //deviceStatus.loopStatus = ? + + // Mock out some loop data for testing +// let loopTime = NSDate() +// let iob = IOBStatus(iob: 3.0, basaliob: 1.2, timestamp: NSDate()) +// let loopSuggested = LoopSuggested(timestamp: loopTime, rate: 1.2, duration: NSTimeInterval(30*60), correction: 0, eventualBG: 200, reason: "Test Reason", bg: 205, tick: 5) +// let loopEnacted = LoopEnacted(rate: 1.2, duration: NSTimeInterval(30*60), timestamp: loopTime, received: true) +// deviceStatus.loopStatus = LoopStatus(name: "TestLoopName", timestamp: NSDate(), iob: iob, suggested: loopSuggested, enacted: loopEnacted, failureReason: nil) + + // Gather PumpStatus from MySentry packet + do { + let pumpStatus = try remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) + deviceStatus.pumpStatus = pumpStatus + } catch { + print("Could not get pump status: \(error)") + } + if Config.sharedInstance().uploadEnabled { remoteDataManager.nightscoutUploader?.uploadDeviceStatus(deviceStatus) } From 117b1c3bf44c4f394a6e2c56ac953539ed60881c Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Thu, 28 Jul 2016 14:06:45 -0500 Subject: [PATCH 07/35] make DeviceData immutable --- .../DeviceStatus/DeviceStatus.swift | 18 ++++--- RileyLink/DeviceDataManager.swift | 47 +++++++++---------- RileyLink/RemoteDataManager.swift | 4 +- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift index 768a70145..9c08023e1 100644 --- a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift @@ -9,15 +9,18 @@ import Foundation public class DeviceStatus { - public var loopStatus: LoopStatus? = nil - public var uploaderStatus: UploaderStatus? = nil - public var pumpStatus: PumpStatus? = nil - public let device: String - public let timestamp: NSDate + let device: String + let timestamp: NSDate + let pumpStatus: PumpStatus? + let uploaderStatus: UploaderStatus? + let loopStatus: LoopStatus? - public init(device: String, timestamp: NSDate) { + public init(device: String, timestamp: NSDate, pumpStatus: PumpStatus? = nil, uploaderStatus: UploaderStatus? = nil, loopStatus: LoopStatus? = nil) { self.device = device self.timestamp = timestamp + self.pumpStatus = pumpStatus + self.uploaderStatus = uploaderStatus + self.loopStatus = loopStatus } public var dictionaryRepresentation: [String: AnyObject] { @@ -35,7 +38,8 @@ public class DeviceStatus { } if let loop = loopStatus { - rval["loop"] = loop.dictionaryRepresentation + // Would like to change this to avoid confusion about whether or not this was uploaded from Loop or openaps + rval["openaps"] = loop.dictionaryRepresentation } return rval diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 3918c2609..a257da826 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -151,9 +151,19 @@ class DeviceDataManager { if status != latestPumpStatus { latestPumpStatus = status + // Sentry packets are sent in groups of 3, 5s apart. Wait 11s to avoid conflicting comms. + let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(11 * NSEC_PER_SEC)) + dispatch_after(delay, dispatch_get_main_queue()) { + self.getPumpHistory(device) + } + if status.batteryRemainingPercent == 0 { //NotificationManager.sendPumpBatteryLowNotification() } + + guard Config.sharedInstance().uploadEnabled else { + return + } // Gather UploaderStatus let uploaderDevice = UIDevice.currentDevice() @@ -162,39 +172,28 @@ class DeviceDataManager { uploaderStatus.batteryPct = Int(uploaderDevice.batteryLevel * 100) } - // Build DeviceStatus - let deviceStatus = DeviceStatus(device: device.deviceURI, timestamp: NSDate()) - deviceStatus.uploaderStatus = uploaderStatus + // Gather PumpStatus from MySentry packet + let pumpStatus: PumpStatus? + do { + pumpStatus = try remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) + } catch { + pumpStatus = nil + print("Could not get pump status: \(error)") + } // Mock out some loop data for testing // let loopTime = NSDate() // let iob = IOBStatus(iob: 3.0, basaliob: 1.2, timestamp: NSDate()) // let loopSuggested = LoopSuggested(timestamp: loopTime, rate: 1.2, duration: NSTimeInterval(30*60), correction: 0, eventualBG: 200, reason: "Test Reason", bg: 205, tick: 5) // let loopEnacted = LoopEnacted(rate: 1.2, duration: NSTimeInterval(30*60), timestamp: loopTime, received: true) -// deviceStatus.loopStatus = LoopStatus(name: "TestLoopName", timestamp: NSDate(), iob: iob, suggested: loopSuggested, enacted: loopEnacted, failureReason: nil) +// let loopStatus = LoopStatus(name: "TestLoopName", timestamp: NSDate(), iob: iob, suggested: loopSuggested, enacted: loopEnacted, failureReason: nil) - // Gather PumpStatus from MySentry packet - do { - let pumpStatus = try remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) - deviceStatus.pumpStatus = pumpStatus - } catch { - print("Could not get pump status: \(error)") - } - - if Config.sharedInstance().uploadEnabled { - remoteDataManager.nightscoutUploader?.uploadDeviceStatus(deviceStatus) - } + // Build DeviceStatus + let deviceStatus = DeviceStatus(device: uploaderDevice.name, timestamp: NSDate(), pumpStatus: pumpStatus, uploaderStatus: uploaderStatus) + remoteDataManager.nightscoutUploader?.uploadDeviceStatus(deviceStatus) // Send SGVs - if Config.sharedInstance().uploadEnabled { - remoteDataManager.nightscoutUploader?.uploadSGVFromMySentryPumpStatus(status, device: device.deviceURI) - } - - // Sentry packets are sent in groups of 3, 5s apart. Wait 11s to avoid conflicting comms. - let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(11 * NSEC_PER_SEC)) - dispatch_after(delay, dispatch_get_main_queue()) { - self.getPumpHistory(device) - } + remoteDataManager.nightscoutUploader?.uploadSGVFromMySentryPumpStatus(status, device: device.deviceURI) } } diff --git a/RileyLink/RemoteDataManager.swift b/RileyLink/RemoteDataManager.swift index cec2c6c61..de7a48d66 100644 --- a/RileyLink/RemoteDataManager.swift +++ b/RileyLink/RemoteDataManager.swift @@ -18,7 +18,7 @@ class RemoteDataManager { var nightscoutService: NightscoutService { didSet { - try! keychain.setNightscoutURL(nightscoutService.siteURL, secret: nightscoutService.APISecret) + keychain.setNightscoutURL(nightscoutService.siteURL, secret: nightscoutService.APISecret) } } @@ -32,7 +32,7 @@ class RemoteDataManager { } else if let siteURL = Config.sharedInstance().nightscoutURL, APISecret = Config.sharedInstance().nightscoutAPISecret { - try! keychain.setNightscoutURL(siteURL, secret: APISecret) + keychain.setNightscoutURL(siteURL, secret: APISecret) nightscoutService = NightscoutService(siteURL: siteURL, APISecret: APISecret) } else { nightscoutService = NightscoutService(siteURL: nil, APISecret: nil) From 998549bb6ed494ddddcb81192627aef22afc4a5b Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Thu, 28 Jul 2016 14:52:56 -0500 Subject: [PATCH 08/35] bolusing flag --- NightscoutUploadKit/DeviceStatus/PumpStatus.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift index ef5419aee..a80ba8fdf 100644 --- a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift @@ -12,13 +12,17 @@ public class PumpStatus { let clock: NSDate let iob: IOBStatus? let battery: BatteryStatus? - var suspended: Bool? = nil - var reservoir: Double? = nil + let suspended: Bool? + let bolusing: Bool? + let reservoir: Double? - public init(clock: NSDate, iob: IOBStatus? = nil, battery: BatteryStatus? = nil, suspended: Bool? = nil, reservoir: Double? = nil) { + public init(clock: NSDate, iob: IOBStatus? = nil, battery: BatteryStatus? = nil, suspended: Bool? = nil, bolusing: Bool? = nil, reservoir: Double? = nil) { self.clock = clock self.iob = iob self.battery = battery + self.suspended = suspended + self.bolusing = bolusing + self.reservoir = reservoir } public var dictionaryRepresentation: [String: AnyObject] { From 7558c11dd5137d79fef62bb3158d2d570505a2f5 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Fri, 29 Jul 2016 12:25:47 -0500 Subject: [PATCH 09/35] Add copy-frameworks build phase for app store submission --- RileyLink.xcodeproj/project.pbxproj | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 7ce5e3968..febdea0ad 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -1365,6 +1365,7 @@ C12EA234198B436800309FA4 /* Frameworks */, C12EA235198B436800309FA4 /* Resources */, C10D9BB81C82614F00378342 /* Embed Frameworks */, + C1AF21F51D4BC0C30088C41D /* ShellScript */, ); buildRules = ( ); @@ -1589,6 +1590,23 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + C1AF21F51D4BC0C30088C41D /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/Crypto.framework", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 430D64C61CB855AB00FCA750 /* Sources */ = { isa = PBXSourcesBuildPhase; From 3fe3eb75647828e1acc8331762f1ee6d079ed8e4 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Fri, 29 Jul 2016 13:24:07 -0500 Subject: [PATCH 10/35] Make alarm type more self contained --- .../PumpEvents/PumpAlarmPumpEvent.swift | 58 ++++++++++--------- MinimedKitTests/HistoryPageTests.swift | 15 +++++ 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift index 5fc9a8ef8..72b87b9fd 100644 --- a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift +++ b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift @@ -8,14 +8,33 @@ import Foundation -public enum PumpAlarmType: Int { - case BatteryOutLimitExceeded = 3 - case NoDelivery = 4 - case BatteryDepleted = 5 - case DeviceReset = 16 - case ReprogramError = 61 - case EmptyReservoir = 62 - case UnknownType = -1 +public enum PumpAlarmType { + case BatteryOutLimitExceeded + case NoDelivery + case BatteryDepleted + case DeviceReset + case ReprogramError + case EmptyReservoir + case UnknownType(rawType: UInt8) + + init(rawType: UInt8) { + switch rawType { + case 3: + self = .BatteryOutLimitExceeded + case 4: + self = .NoDelivery + case 5: + self = .BatteryDepleted + case 16: + self = .DeviceReset + case 61: + self = .ReprogramError + case 62: + self = .EmptyReservoir + default: + self = .UnknownType(rawType: rawType) + } + } } public struct PumpAlarmPumpEvent: TimestampedPumpEvent { @@ -23,8 +42,7 @@ public struct PumpAlarmPumpEvent: TimestampedPumpEvent { public let rawData: NSData public let timestamp: NSDateComponents public let alarmType: PumpAlarmType - public let rawType: Int - + public init?(availableData: NSData, pumpModel: PumpModel) { length = 9 @@ -34,30 +52,16 @@ public struct PumpAlarmPumpEvent: TimestampedPumpEvent { rawData = availableData[0.. Date: Fri, 29 Jul 2016 13:39:19 -0500 Subject: [PATCH 11/35] Use structs instead of classes. Because swift. --- NightscoutUploadKit/DeviceStatus/BatteryStatus.swift | 2 +- NightscoutUploadKit/DeviceStatus/DeviceStatus.swift | 2 +- NightscoutUploadKit/DeviceStatus/IOBStatus.swift | 2 +- NightscoutUploadKit/DeviceStatus/LoopEnacted.swift | 2 +- NightscoutUploadKit/DeviceStatus/LoopStatus.swift | 2 +- NightscoutUploadKit/DeviceStatus/LoopSuggested.swift | 2 +- NightscoutUploadKit/DeviceStatus/PumpStatus.swift | 2 +- NightscoutUploadKit/DeviceStatus/UploaderStatus.swift | 11 ++++++----- RileyLink/DeviceDataManager.swift | 11 ++++++++--- 9 files changed, 21 insertions(+), 15 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift index f289f2bf9..4b37c476d 100644 --- a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift @@ -8,7 +8,7 @@ import Foundation -public class BatteryStatus { +public struct BatteryStatus { let percent: Int? let voltage: Double? let status: String diff --git a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift index 9c08023e1..a0c8fc66b 100644 --- a/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/DeviceStatus.swift @@ -8,7 +8,7 @@ import Foundation -public class DeviceStatus { +public struct DeviceStatus { let device: String let timestamp: NSDate let pumpStatus: PumpStatus? diff --git a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift index 8402c38ea..2c3236d1e 100644 --- a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift @@ -8,7 +8,7 @@ import Foundation -public class IOBStatus { +public struct IOBStatus { let iob: Double // basal iob + bolus iob: can be negative let basaliob: Double let timestamp: NSDate diff --git a/NightscoutUploadKit/DeviceStatus/LoopEnacted.swift b/NightscoutUploadKit/DeviceStatus/LoopEnacted.swift index 1fe6e931b..606c902fc 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopEnacted.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopEnacted.swift @@ -8,7 +8,7 @@ import Foundation -public class LoopEnacted { +public struct LoopEnacted { let rate: Double let duration: NSTimeInterval let timestamp: NSDate diff --git a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift index e81ba519f..22b314088 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift @@ -8,7 +8,7 @@ import Foundation -public class LoopStatus { +public struct LoopStatus { let name: String let timestamp: NSDate diff --git a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift index bef59586d..a65895474 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift @@ -8,7 +8,7 @@ import Foundation -public class LoopSuggested { +public struct LoopSuggested { let timestamp: NSDate let rate: Double let duration: NSTimeInterval diff --git a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift index a80ba8fdf..954eb5bb1 100644 --- a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift @@ -8,7 +8,7 @@ import Foundation -public class PumpStatus { +public struct PumpStatus { let clock: NSDate let iob: IOBStatus? let battery: BatteryStatus? diff --git a/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift b/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift index 0cddd9358..a591f566d 100644 --- a/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/UploaderStatus.swift @@ -8,15 +8,16 @@ import Foundation -public class UploaderStatus { - public var batteryPct: Int? = nil - +public struct UploaderStatus { + + public let battery: Int? public let name: String public let timestamp: NSDate - public init(name: String, timestamp: NSDate) { + public init(name: String, timestamp: NSDate, battery: Int? = nil) { self.name = name self.timestamp = timestamp + self.battery = battery } public var dictionaryRepresentation: [String: AnyObject] { @@ -25,7 +26,7 @@ public class UploaderStatus { rval["name"] = name rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) - if let battery = batteryPct { + if let battery = battery { rval["battery"] = battery } diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index a257da826..700d363fa 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -167,11 +167,16 @@ class DeviceDataManager { // Gather UploaderStatus let uploaderDevice = UIDevice.currentDevice() - let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate()) + + + let battery: Int? if uploaderDevice.batteryMonitoringEnabled { - uploaderStatus.batteryPct = Int(uploaderDevice.batteryLevel * 100) + battery = Int(uploaderDevice.batteryLevel * 100) + } else { + battery = nil } - + let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate(), battery: battery) + // Gather PumpStatus from MySentry packet let pumpStatus: PumpStatus? do { From 07ac736780c4b6118b5f36fcd5daab9545331481 Mon Sep 17 00:00:00 2001 From: Nathan Racklyeft Date: Sun, 31 Jul 2016 10:02:44 -0700 Subject: [PATCH 12/35] Adding a stateless upload path for Nightscout treatments (#177) * Adding a stateless upload path for Nightscout treatments * Clarifying return order of history command --- MinimedKit/PumpEventType.swift | 2 +- NightscoutUploadKit/NightscoutUploader.swift | 46 ++++++++++++++------ RileyLinkKit/PumpOps.swift | 2 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/MinimedKit/PumpEventType.swift b/MinimedKit/PumpEventType.swift index 722b72c48..5c7579d96 100644 --- a/MinimedKit/PumpEventType.swift +++ b/MinimedKit/PumpEventType.swift @@ -69,7 +69,7 @@ public enum PumpEventType: UInt8 { case DeleteOtherDeviceID = 0x82 case ChangeCaptureEventEnable = 0x83 - var eventType: PumpEvent.Type { + public var eventType: PumpEvent.Type { switch self { case .BolusNormal: return BolusNormalPumpEvent.self diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 3cd6d3853..181a70553 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -64,7 +64,14 @@ public class NightscoutUploader { } // MARK: - Processing data from pump - + + /** + Enqueues pump history events for upload, with automatic retry management. + + - parameter events: An array of timestamped history events. Only types with known Nightscout mappings will be uploaded. + - parameter source: The device identifier to display in Nightscout + - parameter pumpModel: The pump model info associated with the events + */ public func processPumpEvents(events: [TimestampedHistoryEvent], source: String, pumpModel: PumpModel) { // Find valid event times @@ -99,6 +106,22 @@ public class NightscoutUploader { self.flushAll() } + /** + Attempts to upload pump history events. + + This method will not retry if the network task failed. + + - parameter pumpEvents: An array of timestamped history events. Only types with known Nightscout mappings will be uploaded. + - parameter source: The device identifier to display in Nightscout + - parameter pumpModel: The pump model info associated with the events + - parameter completionHandler: A closure to execute when the task completes. It has a single argument for any error that might have occurred during the upload. + */ + public func upload(pumpEvents: [TimestampedHistoryEvent], forSource source: String, from pumpModel: PumpModel, completionHandler: (ErrorType?) -> Void) { + let treatments = NightscoutPumpEvents.translate(pumpEvents, eventSource: source).map { $0.dictionaryRepresentation } + + uploadToNS(treatments, endpoint: defaultNightscoutTreatmentPath, completion: completionHandler) + } + public func getPumpStatusFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody) throws -> PumpStatus { guard let pumpDate = status.pumpDateComponents.date else { @@ -225,18 +248,15 @@ public class NightscoutUploader { let uploadURL = siteURL.URLByAppendingPathComponent(endpoint) let request = NSMutableURLRequest(URL: uploadURL) + request.HTTPMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.setValue("application/json", forHTTPHeaderField: "Accept") + request.setValue(APISecret.SHA1, forHTTPHeaderField: "api-secret") + do { - - let sendData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted) - request.HTTPMethod = "POST" - - request.setValue("application/json", forHTTPHeaderField:"Content-Type") - request.setValue("application/json", forHTTPHeaderField:"Accept") - request.setValue(APISecret.SHA1, forHTTPHeaderField:"api-secret") - request.HTTPBody = sendData - - let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in - + let sendData = try NSJSONSerialization.dataWithJSONObject(json, options: []) + + let task = NSURLSession.sharedSession().uploadTaskWithRequest(request, fromData: sendData) { (data, response, error) in if let error = error { completion(error) return @@ -248,7 +268,7 @@ public class NightscoutUploader { } else { completion(nil) } - }) + } task.resume() } catch let error as NSError { completion(error) diff --git a/RileyLinkKit/PumpOps.swift b/RileyLinkKit/PumpOps.swift index 4902eabf2..9712138d5 100644 --- a/RileyLinkKit/PumpOps.swift +++ b/RileyLinkKit/PumpOps.swift @@ -105,7 +105,7 @@ public class PumpOps { - parameter startDate: The earliest date of events to retrieve - parameter completion: A closure called after the command is complete. This closure takes a single Result argument: - - Success(events): An array of fetched history entries + - Success(events): An array of fetched history entries, in ascending order of insertion - Failure(error): An error describing why the command failed */ From 169eba5b870be3c3bc22f18eb85540b256dea460 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Sun, 31 Jul 2016 22:57:40 -0500 Subject: [PATCH 13/35] Bundle up fetching of common pump status items into single call, add fetching of bolusing and suspended states --- MinimedKit/MessageType.swift | 3 ++ .../Messages/ReadPumpStatusMessageBody.swift | 27 ++++++++++++++ .../ReadRemainingInsulinMessageBody.swift | 2 +- RileyLink.xcodeproj/project.pbxproj | 4 +++ RileyLink/DeviceDataManager.swift | 2 +- RileyLinkKit/PumpOps.swift | 24 +++++++++++++ RileyLinkKit/PumpOpsSynchronous.swift | 35 +++++++++++++++++++ .../RileyLinkDeviceTableViewController.swift | 20 ++++++----- 8 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 MinimedKit/Messages/ReadPumpStatusMessageBody.swift diff --git a/MinimedKit/MessageType.swift b/MinimedKit/MessageType.swift index a4df84169..7d4915860 100644 --- a/MinimedKit/MessageType.swift +++ b/MinimedKit/MessageType.swift @@ -28,6 +28,7 @@ public enum MessageType: UInt8 { case GetPumpModel = 0x8d case ReadTempBasal = 0x98 case ReadSettings = 0xc0 + case ReadPumpStatus = 0xce var bodyType: MessageBody.Type { switch self { @@ -59,6 +60,8 @@ public enum MessageType: UInt8 { return GetBatteryCarelinkMessageBody.self case .ReadRemainingInsulin: return ReadRemainingInsulinMessageBody.self + case .ReadPumpStatus: + return ReadPumpStatusMessageBody.self default: return UnknownMessageBody.self } diff --git a/MinimedKit/Messages/ReadPumpStatusMessageBody.swift b/MinimedKit/Messages/ReadPumpStatusMessageBody.swift new file mode 100644 index 000000000..7ab72f975 --- /dev/null +++ b/MinimedKit/Messages/ReadPumpStatusMessageBody.swift @@ -0,0 +1,27 @@ +// +// ReadPumpStatusMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 7/31/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ReadPumpStatusMessageBody: CarelinkLongMessageBody { + + public let bolusing: Bool + public let suspended: Bool + + public required init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + return nil + } + + bolusing = (rxData[2] as UInt8) > 0 + suspended = (rxData[3] as UInt8) > 0 + + super.init(rxData: rxData) + } + +} diff --git a/MinimedKit/Messages/ReadRemainingInsulinMessageBody.swift b/MinimedKit/Messages/ReadRemainingInsulinMessageBody.swift index 35af7dff3..f5ec46ae6 100644 --- a/MinimedKit/Messages/ReadRemainingInsulinMessageBody.swift +++ b/MinimedKit/Messages/ReadRemainingInsulinMessageBody.swift @@ -6,7 +6,7 @@ // Copyright © 2016 Pete Schwamb. All rights reserved. // -import UIKit +import Foundation public class ReadRemainingInsulinMessageBody: CarelinkLongMessageBody { diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 444365f6b..b2d9c3431 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ C1711A5C1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1711A5B1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift */; }; C1711A5E1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1711A5D1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift */; }; C174F26B19EB824D00398C72 /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C178845D1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */; }; C1842BBB1C8E184300DB42AC /* PumpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBA1C8E184300DB42AC /* PumpModel.swift */; }; C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */; }; C1842BBF1C8E855A00DB42AC /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */; }; @@ -520,6 +521,7 @@ C1711A5D1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetHistoryPageCarelinkMessageBody.swift; sourceTree = ""; }; C174F26919EB824D00398C72 /* ISO8601DateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601DateFormatter.h; sourceTree = ""; }; C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ISO8601DateFormatter.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadPumpStatusMessageBody.swift; sourceTree = ""; }; C1842BBA1C8E184300DB42AC /* PumpModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModel.swift; sourceTree = ""; }; C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEvent.swift; sourceTree = ""; }; C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = PumpEventType.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -1222,6 +1224,7 @@ 43CA932C1CB8CFA1000026B5 /* ReadTempBasalCarelinkMessageBody.swift */, 43CA932D1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift */, C1EAD6C41C826B92006DBA60 /* UnknownMessageBody.swift */, + C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */, ); path = Messages; sourceTree = ""; @@ -1712,6 +1715,7 @@ C1842C041C8FA45100DB42AC /* DeleteOtherDeviceIDPumpEvent.swift in Sources */, C1842C0B1C8FA45100DB42AC /* ChangeTimePumpEvent.swift in Sources */, C1842C0D1C8FA45100DB42AC /* TempBasalPumpEvent.swift in Sources */, + C178845D1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift in Sources */, 43B0ADCB1D126B1100AAD278 /* SelectBasalProfilePumpEvent.swift in Sources */, C1842C0C1C8FA45100DB42AC /* ChangeTimeFormatPumpEvent.swift in Sources */, C10AB08D1C855613000F102E /* FindDeviceMessageBody.swift in Sources */, diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 700d363fa..b8923b04e 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -178,7 +178,7 @@ class DeviceDataManager { let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate(), battery: battery) // Gather PumpStatus from MySentry packet - let pumpStatus: PumpStatus? + let pumpStatus: NightscoutUploadKit.PumpStatus? do { pumpStatus = try remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) } catch { diff --git a/RileyLinkKit/PumpOps.swift b/RileyLinkKit/PumpOps.swift index 4902eabf2..bdc599e4a 100644 --- a/RileyLinkKit/PumpOps.swift +++ b/RileyLinkKit/PumpOps.swift @@ -149,6 +149,30 @@ public class PumpOps { } } + + /** + Reads clock, reservoir, battery, bolusing, and suspended state from pump + + This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. + + - parameter completion: A closure called after the command is complete. This closure takes a single Result argument: + - Success(status): A structure describing the current status of the pump + - Failure(error): An error describing why the command failed + */ + public func readPumpStatus(completion: (Either) -> Void) { + device.runSession { (session) in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + + do { + let response: PumpStatus = try ops.readPumpStatus() + completion(.Success(response)) + } catch let error { + completion(.Failure(error)) + } + } + } + + /** Sets a bolus diff --git a/RileyLinkKit/PumpOpsSynchronous.swift b/RileyLinkKit/PumpOpsSynchronous.swift index ead51960d..104f6f196 100644 --- a/RileyLinkKit/PumpOpsSynchronous.swift +++ b/RileyLinkKit/PumpOpsSynchronous.swift @@ -411,6 +411,41 @@ class PumpOpsSynchronous { } return frameData } + + internal func readPumpStatus() throws -> PumpStatus { + let clockResp: ReadTimeCarelinkMessageBody = try getMessageBodyWithType(.ReadTime) + + let pumpModel = try getPumpModel() + + let resResp: ReadRemainingInsulinMessageBody = try getMessageBodyWithType(.ReadRemainingInsulin) + + let reservoir = resResp.getUnitsRemainingForStrokes(pumpModel.strokesPerUnit) + + let battResp: GetBatteryCarelinkMessageBody = try getMessageBodyWithType(.GetBattery) + + let statusResp: ReadPumpStatusMessageBody = try getMessageBodyWithType(.ReadPumpStatus) + + return PumpStatus(clock: clockResp.dateComponents, batteryVolts: battResp.volts, suspended: statusResp.suspended, bolusing: statusResp.bolusing, reservoir: reservoir, model: pumpModel) + + } +} + +public struct PumpStatus { + let clock: NSDateComponents + let batteryVolts: Double + let suspended: Bool + let bolusing: Bool + let reservoir: Double + let model: PumpModel + + public init(clock: NSDateComponents, batteryVolts: Double, suspended: Bool, bolusing: Bool, reservoir: Double, model: PumpModel) { + self.clock = clock + self.batteryVolts = batteryVolts + self.suspended = suspended + self.bolusing = bolusing + self.reservoir = reservoir + self.model = model + } } public struct FrequencyTrial { diff --git a/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift b/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift index ab24ec932..47abbee69 100644 --- a/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift +++ b/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift @@ -153,7 +153,7 @@ public class RileyLinkDeviceTableViewController: UITableViewController, TextFiel case DumpHistory case GetPumpModel case PressDownButton - case ReadRemainingInsulin + case ReadPumpStatus static let count = 7 } @@ -288,8 +288,8 @@ public class RileyLinkDeviceTableViewController: UITableViewController, TextFiel case .PressDownButton: cell.textLabel?.text = NSLocalizedString("Send Button Press", comment: "The title of the command to send a button press") - case .ReadRemainingInsulin: - cell.textLabel?.text = NSLocalizedString("Read Remaining Insulin", comment: "The title of the command to read remaining insulin") + case .ReadPumpStatus: + cell.textLabel?.text = NSLocalizedString("Read Pump Status", comment: "The title of the command to read pump status") } } @@ -477,21 +477,25 @@ public class RileyLinkDeviceTableViewController: UITableViewController, TextFiel }) return NSLocalizedString("Sending button press…", comment: "Progress message for sending button press to pump.") } - case .ReadRemainingInsulin: + case .ReadPumpStatus: vc = CommandResponseViewController { [unowned self] (completionHandler) -> String in - self.device.ops?.readRemainingInsulin { (result) in + self.device.ops?.readPumpStatus { (result) in dispatch_async(dispatch_get_main_queue()) { switch result { - case .Success(let units): - completionHandler(responseText: String(format: NSLocalizedString("%1$@ Units remaining", comment: "The format string describing units of insulin remaining: (1: number of units)"), self.decimalFormatter.stringFromNumber(units)!)) + case .Success(let status): + var str = String(format: NSLocalizedString("%1$@ Units of insulin remaining\n", comment: "The format string describing units of insulin remaining: (1: number of units)"), self.decimalFormatter.stringFromNumber(status.reservoir)!) + str += String(format: NSLocalizedString("Battery: %1$@ volts\n", comment: "The format string describing pump battery voltage: (1: battery voltage)"), self.decimalFormatter.stringFromNumber(status.batteryVolts)!) + str += String(format: NSLocalizedString("Suspended: %1$@\n", comment: "The format string describing pump suspended state: (1: suspended)"), status.suspended.description) + str += String(format: NSLocalizedString("Bolusing: %1$@\n", comment: "The format string describing pump bolusing state: (1: bolusing)"), status.bolusing.description) + completionHandler(responseText: str) case .Failure(let error): completionHandler(responseText: String(error)) } } } - return NSLocalizedString("Reading remaining insulin…", comment: "Progress message for reading pump insulin reservoir volume") + return NSLocalizedString("Reading pump status…", comment: "Progress message for reading pump status") } } From d9cf8f7517854bb45673d92299e574631df919f6 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 1 Aug 2016 10:19:12 -0500 Subject: [PATCH 14/35] Add battery status to PumpStatus --- .../GetBatteryCarelinkMessageBody.swift | 28 +++++++++++++------ RileyLinkKit/PumpOps.swift | 4 +-- RileyLinkKit/PumpOpsSynchronous.swift | 12 ++------ .../RileyLinkDeviceTableViewController.swift | 4 +-- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/MinimedKit/Messages/GetBatteryCarelinkMessageBody.swift b/MinimedKit/Messages/GetBatteryCarelinkMessageBody.swift index 681633019..a8dd6f8ff 100644 --- a/MinimedKit/Messages/GetBatteryCarelinkMessageBody.swift +++ b/MinimedKit/Messages/GetBatteryCarelinkMessageBody.swift @@ -8,25 +8,37 @@ import Foundation +public enum BatteryStatus { + case Low + case Normal + case Unknown(rawVal: UInt8) + + init(statusByte: UInt8) { + switch statusByte { + case 1: + self = .Low + case 0: + self = .Normal + default: + self = .Unknown(rawVal: statusByte) + } + } +} + public class GetBatteryCarelinkMessageBody: CarelinkLongMessageBody { - public let status: String + public let status: BatteryStatus public let volts: Double public required init?(rxData: NSData) { guard rxData.length == self.dynamicType.length else { - status = "" volts = 0 + status = .Unknown(rawVal: 0) super.init(rxData: rxData) return nil } volts = Double(Int(rxData[2] as UInt8) << 8 + Int(rxData[3] as UInt8)) / 100.0 - - if rxData[1] as UInt8 > 0 { - status = "Low" - } else { - status = "Normal" - } + status = BatteryStatus(statusByte: rxData[1] as UInt8) super.init(rxData: rxData) } diff --git a/RileyLinkKit/PumpOps.swift b/RileyLinkKit/PumpOps.swift index bdc599e4a..59358020c 100644 --- a/RileyLinkKit/PumpOps.swift +++ b/RileyLinkKit/PumpOps.swift @@ -156,8 +156,8 @@ public class PumpOps { This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - parameter completion: A closure called after the command is complete. This closure takes a single Result argument: - - Success(status): A structure describing the current status of the pump - - Failure(error): An error describing why the command failed + - Success(status): A structure describing the current status of the pump + - Failure(error): An error describing why the command failed */ public func readPumpStatus(completion: (Either) -> Void) { device.runSession { (session) in diff --git a/RileyLinkKit/PumpOpsSynchronous.swift b/RileyLinkKit/PumpOpsSynchronous.swift index 104f6f196..a7c3a8c83 100644 --- a/RileyLinkKit/PumpOpsSynchronous.swift +++ b/RileyLinkKit/PumpOpsSynchronous.swift @@ -425,7 +425,7 @@ class PumpOpsSynchronous { let statusResp: ReadPumpStatusMessageBody = try getMessageBodyWithType(.ReadPumpStatus) - return PumpStatus(clock: clockResp.dateComponents, batteryVolts: battResp.volts, suspended: statusResp.suspended, bolusing: statusResp.bolusing, reservoir: reservoir, model: pumpModel) + return PumpStatus(clock: clockResp.dateComponents, batteryVolts: battResp.volts, batteryStatus: battResp.status, suspended: statusResp.suspended, bolusing: statusResp.bolusing, reservoir: reservoir, model: pumpModel) } } @@ -433,19 +433,11 @@ class PumpOpsSynchronous { public struct PumpStatus { let clock: NSDateComponents let batteryVolts: Double + let batteryStatus: BatteryStatus let suspended: Bool let bolusing: Bool let reservoir: Double let model: PumpModel - - public init(clock: NSDateComponents, batteryVolts: Double, suspended: Bool, bolusing: Bool, reservoir: Double, model: PumpModel) { - self.clock = clock - self.batteryVolts = batteryVolts - self.suspended = suspended - self.bolusing = bolusing - self.reservoir = reservoir - self.model = model - } } public struct FrequencyTrial { diff --git a/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift b/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift index 47abbee69..e418a9211 100644 --- a/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift +++ b/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift @@ -486,8 +486,8 @@ public class RileyLinkDeviceTableViewController: UITableViewController, TextFiel case .Success(let status): var str = String(format: NSLocalizedString("%1$@ Units of insulin remaining\n", comment: "The format string describing units of insulin remaining: (1: number of units)"), self.decimalFormatter.stringFromNumber(status.reservoir)!) str += String(format: NSLocalizedString("Battery: %1$@ volts\n", comment: "The format string describing pump battery voltage: (1: battery voltage)"), self.decimalFormatter.stringFromNumber(status.batteryVolts)!) - str += String(format: NSLocalizedString("Suspended: %1$@\n", comment: "The format string describing pump suspended state: (1: suspended)"), status.suspended.description) - str += String(format: NSLocalizedString("Bolusing: %1$@\n", comment: "The format string describing pump bolusing state: (1: bolusing)"), status.bolusing.description) + str += String(format: NSLocalizedString("Suspended: %1$@\n", comment: "The format string describing pump suspended state: (1: suspended)"), String(status.suspended)) + str += String(format: NSLocalizedString("Bolusing: %1$@\n", comment: "The format string describing pump bolusing state: (1: bolusing)"), String(status.bolusing)) completionHandler(responseText: str) case .Failure(let error): completionHandler(responseText: String(error)) From adcdc92f385312fccc35a35ee8104ef9c80ae561 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Wed, 27 Jul 2016 19:20:21 -0500 Subject: [PATCH 15/35] Stop processing history events if we get to a pump alarm that indicates the pump lost track of time --- .../PumpEvents/ChangeTimePumpEvent.swift | 2 +- .../PumpEvents/PumpAlarmPumpEvent.swift | 29 ++++++++++++++++++- RileyLinkKit/PumpOpsSynchronous.swift | 10 +++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift b/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift index 8126dbf5a..99ebb210a 100644 --- a/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift +++ b/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift @@ -30,7 +30,7 @@ public struct ChangeTimePumpEvent: TimestampedPumpEvent { oldTimestamp = NSDateComponents(pumpEventData: availableData, offset: 2) timestamp = NSDateComponents(pumpEventData: availableData, offset: 9) } - + public var dictionaryRepresentation: [String: AnyObject] { return [ "_type": "ChangeTime", diff --git a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift index b4d47f5e7..5fc9a8ef8 100644 --- a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift +++ b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift @@ -8,11 +8,22 @@ import Foundation +public enum PumpAlarmType: Int { + case BatteryOutLimitExceeded = 3 + case NoDelivery = 4 + case BatteryDepleted = 5 + case DeviceReset = 16 + case ReprogramError = 61 + case EmptyReservoir = 62 + case UnknownType = -1 +} + public struct PumpAlarmPumpEvent: TimestampedPumpEvent { public let length: Int public let rawData: NSData public let timestamp: NSDateComponents - let rawType: Int + public let alarmType: PumpAlarmType + public let rawType: Int public init?(availableData: NSData, pumpModel: PumpModel) { length = 9 @@ -24,13 +35,29 @@ public struct PumpAlarmPumpEvent: TimestampedPumpEvent { rawData = availableData[0.. Date: Fri, 29 Jul 2016 12:25:47 -0500 Subject: [PATCH 16/35] Add copy-frameworks build phase for app store submission --- RileyLink.xcodeproj/project.pbxproj | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index b2d9c3431..02a53666f 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -1408,6 +1408,7 @@ C12EA234198B436800309FA4 /* Frameworks */, C12EA235198B436800309FA4 /* Resources */, C10D9BB81C82614F00378342 /* Embed Frameworks */, + C1AF21F51D4BC0C30088C41D /* ShellScript */, ); buildRules = ( ); @@ -1632,6 +1633,23 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + C1AF21F51D4BC0C30088C41D /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/Crypto.framework", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 430D64C61CB855AB00FCA750 /* Sources */ = { isa = PBXSourcesBuildPhase; From ba06c5e173c5de765cba8569bde1e969bbac2849 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Fri, 29 Jul 2016 13:24:07 -0500 Subject: [PATCH 17/35] Make alarm type more self contained --- .../PumpEvents/PumpAlarmPumpEvent.swift | 58 ++++++++++--------- MinimedKitTests/HistoryPageTests.swift | 15 +++++ 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift index 5fc9a8ef8..72b87b9fd 100644 --- a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift +++ b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift @@ -8,14 +8,33 @@ import Foundation -public enum PumpAlarmType: Int { - case BatteryOutLimitExceeded = 3 - case NoDelivery = 4 - case BatteryDepleted = 5 - case DeviceReset = 16 - case ReprogramError = 61 - case EmptyReservoir = 62 - case UnknownType = -1 +public enum PumpAlarmType { + case BatteryOutLimitExceeded + case NoDelivery + case BatteryDepleted + case DeviceReset + case ReprogramError + case EmptyReservoir + case UnknownType(rawType: UInt8) + + init(rawType: UInt8) { + switch rawType { + case 3: + self = .BatteryOutLimitExceeded + case 4: + self = .NoDelivery + case 5: + self = .BatteryDepleted + case 16: + self = .DeviceReset + case 61: + self = .ReprogramError + case 62: + self = .EmptyReservoir + default: + self = .UnknownType(rawType: rawType) + } + } } public struct PumpAlarmPumpEvent: TimestampedPumpEvent { @@ -23,8 +42,7 @@ public struct PumpAlarmPumpEvent: TimestampedPumpEvent { public let rawData: NSData public let timestamp: NSDateComponents public let alarmType: PumpAlarmType - public let rawType: Int - + public init?(availableData: NSData, pumpModel: PumpModel) { length = 9 @@ -34,30 +52,16 @@ public struct PumpAlarmPumpEvent: TimestampedPumpEvent { rawData = availableData[0.. Date: Sun, 31 Jul 2016 10:02:44 -0700 Subject: [PATCH 18/35] Adding a stateless upload path for Nightscout treatments (#177) * Adding a stateless upload path for Nightscout treatments * Clarifying return order of history command --- MinimedKit/PumpEventType.swift | 2 +- NightscoutUploadKit/NightscoutUploader.swift | 46 ++++++++++++++------ RileyLinkKit/PumpOps.swift | 2 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/MinimedKit/PumpEventType.swift b/MinimedKit/PumpEventType.swift index 722b72c48..5c7579d96 100644 --- a/MinimedKit/PumpEventType.swift +++ b/MinimedKit/PumpEventType.swift @@ -69,7 +69,7 @@ public enum PumpEventType: UInt8 { case DeleteOtherDeviceID = 0x82 case ChangeCaptureEventEnable = 0x83 - var eventType: PumpEvent.Type { + public var eventType: PumpEvent.Type { switch self { case .BolusNormal: return BolusNormalPumpEvent.self diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 3cd6d3853..181a70553 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -64,7 +64,14 @@ public class NightscoutUploader { } // MARK: - Processing data from pump - + + /** + Enqueues pump history events for upload, with automatic retry management. + + - parameter events: An array of timestamped history events. Only types with known Nightscout mappings will be uploaded. + - parameter source: The device identifier to display in Nightscout + - parameter pumpModel: The pump model info associated with the events + */ public func processPumpEvents(events: [TimestampedHistoryEvent], source: String, pumpModel: PumpModel) { // Find valid event times @@ -99,6 +106,22 @@ public class NightscoutUploader { self.flushAll() } + /** + Attempts to upload pump history events. + + This method will not retry if the network task failed. + + - parameter pumpEvents: An array of timestamped history events. Only types with known Nightscout mappings will be uploaded. + - parameter source: The device identifier to display in Nightscout + - parameter pumpModel: The pump model info associated with the events + - parameter completionHandler: A closure to execute when the task completes. It has a single argument for any error that might have occurred during the upload. + */ + public func upload(pumpEvents: [TimestampedHistoryEvent], forSource source: String, from pumpModel: PumpModel, completionHandler: (ErrorType?) -> Void) { + let treatments = NightscoutPumpEvents.translate(pumpEvents, eventSource: source).map { $0.dictionaryRepresentation } + + uploadToNS(treatments, endpoint: defaultNightscoutTreatmentPath, completion: completionHandler) + } + public func getPumpStatusFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody) throws -> PumpStatus { guard let pumpDate = status.pumpDateComponents.date else { @@ -225,18 +248,15 @@ public class NightscoutUploader { let uploadURL = siteURL.URLByAppendingPathComponent(endpoint) let request = NSMutableURLRequest(URL: uploadURL) + request.HTTPMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.setValue("application/json", forHTTPHeaderField: "Accept") + request.setValue(APISecret.SHA1, forHTTPHeaderField: "api-secret") + do { - - let sendData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted) - request.HTTPMethod = "POST" - - request.setValue("application/json", forHTTPHeaderField:"Content-Type") - request.setValue("application/json", forHTTPHeaderField:"Accept") - request.setValue(APISecret.SHA1, forHTTPHeaderField:"api-secret") - request.HTTPBody = sendData - - let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in - + let sendData = try NSJSONSerialization.dataWithJSONObject(json, options: []) + + let task = NSURLSession.sharedSession().uploadTaskWithRequest(request, fromData: sendData) { (data, response, error) in if let error = error { completion(error) return @@ -248,7 +268,7 @@ public class NightscoutUploader { } else { completion(nil) } - }) + } task.resume() } catch let error as NSError { completion(error) diff --git a/RileyLinkKit/PumpOps.swift b/RileyLinkKit/PumpOps.swift index 59358020c..1cee3002e 100644 --- a/RileyLinkKit/PumpOps.swift +++ b/RileyLinkKit/PumpOps.swift @@ -105,7 +105,7 @@ public class PumpOps { - parameter startDate: The earliest date of events to retrieve - parameter completion: A closure called after the command is complete. This closure takes a single Result argument: - - Success(events): An array of fetched history entries + - Success(events): An array of fetched history entries, in ascending order of insertion - Failure(error): An error describing why the command failed */ From e7ca0ca7a253681afed789b344442a7fb99efdaf Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 1 Aug 2016 09:31:33 -0500 Subject: [PATCH 19/35] updating to match Loop DDM more closely --- RileyLink/DeviceDataManager.swift | 51 +++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index b8923b04e..0cf4784e8 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -89,10 +89,6 @@ class DeviceDataManager { } } - func receivedRileyLinkManagerNotification(note: NSNotification) { - NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) - } - func preferredRileyLink() -> RileyLinkDevice? { if let device = lastRileyLinkHeardFrom { return device @@ -100,7 +96,11 @@ class DeviceDataManager { return self.rileyLinkManager.firstConnectedDevice } - func receivedRileyLinkPacketNotification(note: NSNotification) { + @objc private func receivedRileyLinkManagerNotification(note: NSNotification) { + NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) + } + + @objc private func receivedRileyLinkPacketNotification(note: NSNotification) { if let device = note.object as? RileyLinkDevice, data = note.userInfo?[RileyLinkDevice.IdleMessageDataKey] as? NSData, @@ -132,6 +132,39 @@ class DeviceDataManager { } } + @objc private func receivedRileyLinkTimerTickNotification(note: NSNotification) { +// backfillGlucoseFromShareIfNeeded() { +// self.assertCurrentPumpData() +// } + } + + /** + Ensures pump data is current by either waking and polling, or ensuring we're listening to sentry packets. + */ + private func assertCurrentPumpData() { + guard let device = rileyLinkManager.firstConnectedDevice else { + return + } + + device.assertIdleListening() + + // How long should we wait before we poll for new reservoir data? + let reservoirTolerance = rileyLinkManager.idleListeningEnabled ? NSTimeInterval(minutes: 11) : NSTimeInterval(minutes: 4) + + // If we don't yet have reservoir data, or it's old, poll for it. + if latestReservoirValue == nil || latestReservoirValue!.startDate.timeIntervalSinceNow <= -reservoirTolerance { + readReservoirVolume { (result) in + switch result { + case .Success(let (units, date)): + self.updateReservoirVolume(units, atDate: date, withTimeLeft: nil) + case .Failure: + self.troubleshootPumpCommsWithDevice(device) + } + } + } + } + + func connectToRileyLink(device: RileyLinkDevice) { connectedPeripheralIDs.insert(device.peripheral.identifier.UUIDString) @@ -276,10 +309,10 @@ class DeviceDataManager { self?.receivedRileyLinkManagerNotification(note) } - // TODO: Use delegation instead. - rileyLinkDevicePacketObserver = NSNotificationCenter.defaultCenter().addObserverForName(RileyLinkDevice.DidReceiveIdleMessageNotification, object: nil, queue: nil) { [weak self] (note) -> Void in - self?.receivedRileyLinkPacketNotification(note) - } + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkManagerNotification(_:)), name: nil, object: rileyLinkManager) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkPacketNotification(_:)), name: RileyLinkDevice.DidReceiveIdleMessageNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkTimerTickNotification(_:)), name: RileyLinkDevice.DidUpdateTimerTickNotification, object: nil) + } From bbbae5ccbb506f566ea1ad17bd9f89c267ea4ca4 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 1 Aug 2016 22:11:33 -0500 Subject: [PATCH 20/35] Upload pump status from x22 pumps --- .../DeviceStatus/PumpStatus.swift | 7 +- NightscoutUploadKit/NightscoutUploader.swift | 14 - RileyLink/Config.h | 1 + RileyLink/Config.m | 9 + RileyLink/DeviceDataManager.swift | 334 +++++++++++------- RileyLinkKit/PumpOpsSynchronous.swift | 17 +- 6 files changed, 238 insertions(+), 144 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift index 954eb5bb1..3c6c27a2c 100644 --- a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift @@ -10,14 +10,16 @@ import Foundation public struct PumpStatus { let clock: NSDate + let pumpID: String let iob: IOBStatus? let battery: BatteryStatus? let suspended: Bool? let bolusing: Bool? let reservoir: Double? - public init(clock: NSDate, iob: IOBStatus? = nil, battery: BatteryStatus? = nil, suspended: Bool? = nil, bolusing: Bool? = nil, reservoir: Double? = nil) { + public init(clock: NSDate, pumpID: String, iob: IOBStatus? = nil, battery: BatteryStatus? = nil, suspended: Bool? = nil, bolusing: Bool? = nil, reservoir: Double? = nil) { self.clock = clock + self.pumpID = pumpID self.iob = iob self.battery = battery self.suspended = suspended @@ -29,6 +31,7 @@ public struct PumpStatus { var rval = [String: AnyObject]() rval["clock"] = TimeFormat.timestampStrFromDate(clock) + rval["pumpID"] = pumpID if let battery = battery { rval["battery"] = battery.dictionaryRepresentation @@ -41,7 +44,7 @@ public struct PumpStatus { if let iob = iob { rval["iob"] = iob.dictionaryRepresentation } - + return rval } } \ No newline at end of file diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 181a70553..0c5471f12 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -122,20 +122,6 @@ public class NightscoutUploader { uploadToNS(treatments, endpoint: defaultNightscoutTreatmentPath, completion: completionHandler) } - public func getPumpStatusFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody) throws -> PumpStatus { - - guard let pumpDate = status.pumpDateComponents.date else { - throw UploadError.MissingTimezone - } - - let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") - let iobStatus = IOBStatus(iob: status.iob, basaliob: 0, timestamp: pumpDate) - - let pumpStatus = PumpStatus(clock: pumpDate, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) - - return pumpStatus - } - public func uploadDeviceStatus(status: DeviceStatus) { deviceStatuses.append(status.dictionaryRepresentation) flushAll() diff --git a/RileyLink/Config.h b/RileyLink/Config.h index a56d92aeb..dd3b89aa9 100644 --- a/RileyLink/Config.h +++ b/RileyLink/Config.h @@ -17,6 +17,7 @@ @property (nonatomic, nullable, strong) NSURL *nightscoutURL; @property (nonatomic, nullable, strong) NSString *nightscoutAPISecret; @property (nonatomic, nullable, strong) NSString *pumpID; +@property (nonatomic, nullable, strong) NSString *pumpModelNumber; @property (nonatomic, nullable, strong) NSTimeZone *pumpTimeZone; @property (nonatomic, nullable, strong) NSSet *autoConnectIds; @property (nonatomic, assign) BOOL uploadEnabled; diff --git a/RileyLink/Config.m b/RileyLink/Config.m index 4f7922d5c..6f7dd85f0 100644 --- a/RileyLink/Config.m +++ b/RileyLink/Config.m @@ -64,6 +64,15 @@ - (NSString*) pumpID { return [_defaults stringForKey:@"pumpID"]; } +- (void) setPumpModelNumber:(NSString *)pumpModelNumber { + [_defaults setValue:pumpModelNumber forKey:@"pumpModelNumber"]; +} + +- (NSString*) pumpModelNumber { + return [_defaults stringForKey:@"pumpModelNumber"]; +} + + - (void) setPumpTimeZone:(NSTimeZone *)pumpTimeZone { if (pumpTimeZone) { diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 0cf4784e8..9c56ed89f 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -29,45 +29,87 @@ class DeviceDataManager { } } - var latestPumpStatus: MySentryPumpStatusMessageBody? + var latestPumpStatusDate: NSDate? - var pumpTimeZone: NSTimeZone? = Config.sharedInstance().pumpTimeZone { + var latestPumpStatusFromMySentry: MySentryPumpStatusMessageBody? { didSet { - Config.sharedInstance().pumpTimeZone = pumpTimeZone - - if let pumpTimeZone = pumpTimeZone { - - if let pumpState = rileyLinkManager.pumpState { - pumpState.timeZone = pumpTimeZone - } + if let update = latestPumpStatusFromMySentry, let timeZone = pumpState?.timeZone { + let pumpClock = update.pumpDateComponents + pumpClock.timeZone = timeZone + latestPumpStatusDate = pumpClock.date } } } - - var pumpID: String? = Config.sharedInstance().pumpID { + + + var latestPolledPumpStatus: RileyLinkKit.PumpStatus? { didSet { - if pumpID?.characters.count != 6 { - pumpID = nil + if let update = latestPolledPumpStatus, let timeZone = pumpState?.timeZone { + let pumpClock = update.clock + pumpClock.timeZone = timeZone + latestPumpStatusDate = pumpClock.date + } + } + } + + var pumpID: String? { + get { + return pumpState?.pumpID + } + set { + guard newValue?.characters.count == 6 && newValue != pumpState?.pumpID else { + return } - if let pumpID = pumpID { + if let pumpID = newValue { let pumpState = PumpState(pumpID: pumpID) - if let timeZone = pumpTimeZone { + if let timeZone = self.pumpState?.timeZone { pumpState.timeZone = timeZone } - rileyLinkManager.pumpState = pumpState + self.pumpState = pumpState } else { - rileyLinkManager.pumpState = nil + self.pumpState = nil } - + remoteDataManager.nightscoutUploader?.reset() Config.sharedInstance().pumpID = pumpID } } + var pumpState: PumpState? { + didSet { + rileyLinkManager.pumpState = pumpState + + if let oldValue = oldValue { + NSNotificationCenter.defaultCenter().removeObserver(self, name: PumpState.ValuesDidChangeNotification, object: oldValue) + } + + if let pumpState = pumpState { + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(pumpStateValuesDidChange(_:)), name: PumpState.ValuesDidChangeNotification, object: pumpState) + } + } + } + + @objc private func pumpStateValuesDidChange(note: NSNotification) { + switch note.userInfo?[PumpState.PropertyKey] as? String { + case "timeZone"?: + Config.sharedInstance().pumpTimeZone = pumpState?.timeZone + case "pumpModel"?: + if let sentrySupported = pumpState?.pumpModel?.larger { + rileyLinkManager.idleListeningEnabled = sentrySupported + rileyLinkManager.timerTickEnabled = !sentrySupported + } + Config.sharedInstance().pumpModelNumber = pumpState?.pumpModel?.rawValue + case "lastHistoryDump"?, "awakeUntil"?: + break + default: + break + } + } + var lastHistoryAttempt: NSDate? = nil var lastRileyLinkHeardFrom: RileyLinkDevice? = nil @@ -89,6 +131,10 @@ class DeviceDataManager { } } + @objc private func receivedRileyLinkManagerNotification(note: NSNotification) { + NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) + } + func preferredRileyLink() -> RileyLinkDevice? { if let device = lastRileyLinkHeardFrom { return device @@ -96,33 +142,24 @@ class DeviceDataManager { return self.rileyLinkManager.firstConnectedDevice } - @objc private func receivedRileyLinkManagerNotification(note: NSNotification) { - NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) - } - + /** + Called when a new idle message is received by the RileyLink. + + Only MySentryPumpStatus messages are handled. + + - parameter note: The notification object + */ @objc private func receivedRileyLinkPacketNotification(note: NSNotification) { if let device = note.object as? RileyLinkDevice, data = note.userInfo?[RileyLinkDevice.IdleMessageDataKey] as? NSData, message = PumpMessage(rxData: data) { - lastRileyLinkHeardFrom = device switch message.packetType { case .MySentry: switch message.messageBody { case let body as MySentryPumpStatusMessageBody: - updatePumpStatus(body, fromDevice: device) - case is MySentryAlertMessageBody: - break - // TODO: de-dupe - // logger?.addMessage(body.dictionaryRepresentation, toCollection: "sentryAlert") - case is MySentryAlertClearedMessageBody: - break - // TODO: de-dupe - // logger?.addMessage(body.dictionaryRepresentation, toCollection: "sentryAlert") - case is UnknownMessageBody: - break - //logger?.addMessage(body.dictionaryRepresentation, toCollection: "sentryOther") + pumpStatusUpdateReceived(body, fromDevice: device) default: break } @@ -133,35 +170,7 @@ class DeviceDataManager { } @objc private func receivedRileyLinkTimerTickNotification(note: NSNotification) { -// backfillGlucoseFromShareIfNeeded() { -// self.assertCurrentPumpData() -// } - } - - /** - Ensures pump data is current by either waking and polling, or ensuring we're listening to sentry packets. - */ - private func assertCurrentPumpData() { - guard let device = rileyLinkManager.firstConnectedDevice else { - return - } - - device.assertIdleListening() - - // How long should we wait before we poll for new reservoir data? - let reservoirTolerance = rileyLinkManager.idleListeningEnabled ? NSTimeInterval(minutes: 11) : NSTimeInterval(minutes: 4) - - // If we don't yet have reservoir data, or it's old, poll for it. - if latestReservoirValue == nil || latestReservoirValue!.startDate.timeIntervalSinceNow <= -reservoirTolerance { - readReservoirVolume { (result) in - switch result { - case .Success(let (units, date)): - self.updateReservoirVolume(units, atDate: date, withTimeLeft: nil) - case .Failure: - self.troubleshootPumpCommsWithDevice(device) - } - } - } + self.assertCurrentPumpData() } @@ -177,12 +186,13 @@ class DeviceDataManager { rileyLinkManager.disconnectDevice(device) } - private func updatePumpStatus(status: MySentryPumpStatusMessageBody, fromDevice device: RileyLinkDevice) { - status.pumpDateComponents.timeZone = pumpTimeZone - status.glucoseDateComponents?.timeZone = pumpTimeZone - - if status != latestPumpStatus { - latestPumpStatus = status + private func pumpStatusUpdateReceived(status: MySentryPumpStatusMessageBody, fromDevice device: RileyLinkDevice) { + status.pumpDateComponents.timeZone = pumpState?.timeZone + status.glucoseDateComponents?.timeZone = pumpState?.timeZone + + // Avoid duplicates + if status != latestPumpStatusFromMySentry { + latestPumpStatusFromMySentry = status // Sentry packets are sent in groups of 3, 5s apart. Wait 11s to avoid conflicting comms. let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(11 * NSEC_PER_SEC)) @@ -194,47 +204,132 @@ class DeviceDataManager { //NotificationManager.sendPumpBatteryLowNotification() } - guard Config.sharedInstance().uploadEnabled else { + guard Config.sharedInstance().uploadEnabled, let pumpID = pumpID else { return } - - // Gather UploaderStatus - let uploaderDevice = UIDevice.currentDevice() - - - let battery: Int? - if uploaderDevice.batteryMonitoringEnabled { - battery = Int(uploaderDevice.batteryLevel * 100) - } else { - battery = nil - } - let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate(), battery: battery) - + // Gather PumpStatus from MySentry packet let pumpStatus: NightscoutUploadKit.PumpStatus? do { - pumpStatus = try remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) + guard let pumpDate = status.pumpDateComponents.date else { + throw UploadError.MissingTimezone + } + + let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") + let iobStatus = IOBStatus(iob: status.iob, basaliob: 0, timestamp: pumpDate) + + pumpStatus = NightscoutUploadKit.PumpStatus(clock: pumpDate, pumpID: pumpID, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) + } catch { pumpStatus = nil print("Could not get pump status: \(error)") } - - // Mock out some loop data for testing -// let loopTime = NSDate() -// let iob = IOBStatus(iob: 3.0, basaliob: 1.2, timestamp: NSDate()) -// let loopSuggested = LoopSuggested(timestamp: loopTime, rate: 1.2, duration: NSTimeInterval(30*60), correction: 0, eventualBG: 200, reason: "Test Reason", bg: 205, tick: 5) -// let loopEnacted = LoopEnacted(rate: 1.2, duration: NSTimeInterval(30*60), timestamp: loopTime, received: true) -// let loopStatus = LoopStatus(name: "TestLoopName", timestamp: NSDate(), iob: iob, suggested: loopSuggested, enacted: loopEnacted, failureReason: nil) - - // Build DeviceStatus - let deviceStatus = DeviceStatus(device: uploaderDevice.name, timestamp: NSDate(), pumpStatus: pumpStatus, uploaderStatus: uploaderStatus) - remoteDataManager.nightscoutUploader?.uploadDeviceStatus(deviceStatus) + + // Trigger device status upload, even if something is wrong with pumpStatus + self.uploadDeviceStatus(pumpStatus) // Send SGVs remoteDataManager.nightscoutUploader?.uploadSGVFromMySentryPumpStatus(status, device: device.deviceURI) } } + private func uploadDeviceStatus(pumpStatus: NightscoutUploadKit.PumpStatus? /*, loopStatus: LoopStatus */) { + + guard let uploader = remoteDataManager.nightscoutUploader else { + return + } + + + // Gather UploaderStatus + let uploaderDevice = UIDevice.currentDevice() + + let battery: Int? + if uploaderDevice.batteryMonitoringEnabled { + battery = Int(uploaderDevice.batteryLevel * 100) + } else { + battery = nil + } + let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate(), battery: battery) + + + // Mock out some loop data for testing + // let loopTime = NSDate() + // let iob = IOBStatus(iob: 3.0, basaliob: 1.2, timestamp: NSDate()) + // let loopSuggested = LoopSuggested(timestamp: loopTime, rate: 1.2, duration: NSTimeInterval(30*60), correction: 0, eventualBG: 200, reason: "Test Reason", bg: 205, tick: 5) + // let loopEnacted = LoopEnacted(rate: 1.2, duration: NSTimeInterval(30*60), timestamp: loopTime, received: true) + // let loopStatus = LoopStatus(name: "TestLoopName", timestamp: NSDate(), iob: iob, suggested: loopSuggested, enacted: loopEnacted, failureReason: nil) + + // Build DeviceStatus + let deviceStatus = DeviceStatus(device: uploaderDevice.name, timestamp: NSDate(), pumpStatus: pumpStatus, uploaderStatus: uploaderStatus) + + uploader.uploadDeviceStatus(deviceStatus) + } + + /** + Ensures pump data is current by either waking and polling, or ensuring we're listening to sentry packets. + */ + private func assertCurrentPumpData() { + guard let device = rileyLinkManager.firstConnectedDevice else { + return + } + + device.assertIdleListening() + + // How long should we wait before we poll for new pump data? + let pumpStatusAgeTolerance = rileyLinkManager.idleListeningEnabled ? NSTimeInterval(minutes: 11) : NSTimeInterval(minutes: 4) + + // If we don't yet have pump status, or it's old, poll for it. + if latestPumpStatusDate == nil || latestPumpStatusDate!.timeIntervalSinceNow <= -pumpStatusAgeTolerance { + guard let device = rileyLinkManager.firstConnectedDevice else { + return + } + + guard let ops = device.ops else { + self.troubleshootPumpCommsWithDevice(device) + return + } + + ops.readPumpStatus({ (result) in + switch result { + case .Success(let status): + self.latestPolledPumpStatus = status + let battery = BatteryStatus(voltage: status.batteryVolts, status: String(status.batteryStatus).lowercaseString) + status.clock.timeZone = ops.pumpState.timeZone + guard let date = status.clock.date else { + print("Could not interpret clock") + return + } + let nsPumpStatus = NightscoutUploadKit.PumpStatus(clock: date, pumpID: ops.pumpState.pumpID, iob: nil, battery: battery, suspended: status.suspended, bolusing: status.bolusing, reservoir: status.reservoir) + self.uploadDeviceStatus(nsPumpStatus) + case .Failure: + self.troubleshootPumpCommsWithDevice(device) + } + }) + } + } + + /** + Attempts to fix an extended communication failure between a RileyLink device and the pump + + - parameter device: The RileyLink device + */ + private func troubleshootPumpCommsWithDevice(device: RileyLinkDevice) { + + // How long we should wait before we re-tune the RileyLink + let tuneTolerance = NSTimeInterval(minutes: 14) + + if device.lastTuned?.timeIntervalSinceNow <= -tuneTolerance { + device.tunePumpWithResultHandler { (result) in + switch result { + case .Success(let scanResult): + print("Device auto-tuned to \(scanResult.bestFrequency) MHz") + case .Failure(let error): + print("Device auto-tune failed with error: \(error)") + } + } + } + } + private func getPumpHistory(device: RileyLinkDevice) { lastHistoryAttempt = NSDate() @@ -275,45 +370,44 @@ class DeviceDataManager { init() { - let pumpState: PumpState? + let pumpID = Config.sharedInstance().pumpID + + var idleListeningEnabled = true if let pumpID = pumpID { - pumpState = PumpState(pumpID: pumpID) + let pumpState = PumpState(pumpID: pumpID) - if let timeZone = pumpTimeZone { - pumpState?.timeZone = timeZone + if let timeZone = Config.sharedInstance().pumpTimeZone { + pumpState.timeZone = timeZone } - } else { - pumpState = nil + + if let pumpModelNumber = Config.sharedInstance().pumpModelNumber { + if let model = PumpModel(rawValue: pumpModelNumber) { + pumpState.pumpModel = model + + idleListeningEnabled = model.larger + } + } + + self.pumpState = pumpState } rileyLinkManager = RileyLinkDeviceManager( - pumpState: pumpState, + pumpState: self.pumpState, autoConnectIDs: connectedPeripheralIDs ) + rileyLinkManager.idleListeningEnabled = idleListeningEnabled + rileyLinkManager.timerTickEnabled = !idleListeningEnabled - getHistoryTimer = NSTimer.scheduledTimerWithTimeInterval(5.0 * 60, target:self, selector:#selector(DeviceDataManager.timerTriggered), userInfo:nil, repeats:true) - - // This triggers one history fetch right away (in 10s) -// let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(10 * Double(NSEC_PER_SEC))) -// dispatch_after(delayTime, dispatch_get_main_queue()) { -// if let rl = DeviceDataManager.sharedManager.preferredRileyLink() { -// DeviceDataManager.sharedManager.getPumpHistory(rl) -// } -// } - UIDevice.currentDevice().batteryMonitoringEnabled = true - rileyLinkManager.timerTickEnabled = false - rileyLinkManagerObserver = NSNotificationCenter.defaultCenter().addObserverForName(nil, object: rileyLinkManager, queue: nil) { [weak self] (note) -> Void in - self?.receivedRileyLinkManagerNotification(note) - } - NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkManagerNotification(_:)), name: nil, object: rileyLinkManager) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkPacketNotification(_:)), name: RileyLinkDevice.DidReceiveIdleMessageNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkTimerTickNotification(_:)), name: RileyLinkDevice.DidUpdateTimerTickNotification, object: nil) - - + + if let pumpState = pumpState { + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(pumpStateValuesDidChange(_:)), name: PumpState.ValuesDidChangeNotification, object: pumpState) + } } diff --git a/RileyLinkKit/PumpOpsSynchronous.swift b/RileyLinkKit/PumpOpsSynchronous.swift index 6331f3c88..131cdb5d1 100644 --- a/RileyLinkKit/PumpOpsSynchronous.swift +++ b/RileyLinkKit/PumpOpsSynchronous.swift @@ -435,19 +435,20 @@ class PumpOpsSynchronous { let statusResp: ReadPumpStatusMessageBody = try getMessageBodyWithType(.ReadPumpStatus) - return PumpStatus(clock: clockResp.dateComponents, batteryVolts: battResp.volts, batteryStatus: battResp.status, suspended: statusResp.suspended, bolusing: statusResp.bolusing, reservoir: reservoir, model: pumpModel) + return PumpStatus(clock: clockResp.dateComponents, batteryVolts: battResp.volts, batteryStatus: battResp.status, suspended: statusResp.suspended, bolusing: statusResp.bolusing, reservoir: reservoir, model: pumpModel, pumpID: pump.pumpID) } } public struct PumpStatus { - let clock: NSDateComponents - let batteryVolts: Double - let batteryStatus: BatteryStatus - let suspended: Bool - let bolusing: Bool - let reservoir: Double - let model: PumpModel + public let clock: NSDateComponents + public let batteryVolts: Double + public let batteryStatus: BatteryStatus + public let suspended: Bool + public let bolusing: Bool + public let reservoir: Double + public let model: PumpModel + public let pumpID: String } public struct FrequencyTrial { From d06fc2e667fb6c69d4ad8f42c192349357c336ca Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 1 Aug 2016 09:31:33 -0500 Subject: [PATCH 21/35] updating to match Loop DDM more closely --- RileyLink/DeviceDataManager.swift | 51 +++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index b8923b04e..0cf4784e8 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -89,10 +89,6 @@ class DeviceDataManager { } } - func receivedRileyLinkManagerNotification(note: NSNotification) { - NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) - } - func preferredRileyLink() -> RileyLinkDevice? { if let device = lastRileyLinkHeardFrom { return device @@ -100,7 +96,11 @@ class DeviceDataManager { return self.rileyLinkManager.firstConnectedDevice } - func receivedRileyLinkPacketNotification(note: NSNotification) { + @objc private func receivedRileyLinkManagerNotification(note: NSNotification) { + NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) + } + + @objc private func receivedRileyLinkPacketNotification(note: NSNotification) { if let device = note.object as? RileyLinkDevice, data = note.userInfo?[RileyLinkDevice.IdleMessageDataKey] as? NSData, @@ -132,6 +132,39 @@ class DeviceDataManager { } } + @objc private func receivedRileyLinkTimerTickNotification(note: NSNotification) { +// backfillGlucoseFromShareIfNeeded() { +// self.assertCurrentPumpData() +// } + } + + /** + Ensures pump data is current by either waking and polling, or ensuring we're listening to sentry packets. + */ + private func assertCurrentPumpData() { + guard let device = rileyLinkManager.firstConnectedDevice else { + return + } + + device.assertIdleListening() + + // How long should we wait before we poll for new reservoir data? + let reservoirTolerance = rileyLinkManager.idleListeningEnabled ? NSTimeInterval(minutes: 11) : NSTimeInterval(minutes: 4) + + // If we don't yet have reservoir data, or it's old, poll for it. + if latestReservoirValue == nil || latestReservoirValue!.startDate.timeIntervalSinceNow <= -reservoirTolerance { + readReservoirVolume { (result) in + switch result { + case .Success(let (units, date)): + self.updateReservoirVolume(units, atDate: date, withTimeLeft: nil) + case .Failure: + self.troubleshootPumpCommsWithDevice(device) + } + } + } + } + + func connectToRileyLink(device: RileyLinkDevice) { connectedPeripheralIDs.insert(device.peripheral.identifier.UUIDString) @@ -276,10 +309,10 @@ class DeviceDataManager { self?.receivedRileyLinkManagerNotification(note) } - // TODO: Use delegation instead. - rileyLinkDevicePacketObserver = NSNotificationCenter.defaultCenter().addObserverForName(RileyLinkDevice.DidReceiveIdleMessageNotification, object: nil, queue: nil) { [weak self] (note) -> Void in - self?.receivedRileyLinkPacketNotification(note) - } + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkManagerNotification(_:)), name: nil, object: rileyLinkManager) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkPacketNotification(_:)), name: RileyLinkDevice.DidReceiveIdleMessageNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkTimerTickNotification(_:)), name: RileyLinkDevice.DidUpdateTimerTickNotification, object: nil) + } From 4a8456557f4f419167a9baa057412eaa2f95fb21 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 1 Aug 2016 22:11:33 -0500 Subject: [PATCH 22/35] Upload pump status from x22 pumps --- .../DeviceStatus/PumpStatus.swift | 7 +- NightscoutUploadKit/NightscoutUploader.swift | 14 - RileyLink/Config.h | 1 + RileyLink/Config.m | 9 + RileyLink/DeviceDataManager.swift | 334 +++++++++++------- RileyLinkKit/PumpOpsSynchronous.swift | 17 +- 6 files changed, 238 insertions(+), 144 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift index 954eb5bb1..3c6c27a2c 100644 --- a/NightscoutUploadKit/DeviceStatus/PumpStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/PumpStatus.swift @@ -10,14 +10,16 @@ import Foundation public struct PumpStatus { let clock: NSDate + let pumpID: String let iob: IOBStatus? let battery: BatteryStatus? let suspended: Bool? let bolusing: Bool? let reservoir: Double? - public init(clock: NSDate, iob: IOBStatus? = nil, battery: BatteryStatus? = nil, suspended: Bool? = nil, bolusing: Bool? = nil, reservoir: Double? = nil) { + public init(clock: NSDate, pumpID: String, iob: IOBStatus? = nil, battery: BatteryStatus? = nil, suspended: Bool? = nil, bolusing: Bool? = nil, reservoir: Double? = nil) { self.clock = clock + self.pumpID = pumpID self.iob = iob self.battery = battery self.suspended = suspended @@ -29,6 +31,7 @@ public struct PumpStatus { var rval = [String: AnyObject]() rval["clock"] = TimeFormat.timestampStrFromDate(clock) + rval["pumpID"] = pumpID if let battery = battery { rval["battery"] = battery.dictionaryRepresentation @@ -41,7 +44,7 @@ public struct PumpStatus { if let iob = iob { rval["iob"] = iob.dictionaryRepresentation } - + return rval } } \ No newline at end of file diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift index 181a70553..0c5471f12 100644 --- a/NightscoutUploadKit/NightscoutUploader.swift +++ b/NightscoutUploadKit/NightscoutUploader.swift @@ -122,20 +122,6 @@ public class NightscoutUploader { uploadToNS(treatments, endpoint: defaultNightscoutTreatmentPath, completion: completionHandler) } - public func getPumpStatusFromMySentryPumpStatus(status: MySentryPumpStatusMessageBody) throws -> PumpStatus { - - guard let pumpDate = status.pumpDateComponents.date else { - throw UploadError.MissingTimezone - } - - let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") - let iobStatus = IOBStatus(iob: status.iob, basaliob: 0, timestamp: pumpDate) - - let pumpStatus = PumpStatus(clock: pumpDate, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) - - return pumpStatus - } - public func uploadDeviceStatus(status: DeviceStatus) { deviceStatuses.append(status.dictionaryRepresentation) flushAll() diff --git a/RileyLink/Config.h b/RileyLink/Config.h index a56d92aeb..dd3b89aa9 100644 --- a/RileyLink/Config.h +++ b/RileyLink/Config.h @@ -17,6 +17,7 @@ @property (nonatomic, nullable, strong) NSURL *nightscoutURL; @property (nonatomic, nullable, strong) NSString *nightscoutAPISecret; @property (nonatomic, nullable, strong) NSString *pumpID; +@property (nonatomic, nullable, strong) NSString *pumpModelNumber; @property (nonatomic, nullable, strong) NSTimeZone *pumpTimeZone; @property (nonatomic, nullable, strong) NSSet *autoConnectIds; @property (nonatomic, assign) BOOL uploadEnabled; diff --git a/RileyLink/Config.m b/RileyLink/Config.m index 4f7922d5c..6f7dd85f0 100644 --- a/RileyLink/Config.m +++ b/RileyLink/Config.m @@ -64,6 +64,15 @@ - (NSString*) pumpID { return [_defaults stringForKey:@"pumpID"]; } +- (void) setPumpModelNumber:(NSString *)pumpModelNumber { + [_defaults setValue:pumpModelNumber forKey:@"pumpModelNumber"]; +} + +- (NSString*) pumpModelNumber { + return [_defaults stringForKey:@"pumpModelNumber"]; +} + + - (void) setPumpTimeZone:(NSTimeZone *)pumpTimeZone { if (pumpTimeZone) { diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 0cf4784e8..9c56ed89f 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -29,45 +29,87 @@ class DeviceDataManager { } } - var latestPumpStatus: MySentryPumpStatusMessageBody? + var latestPumpStatusDate: NSDate? - var pumpTimeZone: NSTimeZone? = Config.sharedInstance().pumpTimeZone { + var latestPumpStatusFromMySentry: MySentryPumpStatusMessageBody? { didSet { - Config.sharedInstance().pumpTimeZone = pumpTimeZone - - if let pumpTimeZone = pumpTimeZone { - - if let pumpState = rileyLinkManager.pumpState { - pumpState.timeZone = pumpTimeZone - } + if let update = latestPumpStatusFromMySentry, let timeZone = pumpState?.timeZone { + let pumpClock = update.pumpDateComponents + pumpClock.timeZone = timeZone + latestPumpStatusDate = pumpClock.date } } } - - var pumpID: String? = Config.sharedInstance().pumpID { + + + var latestPolledPumpStatus: RileyLinkKit.PumpStatus? { didSet { - if pumpID?.characters.count != 6 { - pumpID = nil + if let update = latestPolledPumpStatus, let timeZone = pumpState?.timeZone { + let pumpClock = update.clock + pumpClock.timeZone = timeZone + latestPumpStatusDate = pumpClock.date + } + } + } + + var pumpID: String? { + get { + return pumpState?.pumpID + } + set { + guard newValue?.characters.count == 6 && newValue != pumpState?.pumpID else { + return } - if let pumpID = pumpID { + if let pumpID = newValue { let pumpState = PumpState(pumpID: pumpID) - if let timeZone = pumpTimeZone { + if let timeZone = self.pumpState?.timeZone { pumpState.timeZone = timeZone } - rileyLinkManager.pumpState = pumpState + self.pumpState = pumpState } else { - rileyLinkManager.pumpState = nil + self.pumpState = nil } - + remoteDataManager.nightscoutUploader?.reset() Config.sharedInstance().pumpID = pumpID } } + var pumpState: PumpState? { + didSet { + rileyLinkManager.pumpState = pumpState + + if let oldValue = oldValue { + NSNotificationCenter.defaultCenter().removeObserver(self, name: PumpState.ValuesDidChangeNotification, object: oldValue) + } + + if let pumpState = pumpState { + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(pumpStateValuesDidChange(_:)), name: PumpState.ValuesDidChangeNotification, object: pumpState) + } + } + } + + @objc private func pumpStateValuesDidChange(note: NSNotification) { + switch note.userInfo?[PumpState.PropertyKey] as? String { + case "timeZone"?: + Config.sharedInstance().pumpTimeZone = pumpState?.timeZone + case "pumpModel"?: + if let sentrySupported = pumpState?.pumpModel?.larger { + rileyLinkManager.idleListeningEnabled = sentrySupported + rileyLinkManager.timerTickEnabled = !sentrySupported + } + Config.sharedInstance().pumpModelNumber = pumpState?.pumpModel?.rawValue + case "lastHistoryDump"?, "awakeUntil"?: + break + default: + break + } + } + var lastHistoryAttempt: NSDate? = nil var lastRileyLinkHeardFrom: RileyLinkDevice? = nil @@ -89,6 +131,10 @@ class DeviceDataManager { } } + @objc private func receivedRileyLinkManagerNotification(note: NSNotification) { + NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) + } + func preferredRileyLink() -> RileyLinkDevice? { if let device = lastRileyLinkHeardFrom { return device @@ -96,33 +142,24 @@ class DeviceDataManager { return self.rileyLinkManager.firstConnectedDevice } - @objc private func receivedRileyLinkManagerNotification(note: NSNotification) { - NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: self, userInfo: note.userInfo) - } - + /** + Called when a new idle message is received by the RileyLink. + + Only MySentryPumpStatus messages are handled. + + - parameter note: The notification object + */ @objc private func receivedRileyLinkPacketNotification(note: NSNotification) { if let device = note.object as? RileyLinkDevice, data = note.userInfo?[RileyLinkDevice.IdleMessageDataKey] as? NSData, message = PumpMessage(rxData: data) { - lastRileyLinkHeardFrom = device switch message.packetType { case .MySentry: switch message.messageBody { case let body as MySentryPumpStatusMessageBody: - updatePumpStatus(body, fromDevice: device) - case is MySentryAlertMessageBody: - break - // TODO: de-dupe - // logger?.addMessage(body.dictionaryRepresentation, toCollection: "sentryAlert") - case is MySentryAlertClearedMessageBody: - break - // TODO: de-dupe - // logger?.addMessage(body.dictionaryRepresentation, toCollection: "sentryAlert") - case is UnknownMessageBody: - break - //logger?.addMessage(body.dictionaryRepresentation, toCollection: "sentryOther") + pumpStatusUpdateReceived(body, fromDevice: device) default: break } @@ -133,35 +170,7 @@ class DeviceDataManager { } @objc private func receivedRileyLinkTimerTickNotification(note: NSNotification) { -// backfillGlucoseFromShareIfNeeded() { -// self.assertCurrentPumpData() -// } - } - - /** - Ensures pump data is current by either waking and polling, or ensuring we're listening to sentry packets. - */ - private func assertCurrentPumpData() { - guard let device = rileyLinkManager.firstConnectedDevice else { - return - } - - device.assertIdleListening() - - // How long should we wait before we poll for new reservoir data? - let reservoirTolerance = rileyLinkManager.idleListeningEnabled ? NSTimeInterval(minutes: 11) : NSTimeInterval(minutes: 4) - - // If we don't yet have reservoir data, or it's old, poll for it. - if latestReservoirValue == nil || latestReservoirValue!.startDate.timeIntervalSinceNow <= -reservoirTolerance { - readReservoirVolume { (result) in - switch result { - case .Success(let (units, date)): - self.updateReservoirVolume(units, atDate: date, withTimeLeft: nil) - case .Failure: - self.troubleshootPumpCommsWithDevice(device) - } - } - } + self.assertCurrentPumpData() } @@ -177,12 +186,13 @@ class DeviceDataManager { rileyLinkManager.disconnectDevice(device) } - private func updatePumpStatus(status: MySentryPumpStatusMessageBody, fromDevice device: RileyLinkDevice) { - status.pumpDateComponents.timeZone = pumpTimeZone - status.glucoseDateComponents?.timeZone = pumpTimeZone - - if status != latestPumpStatus { - latestPumpStatus = status + private func pumpStatusUpdateReceived(status: MySentryPumpStatusMessageBody, fromDevice device: RileyLinkDevice) { + status.pumpDateComponents.timeZone = pumpState?.timeZone + status.glucoseDateComponents?.timeZone = pumpState?.timeZone + + // Avoid duplicates + if status != latestPumpStatusFromMySentry { + latestPumpStatusFromMySentry = status // Sentry packets are sent in groups of 3, 5s apart. Wait 11s to avoid conflicting comms. let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(11 * NSEC_PER_SEC)) @@ -194,47 +204,132 @@ class DeviceDataManager { //NotificationManager.sendPumpBatteryLowNotification() } - guard Config.sharedInstance().uploadEnabled else { + guard Config.sharedInstance().uploadEnabled, let pumpID = pumpID else { return } - - // Gather UploaderStatus - let uploaderDevice = UIDevice.currentDevice() - - - let battery: Int? - if uploaderDevice.batteryMonitoringEnabled { - battery = Int(uploaderDevice.batteryLevel * 100) - } else { - battery = nil - } - let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate(), battery: battery) - + // Gather PumpStatus from MySentry packet let pumpStatus: NightscoutUploadKit.PumpStatus? do { - pumpStatus = try remoteDataManager.nightscoutUploader?.getPumpStatusFromMySentryPumpStatus(status) + guard let pumpDate = status.pumpDateComponents.date else { + throw UploadError.MissingTimezone + } + + let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") + let iobStatus = IOBStatus(iob: status.iob, basaliob: 0, timestamp: pumpDate) + + pumpStatus = NightscoutUploadKit.PumpStatus(clock: pumpDate, pumpID: pumpID, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) + } catch { pumpStatus = nil print("Could not get pump status: \(error)") } - - // Mock out some loop data for testing -// let loopTime = NSDate() -// let iob = IOBStatus(iob: 3.0, basaliob: 1.2, timestamp: NSDate()) -// let loopSuggested = LoopSuggested(timestamp: loopTime, rate: 1.2, duration: NSTimeInterval(30*60), correction: 0, eventualBG: 200, reason: "Test Reason", bg: 205, tick: 5) -// let loopEnacted = LoopEnacted(rate: 1.2, duration: NSTimeInterval(30*60), timestamp: loopTime, received: true) -// let loopStatus = LoopStatus(name: "TestLoopName", timestamp: NSDate(), iob: iob, suggested: loopSuggested, enacted: loopEnacted, failureReason: nil) - - // Build DeviceStatus - let deviceStatus = DeviceStatus(device: uploaderDevice.name, timestamp: NSDate(), pumpStatus: pumpStatus, uploaderStatus: uploaderStatus) - remoteDataManager.nightscoutUploader?.uploadDeviceStatus(deviceStatus) + + // Trigger device status upload, even if something is wrong with pumpStatus + self.uploadDeviceStatus(pumpStatus) // Send SGVs remoteDataManager.nightscoutUploader?.uploadSGVFromMySentryPumpStatus(status, device: device.deviceURI) } } + private func uploadDeviceStatus(pumpStatus: NightscoutUploadKit.PumpStatus? /*, loopStatus: LoopStatus */) { + + guard let uploader = remoteDataManager.nightscoutUploader else { + return + } + + + // Gather UploaderStatus + let uploaderDevice = UIDevice.currentDevice() + + let battery: Int? + if uploaderDevice.batteryMonitoringEnabled { + battery = Int(uploaderDevice.batteryLevel * 100) + } else { + battery = nil + } + let uploaderStatus = UploaderStatus(name: uploaderDevice.name, timestamp: NSDate(), battery: battery) + + + // Mock out some loop data for testing + // let loopTime = NSDate() + // let iob = IOBStatus(iob: 3.0, basaliob: 1.2, timestamp: NSDate()) + // let loopSuggested = LoopSuggested(timestamp: loopTime, rate: 1.2, duration: NSTimeInterval(30*60), correction: 0, eventualBG: 200, reason: "Test Reason", bg: 205, tick: 5) + // let loopEnacted = LoopEnacted(rate: 1.2, duration: NSTimeInterval(30*60), timestamp: loopTime, received: true) + // let loopStatus = LoopStatus(name: "TestLoopName", timestamp: NSDate(), iob: iob, suggested: loopSuggested, enacted: loopEnacted, failureReason: nil) + + // Build DeviceStatus + let deviceStatus = DeviceStatus(device: uploaderDevice.name, timestamp: NSDate(), pumpStatus: pumpStatus, uploaderStatus: uploaderStatus) + + uploader.uploadDeviceStatus(deviceStatus) + } + + /** + Ensures pump data is current by either waking and polling, or ensuring we're listening to sentry packets. + */ + private func assertCurrentPumpData() { + guard let device = rileyLinkManager.firstConnectedDevice else { + return + } + + device.assertIdleListening() + + // How long should we wait before we poll for new pump data? + let pumpStatusAgeTolerance = rileyLinkManager.idleListeningEnabled ? NSTimeInterval(minutes: 11) : NSTimeInterval(minutes: 4) + + // If we don't yet have pump status, or it's old, poll for it. + if latestPumpStatusDate == nil || latestPumpStatusDate!.timeIntervalSinceNow <= -pumpStatusAgeTolerance { + guard let device = rileyLinkManager.firstConnectedDevice else { + return + } + + guard let ops = device.ops else { + self.troubleshootPumpCommsWithDevice(device) + return + } + + ops.readPumpStatus({ (result) in + switch result { + case .Success(let status): + self.latestPolledPumpStatus = status + let battery = BatteryStatus(voltage: status.batteryVolts, status: String(status.batteryStatus).lowercaseString) + status.clock.timeZone = ops.pumpState.timeZone + guard let date = status.clock.date else { + print("Could not interpret clock") + return + } + let nsPumpStatus = NightscoutUploadKit.PumpStatus(clock: date, pumpID: ops.pumpState.pumpID, iob: nil, battery: battery, suspended: status.suspended, bolusing: status.bolusing, reservoir: status.reservoir) + self.uploadDeviceStatus(nsPumpStatus) + case .Failure: + self.troubleshootPumpCommsWithDevice(device) + } + }) + } + } + + /** + Attempts to fix an extended communication failure between a RileyLink device and the pump + + - parameter device: The RileyLink device + */ + private func troubleshootPumpCommsWithDevice(device: RileyLinkDevice) { + + // How long we should wait before we re-tune the RileyLink + let tuneTolerance = NSTimeInterval(minutes: 14) + + if device.lastTuned?.timeIntervalSinceNow <= -tuneTolerance { + device.tunePumpWithResultHandler { (result) in + switch result { + case .Success(let scanResult): + print("Device auto-tuned to \(scanResult.bestFrequency) MHz") + case .Failure(let error): + print("Device auto-tune failed with error: \(error)") + } + } + } + } + private func getPumpHistory(device: RileyLinkDevice) { lastHistoryAttempt = NSDate() @@ -275,45 +370,44 @@ class DeviceDataManager { init() { - let pumpState: PumpState? + let pumpID = Config.sharedInstance().pumpID + + var idleListeningEnabled = true if let pumpID = pumpID { - pumpState = PumpState(pumpID: pumpID) + let pumpState = PumpState(pumpID: pumpID) - if let timeZone = pumpTimeZone { - pumpState?.timeZone = timeZone + if let timeZone = Config.sharedInstance().pumpTimeZone { + pumpState.timeZone = timeZone } - } else { - pumpState = nil + + if let pumpModelNumber = Config.sharedInstance().pumpModelNumber { + if let model = PumpModel(rawValue: pumpModelNumber) { + pumpState.pumpModel = model + + idleListeningEnabled = model.larger + } + } + + self.pumpState = pumpState } rileyLinkManager = RileyLinkDeviceManager( - pumpState: pumpState, + pumpState: self.pumpState, autoConnectIDs: connectedPeripheralIDs ) + rileyLinkManager.idleListeningEnabled = idleListeningEnabled + rileyLinkManager.timerTickEnabled = !idleListeningEnabled - getHistoryTimer = NSTimer.scheduledTimerWithTimeInterval(5.0 * 60, target:self, selector:#selector(DeviceDataManager.timerTriggered), userInfo:nil, repeats:true) - - // This triggers one history fetch right away (in 10s) -// let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(10 * Double(NSEC_PER_SEC))) -// dispatch_after(delayTime, dispatch_get_main_queue()) { -// if let rl = DeviceDataManager.sharedManager.preferredRileyLink() { -// DeviceDataManager.sharedManager.getPumpHistory(rl) -// } -// } - UIDevice.currentDevice().batteryMonitoringEnabled = true - rileyLinkManager.timerTickEnabled = false - rileyLinkManagerObserver = NSNotificationCenter.defaultCenter().addObserverForName(nil, object: rileyLinkManager, queue: nil) { [weak self] (note) -> Void in - self?.receivedRileyLinkManagerNotification(note) - } - NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkManagerNotification(_:)), name: nil, object: rileyLinkManager) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkPacketNotification(_:)), name: RileyLinkDevice.DidReceiveIdleMessageNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedRileyLinkTimerTickNotification(_:)), name: RileyLinkDevice.DidUpdateTimerTickNotification, object: nil) - - + + if let pumpState = pumpState { + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(pumpStateValuesDidChange(_:)), name: PumpState.ValuesDidChangeNotification, object: pumpState) + } } diff --git a/RileyLinkKit/PumpOpsSynchronous.swift b/RileyLinkKit/PumpOpsSynchronous.swift index 6331f3c88..131cdb5d1 100644 --- a/RileyLinkKit/PumpOpsSynchronous.swift +++ b/RileyLinkKit/PumpOpsSynchronous.swift @@ -435,19 +435,20 @@ class PumpOpsSynchronous { let statusResp: ReadPumpStatusMessageBody = try getMessageBodyWithType(.ReadPumpStatus) - return PumpStatus(clock: clockResp.dateComponents, batteryVolts: battResp.volts, batteryStatus: battResp.status, suspended: statusResp.suspended, bolusing: statusResp.bolusing, reservoir: reservoir, model: pumpModel) + return PumpStatus(clock: clockResp.dateComponents, batteryVolts: battResp.volts, batteryStatus: battResp.status, suspended: statusResp.suspended, bolusing: statusResp.bolusing, reservoir: reservoir, model: pumpModel, pumpID: pump.pumpID) } } public struct PumpStatus { - let clock: NSDateComponents - let batteryVolts: Double - let batteryStatus: BatteryStatus - let suspended: Bool - let bolusing: Bool - let reservoir: Double - let model: PumpModel + public let clock: NSDateComponents + public let batteryVolts: Double + public let batteryStatus: BatteryStatus + public let suspended: Bool + public let bolusing: Bool + public let reservoir: Double + public let model: PumpModel + public let pumpID: String } public struct FrequencyTrial { From e7d9cbee633218c6b603b4b4cd56b9373c254334 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 12:35:53 -0500 Subject: [PATCH 23/35] use conditionals instead of throwing --- RileyLink/DeviceDataManager.swift | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 9c56ed89f..4a0d8e072 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -210,19 +210,15 @@ class DeviceDataManager { // Gather PumpStatus from MySentry packet let pumpStatus: NightscoutUploadKit.PumpStatus? - do { - guard let pumpDate = status.pumpDateComponents.date else { - throw UploadError.MissingTimezone - } - + if let pumpDate = status.pumpDateComponents.date { + let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") let iobStatus = IOBStatus(iob: status.iob, basaliob: 0, timestamp: pumpDate) pumpStatus = NightscoutUploadKit.PumpStatus(clock: pumpDate, pumpID: pumpID, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) - - } catch { + } else { pumpStatus = nil - print("Could not get pump status: \(error)") + print("Could not interpret pump clock: \(status.pumpDateComponents)") } // Trigger device status upload, even if something is wrong with pumpStatus From 7311229d3c675ce91020d3bfce05e22fa302dfa5 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 15:12:10 -0500 Subject: [PATCH 24/35] agvtool new-marketing-version 0.8.0 && agvtool bump --- MinimedKit/Info.plist | 2 +- MinimedKitTests/Info.plist | 2 +- NightscoutUploadKit/Info.plist | 2 +- NightscoutUploadKitTests/Info.plist | 2 +- RileyLink.xcodeproj/project.pbxproj | 36 ++++++++++++------------ RileyLink/RileyLink-Info.plist | 2 +- RileyLinkBLEKit/Info.plist | 2 +- RileyLinkBLEKitTests/Info.plist | 2 +- RileyLinkKit/Info.plist | 2 +- RileyLinkKitTests/Info.plist | 2 +- RileyLinkTests/RileyLinkTests-Info.plist | 2 +- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/MinimedKit/Info.plist b/MinimedKit/Info.plist index 425ef70fb..5d7827c27 100644 --- a/MinimedKit/Info.plist +++ b/MinimedKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/MinimedKitTests/Info.plist b/MinimedKitTests/Info.plist index 621016d74..ab895996c 100644 --- a/MinimedKitTests/Info.plist +++ b/MinimedKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/NightscoutUploadKit/Info.plist b/NightscoutUploadKit/Info.plist index 425ef70fb..5d7827c27 100644 --- a/NightscoutUploadKit/Info.plist +++ b/NightscoutUploadKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/NightscoutUploadKitTests/Info.plist b/NightscoutUploadKitTests/Info.plist index 8d8ed6042..dc2ece127 100644 --- a/NightscoutUploadKitTests/Info.plist +++ b/NightscoutUploadKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 02a53666f..fc169ed26 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -2013,11 +2013,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2041,11 +2041,11 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2104,11 +2104,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2134,11 +2134,11 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2197,11 +2197,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2226,11 +2226,11 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2299,7 +2299,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -2341,7 +2341,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -2446,11 +2446,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -2479,11 +2479,11 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 10; + DYLIB_CURRENT_VERSION = 11; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( diff --git a/RileyLink/RileyLink-Info.plist b/RileyLink/RileyLink-Info.plist index 1deb996b6..7a682dd5f 100644 --- a/RileyLink/RileyLink-Info.plist +++ b/RileyLink/RileyLink-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkBLEKit/Info.plist b/RileyLinkBLEKit/Info.plist index 425ef70fb..5d7827c27 100644 --- a/RileyLinkBLEKit/Info.plist +++ b/RileyLinkBLEKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkBLEKitTests/Info.plist b/RileyLinkBLEKitTests/Info.plist index 621016d74..ab895996c 100644 --- a/RileyLinkBLEKitTests/Info.plist +++ b/RileyLinkBLEKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkKit/Info.plist b/RileyLinkKit/Info.plist index 425ef70fb..5d7827c27 100644 --- a/RileyLinkKit/Info.plist +++ b/RileyLinkKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkKitTests/Info.plist b/RileyLinkKitTests/Info.plist index 621016d74..ab895996c 100644 --- a/RileyLinkKitTests/Info.plist +++ b/RileyLinkKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkTests/RileyLinkTests-Info.plist b/RileyLinkTests/RileyLinkTests-Info.plist index c3315ea15..81ef2657b 100644 --- a/RileyLinkTests/RileyLinkTests-Info.plist +++ b/RileyLinkTests/RileyLinkTests-Info.plist @@ -13,7 +13,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion From 2a53c441d450f715e9021f3b2f2beb4cffec0ab3 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 18:30:56 -0500 Subject: [PATCH 25/35] Allow some loop values to be optional --- .../DeviceStatus/IOBStatus.swift | 25 ++++++--- .../DeviceStatus/LoopSuggested.swift | 54 +++++++++++-------- RileyLink/DeviceDataManager.swift | 2 - 3 files changed, 48 insertions(+), 33 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift index 2c3236d1e..5fe5b2856 100644 --- a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift @@ -9,21 +9,30 @@ import Foundation public struct IOBStatus { - let iob: Double // basal iob + bolus iob: can be negative - let basaliob: Double + let iob: Double? // basal iob + bolus iob: can be negative + let basaliob: Double? // does not include bolus iob let timestamp: NSDate - public init(iob: Double, basaliob: Double, timestamp: NSDate) { + public init(iob: Double, basaliob: Double?, timestamp: NSDate) { self.iob = iob self.basaliob = basaliob self.timestamp = timestamp } public var dictionaryRepresentation: [String: AnyObject] { - return [ - "iob": iob, - "basaliob": basaliob, - "timestamp": TimeFormat.timestampStrFromDate(timestamp), - ] + + var rval = [String: AnyObject]() + + rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) + + if let iob = iob { + rval["iob"] = iob + } + + if let basaliob = basaliob { + rval["basaliob"] = basaliob + } + + return rval } } \ No newline at end of file diff --git a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift index a65895474..77eda4a7f 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift @@ -14,41 +14,49 @@ public struct LoopSuggested { let duration: NSTimeInterval let correction: Double let eventualBG: Int - let reason: String let bg: Int - let tick: Int + let reason: String? + let tick: Int? - public init(timestamp: NSDate, rate: Double, duration: NSTimeInterval, correction: Double = 0, eventualBG: Int, reason: String, bg: Int, tick: Int) { + public init(timestamp: NSDate, rate: Double, duration: NSTimeInterval, correction: Double = 0, eventualBG: Int, bg: Int, reason: String?, tick: Int?) { self.timestamp = timestamp self.rate = rate self.duration = duration self.correction = correction self.eventualBG = eventualBG - self.reason = reason self.bg = bg + self.reason = reason self.tick = tick } public var dictionaryRepresentation: [String: AnyObject] { - let tickStr: String - - if tick > 0 { - tickStr = "+\(tick)" - } else if tick < 0 { - tickStr = "-\(tick)" - } else { - tickStr = "0" + + var rval = [String: AnyObject]() + + rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) + + if let tick = tick { + let tickStr: String + if tick > 0 { + tickStr = "+\(tick)" + } else if tick < 0 { + tickStr = "-\(tick)" + } else { + tickStr = "0" + } + rval["tick"] = tickStr } - - return [ - "timestamp": TimeFormat.timestampStrFromDate(timestamp), - "rate": rate, - "duration": duration / 60.0, - "bg": bg, - "correction": correction, - "eventualBG": eventualBG, - "reason": reason, - "tick": tickStr, - ] + + rval["rate"] = rate + rval["duration"] = duration / 60.0 + rval["bg"] = bg + rval["correction"] = correction + rval["eventualBG"] = eventualBG + + if let reason = reason { + rval["reaseon"] = reason + } + + return rval } } diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 4a0d8e072..945a1a0ee 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -235,7 +235,6 @@ class DeviceDataManager { return } - // Gather UploaderStatus let uploaderDevice = UIDevice.currentDevice() @@ -354,7 +353,6 @@ class DeviceDataManager { private func handleNewHistoryEvents(events: [TimestampedHistoryEvent], pumpModel: PumpModel, device: RileyLinkDevice) { // TODO: get insulin doses from history - // TODO: upload events to Nightscout if Config.sharedInstance().uploadEnabled { remoteDataManager.nightscoutUploader?.processPumpEvents(events, source: device.deviceURI, pumpModel: pumpModel) } From 50ae6a6dcdb14c5b861c7571bfe59471e98a51b4 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 18:37:22 -0500 Subject: [PATCH 26/35] initializer fix, and typo --- NightscoutUploadKit/DeviceStatus/IOBStatus.swift | 2 +- NightscoutUploadKit/DeviceStatus/LoopSuggested.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift index 5fe5b2856..d728b18a4 100644 --- a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift @@ -13,7 +13,7 @@ public struct IOBStatus { let basaliob: Double? // does not include bolus iob let timestamp: NSDate - public init(iob: Double, basaliob: Double?, timestamp: NSDate) { + public init(iob: Double?, basaliob: Double?, timestamp: NSDate) { self.iob = iob self.basaliob = basaliob self.timestamp = timestamp diff --git a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift index 77eda4a7f..0210fe2c9 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift @@ -54,7 +54,7 @@ public struct LoopSuggested { rval["eventualBG"] = eventualBG if let reason = reason { - rval["reaseon"] = reason + rval["reason"] = reason } return rval From a2ee6d61bdf0afdc8b6a35512e11b399094d19d6 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 19:12:27 -0500 Subject: [PATCH 27/35] Adding COB status --- .../DeviceStatus/COBStatus.swift | 30 +++++++++++++++++++ .../DeviceStatus/LoopStatus.swift | 10 +++++-- RileyLink.xcodeproj/project.pbxproj | 4 +++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 NightscoutUploadKit/DeviceStatus/COBStatus.swift diff --git a/NightscoutUploadKit/DeviceStatus/COBStatus.swift b/NightscoutUploadKit/DeviceStatus/COBStatus.swift new file mode 100644 index 000000000..496b9c99d --- /dev/null +++ b/NightscoutUploadKit/DeviceStatus/COBStatus.swift @@ -0,0 +1,30 @@ +// +// COBStatus.swift +// RileyLink +// +// Created by Pete Schwamb on 8/2/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public struct COBStatus { + let cob: Double + let timestamp: NSDate + + public init(cob: Double, timestamp: NSDate) { + self.cob = cob // grams + self.timestamp = timestamp + } + + public var dictionaryRepresentation: [String: AnyObject] { + + var rval = [String: AnyObject]() + + rval["timestamp"] = TimeFormat.timestampStrFromDate(timestamp) + rval["cob"] = cob + + return rval + } + +} \ No newline at end of file diff --git a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift index 22b314088..f97e20de0 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift @@ -13,17 +13,19 @@ public struct LoopStatus { let timestamp: NSDate let iob: IOBStatus? + let cob: COBStatus? let suggested: LoopSuggested? let enacted: LoopEnacted? let failureReason: String? - public init(name: String, timestamp: NSDate, glucose: Int? = nil, iob: IOBStatus? = nil, suggested: LoopSuggested? = nil, enacted: LoopEnacted?, failureReason: String? = nil) { + public init(name: String, timestamp: NSDate, glucose: Int? = nil, iob: IOBStatus? = nil, cob: COBStatus? = nil, suggested: LoopSuggested? = nil, enacted: LoopEnacted?, failureReason: String? = nil) { self.name = name self.timestamp = timestamp self.suggested = suggested self.enacted = enacted self.iob = iob + self.cob = cob self.failureReason = failureReason } @@ -44,7 +46,11 @@ public struct LoopStatus { if let iob = iob { rval["iob"] = iob.dictionaryRepresentation } - + + if let cob = cob { + rval["cob"] = cob.dictionaryRepresentation + } + return rval } } diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 02a53666f..cea7ee4cd 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -152,6 +152,7 @@ C1711A5E1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1711A5D1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift */; }; C174F26B19EB824D00398C72 /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; C178845D1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */; }; + C178845F1D5166BE00405663 /* COBStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178845E1D5166BE00405663 /* COBStatus.swift */; }; C1842BBB1C8E184300DB42AC /* PumpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBA1C8E184300DB42AC /* PumpModel.swift */; }; C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */; }; C1842BBF1C8E855A00DB42AC /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */; }; @@ -522,6 +523,7 @@ C174F26919EB824D00398C72 /* ISO8601DateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601DateFormatter.h; sourceTree = ""; }; C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ISO8601DateFormatter.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadPumpStatusMessageBody.swift; sourceTree = ""; }; + C178845E1D5166BE00405663 /* COBStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = COBStatus.swift; sourceTree = ""; }; C1842BBA1C8E184300DB42AC /* PumpModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModel.swift; sourceTree = ""; }; C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEvent.swift; sourceTree = ""; }; C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = PumpEventType.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -1119,6 +1121,7 @@ C1AF21E51D48667F0088C41D /* UploaderStatus.swift */, C1AF21E71D4866960088C41D /* PumpStatus.swift */, C1A492621D4A5A19008964FF /* IOBStatus.swift */, + C178845E1D5166BE00405663 /* COBStatus.swift */, C1A492641D4A5DEB008964FF /* BatteryStatus.swift */, C1AF21E31D4865320088C41D /* LoopStatus.swift */, C1A492661D4A65D9008964FF /* LoopSuggested.swift */, @@ -1915,6 +1918,7 @@ C1AF21E41D4865320088C41D /* LoopStatus.swift in Sources */, C1AF21F11D4901220088C41D /* NightscoutTreatment.swift in Sources */, C1A492671D4A65D9008964FF /* LoopSuggested.swift in Sources */, + C178845F1D5166BE00405663 /* COBStatus.swift in Sources */, 43B0ADC91D1268B300AAD278 /* TimeFormat.swift in Sources */, C1AF21E21D4838C90088C41D /* DeviceStatus.swift in Sources */, C1B383281CD0668600CE7782 /* NightscoutUploader.swift in Sources */, From aea2eb9d0ccfa4c82bcf61bd79aa3245164c46a4 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 21:25:37 -0500 Subject: [PATCH 28/35] basaliob -> basalIOB, default parameters for optional values --- NightscoutUploadKit/DeviceStatus/IOBStatus.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift index d728b18a4..8e42dee32 100644 --- a/NightscoutUploadKit/DeviceStatus/IOBStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/IOBStatus.swift @@ -9,14 +9,14 @@ import Foundation public struct IOBStatus { - let iob: Double? // basal iob + bolus iob: can be negative - let basaliob: Double? // does not include bolus iob let timestamp: NSDate - - public init(iob: Double?, basaliob: Double?, timestamp: NSDate) { - self.iob = iob - self.basaliob = basaliob + let iob: Double? // basal iob + bolus iob: can be negative + let basalIOB: Double? // does not include bolus iob + + public init(timestamp: NSDate, iob: Double? = nil, basalIOB: Double? = nil) { self.timestamp = timestamp + self.iob = iob + self.basalIOB = basalIOB } public var dictionaryRepresentation: [String: AnyObject] { @@ -29,8 +29,8 @@ public struct IOBStatus { rval["iob"] = iob } - if let basaliob = basaliob { - rval["basaliob"] = basaliob + if let basalIOB = basalIOB { + rval["basaliob"] = basalIOB } return rval From 4c01a05b134a25ed2e6f839775cf2932556590f7 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 21:27:32 -0500 Subject: [PATCH 29/35] status can be optional, for mysentry updates, which have no status --- NightscoutUploadKit/DeviceStatus/BatteryStatus.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift index 4b37c476d..3b4224299 100644 --- a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift @@ -11,9 +11,9 @@ import Foundation public struct BatteryStatus { let percent: Int? let voltage: Double? - let status: String + let status: String? - public init(percent: Int? = nil, voltage: Double? = nil, status: String = "normal") { + public init(percent: Int? = nil, voltage: Double? = nil, status: String? = nil) { self.percent = percent self.voltage = voltage self.status = status @@ -28,7 +28,10 @@ public struct BatteryStatus { if let voltage = voltage { rval["voltage"] = voltage } - rval["status"] = status + + if let status = status { + rval["status"] = status + } return rval } From c18f68ce8290ca6ae089e1c1c338f6e0fdc460bb Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 21:30:34 -0500 Subject: [PATCH 30/35] update call to IOBStatus constructor to match new signature --- RileyLink/DeviceDataManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 945a1a0ee..29b585286 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -213,7 +213,7 @@ class DeviceDataManager { if let pumpDate = status.pumpDateComponents.date { let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") - let iobStatus = IOBStatus(iob: status.iob, basaliob: 0, timestamp: pumpDate) + let iobStatus = IOBStatus(timestamp: pumpDate, iob: status.iob) pumpStatus = NightscoutUploadKit.PumpStatus(clock: pumpDate, pumpID: pumpID, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) } else { From 1766d69cf699cea9f8441333da5843a41da1dd8f Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 22:37:45 -0500 Subject: [PATCH 31/35] Adding BatteryIndicator to enumerate values for the nightscout battery.status field --- .../DeviceStatus/BatteryStatus.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift index 3b4224299..531e73e34 100644 --- a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift @@ -8,15 +8,20 @@ import Foundation +public enum BatteryIndicator: String { + case Absolute = "absolute" + case Percentage = "percentage" +} + public struct BatteryStatus { let percent: Int? let voltage: Double? - let status: String? + let indicator: BatteryIndicator? - public init(percent: Int? = nil, voltage: Double? = nil, status: String? = nil) { + public init(percent: Int? = nil, voltage: Double? = nil, indicator: BatteryIndicator? = nil) { self.percent = percent self.voltage = voltage - self.status = status + self.indicator = indicator } public var dictionaryRepresentation: [String: AnyObject] { @@ -29,8 +34,8 @@ public struct BatteryStatus { rval["voltage"] = voltage } - if let status = status { - rval["status"] = status + if let indicator = indicator { + rval["status"] = indicator.rawValue } return rval From 327754364bc0215fa18b197a8d219204fc96bbc4 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 22:49:10 -0500 Subject: [PATCH 32/35] add enum for nightscout battery status, and convenience initializer to convert from minimed kit battery status --- .../DeviceStatus/BatteryStatus.swift | 14 +++++------ RileyLink.xcodeproj/project.pbxproj | 4 ++++ RileyLink/BatteryIndicator.swift | 23 +++++++++++++++++++ RileyLink/DeviceDataManager.swift | 4 ++-- 4 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 RileyLink/BatteryIndicator.swift diff --git a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift index 531e73e34..3cfda095f 100644 --- a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift @@ -9,19 +9,19 @@ import Foundation public enum BatteryIndicator: String { - case Absolute = "absolute" - case Percentage = "percentage" + case Low = "low" + case Normal = "normal" } public struct BatteryStatus { let percent: Int? let voltage: Double? - let indicator: BatteryIndicator? + let status: BatteryIndicator? - public init(percent: Int? = nil, voltage: Double? = nil, indicator: BatteryIndicator? = nil) { + public init(percent: Int? = nil, voltage: Double? = nil, status: BatteryIndicator? = nil) { self.percent = percent self.voltage = voltage - self.indicator = indicator + self.status = status } public var dictionaryRepresentation: [String: AnyObject] { @@ -34,8 +34,8 @@ public struct BatteryStatus { rval["voltage"] = voltage } - if let indicator = indicator { - rval["status"] = indicator.rawValue + if let status = status { + rval["status"] = status.rawValue } return rval diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index cea7ee4cd..d4b03bda3 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -153,6 +153,7 @@ C174F26B19EB824D00398C72 /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; C178845D1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */; }; C178845F1D5166BE00405663 /* COBStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178845E1D5166BE00405663 /* COBStatus.swift */; }; + C17884611D519F1E00405663 /* BatteryIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17884601D519F1E00405663 /* BatteryIndicator.swift */; }; C1842BBB1C8E184300DB42AC /* PumpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBA1C8E184300DB42AC /* PumpModel.swift */; }; C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */; }; C1842BBF1C8E855A00DB42AC /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */; }; @@ -524,6 +525,7 @@ C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ISO8601DateFormatter.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadPumpStatusMessageBody.swift; sourceTree = ""; }; C178845E1D5166BE00405663 /* COBStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = COBStatus.swift; sourceTree = ""; }; + C17884601D519F1E00405663 /* BatteryIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryIndicator.swift; sourceTree = ""; }; C1842BBA1C8E184300DB42AC /* PumpModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModel.swift; sourceTree = ""; }; C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEvent.swift; sourceTree = ""; }; C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = PumpEventType.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -1110,6 +1112,7 @@ C14FFC5A1D3D74F90049CF85 /* NibLoadable.swift */, C14FFC601D3D75470049CF85 /* UIColor.swift */, C14FFC6C1D3D85A40049CF85 /* NSTimeInterval.swift */, + C17884601D519F1E00405663 /* BatteryIndicator.swift */, ); name = Extensions; sourceTree = ""; @@ -1874,6 +1877,7 @@ C14FFC551D3D72A50049CF85 /* UIViewController.swift in Sources */, 434FF1DE1CF268F3000DB779 /* RileyLinkDeviceTableViewCell.swift in Sources */, C14FFC651D3D7E250049CF85 /* RemoteDataManager.swift in Sources */, + C17884611D519F1E00405663 /* BatteryIndicator.swift in Sources */, C1AA39941AB6804000BC9E33 /* UIAlertView+Blocks.m in Sources */, C1EF58881B3F93FE001C8C80 /* Config.m in Sources */, C126164B1B685F93001FAD87 /* RileyLink.xcdatamodeld in Sources */, diff --git a/RileyLink/BatteryIndicator.swift b/RileyLink/BatteryIndicator.swift new file mode 100644 index 000000000..9c14117e6 --- /dev/null +++ b/RileyLink/BatteryIndicator.swift @@ -0,0 +1,23 @@ +// +// BatteryIndicator.swift +// RileyLink +// +// Created by Pete Schwamb on 8/2/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import NightscoutUploadKit +import MinimedKit + +extension BatteryIndicator { + init?(batteryStatus: MinimedKit.BatteryStatus) { + switch batteryStatus { + case .Low: + self = .Low + case .Normal: + self = .Normal + default: + return nil + } + } +} \ No newline at end of file diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 29b585286..54e927037 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -212,7 +212,7 @@ class DeviceDataManager { let pumpStatus: NightscoutUploadKit.PumpStatus? if let pumpDate = status.pumpDateComponents.date { - let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") + let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent) let iobStatus = IOBStatus(timestamp: pumpDate, iob: status.iob) pumpStatus = NightscoutUploadKit.PumpStatus(clock: pumpDate, pumpID: pumpID, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) @@ -288,7 +288,7 @@ class DeviceDataManager { switch result { case .Success(let status): self.latestPolledPumpStatus = status - let battery = BatteryStatus(voltage: status.batteryVolts, status: String(status.batteryStatus).lowercaseString) + let battery = BatteryStatus(voltage: status.batteryVolts, status: BatteryIndicator(batteryStatus: status.batteryStatus)) status.clock.timeZone = ops.pumpState.timeZone guard let date = status.clock.date else { print("Could not interpret clock") From 91fe9bdf952fbe27f500eeca436bd124dc2abbb6 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 22:37:45 -0500 Subject: [PATCH 33/35] Adding BatteryIndicator to enumerate values for the nightscout battery.status field --- .../DeviceStatus/BatteryStatus.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift index 3b4224299..531e73e34 100644 --- a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift @@ -8,15 +8,20 @@ import Foundation +public enum BatteryIndicator: String { + case Absolute = "absolute" + case Percentage = "percentage" +} + public struct BatteryStatus { let percent: Int? let voltage: Double? - let status: String? + let indicator: BatteryIndicator? - public init(percent: Int? = nil, voltage: Double? = nil, status: String? = nil) { + public init(percent: Int? = nil, voltage: Double? = nil, indicator: BatteryIndicator? = nil) { self.percent = percent self.voltage = voltage - self.status = status + self.indicator = indicator } public var dictionaryRepresentation: [String: AnyObject] { @@ -29,8 +34,8 @@ public struct BatteryStatus { rval["voltage"] = voltage } - if let status = status { - rval["status"] = status + if let indicator = indicator { + rval["status"] = indicator.rawValue } return rval From daa1f65d20b6e681eba5145b62808521ef637dee Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 2 Aug 2016 22:49:10 -0500 Subject: [PATCH 34/35] add enum for nightscout battery status, and convenience initializer to convert from minimed kit battery status --- .../DeviceStatus/BatteryStatus.swift | 14 +++++------ RileyLink.xcodeproj/project.pbxproj | 4 ++++ RileyLink/BatteryIndicator.swift | 23 +++++++++++++++++++ RileyLink/DeviceDataManager.swift | 4 ++-- 4 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 RileyLink/BatteryIndicator.swift diff --git a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift index 531e73e34..3cfda095f 100644 --- a/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/BatteryStatus.swift @@ -9,19 +9,19 @@ import Foundation public enum BatteryIndicator: String { - case Absolute = "absolute" - case Percentage = "percentage" + case Low = "low" + case Normal = "normal" } public struct BatteryStatus { let percent: Int? let voltage: Double? - let indicator: BatteryIndicator? + let status: BatteryIndicator? - public init(percent: Int? = nil, voltage: Double? = nil, indicator: BatteryIndicator? = nil) { + public init(percent: Int? = nil, voltage: Double? = nil, status: BatteryIndicator? = nil) { self.percent = percent self.voltage = voltage - self.indicator = indicator + self.status = status } public var dictionaryRepresentation: [String: AnyObject] { @@ -34,8 +34,8 @@ public struct BatteryStatus { rval["voltage"] = voltage } - if let indicator = indicator { - rval["status"] = indicator.rawValue + if let status = status { + rval["status"] = status.rawValue } return rval diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index cea7ee4cd..d4b03bda3 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -153,6 +153,7 @@ C174F26B19EB824D00398C72 /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; C178845D1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */; }; C178845F1D5166BE00405663 /* COBStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178845E1D5166BE00405663 /* COBStatus.swift */; }; + C17884611D519F1E00405663 /* BatteryIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17884601D519F1E00405663 /* BatteryIndicator.swift */; }; C1842BBB1C8E184300DB42AC /* PumpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBA1C8E184300DB42AC /* PumpModel.swift */; }; C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */; }; C1842BBF1C8E855A00DB42AC /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */; }; @@ -524,6 +525,7 @@ C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ISO8601DateFormatter.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadPumpStatusMessageBody.swift; sourceTree = ""; }; C178845E1D5166BE00405663 /* COBStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = COBStatus.swift; sourceTree = ""; }; + C17884601D519F1E00405663 /* BatteryIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryIndicator.swift; sourceTree = ""; }; C1842BBA1C8E184300DB42AC /* PumpModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModel.swift; sourceTree = ""; }; C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEvent.swift; sourceTree = ""; }; C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = PumpEventType.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -1110,6 +1112,7 @@ C14FFC5A1D3D74F90049CF85 /* NibLoadable.swift */, C14FFC601D3D75470049CF85 /* UIColor.swift */, C14FFC6C1D3D85A40049CF85 /* NSTimeInterval.swift */, + C17884601D519F1E00405663 /* BatteryIndicator.swift */, ); name = Extensions; sourceTree = ""; @@ -1874,6 +1877,7 @@ C14FFC551D3D72A50049CF85 /* UIViewController.swift in Sources */, 434FF1DE1CF268F3000DB779 /* RileyLinkDeviceTableViewCell.swift in Sources */, C14FFC651D3D7E250049CF85 /* RemoteDataManager.swift in Sources */, + C17884611D519F1E00405663 /* BatteryIndicator.swift in Sources */, C1AA39941AB6804000BC9E33 /* UIAlertView+Blocks.m in Sources */, C1EF58881B3F93FE001C8C80 /* Config.m in Sources */, C126164B1B685F93001FAD87 /* RileyLink.xcdatamodeld in Sources */, diff --git a/RileyLink/BatteryIndicator.swift b/RileyLink/BatteryIndicator.swift new file mode 100644 index 000000000..9c14117e6 --- /dev/null +++ b/RileyLink/BatteryIndicator.swift @@ -0,0 +1,23 @@ +// +// BatteryIndicator.swift +// RileyLink +// +// Created by Pete Schwamb on 8/2/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import NightscoutUploadKit +import MinimedKit + +extension BatteryIndicator { + init?(batteryStatus: MinimedKit.BatteryStatus) { + switch batteryStatus { + case .Low: + self = .Low + case .Normal: + self = .Normal + default: + return nil + } + } +} \ No newline at end of file diff --git a/RileyLink/DeviceDataManager.swift b/RileyLink/DeviceDataManager.swift index 29b585286..54e927037 100644 --- a/RileyLink/DeviceDataManager.swift +++ b/RileyLink/DeviceDataManager.swift @@ -212,7 +212,7 @@ class DeviceDataManager { let pumpStatus: NightscoutUploadKit.PumpStatus? if let pumpDate = status.pumpDateComponents.date { - let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent, status: "normal") + let batteryStatus = BatteryStatus(percent: status.batteryRemainingPercent) let iobStatus = IOBStatus(timestamp: pumpDate, iob: status.iob) pumpStatus = NightscoutUploadKit.PumpStatus(clock: pumpDate, pumpID: pumpID, iob: iobStatus, battery: batteryStatus, reservoir: status.reservoirRemainingUnits) @@ -288,7 +288,7 @@ class DeviceDataManager { switch result { case .Success(let status): self.latestPolledPumpStatus = status - let battery = BatteryStatus(voltage: status.batteryVolts, status: String(status.batteryStatus).lowercaseString) + let battery = BatteryStatus(voltage: status.batteryVolts, status: BatteryIndicator(batteryStatus: status.batteryStatus)) status.clock.timeZone = ops.pumpState.timeZone guard let date = status.clock.date else { print("Could not interpret clock") From 3505a4c9aa3b3ca181cb51cc792d0166fdf7e679 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Wed, 3 Aug 2016 21:37:51 -0500 Subject: [PATCH 35/35] Make correction optional in LoopSuggested --- .../DeviceStatus/LoopSuggested.swift | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift index 0210fe2c9..45ab81313 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopSuggested.swift @@ -12,21 +12,21 @@ public struct LoopSuggested { let timestamp: NSDate let rate: Double let duration: NSTimeInterval - let correction: Double let eventualBG: Int let bg: Int let reason: String? let tick: Int? - - public init(timestamp: NSDate, rate: Double, duration: NSTimeInterval, correction: Double = 0, eventualBG: Int, bg: Int, reason: String?, tick: Int?) { + let correction: Double? + + public init(timestamp: NSDate, rate: Double, duration: NSTimeInterval, eventualBG: Int, bg: Int, reason: String? = nil, tick: Int? = nil, correction: Double? = nil) { self.timestamp = timestamp self.rate = rate self.duration = duration - self.correction = correction self.eventualBG = eventualBG self.bg = bg self.reason = reason self.tick = tick + self.correction = correction } public var dictionaryRepresentation: [String: AnyObject] { @@ -50,13 +50,17 @@ public struct LoopSuggested { rval["rate"] = rate rval["duration"] = duration / 60.0 rval["bg"] = bg - rval["correction"] = correction rval["eventualBG"] = eventualBG if let reason = reason { rval["reason"] = reason } + if let correction = correction { + rval["correction"] = correction + } + + return rval } }