From a169245dc3b4d683d8bfd3fe7a189ce42abc004d Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 12:10:07 +0100 Subject: [PATCH 1/9] On bolusing failure, attempt verify by reading last bolus from history. --- .../plugins/PumpCombo/ComboPlugin.java | 74 +++++++++++++++---- app/src/main/res/values/strings.xml | 4 +- 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index e249c58981..0ea643bad8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import java.util.Calendar; import java.util.Date; +import java.util.List; import de.jotomo.ruffy.spi.BasalProfile; import de.jotomo.ruffy.spi.BolusProgressReporter; @@ -39,7 +40,6 @@ import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; -import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; @@ -47,8 +47,6 @@ import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; import info.nightscout.utils.DateUtil; -import static de.jotomo.ruffy.spi.BolusProgressReporter.State.FINISHED; - /** * Created by mike on 05.08.2016. */ @@ -457,6 +455,8 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf } lastRequestedBolus = new Bolus(System.currentTimeMillis(), detailedBolusInfo.insulin, true); + long pumpTimeAtStartOfCommand = runCommand(null, 1, ruffyScripter::readPumpState).state.pumpTime; + try { pump.activity = MainApp.sResources.getString(R.string.combo_pump_action_bolusing, detailedBolusInfo.insulin); MainApp.bus().post(new EventComboPumpUpdateGUI()); @@ -472,19 +472,20 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf detailedBolusInfo.isSMB ? nullBolusProgressReporter : bolusProgressReporter)); bolusInProgress = false; - if (bolusCmdResult.delivered > 0) { - detailedBolusInfo.insulin = bolusCmdResult.delivered; - detailedBolusInfo.source = Source.USER; - MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + if (bolusCmdResult.success) { + if (bolusCmdResult.delivered > 0) { + detailedBolusInfo.insulin = bolusCmdResult.delivered; + detailedBolusInfo.source = Source.USER; + MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + } + return new PumpEnactResult() + .success(true) + .enacted(bolusCmdResult.delivered > 0) + .bolusDelivered(bolusCmdResult.delivered) + .carbsDelivered(detailedBolusInfo.carbs); + } else { + return recoverFromErrorDuringBolusDelivery(detailedBolusInfo, pumpTimeAtStartOfCommand); } - - return new PumpEnactResult() - .success(bolusCmdResult.success) - .enacted(bolusCmdResult.delivered > 0) - .bolusDelivered(bolusCmdResult.delivered) - .carbsDelivered(detailedBolusInfo.carbs) - .comment(bolusCmdResult.success ? "" : - MainApp.sResources.getString(R.string.combo_bolus_bolus_delivery_failed)); } finally { pump.activity = null; MainApp.bus().post(new EventComboPumpUpdateGUI()); @@ -493,6 +494,49 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf } } + + /** + * If there was an error during BolusCommand the scripter will have reconnected as needed and waited + * for a bolus delivery to complete (once bolus delivery started it continues regardless of a connection loss). + * So, here we are with a connection again, let's read the last bolus record and check if + * its date is >= the time this command started (using the pump's time!). + * If there is such a bolus with <= the requested amount, then it's from this + * command and shall be added to treatments. If the bolus wasn't delivered in full + * add it but raise a warning. Raise a warning as well if no bolus was delivered at all. + */ + private PumpEnactResult recoverFromErrorDuringBolusDelivery(DetailedBolusInfo detailedBolusInfo, long pumpTimeAtStartOfCommand) { + log.debug("Trying to determine from pump history what was actually delivered"); + CommandResult readLastBolusResult = runCommand(MainApp.sResources.getString(R.string.combo_activity_verifying_delivered_bolus), 3, + () -> ruffyScripter.readHistory(new PumpHistoryRequest().bolusHistory(PumpHistoryRequest.LAST))); + List bolusHistory = readLastBolusResult.history.bolusHistory; + Bolus lastBolus = !bolusHistory.isEmpty() ? bolusHistory.get(0) : null; + + if (lastBolus == null // no bolus ever given + || lastBolus.timestamp < pumpTimeAtStartOfCommand // this is not the bolus you're looking for + || !lastBolus.isValid) { // ext/multiwave bolus + log.debug("No bolus was delivered"); + return new PumpEnactResult().success(false).enacted(false) + .comment(MainApp.sResources.getString(R.string.combo_error_no_bolus_delivered)); + } else if (Math.abs(lastBolus.amount - detailedBolusInfo.insulin) > 0.01) { // bolus only partially delivered + detailedBolusInfo.insulin = lastBolus.amount; + detailedBolusInfo.source = Source.USER; + MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + log.debug(String.format("Added partial bolus of %.2f to treatments", lastBolus.amount)); + return new PumpEnactResult().success(false).enacted(true) + .comment(String.format(MainApp.sResources.getString(R.string.combo_error_partial_bolus_delivered), + lastBolus.amount, detailedBolusInfo.insulin)); + } + + // bolus was correctly and fully delivered + detailedBolusInfo.insulin = lastBolus.amount; + detailedBolusInfo.source = Source.USER; + MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + log.debug("Added correctly delivered bolus to treatments"); + return new PumpEnactResult().success(true).enacted(true) + .bolusDelivered(lastBolus.amount) + .carbsDelivered(detailedBolusInfo.carbs); + } + @Override public void stopBolusDelivering() { if (bolusInProgress) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fa2f33d6b2..74702bdfd4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -812,7 +812,6 @@ Use system notifications for alerts Never Requested operation not supported by pump - Bolus delivery failed. A (partial) bolus might have been delivered. Please check the pump and the treatments tabs and bolus again as needed. Unsafe usage: extended or multiwave boluses have been delivered within the last 6 hours or the selected basal rate is not 1. Loop mode has been set to low-suspend only until 6 hours after the last unsupported bolus or basal rate profile. Only normal boluses are supported in loop mode with basal rate profile 1. A bolus with the same amount was requested within the last minute. For safety reasons this is disallowed. Now @@ -838,5 +837,8 @@ This will read the full history and state of the pump. Everything in \"My Data\" and the basal rate. Boluses and TBRs will be added to Treatments if they don\'t already exist. This can cause entries to be duplicated because the pump\'s time is imprecise. Using this when normally looping with the pump is highly discouraged and reserved for special circumstances. If you still want to do this, long press this button again.\n\nWARNING: this can trigger a bug which causes the pump to reject all connection attempts and requires pressing a button on the pump to recover and should therefore be avoided. Are you really sure you want to read all pump data and take the consequences of this action? TBR CANCELLED warning was confirmed + Bolus delivery failed. It appears no bolus was delivered. To be sure, please check the pump to avoid a double bolus and then bolus again. To guard against bugs, boluses are not automatically retried. + Only %.2f U of the requested bolus of %.2f U was delivered due to an error. Please check the pump to verify this and take appropriate actions. + Verifying delivered bolus From 5654a8ee6ef371131a694f9151521b9d33d45428 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 12:49:26 +0100 Subject: [PATCH 2/9] Make RuffyScripter.readPumpStateInternal more robust. --- .../jotomo/ruffyscripter/RuffyScripter.java | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index e9b42ad34b..c50c639084 100644 --- a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -495,6 +495,7 @@ public class RuffyScripter implements RuffyCommands { return state; } + log.debug("Parsing menu: " + menu); MenuType menuType = menu.getType(); state.menu = menuType.name(); @@ -505,7 +506,7 @@ public class RuffyScripter implements RuffyCommands { if (bolusType != null && bolusType != BolusType.NORMAL || !activeBasalRate.equals(1)) { state.unsafeUsageDetected = true; - } else if (tbrPercentage != 100) { + } else if (tbrPercentage != null && tbrPercentage != 100) { state.tbrActive = true; Double displayedTbr = (Double) menu.getAttribute(MenuAttribute.TBR); state.tbrPercent = displayedTbr.intValue(); @@ -513,24 +514,36 @@ public class RuffyScripter implements RuffyCommands { state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); state.tbrRate = ((double) menu.getAttribute(MenuAttribute.BASAL_RATE)); } - state.batteryState = ((int) menu.getAttribute(MenuAttribute.BATTERY_STATE)); - state.insulinState = ((int) menu.getAttribute(MenuAttribute.INSULIN_STATE)); - MenuTime time = (MenuTime) menu.getAttribute(MenuAttribute.TIME); - Date date = new Date(); - date.setHours(time.getHour()); - date.setMinutes(time.getMinute()); - state.pumpTime = date.getTime(); + if (menu.attributes().contains(MenuAttribute.BATTERY_STATE)) { + state.batteryState = ((int) menu.getAttribute(MenuAttribute.BATTERY_STATE)); + } + if (menu.attributes().contains(MenuAttribute.INSULIN_STATE)) { + state.insulinState = ((int) menu.getAttribute(MenuAttribute.INSULIN_STATE)); + } + if (menu.attributes().contains(MenuAttribute.TIME)) { + MenuTime time = (MenuTime) menu.getAttribute(MenuAttribute.TIME); + Date date = new Date(); + date.setHours(time.getHour()); + date.setMinutes(time.getMinute()); + state.pumpTime = date.getTime(); + } } else if (menuType == MenuType.WARNING_OR_ERROR) { state.activeAlert = readWarningOrErrorCode(); } else if (menuType == MenuType.STOP) { state.suspended = true; - state.batteryState = ((int) menu.getAttribute(MenuAttribute.BATTERY_STATE)); - state.insulinState = ((int) menu.getAttribute(MenuAttribute.INSULIN_STATE)); - MenuTime time = (MenuTime) menu.getAttribute(MenuAttribute.TIME); - Date date = new Date(); - date.setHours(time.getHour()); - date.setMinutes(time.getMinute()); - state.pumpTime = date.getTime(); + if (menu.attributes().contains(MenuAttribute.BATTERY_STATE)) { + state.batteryState = ((int) menu.getAttribute(MenuAttribute.BATTERY_STATE)); + } + if (menu.attributes().contains(MenuAttribute.INSULIN_STATE)) { + state.insulinState = ((int) menu.getAttribute(MenuAttribute.INSULIN_STATE)); + } + if (menu.attributes().contains(MenuAttribute.TIME)) { + MenuTime time = (MenuTime) menu.getAttribute(MenuAttribute.TIME); + Date date = new Date(); + date.setHours(time.getHour()); + date.setMinutes(time.getMinute()); + state.pumpTime = date.getTime(); + } } return state; From 7eb40653b298643ccd09cb2af1f36d66f7dc35fd Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 13:00:47 +0100 Subject: [PATCH 3/9] The pump doesn't accept connections while a bolus delivery is in progress. Remove the code which checked for a bolus delivery in progress and waited. --- .../plugins/PumpCombo/ComboPlugin.java | 14 +++++----- .../jotomo/ruffyscripter/RuffyScripter.java | 26 ------------------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 0ea643bad8..ceefccd76c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -496,12 +496,14 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf /** - * If there was an error during BolusCommand the scripter will have reconnected as needed and waited - * for a bolus delivery to complete (once bolus delivery started it continues regardless of a connection loss). - * So, here we are with a connection again, let's read the last bolus record and check if - * its date is >= the time this command started (using the pump's time!). - * If there is such a bolus with <= the requested amount, then it's from this - * command and shall be added to treatments. If the bolus wasn't delivered in full + * If there was an error during BolusCommand the scripter try to reconnect. The pump refuses + * connections while a bolus delivery is still in progress (once bolus delivery started it + * continues regardless of a connection loss), retry the read history command a few + * times if we run into the 90s connect timeout (with 3 retries, a bolus of up to 54 U could + * be delivered until we give up). + * Then verify the bolus record we read has a date which is >= the time this command started + * (using the pump's time!). If there is such a bolus with <= the requested amount, then it's + * from this command and shall be added to treatments. If the bolus wasn't delivered in full * add it but raise a warning. Raise a warning as well if no bolus was delivered at all. */ private PumpEnactResult recoverFromErrorDuringBolusDelivery(DetailedBolusInfo detailedBolusInfo, long pumpTimeAtStartOfCommand) { diff --git a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index c50c639084..759c1b6f2c 100644 --- a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -363,21 +363,6 @@ public class RuffyScripter implements RuffyCommands { return false; } } - - // if everything broke before, the pump might still be delivering a bolus, if that's the case, wait for bolus to finish - Double bolusRemaining = (Double) getCurrentMenu().getAttribute(MenuAttribute.BOLUS_REMAINING); - BolusType bolusType = (BolusType) getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE); - if (bolusType != null && bolusType == BolusType.NORMAL) { - try { - while (isConnected() && bolusRemaining != null) { - log.debug("Waiting for bolus from previous connection to complete, remaining: " + bolusRemaining); - waitForScreenUpdate(); - } - } catch (Exception e) { - log.error("Exception waiting for bolus from previous command to finish", e); - return false; - } - } return true; } @@ -404,17 +389,6 @@ public class RuffyScripter implements RuffyCommands { } } - // A BOLUS CANCELLED alert is raised BEFORE a bolus is started. If a disconnect occurs after a - // bolus has started (or the user interacts with the pump) the bolus continues. - // If that happened, wait till the pump has finished the bolus, then it can be read from - // the history as delivered. - Double bolusRemaining = (Double) getCurrentMenu().getAttribute(MenuAttribute.BOLUS_REMAINING); - BolusType bolusType = (BolusType) getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE); - while (isConnected() && bolusRemaining != null && bolusType == BolusType.NORMAL) { - waitForScreenUpdate(); - bolusRemaining = (Double) getCurrentMenu().getAttribute(MenuAttribute.BOLUS_REMAINING); - bolusType = (BolusType) getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE); - } boolean connected = isConnected(); if (connected) { MenuType menuType = getCurrentMenu().getType(); From 25f46fe60153d488d080cd42527bdbd833983ecf Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 13:08:41 +0100 Subject: [PATCH 4/9] Cleanup. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index ceefccd76c..3afe16786b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory; import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.Locale; import de.jotomo.ruffy.spi.BasalProfile; import de.jotomo.ruffy.spi.BolusProgressReporter; @@ -455,7 +456,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf } lastRequestedBolus = new Bolus(System.currentTimeMillis(), detailedBolusInfo.insulin, true); - long pumpTimeAtStartOfCommand = runCommand(null, 1, ruffyScripter::readPumpState).state.pumpTime; + long pumpTimeWhenBolusWasRequested = runCommand(null, 1, ruffyScripter::readPumpState).state.pumpTime; try { pump.activity = MainApp.sResources.getString(R.string.combo_pump_action_bolusing, detailedBolusInfo.insulin); @@ -484,7 +485,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf .bolusDelivered(bolusCmdResult.delivered) .carbsDelivered(detailedBolusInfo.carbs); } else { - return recoverFromErrorDuringBolusDelivery(detailedBolusInfo, pumpTimeAtStartOfCommand); + return recoverFromErrorDuringBolusDelivery(detailedBolusInfo, pumpTimeWhenBolusWasRequested); } } finally { pump.activity = null; @@ -501,12 +502,12 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf * continues regardless of a connection loss), retry the read history command a few * times if we run into the 90s connect timeout (with 3 retries, a bolus of up to 54 U could * be delivered until we give up). - * Then verify the bolus record we read has a date which is >= the time this command started + * Then verify the bolus record we read has a date which is >= the time the bolus was requested * (using the pump's time!). If there is such a bolus with <= the requested amount, then it's * from this command and shall be added to treatments. If the bolus wasn't delivered in full * add it but raise a warning. Raise a warning as well if no bolus was delivered at all. */ - private PumpEnactResult recoverFromErrorDuringBolusDelivery(DetailedBolusInfo detailedBolusInfo, long pumpTimeAtStartOfCommand) { + private PumpEnactResult recoverFromErrorDuringBolusDelivery(DetailedBolusInfo detailedBolusInfo, long pumpTimeWhenBolusWasRequested) { log.debug("Trying to determine from pump history what was actually delivered"); CommandResult readLastBolusResult = runCommand(MainApp.sResources.getString(R.string.combo_activity_verifying_delivered_bolus), 3, () -> ruffyScripter.readHistory(new PumpHistoryRequest().bolusHistory(PumpHistoryRequest.LAST))); @@ -514,16 +515,16 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf Bolus lastBolus = !bolusHistory.isEmpty() ? bolusHistory.get(0) : null; if (lastBolus == null // no bolus ever given - || lastBolus.timestamp < pumpTimeAtStartOfCommand // this is not the bolus you're looking for + || lastBolus.timestamp < pumpTimeWhenBolusWasRequested // this is not the bolus you're looking for || !lastBolus.isValid) { // ext/multiwave bolus - log.debug("No bolus was delivered"); + log.debug("It appears no bolus was delivered"); return new PumpEnactResult().success(false).enacted(false) .comment(MainApp.sResources.getString(R.string.combo_error_no_bolus_delivered)); } else if (Math.abs(lastBolus.amount - detailedBolusInfo.insulin) > 0.01) { // bolus only partially delivered detailedBolusInfo.insulin = lastBolus.amount; detailedBolusInfo.source = Source.USER; MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); - log.debug(String.format("Added partial bolus of %.2f to treatments", lastBolus.amount)); + log.debug(String.format(Locale.getDefault(), "Added partial bolus of %.2f to treatments", lastBolus.amount)); return new PumpEnactResult().success(false).enacted(true) .comment(String.format(MainApp.sResources.getString(R.string.combo_error_partial_bolus_delivered), lastBolus.amount, detailedBolusInfo.insulin)); From 67eb6b20ed984df85615c7377b3f7116d575bbd0 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 13:54:23 +0100 Subject: [PATCH 5/9] Handle errors when reading the history for verification fails. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 7 +++++++ app/src/main/res/values/strings.xml | 1 + 2 files changed, 8 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 3afe16786b..01daaddb58 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -511,6 +511,13 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf log.debug("Trying to determine from pump history what was actually delivered"); CommandResult readLastBolusResult = runCommand(MainApp.sResources.getString(R.string.combo_activity_verifying_delivered_bolus), 3, () -> ruffyScripter.readHistory(new PumpHistoryRequest().bolusHistory(PumpHistoryRequest.LAST))); + if (!readLastBolusResult.success || readLastBolusResult.history == null) { + // this happens when the cartridge runs empty during delivery, the pump will be in an error + // state with multiple alarms ringing and no chance of reading history + return new PumpEnactResult().success(false).enacted(false) + .comment(MainApp.sResources.getString(R.string.combo_error_bolus_verification_failed)); + } + List bolusHistory = readLastBolusResult.history.bolusHistory; Bolus lastBolus = !bolusHistory.isEmpty() ? bolusHistory.get(0) : null; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 74702bdfd4..e86aa7872d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -840,5 +840,6 @@ Bolus delivery failed. It appears no bolus was delivered. To be sure, please check the pump to avoid a double bolus and then bolus again. To guard against bugs, boluses are not automatically retried. Only %.2f U of the requested bolus of %.2f U was delivered due to an error. Please check the pump to verify this and take appropriate actions. Verifying delivered bolus + Delivering the bolus and verifying the pump\'s history failed, please check the pump and manually create a bolus record using the Careportal tab if a bolus was delivered. From 27922a045e3ae8a53c7c8f904be6364a016b2628 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 14:18:23 +0100 Subject: [PATCH 6/9] Log who requested the disconnect. --- .../src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 759c1b6f2c..af437ae49f 100644 --- a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -196,6 +196,7 @@ public class RuffyScripter implements RuffyCommands { return; } try { + log.debug("Disconnecting, requested by ...", new Exception()); ruffyService.doRTDisconnect(); } catch (RemoteException e) { // ignore From 97a9d65b52bb866ed5e3d49ac383118a126c3e2a Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 15:09:45 +0100 Subject: [PATCH 7/9] Fix reading pump time. --- .../main/java/de/jotomo/ruffy/spi/PumpState.java | 8 ++++++-- .../de/jotomo/ruffyscripter/RuffyScripter.java | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/PumpState.java b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/PumpState.java index d646de7f63..728b9f7fa0 100644 --- a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/PumpState.java +++ b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/PumpState.java @@ -81,15 +81,19 @@ public class PumpState { @Override public String toString() { return "PumpState{" + - "menu=" + menu + + "timestamp=" + timestamp + + ", pumpTime=" + pumpTime + + ", menu='" + menu + '\'' + + ", suspended=" + suspended + ", tbrActive=" + tbrActive + ", tbrPercent=" + tbrPercent + ", tbrRate=" + tbrRate + ", tbrRemainingDuration=" + tbrRemainingDuration + - ", suspended=" + suspended + + ", activeAlert=" + activeAlert + ", batteryState=" + batteryState + ", insulinState=" + insulinState + ", activeBasalProfileNumber=" + activeBasalProfileNumber + + ", unsafeUsageDetected=" + unsafeUsageDetected + '}'; } } diff --git a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index af437ae49f..b0dfa5280a 100644 --- a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -392,6 +392,15 @@ public class RuffyScripter implements RuffyCommands { boolean connected = isConnected(); if (connected) { + long menuTime = this.menuLastUpdated; + waitForScreenUpdate(); + if (menuTime == this.menuLastUpdated) { + log.error("NOT RECEIVING UPDATES YET JOE"); + } + while(currentMenu==null) { + log.warn("waiting for currentMenu to become != null"); + waitForScreenUpdate(); + } MenuType menuType = getCurrentMenu().getType(); if (menuType != MenuType.MAIN_MENU && menuType != MenuType.WARNING_OR_ERROR) { returnToRootMenu(); @@ -500,7 +509,8 @@ public class RuffyScripter implements RuffyCommands { Date date = new Date(); date.setHours(time.getHour()); date.setMinutes(time.getMinute()); - state.pumpTime = date.getTime(); + date.setSeconds(0); + state.pumpTime = date.getTime() - date.getTime() % 1000; } } else if (menuType == MenuType.WARNING_OR_ERROR) { state.activeAlert = readWarningOrErrorCode(); @@ -517,10 +527,12 @@ public class RuffyScripter implements RuffyCommands { Date date = new Date(); date.setHours(time.getHour()); date.setMinutes(time.getMinute()); - state.pumpTime = date.getTime(); + date.setSeconds(0); + state.pumpTime = date.getTime() - date.getTime() % 1000; } } + log.debug("State read: " + state); return state; } From 618e00d71d3f1f828e4b79f7f5691e4af32e4ae7 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 15:10:30 +0100 Subject: [PATCH 8/9] Update bolus progress dialog when recovery kicks in. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 14 +++++++++++--- .../de/jotomo/ruffy/spi/BolusProgressReporter.java | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 01daaddb58..c88d954dee 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -404,6 +404,8 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf case STOPPED: event.status = MainApp.sResources.getString(R.string.bolusstopped); break; + case RECOVERING: + event.status = "Connection was interrupted. Please wait while recovery takes place."; case FINISHED: // no state, just percent below to close bolus progress dialog break; @@ -466,11 +468,15 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf return new PumpEnactResult().success(true).enacted(false); } + BolusProgressReporter progressReporter = detailedBolusInfo.isSMB ? nullBolusProgressReporter : ComboPlugin.bolusProgressReporter; + // start bolus delivery bolusInProgress = true; CommandResult bolusCmdResult = runCommand(null, 0, - () -> ruffyScripter.deliverBolus(detailedBolusInfo.insulin, - detailedBolusInfo.isSMB ? nullBolusProgressReporter : bolusProgressReporter)); + () -> { + return ruffyScripter.deliverBolus(detailedBolusInfo.insulin, + progressReporter); + }); bolusInProgress = false; if (bolusCmdResult.success) { @@ -485,6 +491,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf .bolusDelivered(bolusCmdResult.delivered) .carbsDelivered(detailedBolusInfo.carbs); } else { + progressReporter.report(BolusProgressReporter.State.RECOVERING, 0, 0); return recoverFromErrorDuringBolusDelivery(detailedBolusInfo, pumpTimeWhenBolusWasRequested); } } finally { @@ -509,7 +516,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf */ private PumpEnactResult recoverFromErrorDuringBolusDelivery(DetailedBolusInfo detailedBolusInfo, long pumpTimeWhenBolusWasRequested) { log.debug("Trying to determine from pump history what was actually delivered"); - CommandResult readLastBolusResult = runCommand(MainApp.sResources.getString(R.string.combo_activity_verifying_delivered_bolus), 3, + CommandResult readLastBolusResult = runCommand(null , 3, () -> ruffyScripter.readHistory(new PumpHistoryRequest().bolusHistory(PumpHistoryRequest.LAST))); if (!readLastBolusResult.success || readLastBolusResult.history == null) { // this happens when the cartridge runs empty during delivery, the pump will be in an error @@ -520,6 +527,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf List bolusHistory = readLastBolusResult.history.bolusHistory; Bolus lastBolus = !bolusHistory.isEmpty() ? bolusHistory.get(0) : null; + log.debug("Last bolus read from history: " + lastBolus + ", request time: " + pumpTimeWhenBolusWasRequested); if (lastBolus == null // no bolus ever given || lastBolus.timestamp < pumpTimeWhenBolusWasRequested // this is not the bolus you're looking for diff --git a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/BolusProgressReporter.java b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/BolusProgressReporter.java index 7539513120..645d126c75 100644 --- a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/BolusProgressReporter.java +++ b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/BolusProgressReporter.java @@ -7,6 +7,7 @@ public interface BolusProgressReporter { DELIVERED, STOPPING, STOPPED, + RECOVERING, FINISHED } From b6bc9578138c488494d8b8b377b280f346cd93cd Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 13 Dec 2017 15:22:08 +0100 Subject: [PATCH 9/9] Minor tewaks and cleanups. --- Testing-Combo.md | 10 ++++++++ .../plugins/PumpCombo/ComboPlugin.java | 24 ++++++++++--------- .../layout/overview_bolusprogress_dialog.xml | 2 ++ .../main/res/layout/overview_error_dialog.xml | 3 ++- app/src/main/res/values/strings.xml | 1 + .../de/jotomo/ruffy/spi/history/Bolus.java | 2 +- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Testing-Combo.md b/Testing-Combo.md index 7346561c56..6550f5f9b8 100644 --- a/Testing-Combo.md +++ b/Testing-Combo.md @@ -35,6 +35,16 @@ It might be interesting to experiment with the Config software to set lower menu or display timeouts (or whatever they're called ...) to improve recovery speed. - [ ] Same as above while bolusing must report an error and NOT retry the command + - [ ] Recovery from connection issues during bolusing + - [ ] Bolusing still works => No error dialog, record is added to treatments + - [ ] Cancelling the bolus still works (while bolus is in progress) + - [ ] Pressing a button on the pump during delivery => Progress dialog freezes, then states that recovery + is in process and then closes; no error dialog, record correctly added to treatments + - [ ] Breaking the connection e.g. by moving the pump away from phone for up to a minute => same as above + - [ ] Same as above but put pump out of reach for 5 minutes => Error dialog, no record in treatments + - [ ] Starting a bolus bigger than what's left in the reservoir => Error dialog and a record in treatments with the partially delivered bolus + - [ ] When the connection breaks during bolusing, pressing the cancel button should not interfere with recovery and + the delivered bolus should be added to treatments - [ ] AAPS start - [ ] Starting AAPS without a reachable pump must show something sensible in the Combo tab (not hanging indefinitely with "initializing" activity) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index c88d954dee..e184426504 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -405,7 +405,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf event.status = MainApp.sResources.getString(R.string.bolusstopped); break; case RECOVERING: - event.status = "Connection was interrupted. Please wait while recovery takes place."; + event.status = MainApp.sResources.getString(R.string.combo_error_bolus_recovery_progress); case FINISHED: // no state, just percent below to close bolus progress dialog break; @@ -504,19 +504,20 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf /** - * If there was an error during BolusCommand the scripter try to reconnect. The pump refuses - * connections while a bolus delivery is still in progress (once bolus delivery started it - * continues regardless of a connection loss), retry the read history command a few - * times if we run into the 90s connect timeout (with 3 retries, a bolus of up to 54 U could - * be delivered until we give up). - * Then verify the bolus record we read has a date which is >= the time the bolus was requested + * If there was an error during BolusCommand the scripter reconnects and cleans up. The pump + * refuses connections while a bolus delivery is still in progress (once bolus delivery started + * it continues regardless of a connection loss). + * Then verify the bolus record we read has a date which is >= the time the bolus was requested * (using the pump's time!). If there is such a bolus with <= the requested amount, then it's - * from this command and shall be added to treatments. If the bolus wasn't delivered in full - * add it but raise a warning. Raise a warning as well if no bolus was delivered at all. + * from this command and shall be added to treatments. If the bolus wasn't delivered in full, + * add it to treatments but raise a warning. Raise a warning as well if no bolus was delivered + * at all. + * This all still might fail for very large boluses and earthquakes in which case an error + * is raised asking to user to deal with it. */ private PumpEnactResult recoverFromErrorDuringBolusDelivery(DetailedBolusInfo detailedBolusInfo, long pumpTimeWhenBolusWasRequested) { log.debug("Trying to determine from pump history what was actually delivered"); - CommandResult readLastBolusResult = runCommand(null , 3, + CommandResult readLastBolusResult = runCommand(null , 2, () -> ruffyScripter.readHistory(new PumpHistoryRequest().bolusHistory(PumpHistoryRequest.LAST))); if (!readLastBolusResult.success || readLastBolusResult.history == null) { // this happens when the cartridge runs empty during delivery, the pump will be in an error @@ -527,7 +528,8 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf List bolusHistory = readLastBolusResult.history.bolusHistory; Bolus lastBolus = !bolusHistory.isEmpty() ? bolusHistory.get(0) : null; - log.debug("Last bolus read from history: " + lastBolus + ", request time: " + pumpTimeWhenBolusWasRequested); + log.debug("Last bolus read from history: " + lastBolus + ", request time: " + + pumpTimeWhenBolusWasRequested + " (" + new Date(pumpTimeWhenBolusWasRequested) + ")"); if (lastBolus == null // no bolus ever given || lastBolus.timestamp < pumpTimeWhenBolusWasRequested // this is not the bolus you're looking for diff --git a/app/src/main/res/layout/overview_bolusprogress_dialog.xml b/app/src/main/res/layout/overview_bolusprogress_dialog.xml index 2caa547c1e..85fe401052 100644 --- a/app/src/main/res/layout/overview_bolusprogress_dialog.xml +++ b/app/src/main/res/layout/overview_bolusprogress_dialog.xml @@ -11,6 +11,8 @@ android:id="@+id/overview_bolusprogress_status" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:paddingLeft="10dp" + android:paddingRight="10dp" android:layout_gravity="center_horizontal" />