|
@@ -16,9 +16,7 @@ protocol NightscoutManager: GlucoseSource {
|
|
|
func uploadStatus() async
|
|
func uploadStatus() async
|
|
|
func uploadGlucose() async
|
|
func uploadGlucose() async
|
|
|
func uploadManualGlucose() async
|
|
func uploadManualGlucose() async
|
|
|
- func uploadStatistics(dailystat: Statistics) async
|
|
|
|
|
- func uploadPreferences(_ preferences: Preferences) async
|
|
|
|
|
- func uploadProfileAndSettings(_: Bool) async
|
|
|
|
|
|
|
+ func uploadProfiles() async
|
|
|
func importSettings() async -> ScheduledNightscoutProfile?
|
|
func importSettings() async -> ScheduledNightscoutProfile?
|
|
|
var cgmURL: URL? { get }
|
|
var cgmURL: URL? { get }
|
|
|
}
|
|
}
|
|
@@ -285,53 +283,6 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- func uploadStatistics(dailystat: Statistics) async {
|
|
|
|
|
- let stats = NightscoutStatistics(dailystats: dailystat)
|
|
|
|
|
-
|
|
|
|
|
- guard let nightscout = nightscoutAPI, isUploadEnabled else {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- do {
|
|
|
|
|
- try await nightscout.uploadStats(stats)
|
|
|
|
|
- debug(.nightscout, "Statistics uploaded")
|
|
|
|
|
- } catch {
|
|
|
|
|
- debug(.nightscout, error.localizedDescription)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- func uploadPreferences(_ preferences: Preferences) async {
|
|
|
|
|
- let prefs = NightscoutPreferences(preferences: settingsManager.preferences)
|
|
|
|
|
-
|
|
|
|
|
- guard let nightscout = nightscoutAPI, isUploadEnabled else {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- do {
|
|
|
|
|
- try await nightscout.uploadPrefs(prefs)
|
|
|
|
|
- debug(.nightscout, "Preferences uploaded")
|
|
|
|
|
- storage.save(preferences, as: OpenAPS.Nightscout.uploadedPreferences)
|
|
|
|
|
- } catch {
|
|
|
|
|
- debug(.nightscout, error.localizedDescription)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- func uploadSettings(_ settings: FreeAPSSettings) async {
|
|
|
|
|
- let sets = NightscoutSettings(settings: settingsManager.settings)
|
|
|
|
|
-
|
|
|
|
|
- guard let nightscout = nightscoutAPI, isUploadEnabled else {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- do {
|
|
|
|
|
- try await nightscout.uploadSettings(sets)
|
|
|
|
|
- debug(.nightscout, "Settings uploaded")
|
|
|
|
|
- storage.save(settings, as: OpenAPS.Nightscout.uploadedSettings)
|
|
|
|
|
- } catch {
|
|
|
|
|
- debug(.nightscout, error.localizedDescription)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
private func fetchBattery() async -> Battery {
|
|
private func fetchBattery() async -> Battery {
|
|
|
await backgroundContext.perform {
|
|
await backgroundContext.perform {
|
|
|
do {
|
|
do {
|
|
@@ -513,160 +464,128 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- func uploadProfileAndSettings(_ force: Bool) async {
|
|
|
|
|
- do {
|
|
|
|
|
- guard let sensitivities = await storage.retrieveAsync(
|
|
|
|
|
- OpenAPS.Settings.insulinSensitivities,
|
|
|
|
|
- as: InsulinSensitivities.self
|
|
|
|
|
- ) else {
|
|
|
|
|
- debug(.nightscout, "NightscoutManager uploadProfile: error loading insulinSensitivities")
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- guard let settings = await storage.retrieveAsync(OpenAPS.FreeAPS.settings, as: FreeAPSSettings.self) else {
|
|
|
|
|
- debug(.nightscout, "NightscoutManager uploadProfile: error loading settings")
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- guard let preferences = await storage.retrieveAsync(OpenAPS.Settings.preferences, as: Preferences.self) else {
|
|
|
|
|
- debug(.nightscout, "NightscoutManager uploadProfile: error loading preferences")
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- guard let targets = await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self) else {
|
|
|
|
|
- debug(.nightscout, "NightscoutManager uploadProfile: error loading bgTargets")
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- guard let carbRatios = await storage.retrieveAsync(OpenAPS.Settings.carbRatios, as: CarbRatios.self) else {
|
|
|
|
|
- debug(.nightscout, "NightscoutManager uploadProfile: error loading carbRatios")
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- guard let basalProfile = await storage.retrieveAsync(OpenAPS.Settings.basalProfile, as: [BasalProfileEntry].self)
|
|
|
|
|
- else {
|
|
|
|
|
- debug(.nightscout, "NightscoutManager uploadProfile: error loading basalProfile")
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let sens = sensitivities.sensitivities.map { item in
|
|
|
|
|
- NightscoutTimevalue(
|
|
|
|
|
- time: String(item.start.prefix(5)),
|
|
|
|
|
- value: item.sensitivity,
|
|
|
|
|
- timeAsSeconds: item.offset * 60
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- let targetLow = targets.targets.map { item in
|
|
|
|
|
- NightscoutTimevalue(
|
|
|
|
|
- time: String(item.start.prefix(5)),
|
|
|
|
|
- value: item.low,
|
|
|
|
|
- timeAsSeconds: item.offset * 60
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- let targetHigh = targets.targets.map { item in
|
|
|
|
|
- NightscoutTimevalue(
|
|
|
|
|
- time: String(item.start.prefix(5)),
|
|
|
|
|
- value: item.high,
|
|
|
|
|
- timeAsSeconds: item.offset * 60
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- let cr = carbRatios.schedule.map { item in
|
|
|
|
|
- NightscoutTimevalue(
|
|
|
|
|
- time: String(item.start.prefix(5)),
|
|
|
|
|
- value: item.ratio,
|
|
|
|
|
- timeAsSeconds: item.offset * 60
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- let basal = basalProfile.map { item in
|
|
|
|
|
- NightscoutTimevalue(
|
|
|
|
|
- time: String(item.start.prefix(5)),
|
|
|
|
|
- value: item.rate,
|
|
|
|
|
- timeAsSeconds: item.minutes * 60
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let nsUnits: String = {
|
|
|
|
|
- switch settingsManager.settings.units {
|
|
|
|
|
- case .mgdL:
|
|
|
|
|
- return "mg/dl"
|
|
|
|
|
- case .mmolL:
|
|
|
|
|
- return "mmol"
|
|
|
|
|
|
|
+ func uploadProfiles() async {
|
|
|
|
|
+ if isUploadEnabled {
|
|
|
|
|
+ do {
|
|
|
|
|
+ guard let sensitivities = await storage.retrieveAsync(
|
|
|
|
|
+ OpenAPS.Settings.insulinSensitivities,
|
|
|
|
|
+ as: InsulinSensitivities.self
|
|
|
|
|
+ ) else {
|
|
|
|
|
+ debug(.nightscout, "NightscoutManager uploadProfile: error loading insulinSensitivities")
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
- }()
|
|
|
|
|
-
|
|
|
|
|
- var carbsHr: Decimal = 0
|
|
|
|
|
- if let isf = sensitivities.sensitivities.map(\.sensitivity).first,
|
|
|
|
|
- let cr = carbRatios.schedule.map(\.ratio).first,
|
|
|
|
|
- isf > 0, cr > 0
|
|
|
|
|
- {
|
|
|
|
|
- carbsHr = settingsManager.preferences.min5mCarbimpact * 12 / isf * cr
|
|
|
|
|
- if settingsManager.settings.units == .mmolL {
|
|
|
|
|
- carbsHr *= GlucoseUnits.exchangeRate
|
|
|
|
|
|
|
+ guard let targets = await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self) else {
|
|
|
|
|
+ debug(.nightscout, "NightscoutManager uploadProfile: error loading bgTargets")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ guard let carbRatios = await storage.retrieveAsync(OpenAPS.Settings.carbRatios, as: CarbRatios.self) else {
|
|
|
|
|
+ debug(.nightscout, "NightscoutManager uploadProfile: error loading carbRatios")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ guard let basalProfile = await storage.retrieveAsync(OpenAPS.Settings.basalProfile, as: [BasalProfileEntry].self)
|
|
|
|
|
+ else {
|
|
|
|
|
+ debug(.nightscout, "NightscoutManager uploadProfile: error loading basalProfile")
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
- carbsHr = Decimal(round(Double(carbsHr) * 10.0)) / 10
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- let scheduledProfile = ScheduledNightscoutProfile(
|
|
|
|
|
- dia: settingsManager.pumpSettings.insulinActionCurve,
|
|
|
|
|
- carbs_hr: Int(carbsHr),
|
|
|
|
|
- delay: 0,
|
|
|
|
|
- timezone: TimeZone.current.identifier,
|
|
|
|
|
- target_low: targetLow,
|
|
|
|
|
- target_high: targetHigh,
|
|
|
|
|
- sens: sens,
|
|
|
|
|
- basal: basal,
|
|
|
|
|
- carbratio: cr,
|
|
|
|
|
- units: nsUnits
|
|
|
|
|
- )
|
|
|
|
|
- let defaultProfile = "default"
|
|
|
|
|
-
|
|
|
|
|
- let now = Date()
|
|
|
|
|
- let profileStore = NightscoutProfileStore(
|
|
|
|
|
- defaultProfile: defaultProfile,
|
|
|
|
|
- startDate: now,
|
|
|
|
|
- mills: Int(now.timeIntervalSince1970) * 1000,
|
|
|
|
|
- units: nsUnits,
|
|
|
|
|
- enteredBy: NightscoutTreatment.local,
|
|
|
|
|
- store: [defaultProfile: scheduledProfile]
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ let sens = sensitivities.sensitivities.map { item in
|
|
|
|
|
+ NightscoutTimevalue(
|
|
|
|
|
+ time: String(item.start.prefix(5)),
|
|
|
|
|
+ value: item.sensitivity,
|
|
|
|
|
+ timeAsSeconds: item.offset * 60
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ let targetLow = targets.targets.map { item in
|
|
|
|
|
+ NightscoutTimevalue(
|
|
|
|
|
+ time: String(item.start.prefix(5)),
|
|
|
|
|
+ value: item.low,
|
|
|
|
|
+ timeAsSeconds: item.offset * 60
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ let targetHigh = targets.targets.map { item in
|
|
|
|
|
+ NightscoutTimevalue(
|
|
|
|
|
+ time: String(item.start.prefix(5)),
|
|
|
|
|
+ value: item.high,
|
|
|
|
|
+ timeAsSeconds: item.offset * 60
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ let cr = carbRatios.schedule.map { item in
|
|
|
|
|
+ NightscoutTimevalue(
|
|
|
|
|
+ time: String(item.start.prefix(5)),
|
|
|
|
|
+ value: item.ratio,
|
|
|
|
|
+ timeAsSeconds: item.offset * 60
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ let basal = basalProfile.map { item in
|
|
|
|
|
+ NightscoutTimevalue(
|
|
|
|
|
+ time: String(item.start.prefix(5)),
|
|
|
|
|
+ value: item.rate,
|
|
|
|
|
+ timeAsSeconds: item.minutes * 60
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- guard let nightscout = nightscoutAPI, isNetworkReachable, isUploadEnabled else {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let nsUnits: String = {
|
|
|
|
|
+ switch settingsManager.settings.units {
|
|
|
|
|
+ case .mgdL:
|
|
|
|
|
+ return "mg/dl"
|
|
|
|
|
+ case .mmolL:
|
|
|
|
|
+ return "mmol"
|
|
|
|
|
+ }
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ var carbsHr: Decimal = 0
|
|
|
|
|
+ if let isf = sensitivities.sensitivities.map(\.sensitivity).first,
|
|
|
|
|
+ let cr = carbRatios.schedule.map(\.ratio).first,
|
|
|
|
|
+ isf > 0, cr > 0
|
|
|
|
|
+ {
|
|
|
|
|
+ carbsHr = settingsManager.preferences.min5mCarbimpact * 12 / isf * cr
|
|
|
|
|
+ if settingsManager.settings.units == .mmolL {
|
|
|
|
|
+ carbsHr *= GlucoseUnits.exchangeRate
|
|
|
|
|
+ }
|
|
|
|
|
+ carbsHr = Decimal(round(Double(carbsHr) * 10.0)) / 10
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Upload Preferences when changed
|
|
|
|
|
- if let uploadedPreferences = await storage.retrieveAsync(
|
|
|
|
|
- OpenAPS.Nightscout.uploadedPreferences,
|
|
|
|
|
- as: Preferences.self
|
|
|
|
|
- ),
|
|
|
|
|
- uploadedPreferences.rawJSON.sorted() == preferences.rawJSON.sorted(), !force
|
|
|
|
|
- {
|
|
|
|
|
- NSLog("NightscoutManager Preferences, preferences unchanged")
|
|
|
|
|
- } else {
|
|
|
|
|
- await uploadPreferences(preferences)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let scheduledProfile = ScheduledNightscoutProfile(
|
|
|
|
|
+ dia: settingsManager.pumpSettings.insulinActionCurve,
|
|
|
|
|
+ carbs_hr: Int(carbsHr),
|
|
|
|
|
+ delay: 0,
|
|
|
|
|
+ timezone: TimeZone.current.identifier,
|
|
|
|
|
+ target_low: targetLow,
|
|
|
|
|
+ target_high: targetHigh,
|
|
|
|
|
+ sens: sens,
|
|
|
|
|
+ basal: basal,
|
|
|
|
|
+ carbratio: cr,
|
|
|
|
|
+ units: nsUnits
|
|
|
|
|
+ )
|
|
|
|
|
+ let defaultProfile = "default"
|
|
|
|
|
+
|
|
|
|
|
+ let now = Date()
|
|
|
|
|
+ let profileStore = NightscoutProfileStore(
|
|
|
|
|
+ defaultProfile: defaultProfile,
|
|
|
|
|
+ startDate: now,
|
|
|
|
|
+ mills: Int(now.timeIntervalSince1970) * 1000,
|
|
|
|
|
+ units: nsUnits,
|
|
|
|
|
+ enteredBy: NightscoutTreatment.local,
|
|
|
|
|
+ store: [defaultProfile: scheduledProfile]
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
- // Upload FreeAPS Settings when changed
|
|
|
|
|
- if let uploadedSettings = await storage.retrieveAsync(OpenAPS.Nightscout.uploadedSettings, as: FreeAPSSettings.self),
|
|
|
|
|
- uploadedSettings.rawJSON.sorted() == settings.rawJSON.sorted(), !force
|
|
|
|
|
- {
|
|
|
|
|
- NSLog("NightscoutManager Settings, settings unchanged")
|
|
|
|
|
- } else {
|
|
|
|
|
- await uploadSettings(settings)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ guard let nightscout = nightscoutAPI, isNetworkReachable else {
|
|
|
|
|
+ if !isNetworkReachable {
|
|
|
|
|
+ debug(.nightscout, "Network issues; aborting upload")
|
|
|
|
|
+ }
|
|
|
|
|
+ debug(.nightscout, "Nightscout API service not available; aborting upload")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Upload Profiles when changed
|
|
|
|
|
- if let uploadedProfile = await storage.retrieveAsync(
|
|
|
|
|
- OpenAPS.Nightscout.uploadedProfile,
|
|
|
|
|
- as: NightscoutProfileStore.self
|
|
|
|
|
- ),
|
|
|
|
|
- (uploadedProfile.store["default"]?.rawJSON ?? "").sorted() == scheduledProfile.rawJSON.sorted(), !force
|
|
|
|
|
- {
|
|
|
|
|
- NSLog("NightscoutManager uploadProfile, no profile change")
|
|
|
|
|
- } else {
|
|
|
|
|
do {
|
|
do {
|
|
|
try await nightscout.uploadProfile(profileStore)
|
|
try await nightscout.uploadProfile(profileStore)
|
|
|
- storage.save(profileStore, as: OpenAPS.Nightscout.uploadedProfile)
|
|
|
|
|
debug(.nightscout, "Profile uploaded")
|
|
debug(.nightscout, "Profile uploaded")
|
|
|
} catch {
|
|
} catch {
|
|
|
debug(.nightscout, "NightscoutManager uploadProfile: \(error.localizedDescription)")
|
|
debug(.nightscout, "NightscoutManager uploadProfile: \(error.localizedDescription)")
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ debug(.nightscout, "Upload to NS disabled; aborting profile uploaded")
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|