- Improve Pod state accuracy for basal profile & TBR

- Add certainty info about last bolus and temp basal to Pod state and display in OmnipodFragment
- Improve user notifications of delivery errors# Please enter the commit message for your changes. Lines starting
This commit is contained in:
Bart Sopers 2020-09-02 20:48:56 +02:00
parent 6b027b8360
commit b1abc55def
8 changed files with 245 additions and 139 deletions

View file

@ -37,6 +37,7 @@ public class InsertCannulaAction implements OmnipodAction<StatusResponse> {
}
if (podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.BASAL_INITIALIZED)) {
podStateManager.setBasalSchedule(initialBasalSchedule);
service.programInitialBasalSchedule(communicationService, podStateManager, initialBasalSchedule);
}

View file

@ -46,8 +46,6 @@ public class SetBasalScheduleAction implements OmnipodAction<StatusResponse> {
OmnipodMessage basalMessage = new OmnipodMessage(podStateManager.getAddress(), Arrays.asList(setBasal, extraCommand),
podStateManager.getMessageNumber());
StatusResponse statusResponse = communicationService.exchangeMessages(StatusResponse.class, podStateManager, basalMessage);
podStateManager.setBasalSchedule(basalSchedule);
return statusResponse;
return communicationService.exchangeMessages(StatusResponse.class, podStateManager, basalMessage);
}
}

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import java.util.Arrays;
@ -11,7 +10,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.SetInsulinScheduleCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.TempBasalExtraCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager;
import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager;
@ -45,8 +43,6 @@ public class SetTempBasalAction implements OmnipodAction<StatusResponse> {
new TempBasalExtraCommand(rate, duration, acknowledgementBeep, completionBeep, Duration.ZERO));
OmnipodMessage message = new OmnipodMessage(podStateManager.getAddress(), messageBlocks, podStateManager.getMessageNumber());
StatusResponse statusResponse = communicationService.exchangeMessages(StatusResponse.class, podStateManager, message);
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration);
return statusResponse;
return communicationService.exchangeMessages(StatusResponse.class, podStateManager, message);
}
}

View file

@ -212,6 +212,7 @@ public class OmnipodManager {
try {
executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podStateManager, schedule,
false, podStateManager.getScheduleOffset(), acknowledgementBeep)));
podStateManager.setBasalSchedule(schedule);
} catch (OmnipodException ex) {
if (ex.isCertainFailure()) {
if (!wasSuspended) {
@ -221,7 +222,9 @@ public class OmnipodManager {
}
// verifyDeliveryStatus will throw an exception if verification fails
if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) {
if (verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) {
podStateManager.setBasalSchedule(schedule);
} else {
if (!wasSuspended) {
throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but setting the new basal schedule did not", ex);
}
@ -262,6 +265,7 @@ public class OmnipodManager {
try {
executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(
podStateManager, rate, duration, acknowledgementBeep, completionBeep)));
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, true);
} catch (OmnipodException ex) {
if (ex.isCertainFailure()) {
if (cancelCurrentTbr) {
@ -271,13 +275,25 @@ public class OmnipodManager {
}
// verifyDeliveryStatus will throw an exception if verification fails
if (!verifyDeliveryStatus(DeliveryStatus.TEMP_BASAL_RUNNING, ex)) {
if (cancelCurrentTbr) {
throw new CommandFailedAfterChangingDeliveryStatusException("Failed to set new TBR while cancelling old TBR succeeded", ex);
}
try {
if (verifyDeliveryStatus(DeliveryStatus.TEMP_BASAL_RUNNING, ex)) {
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, true);
} else {
if (cancelCurrentTbr) {
throw new CommandFailedAfterChangingDeliveryStatusException("Failed to set new TBR while cancelling old TBR succeeded", ex);
}
ex.setCertainFailure(true);
throw ex;
ex.setCertainFailure(true);
throw ex;
}
} catch (OmnipodException ex2) {
if (!ex2.isCertainFailure()) {
// We're not sure that setting the new TBR failed, so we assume that it succeeded
// If it didn't, PodStateManager.updateFromResponse() will fix the state
// upon receiving the next StatusResponse
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, false);
}
throw ex2;
}
}
} finally {
@ -331,15 +347,16 @@ public class OmnipodManager {
commandDeliveryStatus = CommandDeliveryStatus.UNCERTAIN_FAILURE;
}
Duration bolusDuration = calculateBolusDuration(units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE);
Duration estimatedRemainingBolusDuration = bolusDuration.minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
DateTime estimatedBolusStartDate = DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
Duration estimatedBolusDuration = calculateBolusDuration(units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE);
Duration estimatedRemainingBolusDuration = estimatedBolusDuration.minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
DateTime startDate = DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
podStateManager.setLastBolus(startDate, units, estimatedRemainingBolusDuration);
podStateManager.setLastBolus(estimatedBolusStartDate, units, estimatedBolusDuration, commandDeliveryStatus == CommandDeliveryStatus.SUCCESS);
CompositeDisposable disposables = new CompositeDisposable();
if (progressIndicationConsumer != null) {
int numberOfProgressReports = Math.max(20, Math.min(100, (int) Math.ceil(units) * 10));
long progressReportInterval = estimatedRemainingBolusDuration.getMillis() / numberOfProgressReports;
@ -355,7 +372,7 @@ public class OmnipodManager {
SingleSubject<BolusDeliveryResult> bolusCompletionSubject = SingleSubject.create();
synchronized (bolusDataMutex) {
activeBolusData = new ActiveBolusData(units, startDate, bolusCompletionSubject, disposables);
activeBolusData = new ActiveBolusData(units, estimatedBolusStartDate, commandDeliveryStatus, bolusCompletionSubject, disposables);
}
// Return successful command execution AFTER storing activeBolusData
@ -380,7 +397,7 @@ public class OmnipodManager {
break;
}
} catch (PodFaultException ex) {
// Substract units not delivered in case of a Pod failure
// Subtract units not delivered in case of a Pod failure
bolusNotDelivered = ex.getFaultEvent().getBolusNotDelivered();
aapsLogger.debug(LTag.PUMPCOMM, "Caught PodFaultException in bolus completion verification", ex);
@ -428,7 +445,7 @@ public class OmnipodManager {
private void discardActiveBolusData(double bolusNotDelivered) {
synchronized (bolusDataMutex) {
double unitsDelivered = activeBolusData.getUnits() - bolusNotDelivered;
podStateManager.setLastBolus(activeBolusData.getStartDate(), unitsDelivered, new Duration(activeBolusData.getStartDate(), DateTime.now()));
podStateManager.setLastBolus(activeBolusData.getStartDate(), unitsDelivered, new Duration(activeBolusData.getStartDate(), DateTime.now()), activeBolusData.getCommandDeliveryStatus() == CommandDeliveryStatus.SUCCESS);
activeBolusData.getDisposables().dispose();
activeBolusData.getBolusCompletionSubject().onSuccess(new BolusDeliveryResult(unitsDelivered));
activeBolusData = null;
@ -465,8 +482,6 @@ public class OmnipodManager {
logStartingCommandExecution("setTime [acknowledgementBeeps=" + acknowledgementBeeps + "]");
try {
suspendDelivery(acknowledgementBeeps);
DateTimeZone oldTimeZone = podStateManager.getTimeZone();
try {
@ -476,20 +491,8 @@ public class OmnipodManager {
setBasalSchedule(podStateManager.getBasalSchedule(), acknowledgementBeeps);
} catch (OmnipodException ex) {
if (ex.isCertainFailure()) {
podStateManager.setTimeZone(oldTimeZone);
throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but resuming did not", ex);
}
try {
// verifyDeliveryStatus will throw an exception if verification fails
if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) {
throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but resuming did not", ex);
}
} catch (Exception ex2) {
podStateManager.setTimeZone(oldTimeZone);
throw ex2;
}
podStateManager.setTimeZone(oldTimeZone);
throw ex;
}
} finally {
logCommandExecutionFinished("setTime");
@ -620,13 +623,14 @@ public class OmnipodManager {
*/
private boolean verifyDeliveryStatus(DeliveryStatus expectedStatus, Throwable verificationCause) {
aapsLogger.debug(LTag.PUMPCOMM, "Attempting to verify delivery status (expected={})", expectedStatus);
for (int i = 0; 2 > i; i++) {
for (int i = 0; 3 > i; i++) {
try {
StatusResponse podStatus = getPodStatus();
aapsLogger.debug(LTag.PUMPCOMM, "Resolved delivery status (expected={}, actual={})", expectedStatus, podStatus.getDeliveryStatus());
return podStatus.getDeliveryStatus().equals(expectedStatus);
} catch (Exception ignored) {
// ignore and try to continue
} catch (Exception ex) {
aapsLogger.debug(LTag.PUMPCOMM, "Ignoring exception thrown in getPodStatus() during attempt to verify delivery status: {}: {}",
ex.getClass().getSimpleName(), ex.getMessage());
}
}
aapsLogger.warn(LTag.PUMPCOMM, "Failed to verify delivery status");
@ -694,12 +698,14 @@ public class OmnipodManager {
private static class ActiveBolusData {
private final double units;
private final DateTime startDate;
private final CommandDeliveryStatus commandDeliveryStatus;
private final SingleSubject<BolusDeliveryResult> bolusCompletionSubject;
private final CompositeDisposable disposables;
private ActiveBolusData(double units, DateTime startDate, SingleSubject<BolusDeliveryResult> bolusCompletionSubject, CompositeDisposable disposables) {
private ActiveBolusData(double units, DateTime startDate, CommandDeliveryStatus commandDeliveryStatus, SingleSubject<BolusDeliveryResult> bolusCompletionSubject, CompositeDisposable disposables) {
this.units = units;
this.startDate = startDate;
this.commandDeliveryStatus = commandDeliveryStatus;
this.bolusCompletionSubject = bolusCompletionSubject;
this.disposables = disposables;
}
@ -712,6 +718,10 @@ public class OmnipodManager {
return startDate;
}
CommandDeliveryStatus getCommandDeliveryStatus() {
return commandDeliveryStatus;
}
CompositeDisposable getDisposables() {
return disposables;
}

View file

@ -357,14 +357,24 @@ public abstract class PodStateManager {
return getSafe(() -> podState.getLastBolusDuration());
}
public final void setLastBolus(DateTime startTime, double amount, Duration duration) {
public final boolean isLastBolusCertain() {
Boolean certain = getSafe(() -> podState.isLastBolusCertain());
return certain == null || certain;
}
public final void setLastBolus(DateTime startTime, double amount, Duration duration, boolean certain) {
setAndStore(() -> {
podState.setLastBolusStartTime(startTime);
podState.setLastBolusAmount(amount);
podState.setLastBolusDuration(duration);
podState.setLastBolusCertain(certain);
});
}
public final boolean hasLastBolus() {
return getLastBolusAmount() != null && getLastBolusDuration() != null && getLastBolusStartTime() != null;
}
public final DateTime getTempBasalStartTime() {
return getSafe(() -> podState.getTempBasalStartTime());
}
@ -377,11 +387,16 @@ public abstract class PodStateManager {
return getSafe(() -> podState.getTempBasalDuration());
}
public final void setTempBasal(DateTime startTime, Double amount, Duration duration) {
setTempBasal(startTime, amount, duration, true);
public final boolean isTempBasalCertain() {
Boolean certain = getSafe(() -> podState.isTempBasalCertain());
return certain == null || certain;
}
public final void setTempBasal(DateTime startTime, Double amount, Duration duration, boolean store) {
public final void setTempBasal(DateTime startTime, Double amount, Duration duration, boolean certain) {
setTempBasal(startTime, amount, duration, certain, true);
}
public final void setTempBasal(DateTime startTime, Double amount, Duration duration, Boolean certain, boolean store) {
DateTime currentStartTime = getTempBasalStartTime();
Double currentAmount = getTempBasalAmount();
Duration currentDuration = getTempBasalDuration();
@ -390,6 +405,7 @@ public abstract class PodStateManager {
podState.setTempBasalStartTime(startTime);
podState.setTempBasalAmount(amount);
podState.setTempBasalDuration(duration);
podState.setTempBasalCertain(certain);
};
if (store) {
@ -401,10 +417,26 @@ public abstract class PodStateManager {
}
}
/**
* @return true when a Temp Basal is stored in the Pod Stated
* Please note that this could also be an expired Temp Basal. For an indication on whether or not
* a temp basal is actually running, use {@link #isTempBasalRunning() isTempBasalRunning()}
*/
public final boolean hasTempBasal() {
return getTempBasalAmount() != null && getTempBasalDuration() != null && getTempBasalStartTime() != null;
}
/**
* @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)
*/
public final boolean isTempBasalRunning() {
if (hasTempBasal()) {
DateTime tempBasalEndTime = getTempBasalStartTime().plus(getTempBasalDuration());
return DateTime.now().isBefore(tempBasalEndTime);
}
return false;
}
public final DeliveryStatus getLastDeliveryStatus() {
return getSafe(() -> podState.getLastDeliveryStatus());
}
@ -430,9 +462,13 @@ public abstract class PodStateManager {
podState.setReservoirLevel(statusResponse.getReservoirLevel());
podState.setTotalTicksDelivered(statusResponse.getTicksDelivered());
podState.setPodProgressStatus(statusResponse.getPodProgressStatus());
if (!statusResponse.getDeliveryStatus().isTbrRunning()) {
if (statusResponse.getDeliveryStatus().isTbrRunning()) {
if (!isTempBasalCertain() && isTempBasalRunning()) {
podState.setTempBasalCertain(true);
}
} else {
// Triggers {@link #onTbrChanged() onTbrChanged()} when appropriate
setTempBasal(null, null, null, false);
setTempBasal(null, null, null, true, false);
}
podState.setLastUpdatedFromResponse(DateTime.now());
});
@ -538,9 +574,11 @@ public abstract class PodStateManager {
private DateTime lastBolusStartTime;
private Double lastBolusAmount;
private Duration lastBolusDuration;
private Boolean lastBolusCertain;
private Double tempBasalAmount;
private DateTime tempBasalStartTime;
private Duration tempBasalDuration;
private Boolean tempBasalCertain;
private final Map<AlertSlot, AlertType> configuredAlerts = new HashMap<>();
private PodState(int address) {
@ -751,6 +789,14 @@ public abstract class PodStateManager {
this.lastBolusDuration = lastBolusDuration;
}
Boolean isLastBolusCertain() {
return lastBolusCertain;
}
void setLastBolusCertain(Boolean certain) {
this.lastBolusCertain = certain;
}
Double getTempBasalAmount() {
return tempBasalAmount;
}
@ -775,6 +821,14 @@ public abstract class PodStateManager {
this.tempBasalDuration = tempBasalDuration;
}
Boolean isTempBasalCertain() {
return tempBasalCertain;
}
void setTempBasalCertain(Boolean certain) {
this.tempBasalCertain = certain;
}
Map<AlertSlot, AlertType> getConfiguredAlerts() {
return configuredAlerts;
}

View file

@ -43,6 +43,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitReceive
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType;
@ -152,17 +153,15 @@ public class AapsOmnipodManager {
return new PumpEnactResult(injector).success(false).enacted(false).comment(getStringResource(R.string.omnipod_error_illegal_init_action_type, podInitActionType.name()));
}
long time = System.currentTimeMillis();
try {
Disposable disposable = delegate.pairAndPrime().subscribe(res -> //
handleSetupActionResult(podInitActionType, podInitReceiver, res, time, null));
handleSetupActionResult(podInitActionType, podInitReceiver, res, System.currentTimeMillis(), null));
return new PumpEnactResult(injector).success(true).enacted(true);
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
podInitReceiver.returnInitTaskStatus(podInitActionType, false, comment);
addFailureToHistory(time, PodHistoryEntryType.PAIR_AND_PRIME, comment);
addFailureToHistory(System.currentTimeMillis(), PodHistoryEntryType.PAIR_AND_PRIME, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
}
@ -172,8 +171,6 @@ public class AapsOmnipodManager {
return new PumpEnactResult(injector).success(false).enacted(false).comment(getStringResource(R.string.omnipod_error_illegal_init_action_type, podInitActionType.name()));
}
long time = System.currentTimeMillis();
try {
BasalSchedule basalSchedule;
try {
@ -182,7 +179,7 @@ public class AapsOmnipodManager {
throw new CommandInitializationException("Basal profile mapping failed", ex);
}
Disposable disposable = delegate.insertCannula(basalSchedule).subscribe(res -> //
handleSetupActionResult(podInitActionType, podInitReceiver, res, time, profile));
handleSetupActionResult(podInitActionType, podInitReceiver, res, System.currentTimeMillis(), profile));
rxBus.send(new EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED));
@ -192,36 +189,34 @@ public class AapsOmnipodManager {
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
podInitReceiver.returnInitTaskStatus(podInitActionType, false, comment);
addFailureToHistory(time, PodHistoryEntryType.FILL_CANNULA_SET_BASAL_PROFILE, comment);
addFailureToHistory(PodHistoryEntryType.FILL_CANNULA_SET_BASAL_PROFILE, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
}
public PumpEnactResult getPodStatus() {
long time = System.currentTimeMillis();
try {
StatusResponse statusResponse = delegate.getPodStatus();
addSuccessToHistory(time, PodHistoryEntryType.GET_POD_STATUS, statusResponse);
addSuccessToHistory(PodHistoryEntryType.GET_POD_STATUS, statusResponse);
return new PumpEnactResult(injector).success(true).enacted(false);
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
addFailureToHistory(time, PodHistoryEntryType.GET_POD_STATUS, comment);
addFailureToHistory(PodHistoryEntryType.GET_POD_STATUS, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
}
public PumpEnactResult deactivatePod(PodInitReceiver podInitReceiver) {
long time = System.currentTimeMillis();
try {
delegate.deactivatePod();
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
podInitReceiver.returnInitTaskStatus(PodInitActionType.DEACTIVATE_POD_WIZARD_STEP, false, comment);
addFailureToHistory(time, PodHistoryEntryType.DEACTIVATE_POD, comment);
addFailureToHistory(PodHistoryEntryType.DEACTIVATE_POD, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
addSuccessToHistory(time, PodHistoryEntryType.DEACTIVATE_POD, null);
addSuccessToHistory(PodHistoryEntryType.DEACTIVATE_POD, null);
createSuspendedFakeTbrIfNotExists();
@ -231,7 +226,6 @@ public class AapsOmnipodManager {
}
public PumpEnactResult setBasalProfile(Profile profile) {
long time = System.currentTimeMillis();
PodHistoryEntryType historyEntryType = podStateManager.isSuspended() ? PodHistoryEntryType.RESUME_DELIVERY : PodHistoryEntryType.SET_BASAL_SCHEDULE;
try {
@ -243,25 +237,24 @@ public class AapsOmnipodManager {
}
delegate.setBasalSchedule(basalSchedule, isBasalBeepsEnabled());
time = System.currentTimeMillis();
if (historyEntryType == PodHistoryEntryType.RESUME_DELIVERY) {
cancelSuspendedFakeTbrIfExists();
}
addSuccessToHistory(time, historyEntryType, profile.getBasalValues());
addSuccessToHistory(historyEntryType, profile.getBasalValues());
} catch (CommandFailedAfterChangingDeliveryStatusException ex) {
createSuspendedFakeTbrIfNotExists();
String comment = getStringResource(R.string.omnipod_error_set_basal_failed_delivery_suspended);
showErrorDialog(comment, R.raw.boluserror);
addFailureToHistory(time, historyEntryType, comment);
showNotification(comment, Notification.URGENT, R.raw.boluserror);
addFailureToHistory(historyEntryType, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
} catch (DeliveryStatusVerificationFailedException ex) {
String comment = getStringResource(R.string.omnipod_error_set_basal_failed_delivery_might_be_suspended);
showErrorDialog(comment, R.raw.boluserror);
addFailureToHistory(time, historyEntryType, comment);
showNotification(comment, Notification.URGENT, R.raw.boluserror);
addFailureToHistory(historyEntryType, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
addFailureToHistory(time, historyEntryType, comment);
addFailureToHistory(historyEntryType, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
@ -302,8 +295,11 @@ public class AapsOmnipodManager {
if (OmnipodManager.CommandDeliveryStatus.UNCERTAIN_FAILURE.equals(bolusCommandResult.getCommandDeliveryStatus())) {
// For safety reasons, we treat this as a bolus that has successfully been delivered, in order to prevent insulin overdose
showErrorDialog(getStringResource(R.string.omnipod_bolus_failed_uncertain), R.raw.boluserror);
if (detailedBolusInfo.isSMB) {
showNotification(getStringResource(R.string.omnipod_bolus_failed_uncertain_smb, detailedBolusInfo.insulin), Notification.URGENT, R.raw.boluserror);
} else {
showErrorDialog(getStringResource(R.string.omnipod_bolus_failed_uncertain), R.raw.boluserror);
}
}
detailedBolusInfo.date = bolusStarted.getTime();
@ -393,47 +389,56 @@ public class AapsOmnipodManager {
public PumpEnactResult setTemporaryBasal(TempBasalPair tempBasalPair) {
boolean beepsEnabled = isTbrBeepsEnabled();
long time = System.currentTimeMillis();
try {
delegate.setTemporaryBasal(PumpType.Insulet_Omnipod.determineCorrectBasalSize(tempBasalPair.getInsulinRate()), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), beepsEnabled, beepsEnabled);
time = System.currentTimeMillis();
} catch (CommandFailedAfterChangingDeliveryStatusException ex) {
String comment = getStringResource(R.string.omnipod_cancelled_old_tbr_failed_to_set_new);
addFailureToHistory(time, PodHistoryEntryType.SET_TEMPORARY_BASAL, comment);
addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment);
showNotification(comment, Notification.URGENT, null);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
} catch (DeliveryStatusVerificationFailedException ex) {
String comment = getStringResource(R.string.omnipod_error_set_temp_basal_failed_old_tbr_might_be_cancelled);
String comment;
if (ex.getExpectedStatus() == DeliveryStatus.TEMP_BASAL_RUNNING) {
// Happened after cancelling the old TBR, when attempting to set new TBR
comment = getStringResource(R.string.omnipod_error_set_temp_basal_failed_old_tbr_cancelled_new_might_have_failed);
long pumpId = addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment);
// Assume that setting the temp basal succeeded here, because in case it didn't succeed,
// The next StatusResponse that we receive will allow us to recover from the wrong state
// as we can see that the delivery status doesn't actually show that a TBR is running
// If we would assume that the TBR didn't succeed, we couldn't properly recover upon the next StatusResponse,
// as we could only see that the Pod is running a TBR, but we don't know the rate and duration as
// the Pod doesn't provide this information
addTempBasalTreatment(System.currentTimeMillis(), pumpId, tempBasalPair);
} else {
// Happened when attempting to cancel the old TBR
comment = getStringResource(R.string.omnipod_error_set_temp_basal_failed_old_tbr_might_be_cancelled);
addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment);
}
showNotification(comment, Notification.URGENT, R.raw.boluserror);
addFailureToHistory(time, PodHistoryEntryType.SET_TEMPORARY_BASAL, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
addFailureToHistory(time, PodHistoryEntryType.SET_TEMPORARY_BASAL, comment);
addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
long pumpId = addSuccessToHistory(time, PodHistoryEntryType.SET_TEMPORARY_BASAL, tempBasalPair);
long pumpId = addSuccessToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, tempBasalPair);
TemporaryBasal tempStart = new TemporaryBasal(injector) //
.date(time) //
.duration(tempBasalPair.getDurationMinutes()) //
.absolute(tempBasalPair.getInsulinRate()) //
.pumpId(pumpId)
.source(Source.PUMP);
activePlugin.getActiveTreatments().addToHistoryTempBasal(tempStart);
addTempBasalTreatment(System.currentTimeMillis(), pumpId, tempBasalPair);
return new PumpEnactResult(injector).success(true).enacted(true);
}
public PumpEnactResult cancelTemporaryBasal() {
long time = System.currentTimeMillis();
try {
delegate.cancelTemporaryBasal(isTbrBeepsEnabled());
addSuccessToHistory(time, PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, null);
addSuccessToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, null);
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
addFailureToHistory(time, PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, comment);
addFailureToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
@ -441,30 +446,27 @@ public class AapsOmnipodManager {
}
public PumpEnactResult acknowledgeAlerts() {
long time = System.currentTimeMillis();
try {
delegate.acknowledgeAlerts();
addSuccessToHistory(time, PodHistoryEntryType.ACKNOWLEDGE_ALERTS, null);
addSuccessToHistory(PodHistoryEntryType.ACKNOWLEDGE_ALERTS, null);
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
addFailureToHistory(time, PodHistoryEntryType.ACKNOWLEDGE_ALERTS, comment);
addFailureToHistory(PodHistoryEntryType.ACKNOWLEDGE_ALERTS, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
return new PumpEnactResult(injector).success(true).enacted(true);
}
public PumpEnactResult suspendDelivery() {
long time = System.currentTimeMillis();
try {
delegate.suspendDelivery(isBasalBeepsEnabled());
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
addFailureToHistory(time, PodHistoryEntryType.SUSPEND_DELIVERY, comment);
addFailureToHistory(PodHistoryEntryType.SUSPEND_DELIVERY, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
addSuccessToHistory(time, PodHistoryEntryType.SUSPEND_DELIVERY, null);
addSuccessToHistory(PodHistoryEntryType.SUSPEND_DELIVERY, null);
createSuspendedFakeTbrIfNotExists();
@ -473,25 +475,23 @@ public class AapsOmnipodManager {
// Updates the pods current time based on the device timezone and the pod's time zone
public PumpEnactResult setTime() {
long time = System.currentTimeMillis();
try {
delegate.setTime(isBasalBeepsEnabled());
time = System.currentTimeMillis();
addSuccessToHistory(time, PodHistoryEntryType.SET_TIME, null);
addSuccessToHistory(PodHistoryEntryType.SET_TIME, null);
} catch (CommandFailedAfterChangingDeliveryStatusException ex) {
createSuspendedFakeTbrIfNotExists();
String comment = getStringResource(R.string.omnipod_error_set_time_failed_delivery_suspended);
showErrorDialog(comment, R.raw.boluserror);
addFailureToHistory(time, PodHistoryEntryType.SET_TIME, comment);
showNotification(comment, Notification.URGENT, R.raw.boluserror);
addFailureToHistory(PodHistoryEntryType.SET_TIME, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
} catch (DeliveryStatusVerificationFailedException ex) {
String comment = getStringResource(R.string.omnipod_error_set_time_failed_delivery_might_be_suspended);
showErrorDialog(comment, R.raw.boluserror);
addFailureToHistory(time, PodHistoryEntryType.SET_TIME, comment);
showNotification(comment, Notification.URGENT, R.raw.boluserror);
addFailureToHistory(PodHistoryEntryType.SET_TIME, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
} catch (Exception ex) {
String comment = handleAndTranslateException(ex);
addFailureToHistory(time, PodHistoryEntryType.SET_TIME, comment);
addFailureToHistory(PodHistoryEntryType.SET_TIME, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
@ -587,13 +587,12 @@ public class AapsOmnipodManager {
}
public void reportCancelledTbr() {
long time = System.currentTimeMillis();
aapsLogger.debug(LTag.PUMP, "Reporting cancelled TBR to AAPS");
long pumpId = addSuccessToHistory(time, PodHistoryEntryType.CANCEL_TEMPORARY_BASAL_BY_DRIVER, null);
long pumpId = addSuccessToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL_BY_DRIVER, null);
TemporaryBasal temporaryBasal = new TemporaryBasal(injector) //
.date(time) //
.date(System.currentTimeMillis()) //
.duration(0) //
.source(Source.PUMP) //
.pumpId(pumpId);
@ -601,10 +600,29 @@ public class AapsOmnipodManager {
activePlugin.getActiveTreatments().addToHistoryTempBasal(temporaryBasal);
}
private void addTempBasalTreatment(long time, long pumpId, TempBasalPair tempBasalPair) {
TemporaryBasal tempStart = new TemporaryBasal(injector) //
.date(time) //
.duration(tempBasalPair.getDurationMinutes()) //
.absolute(tempBasalPair.getInsulinRate()) //
.pumpId(pumpId)
.source(Source.PUMP);
activePlugin.getActiveTreatments().addToHistoryTempBasal(tempStart);
}
private long addSuccessToHistory(PodHistoryEntryType entryType, Object data) {
return addSuccessToHistory(System.currentTimeMillis(), entryType, data);
}
private long addSuccessToHistory(long requestTime, PodHistoryEntryType entryType, Object data) {
return addToHistory(requestTime, entryType, data, true);
}
private long addFailureToHistory(PodHistoryEntryType entryType, Object data) {
return addFailureToHistory(System.currentTimeMillis(), entryType, data);
}
private long addFailureToHistory(long requestTime, PodHistoryEntryType entryType, Object data) {
return addToHistory(requestTime, entryType, data, false);
}

View file

@ -205,6 +205,8 @@ class OmnipodFragment : DaggerFragment() {
private fun updateOmnipodStatus() {
updateLastConnection()
updateLastBolus()
updateTempBasal()
updatePodStatus()
val errors = ArrayList<String>();
@ -228,8 +230,6 @@ class OmnipodFragment : DaggerFragment() {
omnipod_base_basal_rate.text = PLACEHOLDER
omnipod_total_delivered.text = PLACEHOLDER
omnipod_reservoir.text = PLACEHOLDER
omnipod_temp_basal.text = PLACEHOLDER
omnipod_last_bolus.text = PLACEHOLDER
omnipod_pod_active_alerts.text = PLACEHOLDER
} else {
omnipod_pod_address.text = podStateManager.address.toString()
@ -248,13 +248,6 @@ class OmnipodFragment : DaggerFragment() {
errors.add(resourceHelper.gs(R.string.omnipod_pod_status_pod_fault_description, faultEventCode.value, faultEventCode.name))
}
// last bolus
omnipod_last_bolus.text = if (podStateManager.lastBolusStartTime != null && podStateManager.lastBolusAmount != null) {
resourceHelper.gs(R.string.omnipod_last_bolus, omnipodPumpPlugin.model().determineCorrectBolusSize(podStateManager.lastBolusAmount), resourceHelper.gs(R.string.insulin_unit_shortname), readableDuration(podStateManager.lastBolusStartTime))
} else {
PLACEHOLDER
}
val now = DateTime.now()
// base basal rate
@ -264,22 +257,6 @@ class OmnipodFragment : DaggerFragment() {
PLACEHOLDER
}
// Temp basal
val lastTempBasalStartTime = podStateManager.tempBasalStartTime;
val lastTempBasalAmount = podStateManager.tempBasalAmount
val lastTempBasalDuration = podStateManager.tempBasalDuration;
if (lastTempBasalStartTime != null && lastTempBasalAmount != null && lastTempBasalDuration != null) {
val endTime = lastTempBasalStartTime.plus(lastTempBasalDuration);
val minutesRunning = Duration(lastTempBasalStartTime, now).standardMinutes
omnipod_temp_basal.text = if (endTime.isAfter(now)) {
resourceHelper.gs(R.string.omnipod_temp_basal, lastTempBasalAmount, dateUtil.timeString(lastTempBasalStartTime.millis), minutesRunning, lastTempBasalDuration.standardMinutes)
} else {
PLACEHOLDER
}
} else {
omnipod_temp_basal.text = PLACEHOLDER
}
// total delivered
omnipod_total_delivered.text = if (podStateManager.isPodActivationCompleted && podStateManager.totalInsulinDelivered != null) {
resourceHelper.gs(R.string.omnipod_total_delivered, podStateManager.totalInsulinDelivered - OmnipodConstants.POD_SETUP_UNITS);
@ -371,6 +348,55 @@ class OmnipodFragment : DaggerFragment() {
omnipod_pod_status.setTextColor(podStatusColor)
}
private fun updateLastBolus() {
if (podStateManager.isPodActivationCompleted && podStateManager.hasLastBolus()) {
var text = resourceHelper.gs(R.string.omnipod_last_bolus, omnipodPumpPlugin.model().determineCorrectBolusSize(podStateManager.lastBolusAmount), resourceHelper.gs(R.string.insulin_unit_shortname), readableDuration(podStateManager.lastBolusStartTime))
val textColor: Int
if (podStateManager.isLastBolusCertain) {
textColor = Color.WHITE
} else {
textColor = Color.RED
text += " (" + resourceHelper.gs(R.string.omnipod_uncertain) + ")"
}
omnipod_last_bolus.text = text;
omnipod_last_bolus.setTextColor(textColor)
} else {
omnipod_last_bolus.text = PLACEHOLDER
omnipod_last_bolus.setTextColor(Color.WHITE)
}
}
private fun updateTempBasal() {
if (podStateManager.isPodActivationCompleted && podStateManager.isTempBasalRunning) {
val now = DateTime.now()
val startTime = podStateManager.tempBasalStartTime;
val amount = podStateManager.tempBasalAmount
val duration = podStateManager.tempBasalDuration;
val minutesRunning = Duration(startTime, now).standardMinutes
var text: String
val textColor: Int
text = resourceHelper.gs(R.string.omnipod_temp_basal, amount, dateUtil.timeString(startTime.millis), minutesRunning, duration.standardMinutes)
if (podStateManager.isTempBasalCertain) {
textColor = Color.WHITE
} else {
textColor = Color.RED
text += " (" + resourceHelper.gs(R.string.omnipod_uncertain) + ")"
}
omnipod_temp_basal.text = text;
omnipod_temp_basal.setTextColor(textColor)
} else {
omnipod_temp_basal.text = PLACEHOLDER
omnipod_temp_basal.setTextColor(Color.WHITE)
}
}
private fun updateQueueStatus() {
if (isQueueEmpty()) {
omnipod_queue.visibility = View.GONE

View file

@ -133,12 +133,14 @@
<string name="omnipod_alert_shutdown_imminent">Shutdown is imminent</string>
<string name="omnipod_alert_low_reservoir">Low reservoir</string>
<string name="omnipod_alert_unknown_alert">Unknown alert</string>
<string name="omnipod_error_set_basal_failed_delivery_might_be_suspended">Setting basal profile might have failed. Delivery might be suspended! Please refresh Pod status and resume delivery from the Omnipod tab if needed.</string>
<string name="omnipod_error_set_basal_failed_delivery_suspended">Setting basal profile failed. Delivery is suspended! Please resume delivery from the Omnipod tab.</string>
<string name="omnipod_error_set_temp_basal_failed_old_tbr_might_be_cancelled">Setting temp basal might have failed. If a temp basal was already running, it might have been cancelled without AndroidAPS being aware!</string>
<string name="omnipod_error_set_time_failed_delivery_might_be_suspended">Setting time might have failed. Delivery might be suspended! Please refresh Pod status and resume delivery from the Omnipod tab if needed.</string>
<string name="omnipod_error_set_time_failed_delivery_suspended">Setting time failed. Delivery is suspended! Please resume delivery from the Omnipod tab.</string>
<string name="omnipod_bolus_failed_uncertain">Unable to verify whether the bolus succeeded. Please verify that your Pod is bolusing or cancel the bolus.</string>
<string name="omnipod_error_set_basal_failed_delivery_might_be_suspended">Setting basal profile might have failed. Delivery might be suspended! Please manually refresh the Pod status from the Omnipod tab and resume delivery if needed.</string>
<string name="omnipod_error_set_basal_failed_delivery_suspended">Setting basal profile failed. Delivery is suspended! Please manually resume delivery from the Omnipod tab.</string>
<string name="omnipod_error_set_temp_basal_failed_old_tbr_might_be_cancelled">Setting temp basal failed. If a temp basal was previously running, it might have been cancelled. Please manually refresh the Pod status from the Omnipod tab.</string>
<string name="omnipod_error_set_temp_basal_failed_old_tbr_cancelled_new_might_have_failed">Setting temp might have basal failed. If a temp basal was previously running, it has been cancelled. Please manually refresh the Pod status from the Omnipod tab.</string>
<string name="omnipod_error_set_time_failed_delivery_might_be_suspended">Setting time might have failed. Delivery might be suspended! Please manually refresh the Pod status from the Omnipod tab and resume delivery if needed.</string>
<string name="omnipod_error_set_time_failed_delivery_suspended">Setting time failed. Delivery is suspended! Please manually resume delivery from the Omnipod tab.</string>
<string name="omnipod_bolus_failed_uncertain">Unable to verify whether the bolus succeeded. Please manually verify that your Pod is bolusing by listening to clicks. <b>If you are sure that the bolus didn\'t succeed, you should manually delete the bolus entry from Treatments, even if you click \'Cancel bolus\' now!</b></string>
<string name="omnipod_bolus_failed_uncertain_smb">Unable to verify whether SMB bolus (%1$.2f U) succeeded. <b>If you are sure that the Bolus didn\'t succeed, you should manually delete the SMB entry from Treatments.</b></string>
<string name="omnipod_rl_stats">RL stats</string>
<string name="omnipod_read_pulse_log_short">Pulse log</string>
<string name="omnipod_pod_lot">LOT</string>
@ -165,6 +167,7 @@
<string name="omnipod_cancelled_old_tbr_failed_to_set_new">Cancelled the old temporary basal, but failed to set new temporary basal</string>
<string name="omnipod_cmd_set_fake_suspended_tbr">Set fake temporary basal because the Pod is suspended</string>
<string name="omnipod_cmd_cancel_fake_suspended_tbr">Cancel fake temporary basal that was created because the Pod was suspended</string>
<string name="omnipod_uncertain">uncertain</string>
<plurals name="omnipod_minutes">
<item quantity="one">%1$d minute</item>