Ivan Valkou 4 лет назад
Родитель
Сommit
54114446cb

+ 5 - 1
FreeAPS/Sources/APS/CGM/CGMType.swift

@@ -9,6 +9,7 @@ enum CGMType: String, JSON, CaseIterable, Identifiable {
     case dexcomG5
     case simulator
     case libreTransmitter
+    case enlite
 
     var displayName: String {
         switch self {
@@ -24,12 +25,15 @@ enum CGMType: String, JSON, CaseIterable, Identifiable {
             return NSLocalizedString("Glucose Simulator", comment: "Glucose Simulator CGM type")
         case .libreTransmitter:
             return NSLocalizedString("Libre Transmitter", comment: "Libre Transmitter type")
+        case .enlite:
+            return "Medtronic Enlite"
         }
     }
 
     var appURL: URL? {
         switch self {
-        case .nightscout:
+        case .enlite,
+             .nightscout:
             return nil
         case .xdrip:
             return URL(string: "xdripswift://")!

+ 59 - 1
FreeAPS/Sources/APS/DeviceDataManager.swift

@@ -1,3 +1,4 @@
+import Algorithms
 import Combine
 import Foundation
 import LoopKit
@@ -9,7 +10,7 @@ import SwiftDate
 import Swinject
 import UserNotifications
 
-protocol DeviceDataManager {
+protocol DeviceDataManager: GlucoseSource {
     var pumpManager: PumpManagerUI? { get set }
     var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> { get }
     var recommendsLoop: PassthroughSubject<Void, Never> { get }
@@ -154,6 +155,63 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable {
 
         return staticPumpManagersByIdentifier[managerIdentifier]
     }
+
+    // MARK: - GlucoseSource
+
+    @Persisted(key: "BaseDeviceDataManager.lastFetchGlucoseDate") private var lastFetchGlucoseDate: Date = .distantPast
+
+    func fetch() -> AnyPublisher<[BloodGlucose], Never> {
+        guard let medtrinic = pumpManager as? MinimedPumpManager else {
+            warning(.deviceManager, "Fetch minilink glucose failed: Pump is not Medtronic")
+            return Just([]).eraseToAnyPublisher()
+        }
+
+        guard lastFetchGlucoseDate.addingTimeInterval(4.5 * 60) < Date() else {
+            return Just([]).eraseToAnyPublisher()
+        }
+
+        return Future<[BloodGlucose], Error> { promise in
+            self.processQueue.async {
+                medtrinic.fetchNewDataIfNeeded { result in
+                    switch result {
+                    case .noData:
+                        promise(.success([]))
+                    case let .newData(glucose):
+                        let directions: [BloodGlucose.Direction?] = [nil]
+                            + glucose.windows(ofCount: 2).map { window -> BloodGlucose.Direction? in
+                                let firstValue = Int(window[0].quantity.doubleValue(for: .milligramsPerDeciliter))
+                                let secondValue = Int(window[1].quantity.doubleValue(for: .milligramsPerDeciliter))
+                                return .init(trend: secondValue - firstValue)
+                            }
+
+                        let results = glucose.enumerated().map { index, sample -> BloodGlucose in
+                            let value = Int(sample.quantity.doubleValue(for: .milligramsPerDeciliter))
+                            return BloodGlucose(
+                                _id: sample.syncIdentifier,
+                                sgv: value,
+                                direction: directions[index],
+                                date: Decimal(Int(sample.date.timeIntervalSince1970 * 1000)),
+                                dateString: sample.date,
+                                unfiltered: nil,
+                                filtered: nil,
+                                noise: nil,
+                                glucose: value,
+                                type: "sgv"
+                            )
+                        }
+                        self.lastFetchGlucoseDate = Date()
+                        promise(.success(results))
+                    case let .error(error):
+                        warning(.deviceManager, "Fetch minilink glucose failed", error: error)
+                        promise(.failure(error))
+                    }
+                }
+            }
+        }
+        .timeout(60, scheduler: processQueue, options: nil, customError: nil)
+        .replaceError(with: [])
+        .eraseToAnyPublisher()
+    }
 }
 
 extension BaseDeviceDataManager: PumpManagerDelegate {

+ 3 - 0
FreeAPS/Sources/APS/FetchGlucoseManager.swift

@@ -13,6 +13,7 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
     @Injected() var settingsManager: SettingsManager!
     @Injected() var libreTransmitter: LibreTransmitterSource!
     @Injected() var healthKitManager: HealthKitManager!
+    @Injected() var deviceDataManager: DeviceDataManager!
 
     private var lifetime = Lifetime()
     private let timer = DispatchTimer(timeInterval: 1.minutes.timeInterval)
@@ -42,6 +43,8 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
             glucoseSource = simulatorSource
         case .libreTransmitter:
             glucoseSource = libreTransmitter
+        case .enlite:
+            glucoseSource = deviceDataManager
         }
 
         if settingsManager.settings.cgm != .libreTransmitter {