|
@@ -11,6 +11,7 @@ protocol NightscoutManager: GlucoseSource {
|
|
|
func deleteCarbs(at date: Date)
|
|
func deleteCarbs(at date: Date)
|
|
|
func uploadStatus()
|
|
func uploadStatus()
|
|
|
func uploadGlucose()
|
|
func uploadGlucose()
|
|
|
|
|
+ func uploadProfile()
|
|
|
var cgmURL: URL? { get }
|
|
var cgmURL: URL? { get }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -262,6 +263,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() {
|
|
func uploadGlucose() {
|
|
|
uploadGlucose(glucoseStorage.nightscoutGlucoseNotUploaded(), fileToSave: OpenAPS.Nightscout.uploadedGlucose)
|
|
uploadGlucose(glucoseStorage.nightscoutGlucoseNotUploaded(), fileToSave: OpenAPS.Nightscout.uploadedGlucose)
|
|
|
|
|
|