Skip to content

Remote Bolus Dev#1508

Closed
gestrich wants to merge 15 commits into
LoopKit:devfrom
gestrich:dev_otp
Closed

Remote Bolus Dev#1508
gestrich wants to merge 15 commits into
LoopKit:devfrom
gestrich:dev_otp

Conversation

@gestrich

@gestrich gestrich commented May 23, 2021

Copy link
Copy Markdown
Contributor

This PR includes changes to the Loop module to support remote/bolus in dev. See the workspace PR for more details on the overall effort. Comments added inline for review.

@gestrich gestrich changed the title Dev otp Remote Bolus Dev May 23, 2021
@gestrich gestrich force-pushed the dev_otp branch 3 times, most recently from 5b2e804 to 9efa688 Compare June 12, 2021 19:50
@gestrich gestrich force-pushed the dev_otp branch 6 times, most recently from 2a07601 to c8d6c9a Compare June 20, 2021 15:59

@ps2 ps2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Bill, could you address the comments? Otherwise, this is looking great! Thanks!

Comment thread Loop/AppDelegate.swift Outdated

loopAppManager.initialize(windowProvider: self, launchOptions: launchOptions)
loopAppManager.launch()
UIApplication.shared.registerForRemoteNotifications()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already happening in NotificationManager; we should probably only do this once.

@gestrich gestrich Aug 31, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ps2 This is part of the proposed fix outlined in 1536 (among others). From what I can tell, we only fetch the token via registerForRemoteNotifications during onboarding. Since we can't persist the token per iOS guidelines, it will be available in-memory only and not be available for later upload after an app reboot. Here's the cases where that could pose an issue:

  1. User chooses to setup Nightscout after onboarding.
  2. User goes offline during onboarding process.

I think attempting to fetch it on each startup would be good protection against the above scenarios -- it will always be available to in memory and uploaded to Nightscout when needed.

If that seems reasonable, I agree we don't need it in both places. How about I remove it from onboarding? Or are there other considerations I'm not thinking of?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this PR in this way. Please let me know if any any questions on that.

Comment thread Loop/Managers/DeviceDataManager.swift Outdated
case .cancelTemporaryOverride:
log.default("Canceling temporary override from remote command")
loopManager.settings.scheduleOverride = nil
case .bolusEntry(let bolusValue):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should trigger a user notification when this happens. Or is the push notification including foreground text?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added notifications to indicate success and failure once the remote notification is processed. That should handle the foreground notification and allow for better troubleshooting for both foreground and background states. I've added screenshots and more discussion in Zulip https://loop.zulipchat.com/#narrow/stream/144182-development/topic/Remote.20bolus.20.2F.20remote.20carbs

log.default("No max bolus detected. Aborting...")
}
case .carbsEntry(let newEntry):
log.default("Adding carbs entry.")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A local notification should happen with this too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@@ -375,6 +375,8 @@
89FE21AD24AC57E30033F501 /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FE21AC24AC57E30033F501 /* Collection.swift */; };
A90EF53C25DEF06200F32D61 /* PluginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16DA84122E8E112008624C2 /* PluginManager.swift */; };
A90EF54425DEF0A000F32D61 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5EE209D84BE00D17AA8 /* OSLog.swift */; };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Base32 and OneTimePassword are the new git submodules that are linked in the workspace. I believe they need added to the Loop project, and to be embedded, in order for things to work.

loopManager.settings.scheduleOverride = nil
case .bolusEntry(let bolusAmount):
log.default("Enacting remote bolus entry: %{public}@", String(describing: bolusAmount))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add explicit guards for the various error conditions on a remote bolus. In there is an error, that will be reported back as a user local notification.

log.default("Remote bolus higher than maximum. Aborting...")
return
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When enacting the bolus here, we may get a specialized error from the enactBolus API which will also be presented in a local notification.... otherwise we show a local notification with a success message.

} else {
NotificationManager.sendRemoteBolusNotification(amount: bolusAmount)
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same paradigm here for remote carb entries.

log.default("Invalid carb entry amount. Aborting...")
return
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this check that we don't exceed the max carb entry amount.

log.default("Carbs higher than maximum. Aborting...")
return
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally we attempt to add the carbs, and also show an error if that fails (unlikely - would be Core Data issue it seems)

Comment thread Loop/Managers/LoopAppManager.swift
}

// MARK: - Remote Notification

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pete - Since you looked over this before I realized I should have this feature flag check. At least that is what is done in dev now.

@@ -324,10 +332,13 @@ extension LoopAppManager: UNUserNotificationCenterDelegate {
case LoopNotificationCategory.bolusFailure.rawValue,
LoopNotificationCategory.pumpBatteryLow.rawValue,
LoopNotificationCategory.pumpExpired.rawValue,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New notifications for remote bolus/carbs. More on that below.

Comment thread Loop/Managers/LoopDataManager.swift Outdated
@@ -798,7 +798,7 @@ extension LoopDataManager {
maximumBasalRatePerHour: loopSettings.maximumBasalRatePerHour,
maximumBolus: loopSettings.maximumBolus,
suspendThreshold: loopSettings.suspendThreshold,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was discussed in #1536... But basically loopSettings doeesn't store the deviceToken so this will be nil. We may want to just remove that property altogether to avoid the confusion but I'd need to verify that is ok.

@@ -67,14 +67,6 @@ extension NotificationManager {
center.requestAuthorization(options: authOptions) { (granted, error) in
UNUserNotificationCenter.current().getNotificationSettings { settings in
completion(settings.authorizationStatus)

@gestrich gestrich Sep 3, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed in #1536 but need to make sure this is called on each startup since we are not persisting it anywhere. Moved to LoopAppManager above.

@@ -156,6 +148,85 @@ extension NotificationManager {
UNUserNotificationCenter.current().add(request)
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helpers to send the new local notifications.

@@ -361,6 +361,21 @@ extension RemoteDataServicesManager {

}

@gestrich gestrich Sep 3, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check our data services for one to validate our notification here. As a future enhancement, data services like Nightscout could provide some kind of identifier in the push payload that maps to the service. That would allow Loop to dispatch the notification to the corresponding service rather than sending it to all the services like this.

import Foundation
import LoopKit
import HealthKit

@gestrich gestrich Sep 3, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this was being used from what I can tell. But it looks like the right structure to add new remote command errors like I needed for remote bolus/carbs.

case exceedsMaxBolus
case exceedsMaxCarbs
case invalidCarbs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using this description in the local notifications that show.

self = .cancelTemporaryOverride
} else if let bolusValue = notification["bolus-entry"] as? Double {
self = .bolusEntry(bolusValue)
} else if let carbsValue = notification["carbs-entry"] as? Double {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jose had this original comment on the default absorption value. I hadn't dug in but it doesn't seem critical now either.

@gestrich gestrich marked this pull request as ready for review September 3, 2021 20:27
@gestrich gestrich requested a review from ps2 September 3, 2021 20:27
@ps2

ps2 commented Mar 9, 2022

Copy link
Copy Markdown
Collaborator

Token management has been resolved in dev, I believe. This PR needs to be updated to resolve conflicts with the latest dev. I'll see if I can land the NightScoutService soon.

@gestrich

Copy link
Copy Markdown
Contributor Author

@ps2 conflicts + token workarounds have been removed.

@ps2

ps2 commented Mar 14, 2022

Copy link
Copy Markdown
Collaborator

Merged these changes in 5b25c83. Forgot to squash, so they're all separate in the log. :-/

@ps2 ps2 closed this Mar 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants