Jelajahi Sumber

NightscoutStatus model

Ivan Valkou 5 tahun lalu
induk
melakukan
e81745494b

+ 5 - 1
FreeAPS.xcodeproj/project.pbxproj

@@ -115,6 +115,7 @@
 		3883581C25EE79BB00E024B2 /* DecimalTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3883581B25EE79BB00E024B2 /* DecimalTextField.swift */; };
 		3883583425EEB38000E024B2 /* PumpSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3883583325EEB38000E024B2 /* PumpSettings.swift */; };
 		388358C825EEF6D200E024B2 /* BasalProfileEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388358C725EEF6D200E024B2 /* BasalProfileEntry.swift */; };
+		38887CCE25F5725200944304 /* IOBEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38887CCD25F5725200944304 /* IOBEntry.swift */; };
 		388E595C25AD948C0019842D /* FreeAPSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E595B25AD948C0019842D /* FreeAPSApp.swift */; };
 		388E596025AD948E0019842D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 388E595F25AD948E0019842D /* Assets.xcassets */; };
 		388E596C25AD95110019842D /* OpenAPS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E596B25AD95110019842D /* OpenAPS.swift */; };
@@ -719,6 +720,7 @@
 		3883581B25EE79BB00E024B2 /* DecimalTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalTextField.swift; sourceTree = "<group>"; };
 		3883583325EEB38000E024B2 /* PumpSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpSettings.swift; sourceTree = "<group>"; };
 		388358C725EEF6D200E024B2 /* BasalProfileEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasalProfileEntry.swift; sourceTree = "<group>"; };
+		38887CCD25F5725200944304 /* IOBEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBEntry.swift; sourceTree = "<group>"; };
 		388E595825AD948C0019842D /* FreeAPS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FreeAPS.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		388E595B25AD948C0019842D /* FreeAPSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FreeAPSApp.swift; sourceTree = "<group>"; };
 		388E595F25AD948E0019842D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -1302,16 +1304,17 @@
 				38AEE73C25F0200C0013F05B /* FreeAPSSettings.swift */,
 				383948D925CD64D500E91849 /* Glucose.swift */,
 				382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */,
+				38887CCD25F5725200944304 /* IOBEntry.swift */,
 				385CEA8125F23DFD002D6D5B /* NightscoutStatus.swift */,
 				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 				38A13D3125E28B4B00EAA382 /* PumpHistoryEvent.swift */,
 				3883583325EEB38000E024B2 /* PumpSettings.swift */,
+				38E989DC25F5021400C0CED0 /* PumpStatus.swift */,
 				38BF021C25E7E3AF00579895 /* Reservoir.swift */,
 				3871F38625ED661C0013ECB5 /* Suggestion.swift */,
 				38A0364125ED069400FCBB52 /* TempBasal.swift */,
 				3871F39B25ED892B0013ECB5 /* TempTarget.swift */,
 				3811DE8E25C9D80400A708ED /* User.swift */,
-				38E989DC25F5021400C0CED0 /* PumpStatus.swift */,
 			);
 			path = Models;
 			sourceTree = "<group>";
@@ -2270,6 +2273,7 @@
 				FA630397F76B582C8D8681A7 /* BasalProfileEditorProvider.swift in Sources */,
 				63E890B4D951EAA91C071D5C /* BasalProfileEditorViewModel.swift in Sources */,
 				385CEA8225F23DFD002D6D5B /* NightscoutStatus.swift in Sources */,
+				38887CCE25F5725200944304 /* IOBEntry.swift in Sources */,
 				38E98A2425F52C9300C0CED0 /* Logger.swift in Sources */,
 				CA370FC152BC98B3D1832968 /* BasalProfileEditorRootView.swift in Sources */,
 				F215CAB49BA4B5A01C3BC6B6 /* ISFEditorBuilder.swift in Sources */,

+ 13 - 13
FreeAPS/Sources/APS/APSManager.swift

@@ -161,7 +161,7 @@ final class BaseAPSManager: APSManager, Injectable {
             switch result {
             case .success:
                 debug(.apsManager, "Temp Basal succeeded")
-                let temp = TempBasal(duration: Int(duration / 60), rate: Decimal(rate), temp: .absolute, updatedAt: Date())
+                let temp = TempBasal(duration: Int(duration / 60), rate: Decimal(rate), temp: .absolute, timestamp: Date())
                 try? self.storage.save(temp, as: OpenAPS.Monitor.tempBasal)
             case let .failure(error):
                 debug(.apsManager, "Temp Basal failed with error: \(error.localizedDescription)")
@@ -170,11 +170,11 @@ final class BaseAPSManager: APSManager, Injectable {
     }
 
     func autosense() {
-        _ = openAPS.autosense()
+        openAPS.autosense().sink {}.store(in: &lifetime)
     }
 
     func autotune() {
-        _ = openAPS.autotune()
+        openAPS.autotune().sink {}.store(in: &lifetime)
     }
 
     private func enactAnnouncement(_ announcement: Announcement) {
@@ -243,21 +243,21 @@ final class BaseAPSManager: APSManager, Injectable {
     private func currentTemp(date: Date) -> TempBasal {
         let defaultTemp = { () -> TempBasal in
             guard let temp = try? storage.retrieve(OpenAPS.Monitor.tempBasal, as: TempBasal.self) else {
-                return TempBasal(duration: 0, rate: 0, temp: .absolute, updatedAt: Date())
+                return TempBasal(duration: 0, rate: 0, temp: .absolute, timestamp: Date())
             }
-            let delta = Int((date.timeIntervalSince1970 - temp.updatedAt.timeIntervalSince1970) / 60)
+            let delta = Int((date.timeIntervalSince1970 - temp.timestamp.timeIntervalSince1970) / 60)
             let duration = max(0, temp.duration - delta)
-            return TempBasal(duration: duration, rate: temp.rate, temp: .absolute, updatedAt: date)
+            return TempBasal(duration: duration, rate: temp.rate, temp: .absolute, timestamp: date)
         }()
 
         guard let state = pumpManager?.status.basalDeliveryState else { return defaultTemp }
         switch state {
         case .active:
-            return TempBasal(duration: 0, rate: 0, temp: .absolute, updatedAt: date)
+            return TempBasal(duration: 0, rate: 0, temp: .absolute, timestamp: date)
         case let .tempBasal(dose):
             let rate = Decimal(dose.unitsPerHour)
             let durationMin = max(0, Int((dose.endDate.timeIntervalSince1970 - date.timeIntervalSince1970) / 60))
-            return TempBasal(duration: durationMin, rate: rate, temp: .absolute, updatedAt: date)
+            return TempBasal(duration: durationMin, rate: rate, temp: .absolute, timestamp: date)
         default:
             return defaultTemp
         }
@@ -283,7 +283,7 @@ final class BaseAPSManager: APSManager, Injectable {
                     .eraseToAnyPublisher()
             }
             return pump.enactTempBasal(unitsPerHour: Double(rate), for: TimeInterval(duration * 60)).map { _ in
-                let temp = TempBasal(duration: duration, rate: rate, temp: .absolute, updatedAt: Date())
+                let temp = TempBasal(duration: duration, rate: rate, temp: .absolute, timestamp: Date())
                 try? self.storage.save(temp, as: OpenAPS.Monitor.tempBasal)
                 return ()
             }
@@ -307,9 +307,9 @@ final class BaseAPSManager: APSManager, Injectable {
                 }
             } receiveValue: { [weak self] in
                 debug(.apsManager, "Loop succeeded")
-                if let rawSuggested = self?.storage.retrieveRaw(OpenAPS.Enact.suggested) {
-                    try? self?.storage.save(rawSuggested, as: OpenAPS.Enact.enacted)
-                }
+                var enacted = suggested
+                enacted.timestamp = Date()
+                try? self?.storage.save(enacted, as: OpenAPS.Enact.enacted)
             }.store(in: &lifetime)
     }
 }
@@ -377,6 +377,6 @@ extension PumpManagerStatus {
         let bolusing = bolusState != .noBolus
         let suspended = basalDeliveryState?.isSuspended ?? true
         let type = suspended ? StatusType.suspended : (bolusing ? .bolusing : .normal)
-        return PumpStatus(status: type, bolusing: bolusing, suspended: suspended)
+        return PumpStatus(status: type, bolusing: bolusing, suspended: suspended, timestamp: Date())
     }
 }

+ 4 - 2
FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift

@@ -66,8 +66,10 @@ final class OpenAPS {
                 )
                 debug(.openAPS, "SUGGESTED: \(suggested)")
 
-                try? self.storage.save(suggested, as: Enact.suggested)
-
+                if var suggestion = Suggestion(from: suggested) {
+                    suggestion.timestamp = clock
+                    try? self.storage.save(suggestion, as: Enact.suggested)
+                }
                 promise(.success(()))
             }
         }

+ 2 - 1
FreeAPS/Sources/Models/Battery.swift

@@ -1,7 +1,8 @@
 import Foundation
 
 struct Battery: JSON {
-    let percent: Int
+    let percent: Int?
+    let voltage: Decimal?
     let string: BatteryState
 }
 

+ 32 - 0
FreeAPS/Sources/Models/IOBEntry.swift

@@ -0,0 +1,32 @@
+import Foundation
+
+struct IOBEntry: JSON {
+    let iob: Decimal
+    let activity: Decimal
+    let basaliob: Decimal
+    let bolusiob: Decimal
+    let netbasalinsulin: Decimal
+    let bolusinulin: Decimal
+    let iobWithZeroTemp: WithZeroTemp
+    let lastBolusTime: UInt64
+    let lastTemp: LastTemp
+    var timestamp: Date?
+
+    struct WithZeroTemp: JSON {
+        let iob: Decimal
+        let activity: Decimal
+        let basaliob: Decimal
+        let bolusiob: Decimal
+        let netbasalinsulin: Decimal
+        let bolusinulin: Decimal
+        let time: Date
+    }
+
+    struct LastTemp: JSON {
+        let rate: Decimal
+        let timestamp: Date
+        let started_at: Date
+        let date: UInt64
+        let duration: Decimal
+    }
+}

+ 26 - 1
FreeAPS/Sources/Models/NightscoutStatus.swift

@@ -1,3 +1,28 @@
 import Foundation
 
-struct NightscoutStatus: JSON {}
+struct NightscoutStatus: JSON {
+    let device: String
+    let openaps: OpenAPSStatus
+    let pump: NSPumpStatus
+    let preferences: Preferences
+    let uploader: Uploader
+}
+
+struct OpenAPSStatus: JSON {
+    let iob: IOBEntry
+    let suggested: Suggestion
+    let enacted: Suggestion
+    let version: String
+}
+
+struct NSPumpStatus: JSON {
+    let clock: Date
+    let battery: Battery
+    let reservoir: Decimal
+    let status: PumpStatus
+}
+
+struct Uploader: JSON {
+    let batteryVoltage: Decimal?
+    let battery: Int
+}

+ 1 - 0
FreeAPS/Sources/Models/Preferences.swift

@@ -40,6 +40,7 @@ struct Preferences: JSON {
     var carbsReqThreshold: Decimal = 1.0
     var noisyCGMTargetMultiplier: Decimal = 1.3
     var suspendZerosIOB: Bool = true
+    var timestamp: Date?
 }
 
 extension Preferences {

+ 3 - 0
FreeAPS/Sources/Models/PumpStatus.swift

@@ -1,7 +1,10 @@
+import Foundation
+
 struct PumpStatus: JSON {
     let status: StatusType
     let bolusing: Bool
     let suspended: Bool
+    let timestamp: Date?
 }
 
 enum StatusType: String, JSON {

+ 15 - 1
FreeAPS/Sources/Models/Suggestion.swift

@@ -10,7 +10,14 @@ struct Suggestion: JSON {
     let duration: Int?
     let iob: Decimal?
     let cob: Decimal?
-    let predictions: Predictions?
+    var predictions: Predictions?
+    let deliverAt: Date?
+    let carbsReq: Decimal?
+    let temp: TempType?
+    let bg: Int?
+    let tick: String?
+    let reservoir: Decimal?
+    var timestamp: Date?
 }
 
 struct Predictions: JSON {
@@ -32,6 +39,13 @@ extension Suggestion {
         case iob = "IOB"
         case cob = "COB"
         case predictions = "predBGs"
+        case deliverAt
+        case carbsReq
+        case temp
+        case bg
+        case tick
+        case reservoir
+        case timestamp
     }
 }
 

+ 1 - 1
FreeAPS/Sources/Models/TempBasal.swift

@@ -4,5 +4,5 @@ struct TempBasal: JSON {
     let duration: Int
     let rate: Decimal
     let temp: TempType
-    let updatedAt: Date
+    let timestamp: Date
 }

+ 2 - 2
FreeAPS/Sources/Modules/ManualTempBasal/View/ManualTempBasalRootView.swift

@@ -34,10 +34,10 @@ extension ManualTempBasal {
                 }
 
                 Section {
-                    Button { viewModel.cancel() }
-                    label: { Text("Cancel Temp Basal") }
                     Button { viewModel.enact() }
                     label: { Text("Enact") }
+                    Button { viewModel.cancel() }
+                    label: { Text("Cancel Temp Basal") }
                 }
             }
             .navigationTitle("Manual Temp Basal")

+ 3 - 1
FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorProvider.swift

@@ -11,7 +11,9 @@ extension PreferencesEditor {
 
         func savePreferences(_ preferences: Preferences) {
             processQueue.async {
-                try? self.storage.save(preferences, as: OpenAPS.Settings.preferences)
+                var prefs = preferences
+                prefs.timestamp = Date()
+                try? self.storage.save(prefs, as: OpenAPS.Settings.preferences)
             }
         }
     }

+ 2 - 0
FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift

@@ -50,6 +50,8 @@ extension Settings {
                     }
 
                     Group {
+                        Text("IOB").chevronCell()
+                            .navigationLink(to: .configEditor(file: OpenAPS.Monitor.iob), from: self)
                         Text("Pump profile").chevronCell()
                             .navigationLink(to: .configEditor(file: OpenAPS.Settings.pumpProfile), from: self)
                         Text("Profile").chevronCell()

+ 4 - 3
FreeAPS/Sources/Services/Network/NightscoutManager.swift

@@ -90,11 +90,12 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
             }.eraseToAnyPublisher()
     }
 
-    func upload() {}
+    func upload() {
+        uploadStatus()
+        uploadTreatments()
+    }
 
     private func uploadStatus() {}
 
     private func uploadTreatments() {}
-
-    private func uploadPumphistory() {}
 }