Просмотр исходного кода

Add the ability to automatically store the current profile on Nightscout (#177)

* Upload profile to nightscout upon settings change (triggered by exiting the menu)

* remove json debugging logic.

* Remove debug comments

* Revert unintended change and extraneous comment

* make units lower case and use mg/dl instead of mgdl

* Use the canonical nightscout representation for units, see https://github.com/nightscout/cgm-remote-monitor/search?q=settings.units

* Convert seconds to milliseconds for Nightscout profile

* Fix calculation of 5m-carb-impact to carbs_hr absorption rate, according to https://openaps.readthedocs.io/en/latest/docs/While%20You%20Wait%20For%20Gear/preferences-and-safety-settings.html#min-5m-carbimpact

* Make carbs_hr work for mmol and round it to one decimal place.

* Make carbs_hr an Int as expected by Nightsocut.
Jon B.M 3 лет назад
Родитель
Сommit
b9b3b80746
1 измененных файлов с 116 добавлено и 0 удалено
  1. 116 0
      FreeAPS/Sources/Services/Network/NightscoutManager.swift

+ 116 - 0
FreeAPS/Sources/Services/Network/NightscoutManager.swift

@@ -383,6 +383,122 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
         }
     }
 
+    func uploadProfile() {
+        // These should be modified anyways and not the defaults
+        guard let sensitivities = storage.retrieve(OpenAPS.Settings.insulinSensitivities, as: InsulinSensitivities.self),
+              let basalProfile = storage.retrieve(OpenAPS.Settings.basalProfile, as: [BasalProfileEntry].self),
+              let carbRatios = storage.retrieve(OpenAPS.Settings.carbRatios, as: CarbRatios.self),
+              let targets = storage.retrieve(OpenAPS.Settings.bgTargets, as: BGTargets.self)
+        else {
+            NSLog("NightscoutManager uploadProfile Not all settings found to build profile!")
+            return
+        }
+
+        let sens = sensitivities.sensitivities.map { item -> NightscoutTimevalue in
+            NightscoutTimevalue(
+                time: String(item.start.prefix(5)),
+                value: item.sensitivity,
+                timeAsSeconds: item.offset
+            )
+        }
+
+        let target_low = targets.targets.map { item -> NightscoutTimevalue in
+            NightscoutTimevalue(
+                time: String(item.start.prefix(5)),
+                value: item.low,
+                timeAsSeconds: item.offset
+            )
+        }
+        let target_high = targets.targets.map { item -> NightscoutTimevalue in
+            NightscoutTimevalue(
+                time: String(item.start.prefix(5)),
+                value: item.high,
+                timeAsSeconds: item.offset
+            )
+        }
+        let cr = carbRatios.schedule.map { item -> NightscoutTimevalue in
+            NightscoutTimevalue(
+                time: String(item.start.prefix(5)),
+                value: item.ratio,
+                timeAsSeconds: item.offset
+            )
+        }
+
+        let basal = basalProfile.map { item -> NightscoutTimevalue in
+            NightscoutTimevalue(
+                time: String(item.start.prefix(5)),
+                value: item.rate,
+                timeAsSeconds: item.minutes * 60
+            )
+        }
+        var nsUnits = ""
+        switch settingsManager.settings.units {
+        case .mgdL:
+            nsUnits = "mg/dl"
+        case .mmolL:
+            nsUnits = "mmol"
+        }
+
+        var carbs_hr: Decimal = 0
+        if let isf = sensitivities.sensitivities.map(\.sensitivity).first,
+           let cr = carbRatios.schedule.map(\.ratio).first,
+           isf > 0, cr > 0
+        {
+            // CarbImpact -> Carbs/hr = CI [mg/dl/5min] * 12 / ISF [mg/dl/U] * CR [g/U]
+            carbs_hr = settingsManager.preferences.min5mCarbimpact * 12 / isf * cr
+            if settingsManager.settings.units == .mmolL {
+                carbs_hr = carbs_hr * GlucoseUnits.exchangeRate
+            }
+            // No, Decimal has no rounding function.
+            carbs_hr = Decimal(round(Double(carbs_hr) * 10.0)) / 10
+        }
+        let ps = ScheduledNightscoutProfile(
+            dia: settingsManager.pumpSettings.insulinActionCurve,
+            carbs_hr: Int(carbs_hr),
+            delay: 0,
+            timezone: TimeZone.current.identifier,
+            target_low: target_low,
+            target_high: target_high,
+            sens: sens,
+            basal: basal,
+            carbratio: cr,
+            units: nsUnits
+        )
+        let defaultProfile = "default"
+        let now = Date()
+        let p = NightscoutProfileStore(
+            defaultProfile: defaultProfile,
+            startDate: now,
+            mills: Int(now.timeIntervalSince1970) * 1000,
+            units: nsUnits,
+            enteredBy: NigtscoutTreatment.local,
+            store: [defaultProfile: ps]
+        )
+
+        if let uploadedProfile = storage.retrieve(OpenAPS.Nightscout.uploadedProfile, as: NightscoutProfileStore.self),
+           (uploadedProfile.store[defaultProfile]?.rawJSON ?? "") == ps.rawJSON
+        {
+            NSLog("NightscoutManager uploadProfile, no profile change")
+            return
+        }
+        guard let nightscout = nightscoutAPI, isNetworkReachable, isUploadEnabled else {
+            return
+        }
+        processQueue.async {
+            nightscout.uploadProfile(p)
+                .sink { completion in
+                    switch completion {
+                    case .finished:
+                        self.storage.save(p, as: OpenAPS.Nightscout.uploadedProfile)
+                        debug(.nightscout, "Profile uploaded")
+                    case let .failure(error):
+                        debug(.nightscout, error.localizedDescription)
+                    }
+                } receiveValue: {}
+                .store(in: &self.lifetime)
+        }
+    }
+
     func uploadGlucose() {
         uploadGlucose(glucoseStorage.nightscoutGlucoseNotUploaded(), fileToSave: OpenAPS.Nightscout.uploadedGlucose)