From 4da160a951db4bca19cf85ec4150f40ddb440480 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 1 Nov 2017 01:44:31 +0100 Subject: [PATCH] Disable closed loop under unsafe conditions. --- .../plugins/PumpCombo/ComboPlugin.java | 94 ++++++++++++++++++- app/src/main/res/values/strings.xml | 1 + .../de/jotomo/ruffy/spi/history/Bolus.java | 7 +- .../jotomo/ruffy/spi/history/PumpHistory.java | 3 +- .../commands/ReadHistoryCommand.java | 7 +- .../ReadReservoirLevelAndLastBolus.java | 7 +- 6 files changed, 102 insertions(+), 17 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 63e2eecefd..9c90b896e5 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 @@ -32,10 +32,13 @@ import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventTreatmentChange; +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.Notification; +import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; import info.nightscout.utils.DateUtil; @@ -46,7 +49,7 @@ import static de.jotomo.ruffy.spi.BolusProgressReporter.State.FINISHED; /** * Created by mike on 05.08.2016. */ -public class ComboPlugin implements PluginBase, PumpInterface { +public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterface { private static Logger log = LoggerFactory.getLogger(ComboPlugin.class); private boolean fragmentEnabled = false; @@ -148,7 +151,9 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public boolean isEnabled(int type) { - return type == PUMP && fragmentEnabled; + if (type == PluginBase.PUMP) return fragmentEnabled; + else if (type == PluginBase.CONSTRAINTS) return fragmentEnabled; + return false; } @Override @@ -249,10 +254,14 @@ public class ComboPlugin implements PluginBase, PumpInterface { } private void updateLocalData(CommandResult result) { - if (result.reservoirLevel != PumpState.UNKNOWN) + if (result.reservoirLevel != PumpState.UNKNOWN) { pump.reservoirLevel = result.reservoirLevel; - if (result.lastBolus != null) + } + if (result.lastBolus != null) { pump.lastBolus = result.lastBolus; + } else if (result.history != null && !result.history.bolusHistory.isEmpty()) { + pump.lastBolus = result.history.bolusHistory.get(0); + } pump.state = result.state; MainApp.bus().post(new EventComboPumpUpdateGUI()); } @@ -610,11 +619,13 @@ public class ComboPlugin implements PluginBase, PumpInterface { if (!commandResult.success && retries > 0) { for (int retryAttempts = 1; !commandResult.success && retryAttempts <= retries; retryAttempts++) { - log.debug("Command was not successful, retries request, doing retry #" + retryAttempts); + log.debug("Command was not successful, retries requested, doing retry #" + retryAttempts); commandResult = commandExecution.execute(); } } + checkForUnsupportedBoluses(commandResult); + pump.lastCmdResult = commandResult; pump.lastConnectionAttempt = System.currentTimeMillis(); if (commandResult.success) { @@ -629,6 +640,31 @@ public class ComboPlugin implements PluginBase, PumpInterface { return commandResult; } + private void checkForUnsupportedBoluses(CommandResult commandResult) { + long lastViolation = 0; + if (commandResult.lastBolus != null && !commandResult.lastBolus.isValid) { + lastViolation = commandResult.lastBolus.timestamp; + } else if (commandResult.history != null) { + for (Bolus bolus : commandResult.history.bolusHistory) { + if (!bolus.isValid && bolus.timestamp > lastViolation) { + lastViolation = bolus.timestamp; + } + } + } + + if (lastViolation > 0) { + closedLoopDisabledUntil = lastViolation + 6 * 60 * 60 * 1000; + if (closedLoopDisabledUntil > System.currentTimeMillis()) { + // TODO add message to either Combo tab or its errors popup + Notification n = new Notification(Notification.COMBO_PUMP_ALARM, + MainApp.sResources.getString(R.string.combo_force_disabled), + Notification.URGENT); + n.soundId = R.raw.alarm; + MainApp.bus().post(new EventNewNotification(n)); + } + } + } + // TODO rename to checkState or so and also check time (& date) of pump private void checkForTbrMismatch() { // detectTbrMismatch(): 'quick' check with no overhead on the pump side @@ -869,4 +905,52 @@ public class ComboPlugin implements PluginBase, PumpInterface { public boolean isFakingTempsByExtendedBoluses() { return false; } + + // Constraints interface + private long closedLoopDisabledUntil = 0; + + @Override + public boolean isLoopEnabled() { + return true; + } + + @Override + public boolean isClosedModeEnabled() { + return closedLoopDisabledUntil < System.currentTimeMillis(); + } + + @Override + public boolean isAutosensModeEnabled() { + return true; + } + + @Override + public boolean isAMAModeEnabled() { + return true; + } + + @Override + public Double applyBasalConstraints(Double absoluteRate) { + return absoluteRate; + } + + @Override + public Integer applyBasalConstraints(Integer percentRate) { + return percentRate; + } + + @Override + public Double applyBolusConstraints(Double insulin) { + return insulin; + } + + @Override + public Integer applyCarbsConstraints(Integer carbs) { + return carbs; + } + + @Override + public Double applyMaxIOBConstraints(Double maxIob) { + return maxIob; + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4a2d355ab9..731d0e7911 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -791,5 +791,6 @@ Bolus delivery verification failed. The pump history will be read again on the next loop run or when refreshing from the Combo page. Please check and bolus again if needed. Requested operation not supported by pump Bolus delivery failed. A (partial) bolus might have been delivered. Attempting to update history from pump. Please check the Combo page and bolus again as needed. + Unsafe usage: extended or multiwave boluses have been delivered within the last 6h. Closed loop mode forcefully disabled. Only normal boluses are supported when running in closed loop mode. diff --git a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/Bolus.java b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/Bolus.java index 382bcc7c6a..71ae8f2727 100644 --- a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/Bolus.java +++ b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/Bolus.java @@ -2,12 +2,15 @@ package de.jotomo.ruffy.spi.history; public class Bolus extends HistoryRecord { public final double amount; + public final boolean isValid; - public Bolus(long timestamp, double amount) { + public Bolus(long timestamp, double amount, boolean isValid) { super(timestamp); this.amount = amount; + this.isValid = isValid; } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -16,6 +19,7 @@ public class Bolus extends HistoryRecord { Bolus bolus = (Bolus) o; if (timestamp != bolus.timestamp) return false; + if (isValid != bolus.isValid) return false; return Double.compare(bolus.amount, amount) == 0; } @@ -25,6 +29,7 @@ public class Bolus extends HistoryRecord { long temp; result = (int) (timestamp ^ (timestamp >>> 32)); temp = Double.doubleToLongBits(amount); + result = result + (isValid ? 1 : 0); result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } diff --git a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/PumpHistory.java b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/PumpHistory.java index 9af252caa4..b33bf2e7a4 100644 --- a/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/PumpHistory.java +++ b/ruffy-spi/src/main/java/de/jotomo/ruffy/spi/history/PumpHistory.java @@ -3,9 +3,10 @@ package de.jotomo.ruffy.spi.history; import android.support.annotation.NonNull; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; +/** History data as read from the pump's My Data menu. + * Records are ordered from newest to oldest, so the first record is always the newest. */ public class PumpHistory { @NonNull public List bolusHistory = new ArrayList<>(); diff --git a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadHistoryCommand.java b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadHistoryCommand.java index 8db1218c60..6c9ab3e15f 100644 --- a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadHistoryCommand.java +++ b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadHistoryCommand.java @@ -127,14 +127,11 @@ public class ReadHistoryCommand extends BaseCommand { @NonNull private Bolus readBolusRecord() { scripter.verifyMenuIsDisplayed(MenuType.BOLUS_DATA); - // Could also be extended, multiwave BolusType bolusType = (BolusType) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE); - if (!bolusType.equals(BolusType.NORMAL)) { - throw new CommandException("Unsupported bolus type encountered: " + bolusType); - } + boolean isValid = bolusType == BolusType.NORMAL; Double bolus = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS); long recordDate = readRecordDate(); - return new Bolus(recordDate, bolus); + return new Bolus(recordDate, bolus, isValid); } private void readErrorRecords(long requestedTime) { diff --git a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadReservoirLevelAndLastBolus.java b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadReservoirLevelAndLastBolus.java index d6f5736394..0f2bdfab20 100644 --- a/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadReservoirLevelAndLastBolus.java +++ b/ruffyscripter/src/main/java/de/jotomo/ruffyscripter/commands/ReadReservoirLevelAndLastBolus.java @@ -31,14 +31,11 @@ public class ReadReservoirLevelAndLastBolus extends BaseCommand { @NonNull private Bolus readBolusRecord() { scripter.verifyMenuIsDisplayed(MenuType.BOLUS_DATA); - // Could also be extended, multiwave BolusType bolusType = (BolusType) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE); - if (!bolusType.equals(BolusType.NORMAL)) { - throw new CommandException("Unsupported bolus type encountered: " + bolusType); - } + boolean isValid = bolusType == BolusType.NORMAL; Double bolus = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS); long recordDate = readRecordDate(); - return new Bolus(recordDate, bolus); + return new Bolus(recordDate, bolus, isValid); } private long readRecordDate() {