-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Nightscout upload #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
91d1624
75fa34a
e916d09
fed1b4a
b198dc5
2d22b10
85f51db
82d8f2d
5b2c220
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ import MinimedKit | |
| import RileyLinkKit | ||
| import ShareClient | ||
| import xDripG5 | ||
| import NightscoutUploadKit | ||
|
|
||
| enum State<T> { | ||
| case NeedsConfiguration | ||
|
|
@@ -40,6 +41,13 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
| /// The share server client | ||
| private let shareClient: ShareClient? | ||
|
|
||
| /// Nightscout Uploader | ||
| var nightscoutUploader: NightscoutUploader? | ||
|
|
||
| // Timestamp of last event we've retrieved from pump | ||
| var observingPumpEventsSince: NSDate = NSDate().dateByAddingTimeInterval(60*60*24*(-1)) | ||
|
|
||
|
|
||
| /// The G5 transmitter object | ||
| var transmitter: Transmitter? { | ||
| switch transmitterState { | ||
|
|
@@ -58,7 +66,7 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
|
|
||
| /** | ||
| Called when a new idle message is received by the RileyLink. | ||
|
|
||
| Only MySentryPumpStatus messages are handled. | ||
|
|
||
| - parameter note: The notification object | ||
|
|
@@ -115,7 +123,7 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
|
|
||
| /** | ||
| Handles receiving a MySentry status message, which are only posted by MM x23 pumps. | ||
|
|
||
| This message has two important pieces of info about the pump: reservoir volume and battery. | ||
|
|
||
| Because the RileyLink must actively listen for these packets, they are not the most reliable heartbeat. However, we can still use them to assert glucose data is current. | ||
|
|
@@ -144,6 +152,8 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
| if status.batteryRemainingPercent == 0 { | ||
| NotificationManager.sendPumpBatteryLowNotification() | ||
| } | ||
|
|
||
| nightscoutUploader?.handlePumpStatus(status, device: device.deviceURI) | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -214,27 +224,50 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
| } | ||
|
|
||
| private func fetchPumpHistory() { | ||
|
|
||
| guard let device = rileyLinkManager.firstConnectedDevice else { | ||
| return | ||
| } | ||
|
|
||
| /* | ||
| This is where we fetch history. | ||
| */ | ||
| */ | ||
|
|
||
| let startDate = doseStore.pumpEventQueryAfterDate | ||
| // TODO: Reconcile these | ||
| //let startDate = doseStore.pumpEventQueryAfterDate | ||
| let startDate = nightscoutUploader?.observingPumpEventsSince ?? observingPumpEventsSince | ||
|
|
||
| device.ops?.getHistoryEventsSinceDate(startDate) { (result) in | ||
| switch result { | ||
| case let .Success(events, _): | ||
| case let .Success(events, pumpModel): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've changed this in a coming PR, since |
||
| // TODO: Surface raw pump event data and add DoseEntry conformance | ||
| self.doseStore.addPumpEvents(events.map({ ($0.date, nil, nil, $0.isMutable()) })) { (error) in | ||
| if let error = error { | ||
| self.logger?.addError("Failed to store history: \(error)", fromSource: "DoseStore") | ||
| } | ||
| // self.doseStore.addPumpEvents(events.map({ ($0.date, nil, nil, $0.isMutable()) })) { (error) in | ||
| // if let error = error { | ||
| // self.logger?.addError("Failed to store history: \(error)", fromSource: "DoseStore") | ||
| // } | ||
| // } | ||
|
|
||
| NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.PumpStatusUpdatedNotification, object: self) | ||
| self.nightscoutUploader?.processPumpEvents(events, source: device.deviceURI, pumpModel: pumpModel) | ||
|
|
||
|
|
||
| var lastFinalDate: NSDate? | ||
| var firstMutableDate: NSDate? | ||
|
|
||
| NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.PumpStatusUpdatedNotification, object: self) | ||
| for event in events { | ||
| if event.isMutable() { | ||
| firstMutableDate = min(event.date, firstMutableDate ?? event.date) | ||
| } else { | ||
| lastFinalDate = max(event.date, lastFinalDate ?? event.date) | ||
| } | ||
| } | ||
| if let mutableDate = firstMutableDate { | ||
| self.observingPumpEventsSince = mutableDate | ||
| } else if let finalDate = lastFinalDate { | ||
| self.observingPumpEventsSince = finalDate | ||
| } | ||
|
|
||
|
|
||
| case .Failure(let error): | ||
| self.logger?.addError("Failed to fetch history: \(error)", fromSource: "RileyLink") | ||
| self.troubleshootPumpCommsWithDevice(device) | ||
|
|
@@ -248,6 +281,7 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
| - 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) | ||
|
|
||
|
|
@@ -393,6 +427,8 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
| self.pumpState = nil | ||
| } | ||
|
|
||
| nightscoutUploader?.pumpID = pumpID | ||
|
|
||
| doseStore.pumpID = pumpID | ||
|
|
||
| NSUserDefaults.standardUserDefaults().pumpID = pumpID | ||
|
|
@@ -481,7 +517,7 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
| ID: transmitterID, | ||
| startTimeInterval: NSUserDefaults.standardUserDefaults().transmitterStartTime, | ||
| passiveModeEnabled: true | ||
| )) | ||
| )) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary indent here?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's where xcode puts it. I can move it if you want.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting, but it re-indented it even when code around it didn't change? Not a big deal. I think Xcode needs to get with it. |
||
| case (.Ready, .None): | ||
| transmitterState = .NeedsConfiguration | ||
| case (.Ready(let transmitter), let transmitterID?): | ||
|
|
@@ -637,15 +673,28 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { | |
| rileyLinkManager.idleListeningEnabled = idleListeningEnabled | ||
|
|
||
| if let settings = NSBundle.mainBundle().remoteSettings, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's two spaces in |
||
| username = settings["ShareAccountName"], | ||
| password = settings["ShareAccountPassword"] | ||
| username = settings["ShareAccountName"], | ||
| password = settings["ShareAccountPassword"] | ||
| where !username.isEmpty && !password.isEmpty | ||
| { | ||
| shareClient = ShareClient(username: username, password: password) | ||
| } else { | ||
| shareClient = nil | ||
| } | ||
|
|
||
| if let settings = NSBundle.mainBundle().remoteSettings, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra space between |
||
| siteURL = settings["NightscoutSiteURL"], | ||
| APISecret = settings["NightscoutAPISecret"] | ||
| { | ||
| nightscoutUploader = NightscoutUploader(siteURL: siteURL, APISecret: APISecret, pumpID: pumpID) | ||
| nightscoutUploader!.errorHandler = { (error: ErrorType, context: String) -> Void in | ||
| print("Error \(error), while \(context)") | ||
| } | ||
|
|
||
| } else { | ||
| nightscoutUploader = nil | ||
| } | ||
|
|
||
| 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) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,6 +77,8 @@ In the Loop project's Build Settings, change the value of `MAIN_APP_BUNDLE_IDENT | |
|
|
||
| Loop optionally supports select third-party remote services. While none of them are required to run the app, including [mLab](https://mlab.com) keys is strongly recommended at this time so loop diagnostic data can be stored in case retrospective analysis is needed. | ||
|
|
||
| If the Nightscout related entries are included, treatments and other pump data will be uploaded to your Nightscout site. Note you will need to set "Insulin Data Source" to "History" in Settings for treatments to be fetched from your pump and uploaded to Nightscout. | ||
|
|
||
| After a fresh clone of the repository, you'll need duplicate the template file and populate the copy with values. | ||
|
|
||
| ```bash | ||
|
|
@@ -93,6 +95,8 @@ $ cp Loop/RemoteSettings-template.plist Loop/RemoteSettings.plist | |
| | `AmplitudeAPIKey` | Your Amplitude analytics API Key (for optional, private behavior tracking) | ||
| | `ShareAccountName` | Your username for Dexcom share (for backfilling glucose data) | ||
| | `ShareAccountPassword` | Your password for Dexcom share | ||
| | `NightscoutSiteURL` | Your Nightscout site URL | ||
| | `NightscoutAPISecret` | Your Nightscout API Secret (not hashed) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI I'm going to migrate these all eventually (rather than storing in plain text in the app bundle) |
||
|
|
||
| # Making it Your Own | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NSDate(timeIntervalSinceNow: NSTimeInterval(hours: -24))There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And you can remove the explicit type
: NSDateThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think your extension is available in Loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, it looks like it is; typo