|
@@ -245,9 +245,6 @@ final class OpenAPS {
|
|
|
|
|
|
|
|
let context = newContext("determineBasal")
|
|
let context = newContext("determineBasal")
|
|
|
|
|
|
|
|
- // temp_basal
|
|
|
|
|
- let tempBasal = currentTemp.rawJSON
|
|
|
|
|
-
|
|
|
|
|
// Perform asynchronous calls in parallel
|
|
// Perform asynchronous calls in parallel
|
|
|
async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs(on: context) ?? []
|
|
async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs(on: context) ?? []
|
|
|
async let carbsFetch = carbsStorage.getCarbsForAlgorithm(
|
|
async let carbsFetch = carbsStorage.getCarbsForAlgorithm(
|
|
@@ -274,11 +271,11 @@ final class OpenAPS {
|
|
|
pumpHistory,
|
|
pumpHistory,
|
|
|
carbs,
|
|
carbs,
|
|
|
glucose,
|
|
glucose,
|
|
|
- trioCustomOrefVariables,
|
|
|
|
|
- profile,
|
|
|
|
|
- basalProfile,
|
|
|
|
|
- autosens,
|
|
|
|
|
- reservoir,
|
|
|
|
|
|
|
+ rawTrioCustomOrefVariables,
|
|
|
|
|
+ rawProfile,
|
|
|
|
|
+ rawBasalProfile,
|
|
|
|
|
+ rawAutosens,
|
|
|
|
|
+ rawReservoir,
|
|
|
hasSufficientTdd
|
|
hasSufficientTdd
|
|
|
) = await (
|
|
) = await (
|
|
|
try parsePumpHistory(on: context, await pumpHistoryObjectIDs, simulatedBolusAmount: simulatedBolusAmount),
|
|
try parsePumpHistory(on: context, await pumpHistoryObjectIDs, simulatedBolusAmount: simulatedBolusAmount),
|
|
@@ -292,6 +289,13 @@ final class OpenAPS {
|
|
|
try hasSufficientTddForDynamic
|
|
try hasSufficientTddForDynamic
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ // Decode the JSON-at-rest inputs into native models at the call boundary.
|
|
|
|
|
+ let profile = try JSONBridge.profile(from: rawProfile)
|
|
|
|
|
+ let basalProfile = try JSONBridge.basalProfile(from: rawBasalProfile)
|
|
|
|
|
+ let autosens = try JSONBridge.autosens(from: rawAutosens.isEmpty ? .null : rawAutosens)
|
|
|
|
|
+ let reservoir = Decimal(string: rawReservoir) ?? 100
|
|
|
|
|
+ let trioCustomOrefVariables = try JSONBridge.trioCustomOrefVariables(from: rawTrioCustomOrefVariables)
|
|
|
|
|
+
|
|
|
// Meal calculation
|
|
// Meal calculation
|
|
|
let meal = try self.meal(
|
|
let meal = try self.meal(
|
|
|
pumphistory: pumpHistory,
|
|
pumphistory: pumpHistory,
|
|
@@ -307,7 +311,7 @@ final class OpenAPS {
|
|
|
pumphistory: pumpHistory,
|
|
pumphistory: pumpHistory,
|
|
|
profile: profile,
|
|
profile: profile,
|
|
|
clock: clock,
|
|
clock: clock,
|
|
|
- autosens: autosens.isEmpty ? .null : autosens
|
|
|
|
|
|
|
+ autosens: autosens
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
// TODO: refactor this to core data
|
|
// TODO: refactor this to core data
|
|
@@ -324,21 +328,20 @@ final class OpenAPS {
|
|
|
// Determine basal
|
|
// Determine basal
|
|
|
let orefDetermination = try determineBasal(
|
|
let orefDetermination = try determineBasal(
|
|
|
glucose: glucose,
|
|
glucose: glucose,
|
|
|
- currentTemp: tempBasal,
|
|
|
|
|
|
|
+ currentTemp: currentTemp,
|
|
|
iob: iob,
|
|
iob: iob,
|
|
|
profile: profile,
|
|
profile: profile,
|
|
|
- autosens: autosens.isEmpty ? .null : autosens,
|
|
|
|
|
|
|
+ autosens: autosens,
|
|
|
meal: meal,
|
|
meal: meal,
|
|
|
microBolusAllowed: true,
|
|
microBolusAllowed: true,
|
|
|
reservoir: reservoir,
|
|
reservoir: reservoir,
|
|
|
preferences: preferences,
|
|
preferences: preferences,
|
|
|
- basalProfile: basalProfile,
|
|
|
|
|
trioCustomOrefVariables: trioCustomOrefVariables
|
|
trioCustomOrefVariables: trioCustomOrefVariables
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- debug(.openAPS, "\(simulation ? "[SIMULATION]" : "") OREF DETERMINATION: \(orefDetermination)")
|
|
|
|
|
|
|
+ debug(.openAPS, "\(simulation ? "[SIMULATION]" : "") OREF DETERMINATION: \(String(describing: orefDetermination))")
|
|
|
|
|
|
|
|
- if var determination = Determination(from: orefDetermination), let deliverAt = determination.deliverAt {
|
|
|
|
|
|
|
+ if var determination = orefDetermination, let deliverAt = determination.deliverAt {
|
|
|
// set both timestamp and deliverAt to the SAME date; this will be updated for timestamp once it is enacted
|
|
// set both timestamp and deliverAt to the SAME date; this will be updated for timestamp once it is enacted
|
|
|
// AAPS does it the same way! we'll follow their example!
|
|
// AAPS does it the same way! we'll follow their example!
|
|
|
determination.timestamp = deliverAt
|
|
determination.timestamp = deliverAt
|
|
@@ -352,7 +355,7 @@ final class OpenAPS {
|
|
|
} else {
|
|
} else {
|
|
|
debug(
|
|
debug(
|
|
|
.openAPS,
|
|
.openAPS,
|
|
|
- "\(DebuggingIdentifiers.failed) No determination data. orefDetermination: \(orefDetermination), Determination(from: orefDetermination): \(String(describing: Determination(from: orefDetermination))), deliverAt: \(String(describing: Determination(from: orefDetermination)?.deliverAt))"
|
|
|
|
|
|
|
+ "\(DebuggingIdentifiers.failed) No determination data. determination: \(String(describing: orefDetermination)), deliverAt: \(String(describing: orefDetermination?.deliverAt))"
|
|
|
)
|
|
)
|
|
|
throw APSError.apsError(message: "No determination data.")
|
|
throw APSError.apsError(message: "No determination data.")
|
|
|
}
|
|
}
|
|
@@ -444,7 +447,7 @@ final class OpenAPS {
|
|
|
async let getTempTargets = loadFileFromStorageAsync(name: Settings.tempTargets)
|
|
async let getTempTargets = loadFileFromStorageAsync(name: Settings.tempTargets)
|
|
|
|
|
|
|
|
// Await the results of asynchronous tasks
|
|
// Await the results of asynchronous tasks
|
|
|
- let (pumpHistory, carbs, glucose, profile, basalProfile, tempTargets) = await (
|
|
|
|
|
|
|
+ let (pumpHistory, carbs, glucose, rawProfile, rawBasalProfile, rawTempTargets) = await (
|
|
|
try parsePumpHistory(on: context, await pumpHistoryObjectIDs),
|
|
try parsePumpHistory(on: context, await pumpHistoryObjectIDs),
|
|
|
try carbsFetch,
|
|
try carbsFetch,
|
|
|
try glucoseFetch,
|
|
try glucoseFetch,
|
|
@@ -453,25 +456,27 @@ final class OpenAPS {
|
|
|
getTempTargets
|
|
getTempTargets
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ // Decode the JSON-at-rest inputs into native models at the call boundary.
|
|
|
|
|
+ let profile = try JSONBridge.profile(from: rawProfile)
|
|
|
|
|
+ let basalProfile = try JSONBridge.basalProfile(from: rawBasalProfile)
|
|
|
|
|
+ let tempTargets = try JSONBridge.tempTargets(from: rawTempTargets)
|
|
|
|
|
+
|
|
|
// Autosense
|
|
// Autosense
|
|
|
- let autosenseResult = try autosense(
|
|
|
|
|
|
|
+ var autosens = try autosense(
|
|
|
glucose: glucose,
|
|
glucose: glucose,
|
|
|
pumpHistory: pumpHistory,
|
|
pumpHistory: pumpHistory,
|
|
|
- basalprofile: basalProfile,
|
|
|
|
|
|
|
+ basalProfile: basalProfile,
|
|
|
profile: profile,
|
|
profile: profile,
|
|
|
carbs: carbs,
|
|
carbs: carbs,
|
|
|
- temptargets: tempTargets
|
|
|
|
|
|
|
+ tempTargets: tempTargets,
|
|
|
|
|
+ clock: Date()
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- debug(.openAPS, "AUTOSENS: \(autosenseResult)")
|
|
|
|
|
- if var autosens = Autosens(from: autosenseResult) {
|
|
|
|
|
- autosens.timestamp = Date()
|
|
|
|
|
- await storage.saveAsync(autosens, as: Settings.autosense)
|
|
|
|
|
|
|
+ debug(.openAPS, "AUTOSENS: \(autosens)")
|
|
|
|
|
+ autosens.timestamp = Date()
|
|
|
|
|
+ await storage.saveAsync(autosens, as: Settings.autosense)
|
|
|
|
|
|
|
|
- return autosens
|
|
|
|
|
- } else {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return autosens
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func createProfiles() async throws {
|
|
func createProfiles() async throws {
|
|
@@ -550,24 +555,24 @@ final class OpenAPS {
|
|
|
let carbRatios = try JSONBridge.carbRatios(from: carbRatios)
|
|
let carbRatios = try JSONBridge.carbRatios(from: carbRatios)
|
|
|
let tempTargets = try JSONBridge.tempTargets(from: tempTargets)
|
|
let tempTargets = try JSONBridge.tempTargets(from: tempTargets)
|
|
|
|
|
|
|
|
- let pumpProfile = try OpenAPSSwift.makeProfile(
|
|
|
|
|
- preferences: adjustedPreferences,
|
|
|
|
|
|
|
+ let pumpProfile = try ProfileGenerator.generate(
|
|
|
pumpSettings: pumpSettings,
|
|
pumpSettings: pumpSettings,
|
|
|
bgTargets: bgTargets,
|
|
bgTargets: bgTargets,
|
|
|
basalProfile: basalProfile,
|
|
basalProfile: basalProfile,
|
|
|
- insulinSensitivities: insulinSensitivities,
|
|
|
|
|
|
|
+ isf: insulinSensitivities,
|
|
|
|
|
+ preferences: adjustedPreferences,
|
|
|
carbRatios: carbRatios,
|
|
carbRatios: carbRatios,
|
|
|
tempTargets: tempTargets,
|
|
tempTargets: tempTargets,
|
|
|
model: model,
|
|
model: model,
|
|
|
clock: clock
|
|
clock: clock
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- let profile = try OpenAPSSwift.makeProfile(
|
|
|
|
|
- preferences: adjustedPreferences,
|
|
|
|
|
|
|
+ let profile = try ProfileGenerator.generate(
|
|
|
pumpSettings: pumpSettings,
|
|
pumpSettings: pumpSettings,
|
|
|
bgTargets: bgTargets,
|
|
bgTargets: bgTargets,
|
|
|
basalProfile: basalProfile,
|
|
basalProfile: basalProfile,
|
|
|
- insulinSensitivities: insulinSensitivities,
|
|
|
|
|
|
|
+ isf: insulinSensitivities,
|
|
|
|
|
+ preferences: adjustedPreferences,
|
|
|
carbRatios: carbRatios,
|
|
carbRatios: carbRatios,
|
|
|
tempTargets: tempTargets,
|
|
tempTargets: tempTargets,
|
|
|
model: model,
|
|
model: model,
|
|
@@ -588,88 +593,105 @@ final class OpenAPS {
|
|
|
|
|
|
|
|
private func iob(
|
|
private func iob(
|
|
|
pumphistory: [PumpHistoryEvent],
|
|
pumphistory: [PumpHistoryEvent],
|
|
|
- profile: JSON,
|
|
|
|
|
- clock: JSON,
|
|
|
|
|
- autosens: JSON
|
|
|
|
|
- ) throws -> RawJSON {
|
|
|
|
|
|
|
+ profile: Profile,
|
|
|
|
|
+ clock: Date,
|
|
|
|
|
+ autosens: Autosens?
|
|
|
|
|
+ ) throws -> [IobResult] {
|
|
|
// FIXME: For now we'll just remove duplicate suspends here (ISSUE-399)
|
|
// FIXME: For now we'll just remove duplicate suspends here (ISSUE-399)
|
|
|
let pumphistory = pumphistory.removingDuplicateSuspendResumeEvents()
|
|
let pumphistory = pumphistory.removingDuplicateSuspendResumeEvents()
|
|
|
|
|
|
|
|
- let swiftResult = OpenAPSSwift
|
|
|
|
|
- .iob(pumphistory: pumphistory, profile: profile, clock: clock, autosens: autosens)
|
|
|
|
|
- return try swiftResult.returnOrThrow()
|
|
|
|
|
|
|
+ return try IobGenerator.generate(
|
|
|
|
|
+ history: pumphistory,
|
|
|
|
|
+ profile: profile,
|
|
|
|
|
+ clock: clock,
|
|
|
|
|
+ autosens: autosens
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func meal(
|
|
private func meal(
|
|
|
pumphistory: [PumpHistoryEvent],
|
|
pumphistory: [PumpHistoryEvent],
|
|
|
- profile: JSON,
|
|
|
|
|
- basalProfile: JSON,
|
|
|
|
|
- clock: JSON,
|
|
|
|
|
|
|
+ profile: Profile,
|
|
|
|
|
+ basalProfile: [BasalProfileEntry],
|
|
|
|
|
+ clock: Date,
|
|
|
carbs: [CarbsEntry],
|
|
carbs: [CarbsEntry],
|
|
|
glucose: [BloodGlucose]
|
|
glucose: [BloodGlucose]
|
|
|
- ) throws -> RawJSON {
|
|
|
|
|
- let swiftResult = OpenAPSSwift
|
|
|
|
|
- .meal(
|
|
|
|
|
- pumphistory: pumphistory,
|
|
|
|
|
- profile: profile,
|
|
|
|
|
- basalProfile: basalProfile,
|
|
|
|
|
- clock: clock,
|
|
|
|
|
- carbs: carbs,
|
|
|
|
|
- glucose: glucose
|
|
|
|
|
- )
|
|
|
|
|
- return try swiftResult.returnOrThrow()
|
|
|
|
|
|
|
+ ) throws -> ComputedCarbs? {
|
|
|
|
|
+ try MealGenerator.generate(
|
|
|
|
|
+ pumpHistory: pumphistory,
|
|
|
|
|
+ profile: profile,
|
|
|
|
|
+ basalProfile: basalProfile,
|
|
|
|
|
+ clock: clock,
|
|
|
|
|
+ carbHistory: carbs,
|
|
|
|
|
+ glucoseHistory: glucose
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func autosense(
|
|
private func autosense(
|
|
|
glucose: [BloodGlucose],
|
|
glucose: [BloodGlucose],
|
|
|
pumpHistory: [PumpHistoryEvent],
|
|
pumpHistory: [PumpHistoryEvent],
|
|
|
- basalprofile: JSON,
|
|
|
|
|
- profile: JSON,
|
|
|
|
|
|
|
+ basalProfile: [BasalProfileEntry],
|
|
|
|
|
+ profile: Profile,
|
|
|
carbs: [CarbsEntry],
|
|
carbs: [CarbsEntry],
|
|
|
- temptargets: JSON
|
|
|
|
|
- ) throws -> RawJSON {
|
|
|
|
|
- let swiftResult = OpenAPSSwift
|
|
|
|
|
- .autosense(
|
|
|
|
|
- glucose: glucose,
|
|
|
|
|
- pumpHistory: pumpHistory,
|
|
|
|
|
- basalProfile: basalprofile,
|
|
|
|
|
- profile: profile,
|
|
|
|
|
- carbs: carbs,
|
|
|
|
|
- tempTargets: temptargets,
|
|
|
|
|
- clock: Date()
|
|
|
|
|
- )
|
|
|
|
|
- return try swiftResult.returnOrThrow()
|
|
|
|
|
|
|
+ tempTargets: [TempTarget],
|
|
|
|
|
+ clock: Date
|
|
|
|
|
+ ) throws -> Autosens {
|
|
|
|
|
+ // this logic is from prepare/autosens.js
|
|
|
|
|
+ let ratio8h = try AutosensGenerator.generate(
|
|
|
|
|
+ glucose: glucose,
|
|
|
|
|
+ pumpHistory: pumpHistory,
|
|
|
|
|
+ basalProfile: basalProfile,
|
|
|
|
|
+ profile: profile,
|
|
|
|
|
+ carbs: carbs,
|
|
|
|
|
+ tempTargets: tempTargets,
|
|
|
|
|
+ maxDeviations: 96,
|
|
|
|
|
+ clock: clock
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ let ratio24h = try AutosensGenerator.generate(
|
|
|
|
|
+ glucose: glucose,
|
|
|
|
|
+ pumpHistory: pumpHistory,
|
|
|
|
|
+ basalProfile: basalProfile,
|
|
|
|
|
+ profile: profile,
|
|
|
|
|
+ carbs: carbs,
|
|
|
|
|
+ tempTargets: tempTargets,
|
|
|
|
|
+ maxDeviations: 288,
|
|
|
|
|
+ clock: clock
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ return ratio8h.ratio < ratio24h.ratio ? ratio8h : ratio24h
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func determineBasal(
|
|
private func determineBasal(
|
|
|
glucose: [BloodGlucose],
|
|
glucose: [BloodGlucose],
|
|
|
- currentTemp: JSON,
|
|
|
|
|
- iob: JSON,
|
|
|
|
|
- profile: JSON,
|
|
|
|
|
- autosens: JSON,
|
|
|
|
|
- meal: JSON,
|
|
|
|
|
|
|
+ currentTemp: TempBasal,
|
|
|
|
|
+ iob: [IobResult],
|
|
|
|
|
+ profile: Profile,
|
|
|
|
|
+ autosens: Autosens?,
|
|
|
|
|
+ meal: ComputedCarbs?,
|
|
|
microBolusAllowed: Bool,
|
|
microBolusAllowed: Bool,
|
|
|
- reservoir: JSON,
|
|
|
|
|
- preferences: JSON,
|
|
|
|
|
- basalProfile: JSON,
|
|
|
|
|
- trioCustomOrefVariables: JSON
|
|
|
|
|
- ) throws -> RawJSON {
|
|
|
|
|
|
|
+ reservoir: Decimal,
|
|
|
|
|
+ preferences: Preferences,
|
|
|
|
|
+ trioCustomOrefVariables: TrioCustomOrefVariables
|
|
|
|
|
+ ) throws -> Determination? {
|
|
|
let clock = Date()
|
|
let clock = Date()
|
|
|
- let swiftResult = OpenAPSSwift.determineBasal(
|
|
|
|
|
- glucose: glucose,
|
|
|
|
|
- currentTemp: currentTemp,
|
|
|
|
|
- iob: iob,
|
|
|
|
|
|
|
+
|
|
|
|
|
+ guard let meal = meal, let autosens = autosens else {
|
|
|
|
|
+ throw DeterminationError.missingInputs
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return try DeterminationGenerator.generate(
|
|
|
profile: profile,
|
|
profile: profile,
|
|
|
- autosens: autosens,
|
|
|
|
|
- meal: meal,
|
|
|
|
|
- microBolusAllowed: microBolusAllowed,
|
|
|
|
|
- reservoir: reservoir,
|
|
|
|
|
preferences: preferences,
|
|
preferences: preferences,
|
|
|
- basalProfile: basalProfile,
|
|
|
|
|
|
|
+ currentTemp: currentTemp,
|
|
|
|
|
+ iobData: iob,
|
|
|
|
|
+ mealData: meal,
|
|
|
|
|
+ autosensData: autosens,
|
|
|
|
|
+ reservoirData: reservoir,
|
|
|
|
|
+ glucose: glucose,
|
|
|
|
|
+ microBolusAllowed: microBolusAllowed,
|
|
|
trioCustomOrefVariables: trioCustomOrefVariables,
|
|
trioCustomOrefVariables: trioCustomOrefVariables,
|
|
|
- clock: clock
|
|
|
|
|
|
|
+ currentTime: clock
|
|
|
)
|
|
)
|
|
|
- return try swiftResult.returnOrThrow()
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func loadJSON(name: String) -> String {
|
|
private func loadJSON(name: String) -> String {
|