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
4 changes: 4 additions & 0 deletions Common/Extensions/NSTimeInterval.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import Foundation


extension TimeInterval {
static func seconds(_ seconds: Double) -> TimeInterval {
return seconds
}

static func minutes(_ minutes: Double) -> TimeInterval {
return TimeInterval(minutes: minutes)
}
Expand Down
30 changes: 25 additions & 5 deletions Loop/Managers/AnalyticsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,27 @@ final class AnalyticsManager: IdentifiableClass {
// MARK: - Config Events

func didChangeRileyLinkConnectionState() {
logEvent("RileyLink Connection")
logEvent("RileyLink Connection", outOfSession: true)
}

func transmitterTimeDidDrift(_ drift: TimeInterval) {
logEvent("Transmitter time change", withProperties: ["value" : drift])
logEvent("Transmitter time change", withProperties: ["value" : drift], outOfSession: true)
}

func pumpTimeDidDrift(_ drift: TimeInterval) {
logEvent("Pump time change", withProperties: ["value": drift], outOfSession: true)
}

func punpTimeZoneDidChange() {
logEvent("Pump time zone change", outOfSession: true)
}

func pumpBatteryWasReplaced() {
logEvent("Pump battery replacement")
logEvent("Pump battery replacement", outOfSession: true)
}

func reservoirWasRewound() {
logEvent("Pump reservoir rewind")
logEvent("Pump reservoir rewind", outOfSession: true)
}

func didChangeBasalRateSchedule() {
Expand All @@ -98,7 +106,7 @@ final class AnalyticsManager: IdentifiableClass {
}

func didChangeLoopSettings(from oldValue: LoopSettings, to newValue: LoopSettings) {
logEvent("Loop settings change")
logEvent("Loop settings change", outOfSession: true)

if newValue.maximumBasalRatePerHour != oldValue.maximumBasalRatePerHour {
logEvent("Maximum basal rate change")
Expand All @@ -111,6 +119,14 @@ final class AnalyticsManager: IdentifiableClass {
if newValue.suspendThreshold != oldValue.suspendThreshold {
logEvent("Minimum BG Guard change")
}

if newValue.dosingEnabled != oldValue.dosingEnabled {
logEvent("Closed loop enabled change")
}

if newValue.retrospectiveCorrectionEnabled != oldValue.retrospectiveCorrectionEnabled {
logEvent("Retrospective correction enabled change")
}
}

// MARK: - Loop Events
Expand All @@ -127,6 +143,10 @@ final class AnalyticsManager: IdentifiableClass {
logEvent("Bolus set", withProperties: ["source" : "Watch"], outOfSession: true)
}

func didFetchNewCGMData() {
logEvent("CGM Fetch", outOfSession: true)
}

func loopDidSucceed() {
logEvent("Loop success", outOfSession: true)
}
Expand Down
58 changes: 44 additions & 14 deletions Loop/Managers/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ final class DeviceDataManager {
self.lastTimerTick = Date()

self.cgmManager?.fetchNewDataIfNeeded(with: self) { (result) in
if case .newData = result {
AnalyticsManager.shared.didFetchNewCGMData()
}

// TODO: Isolate to queue?
self.cgmManager(self.cgmManager!, didUpdateWith: result)
}
Expand Down Expand Up @@ -487,6 +491,16 @@ final class DeviceDataManager {
return
}

// Check if the clock should be reset
if abs(date.timeIntervalSinceNow) > .seconds(20) {
self.logger.addError("Pump clock is more than 20 seconds off. Resetting.", fromSource: "RileyLink")
AnalyticsManager.shared.pumpTimeDidDrift(date.timeIntervalSinceNow)
try session.setTime { () -> DateComponents in
let calendar = Calendar(identifier: .gregorian)
return calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date())
}
}

self.observeBatteryDuring {
self.latestPumpStatus = status
}
Expand Down Expand Up @@ -840,18 +854,6 @@ extension DeviceDataManager: LoopDataManagerDelegate {
return
}

let notify = { (result: Result<DoseEntry>) -> Void in
// If we haven't fetched history in a while (preferredInsulinDataSource == .reservoir),
// let's try to do so while the pump radio is on.
if self.loopManager.doseStore.lastAddedPumpEvents.timeIntervalSinceNow < .minutes(-4) {
self.fetchPumpHistory { (_) in
completion(result)
}
} else {
completion(result)
}
}

pumpOps.runSession(withName: "Set Temp Basal", using: rileyLinkManager.firstConnectedDevice) { (session) in
guard let session = session else {
completion(.failure(LoopError.connectionError))
Expand All @@ -864,15 +866,43 @@ extension DeviceDataManager: LoopDataManagerDelegate {
let now = Date()
let endDate = now.addingTimeInterval(response.timeRemaining)
let startDate = endDate.addingTimeInterval(-basal.recommendation.duration)
notify(.success(DoseEntry(
completion(.success(DoseEntry(
type: .tempBasal,
startDate: startDate,
endDate: endDate,
value: response.rate,
unit: .unitsPerHour
)))

// Continue below
} catch let error {
completion(.failure(error))
return
}

do {
// If we haven't fetched history in a while, our preferredInsulinDataSource is probably .reservoir, so
// let's take advantage of the pump radio being on.
if self.loopManager.doseStore.lastAddedPumpEvents.timeIntervalSinceNow < .minutes(-4) {
let clock = try session.getTime()
// Check if the clock should be reset
if let date = clock.date, abs(date.timeIntervalSinceNow) > .seconds(20) {
self.logger.addError("Pump clock is more than 20 seconds off. Resetting.", fromSource: "RileyLink")
AnalyticsManager.shared.pumpTimeDidDrift(date.timeIntervalSinceNow)
try session.setTime { () -> DateComponents in
let calendar = Calendar(identifier: .gregorian)
return calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date())
}
}

self.fetchPumpHistory { (error) in
if let error = error {
self.logger.addError("Post-basal history fetch failed: \(error)", fromSource: "RileyLink")
}
}
}
} catch let error {
notify(.failure(error))
self.logger.addError("Post-basal time sync failed: \(error)", fromSource: "RileyLink")
}
}
}
Expand Down
18 changes: 10 additions & 8 deletions Loop/Managers/LoopDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class LoopDataManager {
}

static let LoopUpdateContextKey = "com.loudnate.Loop.LoopDataManager.LoopUpdateContext"
static let LastLoopCompletedKey = "com.loopkit.Loop.LoopDataManager.LastLoopCompleted"

fileprivate typealias GlucoseChange = (start: GlucoseValue, end: GlucoseValue)

Expand Down Expand Up @@ -134,13 +135,6 @@ final class LoopDataManager {
}
}

/// Disable any active workout glucose targets
func disableWorkoutMode() {
settings.glucoseTargetRangeSchedule?.clearOverride()

notify(forChange: .preferences)
}

/// The length of time insulin has an effect on blood glucose
var insulinModelSettings: InsulinModelSettings? {
get {
Expand Down Expand Up @@ -596,9 +590,17 @@ final class LoopDataManager {
}

private func notify(forChange context: LoopUpdateContext) {
var userInfo: [String: Any] = [
type(of: self).LoopUpdateContextKey: context.rawValue
]

if let lastLoopCompleted = lastLoopCompleted {
userInfo[type(of: self).LastLoopCompletedKey] = lastLoopCompleted
}

NotificationCenter.default.post(name: .LoopDataUpdated,
object: self,
userInfo: [type(of: self).LoopUpdateContextKey: context.rawValue]
userInfo: userInfo
)
}

Expand Down
5 changes: 5 additions & 0 deletions Loop/View Controllers/StatusTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ final class StatusTableViewController: ChartsTableViewController {
notificationObservers += [
notificationCenter.addObserver(forName: .LoopDataUpdated, object: deviceManager.loopManager, queue: nil) { [unowned self] note in
let context = note.userInfo?[LoopDataManager.LoopUpdateContextKey] as! LoopDataManager.LoopUpdateContext.RawValue
let lastLoopCompleted = note.userInfo?[LoopDataManager.LastLoopCompletedKey] as? Date
DispatchQueue.main.async {
switch LoopDataManager.LoopUpdateContext(rawValue: context) {
case .none, .bolus?:
Expand All @@ -58,6 +59,10 @@ final class StatusTableViewController: ChartsTableViewController {
self.refreshContext.formUnion([.glucose, .carbs])
case .tempBasal?:
self.refreshContext.update(with: .insulin)

if let lastLoopCompleted = lastLoopCompleted {
self.hudView?.loopCompletionHUD.lastLoopCompleted = lastLoopCompleted
}
}

self.hudView?.loopCompletionHUD.loopInProgress = false
Expand Down
2 changes: 1 addition & 1 deletion LoopUI/Views/LoopCompletionHUDView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public final class LoopCompletionHUDView: BaseHUDView {
)
updateTimer = timer

RunLoop.main.add(timer, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.main.add(timer, forMode: .defaultRunLoopMode)
}

private var updateTimer: Timer? {
Expand Down