DeviceDataManager.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import Combine
  2. import Foundation
  3. import LoopKit
  4. import LoopKitUI
  5. import MinimedKit
  6. import MockKit
  7. import OmniKit
  8. import SwiftDate
  9. import Swinject
  10. import UserNotifications
  11. protocol DeviceDataManager {
  12. var pumpManager: PumpManagerUI? { get set }
  13. var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> { get }
  14. var recommendsLoop: PassthroughSubject<Void, Never> { get }
  15. }
  16. private let staticPumpManagers: [PumpManagerUI.Type] = [
  17. MinimedPumpManager.self,
  18. OmnipodPumpManager.self,
  19. MockPumpManager.self
  20. ]
  21. private let staticPumpManagersByIdentifier: [String: PumpManagerUI.Type] = staticPumpManagers.reduce(into: [:]) { map, Type in
  22. map[Type.managerIdentifier] = Type
  23. }
  24. final class BaseDeviceDataManager: DeviceDataManager, Injectable {
  25. @Injected() private var pumpHistoryStorage: PumpHistoryStorage!
  26. @Injected() private var storage: FileStorage!
  27. @Persisted(key: "BaseDeviceDataManager.lastEventDate") var lastEventDate: Date? = nil
  28. let recommendsLoop = PassthroughSubject<Void, Never>()
  29. var pumpManager: PumpManagerUI? {
  30. didSet {
  31. pumpManager?.pumpManagerDelegate = self
  32. UserDefaults.standard.pumpManagerRawValue = pumpManager?.rawValue
  33. if let pumpManager = pumpManager {
  34. pumpDisplayState.value = PumpDisplayState(name: pumpManager.localizedTitle, image: pumpManager.smallImage)
  35. } else {
  36. pumpDisplayState.value = nil
  37. }
  38. }
  39. }
  40. let pumpDisplayState = CurrentValueSubject<PumpDisplayState?, Never>(nil)
  41. init(resolver: Resolver) {
  42. injectServices(resolver)
  43. setupPumpManager()
  44. UIDevice.current.isBatteryMonitoringEnabled = true
  45. }
  46. func setupPumpManager() {
  47. if let pumpManagerRawValue = UserDefaults.standard.pumpManagerRawValue {
  48. pumpManager = pumpManagerFromRawValue(pumpManagerRawValue)
  49. }
  50. }
  51. private func pumpManagerFromRawValue(_ rawValue: [String: Any]) -> PumpManagerUI? {
  52. guard let rawState = rawValue["state"] as? PumpManager.RawStateValue,
  53. let Manager = pumpManagerTypeFromRawValue(rawValue)
  54. else {
  55. return nil
  56. }
  57. return Manager.init(rawState: rawState) as? PumpManagerUI
  58. }
  59. private func pumpManagerTypeFromRawValue(_ rawValue: [String: Any]) -> PumpManager.Type? {
  60. guard let managerIdentifier = rawValue["managerIdentifier"] as? String else {
  61. return nil
  62. }
  63. return staticPumpManagersByIdentifier[managerIdentifier]
  64. }
  65. }
  66. extension BaseDeviceDataManager: PumpManagerDelegate {
  67. func pumpManager(_: PumpManager, didAdjustPumpClockBy _: TimeInterval) {
  68. // log.debug("didAdjustPumpClockBy %@", adjustment)
  69. }
  70. func pumpManagerDidUpdateState(_ pumpManager: PumpManager) {
  71. UserDefaults.standard.pumpManagerRawValue = pumpManager.rawValue
  72. }
  73. func pumpManagerBLEHeartbeatDidFire(_ pumpManager: PumpManager) {
  74. debug(.deviceManager, "Pump Heartbeat")
  75. pumpManager.ensureCurrentPumpData {
  76. debug(.deviceManager, "Pump Data updated")
  77. }
  78. }
  79. func pumpManagerMustProvideBLEHeartbeat(_: PumpManager) -> Bool {
  80. true
  81. }
  82. func pumpManager(_: PumpManager, didUpdate status: PumpManagerStatus, oldStatus _: PumpManagerStatus) {
  83. debug(.deviceManager, "New pump status Bolus: \(status.bolusState)")
  84. debug(.deviceManager, "New pump status Basal: \(String(describing: status.basalDeliveryState))")
  85. }
  86. func pumpManagerWillDeactivate(_: PumpManager) {
  87. pumpManager = nil
  88. }
  89. func pumpManager(_: PumpManager, didUpdatePumpRecordsBasalProfileStartEvents _: Bool) {}
  90. func pumpManager(_: PumpManager, didError error: PumpManagerError) {
  91. info(.deviceManager, "error: \(error.localizedDescription)")
  92. }
  93. func pumpManager(
  94. _: PumpManager,
  95. hasNewPumpEvents events: [NewPumpEvent],
  96. lastReconciliation _: Date?,
  97. completion: @escaping (_ error: Error?) -> Void
  98. ) {
  99. pumpHistoryStorage.storePumpEvents(events)
  100. lastEventDate = events.last?.date
  101. completion(nil)
  102. }
  103. func pumpManager(
  104. _: PumpManager,
  105. didReadReservoirValue units: Double,
  106. at date: Date,
  107. completion: @escaping (Result<
  108. (newValue: ReservoirValue, lastValue: ReservoirValue?, areStoredValuesContinuous: Bool),
  109. Error
  110. >) -> Void
  111. ) {
  112. debug(.deviceManager, "Reservoir Value \(units), at: \(date)")
  113. try? storage.save(Decimal(units), as: OpenAPS.Monitor.reservoir)
  114. let batteryPercent = Int((pumpManager?.status.pumpBatteryChargeRemaining ?? 1) * 100)
  115. let battery = Battery(percent: batteryPercent, voltage: nil, string: batteryPercent >= 10 ? .normal : .low)
  116. try? storage.save(battery, as: OpenAPS.Monitor.battery)
  117. completion(.success((
  118. newValue: Reservoir(startDate: Date(), unitVolume: units),
  119. lastValue: nil,
  120. areStoredValuesContinuous: true
  121. )))
  122. }
  123. func pumpManagerRecommendsLoop(_: PumpManager) {
  124. debug(.deviceManager, "Recomends loop")
  125. recommendsLoop.send()
  126. }
  127. func startDateToFilterNewPumpEvents(for _: PumpManager) -> Date {
  128. lastEventDate ?? Date().addingTimeInterval(-2.hours.timeInterval)
  129. }
  130. }
  131. // MARK: - DeviceManagerDelegate
  132. extension BaseDeviceDataManager: DeviceManagerDelegate {
  133. func scheduleNotification(
  134. for _: DeviceManager,
  135. identifier: String,
  136. content: UNNotificationContent,
  137. trigger: UNNotificationTrigger?
  138. ) {
  139. let request = UNNotificationRequest(
  140. identifier: identifier,
  141. content: content,
  142. trigger: trigger
  143. )
  144. DispatchQueue.main.async {
  145. UNUserNotificationCenter.current().add(request)
  146. }
  147. }
  148. func clearNotification(for _: DeviceManager, identifier: String) {
  149. DispatchQueue.main.async {
  150. UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier])
  151. }
  152. }
  153. func removeNotificationRequests(for _: DeviceManager, identifiers: [String]) {
  154. DispatchQueue.main.async {
  155. UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: identifiers)
  156. }
  157. }
  158. func deviceManager(
  159. _: DeviceManager,
  160. logEventForDeviceIdentifier _: String?,
  161. type _: DeviceLogEntryType,
  162. message _: String,
  163. completion _: ((Error?) -> Void)?
  164. ) {}
  165. }
  166. // MARK: - AlertPresenter
  167. extension BaseDeviceDataManager: AlertPresenter {
  168. func issueAlert(_: Alert) {}
  169. func retractAlert(identifier _: Alert.Identifier) {}
  170. }