|
|
@@ -30,43 +30,48 @@ struct COBInputs {
|
|
|
}
|
|
|
|
|
|
enum MealTotal {
|
|
|
- static func recentCarbs(treatments: [MealInput], pumpHistory: [PumpHistoryEvent], profile: Profile, basalProfile: [BasalProfileEntry], glucose: [BloodGlucose], time: Date) -> ComputedCarbs? {
|
|
|
+ static func recentCarbs(
|
|
|
+ treatments: [MealInput],
|
|
|
+ pumpHistory: [PumpHistoryEvent],
|
|
|
+ profile: Profile,
|
|
|
+ basalProfile: [BasalProfileEntry],
|
|
|
+ glucose: [BloodGlucose],
|
|
|
+ time: Date
|
|
|
+ ) -> ComputedCarbs? {
|
|
|
guard treatments.isNotEmpty else { return nil }
|
|
|
-
|
|
|
+
|
|
|
var _treatments = treatments
|
|
|
- var carbs: Decimal = Decimal(0)
|
|
|
- var nsCarbs: Decimal = Decimal(0)
|
|
|
- var bwCarbs: Decimal = Decimal(0)
|
|
|
- var journalCarbs: Decimal = Decimal(0)
|
|
|
+ var carbs = Decimal(0)
|
|
|
+ var nsCarbs = Decimal(0)
|
|
|
+ var bwCarbs = Decimal(0)
|
|
|
+ var journalCarbs = Decimal(0)
|
|
|
let mealCarbTime: TimeInterval = time.timeIntervalSince1970
|
|
|
var lastCarbTime: TimeInterval = 0
|
|
|
var bwFound: Bool = false
|
|
|
-
|
|
|
+
|
|
|
let iobInputs = IOBInput(profile: profile, history: pumpHistory)
|
|
|
var cobInputs = COBInputs(glucoseData: glucose, iobInputs: iobInputs, basalProfile: basalProfile, mealTime: mealCarbTime)
|
|
|
- var mealCOB: Decimal = Decimal(0)
|
|
|
+ var mealCOB = Decimal(0)
|
|
|
|
|
|
-
|
|
|
_treatments.sort(by: {
|
|
|
$0.timestamp > $1.timestamp
|
|
|
})
|
|
|
-
|
|
|
- var carbsToRemove: Decimal = Decimal(0)
|
|
|
- var nsCarbsToRemove: Decimal = Decimal(0)
|
|
|
- var bwCarbsToRemove: Decimal = Decimal(0)
|
|
|
- var journalCarbsToRemove: Decimal = Decimal(0)
|
|
|
-
|
|
|
+
|
|
|
+ var carbsToRemove = Decimal(0)
|
|
|
+ var nsCarbsToRemove = Decimal(0)
|
|
|
+ var bwCarbsToRemove = Decimal(0)
|
|
|
+ var journalCarbsToRemove = Decimal(0)
|
|
|
+
|
|
|
for treatment in _treatments {
|
|
|
let now = time.timeIntervalSince1970
|
|
|
-
|
|
|
- // Use new maxMealAbsorptionTime setting here instead of default 6 hrs
|
|
|
+
|
|
|
+ // Use new maxMealAbsorptionTime setting here instead of default 6 hrs
|
|
|
var carbWindow = now - TimeInterval(hours: Double(truncating: profile.maxMealAbsorptionTime as NSNumber))
|
|
|
-
|
|
|
+
|
|
|
let treatmentDate = treatment.timestamp
|
|
|
let treatmentTime = treatmentDate.timeIntervalSince1970
|
|
|
-
|
|
|
- if (treatmentTime > carbWindow && treatmentTime <= now) {
|
|
|
-
|
|
|
+
|
|
|
+ if treatmentTime > carbWindow, treatmentTime <= now {
|
|
|
if var _carbs = treatment.carbs, carbs >= 1 {
|
|
|
if var _nsCarbs = treatment.nsCarbs, nsCarbs >= 1 {
|
|
|
nsCarbs += _nsCarbs
|
|
|
@@ -78,18 +83,18 @@ enum MealTotal {
|
|
|
} else {
|
|
|
print("Treatment carbs unclassified: \(treatment)")
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
carbs += _carbs
|
|
|
-
|
|
|
+
|
|
|
cobInputs.mealTime = treatmentTime
|
|
|
- lastCarbTime = max(lastCarbTime,treatmentTime)
|
|
|
-
|
|
|
+ lastCarbTime = max(lastCarbTime, treatmentTime)
|
|
|
+
|
|
|
let myCarbsAbsorbed = Decimal(0) // TODO: call perted cob method here
|
|
|
-
|
|
|
+
|
|
|
// TODO: add logging?
|
|
|
let myMealCOB = max(0, carbs - myCarbsAbsorbed)
|
|
|
mealCOB = max(mealCOB, myMealCOB)
|
|
|
-
|
|
|
+
|
|
|
if myMealCOB < mealCOB {
|
|
|
carbsToRemove += treatment.carbs ?? 0
|
|
|
if var _nsCarbs = treatment.nsCarbs, nsCarbs >= 1 {
|
|
|
@@ -100,28 +105,28 @@ enum MealTotal {
|
|
|
journalCarbsToRemove += _journalCarbs
|
|
|
}
|
|
|
} else {
|
|
|
- carbsToRemove = 0;
|
|
|
- nsCarbsToRemove = 0;
|
|
|
- bwCarbsToRemove = 0;
|
|
|
+ carbsToRemove = 0
|
|
|
+ nsCarbsToRemove = 0
|
|
|
+ bwCarbsToRemove = 0
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// only include carbs actually used in calculating COB
|
|
|
carbs -= carbsToRemove
|
|
|
nsCarbs -= nsCarbsToRemove
|
|
|
bwCarbs -= bwCarbsToRemove
|
|
|
journalCarbs -= journalCarbsToRemove
|
|
|
-
|
|
|
+
|
|
|
// calculate the current deviation and steepest deviation downslope over the last hour
|
|
|
cobInputs.ciTime = time.timeIntervalSince1970
|
|
|
cobInputs.mealTime = TimeInterval(hours: Double(truncating: profile.maxMealAbsorptionTime as NSNumber))
|
|
|
-
|
|
|
+
|
|
|
// set a hard upper limit on COB to mitigate impact of erroneous or malicious carb entry
|
|
|
mealCOB = min(profile.maxCOB, mealCOB)
|
|
|
/// omiting maxCOB check here, the setting is not Optional in Swift and must be part of profile
|
|
|
-
|
|
|
+
|
|
|
// if currentDeviation is null or maxDeviation is 0, set mealCOB to 0 for zombie-carb safety
|
|
|
// TODO: make these adjustments once we have cob.js ported
|
|
|
// if (typeof(c.currentDeviation) === 'undefined' || c.currentDeviation === null) {
|
|
|
@@ -134,7 +139,7 @@ enum MealTotal {
|
|
|
// console.error("Warning: setting mealCOB to 0 because maxDeviation is 0 or undefined");
|
|
|
// mealCOB = 0;
|
|
|
// }
|
|
|
-
|
|
|
+
|
|
|
return ComputedCarbs(
|
|
|
carbs: carbs,
|
|
|
nsCarbs: nsCarbs,
|
|
|
@@ -152,4 +157,3 @@ enum MealTotal {
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
-
|