Make sure that after restart, bolus treatment is added when the app is killed during a bolus

This commit is contained in:
Bart Sopers 2020-08-20 02:20:05 +02:00
parent 557e5ee0e9
commit 0e9adda3a4
5 changed files with 79 additions and 64 deletions

View file

@ -30,6 +30,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
@ -61,12 +62,14 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodPumpPluginInt
import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodStatusRequest;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateManager;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodPumpStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.comm.AapsOmnipodManager;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.ui.OmnipodUIComm;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.ui.OmnipodUITask;
import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodPumpValuesChanged;
import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodRefreshButtonState;
import info.nightscout.androidaps.plugins.pump.omnipod.service.RileyLinkOmnipodService;
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.Round;
@ -87,6 +90,8 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
private final RileyLinkServiceData rileyLinkServiceData;
private final ServiceTaskExecutor serviceTaskExecutor;
private final OmnipodPumpStatus omnipodPumpStatus;
private final AapsOmnipodManager aapsOmnipodManager;
private final OmnipodUtil omnipodUtil;
private CompositeDisposable disposable = new CompositeDisposable();
@ -95,7 +100,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
protected boolean isRefresh = false;
private boolean isInitialized = false;
private RileyLinkOmnipodService rileyLinkOmnipodService;
private boolean isBusy = false;
@ -119,13 +123,14 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
SP sp,
OmnipodPumpStatus omnipodPumpStatus,
PodStateManager podStateManager,
AapsOmnipodManager aapsOmnipodManager,
CommandQueueProvider commandQueue,
FabricPrivacy fabricPrivacy,
RileyLinkServiceData rileyLinkServiceData,
ServiceTaskExecutor serviceTaskExecutor,
DateUtil dateUtil
DateUtil dateUtil,
OmnipodUtil omnipodUtil
) {
super(new PluginDescription() //
.mainType(PluginType.PUMP) //
.fragmentClass(OmnipodFragment.class.getName()) //
@ -134,26 +139,25 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
.preferencesId(R.xml.pref_omnipod) //
.description(R.string.description_pump_omnipod), //
PumpType.Insulet_Omnipod,
injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil
);
injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil);
this.podStateManager = podStateManager;
this.rileyLinkServiceData = rileyLinkServiceData;
this.serviceTaskExecutor = serviceTaskExecutor;
this.omnipodPumpStatus = omnipodPumpStatus;
this.aapsOmnipodManager = aapsOmnipodManager;
this.omnipodUtil = omnipodUtil;
displayConnectionMessages = false;
this.serviceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
aapsLogger.debug(LTag.PUMP, "RileyLinkOmnipodService is disconnected");
rileyLinkOmnipodService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aapsLogger.debug(LTag.PUMP, "RileyLinkOmnipodService is connected");
RileyLinkOmnipodService.LocalBinder mLocalBinder = (RileyLinkOmnipodService.LocalBinder) service;
rileyLinkOmnipodService = mLocalBinder.getServiceInstance();
@ -172,7 +176,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
}).start();
}
};
}
public PodStateManager getPodStateManager() {
@ -199,6 +202,27 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
rileyLinkOmnipodService.verifyConfiguration();
}, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventAppInitialized.class)
.observeOn(Schedulers.io())
.subscribe(event -> {
// See if a bolus was active before the app previously exited
// If so, add it to history
// Needs to be done after EventAppInitialized because otherwise, TreatmentsPlugin.onStart() hasn't been called yet
// so it didn't initialize a TreatmentService yet, resulting in a NullPointerException
if (sp.contains(OmnipodConst.Prefs.CurrentBolus)) {
String currentBolusString = sp.getString(OmnipodConst.Prefs.CurrentBolus, "");
aapsLogger.warn(LTag.PUMP, "Found active bolus in SP. Adding Treatment: {}", currentBolusString);
try {
DetailedBolusInfo detailedBolusInfo = omnipodUtil.getGsonInstance().fromJson(currentBolusString, DetailedBolusInfo.class);
aapsOmnipodManager.addBolusToHistory(detailedBolusInfo);
} catch (Exception ex) {
aapsLogger.error(LTag.PUMP, "Failed to add active bolus to history", ex);
}
sp.remove(OmnipodConst.Prefs.CurrentBolus);
}
}, fabricPrivacy::logException)
);
super.onStart();
}
@ -215,7 +239,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
@Override
public void initPumpStatusData() {
omnipodPumpStatus.lastConnection = sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L);
omnipodPumpStatus.lastDataTime = omnipodPumpStatus.lastConnection;
omnipodPumpStatus.previousConnection = omnipodPumpStatus.lastConnection;
@ -267,7 +290,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
}
}
@Override
public Class getServiceClass() {
return RileyLinkOmnipodService.class;
@ -278,20 +300,17 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return this.omnipodPumpStatus;
}
@Override
public String deviceID() {
return "Omnipod";
}
// Pump Plugin
private boolean isServiceSet() {
return rileyLinkOmnipodService != null;
}
@Override
public boolean isInitialized() {
if (displayConnectionMessages)
@ -299,7 +318,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return isServiceSet() && isInitialized;
}
@Override
public boolean isBusy() {
if (displayConnectionMessages)
@ -321,19 +339,16 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return false;
}
@Override
public void resetRileyLinkConfiguration() {
rileyLinkOmnipodService.resetRileyLinkConfiguration();
}
@Override
public boolean hasTuneUp() {
return false;
}
@Override
public void doTuneUpDevice() {
//rileyLinkOmnipodService.doTuneUpDevice();
@ -344,7 +359,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
rxBus.send(new EventOmnipodPumpValuesChanged());
}
@Override
public RileyLinkOmnipodService getRileyLinkService() {
return rileyLinkOmnipodService;
@ -354,7 +368,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return rileyLinkOmnipodService.getDeviceCommandExecutor();
}
private synchronized void clearBusyQueue() {
if (busyTimestamps.size() == 0) {
@ -381,7 +394,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
}
@Override
public boolean isConnected() {
if (displayConnectionMessages)
@ -389,7 +401,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return isServiceSet() && rileyLinkOmnipodService.isInitialized();
}
@Override
public boolean isConnecting() {
if (displayConnectionMessages)
@ -397,7 +408,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return !isServiceSet() || !rileyLinkOmnipodService.isInitialized();
}
@Override
public boolean isSuspended() {
return !podStateManager.isPodRunning() || podStateManager.isSuspended();
@ -405,10 +415,10 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
@Override
public void getPumpStatus() {
if (firstRun) {
initializePump(!isRefresh);
triggerUIChange();
} else if (!omnipodStatusRequestList.isEmpty()) {
List<OmnipodStatusRequest> removeList = new ArrayList<>();
@ -492,14 +502,12 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
isRefresh = true;
}
// FIXME do we actually need this? If a user presses refresh during an action,
// I suppose the GetStatusCommand would just be queued?
private void setRefreshButtonEnabled(boolean enabled) {
rxBus.send(new EventOmnipodRefreshButtonState(enabled));
}
private void initializePump(boolean realInit) {
aapsLogger.info(LTag.PUMP, getLogPrefix() + "initializePump - start");
@ -532,7 +540,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
this.firstRun = false;
}
@Override
public boolean isThisProfileSet(Profile profile) {
@ -546,7 +553,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return (currentProfile.areProfileBasalPatternsSame(profile));
}
@Override
public long lastDataTime() {
if (omnipodPumpStatus.lastConnection != 0) {
@ -556,7 +562,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return System.currentTimeMillis();
}
@Override
public double getBaseBasalRate() {
@ -568,35 +573,29 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
}
}
@Override
public double getReservoirLevel() {
return omnipodPumpStatus.reservoirRemainingUnits;
}
@Override
public int getBatteryLevel() {
return 75;
}
@Override
protected void triggerUIChange() {
rxBus.send(new EventOmnipodPumpValuesChanged());
}
@Override
public boolean isFakingTempsByExtendedBoluses() {
return false;
}
@Override
@NonNull
protected PumpEnactResult deliverBolus(final DetailedBolusInfo detailedBolusInfo) {
aapsLogger.info(LTag.PUMP, getLogPrefix() + "deliverBolus - {}", detailedBolusInfo);
setRefreshButtonEnabled(false);
@ -647,20 +646,17 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
//finishAction("Bolus");
}
private void incrementStatistics(String statsKey) {
long currentCount = sp.getLong(statsKey, 0L);
currentCount++;
sp.putLong(statsKey, currentCount);
}
// if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged),
// if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
setRefreshButtonEnabled(false);
aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes);
@ -709,7 +705,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return omnipodPumpStatus.getTemporaryBasal();
}
protected void finishAction(String overviewKey) {
if (overviewKey != null)
rxBus.send(new EventRefreshOverview(overviewKey, false));
@ -719,7 +714,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
setRefreshButtonEnabled(true);
}
@Override
public PumpEnactResult cancelTempBasal(boolean enforceNew) {
@ -802,7 +796,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
return result;
}
// OPERATIONS not supported by Pump or Plugin
protected List<CustomAction> customActions = null;
@ -813,7 +806,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
@Override
public List<CustomAction> getCustomActions() {
if (customActions == null) {
this.customActions = Arrays.asList(
customActionResetRLConfig //,
@ -829,7 +821,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
OmnipodCustomActionType mcat = (OmnipodCustomActionType) customActionType;
switch (mcat) {
case ResetRileyLinkConfiguration: {
serviceTaskExecutor.startTask(new ResetRileyLinkConfigurationTask(getInjector()));
}

View file

@ -71,6 +71,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateManage
import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodPumpStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.db.PodHistoryEntryType;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.OmnipodException;
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -89,6 +90,7 @@ public class AapsOmnipodManager implements IOmnipodManager {
private final ActivePluginProvider activePlugin;
private final OmnipodPumpStatus pumpStatus;
private final Context context;
private final SP sp;
private final OmnipodManager delegate;
private DatabaseHelperInterface databaseHelper;
@ -119,6 +121,7 @@ public class AapsOmnipodManager implements IOmnipodManager {
this.pumpStatus = pumpStatus;
this.context = context;
this.databaseHelper = databaseHelper;
this.sp = sp;
delegate = new OmnipodManager(aapsLogger, sp, communicationService, podStateManager);
}
@ -271,26 +274,43 @@ public class AapsOmnipodManager implements IOmnipodManager {
showErrorDialog(getStringResource(R.string.omnipod_bolus_failed_uncertain), R.raw.boluserror);
}
detailedBolusInfo.date = bolusStarted.getTime();
detailedBolusInfo.source = Source.PUMP;
// Store the current bolus for in case the app crashes, gets killed, the phone dies or whatever before the bolus finishes
// If we have a stored value for the current bolus on startup, we'll create a Treatment for it
// However this can potentially be hours later if for example your phone died and you can't charge it
// FIXME !!!
// The proper solution here would be to create a treatment right after the bolus started,
// and update that treatment after the bolus has finished in case the actual units delivered don't match the requested bolus units
// That way, the bolus would immediately be sent to NS so in case the phone dies you could still see the bolus
// Unfortunately this doesn't work because
// a) when cancelling a bolus within a few seconds of starting it, after updating the Treatment,
// we get a new treatment event from NS containing the originally created treatment with the original insulin amount.
// This event is processed in TreatmentService.createTreatmentFromJsonIfNotExists().
// Opposed to what the name of this method suggests, it does createOrUpdate,
// overwriting the insulin delivered with the original value.
// So practically it seems impossible to update a Treatment when using NS
// b) we only send newly created treatments to NS, so the insulin amount in NS would never be updated
//
// I discussed this with the AAPS team but nobody seems to care so we're stuck with this ugly workaround for now
try {
sp.putString(OmnipodConst.Prefs.CurrentBolus, omnipodUtil.getGsonInstance().toJson(detailedBolusInfo));
} catch (Exception ex) {
aapsLogger.error(LTag.PUMP, "Failed to store current bolus to SP", ex);
}
// Wait for the bolus to finish
OmnipodManager.BolusDeliveryResult bolusDeliveryResult =
bolusCommandResult.getDeliveryResultSubject().blockingGet();
double unitsDelivered = bolusDeliveryResult.getUnitsDelivered();
detailedBolusInfo.insulin = bolusDeliveryResult.getUnitsDelivered();
long pumpId = addSuccessToHistory(bolusStarted.getTime(), PodHistoryEntryType.SetBolus, unitsDelivered + ";" + detailedBolusInfo.carbs);
addBolusToHistory(detailedBolusInfo);
detailedBolusInfo.date = bolusStarted.getTime();
detailedBolusInfo.insulin = unitsDelivered;
detailedBolusInfo.pumpId = pumpId;
detailedBolusInfo.source = Source.PUMP;
sp.remove(OmnipodConst.Prefs.CurrentBolus);
activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false);
if (podStateManager.hasFaultEvent()) {
showPodFaultErrorDialog(podStateManager.getFaultEvent().getFaultEventCode());
}
return new PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(unitsDelivered);
return new PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(detailedBolusInfo.insulin);
}
@Override
@ -310,19 +330,18 @@ public class AapsOmnipodManager implements IOmnipodManager {
}
}
long time = System.currentTimeMillis();
String comment = null;
for (int i = 1; delegate.hasActiveBolus(); i++) {
aapsLogger.debug(LTag.PUMP, "Attempting to cancel bolus (#{})", i);
try {
delegate.cancelBolus(isBolusBeepsEnabled());
aapsLogger.debug(LTag.PUMP, "Successfully cancelled bolus", i);
addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null);
addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.CancelBolus, null);
return new PumpEnactResult(injector).success(true).enacted(true);
} catch (PodFaultException ex) {
aapsLogger.debug(LTag.PUMP, "Successfully cancelled bolus (implicitly because of a Pod Fault)");
showPodFaultErrorDialog(ex.getFaultEvent().getFaultEventCode(), null);
addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null);
addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.CancelBolus, null);
return new PumpEnactResult(injector).success(true).enacted(true);
} catch (Exception ex) {
aapsLogger.debug(LTag.PUMP, "Failed to cancel bolus", ex);
@ -330,7 +349,7 @@ public class AapsOmnipodManager implements IOmnipodManager {
}
}
addFailureToHistory(time, PodHistoryEntryType.CancelBolus, comment);
addFailureToHistory(System.currentTimeMillis(), PodHistoryEntryType.CancelBolus, comment);
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
}
@ -483,6 +502,12 @@ public class AapsOmnipodManager implements IOmnipodManager {
return delegate.isPodRunning();
}
public void addBolusToHistory(DetailedBolusInfo detailedBolusInfo) {
long pumpId = addSuccessToHistory(detailedBolusInfo.date, PodHistoryEntryType.SetBolus, detailedBolusInfo.insulin + ";" + detailedBolusInfo.carbs);
detailedBolusInfo.pumpId = pumpId;
activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false);
}
private void reportImplicitlyCanceledTbr() {
//TreatmentsPlugin plugin = TreatmentsPlugin.getPlugin();
TreatmentsInterface plugin = activePlugin.getActiveTreatments();

View file

@ -14,6 +14,7 @@ public class OmnipodConst {
public static class Prefs {
public static final String PodState = Prefix + "pod_state";
public static final String CurrentBolus = Prefix + "current_bolus";
public static final int BeepBasalEnabled = R.string.key_omnipod_beep_basal_enabled;
public static final int BeepBolusEnabled = R.string.key_omnipod_beep_bolus_enabled;
public static final int BeepSMBEnabled = R.string.key_omnipod_beep_smb_enabled;
@ -26,11 +27,9 @@ public class OmnipodConst {
public static final String StatsPrefix = "omnipod_";
public static final String FirstPumpStart = Prefix + "first_pump_use";
public static final String LastGoodPumpCommunicationTime = Prefix + "lastGoodPumpCommunicationTime";
//public static final String LastGoodPumpFrequency = Prefix + "LastGoodPumpFrequency";
public static final String TBRsSet = StatsPrefix + "tbrs_set";
public static final String StandardBoluses = StatsPrefix + "std_boluses_delivered";
public static final String SMBBoluses = StatsPrefix + "smb_boluses_delivered";
//public static final String LastPumpHistoryEntry = StatsPrefix + "pump_history_entry";
}
public static final double POD_PULSE_SIZE = 0.05;

View file

@ -93,9 +93,9 @@
<string name="omnipod_cmd_suspend_delivery">Suspend Delivery</string>
<string name="omnipod_cmd_resume_delivery">Resume Delivery</string>
<string name="omnipod_cmd_unknown_entry">Unknown Entry</string>
<string name="omnipod_cmd_bolus_value">%1$.1f U</string>
<string name="omnipod_cmd_bolus_value_with_carbs">%1$.1f U, CH=%2$.1f g</string>
<string name="omnipod_cmd_tbr_value">Rate: %1$.1f U, Duration: %2$d min</string>
<string name="omnipod_cmd_bolus_value">%1$.2f U</string>
<string name="omnipod_cmd_bolus_value_with_carbs">%1$.2f U, CH=%2$.1f g</string>
<string name="omnipod_cmd_tbr_value">Rate: %1$.2f U, Duration: %2$d min</string>
<string name="omnipod_cmd_reset_pod_desc">If you press <b>OK</b>, the Pod state will be forcibly reset and you will not be able to communicate with the Pod anymore. Do this only if you can not communicate with the Pod anymore. If you can still communicate with the Pod, please use the <b>Deactivate Pod</b> option.</string>
<string name="omnipod_cmd_pod_history_na">Pod History not available at the moment.</string>
<string name="omnipod_init_pod_wizard_step1_title">Fill the Pod</string>