Profile tests

This commit is contained in:
Milos Kozak 2018-03-18 15:02:21 +01:00
parent 7961a9f00a
commit f7621c4cc5
20 changed files with 277 additions and 93 deletions

View file

@ -238,6 +238,7 @@ dependencies {
testCompile "org.powermock:powermock-module-junit4:${powermockVersion}" testCompile "org.powermock:powermock-module-junit4:${powermockVersion}"
testCompile "joda-time:joda-time:2.9.4.2" testCompile "joda-time:joda-time:2.9.4.2"
testCompile "com.google.truth:truth:0.39" testCompile "com.google.truth:truth:0.39"
testCompile "org.skyscreamer:jsonassert:1.5.0"
androidTestCompile "org.mockito:mockito-core:2.7.22" androidTestCompile "org.mockito:mockito-core:2.7.22"
androidTestCompile "com.google.dexmaker:dexmaker:${dexmakerVersion}" androidTestCompile "com.google.dexmaker:dexmaker:${dexmakerVersion}"

View file

@ -2,8 +2,6 @@ package info.nightscout.androidaps.data;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -19,41 +17,43 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.ToastUtils;
public class Profile { public class Profile {
private static Logger log = LoggerFactory.getLogger(Profile.class); private static Logger log = LoggerFactory.getLogger(Profile.class);
private JSONObject json; private JSONObject json;
private String units = null; private String units;
private double dia = Constants.defaultDIA; private double dia;
private TimeZone timeZone = TimeZone.getDefault(); private TimeZone timeZone;
private JSONArray isf; private JSONArray isf;
private LongSparseArray<Double> isf_v = null; // oldest at index 0 private LongSparseArray<Double> isf_v; // oldest at index 0
private JSONArray ic; private JSONArray ic;
private LongSparseArray<Double> ic_v = null; // oldest at index 0 private LongSparseArray<Double> ic_v; // oldest at index 0
private JSONArray basal; private JSONArray basal;
private LongSparseArray<Double> basal_v = null; // oldest at index 0 private LongSparseArray<Double> basal_v; // oldest at index 0
private JSONArray targetLow; private JSONArray targetLow;
private LongSparseArray<Double> targetLow_v = null; // oldest at index 0 private LongSparseArray<Double> targetLow_v; // oldest at index 0
private JSONArray targetHigh; private JSONArray targetHigh;
private LongSparseArray<Double> targetHigh_v = null; // oldest at index 0 private LongSparseArray<Double> targetHigh_v; // oldest at index 0
private int percentage = 100; private int percentage;
private int timeshift = 0; private int timeshift;
private boolean isValid = true; protected boolean isValid;
private boolean isValidated = false; protected boolean isValidated;
// Default constructor for tests
protected Profile() {
}
// Constructor from profileStore JSON
public Profile(JSONObject json, String units) { public Profile(JSONObject json, String units) {
this(json, 100, 0); init(json, 100, 0);
if (this.units == null) { if (this.units == null) {
if (units != null) if (units != null)
this.units = units; this.units = units;
@ -65,6 +65,22 @@ public class Profile {
} }
public Profile(JSONObject json, int percentage, int timeshift) { public Profile(JSONObject json, int percentage, int timeshift) {
init(json, percentage, timeshift);
}
protected void init(JSONObject json, int percentage, int timeshift) {
units = null;
dia = Constants.defaultDIA;
timeZone = TimeZone.getDefault();
isf_v = null;
ic_v = null;
basal_v = null;
targetLow_v = null;
targetHigh_v = null;
isValid = true;
isValidated = false;
this.percentage = percentage; this.percentage = percentage;
this.timeshift = timeshift; this.timeshift = timeshift;
this.json = json; this.json = json;
@ -92,7 +108,7 @@ public class Profile {
public String log() { public String log() {
String ret = "\n"; String ret = "\n";
for (Integer hour = 0; hour < 24; hour++) { for (Integer hour = 0; hour < 24; hour++) {
double value = getBasal((Integer) (hour * 60 * 60)); double value = getBasalTimeFromMidnight((Integer) (hour * 60 * 60));
ret += "NS basal value for " + hour + ":00 is " + value + "\n"; ret += "NS basal value for " + hour + ":00 is " + value + "\n";
} }
ret += "NS units: " + getUnits(); ret += "NS units: " + getUnits();
@ -114,6 +130,10 @@ public class Profile {
} }
// mmol or mg/dl // mmol or mg/dl
public void setUnits(String units) {
this.units = units;
}
public String getUnits() { public String getUnits() {
return units; return units;
} }
@ -199,7 +219,7 @@ public class Profile {
for (int i = 0; i < basal_v.size(); i++) { for (int i = 0; i < basal_v.size(); i++) {
if (basal_v.valueAt(i) < description.basalMinimumRate) { if (basal_v.valueAt(i) < description.basalMinimumRate) {
basal_v.setValueAt(i, description.basalMinimumRate); basal_v.setValueAt(i, description.basalMinimumRate);
MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL))); sendBelowMinimumNotification(from);
} }
} }
} else { } else {
@ -213,6 +233,10 @@ public class Profile {
return isValid; return isValid;
} }
protected void sendBelowMinimumNotification(String from) {
MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL)));
}
private void validate(LongSparseArray array) { private void validate(LongSparseArray array) {
if (array.size() == 0) { if (array.size() == 0) {
isValid = false; isValid = false;
@ -226,6 +250,7 @@ public class Profile {
} }
} }
/*
private Double getValueToTime(JSONArray array, Integer timeAsSeconds) { private Double getValueToTime(JSONArray array, Integer timeAsSeconds) {
Double lastValue = null; Double lastValue = null;
@ -245,6 +270,7 @@ public class Profile {
} }
return lastValue; return lastValue;
} }
*/
Integer getShitfTimeSecs(Integer originalTime) { Integer getShitfTimeSecs(Integer originalTime) {
Integer shiftedTime = originalTime + timeshift * 60 * 60; Integer shiftedTime = originalTime + timeshift * 60 * 60;
@ -286,7 +312,7 @@ public class Profile {
return multiplier; return multiplier;
} }
private Double getValueToTime(LongSparseArray<Double> array, Integer timeAsSeconds) { private double getValueToTime(LongSparseArray<Double> array, Integer timeAsSeconds) {
Double lastValue = null; Double lastValue = null;
for (Integer index = 0; index < array.size(); index++) { for (Integer index = 0; index < array.size(); index++) {
@ -301,7 +327,7 @@ public class Profile {
return lastValue; return lastValue;
} }
private String format_HH_MM(Integer timeAsSeconds) { protected String format_HH_MM(Integer timeAsSeconds) {
String time; String time;
int hour = timeAsSeconds / 60 / 60; int hour = timeAsSeconds / 60 / 60;
int minutes = (timeAsSeconds - hour * 60 * 60) / 60; int minutes = (timeAsSeconds - hour * 60 * 60) / 60;
@ -328,15 +354,15 @@ public class Profile {
return retValue; return retValue;
} }
public Double getIsf() { public double getIsf() {
return getIsf(secondsFromMidnight(System.currentTimeMillis())); return getIsfTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getIsf(long time) { public double getIsf(long time) {
return getIsf(secondsFromMidnight(time)); return getIsfTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getIsf(Integer timeAsSeconds) { double getIsfTimeFromMidnight(int timeAsSeconds) {
if (isf_v == null) if (isf_v == null)
isf_v = convertToSparseArray(isf); isf_v = convertToSparseArray(isf);
return getValueToTime(isf_v, timeAsSeconds); return getValueToTime(isf_v, timeAsSeconds);
@ -348,15 +374,15 @@ public class Profile {
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U"); return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U");
} }
public Double getIc() { public double getIc() {
return getIc(secondsFromMidnight(System.currentTimeMillis())); return getIcTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getIc(long time) { public double getIc(long time) {
return getIc(secondsFromMidnight(time)); return getIcTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getIc(Integer timeAsSeconds) { public double getIcTimeFromMidnight(int timeAsSeconds) {
if (ic_v == null) if (ic_v == null)
ic_v = convertToSparseArray(ic); ic_v = convertToSparseArray(ic);
return getValueToTime(ic_v, timeAsSeconds); return getValueToTime(ic_v, timeAsSeconds);
@ -368,15 +394,15 @@ public class Profile {
return getValuesList(ic_v, null, new DecimalFormat("0.0"), "g/U"); return getValuesList(ic_v, null, new DecimalFormat("0.0"), "g/U");
} }
public Double getBasal() { public double getBasal() {
return getBasal(secondsFromMidnight(System.currentTimeMillis())); return getBasalTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getBasal(long time) { public double getBasal(long time) {
return getBasal(secondsFromMidnight(time)); return getBasalTimeFromMidnight(secondsFromMidnight(time));
} }
public synchronized Double getBasal(Integer timeAsSeconds) { public synchronized double getBasalTimeFromMidnight(int timeAsSeconds) {
if (basal_v == null) { if (basal_v == null) {
basal_v = convertToSparseArray(basal); basal_v = convertToSparseArray(basal);
} }
@ -386,17 +412,17 @@ public class Profile {
public String getBasalList() { public String getBasalList() {
if (basal_v == null) if (basal_v == null)
basal_v = convertToSparseArray(basal); basal_v = convertToSparseArray(basal);
return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U"); return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U/h");
} }
public class BasalValue { public class BasalValue {
public BasalValue(Integer timeAsSeconds, Double value) { public BasalValue(int timeAsSeconds, double value) {
this.timeAsSeconds = timeAsSeconds; this.timeAsSeconds = timeAsSeconds;
this.value = value; this.value = value;
} }
public Integer timeAsSeconds; public int timeAsSeconds;
public Double value; public double value;
} }
public synchronized BasalValue[] getBasalValues() { public synchronized BasalValue[] getBasalValues() {
@ -406,7 +432,7 @@ public class Profile {
for (Integer index = 0; index < basal_v.size(); index++) { for (Integer index = 0; index < basal_v.size(); index++) {
Integer tas = (int) basal_v.keyAt(index); Integer tas = (int) basal_v.keyAt(index);
Double value = basal_v.valueAt(index); double value = basal_v.valueAt(index);
ret[index] = new BasalValue(tas, value); ret[index] = new BasalValue(tas, value);
} }
return ret; return ret;
@ -416,33 +442,33 @@ public class Profile {
return getTarget(secondsFromMidnight(System.currentTimeMillis())); return getTarget(secondsFromMidnight(System.currentTimeMillis()));
} }
private double getTarget(Integer time) { protected double getTarget(int timeAsSeconds) {
return (getTargetLow(time) + getTargetHigh(time))/2; return (getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds))/2;
} }
public Double getTargetLow() { public double getTargetLow() {
return getTargetLow(secondsFromMidnight(System.currentTimeMillis())); return getTargetLowTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getTargetLow(long time) { public double getTargetLow(long time) {
return getTargetLow(secondsFromMidnight(time)); return getTargetLowTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getTargetLow(Integer timeAsSeconds) { public double getTargetLowTimeFromMidnight(int timeAsSeconds) {
if (targetLow_v == null) if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow); targetLow_v = convertToSparseArray(targetLow);
return getValueToTime(targetLow_v, timeAsSeconds); return getValueToTime(targetLow_v, timeAsSeconds);
} }
public Double getTargetHigh() { public double getTargetHigh() {
return getTargetHigh(secondsFromMidnight(System.currentTimeMillis())); return getTargetHighTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getTargetHigh(long time) { public double getTargetHigh(long time) {
return getTargetHigh(secondsFromMidnight(time)); return getTargetHighTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getTargetHigh(Integer timeAsSeconds) { public double getTargetHighTimeFromMidnight(int timeAsSeconds) {
if (targetHigh_v == null) if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh); targetHigh_v = convertToSparseArray(targetHigh);
return getValueToTime(targetHigh_v, timeAsSeconds); return getValueToTime(targetHigh_v, timeAsSeconds);
@ -457,15 +483,15 @@ public class Profile {
} }
public double getMaxDailyBasal() { public double getMaxDailyBasal() {
Double max = 0d; double max = 0d;
for (Integer hour = 0; hour < 24; hour++) { for (int hour = 0; hour < 24; hour++) {
double value = getBasal((Integer) (hour * 60 * 60)); double value = getBasalTimeFromMidnight((Integer) (hour * 60 * 60));
if (value > max) max = value; if (value > max) max = value;
} }
return max; return max;
} }
public static Integer secondsFromMidnight() { public static int secondsFromMidnight() {
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis(); long now = c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.HOUR_OF_DAY, 0);
@ -476,7 +502,7 @@ public class Profile {
return (int) (passed / 1000); return (int) (passed / 1000);
} }
public static Integer secondsFromMidnight(long date) { public static int secondsFromMidnight(long date) {
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
c.setTimeInMillis(date); c.setTimeInMillis(date);
c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.HOUR_OF_DAY, 0);
@ -487,22 +513,22 @@ public class Profile {
return (int) (passed / 1000); return (int) (passed / 1000);
} }
public static Double toMgdl(Double value, String units) { public static double toMgdl(double value, String units) {
if (units.equals(Constants.MGDL)) return value; if (units.equals(Constants.MGDL)) return value;
else return value * Constants.MMOLL_TO_MGDL; else return value * Constants.MMOLL_TO_MGDL;
} }
public static Double toMmol(Double value, String units) { public static double toMmol(double value, String units) {
if (units.equals(Constants.MGDL)) return value * Constants.MGDL_TO_MMOLL; if (units.equals(Constants.MGDL)) return value * Constants.MGDL_TO_MMOLL;
else return value; else return value;
} }
public static Double fromMgdlToUnits(Double value, String units) { public static double fromMgdlToUnits(double value, String units) {
if (units.equals(Constants.MGDL)) return value; if (units.equals(Constants.MGDL)) return value;
else return value * Constants.MGDL_TO_MMOLL; else return value * Constants.MGDL_TO_MMOLL;
} }
public static Double toUnits(Double valueInMgdl, Double valueInMmol, String units) { public static double toUnits(Double valueInMgdl, Double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) return valueInMgdl; if (units.equals(Constants.MGDL)) return valueInMgdl;
else return valueInMmol; else return valueInMmol;
} }
@ -528,7 +554,7 @@ public class Profile {
public double percentageBasalSum() { public double percentageBasalSum() {
double result = 0d; double result = 0d;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
result += getBasal((Integer) (i * 60 * 60)); result += getBasalTimeFromMidnight(i * 60 * 60);
} }
return result; return result;
} }
@ -537,7 +563,7 @@ public class Profile {
public double baseBasalSum() { public double baseBasalSum() {
double result = 0d; double result = 0d;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
result += getBasal((Integer) (i * 60 * 60)) / getMultiplier(basal_v); result += getBasalTimeFromMidnight(i * 60 * 60) / getMultiplier(basal_v);
} }
return result; return result;
} }

View file

@ -110,11 +110,6 @@ public class IobCobThread extends Thread {
return; // profile not set yet return; // profile not set yet
} }
if (profile.getIsf(bgTime) == null) {
log.debug("Aborting calculation thread (no ISF): " + from);
return; // profile not set yet
}
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")"); log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");

View file

@ -204,7 +204,7 @@ public class DetermineBasalAdapterAMAJS {
mProfile.put("max_bg", maxBg); mProfile.put("max_bg", maxBg);
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().doubleValue(), 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("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("openapsama_current_basal_safety_multiplier", 4d));
mProfile.put("skip_neutral_temps", true); mProfile.put("skip_neutral_temps", true);

View file

@ -212,9 +212,9 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
if (!HardLimits.checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA)) if (!HardLimits.checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA))
return; return;
if (!HardLimits.checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC)) if (!HardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return; return;
if (!HardLimits.checkOnlyHardLimits(Profile.toMgdl(profile.getIsf().doubleValue(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) if (!HardLimits.checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return; return;
if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal())) if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
return; return;

View file

@ -172,7 +172,7 @@ public class DetermineBasalAdapterMAJS {
mProfile.put("max_bg", maxBg); mProfile.put("max_bg", maxBg);
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().doubleValue(), units)); mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units));
mProfile.put("current_basal", basalRate); mProfile.put("current_basal", basalRate);

View file

@ -212,9 +212,9 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA)) if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA))
return; return;
if (!checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC)) if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return; return;
if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf().doubleValue(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return; return;
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal())) if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
return; return;

View file

@ -228,7 +228,7 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("max_bg", maxBg); mProfile.put("max_bg", maxBg);
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().doubleValue(), 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("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("openapsama_current_basal_safety_multiplier", 4d));

View file

@ -216,9 +216,9 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal()); maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA)) return; if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA)) return;
if (!checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC)) if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return; return;
if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf().doubleValue(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return; return;
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal())) return; if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal())) return;
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return; if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return;

View file

@ -184,7 +184,7 @@ public abstract class AbstractDanaRPlugin implements PluginBase, PumpInterface,
int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60; int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) { for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h]; Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasal((Integer) (h * basalIncrement)); Double profileValue = profile.getBasalTimeFromMidnight((Integer) (h * basalIncrement));
if (profileValue == null) return true; if (profileValue == null) return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) { if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue); log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);

View file

@ -241,7 +241,7 @@ public class DanaRPump {
for (Integer hour = 0; hour < 24; hour++) { for (Integer hour = 0; hour < 24; hour++) {
//Some values get truncated to the next lower one. //Some values get truncated to the next lower one.
// -> round them to two decimals and make sure we are a small delta larger (that will get truncated) // -> round them to two decimals and make sure we are a small delta larger (that will get truncated)
double value = Math.round(100d * nsProfile.getBasal((Integer) (hour * 60 * 60)))/100d + 0.00001; double value = Math.round(100d * nsProfile.getBasalTimeFromMidnight((Integer) (hour * 60 * 60)))/100d + 0.00001;
if (Config.logDanaMessageDetail) if (Config.logDanaMessageDetail)
log.debug("NS basal value for " + hour + ":00 is " + value); log.debug("NS basal value for " + hour + ":00 is " + value);
record[hour] = value; record[hour] = value;

View file

@ -428,7 +428,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60; int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) { for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h]; Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasal((Integer) (h * basalIncrement)); Double profileValue = profile.getBasalTimeFromMidnight((Integer) (h * basalIncrement));
if (profileValue == null) return true; if (profileValue == null) return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) { if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue); log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);

View file

@ -52,12 +52,12 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
private PumpDescription pumpDescription = new PumpDescription(); private PumpDescription pumpDescription = new PumpDescription();
private static void loadFakingStatus() { private static void loadFakingStatus() {
fromNSAreCommingFakedExtendedBoluses = SP.getBoolean("fromNSAreCommingFakedExtendedBoluses", false); fromNSAreCommingFakedExtendedBoluses = SP.getBoolean(R.string.key_fromNSAreCommingFakedExtendedBoluses, false);
} }
public static void setFakingStatus(boolean newStatus) { public static void setFakingStatus(boolean newStatus) {
fromNSAreCommingFakedExtendedBoluses = newStatus; fromNSAreCommingFakedExtendedBoluses = newStatus;
SP.putBoolean("fromNSAreCommingFakedExtendedBoluses", fromNSAreCommingFakedExtendedBoluses); SP.putBoolean(R.string.key_fromNSAreCommingFakedExtendedBoluses, fromNSAreCommingFakedExtendedBoluses);
} }
public static boolean getFakingStatus() { public static boolean getFakingStatus() {
@ -73,7 +73,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
return plugin; return plugin;
} }
private VirtualPumpPlugin() { public VirtualPumpPlugin() {
pumpDescription.isBolusCapable = true; pumpDescription.isBolusCapable = true;
pumpDescription.bolusStep = 0.1d; pumpDescription.bolusStep = 0.1d;
@ -245,7 +245,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
public double getBaseBasalRate() { public double getBaseBasalRate() {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile != null) if (profile != null)
return profile.getBasal() != null ? profile.getBasal() : 0d; return profile.getBasal();
else else
return 0d; return 0d;
} }

View file

@ -33,8 +33,8 @@ public class ProfileGraph extends GraphView {
List<DataPoint> basalArray = new ArrayList<>(); List<DataPoint> basalArray = new ArrayList<>();
for (int hour = 0; hour < 24; hour++) { for (int hour = 0; hour < 24; hour++) {
basalArray.add(new DataPoint(hour, profile.getBasal(new Integer(hour*60*60)))); basalArray.add(new DataPoint(hour, profile.getBasalTimeFromMidnight(new Integer(hour*60*60))));
basalArray.add(new DataPoint(hour+1, profile.getBasal(new Integer(hour*60*60)))); basalArray.add(new DataPoint(hour+1, profile.getBasalTimeFromMidnight(new Integer(hour*60*60))));
} }
DataPoint[] basalDataPoints = new DataPoint[basalArray.size()]; DataPoint[] basalDataPoints = new DataPoint[basalArray.size()];
basalDataPoints = basalArray.toArray(basalDataPoints); basalDataPoints = basalArray.toArray(basalDataPoints);

View file

@ -586,7 +586,7 @@ public class ActionStringHandler {
} }
final Profile profile = MainApp.getConfigBuilder().getProfile(); final Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null || profile.getBasal() == null) { if (profile == null) {
msg += MainApp.sResources.getString(R.string.notloadedplugins) + "\n"; msg += MainApp.sResources.getString(R.string.notloadedplugins) + "\n";
} }
if (!"".equals(msg)) { if (!"".equals(msg)) {

View file

@ -52,7 +52,7 @@ public class KeepAliveReceiver extends BroadcastReceiver {
private void checkPump() { private void checkPump() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
final Profile profile = MainApp.getConfigBuilder().getProfile(); final Profile profile = MainApp.getConfigBuilder().getProfile();
if (pump != null && profile != null && profile.getBasal() != null) { if (pump != null && profile != null) {
Date lastConnection = pump.lastDataTime(); Date lastConnection = pump.lastDataTime();
boolean isStatusOutdated = lastConnection.getTime() + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis(); boolean isStatusOutdated = lastConnection.getTime() + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis();
boolean isBasalOutdated = Math.abs(profile.getBasal() - pump.getBaseBasalRate()) > pump.getPumpDescription().basalStep; boolean isBasalOutdated = Math.abs(profile.getBasal() - pump.getBaseBasalRate()) > pump.getPumpDescription().basalStep;

View file

@ -76,7 +76,7 @@ public class LocalAlertUtils {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
final Profile profile = MainApp.getConfigBuilder().getProfile(); final Profile profile = MainApp.getConfigBuilder().getProfile();
if (pump != null && profile != null && profile.getBasal() != null) { if (pump != null && profile != null) {
Date lastConnection = pump.lastDataTime(); Date lastConnection = pump.lastDataTime();
long earliestAlarmTime = lastConnection.getTime() + pumpUnreachableThreshold(); long earliestAlarmTime = lastConnection.getTime() + pumpUnreachableThreshold();
if (SP.getLong("nextPumpDisconnectedAlarm", 0l) < earliestAlarmTime) { if (SP.getLong("nextPumpDisconnectedAlarm", 0l) < earliestAlarmTime) {

View file

@ -980,5 +980,6 @@
<string name="overview_show_cob">Carbs On Board</string> <string name="overview_show_cob">Carbs On Board</string>
<string name="overview_show_iob">Insulin On Board</string> <string name="overview_show_iob">Insulin On Board</string>
<string name="overview_show_basals">Basals</string> <string name="overview_show_basals">Basals</string>
<string name="key_fromNSAreCommingFakedExtendedBoluses" translatable="false">fromNSAreCommingFakedExtendedBoluses</string>
</resources> </resources>

View file

@ -0,0 +1,161 @@
package info.nightscout.androidaps.data;
import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer;
import junit.framework.Assert;
import org.json.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.skyscreamer.jsonassert.JSONAssert;
import java.util.Calendar;
import java.util.TimeZone;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.utils.FabricPrivacy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Created by mike on 18.03.2018.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, VirtualPumpPlugin.class, FabricPrivacy.class})
public class ProfileTest extends Profile {
PumpInterface pump = new VirtualPumpPlugin();
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\"}";
String belowLimitValidProfile = "{\"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.001\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}";
String notStartingAtZeroValidProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:30\",\"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 noUnitsValidProfile = "{\"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\"}";
String wrongProfile = "{\"dia\":\"3\",\"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 profileStore = "{\"defaultProfile\":\"Default\",\"store\":{\"Default\":" + validProfile + "}}";
boolean notificationBelowLimitSent = false;
@Test
public void doTests() throws Exception {
prepareMock();
// Test valid profile
init(new JSONObject(validProfile), 100, 0);
Assert.assertEquals(true, isValid("Test"));
Assert.assertEquals(true, log().contains("NS units: mmol"));
JSONAssert.assertEquals(validProfile, getData(), false);
Assert.assertEquals(3.0d, getDia(), 0.01d);
Assert.assertEquals(TimeZone.getTimeZone("UTC"), getTimeZone());
Assert.assertEquals("00:30", format_HH_MM(30 * 60));
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 1);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
Assert.assertEquals(100d, getIsf(c.getTimeInMillis()), 0.01d);
c.set(Calendar.HOUR_OF_DAY, 2);
Assert.assertEquals(110d, getIsf(c.getTimeInMillis()), 0.01d);
Assert.assertEquals(110d, getIsfTimeFromMidnight(2 * 60 * 60), 0.01d);
Assert.assertEquals("00:00 100,0 mmol/U\n" + "02:00 110,0 mmol/U", getIsfList());
Assert.assertEquals(30d, getIc(c.getTimeInMillis()), 0.01d);
Assert.assertEquals(30d, getIcTimeFromMidnight(2 * 60 * 60), 0.01d);
Assert.assertEquals("00:00 30,0 g/U", getIcList());
Assert.assertEquals(0.1d, getBasal(c.getTimeInMillis()), 0.01d);
Assert.assertEquals(0.1d, getBasalTimeFromMidnight(2 * 60 * 60), 0.01d);
Assert.assertEquals("00:00 0,10 U/h", getBasalList());
Assert.assertEquals(0.1d, getBasalValues()[0].value);
Assert.assertEquals(0.1d, getMaxDailyBasal());
Assert.assertEquals(2.4d, percentageBasalSum(), 0.01d);
Assert.assertEquals(2.4d, baseBasalSum(), 0.01d);
Assert.assertEquals(4.5d, getTarget(2 * 60 * 60), 0.01d);
Assert.assertEquals(4d, getTargetLow(c.getTimeInMillis()), 0.01d);
Assert.assertEquals(4d, getTargetLowTimeFromMidnight(2 * 60 * 60), 0.01d);
Assert.assertEquals(5d, getTargetHigh(c.getTimeInMillis()), 0.01d);
Assert.assertEquals(5d, getTargetHighTimeFromMidnight(2 * 60 * 60), 0.01d);
Assert.assertEquals("00:00 4,0 - 5,0 mmol", getTargetList());
Assert.assertEquals(100, getPercentage());
Assert.assertEquals(0, getTimeshift());
Assert.assertEquals(0.1d, toMgdl(0.1d, Constants.MGDL));
Assert.assertEquals(18d, toMgdl(1d, Constants.MMOL));
Assert.assertEquals(1d, toMmol(18d, Constants.MGDL));
Assert.assertEquals(18d, toMmol(18d, Constants.MMOL));
Assert.assertEquals(18d, fromMgdlToUnits(18d, Constants.MGDL));
Assert.assertEquals(1d, fromMgdlToUnits(18d, Constants.MMOL));
Assert.assertEquals(18d, toUnits(18d, 1d, Constants.MGDL));
Assert.assertEquals(1d, toUnits(18d, 1d, Constants.MMOL));
Assert.assertEquals("18", toUnitsString(18d, 1d, Constants.MGDL));
Assert.assertEquals("1,0", toUnitsString(18d, 1d, Constants.MMOL));
Assert.assertEquals("5 - 6", toTargetRangeString(5d, 6d, Constants.MGDL, Constants.MGDL));
//Test basal profile below limit
Assert.assertEquals(false, notificationBelowLimitSent);
init(new JSONObject(belowLimitValidProfile), 100, 0);
isValid("Test");
Assert.assertEquals(true, notificationBelowLimitSent);
// Test profile w/o units
init(new JSONObject(noUnitsValidProfile), 100, 0);
Assert.assertEquals(null, getUnits());
Profile nup = new Profile(new JSONObject(noUnitsValidProfile), Constants.MMOL);
Assert.assertEquals(Constants.MMOL, nup.getUnits());
// failover to MGDL
nup = new Profile(new JSONObject(noUnitsValidProfile), null);
Assert.assertEquals(Constants.MGDL, nup.getUnits());
//Test profile not starting at midnight
init(new JSONObject(notStartingAtZeroValidProfile), 100, 0);
Assert.assertEquals(30.0d, getIc(0), 0.01d);
// Test wrong profile
init(new JSONObject(wrongProfile), 100, 0);
Assert.assertEquals(false, isValid("Test"));
// Test percentage functionality
init(new JSONObject(validProfile), 50, 0);
Assert.assertEquals(0.05d, getBasal(c.getTimeInMillis()), 0.01d);
Assert.assertEquals(1.2d, percentageBasalSum(), 0.01d);
Assert.assertEquals(60d, getIc(c.getTimeInMillis()), 0.01d);
Assert.assertEquals(220d, getIsf(c.getTimeInMillis()), 0.01d);
// Test timeshift functionality
init(new JSONObject(validProfile), 100, 1);
Assert.assertEquals(
"00:00 110,0 mmol/U\n" +
"01:00 100,0 mmol/U\n" +
"03:00 110,0 mmol/U", getIsfList());
}
private void prepareMock() throws Exception {
ConfigBuilderPlugin configBuilderPlugin = mock(ConfigBuilderPlugin.class);
PowerMockito.mockStatic(ConfigBuilderPlugin.class);
MainApp mainApp = mock(MainApp.class);
PowerMockito.mockStatic(MainApp.class);
when(MainApp.instance()).thenReturn(mainApp);
when(MainApp.getConfigBuilder()).thenReturn(configBuilderPlugin);
when(MainApp.getConfigBuilder().getActivePump()).thenReturn(pump);
PowerMockito.mockStatic(FabricPrivacy.class);
// PowerMockito.doNothing().when(FabricPrivacy.log(""));
Bus bus = new Bus(ThreadEnforcer.ANY);
when(MainApp.bus()).thenReturn(bus);
}
@Override
protected void sendBelowMinimumNotification(String from) {
notificationBelowLimitSent = true;
}
}

View file

@ -33,7 +33,7 @@ import static org.mockito.Mockito.when;
*/ */
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, ConfigBuilderPlugin.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 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\"}";