Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 0 additions & 49 deletions Common/Models/BolusSuggestionUserInfo.swift

This file was deleted.

13 changes: 2 additions & 11 deletions Common/Models/WatchContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import HealthKit
import LoopKit


final class WatchContext: NSObject, RawRepresentable {
final class WatchContext: RawRepresentable {
typealias RawValue = [String: Any]

private let version = 4
Expand All @@ -32,12 +32,6 @@ final class WatchContext: NSObject, RawRepresentable {
var lastNetTempBasalDate: Date?
var recommendedBolusDose: Double?

var bolusSuggestion: BolusSuggestionUserInfo? {
guard let recommended = recommendedBolusDose else { return nil }

return BolusSuggestionUserInfo(recommendedBolus: recommended)
}

var cob: Double?
var iob: Double?
var reservoir: Double?
Expand All @@ -46,13 +40,10 @@ final class WatchContext: NSObject, RawRepresentable {

var cgmManagerState: CGMManager.RawStateValue?

override init() {
super.init()
init() {
}

required init?(rawValue: RawValue) {
super.init()

guard rawValue["v"] as? Int == version else {
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions Common/Models/WatchPredictedGlucose.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import LoopKit
import HealthKit


struct WatchPredictedGlucose {
let values: [GlucoseValue]
struct WatchPredictedGlucose: Equatable {
let values: [PredictedGlucoseValue]

init?(values: [GlucoseValue]) {
init?(values: [PredictedGlucoseValue]) {
guard values.count > 1 else {
return nil
}
Expand Down
8 changes: 4 additions & 4 deletions DoseMathTests/DoseMathTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class RecommendTempBasalTests: XCTestCase {

fileprivate let fortyIncrementsPerUnitRounder = { round($0 * 40) / 40 }

func loadGlucoseValueFixture(_ resourceName: String) -> [GlucoseValue] {
func loadGlucoseValueFixture(_ resourceName: String) -> [GlucoseFixtureValue] {
let fixture: [JSONDictionary] = loadFixture(resourceName)
let dateFormatter = ISO8601DateFormatter.localTimeDateFormatter()

Expand Down Expand Up @@ -441,7 +441,7 @@ class RecommendTempBasalTests: XCTestCase {


func testNoInputGlucose() {
let glucose: [GlucoseValue] = []
let glucose: [GlucoseFixtureValue] = []

let dose = glucose.recommendedTempBasal(
to: glucoseTargetRange,
Expand All @@ -464,7 +464,7 @@ class RecommendBolusTests: XCTestCase {

fileprivate let fortyIncrementsPerUnitRounder = { round($0 * 40) / 40 }

func loadGlucoseValueFixture(_ resourceName: String) -> [GlucoseValue] {
func loadGlucoseValueFixture(_ resourceName: String) -> [GlucoseFixtureValue] {
let fixture: [JSONDictionary] = loadFixture(resourceName)
let dateFormatter = ISO8601DateFormatter.localTimeDateFormatter()

Expand Down Expand Up @@ -823,7 +823,7 @@ class RecommendBolusTests: XCTestCase {


func testNoInputGlucose() {
let glucose: [GlucoseValue] = []
let glucose: [GlucoseFixtureValue] = []

let dose = glucose.recommendedBolus(
to: glucoseTargetRange,
Expand Down
6 changes: 0 additions & 6 deletions Loop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@
43511CE321FD80E400566C63 /* StandardRetrospectiveCorrection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43511CE021FD80E400566C63 /* StandardRetrospectiveCorrection.swift */; };
43511CEE220FC61700566C63 /* HUDRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43511CED220FC61700566C63 /* HUDRowController.swift */; };
43523EDB1CC35083001850F1 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43523EDA1CC35083001850F1 /* RileyLinkKit.framework */; };
435400311C9F744E00D5819C /* BolusSuggestionUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400301C9F744E00D5819C /* BolusSuggestionUserInfo.swift */; };
435400321C9F745500D5819C /* BolusSuggestionUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400301C9F744E00D5819C /* BolusSuggestionUserInfo.swift */; };
435400341C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */; };
435400351C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */; };
435CB6231F37967800C320C7 /* InsulinModelSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6221F37967800C320C7 /* InsulinModelSettingsViewController.swift */; };
Expand Down Expand Up @@ -623,7 +621,6 @@
43511CE021FD80E400566C63 /* StandardRetrospectiveCorrection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandardRetrospectiveCorrection.swift; sourceTree = "<group>"; };
43511CED220FC61700566C63 /* HUDRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDRowController.swift; sourceTree = "<group>"; };
43523EDA1CC35083001850F1 /* RileyLinkKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RileyLinkKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
435400301C9F744E00D5819C /* BolusSuggestionUserInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusSuggestionUserInfo.swift; sourceTree = "<group>"; };
435400331C9F878D00D5819C /* SetBolusUserInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetBolusUserInfo.swift; sourceTree = "<group>"; };
435CB6221F37967800C320C7 /* InsulinModelSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinModelSettingsViewController.swift; sourceTree = "<group>"; };
435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExponentialInsulinModelPreset.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1709,7 +1706,6 @@
4FF4D0FB1E1834C400846527 /* Models */ = {
isa = PBXGroup;
children = (
435400301C9F744E00D5819C /* BolusSuggestionUserInfo.swift */,
4F11D3BF20DCBEEC006E072C /* GlucoseBackfillRequestUserInfo.swift */,
4372E48F213CFCE70068E043 /* LoopSettingsUserInfo.swift */,
435400331C9F878D00D5819C /* SetBolusUserInfo.swift */,
Expand Down Expand Up @@ -2473,7 +2469,6 @@
C15713821DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift in Sources */,
43FCEEA9221A615B0013DD30 /* StatusChartsManager.swift in Sources */,
43511CE321FD80E400566C63 /* StandardRetrospectiveCorrection.swift in Sources */,
435400321C9F745500D5819C /* BolusSuggestionUserInfo.swift in Sources */,
43E3449F1B9D68E900C85C07 /* StatusTableViewController.swift in Sources */,
43DBF0531C93EC8200B3C386 /* DeviceDataManager.swift in Sources */,
43E2D8C81D208D5B004DA55F /* KeychainManager+Loop.swift in Sources */,
Expand Down Expand Up @@ -2559,7 +2554,6 @@
4372E488213C862B0068E043 /* SampleValue.swift in Sources */,
4F2C15741E0209F500E160D4 /* NSTimeInterval.swift in Sources */,
4FF4D1011E18375000846527 /* WatchContext.swift in Sources */,
435400311C9F744E00D5819C /* BolusSuggestionUserInfo.swift in Sources */,
898ECA63218ABD21001E9D35 /* ComplicationChartManager.swift in Sources */,
43A9438A1B926B7B0051FA24 /* NotificationController.swift in Sources */,
439A7945211FE23A0041B75F /* NSUserActivity.swift in Sources */,
Expand Down
6 changes: 4 additions & 2 deletions Loop/Managers/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,16 @@ private extension DeviceDataManager {

// MARK: - Client API
extension DeviceDataManager {
func enactBolus(units: Double, at startDate: Date = Date(), completion: @escaping (_ error: Error?) -> Void) {
func enactBolus(units: Double, at startDate: Date = Date(), willRequest: ((DoseEntry) -> Void)? = nil, completion: @escaping (_ error: Error?) -> Void) {
guard let pumpManager = pumpManager else {
completion(LoopError.configurationError(.pumpManager))
return
}

pumpManager.enactBolus(units: units, at: startDate, willRequest: { (dose) in
self.loopManager.addRequestedBolus(dose, completion: nil)
self.loopManager.addRequestedBolus(dose, completion: {
willRequest?(dose)
})
}) { (result) in
switch result {
case .failure(let error):
Expand Down
2 changes: 1 addition & 1 deletion Loop/Managers/DoseMath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ private func targetGlucoseValue(percentEffectDuration: Double, minValue: Double,
}


extension Collection where Element == GlucoseValue {
extension Collection where Element: GlucoseValue {

/// For a collection of glucose prediction, determine the least amount of insulin delivered at
/// `date` to correct the predicted glucose to the middle of `correctionRange` at the time of prediction.
Expand Down
8 changes: 4 additions & 4 deletions Loop/Managers/LoopDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ final class LoopDataManager {
}
private var retrospectiveGlucoseDiscrepanciesSummed: [GlucoseChange]?

fileprivate var predictedGlucose: [GlucoseValue]? {
fileprivate var predictedGlucose: [PredictedGlucoseValue]? {
didSet {
recommendedTempBasal = nil
recommendedBolus = nil
Expand Down Expand Up @@ -790,7 +790,7 @@ extension LoopDataManager {
}

/// - Throws: LoopError.missingDataError
fileprivate func predictGlucose(using inputs: PredictionInputEffect) throws -> [GlucoseValue] {
fileprivate func predictGlucose(using inputs: PredictionInputEffect) throws -> [PredictedGlucoseValue] {
dispatchPrecondition(condition: .onQueue(dataAccessQueue))

guard let model = insulinModelSettings?.model else {
Expand Down Expand Up @@ -1020,7 +1020,7 @@ protocol LoopState {
var lastTempBasal: DoseEntry? { get }

/// The calculated timeline of predicted glucose values
var predictedGlucose: [GlucoseValue]? { get }
var predictedGlucose: [PredictedGlucoseValue]? { get }

/// The recommended temp basal based on predicted glucose
var recommendedTempBasal: (recommendation: TempBasalRecommendation, date: Date)? { get }
Expand Down Expand Up @@ -1074,7 +1074,7 @@ extension LoopDataManager {
return loopDataManager.lastTempBasal
}

var predictedGlucose: [GlucoseValue]? {
var predictedGlucose: [PredictedGlucoseValue]? {
dispatchPrecondition(condition: .onQueue(loopDataManager.dataAccessQueue))
return loopDataManager.predictedGlucose
}
Expand Down
35 changes: 23 additions & 12 deletions Loop/Managers/WatchDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ final class WatchDataManager: NSObject {
}

createWatchContext { (context) in
if let context = context {
self.sendWatchContext(context)
}
self.sendWatchContext(context)
}
}

Expand Down Expand Up @@ -142,7 +140,7 @@ final class WatchDataManager: NSObject {
}
}

private func createWatchContext(_ completion: @escaping (_ context: WatchContext?) -> Void) {
private func createWatchContext(_ completion: @escaping (_ context: WatchContext) -> Void) {
let loopManager = deviceManager.loopManager!

let glucose = loopManager.glucoseStore.latestGlucose
Expand Down Expand Up @@ -179,7 +177,7 @@ final class WatchDataManager: NSObject {
if let scheduledBasal = manager.basalRateScheduleApplyingOverrideHistory?.between(start: date, end: date).first,
let lastTempBasal = state.lastTempBasal,
lastTempBasal.endDate > Date() {
context.lastNetTempBasalDose = lastTempBasal.unitsPerHour - scheduledBasal.value
context.lastNetTempBasalDose = lastTempBasal.unitsPerHour - scheduledBasal.value
}

// Drop the first element in predictedGlucose because it is the current glucose
Expand All @@ -192,19 +190,20 @@ final class WatchDataManager: NSObject {
}
}

private func addCarbEntryFromWatchMessage(_ message: [String: Any], completionHandler: ((_ units: Double?) -> Void)? = nil) {
private func addCarbEntryFromWatchMessage(_ message: [String: Any], completionHandler: ((_ error: Error?) -> Void)? = nil) {
if let carbEntry = CarbEntryUserInfo(rawValue: message)?.carbEntry {
deviceManager.loopManager.addCarbEntryAndRecommendBolus(carbEntry) { (result) in
switch result {
case .success(let recommendation):
case .success:
AnalyticsManager.shared.didAddCarbsFromWatch()
completionHandler?(recommendation?.amount)
completionHandler?(nil)
case .failure(let error):
self.log.error(error)
completionHandler?(nil)
completionHandler?(error)
}
}
} else {
log.error("Could not add carb entry from unknown message: \(message)")
completionHandler?(nil)
}
}
Expand All @@ -215,18 +214,26 @@ extension WatchDataManager: WCSessionDelegate {
func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
switch message["name"] as? String {
case CarbEntryUserInfo.name?:
addCarbEntryFromWatchMessage(message) { (units) in
replyHandler(BolusSuggestionUserInfo(recommendedBolus: units ?? 0, maxBolus: self.deviceManager.loopManager.settings.maximumBolus).rawValue)
addCarbEntryFromWatchMessage(message) { (_) in
self.createWatchContext { (context) in
// Send back the updated prediction and recommended bolus
replyHandler(context.rawValue)
}
}
case SetBolusUserInfo.name?:
// Start the bolus and reply when it's successfully requested
if let bolus = SetBolusUserInfo(rawValue: message as SetBolusUserInfo.RawValue) {
self.deviceManager.enactBolus(units: bolus.value, at: bolus.startDate) { (error) in
if error == nil {
AnalyticsManager.shared.didSetBolusFromWatch(bolus.value)
}

// When we've successfully started the bolus, send a new context with our new prediction
self.sendWatchContextIfNeeded()
}
}

// Reply immediately
replyHandler([:])
case LoopSettingsUserInfo.name?:
if let watchSettings = LoopSettingsUserInfo(rawValue: message)?.settings {
Expand All @@ -238,7 +245,11 @@ extension WatchDataManager: WCSessionDelegate {
lastSentSettings = settings
deviceManager.loopManager.settings = settings
}
replyHandler([:])

// Since target range affects recommended bolus, send back a new one
createWatchContext { (context) in
replyHandler(context.rawValue)
}
case GlucoseBackfillRequestUserInfo.name?:
if let userInfo = GlucoseBackfillRequestUserInfo(rawValue: message),
let manager = deviceManager.loopManager {
Expand Down
16 changes: 10 additions & 6 deletions WatchApp Extension/Controllers/ActionHUDController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,21 @@ final class ActionHUDController: HUDInterfaceController {
settings.scheduleOverride = override
let userInfo = LoopSettingsUserInfo(settings: settings)
do {
try WCSession.default.sendSettingsUpdateMessage(userInfo, completionHandler: { error in
try WCSession.default.sendSettingsUpdateMessage(userInfo, completionHandler: { (result) in
DispatchQueue.main.async {
self.pendingMessageResponses -= 1
if let error = error {

switch result {
case .success(let context):
if self.pendingMessageResponses == 0 {
ExtensionDelegate.shared().present(error)
self.updateForOverrideContext(self.loopManager.settings.scheduleOverride?.context)
self.loopManager.settings.scheduleOverride = override
}
} else {

ExtensionDelegate.shared().loopManager.updateContext(context)
case .failure(let error):
if self.pendingMessageResponses == 0 {
self.loopManager.settings.scheduleOverride = override
ExtensionDelegate.shared().present(error)
self.updateForOverrideContext(self.loopManager.settings.scheduleOverride?.context)
}
}
}
Expand Down
11 changes: 6 additions & 5 deletions WatchApp Extension/Controllers/AddCarbsInterfaceController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,15 @@ final class AddCarbsInterfaceController: WKInterfaceController, IdentifiableClas

do {
try WCSession.default.sendCarbEntryMessage(entry,
replyHandler: { (suggestion) in
replyHandler: { (context) in
DispatchQueue.main.async {
WKInterfaceDevice.current().play(.success)
let loopManager = ExtensionDelegate.shared().loopManager
loopManager.addConfirmedCarbEntry(entry.carbEntry)
loopManager.updateContext(context)

ExtensionDelegate.shared().loopManager.addConfirmedCarbEntry(entry.carbEntry)

if let recommendedBolus = suggestion.recommendedBolus?.rawValue, recommendedBolus > 0.0 {
WKExtension.shared().rootInterfaceController?.presentController(withName: BolusInterfaceController.className, context: suggestion)
if let units = context.recommendedBolusDose, units > 0.0 {
WKExtension.shared().rootInterfaceController?.presentController(withName: BolusInterfaceController.className, context: context)
}
}
},
Expand Down
Loading