Take Basal into account when calculating bolus duration

This commit is contained in:
Bart Sopers 2020-09-09 17:04:39 +02:00
parent 5f28740068
commit e891f26be0
3 changed files with 63 additions and 18 deletions

View file

@ -21,10 +21,8 @@ public class OmnipodConstants {
public static final Duration AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION = Duration.millis(1500);
public static final Duration SERVICE_DURATION = Duration.standardHours(80);
public static final Duration EXPIRATION_ADVISORY_WINDOW = Duration.standardHours(9);
public static final Duration END_OF_SERVICE_IMMINENT_WINDOW = Duration.standardHours(1);
public static final Duration NOMINAL_POD_LIFE = Duration.standardHours(72);
public static final double LOW_RESERVOIR_ALERT = 20.0;
public static final double POD_PRIME_BOLUS_UNITS = 2.6;
public static final double POD_CANNULA_INSERTION_BOLUS_UNITS = 0.5;

View file

@ -126,9 +126,9 @@ public class OmnipodManager {
logCommandExecutionFinished("pairAndPrime");
}
long delayInSeconds = calculateBolusDuration(OmnipodConstants.POD_PRIME_BOLUS_UNITS, OmnipodConstants.POD_PRIMING_DELIVERY_RATE).getStandardSeconds();
long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_PRIME_BOLUS_UNITS, OmnipodConstants.POD_PRIMING_DELIVERY_RATE).getMillis();
return Single.timer(delayInSeconds, TimeUnit.SECONDS) //
return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) //
.map(o -> verifySetupAction(PodProgressStatus.PRIMING_COMPLETED)) //
.observeOn(Schedulers.io());
}
@ -154,9 +154,9 @@ public class OmnipodManager {
logCommandExecutionFinished("insertCannula");
}
long delayInSeconds = calculateBolusDuration(OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS, OmnipodConstants.POD_CANNULA_INSERTION_DELIVERY_RATE).getStandardSeconds();
long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS, OmnipodConstants.POD_CANNULA_INSERTION_DELIVERY_RATE).getMillis();
return Single.timer(delayInSeconds, TimeUnit.SECONDS) //
return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) //
.map(o -> verifySetupAction(PodProgressStatus.ABOVE_FIFTY_UNITS)) //
.observeOn(Schedulers.io());
}
@ -367,7 +367,7 @@ public class OmnipodManager {
}
DateTime estimatedBolusStartDate = DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
Duration estimatedBolusDuration = calculateBolusDuration(units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE);
Duration estimatedBolusDuration = calculateEstimatedBolusDuration(estimatedBolusStartDate, units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE);
Duration estimatedRemainingBolusDuration = estimatedBolusDuration.minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
podStateManager.setLastBolus(estimatedBolusStartDate, units, estimatedBolusDuration, commandDeliveryStatus == CommandDeliveryStatus.SUCCESS);
@ -376,7 +376,7 @@ public class OmnipodManager {
if (progressIndicationConsumer != null) {
int numberOfProgressReports = Math.max(20, Math.min(100, (int) Math.ceil(units) * 10));
long numberOfProgressReports = Math.max(10, Math.min(100, estimatedRemainingBolusDuration.getStandardSeconds()));
long progressReportInterval = estimatedRemainingBolusDuration.getMillis() / numberOfProgressReports;
disposables.add(Flowable.intervalRange(0, numberOfProgressReports + 1, 0, progressReportInterval, TimeUnit.MILLISECONDS) //
@ -664,14 +664,27 @@ public class OmnipodManager {
aapsLogger.debug(LTag.PUMPCOMM, "Command execution finished for action: " + action);
}
private static Duration calculateBolusDuration(double units, double deliveryRate) {
// TODO take current (temp) basal into account
// Be aware that the Pod possibly doesn't have a Basal Schedule yet
return Duration.standardSeconds((long) Math.ceil(units / deliveryRate));
private Duration calculateEstimatedBolusDuration(DateTime startTime, double units, double deliveryRateInUnitsPerSecond) {
if (!podStateManager.isPodActivationCompleted()) {
// No basal or temp basal is active yet
return Duration.standardSeconds((long) Math.ceil(units / deliveryRateInUnitsPerSecond));
}
public static Duration calculateBolusDuration(double units) {
return calculateBolusDuration(units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE);
double pulseIntervalInSeconds = OmnipodConstants.POD_PULSE_SIZE / deliveryRateInUnitsPerSecond;
long numberOfPulses = Math.round(units / OmnipodConstants.POD_PULSE_SIZE);
double totalEstimatedDurationInSeconds = 0D;
for (int i = 0; numberOfPulses > i; i++) {
DateTime estimatedTimeAtPulse = startTime.plusMillis((int) (totalEstimatedDurationInSeconds * 1000));
double effectiveBasalRateAtPulse = podStateManager.getEffectiveBasalRateAt(estimatedTimeAtPulse);
double effectivePulsesPerHourAtPulse = effectiveBasalRateAtPulse / OmnipodConstants.POD_PULSE_SIZE;
double effectiveBasalPulsesPerSecondAtPulse = effectivePulsesPerHourAtPulse / 3600;
double effectiveBasalPulsesPerBolusPulse = pulseIntervalInSeconds * effectiveBasalPulsesPerSecondAtPulse;
totalEstimatedDurationInSeconds += pulseIntervalInSeconds * (1 + effectiveBasalPulsesPerBolusPulse);
}
return Duration.millis(Math.round(totalEstimatedDurationInSeconds * 1000));
}
public static boolean isCertainFailure(Exception ex) {

View file

@ -427,16 +427,50 @@ public abstract class PodStateManager {
}
/**
* @return true when a Temp Basal is stored in the Pod Stated and this temp basal is currently running (based on start time and duration)
* @return true when a Temp Basal is stored in the Pod State and this temp basal is currently running (based on start time and duration)
*/
public final boolean isTempBasalRunning() {
return isTempBasalRunningAt(DateTime.now());
}
/**
* @return true when a Temp Basal is stored in the Pod State and this temp basal is running at the given time (based on start time and duration)
*/
public final boolean isTempBasalRunningAt(DateTime time) {
if (hasTempBasal()) {
DateTime tempBasalEndTime = getTempBasalStartTime().plus(getTempBasalDuration());
return DateTime.now().isBefore(tempBasalEndTime);
DateTime tempBasalStartTime = getTempBasalStartTime();
DateTime tempBasalEndTime = tempBasalStartTime.plus(getTempBasalDuration());
return (time.isAfter(tempBasalStartTime) || time.isEqual(tempBasalStartTime)) && time.isBefore(tempBasalEndTime);
}
return false;
}
/**
* @return the current effective basal rate (taking Pod suspension, TBR, and basal profile into account)
*/
public final double getEffectiveBasalRate() {
if (isSuspended()) {
return 0d;
}
return getEffectiveBasalRateAt(DateTime.now());
}
/**
* @return the effective basal rate at the given time (taking TBR, and basal profile into account)
* Suspension is not taken into account as we don't keep historic data of that
*/
public final double getEffectiveBasalRateAt(DateTime time) {
BasalSchedule basalSchedule = getSafe(() -> podState.getBasalSchedule());
if (basalSchedule == null) {
return 0d;
}
if (isTempBasalRunningAt(time)) {
return getTempBasalAmount();
}
Duration offset = new Duration(time.withTimeAtStartOfDay(), time);
return basalSchedule.rateAt(offset);
}
public final DeliveryStatus getLastDeliveryStatus() {
return getSafe(() -> podState.getLastDeliveryStatus());
}