diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index d96fda8d3b..ec777aed25 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -425,7 +425,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } - private void scheduleBgHistoryChange(@Nullable final long timestamp) { + private void scheduleBgHistoryChange(@Nullable final long timestamp) { class PostRunnable implements Runnable { public void run() { aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg"); @@ -440,8 +440,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { scheduledBgHistoryPost.cancel(false); Runnable task = new PostRunnable(); final int sec = 3; - if (oldestBgHistoryChange == 0 || oldestBgHistoryChange > timestamp) oldestBgHistoryChange = timestamp; - scheduledBgHistoryPost = bgHistoryWorker.schedule(task, sec, TimeUnit.SECONDS); + if (oldestBgHistoryChange == 0 || oldestBgHistoryChange > timestamp) + oldestBgHistoryChange = timestamp; + scheduledBgHistoryPost = bgHistoryWorker.schedule(task, sec, TimeUnit.SECONDS); } @@ -1871,7 +1872,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } } - public List getAllOmnipodHistoryRecordsFromTimeStamp(long from, boolean ascending) { try { Dao daoPodHistory = getDaoPodHistory(); @@ -1890,6 +1890,20 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { return new ArrayList<>(); } + public OmnipodHistoryRecord findOmnipodHistoryRecordByPumpId(long pumpId) { + try { + Dao daoPodHistory = getDaoPodHistory(); + QueryBuilder queryBuilder = daoPodHistory.queryBuilder(); + queryBuilder.orderBy("date", false); + Where where = queryBuilder.where(); + where.eq("pumpId", pumpId); + PreparedQuery preparedQuery = queryBuilder.prepare(); + return daoPodHistory.queryForFirst(preparedQuery); + } catch (SQLException e) { + aapsLogger.error("Unhandled exception", e); + } + return null; + } // Copied from xDrip+ String calculateDirection(BgReading bgReading) { diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java index 4468692189..ae3e52180c 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java @@ -3,6 +3,7 @@ package info.nightscout.androidaps.db; import com.j256.ormlite.dao.CloseableIterator; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.sql.SQLException; import java.util.List; @@ -99,6 +100,10 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { return MainApp.getDbHelper().getAllOmnipodHistoryRecordsFromTimeStamp(timestamp, ascending); } + @Nullable @Override public OmnipodHistoryRecord findOmnipodHistoryRecordByPumpId(long pumpId) { + return MainApp.getDbHelper().findOmnipodHistoryRecordByPumpId(pumpId); + } + @NotNull @Override public List getTDDsForLastXDays(int days) { return MainApp.getDbHelper().getTDDsForLastXDays(days); } diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt index 007ff88b90..aea3be7fee 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt @@ -24,6 +24,7 @@ interface DatabaseHelperInterface { fun getTemporaryBasalsDataFromTime(mills: Long, ascending: Boolean): List fun getCareportalEventFromTimestamp(timestamp: Long): CareportalEvent? fun getAllOmnipodHistoryRecordsFromTimestamp(timestamp: Long, ascending: Boolean): List + fun findOmnipodHistoryRecordByPumpId(pumpId: Long): OmnipodHistoryRecord? fun getTDDsForLastXDays(days: Int): List fun getProfileSwitchData(from: Long, ascending: Boolean): List } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java index 7e294225c1..2744722dd0 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java @@ -214,6 +214,12 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, statusChecker = new Runnable() { @Override public void run() { + if (podStateManager.isPodRunning() && !podStateManager.isSuspended()) { + aapsOmnipodManager.cancelSuspendedFakeTbrIfExists(); + } else { + aapsOmnipodManager.createSuspendedFakeTbrIfNotExists(); + } + if (!OmnipodPumpPlugin.this.statusRequestList.isEmpty() || OmnipodPumpPlugin.this.hasTimeDateOrTimeZoneChanged) { if (!getCommandQueue().statusInQueue()) { getCommandQueue().readStatus(statusRequestList.isEmpty() ? "Date or Time Zone Changed" : "Status Refresh Requested", null); @@ -569,7 +575,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, executeCommand(OmnipodCommandType.CANCEL_BOLUS, aapsOmnipodManager::cancelBolus); } - // if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged), + // if enforceNew===true current temp basal is cancelled 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 @@ -608,7 +614,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, TemporaryBasal tbrCurrent = readTBR(); if (tbrCurrent == null) { - aapsLogger.info(LTag.PUMP, "cancelTempBasal - TBR already canceled."); + aapsLogger.info(LTag.PUMP, "cancelTempBasal - TBR already cancelled."); rxBus.send(new EventRefreshOverview("Omnipod command: CancelTemporaryBasal", false)); return new PumpEnactResult(getInjector()).success(true).enacted(false); } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java index 1965f26d8b..d7b57932e1 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java @@ -21,6 +21,8 @@ public enum PodHistoryEntryType { SET_TEMPORARY_BASAL(10, R.string.omnipod_cmd_set_tbr, PumpHistoryEntryGroup.Basal), CANCEL_TEMPORARY_BASAL_BY_DRIVER(11, R.string.omnipod_cmd_cancel_tbr_by_driver, PumpHistoryEntryGroup.Basal), CANCEL_TEMPORARY_BASAL(12, R.string.omnipod_cmd_cancel_tbr, PumpHistoryEntryGroup.Basal), + SET_FAKE_SUSPENDED_TEMPORARY_BASAL(13, R.string.omnipod_cmd_set_fake_suspended_tbr), + CANCEL_FAKE_SUSPENDED_TEMPORARY_BASAL(14, R.string.omnipod_cmd_cancel_fake_suspended_tbr), SET_BASAL_SCHEDULE(20, R.string.omnipod_cmd_set_basal_schedule, PumpHistoryEntryGroup.Basal), diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java index c117a3c5c3..e0f8dd3f03 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java @@ -547,6 +547,7 @@ public class OmnipodManager { // Only works for commands with nonce resyncable message blocks private StatusResponse executeAndVerify(Supplier supplier) { + logStartingCommandExecution("verifyCommand"); try { return supplier.get(); } catch (Exception originalException) { @@ -556,7 +557,6 @@ public class OmnipodManager { aapsLogger.warn(LTag.PUMPCOMM, "Caught exception in executeAndVerify. Verifying command by using cancel none command to verify nonce", originalException); try { - logStartingCommandExecution("verifyCommand"); StatusResponse statusResponse = communicationService.sendCommand(StatusResponse.class, podStateManager, new CancelDeliveryCommand(podStateManager.getCurrentNonce(), BeepType.NO_BEEP, DeliveryType.NONE), false); aapsLogger.info(LTag.PUMPCOMM, "Command status resolved to SUCCESS. Status response after cancelDelivery[types=DeliveryType.NONE]: {}", statusResponse); diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java index 77522b43ca..c208325330 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java @@ -45,6 +45,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess 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.FaultEventCode; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalScheduleEntry; @@ -186,6 +187,8 @@ public class AapsOmnipodManager { rxBus.send(new EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED)); + cancelSuspendedFakeTbrIfExists(); + return new PumpEnactResult(injector).success(true).enacted(true); } catch (Exception ex) { String comment = handleAndTranslateException(ex); @@ -219,10 +222,10 @@ public class AapsOmnipodManager { return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); } - reportImplicitlyCancelledTbr(); - addSuccessToHistory(time, PodHistoryEntryType.DEACTIVATE_POD, null); + createSuspendedFakeTbrIfNotExists(); + podInitReceiver.returnInitTaskStatus(PodInitActionType.DEACTIVATE_POD_WIZARD_STEP, true, null); return new PumpEnactResult(injector).success(true).enacted(true); @@ -240,11 +243,17 @@ public class AapsOmnipodManager { throw new CommandInitializationException("Basal profile mapping failed", ex); } delegate.setBasalSchedule(basalSchedule, isBasalBeepsEnabled()); + + time = System.currentTimeMillis(); // Because setting a basal profile actually suspends and then resumes delivery, TBR is implicitly cancelled - reportImplicitlyCancelledTbr(); + if (historyEntryType == PodHistoryEntryType.RESUME_DELIVERY) { + cancelSuspendedFakeTbrIfExists(); + } else { + reportImplicitlyCancelledTbr(time - 1000); + } addSuccessToHistory(time, historyEntryType, profile.getBasalValues()); } catch (CommandFailedAfterChangingDeliveryStatusException ex) { - reportImplicitlyCancelledTbr(); + createSuspendedFakeTbrIfNotExists(); String comment = getStringResource(R.string.omnipod_error_set_basal_failed_delivery_suspended); showErrorDialog(comment, R.raw.boluserror); addFailureToHistory(time, historyEntryType, comment); @@ -266,10 +275,10 @@ public class AapsOmnipodManager { public PumpEnactResult discardPodState() { podStateManager.discardState(); - reportImplicitlyCancelledTbr(); - addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.RESET_POD_STATE, null); + createSuspendedFakeTbrIfNotExists(); + return new PumpEnactResult(injector).success(true).enacted(true); } @@ -393,7 +402,7 @@ public class AapsOmnipodManager { delegate.setTemporaryBasal(PumpType.Insulet_Omnipod.determineCorrectBasalSize(tempBasalPair.getInsulinRate()), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), beepsEnabled, beepsEnabled); time = System.currentTimeMillis(); } catch (CommandFailedAfterChangingDeliveryStatusException ex) { - reportImplicitlyCancelledTbr(); + reportImplicitlyCancelledTbr(time); String comment = getStringResource(R.string.omnipod_cancelled_old_tbr_failed_to_set_new); addFailureToHistory(time, PodHistoryEntryType.SET_TEMPORARY_BASAL, comment); return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); @@ -408,8 +417,6 @@ public class AapsOmnipodManager { return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); } - reportImplicitlyCancelledTbr(); - long pumpId = addSuccessToHistory(time, PodHistoryEntryType.SET_TEMPORARY_BASAL, tempBasalPair); TemporaryBasal tempStart = new TemporaryBasal(injector) // @@ -462,8 +469,10 @@ public class AapsOmnipodManager { return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); } - reportImplicitlyCancelledTbr(); addSuccessToHistory(time, PodHistoryEntryType.SUSPEND_DELIVERY, null); + + createSuspendedFakeTbrIfNotExists(); + return new PumpEnactResult(injector).success(true).enacted(true); } @@ -472,11 +481,12 @@ public class AapsOmnipodManager { long time = System.currentTimeMillis(); try { delegate.setTime(isBasalBeepsEnabled()); + time = System.currentTimeMillis(); // Because set time actually suspends and then resumes delivery, TBR is implicitly cancelled - reportImplicitlyCancelledTbr(); + reportImplicitlyCancelledTbr(time - 1000); addSuccessToHistory(time, PodHistoryEntryType.SET_TIME, null); } catch (CommandFailedAfterChangingDeliveryStatusException ex) { - reportImplicitlyCancelledTbr(); + createSuspendedFakeTbrIfNotExists(); String comment = getStringResource(R.string.omnipod_error_set_time_failed_delivery_suspended); showErrorDialog(comment, R.raw.boluserror); addFailureToHistory(time, PodHistoryEntryType.SET_TIME, comment); @@ -542,13 +552,52 @@ public class AapsOmnipodManager { activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false); } - private void reportImplicitlyCancelledTbr() { + public synchronized void createSuspendedFakeTbrIfNotExists() { + if (!hasSuspendedFakeTbr()) { + aapsLogger.debug(LTag.PUMP, "Creating fake suspended TBR"); + + long pumpId = addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.SET_FAKE_SUSPENDED_TEMPORARY_BASAL, null); + + TemporaryBasal temporaryBasal = new TemporaryBasal(injector) // + .date(System.currentTimeMillis()) // + .absolute(0.0) // + .duration((int) OmnipodConstants.SERVICE_DURATION.getStandardMinutes()) // + .source(Source.PUMP) // + .pumpId(pumpId); + + activePlugin.getActiveTreatments().addToHistoryTempBasal(temporaryBasal); + } + } + + public synchronized void cancelSuspendedFakeTbrIfExists() { + if (hasSuspendedFakeTbr()) { + aapsLogger.debug(LTag.PUMP, "Cancelling fake suspended TBR"); + long pumpId = addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.CANCEL_FAKE_SUSPENDED_TEMPORARY_BASAL, null); + + TemporaryBasal temporaryBasal = new TemporaryBasal(injector) // + .date(System.currentTimeMillis()) // + .duration(0) // + .source(Source.PUMP) // + .pumpId(pumpId); + + activePlugin.getActiveTreatments().addToHistoryTempBasal(temporaryBasal); + } + } + + public boolean hasSuspendedFakeTbr() { + if (activePlugin.getActiveTreatments().isTempBasalInProgress()) { + TemporaryBasal tempBasal = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); + OmnipodHistoryRecord historyRecord = databaseHelper.findOmnipodHistoryRecordByPumpId(tempBasal.pumpId); + return historyRecord != null && PodHistoryEntryType.getByCode(historyRecord.getPodEntryTypeCode()).equals(PodHistoryEntryType.SET_FAKE_SUSPENDED_TEMPORARY_BASAL); + } + return false; + } + + private void reportImplicitlyCancelledTbr(long time) { TreatmentsInterface plugin = activePlugin.getActiveTreatments(); if (plugin.isTempBasalInProgress()) { aapsLogger.debug(LTag.PUMP, "Reporting implicitly cancelled TBR to Treatments plugin"); - long time = System.currentTimeMillis() - 1000; - long pumpId = addSuccessToHistory(time, PodHistoryEntryType.CANCEL_TEMPORARY_BASAL_BY_DRIVER, null); TemporaryBasal temporaryBasal = new TemporaryBasal(injector) // diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodFragment.kt index fff4d32ce2..7f30ad6889 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodFragment.kt +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodFragment.kt @@ -207,9 +207,11 @@ class OmnipodFragment : DaggerFragment() { updatePodStatus() val errors = ArrayList(); - val rileyLinkErrorDescription = omnipodPumpPlugin.rileyLinkService.errorDescription - if (StringUtils.isNotEmpty(rileyLinkErrorDescription)) { - errors.add(rileyLinkErrorDescription) + if (omnipodPumpPlugin.rileyLinkService != null) { + val rileyLinkErrorDescription = omnipodPumpPlugin.rileyLinkService.errorDescription + if (StringUtils.isNotEmpty(rileyLinkErrorDescription)) { + errors.add(rileyLinkErrorDescription) + } } if (!podStateManager.hasPodState() || !podStateManager.isPodInitialized) { @@ -254,7 +256,7 @@ class OmnipodFragment : DaggerFragment() { // base basal rate omnipod_base_basal_rate.text = resourceHelper.gs(R.string.pump_basebasalrate, omnipodPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalSchedule.rateAt(Duration(now.withTimeAtStartOfDay(), now)))) - omnipod_tempbasal.text = activePlugin.activeTreatments + omnipod_tempbasal.text = if (aapsOmnipodManager.hasSuspendedFakeTbr()) "-" else activePlugin.activeTreatments .getTempBasalFromHistory(System.currentTimeMillis())?.toStringFull() ?: "-" // total delivered diff --git a/omnipod/src/main/res/values/strings.xml b/omnipod/src/main/res/values/strings.xml index ccca8f1385..46ba10edd1 100644 --- a/omnipod/src/main/res/values/strings.xml +++ b/omnipod/src/main/res/values/strings.xml @@ -162,6 +162,8 @@ Get pulse log Uncertain failure Cancelled the old temporary basal, but failed to set new temporary basal + Set fake temporary basal because the Pod is suspended + Cancel fake temporary basal that was created because the Pod was suspended %1$d minute