Ivan Valkou 5 лет назад
Родитель
Сommit
06ab38b8b3

+ 0 - 6
FreeAPS/Resources/json/defaults/monitor/temp_basal.json

@@ -1,6 +0,0 @@
-{
-  "duration": 0,
-  "temp": "absolute",
-  "rate": 0
-}
-

+ 40 - 10
FreeAPS/Sources/APS/APSManager.swift

@@ -4,13 +4,14 @@ import LoopKitUI
 import Swinject
 import Swinject
 
 
 protocol APSManager {
 protocol APSManager {
-    func loop()
+    func determineBasal()
     func runTest()
     func runTest()
     func makeProfiles()
     func makeProfiles()
+    func fetchLastGlucose()
+    func autosense()
+    func autotune()
     var pumpManager: PumpManagerUI? { get set }
     var pumpManager: PumpManagerUI? { get set }
     var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> { get }
     var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> { get }
-    func fetchLastGlucose()
-    func makeMeal()
 }
 }
 
 
 final class BaseAPSManager: APSManager, Injectable {
 final class BaseAPSManager: APSManager, Injectable {
@@ -39,8 +40,12 @@ final class BaseAPSManager: APSManager, Injectable {
         openAPS = OpenAPS(storage: storage)
         openAPS = OpenAPS(storage: storage)
     }
     }
 
 
-    func loop() {
-        openAPS.loop()
+    func determineBasal() {
+        let now = Date()
+        guard let temp = currentTemp(date: now) else {
+            return
+        }
+        openAPS.determineBasal(currentTemp: temp, clock: now)
     }
     }
 
 
     func runTest() {
     func runTest() {
@@ -52,11 +57,6 @@ final class BaseAPSManager: APSManager, Injectable {
         openAPS.makeProfile(autotuned: true)
         openAPS.makeProfile(autotuned: true)
     }
     }
 
 
-    func makeMeal() {
-        openAPS.makeClock()
-        openAPS.makeMeal()
-    }
-
     func fetchLastGlucose() {
     func fetchLastGlucose() {
         if let urlString = keychain.getValue(String.self, forKey: NightscoutConfig.Config.urlKey),
         if let urlString = keychain.getValue(String.self, forKey: NightscoutConfig.Config.urlKey),
            let url = URL(string: urlString)
            let url = URL(string: urlString)
@@ -68,4 +68,34 @@ final class BaseAPSManager: APSManager, Injectable {
             }
             }
         }
         }
     }
     }
+
+    func autosense() {
+        openAPS.autosense()
+    }
+
+    func autotune() {
+        openAPS.autotune()
+    }
+
+    private func currentTemp(date: Date) -> TempBasal? {
+        guard let state = pumpManager?.status.basalDeliveryState else { return nil }
+        guard let lastTemp = try? storage.retrieve(OpenAPS.Monitor.tempBasal, as: TempBasal.self) else {
+            return TempBasal(duration: 0, rate: 0, temp: .absolute, updatedAt: date)
+        }
+
+        switch state {
+        case .active:
+            return TempBasal(duration: 0, rate: 0, temp: .absolute, updatedAt: date)
+        case let .tempBasal(dose):
+            let doseRate = Decimal(dose.unitsPerHour)
+            if doseRate == lastTemp.rate {
+                let durationMin = Int((date.timeIntervalSince1970 - lastTemp.updatedAt.timeIntervalSince1970) / 60)
+                return TempBasal(duration: durationMin, rate: lastTemp.rate, temp: .absolute, updatedAt: date)
+            } else {
+                let durationMin = Int((date.timeIntervalSince1970 - dose.startDate.timeIntervalSince1970) / 60)
+                return TempBasal(duration: durationMin, rate: doseRate, temp: .absolute, updatedAt: date)
+            }
+        default: return nil
+        }
+    }
 }
 }

+ 96 - 108
FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift

@@ -11,60 +11,21 @@ final class OpenAPS {
         self.storage = storage
         self.storage = storage
     }
     }
 
 
-    func loop() {
+    func determineBasal(currentTemp: TempBasal, clock: Date = Date()) {
         processQueue.async {
         processQueue.async {
-            // status
-            // check it before
-
-            // profile
-            let preferences = self.loadFileFromStorage(name: Settings.preferences)
-            let pumpSettings = self.loadFileFromStorage(name: Settings.settings)
-            let bgTargets = self.loadFileFromStorage(name: Settings.bgTargets)
-            let basalProfile = self.loadFileFromStorage(name: Settings.basalProfile)
-            let isf = self.loadFileFromStorage(name: Settings.insulinSensitivities)
-            let cr = self.loadFileFromStorage(name: Settings.carbRatios)
-            let tempTargets = self.loadFileFromStorage(name: Settings.tempTargets)
-            let model = self.loadFileFromStorage(name: Settings.model)
-            let autotune = self.loadFileFromStorage(name: Settings.autotune)
-
-            let pumpProfile = self.makeProfile(
-                preferences: preferences,
-                pumpSettings: pumpSettings,
-                bgTargets: bgTargets,
-                basalProfile: basalProfile,
-                isf: isf,
-                carbRatio: cr,
-                tempTargets: tempTargets,
-                model: model,
-                autotune: RawJSON.null
-            )
-
-            let profile = self.makeProfile(
-                preferences: preferences,
-                pumpSettings: pumpSettings,
-                bgTargets: bgTargets,
-                basalProfile: basalProfile,
-                isf: isf,
-                carbRatio: cr,
-                tempTargets: tempTargets,
-                model: model,
-                autotune: autotune.isEmpty ? .null : autotune
-            )
-
-            try? self.storage.save(pumpProfile, as: Settings.pumpProfile)
-            try? self.storage.save(profile, as: Settings.profile)
-
             // clock
             // clock
-            try? self.storage.save(Date(), as: Monitor.clock)
+            try? self.storage.save(clock, as: Monitor.clock)
 
 
             // temp_basal
             // temp_basal
-            let tempBasal = self.loadFileFromStorage(name: Monitor.tempBasal)
+            let tempBasal = currentTemp.rawJSON
+            try? self.storage.save(tempBasal, as: Monitor.tempBasal)
 
 
             // meal
             // meal
             let pumpHistory = self.loadFileFromStorage(name: OpenAPS.Monitor.pumpHistory)
             let pumpHistory = self.loadFileFromStorage(name: OpenAPS.Monitor.pumpHistory)
             let carbs = self.loadFileFromStorage(name: Monitor.carbHistory)
             let carbs = self.loadFileFromStorage(name: Monitor.carbHistory)
             let glucose = self.loadFileFromStorage(name: Monitor.glucose)
             let glucose = self.loadFileFromStorage(name: Monitor.glucose)
-            let clock = self.loadFileFromStorage(name: Monitor.clock)
+            let profile = self.loadFileFromStorage(name: Settings.profile)
+            let basalProfile = self.loadFileFromStorage(name: Settings.basalProfile)
 
 
             let meal = self.meal(
             let meal = self.meal(
                 pumphistory: pumpHistory,
                 pumphistory: pumpHistory,
@@ -107,6 +68,95 @@ final class OpenAPS {
         }
         }
     }
     }
 
 
+    func autosense() {
+        processQueue.async {
+            let pumpHistory = self.loadFileFromStorage(name: OpenAPS.Monitor.pumpHistory)
+            let carbs = self.loadFileFromStorage(name: Monitor.carbHistory)
+            let glucose = self.loadFileFromStorage(name: Monitor.glucose)
+            let profile = self.loadFileFromStorage(name: Settings.profile)
+            let basalProfile = self.loadFileFromStorage(name: Settings.basalProfile)
+
+            let autosensResult = self.autosense(
+                pumpHistory: pumpHistory,
+                profile: profile,
+                carbs: carbs,
+                glucose: glucose,
+                basalprofile: basalProfile,
+                temptargets: RawJSON.null
+            )
+
+            print("AUTOSENS: \(autosensResult)")
+            try? self.storage.save(autosensResult, as: Settings.autosense)
+        }
+    }
+
+    func autotune(categorizeUamAsBasal: Bool = false, tuneInsulinCurve: Bool = false) {
+        processQueue.async {
+            let pumpHistory = self.loadFileFromStorage(name: OpenAPS.Monitor.pumpHistory)
+            let glucose = self.loadFileFromStorage(name: Monitor.glucose)
+            let profile = self.loadFileFromStorage(name: Settings.profile)
+
+            let autotunePreppedGlucose = self.autotunePrepare(
+                pumphistory: pumpHistory,
+                profile: profile,
+                glucose: glucose,
+                pumpprofile: profile,
+                categorizeUamAsBasal: categorizeUamAsBasal,
+                tuneInsulinCurve: tuneInsulinCurve
+            )
+            print("AUTOTUNE PREP: \(autotunePreppedGlucose)")
+
+            let previousAutotune = try? self.storage.retrieve(Settings.autotune, as: RawJSON.self)
+
+            let autotuneResult = self.autotuneRun(
+                autotunePreparedData: autotunePreppedGlucose,
+                previousAutotuneResult: previousAutotune ?? profile,
+                pumpProfile: profile
+            )
+
+            try? self.storage.save(autotuneResult, as: Settings.autotune)
+
+            print("AUTOTUNE RESULT: \(autotuneResult)")
+        }
+    }
+
+    func makeProfile(autotuned: Bool) {
+        processQueue.async {
+            print("MAKE PROFILE autotuned \(autotuned)")
+            let preferences = self.loadFileFromStorage(name: Settings.preferences)
+            let pumpSettings = self.loadFileFromStorage(name: Settings.settings)
+            let bgTargets = self.loadFileFromStorage(name: Settings.bgTargets)
+            let basalProfile = self.loadFileFromStorage(name: Settings.basalProfile)
+            let isf = self.loadFileFromStorage(name: Settings.insulinSensitivities)
+            let cr = self.loadFileFromStorage(name: Settings.carbRatios)
+            let tempTargets = self.loadFileFromStorage(name: Settings.tempTargets)
+            let model = self.loadFileFromStorage(name: Settings.model)
+            let autotune = self.loadFileFromStorage(name: Settings.autotune)
+
+            let aututune = autotuned ? (autotune.isEmpty ? .null : autotune) : .null
+
+            let profile = self.makeProfile(
+                preferences: preferences,
+                pumpSettings: pumpSettings,
+                bgTargets: bgTargets,
+                basalProfile: basalProfile,
+                isf: isf,
+                carbRatio: cr,
+                tempTargets: tempTargets,
+                model: model,
+                autotune: aututune
+            )
+
+            print("PROFILE RESULT \n\(profile)")
+
+            if autotuned {
+                try? self.storage.save(profile, as: Settings.profile)
+            } else {
+                try? self.storage.save(profile, as: Settings.pumpProfile)
+            }
+        }
+    }
+
     func test() {
     func test() {
         processQueue.async {
         processQueue.async {
             let now = Date()
             let now = Date()
@@ -194,69 +244,7 @@ final class OpenAPS {
         }
         }
     }
     }
 
 
-    func makeClock() {
-        processQueue.async {
-            try? self.storage.save(Date(), as: Monitor.clock)
-        }
-    }
-
-    func makeMeal() {
-        processQueue.async {
-            let pumphistory = self.loadFileFromStorage(name: Monitor.pumpHistory)
-            let profile = self.loadFileFromStorage(name: Settings.profile)
-            let basalProfile = self.loadFileFromStorage(name: Settings.basalProfile)
-            let clock = self.loadFileFromStorage(name: Monitor.clock)
-            let carbs = self.loadFileFromStorage(name: Monitor.carbHistory)
-            let glucose = self.loadFileFromStorage(name: Monitor.glucose)
-
-            let mealResult = self.meal(
-                pumphistory: pumphistory,
-                profile: profile,
-                basalProfile: basalProfile,
-                clock: clock,
-                carbs: carbs,
-                glucose: glucose
-            )
-
-            print("MEAL: \(mealResult)")
-            try? self.storage.save(mealResult, as: Monitor.meal)
-        }
-    }
-
-    func makeProfile(autotuned: Bool) {
-        processQueue.async {
-            print("MAKE PROFILE autotuned \(autotuned)")
-            let preferences = self.loadFileFromStorage(name: Settings.preferences)
-            let pumpSettings = self.loadFileFromStorage(name: Settings.settings)
-            let bgTargets = self.loadFileFromStorage(name: Settings.bgTargets)
-            let basalProfile = self.loadFileFromStorage(name: Settings.basalProfile)
-            let isf = self.loadFileFromStorage(name: Settings.insulinSensitivities)
-            let cr = self.loadFileFromStorage(name: Settings.carbRatios)
-            let tempTargets = self.loadFileFromStorage(name: Settings.tempTargets)
-            let model = self.loadFileFromStorage(name: Settings.model)
-            let autotune = self.loadFileFromStorage(name: Settings.autotune)
-
-            let profile = self.makeProfile(
-                preferences: preferences,
-                pumpSettings: pumpSettings,
-                bgTargets: bgTargets,
-                basalProfile: basalProfile,
-                isf: isf,
-                carbRatio: cr,
-                tempTargets: tempTargets,
-                model: model,
-                autotune: autotuned ? autotune : .null
-            )
-
-            print("PROFILE RESULT \n\(profile)")
-
-            if autotuned {
-                try? self.storage.save(profile, as: Settings.profile)
-            } else {
-                try? self.storage.save(profile, as: Settings.pumpProfile)
-            }
-        }
-    }
+    // MARK: - Private
 
 
     private func iob(pumphistory: JSON, profile: JSON, clock: JSON, autosens: JSON) -> RawJSON {
     private func iob(pumphistory: JSON, profile: JSON, clock: JSON, autosens: JSON) -> RawJSON {
         dispatchPrecondition(condition: .onQueue(processQueue))
         dispatchPrecondition(condition: .onQueue(processQueue))

+ 1 - 1
FreeAPS/Sources/APS/Storage/GlucoseStorage.swift

@@ -17,7 +17,7 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
     func storeGlucose(_ glucose: [BloodGlucose]) {
     func storeGlucose(_ glucose: [BloodGlucose]) {
         processQueue.async {
         processQueue.async {
             try? self.storage.transaction { storage in
             try? self.storage.transaction { storage in
-                try storage.append(glucose, to: OpenAPS.Monitor.glucose, uniqBy: \.date)
+                try storage.append(glucose, to: OpenAPS.Monitor.glucose, uniqBy: \.dateString)
                 let uniqEvents = try storage.retrieve(OpenAPS.Monitor.glucose, as: [BloodGlucose].self)
                 let uniqEvents = try storage.retrieve(OpenAPS.Monitor.glucose, as: [BloodGlucose].self)
                     .filter { $0.dateString.addingTimeInterval(1.days.timeInterval) > Date() }
                     .filter { $0.dateString.addingTimeInterval(1.days.timeInterval) > Date() }
                     .sorted { $0.dateString > $1.dateString }
                     .sorted { $0.dateString > $1.dateString }

+ 1 - 1
FreeAPS/Sources/Modules/Home/HomeViewModel.swift

@@ -22,7 +22,7 @@ extension Home {
         }
         }
 
 
         func runLoop() {
         func runLoop() {
-            apsManager.loop()
+            apsManager.determineBasal()
         }
         }
     }
     }
 }
 }