Merge branch 'config-options-develop' into 'develop'
Add config options: See merge request !20
This commit is contained in:
commit
2210f3b129
3 changed files with 370 additions and 21 deletions
|
@ -0,0 +1,302 @@
|
|||
package de.jotomo.ruffyscripter.commands;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
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 java.util.Locale;
|
||||
|
||||
import de.jotomo.ruffyscripter.PumpState;
|
||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
||||
|
||||
public class SetTbrCommandAlt implements Command {
|
||||
private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class);
|
||||
|
||||
private final long percentage;
|
||||
private final long duration;
|
||||
|
||||
public SetTbrCommandAlt(long percentage, long duration) {
|
||||
this.percentage = percentage;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> validateArguments() {
|
||||
List<String> violations = new ArrayList<>();
|
||||
|
||||
if (percentage % 10 != 0) {
|
||||
violations.add("TBR percentage must be set in 10% steps");
|
||||
}
|
||||
if (percentage < 0 || percentage > 500) {
|
||||
violations.add("TBR percentage must be within 0-500%");
|
||||
}
|
||||
|
||||
if (percentage != 100) {
|
||||
if (duration % 15 != 0) {
|
||||
violations.add("TBR duration can only be set in 15 minute steps");
|
||||
}
|
||||
if (duration > 60 * 24) {
|
||||
violations.add("Maximum TBR duration is 24 hours");
|
||||
}
|
||||
}
|
||||
|
||||
if (percentage == 0 && duration > 120) {
|
||||
violations.add("Max allowed zero-temp duration is 2h");
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(RuffyScripter scripter, PumpState initialPumpState) {
|
||||
try {
|
||||
enterTbrMenu(scripter);
|
||||
inputTbrPercentage(scripter);
|
||||
verifyDisplayedTbrPercentage(scripter);
|
||||
|
||||
if (percentage == 100) {
|
||||
cancelTbrAndConfirmCancellationWarning(scripter);
|
||||
} else {
|
||||
// switch to TBR_DURATION menu by pressing menu key
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||
scripter.pressMenuKey();
|
||||
scripter.waitForMenuUpdate();
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||
|
||||
inputTbrDuration(scripter);
|
||||
verifyDisplayedTbrDuration(scripter);
|
||||
|
||||
// confirm TBR
|
||||
scripter.pressCheckKey();
|
||||
scripter.waitForMenuToBeLeft(MenuType.TBR_DURATION);
|
||||
}
|
||||
|
||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU,
|
||||
"Pump did not return to MAIN_MEU after setting TBR. " +
|
||||
"Check pump manually, the TBR might not have been set/cancelled.");
|
||||
|
||||
// check main menu shows the same values we just set
|
||||
if (percentage == 100) {
|
||||
verifyMainMenuShowsNoActiveTbr(scripter);
|
||||
return new CommandResult().success(true).enacted(true).message("TBR was cancelled");
|
||||
} else {
|
||||
verifyMainMenuShowsExpectedTbrActive(scripter);
|
||||
return new CommandResult().success(true).enacted(true).message(
|
||||
String.format(Locale.US, "TBR set to %d%% for %d min", percentage, duration));
|
||||
}
|
||||
|
||||
} catch (CommandException e) {
|
||||
return e.toCommandResult();
|
||||
}
|
||||
}
|
||||
|
||||
private void enterTbrMenu(RuffyScripter scripter) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU);
|
||||
scripter.navigateToMenu(MenuType.TBR_MENU);
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_MENU);
|
||||
scripter.pressCheckKey();
|
||||
scripter.waitForMenuUpdate();
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||
}
|
||||
|
||||
private void inputTbrPercentage(RuffyScripter scripter) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||
long currentPercent = readDisplayedTbrPercentage(scripter);
|
||||
log.debug("Current TBR %: " + currentPercent);
|
||||
long percentageChange = percentage - currentPercent;
|
||||
long percentageSteps = percentageChange / 10;
|
||||
boolean increasePercentage = true;
|
||||
if (percentageSteps < 0) {
|
||||
increasePercentage = false;
|
||||
percentageSteps = Math.abs(percentageSteps);
|
||||
}
|
||||
log.debug("Pressing " + (increasePercentage ? "up" : "down") + " " + percentageSteps + " times");
|
||||
for (int i = 0; i < percentageSteps; i++) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||
if (increasePercentage) scripter.pressUpKey();
|
||||
else scripter.pressDownKey();
|
||||
SystemClock.sleep(100);
|
||||
log.debug("Push #" + (i + 1));
|
||||
}
|
||||
// Give the pump time to finish any scrolling that might still be going on, can take
|
||||
// up to 1100ms. Plus some extra time to be sure
|
||||
SystemClock.sleep(2000);
|
||||
}
|
||||
|
||||
private void verifyDisplayedTbrPercentage(RuffyScripter scripter) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||
long displayedPercentage = readDisplayedTbrPercentage(scripter);
|
||||
if (displayedPercentage != percentage) {
|
||||
log.debug("Final displayed TBR percentage: " + displayedPercentage);
|
||||
throw new CommandException().message("Failed to set TBR percentage");
|
||||
}
|
||||
|
||||
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
||||
SystemClock.sleep(2000);
|
||||
long refreshedDisplayedTbrPecentage = readDisplayedTbrPercentage(scripter);
|
||||
if (displayedPercentage != refreshedDisplayedTbrPecentage) {
|
||||
throw new CommandException().message("Failed to set TBR percentage: " +
|
||||
"percentage changed after input stopped from "
|
||||
+ displayedPercentage + " -> " + refreshedDisplayedTbrPecentage);
|
||||
}
|
||||
}
|
||||
|
||||
private long readDisplayedTbrPercentage(RuffyScripter scripter) {
|
||||
// TODO v2 add timeout? Currently the command execution timeout would trigger if exceeded
|
||||
Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE);
|
||||
// this as a bit hacky, the display value is blinking, so we might catch that, so
|
||||
// keep trying till we get the Double we want
|
||||
while (!(percentageObj instanceof Double)) {
|
||||
scripter.waitForMenuUpdate();
|
||||
percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE);
|
||||
}
|
||||
return ((Double) percentageObj).longValue();
|
||||
}
|
||||
|
||||
private void inputTbrDuration(RuffyScripter scripter) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||
long currentDuration = readDisplayedTbrDuration(scripter);
|
||||
if (currentDuration % 15 != 0) {
|
||||
// The duration displayed is how long an active TBR will still run,
|
||||
// which might be something like 0:13, hence not in 15 minute steps.
|
||||
// Pressing up will go to the next higher 15 minute step.
|
||||
// Don't press down, from 0:13 it can't go down, so press up.
|
||||
// Pressing up from 23:59 works to go to 24:00.
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||
scripter.pressUpKey();
|
||||
scripter.waitForMenuUpdate();
|
||||
currentDuration = readDisplayedTbrDuration(scripter);
|
||||
}
|
||||
log.debug("Current TBR duration: " + currentDuration);
|
||||
long durationChange = duration - currentDuration;
|
||||
long durationSteps = durationChange / 15;
|
||||
boolean increaseDuration = true;
|
||||
if (durationSteps < 0) {
|
||||
increaseDuration = false;
|
||||
durationSteps = Math.abs(durationSteps);
|
||||
}
|
||||
log.debug("Pressing " + (increaseDuration ? "up" : "down") + " " + durationSteps + " times");
|
||||
for (int i = 0; i < durationSteps; i++) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||
if (increaseDuration) scripter.pressUpKey();
|
||||
else scripter.pressDownKey();
|
||||
SystemClock.sleep(100);
|
||||
log.debug("Push #" + (i + 1));
|
||||
}
|
||||
// Give the pump time to finish any scrolling that might still be going on, can take
|
||||
// up to 1100ms. Plus some extra time to be sure
|
||||
SystemClock.sleep(2000);
|
||||
}
|
||||
|
||||
private void verifyDisplayedTbrDuration(RuffyScripter scripter) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||
long displayedDuration = readDisplayedTbrDuration(scripter);
|
||||
if (displayedDuration != duration) {
|
||||
log.debug("Final displayed TBR duration: " + displayedDuration);
|
||||
throw new CommandException().message("Failed to set TBR duration");
|
||||
}
|
||||
|
||||
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
||||
SystemClock.sleep(2000);
|
||||
long refreshedDisplayedTbrDuration = readDisplayedTbrDuration(scripter);
|
||||
if (displayedDuration != refreshedDisplayedTbrDuration) {
|
||||
throw new CommandException().message("Failed to set TBR duration: " +
|
||||
"duration changed after input stopped from "
|
||||
+ displayedDuration + " -> " + refreshedDisplayedTbrDuration);
|
||||
}
|
||||
}
|
||||
|
||||
private long readDisplayedTbrDuration(RuffyScripter scripter) {
|
||||
// TODO v2 add timeout? Currently the command execution timeout would trigger if exceeded
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||
Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME);
|
||||
// this as a bit hacky, the display value is blinking, so we might catch that, so
|
||||
// keep trying till we get the Double we want
|
||||
while (!(durationObj instanceof MenuTime)) {
|
||||
scripter.waitForMenuUpdate();
|
||||
durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME);
|
||||
}
|
||||
MenuTime duration = (MenuTime) durationObj;
|
||||
return duration.getHour() * 60 + duration.getMinute();
|
||||
}
|
||||
|
||||
private void cancelTbrAndConfirmCancellationWarning(RuffyScripter scripter) {
|
||||
// confirm entered TBR
|
||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||
scripter.pressCheckKey();
|
||||
|
||||
// A "TBR CANCELLED alert" is only raised by the pump when the remaining time is
|
||||
// greater than 60s (displayed as 0:01, the pump goes from there to finished.
|
||||
// We could read the remaining duration from MAIN_MENU, but by the time we're here,
|
||||
// the pumup could have moved from 0:02 to 0:01, so instead, check if a "TBR CANCELLED" alert
|
||||
// is raised and if so dismiss it
|
||||
long inFiveSeconds = System.currentTimeMillis() + 5 * 1000;
|
||||
boolean alertProcessed = false;
|
||||
while (System.currentTimeMillis() < inFiveSeconds && !alertProcessed) {
|
||||
if (scripter.currentMenu.getType() == MenuType.WARNING_OR_ERROR) {
|
||||
// Check the raised alarm is TBR CANCELLED, so we're not accidentally cancelling
|
||||
// a different alarm that might be raised at the same time.
|
||||
// Note that the message is permanently displayed, while the error code is blinking.
|
||||
// A wait till the error code can be read results in the code hanging, despite
|
||||
// menu updates coming in, so just check the message.
|
||||
// TODO v2 this only works when the pump's language is English
|
||||
String errorMsg = (String) scripter.currentMenu.getAttribute(MenuAttribute.MESSAGE);
|
||||
if (!errorMsg.equals("TBR CANCELLED")) {
|
||||
throw new CommandException().success(false).enacted(false)
|
||||
.message("An alert other than the expected TBR CANCELLED was raised by the pump: "
|
||||
+ errorMsg + ". Please check the pump.");
|
||||
}
|
||||
// confirm "TBR CANCELLED" alert
|
||||
scripter.verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
||||
scripter.pressCheckKey();
|
||||
// dismiss "TBR CANCELLED" alert
|
||||
scripter.verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
||||
scripter.pressCheckKey();
|
||||
scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR);
|
||||
alertProcessed = true;
|
||||
}
|
||||
SystemClock.sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyMainMenuShowsNoActiveTbr(RuffyScripter scripter) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU);
|
||||
Double tbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR);
|
||||
boolean runtimeDisplayed = scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME);
|
||||
if (tbrPercentage != 100 || runtimeDisplayed) {
|
||||
throw new CommandException().message("Cancelling TBR failed, TBR is still set according to MAIN_MENU");
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyMainMenuShowsExpectedTbrActive(RuffyScripter scripter) {
|
||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU);
|
||||
// new TBR set; percentage and duration must be displayed ...
|
||||
if (!scripter.currentMenu.attributes().contains(MenuAttribute.TBR) ||
|
||||
!scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME)) {
|
||||
throw new CommandException().message("Setting TBR failed, according to MAIN_MENU no TBR is active");
|
||||
}
|
||||
Double mmTbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR);
|
||||
MenuTime mmTbrDuration = (MenuTime) scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME);
|
||||
// ... and be the same as what we set
|
||||
// note that displayed duration might have already counted down, e.g. from 30 minutes to
|
||||
// 29 minutes and 59 seconds, so that 29 minutes are displayed
|
||||
int mmTbrDurationInMinutes = mmTbrDuration.getHour() * 60 + mmTbrDuration.getMinute();
|
||||
if (mmTbrPercentage != percentage || (mmTbrDurationInMinutes != duration && mmTbrDurationInMinutes + 1 != duration)) {
|
||||
throw new CommandException().message("Setting TBR failed, TBR in MAIN_MENU differs from expected");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "{" +
|
||||
"percentage=" + percentage +
|
||||
", duration=" + duration +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -47,4 +47,10 @@ public class Config {
|
|||
public static final boolean logDanaBTComm = true;
|
||||
public static final boolean logDanaMessageDetail = true;
|
||||
public static final boolean logDanaSerialEngine = true;
|
||||
|
||||
// Combo specific
|
||||
/** use alternate SetTbrCommand (uses the initial implementation) */
|
||||
public static final boolean comboUseAlternateSetTbrCommand = false;
|
||||
/** very quick hack to split up bolus into 2 U parts, spaced roughly 45s apart */
|
||||
public static final boolean comboSplitBoluses = false;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.util.Date;
|
||||
|
||||
import de.jotomo.ruffyscripter.PumpState;
|
||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
||||
import de.jotomo.ruffyscripter.commands.BolusCommand;
|
||||
import de.jotomo.ruffyscripter.commands.CancelTbrCommand;
|
||||
|
@ -33,8 +34,9 @@ import de.jotomo.ruffyscripter.commands.CommandResult;
|
|||
import de.jotomo.ruffyscripter.commands.DetermineCapabilitiesCommand;
|
||||
import de.jotomo.ruffyscripter.commands.ReadPumpStateCommand;
|
||||
import de.jotomo.ruffyscripter.commands.SetTbrCommand;
|
||||
import de.jotomo.ruffyscripter.PumpState;
|
||||
import de.jotomo.ruffyscripter.commands.SetTbrCommandAlt;
|
||||
import info.nightscout.androidaps.BuildConfig;
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
|
@ -367,28 +369,36 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
|||
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
|
||||
if (detailedBolusInfo.insulin > 0) {
|
||||
// bolus needed, ask pump to deliver it
|
||||
CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin));
|
||||
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
||||
pumpEnactResult.success = bolusCmdResult.success;
|
||||
pumpEnactResult.enacted = bolusCmdResult.enacted;
|
||||
pumpEnactResult.comment = bolusCmdResult.message;
|
||||
|
||||
// if enacted, add bolus and carbs to treatment history
|
||||
if (pumpEnactResult.enacted) {
|
||||
// TODO if no error occurred, the requested bolus is what the pump delievered,
|
||||
// that has been checked. If an error occurred, we should check how much insulin
|
||||
// was delivered, e.g. when the cartridge went empty mid-bolus
|
||||
// For the first iteration, the alert the pump raises must suffice
|
||||
pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin;
|
||||
pumpEnactResult.carbsDelivered = detailedBolusInfo.carbs;
|
||||
|
||||
detailedBolusInfo.date = bolusCmdResult.completionTime;
|
||||
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
|
||||
if (!Config.comboSplitBoluses) {
|
||||
return deliverBolus(detailedBolusInfo);
|
||||
} else {
|
||||
// split up bolus into 2 U parts
|
||||
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
||||
pumpEnactResult.success = true;
|
||||
pumpEnactResult.enacted = true;
|
||||
pumpEnactResult.bolusDelivered = 0d;
|
||||
pumpEnactResult.carbsDelivered = 0d;
|
||||
pumpEnactResult.carbsDelivered = detailedBolusInfo.carbs;
|
||||
pumpEnactResult.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
|
||||
|
||||
double remainingBolus = detailedBolusInfo.insulin;
|
||||
int split = 1;
|
||||
while (remainingBolus > 0.05) {
|
||||
double bolus = remainingBolus > 2 ? 2 : remainingBolus;
|
||||
DetailedBolusInfo bolusInfo = new DetailedBolusInfo();
|
||||
bolusInfo.insulin = bolus;
|
||||
bolusInfo.isValid = false;
|
||||
log.debug("Delivering split bolus #" + split + " with " + bolus + " U");
|
||||
PumpEnactResult bolusResult = deliverBolus(bolusInfo);
|
||||
if (!bolusResult.success) {
|
||||
return bolusResult;
|
||||
}
|
||||
pumpEnactResult.bolusDelivered += bolus;
|
||||
remainingBolus -= 2;
|
||||
split++;
|
||||
}
|
||||
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
|
||||
return pumpEnactResult;
|
||||
}
|
||||
} else {
|
||||
// no bolus required, carb only treatment
|
||||
|
||||
|
@ -418,6 +428,32 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
|||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo) {
|
||||
CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin));
|
||||
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
||||
pumpEnactResult.success = bolusCmdResult.success;
|
||||
pumpEnactResult.enacted = bolusCmdResult.enacted;
|
||||
pumpEnactResult.comment = bolusCmdResult.message;
|
||||
|
||||
// if enacted, add bolus and carbs to treatment history
|
||||
if (pumpEnactResult.enacted) {
|
||||
// TODO if no error occurred, the requested bolus is what the pump delievered,
|
||||
// that has been checked. If an error occurred, we should check how much insulin
|
||||
// was delivered, e.g. when the cartridge went empty mid-bolus
|
||||
// For the first iteration, the alert the pump raises must suffice
|
||||
pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin;
|
||||
pumpEnactResult.carbsDelivered = detailedBolusInfo.carbs;
|
||||
|
||||
detailedBolusInfo.date = bolusCmdResult.completionTime;
|
||||
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
|
||||
} else {
|
||||
pumpEnactResult.bolusDelivered = 0d;
|
||||
pumpEnactResult.carbsDelivered = 0d;
|
||||
}
|
||||
return pumpEnactResult;
|
||||
}
|
||||
|
||||
private CommandResult runCommand(Command command) {
|
||||
if (ruffyScripter == null) {
|
||||
String msg = "No connection to ruffy. Pump control not available.";
|
||||
|
@ -492,12 +528,17 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
|||
adjustedPercent = rounded.intValue();
|
||||
}
|
||||
|
||||
CommandResult commandResult = runCommand(new SetTbrCommand(adjustedPercent, durationInMinutes));
|
||||
Command cmd = !Config.comboUseAlternateSetTbrCommand
|
||||
? new SetTbrCommand(adjustedPercent, durationInMinutes)
|
||||
: new SetTbrCommandAlt(adjustedPercent, durationInMinutes);
|
||||
CommandResult commandResult = runCommand(cmd);
|
||||
|
||||
if (commandResult.enacted) {
|
||||
TemporaryBasal tempStart = new TemporaryBasal(commandResult.completionTime);
|
||||
// TODO commandResult.state.tbrRemainingDuration might already display 29 if 30 was set, since 29:59 is shown as 29 ...
|
||||
// we should check this, but really ... something must be really screwed up if that number was anything different
|
||||
// TODO actually ... might setting 29 help with gaps between TBRs? w/o the hack in TemporaryBasal?
|
||||
// nah, fucks up duration in treatment history
|
||||
tempStart.durationInMinutes = durationInMinutes;
|
||||
tempStart.percentRate = adjustedPercent;
|
||||
tempStart.isAbsolute = false;
|
||||
|
|
Loading…
Reference in a new issue