applyBasalConstraints reactor & tests

This commit is contained in:
Milos Kozak 2018-03-20 22:09:22 +01:00
parent c2cfe4e7ea
commit 15ebfc1193
40 changed files with 353 additions and 205 deletions

View file

@ -12,7 +12,7 @@ public class Constants {
public static final double defaultDIA = 3d; public static final double defaultDIA = 3d;
public static final double basalAbsoluteOnlyForCheckLimit = 10101010d; public static final Double REALLYHIGHBASALRATE = 1111111d;
public static final Integer basalPercentOnlyForCheckLimit = 10101010; public static final Integer basalPercentOnlyForCheckLimit = 10101010;
public static final double bolusOnlyForCheckLimit = 10101010d; public static final double bolusOnlyForCheckLimit = 10101010d;
public static final Integer carbsOnlyForCheckLimit = 10101010; public static final Integer carbsOnlyForCheckLimit = 10101010;

View file

@ -29,7 +29,6 @@ import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.Actions.ActionsFragment; import info.nightscout.androidaps.plugins.Actions.ActionsFragment;
import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin; import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
@ -201,7 +200,7 @@ public class MainApp extends Application {
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-G5Uploader")); FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-G5Uploader"));
else if (Config.PUMPCONTROL) else if (Config.PUMPCONTROL)
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-PumpControl")); FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-PumpControl"));
else if (MainApp.getConstraintChecker().isClosedLoopAllowed().get()) else if (MainApp.getConstraintChecker().isClosedLoopAllowed().value())
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-ClosedLoop")); FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-ClosedLoop"));
else else
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-OpenLoop")); FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-OpenLoop"));

View file

@ -6,7 +6,6 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.utils.SP;
/** /**
* Created by mike on 19.03.2018. * Created by mike on 19.03.2018.
@ -102,25 +101,24 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
Double rateAfterConstrain = absoluteRate;
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue; if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
rateAfterConstrain = Math.min(constrain.applyBasalConstraints(absoluteRate), rateAfterConstrain); constraint.applyBasalConstraints(absoluteRate, profile);
} }
return rateAfterConstrain; return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Integer applyBasalPercentConstraints(Integer percentRate) {
Integer rateAfterConstrain = percentRate; Integer rateAfterConstrain = percentRate;
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue; if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
rateAfterConstrain = Math.min(constrain.applyBasalConstraints(percentRate), rateAfterConstrain); rateAfterConstrain = Math.min(constrain.applyBasalPercentConstraints(percentRate), rateAfterConstrain);
} }
return rateAfterConstrain; return rateAfterConstrain;
} }

View file

@ -1,5 +1,8 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -7,20 +10,30 @@ import java.util.List;
* Created by mike on 19.03.2018. * Created by mike on 19.03.2018.
*/ */
public class Constraint<T> { public class Constraint<T extends Comparable> {
private static Logger log = LoggerFactory.getLogger(Constraint.class);
T value; T value;
T originalValue;
List<String> reasons = new ArrayList<>(); List<String> reasons = new ArrayList<>();
public Constraint(T value) { public Constraint(T value) {
this.value = value; this.value = value;
this.originalValue = value;
} }
public T get() { public T value() {
return value; return value;
} }
public T originalValue() {
return originalValue;
}
public Constraint<T> set(T value) { public Constraint<T> set(T value) {
this.value = value; this.value = value;
this.originalValue = value;
return this; return this;
} }
@ -30,6 +43,26 @@ public class Constraint<T> {
return this; return this;
} }
public Constraint<T> setIfSmaller(T value, String reason) {
if (value.compareTo(this.value) < 0) {
this.value = value;
}
if (value.compareTo(this.originalValue) < 0) {
reason(reason);
}
return this;
}
public Constraint<T> setIfGreater(T value, String reason) {
if (value.compareTo(this.value) > 0) {
this.value = value;
}
if (value.compareTo(this.originalValue) > 0) {
reason(reason);
}
return this;
}
public Constraint reason(String reason) { public Constraint reason(String reason) {
reasons.add(reason); reasons.add(reason);
return this; return this;
@ -38,10 +71,12 @@ public class Constraint<T> {
public String getReasons() { public String getReasons() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int count = 0; int count = 0;
for (String r: reasons) { for (String r : reasons) {
if (count++ != 0) sb.append("\n"); if (count++ != 0) sb.append("\n");
sb.append(r); sb.append(r);
} }
log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString());
return sb.toString(); return sb.toString();
} }
} }

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import info.nightscout.androidaps.data.Profile;
/** /**
* Created by mike on 15.06.2016. * Created by mike on 15.06.2016.
*/ */
@ -15,9 +17,9 @@ public interface ConstraintsInterface {
Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value); Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value);
Double applyBasalConstraints(Double absoluteRate); Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile);
Integer applyBasalConstraints(Integer percentRate); Integer applyBasalPercentConstraints(Integer percentRate);
Double applyBolusConstraints(Double insulin); Double applyBolusConstraints(Double insulin);

View file

@ -35,7 +35,7 @@ public interface PumpInterface {
PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo); PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo);
void stopBolusDelivering(); void stopBolusDelivering();
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew); PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew);
PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew); PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew);
PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes); PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes);
//some pumps might set a very short temp close to 100% as cancelling a temp can be noisy //some pumps might set a very short temp close to 100% as cancelling a temp can be noisy

View file

@ -22,6 +22,7 @@ import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
@ -117,17 +118,21 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
final boolean setAsPercent = percentRadio.isChecked(); final boolean setAsPercent = percentRadio.isChecked();
int durationInMinutes = SafeParse.stringToInt(duration.getText()); int durationInMinutes = SafeParse.stringToInt(duration.getText());
Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null)
return;
String confirmMessage = getString(R.string.setbasalquestion); String confirmMessage = getString(R.string.setbasalquestion);
if (setAsPercent) { if (setAsPercent) {
int basalPercentInput = SafeParse.stringToInt(basalPercent.getText()); int basalPercentInput = SafeParse.stringToInt(basalPercent.getText());
percent = MainApp.getConstraintChecker().applyBasalConstraints(basalPercentInput); percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(basalPercentInput);
confirmMessage += "\n" + percent + "% "; confirmMessage += "\n" + percent + "% ";
confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?";
if (percent != basalPercentInput) if (percent != basalPercentInput)
confirmMessage += "\n" + getString(R.string.constraintapllied); confirmMessage += "\n" + getString(R.string.constraintapllied);
} else { } else {
Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText()); Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText());
absolute = MainApp.getConstraintChecker().applyBasalConstraints(basalAbsoluteInput); absolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(basalAbsoluteInput), profile).value();
confirmMessage += "\n" + absolute + " U/h "; confirmMessage += "\n" + absolute + " U/h ";
confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?";
if (absolute - basalAbsoluteInput != 0d) if (absolute - basalAbsoluteInput != 0d)
@ -159,7 +164,7 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
if (setAsPercent) { if (setAsPercent) {
ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, callback); ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, callback);
} else { } else {
ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, callback); ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, profile, callback);
} }
FabricPrivacy.getInstance().logCustom(new CustomEvent("TempBasal")); FabricPrivacy.getInstance().logCustom(new CustomEvent("TempBasal"));
} }

View file

@ -51,6 +51,7 @@ import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
@ -302,7 +303,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} }
}; };
Integer maxPercent = MainApp.getConstraintChecker().applyBasalConstraints(Constants.basalPercentOnlyForCheckLimit); Integer maxPercent = MainApp.getConstraintChecker().applyBasalPercentConstraints(Constants.basalPercentOnlyForCheckLimit);
editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput); editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput);
editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher); editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher);
@ -324,7 +325,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} }
}; };
Double maxAbsolute = MainApp.getConstraintChecker().applyBasalConstraints(Constants.basalAbsoluteOnlyForCheckLimit); Double maxAbsolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(Constants.REALLYHIGHBASALRATE), profile).value();
editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput); editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput);
editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true, absoluteTextWatcher); editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true, absoluteTextWatcher);

View file

@ -31,6 +31,7 @@ import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppInitialized; import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.BgSourceInterface; import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.ProfileInterface;
@ -351,7 +352,9 @@ public class ConfigBuilderPlugin implements PluginBase, TreatmentsInterface {
*/ */
public void applyTBRRequest(APSResult request, Profile profile, Callback callback) { public void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
PumpInterface pump = getActivePump(); PumpInterface pump = getActivePump();
request.rate = MainApp.getConstraintChecker().applyBasalConstraints(request.rate);
request.rateConstraint = new Constraint<>(request.rate);
request.rate = MainApp.getConstraintChecker().applyBasalConstraints(request.rateConstraint, profile).value();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@ -399,7 +402,7 @@ public class ConfigBuilderPlugin implements PluginBase, TreatmentsInterface {
} else { } else {
if (Config.logCongigBuilderActions) if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: setTempBasalAbsolute()"); log.debug("applyAPSRequest: setTempBasalAbsolute()");
getCommandQueue().tempBasalAbsolute(request.rate, request.duration, false, callback); getCommandQueue().tempBasalAbsolute(request.rate, request.duration, false, profile, callback);
} }
} }
} }

View file

@ -13,6 +13,7 @@ import java.util.List;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
@ -189,7 +190,7 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
case 3: case 3:
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true); Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled); SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return new RequirementResult(closedLoopEnabled.get(), MainApp.gs(R.string.closedmodeenabled) + ": " + yesOrNo(closedLoopEnabled.get())); return new RequirementResult(closedLoopEnabled.value(), MainApp.gs(R.string.closedmodeenabled) + ": " + yesOrNo(closedLoopEnabled.value()));
case 4: case 4:
double maxIOB = MainApp.getConstraintChecker().applyMaxIOBConstraints(1000d); double maxIOB = MainApp.getConstraintChecker().applyMaxIOBConstraints(1000d);
boolean maxIobSet = maxIOB > 0; boolean maxIobSet = maxIOB > 0;
@ -345,12 +346,12 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
return absoluteRate; return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Integer applyBasalPercentConstraints(Integer percentRate) {
return percentRate; return percentRate;
} }

View file

@ -135,40 +135,28 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
Double origAbsoluteRate = absoluteRate;
Double maxBasal = SP.getDouble("openapsma_max_basal", 1d);
Profile profile = MainApp.getConfigBuilder().getProfile(); absoluteRate.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingbasalratio), 0d, MainApp.gs(R.string.basalmustbepositivevalue)));
if (profile == null) return absoluteRate;
if (absoluteRate < 0) absoluteRate = 0d; double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
absoluteRate.setIfSmaller(maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), maxBasal, MainApp.gs(R.string.maxbasalinpreferences)));
Double maxBasalMult = SP.getDouble("openapsama_current_basal_safety_multiplier", 4d);
Integer maxBasalFromDaily = SP.getInt("openapsama_max_daily_safety_multiplier", 3);
// Check percentRate but absolute rate too, because we know real current basal in pump // Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate; Double maxBasalMult = SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
if (absoluteRate > maxBasal) { double maxFromBasalMult = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
absoluteRate = maxBasal; absoluteRate.setIfSmaller(maxFromBasalMult, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromBasalMult, MainApp.gs(R.string.maxbasalmultiplier)));
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origRate + " by maxBasal preference to " + absoluteRate + "U/h"); Double maxBasalFromDaily = SP.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d);
} double maxFromDaily = Math.floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100;
if (absoluteRate > maxBasalMult * profile.getBasal()) { absoluteRate.setIfSmaller(maxFromDaily, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromDaily, MainApp.gs(R.string.maxdailybasalmultiplier)));
absoluteRate = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origRate + " by maxBasalMult to " + absoluteRate + "U/h");
}
if (absoluteRate > profile.getMaxDailyBasal() * maxBasalFromDaily) {
absoluteRate = profile.getMaxDailyBasal() * maxBasalFromDaily;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origRate + " by 3 * maxDailyBasal to " + absoluteRate + "U/h");
}
return absoluteRate; return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Integer applyBasalPercentConstraints(Integer percentRate) {
Integer origPercentRate = percentRate; Integer origPercentRate = percentRate;
Double maxBasal = SP.getDouble("openapsma_max_basal", 1d); Double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) return percentRate; if (profile == null) return percentRate;
@ -181,8 +169,8 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
if (absoluteRate < 0) absoluteRate = 0d; if (absoluteRate < 0) absoluteRate = 0d;
Double maxBasalMult = SP.getDouble("openapsama_current_basal_safety_multiplier", 4d); Double maxBasalMult = SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
Integer maxBasalFromDaily = SP.getInt("openapsama_max_daily_safety_multiplier", 3); Integer maxBasalFromDaily = SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3);
// Check percentRate but absolute rate too, because we know real current basal in pump // Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate; Double origRate = absoluteRate;
if (absoluteRate > maxBasal) { if (absoluteRate > maxBasal) {

View file

@ -17,6 +17,7 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
@ -39,6 +40,9 @@ public class APSResult {
public double smb = 0d; // super micro bolus in units public double smb = 0d; // super micro bolus in units
public long deliverAt = 0; public long deliverAt = 0;
public Constraint<Double> rateConstraint;
public Constraint<Double> smbConstraint;
@Override @Override
public String toString() { public String toString() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
@ -76,8 +80,8 @@ public class APSResult {
ret = MainApp.sResources.getString(R.string.let_temp_basal_run) + "<br>"; ret = MainApp.sResources.getString(R.string.let_temp_basal_run) + "<br>";
else else
ret = "<b>" + MainApp.sResources.getString(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " + ret = "<b>" + MainApp.sResources.getString(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) <br>" + "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) <br>" +
"<b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>"; "<b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>";
// smb // smb
if (smb != 0) if (smb != 0)
@ -101,6 +105,12 @@ public class APSResult {
newResult.tempBasalReqested = tempBasalReqested; newResult.tempBasalReqested = tempBasalReqested;
newResult.bolusRequested = bolusRequested; newResult.bolusRequested = bolusRequested;
newResult.iob = iob; newResult.iob = iob;
newResult.json = json;
newResult.hasPredictions = hasPredictions;
newResult.smb = smb;
newResult.deliverAt = deliverAt;
newResult.rateConstraint = rateConstraint;
newResult.smbConstraint = smbConstraint;
return newResult; return newResult;
} }

View file

@ -261,7 +261,7 @@ public class LoopPlugin implements PluginBase {
log.debug("invoke from " + initiator); log.debug("invoke from " + initiator);
Constraint<Boolean> loopEnabled = MainApp.getConstraintChecker().isLoopInvokationAllowed(); Constraint<Boolean> loopEnabled = MainApp.getConstraintChecker().isLoopInvokationAllowed();
if (!loopEnabled.get()) { if (!loopEnabled.value()) {
String message = MainApp.sResources.getString(R.string.loopdisabled) + "\n" + loopEnabled.getReasons(); String message = MainApp.sResources.getString(R.string.loopdisabled) + "\n" + loopEnabled.getReasons();
log.debug(message); log.debug(message);
MainApp.bus().post(new EventLoopSetLastRunGui(message)); MainApp.bus().post(new EventLoopSetLastRunGui(message));
@ -298,7 +298,8 @@ public class LoopPlugin implements PluginBase {
// check rate for constrais // check rate for constrais
final APSResult resultAfterConstraints = result.clone(); final APSResult resultAfterConstraints = result.clone();
resultAfterConstraints.rate = MainApp.getConstraintChecker().applyBasalConstraints(resultAfterConstraints.rate); resultAfterConstraints.rateConstraint = new Constraint<>(resultAfterConstraints.rate);
resultAfterConstraints.rate = MainApp.getConstraintChecker().applyBasalConstraints(resultAfterConstraints.rateConstraint, profile).value();
resultAfterConstraints.smb = MainApp.getConstraintChecker().applyBolusConstraints(resultAfterConstraints.smb); resultAfterConstraints.smb = MainApp.getConstraintChecker().applyBolusConstraints(resultAfterConstraints.smb);
// safety check for multiple SMBs // safety check for multiple SMBs
@ -332,7 +333,7 @@ public class LoopPlugin implements PluginBase {
Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed(); Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed();
if (closedLoopEnabled.get()) { if (closedLoopEnabled.value()) {
if (result.isChangeRequested()) { if (result.isChangeRequested()) {
final PumpEnactResult waiting = new PumpEnactResult(); final PumpEnactResult waiting = new PumpEnactResult();
waiting.queued = true; waiting.queued = true;

View file

@ -21,6 +21,7 @@ import java.lang.reflect.InvocationTargetException;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
@ -205,8 +206,8 @@ public class DetermineBasalAdapterAMAJS {
mProfile.put("target_bg", targetBg); mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc()); mProfile.put("carb_ratio", profile.getIc());
mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units)); mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units));
mProfile.put("max_daily_safety_multiplier", SP.getInt("openapsama_max_daily_safety_multiplier", 3)); mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
mProfile.put("current_basal_safety_multiplier", SP.getDouble("openapsama_current_basal_safety_multiplier", 4d)); mProfile.put("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
mProfile.put("skip_neutral_temps", true); mProfile.put("skip_neutral_temps", true);
mProfile.put("current_basal", basalrate); mProfile.put("current_basal", basalrate);
mProfile.put("temptargetSet", tempTargetSet); mProfile.put("temptargetSet", tempTargetSet);
@ -250,7 +251,7 @@ public class DetermineBasalAdapterAMAJS {
mMealData.put("boluses", mealData.boluses); mMealData.put("boluses", mealData.boluses);
mMealData.put("mealCOB", mealData.mealCOB); mMealData.put("mealCOB", mealData.mealCOB);
if (MainApp.getConstraintChecker().isAMAModeEnabled().get()) { if (MainApp.getConstraintChecker().isAMAModeEnabled().value()) {
mAutosensData = new JSONObject(); mAutosensData = new JSONObject();
mAutosensData.put("ratio", autosensDataRatio); mAutosensData.put("ratio", autosensDataRatio);
} else { } else {

View file

@ -19,7 +19,6 @@ import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
@ -174,8 +173,8 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
String units = profile.getUnits(); String units = profile.getUnits();
double maxIob = SP.getDouble("openapsma_max_iob", 1.5d); double maxIob = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
double maxBasal = SP.getDouble("openapsma_max_basal", 1d); double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
double minBg = Profile.toMgdl(profile.getTargetLow(), units); double minBg = Profile.toMgdl(profile.getTargetLow(), units);
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units); double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
double targetBg = Profile.toMgdl(profile.getTarget(), units); double targetBg = Profile.toMgdl(profile.getTarget(), units);
@ -223,7 +222,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
return; return;
startPart = new Date(); startPart = new Date();
if (MainApp.getConstraintChecker().isAMAModeEnabled().get()) { if (MainApp.getConstraintChecker().isAMAModeEnabled().value()) {
lastAutosensResult = IobCobCalculatorPlugin.getPlugin().detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis()); lastAutosensResult = IobCobCalculatorPlugin.getPlugin().detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis());
} else { } else {
lastAutosensResult = new AutosensResult(); lastAutosensResult = new AutosensResult();
@ -249,7 +248,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress()) if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
determineBasalResultAMA.tempBasalReqested = false; determineBasalResultAMA.tempBasalReqested = false;
// limit requests on openloop mode // limit requests on openloop mode
if (!MainApp.getConstraintChecker().isClosedLoopAllowed().get()) { if (!MainApp.getConstraintChecker().isClosedLoopAllowed().value()) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(now); TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(now);
if (activeTemp != null && determineBasalResultAMA.rate == 0 && determineBasalResultAMA.duration == 0) { if (activeTemp != null && determineBasalResultAMA.rate == 0 && determineBasalResultAMA.duration == 0) {

View file

@ -19,7 +19,6 @@ import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.androidaps.plugins.Loop.ScriptReader; import info.nightscout.androidaps.plugins.Loop.ScriptReader;
@ -30,7 +29,6 @@ import info.nightscout.utils.HardLimits;
import info.nightscout.utils.Profiler; import info.nightscout.utils.Profiler;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse;
import static info.nightscout.utils.HardLimits.checkOnlyHardLimits; import static info.nightscout.utils.HardLimits.checkOnlyHardLimits;
import static info.nightscout.utils.HardLimits.verifyHardLimits; import static info.nightscout.utils.HardLimits.verifyHardLimits;
@ -175,8 +173,8 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
String units = profile.getUnits(); String units = profile.getUnits();
double maxIob = SP.getDouble("openapsma_max_iob", 1.5d); double maxIob = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
double maxBasal = SafeParse.stringToDouble(SP.getString("openapsma_max_basal", "1")); double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
double minBg = Profile.toMgdl(profile.getTargetLow(), units); double minBg = Profile.toMgdl(profile.getTargetLow(), units);
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units); double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
double targetBg = Profile.toMgdl(profile.getTarget(), units); double targetBg = Profile.toMgdl(profile.getTarget(), units);
@ -238,7 +236,7 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress()) if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
determineBasalResultMA.tempBasalReqested = false; determineBasalResultMA.tempBasalReqested = false;
// limit requests on openloop mode // limit requests on openloop mode
if (!MainApp.getConstraintChecker().isClosedLoopAllowed().get()) { if (!MainApp.getConstraintChecker().isClosedLoopAllowed().value()) {
TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(now); TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(now);
if (activeTemp != null && determineBasalResultMA.rate == 0 && determineBasalResultMA.duration == 0) { if (activeTemp != null && determineBasalResultMA.rate == 0 && determineBasalResultMA.duration == 0) {
// going to cancel // going to cancel

View file

@ -27,7 +27,6 @@ import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Loop.ScriptReader; import info.nightscout.androidaps.plugins.Loop.ScriptReader;
@ -228,8 +227,8 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("target_bg", targetBg); mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc()); mProfile.put("carb_ratio", profile.getIc());
mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units)); mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units));
mProfile.put("max_daily_safety_multiplier", SP.getInt("openapsama_max_daily_safety_multiplier", 3)); mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
mProfile.put("current_basal_safety_multiplier", SP.getDouble("openapsama_current_basal_safety_multiplier", 4d)); mProfile.put("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
mProfile.put("high_temptarget_raises_sensitivity", SMBDefaults.high_temptarget_raises_sensitivity); mProfile.put("high_temptarget_raises_sensitivity", SMBDefaults.high_temptarget_raises_sensitivity);
mProfile.put("low_temptarget_lowers_sensitivity", SMBDefaults.low_temptarget_lowers_sensitivity); mProfile.put("low_temptarget_lowers_sensitivity", SMBDefaults.low_temptarget_lowers_sensitivity);
@ -245,7 +244,7 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap); mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap);
mProfile.put("enableUAM", SP.getBoolean(R.string.key_use_uam, false)); mProfile.put("enableUAM", SP.getBoolean(R.string.key_use_uam, false));
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable); mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
boolean SMBEnabled = MainApp.getConstraintChecker().isSMBModeEnabled().get() && MainApp.getConstraintChecker().isClosedLoopAllowed().get(); boolean SMBEnabled = MainApp.getConstraintChecker().isSMBModeEnabled().value() && MainApp.getConstraintChecker().isClosedLoopAllowed().value();
mProfile.put("enableSMB_with_COB", SMBEnabled && SP.getBoolean(R.string.key_enableSMB_with_COB, false)); mProfile.put("enableSMB_with_COB", SMBEnabled && SP.getBoolean(R.string.key_enableSMB_with_COB, false));
mProfile.put("enableSMB_with_temptarget", SMBEnabled && SP.getBoolean(R.string.key_enableSMB_with_temptarget, false)); mProfile.put("enableSMB_with_temptarget", SMBEnabled && SP.getBoolean(R.string.key_enableSMB_with_temptarget, false));
mProfile.put("allowSMB_with_high_temptarget", SMBEnabled && SP.getBoolean(R.string.key_allowSMB_with_high_temptarget, false)); mProfile.put("allowSMB_with_high_temptarget", SMBEnabled && SP.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
@ -301,7 +300,7 @@ public class DetermineBasalAdapterSMBJS {
mMealData.put("lastCarbTime", mealData.lastCarbTime); mMealData.put("lastCarbTime", mealData.lastCarbTime);
if (MainApp.getConstraintChecker().isAMAModeEnabled().get()) { if (MainApp.getConstraintChecker().isAMAModeEnabled().value()) {
mAutosensData = new JSONObject(); mAutosensData = new JSONObject();
mAutosensData.put("ratio", autosensDataRatio); mAutosensData.put("ratio", autosensDataRatio);
} else { } else {

View file

@ -19,7 +19,6 @@ import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
@ -179,8 +178,8 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
String units = profile.getUnits(); String units = profile.getUnits();
double maxIob = SP.getDouble("openapsma_max_iob", 1.5d); double maxIob = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
double maxBasal = SP.getDouble("openapsma_max_basal", 1d); double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
double minBg = Profile.toMgdl(profile.getTargetLow(), units); double minBg = Profile.toMgdl(profile.getTargetLow(), units);
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units); double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
double targetBg = Profile.toMgdl(profile.getTarget(), units); double targetBg = Profile.toMgdl(profile.getTarget(), units);
@ -225,7 +224,7 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return; if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return;
startPart = new Date(); startPart = new Date();
if (MainApp.getConstraintChecker().isAMAModeEnabled().get()) { if (MainApp.getConstraintChecker().isAMAModeEnabled().value()) {
lastAutosensResult = IobCobCalculatorPlugin.getPlugin().detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis()); lastAutosensResult = IobCobCalculatorPlugin.getPlugin().detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis());
} else { } else {
lastAutosensResult = new AutosensResult(); lastAutosensResult = new AutosensResult();
@ -254,7 +253,7 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress()) if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
determineBasalResultSMB.tempBasalReqested = false; determineBasalResultSMB.tempBasalReqested = false;
// limit requests on openloop mode // limit requests on openloop mode
if (!MainApp.getConstraintChecker().isClosedLoopAllowed().get()) { if (!MainApp.getConstraintChecker().isClosedLoopAllowed().value()) {
TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(now); TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(now);
if (activeTemp != null && determineBasalResultSMB.rate == 0 && determineBasalResultSMB.duration == 0) { if (activeTemp != null && determineBasalResultSMB.rate == 0 && determineBasalResultSMB.duration == 0) {
// going to cancel // going to cancel

View file

@ -1039,7 +1039,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
apsModeView.setText(MainApp.sResources.getString(R.string.pumpsuspended)); apsModeView.setText(MainApp.sResources.getString(R.string.pumpsuspended));
apsModeView.setTextColor(Color.WHITE); apsModeView.setTextColor(Color.WHITE);
} else if (activeloop != null && activeloop.isEnabled(activeloop.getType())) { } else if (activeloop != null && activeloop.isEnabled(activeloop.getType())) {
if (closedLoopEnabled.get()) { if (closedLoopEnabled.value()) {
apsModeView.setText(MainApp.sResources.getString(R.string.closedloop)); apsModeView.setText(MainApp.sResources.getString(R.string.closedloop));
} else { } else {
apsModeView.setText(MainApp.sResources.getString(R.string.openloop)); apsModeView.setText(MainApp.sResources.getString(R.string.openloop));
@ -1069,7 +1069,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// **** Temp button **** // **** Temp button ****
if (acceptTempLayout != null) { if (acceptTempLayout != null) {
boolean showAcceptButton = !closedLoopEnabled.get(); // Open mode needed boolean showAcceptButton = !closedLoopEnabled.value(); // Open mode needed
showAcceptButton = showAcceptButton && finalLastRun != null && finalLastRun.lastAPSRun != null; // aps result must exist showAcceptButton = showAcceptButton && finalLastRun != null && finalLastRun.lastAPSRun != null; // aps result must exist
showAcceptButton = showAcceptButton && (finalLastRun.lastOpenModeAccept == null || finalLastRun.lastOpenModeAccept.getTime() < finalLastRun.lastAPSRun.getTime()); // never accepted or before last result showAcceptButton = showAcceptButton && (finalLastRun.lastOpenModeAccept == null || finalLastRun.lastOpenModeAccept.getTime() < finalLastRun.lastAPSRun.getTime()); // never accepted or before last result
showAcceptButton = showAcceptButton && finalLastRun.constraintsProcessed.isChangeRequested(); // change is requested showAcceptButton = showAcceptButton && finalLastRun.constraintsProcessed.isChangeRequested(); // change is requested

View file

@ -746,7 +746,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
* the new value (and thus still has the old duration of e.g. 1 min) expires?) * the new value (and thus still has the old duration of e.g. 1 min) expires?)
*/ */
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force) { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean force) {
log.debug("setTempBasalAbsolute called with a rate of " + absoluteRate + " for " + durationInMinutes + " min."); log.debug("setTempBasalAbsolute called with a rate of " + absoluteRate + " for " + durationInMinutes + " min.");
int unroundedPercentage = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue(); int unroundedPercentage = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
int roundedPercentage = (int) (Math.round(absoluteRate / getBaseBasalRate() * 10) * 10); int roundedPercentage = (int) (Math.round(absoluteRate / getBaseBasalRate() * 10) * 10);
@ -1453,12 +1453,12 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
return absoluteRate; return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Integer applyBasalPercentConstraints(Integer percentRate) {
return percentRate; return percentRate;
} }

View file

@ -216,7 +216,7 @@ public abstract class AbstractDanaRPlugin implements PluginBase, PumpInterface,
@Override @Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
percent = MainApp.getConstraintChecker().applyBasalConstraints(percent); percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(percent);
if (percent < 0) { if (percent < 0) {
result.isTempCancel = false; result.isTempCancel = false;
result.enacted = false; result.enacted = false;
@ -458,23 +458,16 @@ public abstract class AbstractDanaRPlugin implements PluginBase, PumpInterface,
return value; return value;
} }
@SuppressWarnings("PointlessBooleanExpression")
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
double origAbsoluteRate = absoluteRate; if (pump != null)
if (pump != null) { absoluteRate.setIfSmaller(pump.maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), pump.maxBasal, MainApp.gs(R.string.pumplimit)));
if (absoluteRate > pump.maxBasal) {
absoluteRate = pump.maxBasal;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
}
}
return absoluteRate; return absoluteRate;
} }
@SuppressWarnings("PointlessBooleanExpression") @SuppressWarnings("PointlessBooleanExpression")
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Integer applyBasalPercentConstraints(Integer percentRate) {
Integer origPercentRate = percentRate; Integer origPercentRate = percentRate;
if (percentRate < 0) percentRate = 0; if (percentRate < 0) percentRate = 0;
if (percentRate > getPumpDescription().maxTempPercent) if (percentRate > getPumpDescription().maxTempPercent)

View file

@ -14,12 +14,14 @@ import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService; import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
@ -160,7 +162,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
// This is called from APS // This is called from APS
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
// Recheck pump status if older than 30 min // Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this //This should not be needed while using queue because connection should be done before calling this
//if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) { //if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) {
@ -169,7 +171,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(absoluteRate); absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d; final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate(); final boolean doLowTemp = absoluteRate < getBaseBasalRate();
@ -266,7 +268,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
Integer durationInHalfHours = Math.max(durationInMinutes / 30, 1); Integer durationInHalfHours = Math.max(durationInMinutes / 30, 1);
// We keep current basal running so need to sub current basal // We keep current basal running so need to sub current basal
Double extendedRateToSet = absoluteRate - getBaseBasalRate(); Double extendedRateToSet = absoluteRate - getBaseBasalRate();
extendedRateToSet = MainApp.getConstraintChecker().applyBasalConstraints(extendedRateToSet); extendedRateToSet = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(extendedRateToSet), profile).value();
// needs to be rounded to 0.1 // needs to be rounded to 0.1
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of halfhours extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of halfhours

View file

@ -14,12 +14,14 @@ import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService; import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService;
@ -161,7 +163,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
// This is called from APS // This is called from APS
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
// Recheck pump status if older than 30 min // Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this //This should not be needed while using queue because connection should be done before calling this
//if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) { //if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) {
@ -170,7 +172,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(absoluteRate); absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d; final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate(); final boolean doLowTemp = absoluteRate < getBaseBasalRate();
@ -267,7 +269,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
Integer durationInHalfHours = Math.max(durationInMinutes / 30, 1); Integer durationInHalfHours = Math.max(durationInMinutes / 30, 1);
// We keep current basal running so need to sub current basal // We keep current basal running so need to sub current basal
Double extendedRateToSet = absoluteRate - getBaseBasalRate(); Double extendedRateToSet = absoluteRate - getBaseBasalRate();
extendedRateToSet = MainApp.getConstraintChecker().applyBasalConstraints(extendedRateToSet); extendedRateToSet = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(extendedRateToSet), profile).value();
// needs to be rounded to 0.1 // needs to be rounded to 0.1
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of halfhours extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of halfhours

View file

@ -299,20 +299,14 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
double origAbsoluteRate = absoluteRate; if (pump != null)
if (pump != null) { absoluteRate.setIfSmaller(pump.maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), pump.maxBasal, MainApp.gs(R.string.pumplimit)));
if (absoluteRate > pump.maxBasal) {
absoluteRate = pump.maxBasal;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
}
}
return absoluteRate; return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Integer applyBasalPercentConstraints(Integer percentRate) {
Integer origPercentRate = percentRate; Integer origPercentRate = percentRate;
if (percentRate < 0) percentRate = 0; if (percentRate < 0) percentRate = 0;
if (percentRate > getPumpDescription().maxTempPercent) if (percentRate > getPumpDescription().maxTempPercent)
@ -512,7 +506,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
// This is called from APS // This is called from APS
@Override @Override
public synchronized PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { public synchronized PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
// Recheck pump status if older than 30 min // Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this //This should not be needed while using queue because connection should be done before calling this
@ -522,7 +516,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(absoluteRate); absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d; final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate(); final boolean doLowTemp = absoluteRate < getBaseBasalRate();
@ -594,7 +588,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override @Override
public synchronized PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { public synchronized PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
percent = MainApp.getConstraintChecker().applyBasalConstraints(percent); percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(percent);
if (percent < 0) { if (percent < 0) {
result.isTempCancel = false; result.isTempCancel = false;
result.enacted = false; result.enacted = false;

View file

@ -14,10 +14,12 @@ import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage; import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage;
import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
@ -183,7 +185,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
// This is called from APS // This is called from APS
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
// Recheck pump status if older than 30 min // Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this //This should not be needed while using queue because connection should be done before calling this
//if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) { //if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) {
@ -192,7 +194,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(absoluteRate); absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d; final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate(); final boolean doLowTemp = absoluteRate < getBaseBasalRate();
@ -262,7 +264,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
@Override @Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
percent = MainApp.getConstraintChecker().applyBasalConstraints(percent); percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(percent);
if (percent < 0) { if (percent < 0) {
result.isTempCancel = false; result.isTempCancel = false;
result.enacted = false; result.enacted = false;

View file

@ -355,7 +355,7 @@ public class InsightPumpPlugin implements PluginBase, PumpInterface, Constraints
Mstatus mstatus = async.busyWaitForCommandResult(uuid, BUSY_WAIT_TIME); Mstatus mstatus = async.busyWaitForCommandResult(uuid, BUSY_WAIT_TIME);
if (mstatus.success()) { if (mstatus.success()) {
log("GOT STATUS RESULT!!! PARTY WOOHOO!!!"); log("GOT STATUS RESULT!!! PARTY WOOHOO!!!");
statusResult = (StatusTaskRunner.Result) mstatus.getResponseObject(); setStatusResult((StatusTaskRunner.Result) mstatus.getResponseObject());
statusResultTime = Helpers.tsl(); statusResultTime = Helpers.tsl();
processStatusResult(); processStatusResult();
updateGui(); updateGui();
@ -375,6 +375,10 @@ public class InsightPumpPlugin implements PluginBase, PumpInterface, Constraints
} }
} }
public void setStatusResult(StatusTaskRunner.Result result) {
this.statusResult = result;
}
@Override @Override
public PumpEnactResult setNewBasalProfile(Profile profile) { public PumpEnactResult setNewBasalProfile(Profile profile) {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
@ -543,7 +547,7 @@ public class InsightPumpPlugin implements PluginBase, PumpInterface, Constraints
// Temporary Basals // Temporary Basals
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
absoluteRate = Helpers.roundDouble(absoluteRate, 3); absoluteRate = Helpers.roundDouble(absoluteRate, 3);
log("Set TBR absolute: " + absoluteRate); log("Set TBR absolute: " + absoluteRate);
final double base_basal = getBaseBasalRate(); final double base_basal = getBaseBasalRate();
@ -1105,12 +1109,15 @@ public class InsightPumpPlugin implements PluginBase, PumpInterface, Constraints
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
return Math.min(absoluteRate, statusResult != null ? statusResult.maximumBasalAmount : 0); if (statusResult != null) {
absoluteRate.setIfSmaller(statusResult.maximumBasalAmount, String.format(MainApp.gs(R.string.limitingbasalratio), statusResult.maximumBasalAmount, MainApp.gs(R.string.pumplimit)));
}
return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Integer applyBasalPercentConstraints(Integer percentRate) {
return Math.min(percentRate, pumpDescription.maxTempPercent); return Math.min(percentRate, pumpDescription.maxTempPercent);
} }

View file

@ -194,7 +194,7 @@ public class MDIPlugin implements PluginBase, PumpInterface {
} }
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(); PumpEnactResult result = new PumpEnactResult();
result.success = false; result.success = false;
result.comment = MainApp.instance().getString(R.string.pumperror); result.comment = MainApp.instance().getString(R.string.pumperror);

View file

@ -289,7 +289,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
} }
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
TreatmentsInterface treatmentsInterface = MainApp.getConfigBuilder(); TreatmentsInterface treatmentsInterface = MainApp.getConfigBuilder();
TemporaryBasal tempBasal = new TemporaryBasal(); TemporaryBasal tempBasal = new TemporaryBasal();
tempBasal.date = System.currentTimeMillis(); tempBasal.date = System.currentTimeMillis();

View file

@ -29,6 +29,7 @@ import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
@ -418,18 +419,24 @@ public class SmsCommunicatorPlugin implements PluginBase {
} }
} else { } else {
tempBasal = SafeParse.stringToDouble(splited[1]); tempBasal = SafeParse.stringToDouble(splited[1]);
tempBasal = MainApp.getConstraintChecker().applyBasalConstraints(tempBasal); Profile profile = MainApp.getConfigBuilder().getProfile();
if (remoteCommandsAllowed) { if (profile == null) {
passCode = generatePasscode(); reply = MainApp.sResources.getString(R.string.noprofile);
reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_basalreplywithcode), tempBasal, passCode);
receivedSms.processed = true;
resetWaitingMessages();
sendSMS(tempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode));
tempBasalWaitingForConfirmation.tempBasal = tempBasal;
FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Basal"));
} else {
reply = MainApp.sResources.getString(R.string.smscommunicator_remotebasalnotallowed);
sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
} else {
tempBasal = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(tempBasal), profile).value();
if (remoteCommandsAllowed) {
passCode = generatePasscode();
reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_basalreplywithcode), tempBasal, passCode);
receivedSms.processed = true;
resetWaitingMessages();
sendSMS(tempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode));
tempBasalWaitingForConfirmation.tempBasal = tempBasal;
FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Basal"));
} else {
reply = MainApp.sResources.getString(R.string.smscommunicator_remotebasalnotallowed);
sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
} }
} }
} }
@ -503,20 +510,22 @@ public class SmsCommunicatorPlugin implements PluginBase {
} else if (tempBasalWaitingForConfirmation != null && !tempBasalWaitingForConfirmation.processed && } else if (tempBasalWaitingForConfirmation != null && !tempBasalWaitingForConfirmation.processed &&
tempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - tempBasalWaitingForConfirmation.date.getTime() < CONFIRM_TIMEOUT) { tempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - tempBasalWaitingForConfirmation.date.getTime() < CONFIRM_TIMEOUT) {
tempBasalWaitingForConfirmation.processed = true; tempBasalWaitingForConfirmation.processed = true;
ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(tempBasalWaitingForConfirmation.tempBasal, 30, true, new Callback() { Profile profile = MainApp.getConfigBuilder().getProfile();
@Override if (profile != null)
public void run() { ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(tempBasalWaitingForConfirmation.tempBasal, 30, true, profile, new Callback() {
if (result.success) { @Override
String reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_tempbasalset), result.absolute, result.duration); public void run() {
reply += "\n" + ConfigBuilderPlugin.getActivePump().shortStatus(true); if (result.success) {
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date())); String reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_tempbasalset), result.absolute, result.duration);
} else { reply += "\n" + ConfigBuilderPlugin.getActivePump().shortStatus(true);
String reply = MainApp.sResources.getString(R.string.smscommunicator_tempbasalfailed); sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date()));
reply += "\n" + ConfigBuilderPlugin.getActivePump().shortStatus(true); } else {
sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); String reply = MainApp.sResources.getString(R.string.smscommunicator_tempbasalfailed);
reply += "\n" + ConfigBuilderPlugin.getActivePump().shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
} }
} });
});
} else if (cancelTempBasalWaitingForConfirmation != null && !cancelTempBasalWaitingForConfirmation.processed && } else if (cancelTempBasalWaitingForConfirmation != null && !cancelTempBasalWaitingForConfirmation.processed &&
cancelTempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - cancelTempBasalWaitingForConfirmation.date.getTime() < CONFIRM_TIMEOUT) { cancelTempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - cancelTempBasalWaitingForConfirmation.date.getTime() < CONFIRM_TIMEOUT) {
cancelTempBasalWaitingForConfirmation.processed = true; cancelTempBasalWaitingForConfirmation.processed = true;

View file

@ -27,7 +27,6 @@ import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.Actions.dialogs.FillDialog; import info.nightscout.androidaps.plugins.Actions.dialogs.FillDialog;
import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
@ -435,7 +434,7 @@ public class ActionStringHandler {
// decide if enabled/disabled closed/open; what Plugin as APS? // decide if enabled/disabled closed/open; what Plugin as APS?
final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop();
if (activeloop != null && activeloop.isEnabled(activeloop.getType())) { if (activeloop != null && activeloop.isEnabled(activeloop.getType())) {
if (MainApp.getConstraintChecker().isClosedLoopAllowed().get()) { if (MainApp.getConstraintChecker().isClosedLoopAllowed().value()) {
ret += "CLOSED LOOP\n"; ret += "CLOSED LOOP\n";
} else { } else {
ret += "OPEN LOOP\n"; ret += "OPEN LOOP\n";

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.events.EventBolusRequested; import info.nightscout.androidaps.events.EventBolusRequested;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog; import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
@ -186,7 +187,7 @@ public class CommandQueue {
} }
// returns true if command is queued // returns true if command is queued
public boolean tempBasalAbsolute(double absoluteRate, int durationInMinutes, boolean enforceNew, Callback callback) { public boolean tempBasalAbsolute(double absoluteRate, int durationInMinutes, boolean enforceNew, Profile profile, Callback callback) {
if (isRunning(Command.CommandType.TEMPBASAL)) { if (isRunning(Command.CommandType.TEMPBASAL)) {
if (callback != null) if (callback != null)
callback.result(executingNowError()).run(); callback.result(executingNowError()).run();
@ -196,10 +197,10 @@ public class CommandQueue {
// remove all unfinished // remove all unfinished
removeAll(Command.CommandType.TEMPBASAL); removeAll(Command.CommandType.TEMPBASAL);
Double rateAfterConstraints = MainApp.getConstraintChecker().applyBasalConstraints(absoluteRate); Double rateAfterConstraints = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
// add new command to queue // add new command to queue
add(new CommandTempBasalAbsolute(rateAfterConstraints, durationInMinutes, enforceNew, callback)); add(new CommandTempBasalAbsolute(rateAfterConstraints, durationInMinutes, enforceNew, profile, callback));
notifyAboutNewCommand(); notifyAboutNewCommand();
@ -217,7 +218,7 @@ public class CommandQueue {
// remove all unfinished // remove all unfinished
removeAll(Command.CommandType.TEMPBASAL); removeAll(Command.CommandType.TEMPBASAL);
Integer percentAfterConstraints = MainApp.getConstraintChecker().applyBasalConstraints(percent); Integer percentAfterConstraints = MainApp.getConstraintChecker().applyBasalPercentConstraints(percent);
// add new command to queue // add new command to queue
add(new CommandTempBasalPercent(percentAfterConstraints, durationInMinutes, enforceNew, callback)); add(new CommandTempBasalPercent(percentAfterConstraints, durationInMinutes, enforceNew, callback));

View file

@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
@ -19,18 +20,20 @@ public class CommandTempBasalAbsolute extends Command {
int durationInMinutes; int durationInMinutes;
double absoluteRate; double absoluteRate;
boolean enforceNew; boolean enforceNew;
Profile profile;
public CommandTempBasalAbsolute(double absoluteRate, int durationInMinutes, boolean enforceNew, Callback callback) { public CommandTempBasalAbsolute(double absoluteRate, int durationInMinutes, boolean enforceNew, Profile profile, Callback callback) {
commandType = CommandType.TEMPBASAL; commandType = CommandType.TEMPBASAL;
this.absoluteRate = absoluteRate; this.absoluteRate = absoluteRate;
this.durationInMinutes = durationInMinutes; this.durationInMinutes = durationInMinutes;
this.enforceNew = enforceNew; this.enforceNew = enforceNew;
this.profile = profile;
this.callback = callback; this.callback = callback;
} }
@Override @Override
public void execute() { public void execute() {
PumpEnactResult r = ConfigBuilderPlugin.getActivePump().setTempBasalAbsolute(absoluteRate, durationInMinutes, enforceNew); PumpEnactResult r = ConfigBuilderPlugin.getActivePump().setTempBasalAbsolute(absoluteRate, durationInMinutes, profile, enforceNew);
if (Config.logCongigBuilderActions) if (Config.logCongigBuilderActions)
log.debug("setTempBasalAbsolute rate: " + absoluteRate + " durationInMinutes: " + durationInMinutes + " success: " + r.success + " enacted: " + r.enacted); log.debug("setTempBasalAbsolute rate: " + absoluteRate + " durationInMinutes: " + durationInMinutes + " success: " + r.success + " enacted: " + r.enacted);
if (callback != null) if (callback != null)

View file

@ -430,9 +430,7 @@
<string name="advancedsettings_title">Advanced Settings</string> <string name="advancedsettings_title">Advanced Settings</string>
<string name="danar_model" formatted="false">Model: %02X Protocol: %02X Code: %02X</string> <string name="danar_model" formatted="false">Model: %02X Protocol: %02X Code: %02X</string>
<string name="profile">Profile</string> <string name="profile">Profile</string>
<string name="openapsama_max_daily_safety_multiplier" translatable="false">max_daily_safety_multiplier</string>
<string name="openapsama_max_daily_safety_multiplier_summary">Default value: 3 This is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware thats what is discussed about “3x max daily; 4x current” for safety caps.</string> <string name="openapsama_max_daily_safety_multiplier_summary">Default value: 3 This is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware thats what is discussed about “3x max daily; 4x current” for safety caps.</string>
<string name="openapsama_current_basal_safety_multiplier" translatable="false">current_basal_safety_multiplier</string>
<string name="openapsama_current_basal_safety_multiplier_summary">Default value: 4 This is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.</string> <string name="openapsama_current_basal_safety_multiplier_summary">Default value: 4 This is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.</string>
<string name="openapsama_autosens_max" translatable="false">autosens_max</string> <string name="openapsama_autosens_max" translatable="false">autosens_max</string>
<string name="openapsama_autosens_max_summary">Default value: 1.2\nThis is a multiplier cap for autosens (and soon autotune) to set a 20% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target.</string> <string name="openapsama_autosens_max_summary">Default value: 1.2\nThis is a multiplier cap for autosens (and soon autotune) to set a 20% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target.</string>
@ -968,5 +966,15 @@
<string name="closedmodedisabledinpreferences">Closed loop mode disabled in preferences</string> <string name="closedmodedisabledinpreferences">Closed loop mode disabled in preferences</string>
<string name="amadisabledinpreferences">AMA disabled in preferences</string> <string name="amadisabledinpreferences">AMA disabled in preferences</string>
<string name="smbdisabledinpreferences">SMB disabled in preferences</string> <string name="smbdisabledinpreferences">SMB disabled in preferences</string>
<string name="limitingbasalratio">Limiting basal rate to %.2f U/h because of %s</string>
<string name="pumplimit">pump limit</string>
<string name="key_openapsma_max_basal" translatable="false">openapsma_max_basal</string>
<string name="key_openapsama_current_basal_safety_multiplier" translatable="false">openapsama_current_basal_safety_multiplier</string>
<string name="key_openapsama_max_daily_safety_multiplier" translatable="false">openapsama_max_daily_safety_multiplier</string>
<string name="basalmustbepositivevalue">basal must be positive value</string>
<string name="maxbasalinpreferences">max basal settings in preferences</string>
<string name="maxbasalmultiplier">max basal multiplier</string>
<string name="maxdailybasalmultiplier">max daily basal multiplier</string>
<string name="key_openapsma_max_iob" translatable="false">openapsma_max_iob</string>
</resources> </resources>

View file

@ -46,10 +46,10 @@
android:dialogMessage="@string/openapsama_max_daily_safety_multiplier_summary" android:dialogMessage="@string/openapsama_max_daily_safety_multiplier_summary"
android:digits="0123456789.," android:digits="0123456789.,"
android:inputType="number" android:inputType="number"
android:key="openapsama_max_daily_safety_multiplier" android:key="@string/key_openapsama_max_daily_safety_multiplier"
android:maxLines="20" android:maxLines="20"
android:selectAllOnFocus="true" android:selectAllOnFocus="true"
android:title="@string/openapsama_max_daily_safety_multiplier" android:title="@string/key_openapsama_max_daily_safety_multiplier"
validate:maxNumber="10" validate:maxNumber="10"
validate:minNumber="1" validate:minNumber="1"
validate:testType="numericRange" /> validate:testType="numericRange" />
@ -58,11 +58,11 @@
android:dialogMessage="@string/openapsama_current_basal_safety_multiplier_summary" android:dialogMessage="@string/openapsama_current_basal_safety_multiplier_summary"
android:digits="0123456789.," android:digits="0123456789.,"
android:inputType="number" android:inputType="number"
android:key="openapsama_current_basal_safety_multiplier" android:key="@string/key_openapsama_current_basal_safety_multiplier"
android:maxLines="20" android:maxLines="20"
android:selectAllOnFocus="true" android:selectAllOnFocus="true"
android:singleLine="true" android:singleLine="true"
android:title="@string/openapsama_current_basal_safety_multiplier" android:title="@string/key_openapsama_current_basal_safety_multiplier"
validate:floatmaxNumber="10" validate:floatmaxNumber="10"
validate:floatminNumber="1" validate:floatminNumber="1"
validate:testType="floatNumericRange" /> validate:testType="floatNumericRange" />

View file

@ -7,13 +7,13 @@
<EditTextPreference <EditTextPreference
android:defaultValue="1" android:defaultValue="1"
android:key="openapsma_max_basal" android:key="@string/key_openapsma_max_basal"
android:numeric="decimal" android:numeric="decimal"
android:dialogMessage="@string/openapsma_maxbasal_summary" android:dialogMessage="@string/openapsma_maxbasal_summary"
android:title="@string/openapsma_maxbasal_title" /> android:title="@string/openapsma_maxbasal_title" />
<EditTextPreference <EditTextPreference
android:defaultValue="1.5" android:defaultValue="1.5"
android:key="openapsma_max_iob" android:key="@string/key_openapsma_max_iob"
android:numeric="decimal" android:numeric="decimal"
android:dialogMessage="@string/openapsma_maxiob_summary" android:dialogMessage="@string/openapsma_maxiob_summary"
android:title="@string/openapsma_maxiob_title" /> android:title="@string/openapsma_maxiob_title" />

View file

@ -6,13 +6,13 @@
<EditTextPreference <EditTextPreference
android:defaultValue="1" android:defaultValue="1"
android:key="openapsma_max_basal" android:key="@string/key_openapsma_max_basal"
android:numeric="decimal" android:numeric="decimal"
android:dialogMessage="@string/openapsma_maxbasal_summary" android:dialogMessage="@string/openapsma_maxbasal_summary"
android:title="@string/openapsma_maxbasal_title" /> android:title="@string/openapsma_maxbasal_title" />
<EditTextPreference <EditTextPreference
android:defaultValue="1.5" android:defaultValue="1.5"
android:key="openapsma_max_iob" android:key="@string/key_openapsma_max_iob"
android:numeric="decimal" android:numeric="decimal"
android:dialogMessage="@string/openapsma_maxiob_summary" android:dialogMessage="@string/openapsma_maxiob_summary"
android:title="@string/openapsma_maxiob_title" /> android:title="@string/openapsma_maxiob_title" />

View file

@ -6,13 +6,13 @@
android:title="@string/openapssmb"> android:title="@string/openapssmb">
<EditTextPreference <EditTextPreference
android:defaultValue="1" android:defaultValue="1"
android:key="openapsma_max_basal" android:key="@string/key_openapsma_max_basal"
android:numeric="decimal" android:numeric="decimal"
android:dialogMessage="@string/openapsma_maxbasal_summary" android:dialogMessage="@string/openapsma_maxbasal_summary"
android:title="@string/openapsma_maxbasal_title" /> android:title="@string/openapsma_maxbasal_title" />
<EditTextPreference <EditTextPreference
android:defaultValue="1.5" android:defaultValue="1.5"
android:key="openapsma_max_iob" android:key="@string/key_openapsma_max_iob"
android:numeric="decimal" android:numeric="decimal"
android:dialogMessage="@string/openapsma_maxiob_summary" android:dialogMessage="@string/openapsma_maxiob_summary"
android:title="@string/openapsma_maxiob_title" /> android:title="@string/openapsma_maxiob_title" />

View file

@ -6,8 +6,6 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import info.nightscout.androidaps.interfaces.Constraint;
/** /**
* Created by mike on 19.03.2018. * Created by mike on 19.03.2018.
*/ */
@ -17,19 +15,28 @@ public class ConstraintTest {
@Test @Test
public void doTests() throws Exception { public void doTests() throws Exception {
Constraint<Boolean> c; Constraint<Boolean> b = new Constraint<>(true);
Assert.assertEquals(Boolean.TRUE, b.value());
Assert.assertEquals("", b.getReasons());
b.set(false);
Assert.assertEquals(Boolean.FALSE, b.value());
Assert.assertEquals("", b.getReasons());
b.set(true, "Set true");
Assert.assertEquals(Boolean.TRUE, b.value());
Assert.assertEquals("Set true", b.getReasons());
b.set(false, "Set false");
Assert.assertEquals(Boolean.FALSE, b.value());
Assert.assertEquals("Set true\nSet false", b.getReasons());
c = new Constraint<Boolean>(true); Constraint<Double> d = new Constraint<>(10d);
Assert.assertEquals(Boolean.TRUE, c.get()); d.set(5d, "Set 5d");
Assert.assertEquals("", c.getReasons()); Assert.assertEquals(5d, b.value());
c.set(false); Assert.assertEquals("Set 5d", b.getReasons());
Assert.assertEquals(Boolean.FALSE, c.get()); d.setIfSmaller(6d, "Set 6d");
Assert.assertEquals("", c.getReasons()); Assert.assertEquals(5d, b.value());
c.set(true, "Set true"); Assert.assertEquals("Set 5d", b.getReasons());
Assert.assertEquals(Boolean.TRUE, c.get()); d.setIfSmaller(4d, "Set 4d");
Assert.assertEquals("Set true", c.getReasons()); Assert.assertEquals(4d, b.value());
c.set(false, "Set false"); Assert.assertEquals("Set 5d\nSet 4d", b.getReasons());
Assert.assertEquals(Boolean.FALSE, c.get());
Assert.assertEquals("Set true\nSet false", c.getReasons());
} }
} }

View file

@ -1,9 +1,13 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import android.content.Context;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import junit.framework.Assert; import junit.framework.Assert;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -14,13 +18,20 @@ import org.powermock.modules.junit4.PowerMockRunner;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.ConstraintChecker; import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin; import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPumpPlugin;
import info.nightscout.androidaps.plugins.PumpInsight.connector.StatusTaskRunner;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -32,7 +43,7 @@ import static org.mockito.Mockito.when;
* Created by mike on 18.03.2018. * Created by mike on 18.03.2018.
*/ */
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, FabricPrivacy.class, SP.class}) @PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, FabricPrivacy.class, SP.class, Context.class})
public class ConstraintsCheckerTest { public class ConstraintsCheckerTest {
PumpInterface pump = new VirtualPumpPlugin(); PumpInterface pump = new VirtualPumpPlugin();
@ -42,12 +53,21 @@ public class ConstraintsCheckerTest {
MainApp mainApp = mock(MainApp.class); MainApp mainApp = mock(MainApp.class);
MockedBus bus = new MockedBus(); MockedBus bus = new MockedBus();
String validProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"},{\"time\":\"2:00\",\"value\":\"110\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}";
Profile profile = new Profile(new JSONObject(validProfile), Constants.MGDL);
SafetyPlugin safetyPlugin; SafetyPlugin safetyPlugin;
ObjectivesPlugin objectivesPlugin; ObjectivesPlugin objectivesPlugin;
ComboPlugin comboPlugin; ComboPlugin comboPlugin;
DanaRPlugin danaRPlugin;
DanaRSPlugin danaRSPlugin;
InsightPumpPlugin insightPlugin;
boolean notificationSent = false; boolean notificationSent = false;
public ConstraintsCheckerTest() throws JSONException {
}
// isLoopInvokationAllowed tests // isLoopInvokationAllowed tests
@Test @Test
public void pumpDescriptionShouldLimitLoopInvokation() throws Exception { public void pumpDescriptionShouldLimitLoopInvokation() throws Exception {
@ -55,7 +75,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isLoopInvokationAllowed(); Constraint<Boolean> c = constraintChecker.isLoopInvokationAllowed();
Assert.assertEquals(true, c.getReasons().contains("Pump is not temp basal capable")); Assert.assertEquals(true, c.getReasons().contains("Pump is not temp basal capable"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
@Test @Test
@ -64,7 +84,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isLoopInvokationAllowed(); Constraint<Boolean> c = constraintChecker.isLoopInvokationAllowed();
Assert.assertEquals(true, c.getReasons().contains("Objective 1 not started")); Assert.assertEquals(true, c.getReasons().contains("Objective 1 not started"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
@Test @Test
@ -74,7 +94,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isLoopInvokationAllowed(); Constraint<Boolean> c = constraintChecker.isLoopInvokationAllowed();
Assert.assertEquals(true, c.getReasons().contains("No valid basal rate read from pump")); Assert.assertEquals(true, c.getReasons().contains("No valid basal rate read from pump"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
// isClosedLoopAllowed tests // isClosedLoopAllowed tests
@ -85,7 +105,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isClosedLoopAllowed(); Constraint<Boolean> c = constraintChecker.isClosedLoopAllowed();
Assert.assertEquals(true, c.getReasons().contains("Running dev version. Closed loop is disabled.")); Assert.assertEquals(true, c.getReasons().contains("Running dev version. Closed loop is disabled."));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
@Test @Test
@ -94,7 +114,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isClosedLoopAllowed(); Constraint<Boolean> c = constraintChecker.isClosedLoopAllowed();
Assert.assertEquals(true, c.getReasons().contains("Closed loop mode disabled in preferences")); Assert.assertEquals(true, c.getReasons().contains("Closed loop mode disabled in preferences"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
@Test @Test
@ -104,7 +124,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isClosedLoopAllowed(); Constraint<Boolean> c = constraintChecker.isClosedLoopAllowed();
Assert.assertEquals(true, c.getReasons().contains("Objective 4 not started")); Assert.assertEquals(true, c.getReasons().contains("Objective 4 not started"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
// isAutosensModeEnabled tests // isAutosensModeEnabled tests
@ -114,7 +134,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isAutosensModeEnabled(); Constraint<Boolean> c = constraintChecker.isAutosensModeEnabled();
Assert.assertEquals(true, c.getReasons().contains("Objective 6 not started")); Assert.assertEquals(true, c.getReasons().contains("Objective 6 not started"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
// isAMAModeEnabled tests // isAMAModeEnabled tests
@ -124,7 +144,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isAMAModeEnabled(); Constraint<Boolean> c = constraintChecker.isAMAModeEnabled();
Assert.assertEquals(true, c.getReasons().contains("AMA disabled in preferences")); Assert.assertEquals(true, c.getReasons().contains("AMA disabled in preferences"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
@Test @Test
@ -133,7 +153,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isAMAModeEnabled(); Constraint<Boolean> c = constraintChecker.isAMAModeEnabled();
Assert.assertEquals(true, c.getReasons().contains("Objective 7 not started")); Assert.assertEquals(true, c.getReasons().contains("Objective 7 not started"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
// isSMBModeEnabled tests // isSMBModeEnabled tests
@ -143,7 +163,7 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isSMBModeEnabled(); Constraint<Boolean> c = constraintChecker.isSMBModeEnabled();
Assert.assertEquals(true, c.getReasons().contains("SMB disabled in preferences")); Assert.assertEquals(true, c.getReasons().contains("SMB disabled in preferences"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
} }
@Test @Test
@ -152,7 +172,46 @@ public class ConstraintsCheckerTest {
Constraint<Boolean> c = constraintChecker.isSMBModeEnabled(); Constraint<Boolean> c = constraintChecker.isSMBModeEnabled();
Assert.assertEquals(true, c.getReasons().contains("Objective 8 not started")); Assert.assertEquals(true, c.getReasons().contains("Objective 8 not started"));
Assert.assertEquals(Boolean.FALSE, c.get()); Assert.assertEquals(Boolean.FALSE, c.value());
}
// applyBasalConstraints tests
@Test
public void basalRateShouldBeLimited() throws Exception {
// DanaR, RS
danaRPlugin.setFragmentEnabled(PluginBase.PUMP, true);
danaRSPlugin.setFragmentEnabled(PluginBase.PUMP, true);
DanaRPump.getInstance().maxBasal = 0.8d;
// Insight
insightPlugin.setFragmentEnabled(PluginBase.PUMP, true);
StatusTaskRunner.Result result = new StatusTaskRunner.Result();
result.maximumBasalAmount = 1.1d;
insightPlugin.setStatusResult(result);
// No limit by default
when(SP.getDouble(R.string.key_openapsma_max_basal, 1d)).thenReturn(1d);
when(SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d)).thenReturn(4d);
when(SP.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d)).thenReturn(3d);
// Negative basal not allowed
Constraint<Double> d = new Constraint<>(-0.5d);
constraintChecker.applyBasalConstraints(d, profile);
Assert.assertEquals(0d, d.value());
Assert.assertEquals("Limiting basal rate to 0,00 U/h because of basal must be positive value", d.getReasons());
// Apply all limits
d = new Constraint<>(Constants.REALLYHIGHBASALRATE);
constraintChecker.applyBasalConstraints(d, profile);
Assert.assertEquals(0.8d, d.value());
Assert.assertEquals("Limiting basal rate to 1,00 U/h because of max basal settings in preferences\n" +
"Limiting basal rate to 4,00 U/h because of max basal multiplier\n" +
"Limiting basal rate to 3,00 U/h because of max daily basal multiplier\n" +
"Limiting basal rate to 0,80 U/h because of pump limit\n" +
"Limiting basal rate to 0,80 U/h because of pump limit\n" +
"Limiting basal rate to 1,10 U/h because of pump limit", d.getReasons());
} }
@Before @Before
@ -168,6 +227,9 @@ public class ConstraintsCheckerTest {
PowerMockito.mockStatic(FabricPrivacy.class); PowerMockito.mockStatic(FabricPrivacy.class);
Context context = mock(Context.class);
when(MainApp.instance().getApplicationContext()).thenReturn(context);
when(MainApp.bus()).thenReturn(bus); when(MainApp.bus()).thenReturn(bus);
when(MainApp.gs(R.string.pumpisnottempbasalcapable)).thenReturn("Pump is not temp basal capable"); when(MainApp.gs(R.string.pumpisnottempbasalcapable)).thenReturn("Pump is not temp basal capable");
@ -177,17 +239,32 @@ public class ConstraintsCheckerTest {
when(MainApp.gs(R.string.novalidbasalrate)).thenReturn("No valid basal rate read from pump"); when(MainApp.gs(R.string.novalidbasalrate)).thenReturn("No valid basal rate read from pump");
when(MainApp.gs(R.string.amadisabledinpreferences)).thenReturn("AMA disabled in preferences"); when(MainApp.gs(R.string.amadisabledinpreferences)).thenReturn("AMA disabled in preferences");
when(MainApp.gs(R.string.smbdisabledinpreferences)).thenReturn("SMB disabled in preferences"); when(MainApp.gs(R.string.smbdisabledinpreferences)).thenReturn("SMB disabled in preferences");
when(MainApp.gs(R.string.limitingbasalratio)).thenReturn("Limiting basal rate to %.2f U/h because of %s");
when(MainApp.gs(R.string.pumplimit)).thenReturn("pump limit");
when(MainApp.gs(R.string.basalmustbepositivevalue)).thenReturn("basal must be positive value");
when(MainApp.gs(R.string.maxbasalinpreferences)).thenReturn("max basal settings in preferences");
when(MainApp.gs(R.string.maxbasalmultiplier)).thenReturn("max basal multiplier");
when(MainApp.gs(R.string.maxdailybasalmultiplier)).thenReturn("max daily basal multiplier");
PowerMockito.mockStatic(SP.class);
// RS constructor
when(SP.getString(R.string.key_danars_address, "")).thenReturn("");
safetyPlugin = SafetyPlugin.getPlugin(); safetyPlugin = SafetyPlugin.getPlugin();
objectivesPlugin = ObjectivesPlugin.getPlugin(); objectivesPlugin = ObjectivesPlugin.getPlugin();
comboPlugin = ComboPlugin.getPlugin(); comboPlugin = ComboPlugin.getPlugin();
danaRPlugin = DanaRPlugin.getPlugin();
danaRSPlugin = DanaRSPlugin.getPlugin();
insightPlugin = InsightPumpPlugin.getPlugin();
ArrayList<PluginBase> constraintsPluginsList = new ArrayList<>(); ArrayList<PluginBase> constraintsPluginsList = new ArrayList<>();
constraintsPluginsList.add(safetyPlugin); constraintsPluginsList.add(safetyPlugin);
constraintsPluginsList.add(objectivesPlugin); constraintsPluginsList.add(objectivesPlugin);
constraintsPluginsList.add(comboPlugin); constraintsPluginsList.add(comboPlugin);
constraintsPluginsList.add(danaRPlugin);
constraintsPluginsList.add(danaRSPlugin);
constraintsPluginsList.add(insightPlugin);
when(mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class)).thenReturn(constraintsPluginsList); when(mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class)).thenReturn(constraintsPluginsList);
PowerMockito.mockStatic(SP.class);
} }
class MockedBus extends Bus { class MockedBus extends Bus {

View file

@ -7,6 +7,7 @@ import com.squareup.otto.ThreadEnforcer;
import junit.framework.Assert; import junit.framework.Assert;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -36,7 +37,11 @@ import static org.mockito.Mockito.when;
@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class}) @PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class})
public class CommandQueueTest extends CommandQueue { public class CommandQueueTest extends CommandQueue {
String profileJson = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"; String validProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"},{\"time\":\"2:00\",\"value\":\"110\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}";
Profile profile = new Profile(new JSONObject(validProfile), Constants.MGDL);
public CommandQueueTest() throws JSONException {
}
@Test @Test
public void doTests() throws Exception { public void doTests() throws Exception {
@ -62,7 +67,7 @@ public class CommandQueueTest extends CommandQueue {
Assert.assertEquals(0, size()); Assert.assertEquals(0, size());
// add tempbasal // add tempbasal
tempBasalAbsolute(0, 30, true, null); tempBasalAbsolute(0, 30, true, profile, null);
Assert.assertEquals(1, size()); Assert.assertEquals(1, size());
// add tempbasal percent. it should replace previous TEMPBASAL // add tempbasal percent. it should replace previous TEMPBASAL
@ -83,7 +88,7 @@ public class CommandQueueTest extends CommandQueue {
// add setProfile (command is not queued before unless a ProfileSwitch exists) // add setProfile (command is not queued before unless a ProfileSwitch exists)
// TODO test with profile switch set // TODO test with profile switch set
setProfile(new Profile(new JSONObject(profileJson), Constants.MGDL), null); setProfile(profile, null);
Assert.assertEquals(2, size()); Assert.assertEquals(2, size());
// add loadHistory // add loadHistory
@ -95,7 +100,7 @@ public class CommandQueueTest extends CommandQueue {
Assert.assertEquals(4, size()); Assert.assertEquals(4, size());
clear(); clear();
tempBasalAbsolute(0, 30, true, null); tempBasalAbsolute(0, 30, true, profile, null);
pickup(); pickup();
Assert.assertEquals(0, size()); Assert.assertEquals(0, size());
Assert.assertNotNull(performing); Assert.assertNotNull(performing);