Add async feedback to pod init steps

This commit is contained in:
Bart Sopers 2019-11-27 22:05:40 +01:00
parent 5b3ca232e9
commit f2615d977b
5 changed files with 161 additions and 48 deletions

View file

@ -1,7 +1,5 @@
package info.nightscout.androidaps.plugins.pump.omnipod.comm;
import android.os.SystemClock;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
@ -15,7 +13,6 @@ import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.AcknowledgeAlertsAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.BolusAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.CancelDeliveryAction;
@ -23,7 +20,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.DeactivatePod
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.GetPodInfoAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.GetStatusAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.InsertCannulaAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.OmnipodAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.PairAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.PrimeAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.SetBasalScheduleAction;
@ -43,6 +39,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
import info.nightscout.androidaps.utils.SP;
public class OmnipodManager {
private static final int SETUP_ACTION_VERIFICATION_TRIES = 3;
protected final OmnipodCommunicationService communicationService;
protected PodSessionState podState;
@ -54,7 +52,37 @@ public class OmnipodManager {
this.podState = podState;
}
public PumpEnactResult insertCannula(Profile profile) {
// Returns a PumpEnactResult which describes whether or not all commands have been sent successfully
// After priming should have finished (55 seconds), the pod state is verified.
// The result of that verification is passed to the SetupActionResultHandler
public PumpEnactResult pairAndPrime(SetupActionResultHandler resultHandler) {
try {
if (podState == null) {
podState = communicationService.executeAction(new PairAction(new PairService()));
}
if (podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) {
communicationService.executeAction(new PrimeAction(new PrimeService(), podState));
executeDelayed(() -> verifySetupAction(statusResponse -> PrimeAction.updatePrimingStatus(podState, statusResponse), //
SetupProgress.PRIMING_FINISHED, resultHandler), //
OmnipodConst.POD_PRIME_DURATION);
} else {
// TODO use string resource
return new PumpEnactResult().success(false).enacted(false).comment("Illegal setup state: " + podState.getSetupProgress().name());
}
} catch (Exception ex) {
// TODO distinguish between certain and uncertain failures
// TODO user friendly error messages (string resources)
return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage());
}
return new PumpEnactResult().success(true).enacted(true);
}
// Returns a PumpEnactResult which describes whether or not all commands have been sent successfully
// After inserting the cannula should have finished (10 seconds), the pod state is verified.
// The result of that verification is passed to the SetupActionResultHandler
public PumpEnactResult insertCannula(Profile profile, SetupActionResultHandler resultHandler) {
if (podState == null || podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) {
// TODO use string resource
return new PumpEnactResult().success(false).enacted(false).comment("Pod should be paired and primed first");
@ -67,39 +95,9 @@ public class OmnipodManager {
communicationService.executeAction(new InsertCannulaAction(new InsertCannulaService(), podState,
BasalScheduleMapper.mapProfileToBasalSchedule(profile)));
executeDelayed(() -> {
// TODO improve: repeat get status when it fails and handle unexpected statuses
// TODO give user feedback when priming finished (or somehow failed)
StatusResponse delayedStatusResponse = communicationService.executeAction(new GetStatusAction(podState));
InsertCannulaAction.updateCannulaInsertionStatus(podState, delayedStatusResponse);
}, OmnipodConst.POD_CANNULA_INSERTION_DURATION);
} catch (Exception ex) {
// TODO distinguish between certain and uncertain failures
// TODO user friendly error messages (string resources)
return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage());
}
return new PumpEnactResult().success(true).enacted(true);
}
public PumpEnactResult pairAndPrime() {
try {
if (podState == null) {
podState = communicationService.executeAction(new PairAction(new PairService()));
}
if (podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) {
communicationService.executeAction(new PrimeAction(new PrimeService(), podState));
executeDelayed(() -> {
// TODO improve: repeat get status when it fails and handle unexpected statuses
// TODO give user feedback when priming finished (or somehow failed)
StatusResponse delayedStatusResponse = communicationService.executeAction(new GetStatusAction(podState));
PrimeAction.updatePrimingStatus(podState, delayedStatusResponse);
}, OmnipodConst.POD_PRIME_DURATION);
} else {
// TODO use string resource
return new PumpEnactResult().success(false).enacted(false).comment("Illegal setup state: " + podState.getSetupProgress().name());
}
executeDelayed(() -> verifySetupAction(statusResponse -> InsertCannulaAction.updateCannulaInsertionStatus(podState, statusResponse), //
SetupProgress.COMPLETED, resultHandler),
OmnipodConst.POD_CANNULA_INSERTION_DURATION);
} catch (Exception ex) {
// TODO distinguish between certain and uncertain failures
// TODO user friendly error messages (string resources)
@ -357,4 +355,35 @@ public class OmnipodManager {
public PodSessionState getPodState() {
return this.podState;
}
private void verifySetupAction(StatusResponseHandler statusResponseHandler, SetupProgress expectedSetupProgress, SetupActionResultHandler resultHandler) {
SetupActionResult result = null;
for (int i = 0; SETUP_ACTION_VERIFICATION_TRIES > i; i++) {
try {
StatusResponse delayedStatusResponse = communicationService.executeAction(new GetStatusAction(podState));
statusResponseHandler.handle(delayedStatusResponse);
if (podState.getSetupProgress().equals(expectedSetupProgress)) {
result = new SetupActionResult(SetupActionResult.ResultType.SUCCESS);
break;
} else {
result = new SetupActionResult(SetupActionResult.ResultType.FAILURE) //
.setupProgress(podState.getSetupProgress());
break;
}
} catch (Exception ex) {
result = new SetupActionResult(SetupActionResult.ResultType.VERIFICATION_FAILURE) //
.exception(ex);
}
}
if (resultHandler != null) {
resultHandler.handle(result);
}
}
@FunctionalInterface
private interface StatusResponseHandler {
void handle(StatusResponse podState);
}
}

View file

@ -0,0 +1,61 @@
package info.nightscout.androidaps.plugins.pump.omnipod.comm;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.SetupProgress;
public class SetupActionResult {
private final ResultType resultType;
private String message;
private Exception exception;
private SetupProgress setupProgress;
public SetupActionResult(ResultType resultType) {
this.resultType = resultType;
}
public SetupActionResult message(String message) {
this.message = message;
return this;
}
public SetupActionResult exception(Exception ex) {
exception = ex;
return this;
}
public SetupActionResult setupProgress(SetupProgress setupProgress) {
this.setupProgress = setupProgress;
return this;
}
public ResultType getResultType() {
return resultType;
}
public String getMessage() {
return message;
}
public Exception getException() {
return exception;
}
public SetupProgress getSetupProgress() {
return setupProgress;
}
public enum ResultType {
SUCCESS(true),
VERIFICATION_FAILURE(false),
FAILURE(false);
private final boolean success;
ResultType(boolean success) {
this.success = success;
}
public boolean isSuccess() {
return success;
}
}
}

View file

@ -0,0 +1,6 @@
package info.nightscout.androidaps.plugins.pump.omnipod.comm;
@FunctionalInterface
public interface SetupActionResultHandler {
void handle(SetupActionResult result);
}

View file

@ -15,7 +15,7 @@ public enum PodProgressStatus {
TWO_NOT_USED_BUT_IN_33((byte) 0x0b),
THREE_NOT_USED_BUT_IN_33((byte) 0x0c),
ERROR_EVENT_LOGGED_SHUTTING_DOWN((byte) 0x0d),
DELAYED_PRIME((byte) 0x0e),
a((byte) 0x0e),
INACTIVE((byte) 0x0f);
private byte value;

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.comm;
import org.jetbrains.annotations.Nullable;
import org.joda.time.DateTime;
import info.nightscout.androidaps.data.Profile;
@ -8,6 +9,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodManager;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.SetupActionResult;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.OmnipodAction;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommunicationManagerInterface;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType;
@ -36,20 +38,23 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
instance = this;
}
@Override
public PumpEnactResult initPod(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, Profile profile) {
if (PodInitActionType.PairAndPrimeWizardStep.equals(podInitActionType)) {
PumpEnactResult result = delegate.pairAndPrime();
podInitReceiver.returnInitTaskStatus(podInitActionType, result.success, (result.success ? null : result.comment));
PumpEnactResult result = delegate.pairAndPrime(res -> //
podInitReceiver.returnInitTaskStatus(podInitActionType, res.getResultType().isSuccess(), createCommentForSetupActionResult(res)));
if(!result.success) {
podInitReceiver.returnInitTaskStatus(podInitActionType, false, result.comment);
}
return result;
} else if (PodInitActionType.FillCannulaSetBasalProfileWizardStep.equals(podInitActionType)) {
// FIXME we need a basal profile here
PumpEnactResult result = delegate.insertCannula(profile);
podInitReceiver.returnInitTaskStatus(podInitActionType, result.success, (result.success ? null : result.comment));
if (result.success) {
PumpEnactResult result = delegate.insertCannula(profile, res -> {
podInitReceiver.returnInitTaskStatus(podInitActionType, res.getResultType().isSuccess(), createCommentForSetupActionResult(res));
OmnipodUtil.setPodSessionState(delegate.getPodState());
RxBus.INSTANCE.send(new EventOmnipodPumpValuesChanged());
});
if (!result.success) {
podInitReceiver.returnInitTaskStatus(podInitActionType, false, result.comment);
}
return result;
}
@ -75,8 +80,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
return result;
}
@Override
public PumpEnactResult setBasalProfile(Profile basalProfile) {
return delegate.setBasalProfile(basalProfile);
@ -170,4 +173,18 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
}
@Nullable
private String createCommentForSetupActionResult(SetupActionResult res) {
String comment = null;
switch(res.getResultType()) {
case FAILURE:
comment = "Unexpected setup progress: "+ res.getSetupProgress();
break;
case VERIFICATION_FAILURE:
comment = "Verification failed: "+ res.getException().getClass().getSimpleName() +": "+ res.getException().getMessage();
break;
}
return comment;
}
}