Setting basal rate on pump (combo side).

This commit is contained in:
Johannes Mockenhaupt 2017-11-22 22:14:54 +01:00
parent 1f14f37373
commit 83be0a8315
No known key found for this signature in database
GPG key ID: 9E1EA6AF7BBBB0D1
5 changed files with 178 additions and 5 deletions

View file

@ -12,6 +12,7 @@ import java.util.Date;
import java.util.List;
import java.util.Objects;
import de.jotomo.ruffy.spi.BasalProfile;
import de.jotomo.ruffy.spi.BolusProgressReporter;
import de.jotomo.ruffy.spi.CommandResult;
import de.jotomo.ruffy.spi.PumpState;
@ -215,13 +216,36 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
}
@Override
public int setNewBasalProfile(Profile profile) {
return PumpInterface.FAILED;
public synchronized int setNewBasalProfile(Profile profile) {
BasalProfile requestedBasalProfile = convertProfileToComboProfile(profile);
if (pump.basalProfile.equals(requestedBasalProfile)) {
return PumpInterface.NOT_NEEDED;
}
CommandResult setResult = runCommand(MainApp.sResources.getString(R.string.combo_activity_setting_basal_profile), 0,
() -> ruffyScripter.setBasalProfile(requestedBasalProfile));
if (!setResult.success) {
return PumpInterface.FAILED;
}
CommandResult readResult = runCommand(MainApp.sResources.getString(R.string.combo_activity_setting_basal_profile), 0,
ruffyScripter::readBasalProfile);
return readResult.success && readResult.basalProfile.equals(requestedBasalProfile)
? PumpInterface.SUCCESS : PumpInterface.FAILED;
}
@Override
public boolean isThisProfileSet(Profile profile) {
return true;
return pump.basalProfile.equals(convertProfileToComboProfile(profile));
}
@NonNull
private BasalProfile convertProfileToComboProfile(Profile profile) {
BasalProfile basalProfile = new BasalProfile();
for (int i = 0; i < 24; i++) {
basalProfile.hourlyRates[i] = profile.getBasal(Integer.valueOf(i * 60 * 60));
}
return basalProfile;
}
@NonNull

View file

@ -20,7 +20,12 @@ public class BasalProfile {
BasalProfile that = (BasalProfile) o;
return Arrays.equals(hourlyRates, that.hourlyRates);
for(int i = 0; i < 23; i++) {
if (Math.abs(hourlyRates[i] - that.hourlyRates[i]) > 0.01) {
return false;
}
}
return true;
}
@Override

View file

@ -41,6 +41,7 @@ import de.jotomo.ruffyscripter.commands.ReadBasalProfileCommand;
import de.jotomo.ruffyscripter.commands.ReadHistoryCommand;
import de.jotomo.ruffyscripter.commands.ReadPumpStateCommand;
import de.jotomo.ruffyscripter.commands.ReadReservoirLevelAndLastBolus;
import de.jotomo.ruffyscripter.commands.SetBasalProfileCommand;
import de.jotomo.ruffyscripter.commands.SetDateAndTimeCommand;
import de.jotomo.ruffyscripter.commands.SetTbrCommand;
@ -756,7 +757,7 @@ public class RuffyScripter implements RuffyCommands {
@Override
public CommandResult setBasalProfile(BasalProfile basalProfile) {
throw new CommandException("Setting basal profile is not supported");
return runCommand(new SetBasalProfileCommand(basalProfile));
}
@Override

View file

@ -33,6 +33,7 @@ public class ReadBasalProfileCommand extends BaseCommand {
menu = scripter.getCurrentMenu();
}
scripter.verifyMenuIsDisplayed(MenuType.BASAL_SET);
MenuTime startTime = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.BASAL_START);
if (i != startTime.getHour()) {
throw new CommandException("Attempting to read basal rate for hour " + i + ", but hour " + startTime.getHour() + " is displayed");

View file

@ -0,0 +1,142 @@
package de.jotomo.ruffyscripter.commands;
import android.os.SystemClock;
import org.monkey.d.ruffy.ruffy.driver.display.Menu;
import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute;
import org.monkey.d.ruffy.ruffy.driver.display.MenuType;
import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import de.jotomo.ruffy.spi.BasalProfile;
public class SetBasalProfileCommand extends BaseCommand {
private static final Logger log = LoggerFactory.getLogger(SetBasalProfileCommand.class);
private final BasalProfile basalProfile;
public SetBasalProfileCommand(BasalProfile basalProfile) {
this.basalProfile = basalProfile;
}
@Override
public void execute() {
scripter.navigateToMenu(MenuType.BASAL_1_MENU);
scripter.verifyMenuIsDisplayed(MenuType.BASAL_1_MENU);
scripter.pressCheckKey();
// summary screen is shown; press menu to page through hours, wraps around to summary;
scripter.verifyMenuIsDisplayed(MenuType.BASAL_TOTAL);
for (int i = 0; i < 24; i++) {
scripter.pressMenuKey();
Menu menu = scripter.getCurrentMenu();
while (menu.getType() != MenuType.BASAL_SET
|| ((MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.BASAL_START)).getHour() != i) {
scripter.waitForScreenUpdate();
menu = scripter.getCurrentMenu();
}
scripter.verifyMenuIsDisplayed(MenuType.BASAL_SET);
double requestedRate = basalProfile.hourlyRates[i];
Boolean increasing = inputBasalRate(requestedRate);
if (increasing != null) {
verifyDisplayedRate(requestedRate, increasing);
}
log.debug("Set basal profile, hour " + i + ": " + requestedRate);
}
scripter.pressCheckKey();
scripter.verifyMenuIsDisplayed(MenuType.BASAL_TOTAL);
// check total basal total on pump matches requested total
Double pumpTotal = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BASAL_TOTAL);
Double requestedTotal = 0d;
for (int i = 0; i < 24; i++) {
requestedTotal += basalProfile.hourlyRates[i];
}
if (Math.abs(pumpTotal - requestedTotal) > 0.05) { // TODO leniency actually needed?
throw new CommandException("Basal total of " + pumpTotal + " differs from requested total of " + requestedTotal);
}
scripter.returnToRootMenu();
scripter.verifyRootMenuIsDisplayed();
result.success(true).basalProfile(basalProfile);
}
// TODO boolean to indicate, up, down or neither? yikes
private Boolean inputBasalRate(double requestedRate) {
// 0.05 steps; jumps to 0.10 steps if buttons are kept pressed, so there's room for optimization
double currentRate = scripter.readBlinkingValue(Double.class, MenuAttribute.BASAL_RATE);
if (Math.abs(currentRate - requestedRate) < 0.01) {
return null;
}
log.debug("Current rate: " + currentRate + " = requested => " + requestedRate);
double change = requestedRate - currentRate;
long steps = Math.round(change * 100);
boolean increasing = steps > 0;
log.debug("Pressing " + (increasing ? "up" : "down") + " " + Math.abs(steps) + " times");
for (int i = 0; i < Math.abs(steps); i++) {
scripter.verifyMenuIsDisplayed(MenuType.BASAL_SET);
log.debug("Push #" + (i + 1) + "/" + Math.abs(steps));
if (increasing) scripter.pressUpKey();
else scripter.pressDownKey();
SystemClock.sleep(50);
}
return increasing;
}
private void verifyDisplayedRate(double requestedRate, boolean increasingPercentage) {
scripter.verifyMenuIsDisplayed(MenuType.BASAL_SET);
// wait up to 5s for any scrolling to finish
double displayedRate = scripter.readBlinkingValue(Double.class, MenuAttribute.BASAL_RATE);
long timeout = System.currentTimeMillis() + 10 * 1000;
while (timeout > System.currentTimeMillis()
&& ((increasingPercentage && displayedRate < requestedRate)
|| (!increasingPercentage && displayedRate > requestedRate))) {
log.debug("Waiting for pump to process scrolling input for rate, current: "
+ displayedRate + ", desired: " + requestedRate + ", scrolling "
+ (increasingPercentage ? "up" : "down"));
scripter.waitForScreenUpdate();
displayedRate = scripter.readBlinkingValue(Double.class, MenuAttribute.BASAL_RATE);
}
log.debug("Final displayed basal rate: " + displayedRate);
if (displayedRate != requestedRate) {
throw new CommandException("Failed to set basal rate, requested: "
+ requestedRate + ", actual: " + displayedRate);
}
// check again to ensure the displayed value hasn't change and scrolled past the desired
// value due to due scrolling taking extremely long
SystemClock.sleep(1000);
scripter.verifyMenuIsDisplayed(MenuType.BASAL_SET);
double refreshedDisplayedRate = scripter.readBlinkingValue(Double.class, MenuAttribute.BASAL_RATE);
if (displayedRate != refreshedDisplayedRate) {
throw new CommandException("Failed to set basal rate: " +
"percentage changed after input stopped from "
+ displayedRate + " -> " + refreshedDisplayedRate);
}
}
@Override
public List<String> validateArguments() {
ArrayList<String> violations = new ArrayList<>();
if (basalProfile == null) {
violations.add("No basal profile supplied");
}
return violations;
}
@Override
public String toString() {
return "SetBasalProfileCommand{" +
"basalProfile=" + basalProfile +
'}';
}
}