|
|
@@ -10,10 +10,14 @@ final class OpenAPS {
|
|
|
private let storage: FileStorage
|
|
|
private let tddStorage: TDDStorage
|
|
|
|
|
|
- let context = CoreDataStack.shared.newTaskContext()
|
|
|
-
|
|
|
let jsonConverter = JSONConverter()
|
|
|
|
|
|
+ private func newContext(_ name: String) -> NSManagedObjectContext {
|
|
|
+ let context = CoreDataStack.shared.newTaskContext()
|
|
|
+ context.name = name
|
|
|
+ return context
|
|
|
+ }
|
|
|
+
|
|
|
init(storage: FileStorage, tddStorage: TDDStorage) {
|
|
|
self.storage = storage
|
|
|
self.tddStorage = tddStorage
|
|
|
@@ -32,9 +36,9 @@ final class OpenAPS {
|
|
|
}
|
|
|
|
|
|
// Use the helper function for cleaner code
|
|
|
- func processDetermination(_ determination: Determination) async {
|
|
|
+ func processDetermination(_ determination: Determination, on context: NSManagedObjectContext) async {
|
|
|
await context.perform {
|
|
|
- let newOrefDetermination = OrefDetermination(context: self.context)
|
|
|
+ let newOrefDetermination = OrefDetermination(context: context)
|
|
|
newOrefDetermination.id = UUID()
|
|
|
newOrefDetermination.insulinSensitivity = self.decimalToNSDecimalNumber(determination.isf)
|
|
|
newOrefDetermination.currentTarget = self.decimalToNSDecimalNumber(determination.current_target)
|
|
|
@@ -64,14 +68,14 @@ final class OpenAPS {
|
|
|
["iob": predictions.iob, "zt": predictions.zt, "cob": predictions.cob, "uam": predictions.uam]
|
|
|
.forEach { type, values in
|
|
|
if let values = values {
|
|
|
- let forecast = Forecast(context: self.context)
|
|
|
+ let forecast = Forecast(context: context)
|
|
|
forecast.id = UUID()
|
|
|
forecast.type = type
|
|
|
forecast.date = Date()
|
|
|
forecast.orefDetermination = newOrefDetermination
|
|
|
|
|
|
for (index, value) in values.enumerated() {
|
|
|
- let forecastValue = ForecastValue(context: self.context)
|
|
|
+ let forecastValue = ForecastValue(context: context)
|
|
|
forecastValue.index = Int32(index)
|
|
|
forecastValue.value = Int32(value)
|
|
|
forecast.addToForecastValues(forecastValue)
|
|
|
@@ -83,14 +87,14 @@ final class OpenAPS {
|
|
|
}
|
|
|
|
|
|
// First save the current Determination to Core Data
|
|
|
- await attemptToSaveContext()
|
|
|
+ await attemptToSaveContext(on: context)
|
|
|
}
|
|
|
|
|
|
- func attemptToSaveContext() async {
|
|
|
+ func attemptToSaveContext(on context: NSManagedObjectContext) async {
|
|
|
await context.perform {
|
|
|
do {
|
|
|
- guard self.context.hasChanges else { return }
|
|
|
- try self.context.save()
|
|
|
+ guard context.hasChanges else { return }
|
|
|
+ try context.save()
|
|
|
} catch {
|
|
|
debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to save Determination to Core Data")
|
|
|
}
|
|
|
@@ -156,7 +160,11 @@ final class OpenAPS {
|
|
|
return jsonConverter.convertToJSON(algorithmGlucose)
|
|
|
}
|
|
|
|
|
|
- private func fetchAndProcessCarbs(additionalCarbs: Decimal? = nil, carbsDate: Date? = nil) async throws -> String {
|
|
|
+ private func fetchAndProcessCarbs(
|
|
|
+ on context: NSManagedObjectContext,
|
|
|
+ additionalCarbs: Decimal? = nil,
|
|
|
+ carbsDate: Date? = nil
|
|
|
+ ) async throws -> String {
|
|
|
let results = try await CoreDataStack.shared.fetchEntitiesAsync(
|
|
|
ofType: CarbEntryStored.self,
|
|
|
onContext: context,
|
|
|
@@ -208,7 +216,7 @@ final class OpenAPS {
|
|
|
return json
|
|
|
}
|
|
|
|
|
|
- private func fetchPumpHistoryObjectIDs() async throws -> [NSManagedObjectID]? {
|
|
|
+ private func fetchPumpHistoryObjectIDs(on context: NSManagedObjectContext) async throws -> [NSManagedObjectID]? {
|
|
|
let results = try await CoreDataStack.shared.fetchEntitiesAsync(
|
|
|
ofType: PumpEventStored.self,
|
|
|
onContext: context,
|
|
|
@@ -228,6 +236,7 @@ final class OpenAPS {
|
|
|
}
|
|
|
|
|
|
private func parsePumpHistory(
|
|
|
+ on context: NSManagedObjectContext,
|
|
|
_ pumpHistoryObjectIDs: [NSManagedObjectID],
|
|
|
simulatedBolusAmount: Decimal? = nil
|
|
|
) async throws -> String {
|
|
|
@@ -240,12 +249,12 @@ final class OpenAPS {
|
|
|
// the oldest event in pump history can be a resume with no preceding pump
|
|
|
// activity. oref interprets this as the end of a suspend that never started,
|
|
|
// which drives negative IOB and can cause excessive insulin delivery.
|
|
|
- let orphanedResumes = try await fetchOrphanedResumes()
|
|
|
+ let orphanedResumes = try await fetchOrphanedResumes(on: context)
|
|
|
|
|
|
// Execute all operations on the background context
|
|
|
return await context.perform {
|
|
|
// Load and map pump events to DTOs
|
|
|
- var dtos = self.loadAndMapPumpEvents(pumpHistoryObjectIDs, orphanedResumes: orphanedResumes)
|
|
|
+ var dtos = self.loadAndMapPumpEvents(pumpHistoryObjectIDs, orphanedResumes: orphanedResumes, on: context)
|
|
|
|
|
|
// Optionally add the IOB as a DTO
|
|
|
if let simulatedBolusAmount = simulatedBolusAmount {
|
|
|
@@ -260,7 +269,8 @@ final class OpenAPS {
|
|
|
|
|
|
private func loadAndMapPumpEvents(
|
|
|
_ pumpHistoryObjectIDs: [NSManagedObjectID],
|
|
|
- orphanedResumes: [NSManagedObjectID]
|
|
|
+ orphanedResumes: [NSManagedObjectID],
|
|
|
+ on context: NSManagedObjectContext
|
|
|
) -> [PumpEventDTO] {
|
|
|
OpenAPS.loadAndMapPumpEvents(pumpHistoryObjectIDs, orphanedResumes: orphanedResumes, from: context)
|
|
|
}
|
|
|
@@ -328,7 +338,7 @@ final class OpenAPS {
|
|
|
}
|
|
|
|
|
|
/// Detects a cold-start orphaned resume: returns the resume's object ID if it's an orphaned resume
|
|
|
- private func fetchOrphanedResumes() async throws -> [NSManagedObjectID] {
|
|
|
+ private func fetchOrphanedResumes(on context: NSManagedObjectContext) async throws -> [NSManagedObjectID] {
|
|
|
let results = try await CoreDataStack.shared.fetchEntitiesAsync(
|
|
|
ofType: PumpEventStored.self,
|
|
|
onContext: context,
|
|
|
@@ -388,14 +398,20 @@ final class OpenAPS {
|
|
|
) async throws -> Determination? {
|
|
|
debug(.openAPS, "Start determineBasal")
|
|
|
|
|
|
+ let context = newContext("determineBasal")
|
|
|
+
|
|
|
// temp_basal
|
|
|
let tempBasal = currentTemp.rawJSON
|
|
|
|
|
|
// Perform asynchronous calls in parallel
|
|
|
- async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs() ?? []
|
|
|
- async let carbs = fetchAndProcessCarbs(additionalCarbs: simulatedCarbsAmount ?? 0, carbsDate: simulatedCarbsDate)
|
|
|
+ async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs(on: context) ?? []
|
|
|
+ async let carbs = fetchAndProcessCarbs(
|
|
|
+ on: context,
|
|
|
+ additionalCarbs: simulatedCarbsAmount ?? 0,
|
|
|
+ carbsDate: simulatedCarbsDate
|
|
|
+ )
|
|
|
async let glucose = fetchAndProcessGlucose(context: context, shouldSmoothGlucose: shouldSmoothGlucose, fetchLimit: 72)
|
|
|
- async let prepareTrioCustomOrefVariables = prepareTrioCustomOrefVariables()
|
|
|
+ async let prepareTrioCustomOrefVariables = prepareTrioCustomOrefVariables(on: context)
|
|
|
async let profileAsync = loadFileFromStorageAsync(name: Settings.profile)
|
|
|
async let basalAsync = loadFileFromStorageAsync(name: Settings.basalProfile)
|
|
|
async let autosenseAsync = loadFileFromStorageAsync(name: Settings.autosense)
|
|
|
@@ -415,7 +431,7 @@ final class OpenAPS {
|
|
|
reservoir,
|
|
|
hasSufficientTdd
|
|
|
) = await (
|
|
|
- try parsePumpHistory(await pumpHistoryObjectIDs, simulatedBolusAmount: simulatedBolusAmount),
|
|
|
+ try parsePumpHistory(on: context, await pumpHistoryObjectIDs, simulatedBolusAmount: simulatedBolusAmount),
|
|
|
try carbs,
|
|
|
try glucose,
|
|
|
try prepareTrioCustomOrefVariables,
|
|
|
@@ -482,7 +498,7 @@ final class OpenAPS {
|
|
|
|
|
|
if !simulation {
|
|
|
// save to core data asynchronously
|
|
|
- await processDetermination(determination)
|
|
|
+ await processDetermination(determination, on: context)
|
|
|
}
|
|
|
|
|
|
return determination
|
|
|
@@ -495,7 +511,7 @@ final class OpenAPS {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- func prepareTrioCustomOrefVariables() async throws -> RawJSON {
|
|
|
+ func prepareTrioCustomOrefVariables(on context: NSManagedObjectContext) async throws -> RawJSON {
|
|
|
try await context.perform {
|
|
|
// Retrieve user preferences
|
|
|
let userPreferences = self.storage.retrieve(OpenAPS.Settings.preferences, as: Preferences.self)
|
|
|
@@ -506,10 +522,10 @@ final class OpenAPS {
|
|
|
// Fetch historical events for Total Daily Dose (TDD) calculation
|
|
|
let tenDaysAgo = Date().addingTimeInterval(-10.days.timeInterval)
|
|
|
let twoHoursAgo = Date().addingTimeInterval(-2.hours.timeInterval)
|
|
|
- let historicalTDDData = try self.fetchHistoricalTDDData(from: tenDaysAgo)
|
|
|
+ let historicalTDDData = try self.fetchHistoricalTDDData(from: tenDaysAgo, on: context)
|
|
|
|
|
|
// Fetch the last active Override
|
|
|
- let activeOverrides = try self.fetchActiveOverrides()
|
|
|
+ let activeOverrides = try self.fetchActiveOverrides(on: context)
|
|
|
let isOverrideActive = activeOverrides.first?.enabled ?? false
|
|
|
let overridePercentage = Decimal(activeOverrides.first?.percentage ?? 100)
|
|
|
let isOverrideIndefinite = activeOverrides.first?.indefinite ?? true
|
|
|
@@ -531,7 +547,7 @@ final class OpenAPS {
|
|
|
let averageTDDLastTenDays = totalTDD / Decimal(totalDaysCount)
|
|
|
let weightedTDD = weightPercentage * averageTDDLastTwoHours + (1 - weightPercentage) * averageTDDLastTenDays
|
|
|
|
|
|
- let glucose = try self.fetchGlucose()
|
|
|
+ let glucose = try self.fetchGlucose(on: context)
|
|
|
|
|
|
// Prepare Trio's custom oref variables
|
|
|
let trioCustomOrefVariablesData = TrioCustomOrefVariables(
|
|
|
@@ -566,9 +582,11 @@ final class OpenAPS {
|
|
|
func autosense(shouldSmoothGlucose: Bool) async throws -> Autosens? {
|
|
|
debug(.openAPS, "Start autosens")
|
|
|
|
|
|
+ let context = newContext("autosense")
|
|
|
+
|
|
|
// Perform asynchronous calls in parallel
|
|
|
- async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs() ?? []
|
|
|
- async let carbs = fetchAndProcessCarbs()
|
|
|
+ async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs(on: context) ?? []
|
|
|
+ async let carbs = fetchAndProcessCarbs(on: context)
|
|
|
async let glucose = fetchAndProcessGlucose(context: context, shouldSmoothGlucose: shouldSmoothGlucose, fetchLimit: nil)
|
|
|
async let getProfile = loadFileFromStorageAsync(name: Settings.profile)
|
|
|
async let getBasalProfile = loadFileFromStorageAsync(name: Settings.basalProfile)
|
|
|
@@ -576,7 +594,7 @@ final class OpenAPS {
|
|
|
|
|
|
// Await the results of asynchronous tasks
|
|
|
let (pumpHistoryJSON, carbsAsJSON, glucoseAsJSON, profile, basalProfile, tempTargets) = await (
|
|
|
- try parsePumpHistory(await pumpHistoryObjectIDs),
|
|
|
+ try parsePumpHistory(on: context, await pumpHistoryObjectIDs),
|
|
|
try carbs,
|
|
|
try glucose,
|
|
|
getProfile,
|
|
|
@@ -635,9 +653,10 @@ final class OpenAPS {
|
|
|
var adjustedPreferences = preferences
|
|
|
|
|
|
// Check for active Temp Targets and adjust HBT if necessary
|
|
|
+ let context = newContext("createProfiles")
|
|
|
try await context.perform {
|
|
|
// Check if a Temp Target is active and check HBT differs from setting and adjust
|
|
|
- if let activeTempTarget = try self.fetchActiveTempTargets().first,
|
|
|
+ if let activeTempTarget = try self.fetchActiveTempTargets(on: context).first,
|
|
|
activeTempTarget.enabled,
|
|
|
let targetValue = activeTempTarget.target?.decimalValue
|
|
|
{
|
|
|
@@ -924,15 +943,16 @@ final class OpenAPS {
|
|
|
|
|
|
func processAndSave(forecastData: [String: [Int]]) {
|
|
|
let currentDate = Date()
|
|
|
+ let context = newContext("processAndSave")
|
|
|
|
|
|
context.perform {
|
|
|
for (type, values) in forecastData {
|
|
|
- self.createForecast(type: type, values: values, date: currentDate, context: self.context)
|
|
|
+ self.createForecast(type: type, values: values, date: currentDate, context: context)
|
|
|
}
|
|
|
|
|
|
do {
|
|
|
- guard self.context.hasChanges else { return }
|
|
|
- try self.context.save()
|
|
|
+ guard context.hasChanges else { return }
|
|
|
+ try context.save()
|
|
|
} catch {
|
|
|
print(error.localizedDescription)
|
|
|
}
|
|
|
@@ -956,7 +976,7 @@ final class OpenAPS {
|
|
|
|
|
|
// Non-Async fetch methods for trio_custom_oref_variables
|
|
|
extension OpenAPS {
|
|
|
- func fetchActiveTempTargets() throws -> [TempTargetStored] {
|
|
|
+ func fetchActiveTempTargets(on context: NSManagedObjectContext) throws -> [TempTargetStored] {
|
|
|
try CoreDataStack.shared.fetchEntities(
|
|
|
ofType: TempTargetStored.self,
|
|
|
onContext: context,
|
|
|
@@ -967,7 +987,7 @@ extension OpenAPS {
|
|
|
) as? [TempTargetStored] ?? []
|
|
|
}
|
|
|
|
|
|
- func fetchActiveOverrides() throws -> [OverrideStored] {
|
|
|
+ func fetchActiveOverrides(on context: NSManagedObjectContext) throws -> [OverrideStored] {
|
|
|
try CoreDataStack.shared.fetchEntities(
|
|
|
ofType: OverrideStored.self,
|
|
|
onContext: context,
|
|
|
@@ -978,7 +998,7 @@ extension OpenAPS {
|
|
|
) as? [OverrideStored] ?? []
|
|
|
}
|
|
|
|
|
|
- func fetchHistoricalTDDData(from date: Date) throws -> [[String: Any]] {
|
|
|
+ func fetchHistoricalTDDData(from date: Date, on context: NSManagedObjectContext) throws -> [[String: Any]] {
|
|
|
try CoreDataStack.shared.fetchEntities(
|
|
|
ofType: TDDStored.self,
|
|
|
onContext: context,
|
|
|
@@ -989,7 +1009,7 @@ extension OpenAPS {
|
|
|
) as? [[String: Any]] ?? []
|
|
|
}
|
|
|
|
|
|
- func fetchGlucose() throws -> [GlucoseStored] {
|
|
|
+ func fetchGlucose(on context: NSManagedObjectContext) throws -> [GlucoseStored] {
|
|
|
let results = try CoreDataStack.shared.fetchEntities(
|
|
|
ofType: GlucoseStored.self,
|
|
|
onContext: context,
|