Jelajahi Sumber

check last loop date

Ivan Valkou 5 tahun lalu
induk
melakukan
de6f65e772

+ 17 - 3
FreeAPS/Sources/APS/APSManager.swift

@@ -12,8 +12,10 @@ protocol APSManager {
     var pumpManager: PumpManagerUI? { get set }
     var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> { get }
     var isLooping: CurrentValueSubject<Bool, Never> { get }
+    var lastLoopDate: PassthroughSubject<Date, Never> { get }
     func enactTempBasal(rate: Double, duration: TimeInterval)
     func makeProfiles() -> AnyPublisher<Bool, Never>
+    func determineBasal() -> AnyPublisher<Bool, Never>
 }
 
 final class BaseAPSManager: APSManager, Injectable {
@@ -40,6 +42,7 @@ final class BaseAPSManager: APSManager, Injectable {
     }
 
     let isLooping = CurrentValueSubject<Bool, Never>(false)
+    let lastLoopDate = PassthroughSubject<Date, Never>()
 
     var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> {
         deviceDataManager.pumpDisplayState
@@ -92,7 +95,7 @@ final class BaseAPSManager: APSManager, Injectable {
             nightscout.fetchCarbs(),
             nightscout.fetchTempTargets()
         )
-        .flatMap { _ in self.daylyAutotune() }
+        .flatMap { _ in self.dailyAutotune() }
         .flatMap { _ in self.autosens() }
         .flatMap { _ in self.determineBasal() }
         .sink { _ in } receiveValue: { [weak self] ok in
@@ -104,6 +107,7 @@ final class BaseAPSManager: APSManager, Injectable {
                     self.enactSuggested()
                 } else {
                     self.isLooping.send(false)
+                    self.lastLoopDate.send(Date())
                 }
             } else {
                 self.isLooping.send(false)
@@ -134,7 +138,7 @@ final class BaseAPSManager: APSManager, Injectable {
         return Just(true).eraseToAnyPublisher()
     }
 
-    private func determineBasal() -> AnyPublisher<Bool, Never> {
+    func determineBasal() -> AnyPublisher<Bool, Never> {
         guard let glucose = try? storage.retrieve(OpenAPS.Monitor.glucose, as: [BloodGlucose].self), glucose.count >= 36 else {
             debug(.apsManager, "Not enough glucose data")
             return Just(false).eraseToAnyPublisher()
@@ -198,6 +202,7 @@ final class BaseAPSManager: APSManager, Injectable {
             switch result {
             case .success:
                 debug(.apsManager, "Bolus succeeded")
+                _ = self.determineBasal()
             case let .failure(error):
                 debug(.apsManager, "Bolus failed with error: \(error.localizedDescription)")
             }
@@ -220,7 +225,7 @@ final class BaseAPSManager: APSManager, Injectable {
         }
     }
 
-    func daylyAutotune() -> AnyPublisher<Bool, Never> {
+    func dailyAutotune() -> AnyPublisher<Bool, Never> {
         guard settings.useAutotune else {
             return Just(false).eraseToAnyPublisher()
         }
@@ -328,11 +333,19 @@ final class BaseAPSManager: APSManager, Injectable {
     private func enactSuggested() {
         guard let suggested = try? storage.retrieve(OpenAPS.Enact.suggested, as: Suggestion.self) else {
             isLooping.send(false)
+            debug(.apsManager, "Suggestion not found")
+            return
+        }
+
+        guard Date().timeIntervalSince(suggested.deliverAt ?? .distantPast) < Config.eхpirationInterval else {
+            isLooping.send(false)
+            debug(.apsManager, "Suggestion expired")
             return
         }
 
         guard let pump = pumpManager, verifyStatus() else {
             isLooping.send(false)
+            debug(.apsManager, "Invalid pump status")
             return
         }
 
@@ -370,6 +383,7 @@ final class BaseAPSManager: APSManager, Injectable {
                 self?.isLooping.send(false)
             } receiveValue: {
                 debug(.apsManager, "Loop succeeded")
+                self.lastLoopDate.send(Date())
             }.store(in: &lifetime)
     }
 

+ 1 - 0
FreeAPS/Sources/Config/Config.swift

@@ -5,4 +5,5 @@ enum Config {
     static let treatWarningsAsErrors = true
     static let withSignPosts = false
     static let loopInterval = 5.minutes.timeInterval
+    static let eхpirationInterval = 10.minutes.timeInterval
 }

+ 2 - 0
FreeAPS/Sources/Modules/AddCarbs/AddCarbsViewModel.swift

@@ -3,6 +3,7 @@ import SwiftUI
 extension AddCarbs {
     class ViewModel<Provider>: BaseViewModel<Provider>, ObservableObject where Provider: AddCarbsProvider {
         @Injected() var carbsStorage: CarbsStorage!
+        @Injected() var apsManager: APSManager!
         @Published var carbs: Decimal = 0
         @Published var date = Date()
 
@@ -12,6 +13,7 @@ extension AddCarbs {
             carbsStorage.storeCarbs([
                 CarbsEntry(createdAt: date, carbs: carbs, enteredBy: CarbsEntry.manual)
             ])
+            apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
             showModal(for: nil)
         }
     }

+ 4 - 0
FreeAPS/Sources/Modules/AddTempTarget/AddTempTargetViewModel.swift

@@ -4,6 +4,7 @@ extension AddTempTarget {
     class ViewModel<Provider>: BaseViewModel<Provider>, ObservableObject where Provider: AddTempTargetProvider {
         @Injected() private var storage: TempTargetsStorage!
         @Injected() private var settingsManager: SettingsManager!
+        @Injected() var apsManager: APSManager!
 
         @Published var low: Decimal = 0
         @Published var high: Decimal = 0
@@ -39,6 +40,7 @@ extension AddTempTarget {
                 enteredBy: TempTarget.manual
             )
             storage.storeTempTargets([entry])
+            apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
 
             showModal(for: nil)
         }
@@ -53,6 +55,7 @@ extension AddTempTarget {
                 enteredBy: TempTarget.manual
             )
             storage.storeTempTargets([entry])
+            apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
 
             showModal(for: nil)
         }
@@ -85,6 +88,7 @@ extension AddTempTarget {
             if var preset = presets.first(where: { $0.id == id }) {
                 preset.createdAt = Date()
                 storage.storeTempTargets([preset])
+                apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
                 showModal(for: nil)
             }
         }

+ 14 - 0
FreeAPS/Sources/Modules/Home/HomeViewModel.swift

@@ -24,6 +24,7 @@ extension Home {
         @Published var closedLoop = false
         @Published var isLooping = false
         @Published var statusTitle = ""
+        @Published var lastLoopDate: Date = .distantPast
 
         @Published var allowManualTemp = false
         private(set) var units: GlucoseUnits = .mmolL
@@ -44,6 +45,14 @@ extension Home {
             closedLoop = settingsManager.settings.closedLoop
             setStatusTitle()
 
+            if closedLoop,
+               enactedSuggestion?.deliverAt == suggestion?.deliverAt || (suggestion?.rate == nil && suggestion?.units == nil)
+            {
+                lastLoopDate = enactedSuggestion?.timestamp ?? .distantPast
+            } else {
+                lastLoopDate = suggestion?.timestamp ?? .distantPast
+            }
+
             broadcaster.register(GlucoseObserver.self, observer: self)
             broadcaster.register(SuggestionObserver.self, observer: self)
             broadcaster.register(SettingsObserver.self, observer: self)
@@ -61,6 +70,11 @@ extension Home {
                 .receive(on: DispatchQueue.main)
                 .assign(to: \.isLooping, on: self)
                 .store(in: &lifetime)
+
+            apsManager.lastLoopDate
+                .receive(on: DispatchQueue.main)
+                .assign(to: \.lastLoopDate, on: self)
+                .store(in: &lifetime)
         }
 
         func addCarbs() {

+ 5 - 4
FreeAPS/Sources/Modules/Home/View/Header/LoopView.swift

@@ -12,6 +12,7 @@ struct LoopView: View {
     @Binding var closedLoop: Bool
     @Binding var timerDate: Date
     @Binding var isLooping: Bool
+    @Binding var lastLoopDate: Date
 
     private var dateFormatter: DateFormatter {
         let formatter = DateFormatter()
@@ -35,8 +36,8 @@ struct LoopView: View {
             Spacer()
             if isLooping {
                 Text("looping").font(.caption2)
-            } else if let date = actualSuggestion?.timestamp {
-                Text("\(Int((timerDate.timeIntervalSince(date) - Config.lag) / 60) + 1) min").font(.caption)
+            } else if actualSuggestion?.timestamp != nil {
+                Text("\(Int((timerDate.timeIntervalSince(lastLoopDate) - Config.lag) / 60) + 1) min").font(.caption)
             } else {
                 Text("--").font(.caption)
             }
@@ -44,10 +45,10 @@ struct LoopView: View {
     }
 
     private var color: Color {
-        guard let lastDate = actualSuggestion?.timestamp else {
+        guard actualSuggestion?.timestamp != nil else {
             return Color(UIColor(named: "LoopGray")!)
         }
-        let delta = timerDate.timeIntervalSince(lastDate) - Config.lag
+        let delta = timerDate.timeIntervalSince(lastLoopDate) - Config.lag
 
         if delta <= 5.minutes.timeInterval {
             return Color(UIColor(named: "LoopGreen")!)

+ 2 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -39,7 +39,8 @@ extension Home {
                     enactedSuggestion: $viewModel.enactedSuggestion,
                     closedLoop: $viewModel.closedLoop,
                     timerDate: $viewModel.timerDate,
-                    isLooping: $viewModel.isLooping
+                    isLooping: $viewModel.isLooping,
+                    lastLoopDate: $viewModel.lastLoopDate
                 ).onTapGesture {
                     isStatusPopupPresented = true
                 }.onLongPressGesture {