Disable loop if unsupported basal rate profile is selected. Fixes #31.

This commit is contained in:
Johannes Mockenhaupt 2017-12-27 00:22:34 +01:00
parent c84ba24c77
commit 6af28479d6
No known key found for this signature in database
GPG key ID: 9E1EA6AF7BBBB0D1
6 changed files with 38 additions and 18 deletions

View file

@ -85,6 +85,8 @@ Usage:
- The integration of the Combo with AndroidAPS is designed with the assumption that all inputs are - The integration of the Combo with AndroidAPS is designed with the assumption that all inputs are
made via AndroidAPS. Boluses entered on the pump will NOT be detected by AAPS and may therefore made via AndroidAPS. Boluses entered on the pump will NOT be detected by AAPS and may therefore
result in too much insulin being delivered. result in too much insulin being delivered.
- The pump's first basal rate profile is read on app start and is updated by AAPS. Manually changing
the pump's basal rate profile will lead to wrong basals being delivered and is NOT supported.
- It's recommended to enable key lock on the pump to prevent bolusing from the pump, esp. when the - It's recommended to enable key lock on the pump to prevent bolusing from the pump, esp. when the
pump was used before and quick bolusing was a habit. pump was used before and quick bolusing was a habit.
Also, with keylock enabled, accidentally pressing a key will NOT interrupt a running command Also, with keylock enabled, accidentally pressing a key will NOT interrupt a running command

View file

@ -351,14 +351,22 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
// read basal profile into cache and update pump profile if needed // read basal profile into cache and update pump profile if needed
if (!pump.initialized) { if (!pump.initialized) {
if (stateResult.state.unsafeUsageDetected == PumpState.UNSUPPORTED_BASAL_RATE_PROFILE) {
Notification n = new Notification(Notification.COMBO_PUMP_ALARM,
MainApp.sResources.getString(R.string.combo_force_disabled_notification),
Notification.URGENT);
n.soundId = R.raw.alarm;
MainApp.bus().post(new EventNewNotification(n));
violationWarningRaisedForViolationAt = lowSuspendOnlyLoopEnforcedUntil;
return;
}
CommandResult readBasalResult = runCommand("Reading basal profile", 2, ruffyScripter::readBasalProfile); CommandResult readBasalResult = runCommand("Reading basal profile", 2, ruffyScripter::readBasalProfile);
if (!readBasalResult.success) { if (!readBasalResult.success) {
return; return;
} }
pump.basalProfile = readBasalResult.basalProfile; pump.basalProfile = readBasalResult.basalProfile;
} validBasalRateProfileSelectedOnPump = true;
if (!pump.initialized) {
pump.initialized = true; pump.initialized = true;
MainApp.bus().post(new EventInitializationChanged()); MainApp.bus().post(new EventInitializationChanged());
} }
@ -716,9 +724,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
if (commandResult.success) { if (commandResult.success) {
pump.lastSuccessfulCmdTime = System.currentTimeMillis(); pump.lastSuccessfulCmdTime = System.currentTimeMillis();
} validBasalRateProfileSelectedOnPump = commandResult.state.unsafeUsageDetected != PumpState.UNSUPPORTED_BASAL_RATE_PROFILE;
if (commandResult.success) {
updateLocalData(commandResult); updateLocalData(commandResult);
} }
} finally { } finally {
@ -811,7 +817,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
if (commandResult == null) return; if (commandResult == null) return;
long lastViolation = 0; long lastViolation = 0;
if (commandResult.state.unsafeUsageDetected) { if (commandResult.state.unsafeUsageDetected == PumpState.UNSUPPORTED_BOLUS_TYPE) {
lastViolation = System.currentTimeMillis(); lastViolation = System.currentTimeMillis();
} else if (commandResult.lastBolus != null && !commandResult.lastBolus.isValid) { } else if (commandResult.lastBolus != null && !commandResult.lastBolus.isValid) {
lastViolation = commandResult.lastBolus.timestamp; lastViolation = commandResult.lastBolus.timestamp;
@ -823,14 +829,14 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
} }
} }
if (lastViolation > 0) { if (lastViolation > 0) {
lowSuspendOnlyLoopEnforcetTill = lastViolation + 6 * 60 * 60 * 1000; lowSuspendOnlyLoopEnforcedUntil = lastViolation + 6 * 60 * 60 * 1000;
if (lowSuspendOnlyLoopEnforcetTill > System.currentTimeMillis() && violationWarningRaisedFor != lowSuspendOnlyLoopEnforcetTill) { if (lowSuspendOnlyLoopEnforcedUntil > System.currentTimeMillis() && violationWarningRaisedForViolationAt != lowSuspendOnlyLoopEnforcedUntil) {
Notification n = new Notification(Notification.COMBO_PUMP_ALARM, Notification n = new Notification(Notification.COMBO_PUMP_ALARM,
MainApp.sResources.getString(R.string.combo_force_disabled_notification), MainApp.sResources.getString(R.string.combo_low_suspend_forced_notification),
Notification.URGENT); Notification.URGENT);
n.soundId = R.raw.alarm; n.soundId = R.raw.alarm;
MainApp.bus().post(new EventNewNotification(n)); MainApp.bus().post(new EventNewNotification(n));
violationWarningRaisedFor = lowSuspendOnlyLoopEnforcetTill; violationWarningRaisedForViolationAt = lowSuspendOnlyLoopEnforcedUntil;
} }
} }
} }
@ -1058,8 +1064,9 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
} }
// Constraints interface // Constraints interface
private long lowSuspendOnlyLoopEnforcetTill = 0; private long lowSuspendOnlyLoopEnforcedUntil = 0;
private long violationWarningRaisedFor = 0; private long violationWarningRaisedForViolationAt = 0;
private boolean validBasalRateProfileSelectedOnPump = false;
@Override @Override
public boolean isLoopEnabled() { public boolean isLoopEnabled() {
@ -1068,7 +1075,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
@Override @Override
public boolean isClosedModeEnabled() { public boolean isClosedModeEnabled() {
return true; return validBasalRateProfileSelectedOnPump;
} }
@Override @Override
@ -1103,6 +1110,6 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
@Override @Override
public Double applyMaxIOBConstraints(Double maxIob) { public Double applyMaxIOBConstraints(Double maxIob) {
return lowSuspendOnlyLoopEnforcetTill < System.currentTimeMillis() ? maxIob : 0; return lowSuspendOnlyLoopEnforcedUntil < System.currentTimeMillis() ? maxIob : 0;
} }
} }

View file

@ -816,7 +816,8 @@
<string name="raise_urgent_alarms_as_android_notification">Use system notifications for alerts</string> <string name="raise_urgent_alarms_as_android_notification">Use system notifications for alerts</string>
<string name="combo_pump_never_connected">Never</string> <string name="combo_pump_never_connected">Never</string>
<string name="combo_pump_unsupported_operation">Requested operation not supported by pump</string> <string name="combo_pump_unsupported_operation">Requested operation not supported by pump</string>
<string name="combo_force_disabled_notification">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.</string> <string name="combo_low_suspend_forced_notification">Unsafe usage: extended or multiwave boluses are active. Loop mode has been set to low-suspend only 6 hours. Only normal boluses are supported in loop mode</string>
<string name="combo_force_disabled_notification">Unsafe usage: the pump uses a different basal rate profile than the first, which is not supported. Select the first profile on the pump and refresh.</string>
<string name="bolus_frequency_exceeded">A bolus with the same amount was requested within the last minute. To prevent accidental double boluses and to guard against bugs this is disallowed.</string> <string name="bolus_frequency_exceeded">A bolus with the same amount was requested within the last minute. To prevent accidental double boluses and to guard against bugs this is disallowed.</string>
<string name="combo_pump_connected_now">Now</string> <string name="combo_pump_connected_now">Now</string>
<string name="combo_activity_reading_pump_history">Reading pump history</string> <string name="combo_activity_reading_pump_history">Reading pump history</string>

View file

@ -30,8 +30,12 @@ public class PumpState {
public int insulinState = UNKNOWN; public int insulinState = UNKNOWN;
public int activeBasalProfileNumber; public int activeBasalProfileNumber;
public static final int SAFE_USAGE = 0;
public static final int UNSUPPORTED_BOLUS_TYPE = 1;
public static final int UNSUPPORTED_BASAL_RATE_PROFILE = 2;
/** True if use of an extended or multiwave bolus has been detected */ /** True if use of an extended or multiwave bolus has been detected */
public boolean unsafeUsageDetected; public int unsafeUsageDetected = SAFE_USAGE;
public PumpState menu(String menu) { public PumpState menu(String menu) {
this.menu = menu; this.menu = menu;

View file

@ -501,8 +501,10 @@ public class RuffyScripter implements RuffyCommands {
BolusType bolusType = (BolusType) menu.getAttribute(MenuAttribute.BOLUS_TYPE); BolusType bolusType = (BolusType) menu.getAttribute(MenuAttribute.BOLUS_TYPE);
Integer activeBasalRate = (Integer) menu.getAttribute(MenuAttribute.BASAL_SELECTED); Integer activeBasalRate = (Integer) menu.getAttribute(MenuAttribute.BASAL_SELECTED);
if (bolusType != null && bolusType != BolusType.NORMAL || !activeBasalRate.equals(1)) { if (!activeBasalRate.equals(1)) {
state.unsafeUsageDetected = true; state.unsafeUsageDetected = PumpState.UNSUPPORTED_BASAL_RATE_PROFILE;
} else if (bolusType != null && bolusType != BolusType.NORMAL) {
state.unsafeUsageDetected = PumpState.UNSUPPORTED_BOLUS_TYPE;
} else if (tbrPercentage != null && tbrPercentage != 100) { } else if (tbrPercentage != null && tbrPercentage != 100) {
state.tbrActive = true; state.tbrActive = true;
Double displayedTbr = (Double) menu.getAttribute(MenuAttribute.TBR); Double displayedTbr = (Double) menu.getAttribute(MenuAttribute.TBR);

View file

@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
import java.util.Arrays; import java.util.Arrays;
import de.jotomo.ruffy.spi.BasalProfile; import de.jotomo.ruffy.spi.BasalProfile;
import de.jotomo.ruffy.spi.PumpState;
public class ReadBasalProfileCommand extends BaseCommand { public class ReadBasalProfileCommand extends BaseCommand {
private static final Logger log = LoggerFactory.getLogger(ReadBasalProfileCommand.class); private static final Logger log = LoggerFactory.getLogger(ReadBasalProfileCommand.class);
@ -17,6 +18,9 @@ public class ReadBasalProfileCommand extends BaseCommand {
@Override @Override
public void execute() { public void execute() {
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU);
if (scripter.readPumpStateInternal().unsafeUsageDetected == PumpState.UNSUPPORTED_BASAL_RATE_PROFILE) {
throw new CommandException("Active basal rate profile != 1");
}
scripter.navigateToMenu(MenuType.BASAL_1_MENU); scripter.navigateToMenu(MenuType.BASAL_1_MENU);
scripter.verifyMenuIsDisplayed(MenuType.BASAL_1_MENU); scripter.verifyMenuIsDisplayed(MenuType.BASAL_1_MENU);
scripter.pressCheckKey(); scripter.pressCheckKey();