added trigger Delta

This commit is contained in:
Roumen Georgiev 2019-05-30 12:16:42 +03:00
parent 45d0d8ce13
commit 5c4910ed5b
6 changed files with 508 additions and 1 deletions

View file

@ -19,6 +19,7 @@ import butterknife.Unbinder;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerIob;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerLocation;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerProfilePercent;
@ -37,6 +38,7 @@ public class ChooseTriggerDialog extends DialogFragment {
add(new TriggerTime());
add(new TriggerRecurringTime());
add(new TriggerBg());
add(new TriggerDelta());
add(new TriggerIob());
add(new TriggerProfilePercent());
add(new TriggerTempTarget());

View file

@ -0,0 +1,132 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputDelta extends Element {
private Comparator.Compare compare = Comparator.Compare.IS_EQUAL;
final TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
private double value;
double minValue;
double maxValue;
private double step;
private DecimalFormat decimalFormat;
private int deltaType;
NumberPicker numberPicker;
public InputDelta() {
super();
}
public InputDelta(double value, double minValue, double maxValue, double step, DecimalFormat decimalFormat, int deltaType) {
super();
this.value = value;
this.minValue = minValue;
this.maxValue = maxValue;
this.step = step;
this.decimalFormat = decimalFormat;
this.deltaType = deltaType;
}
public InputDelta(InputDelta another) {
super();
value = another.getValue();
minValue = another.minValue;
maxValue = another.maxValue;
step = another.step;
decimalFormat = another.decimalFormat;
deltaType = another.deltaType;
}
@Override
public void addToLayout(LinearLayout root) {
Spinner spinner = new Spinner(root.getContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_item, InputDelta.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
spinner.setLayoutParams(spinnerParams);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
deltaType = spinner.getSelectedItemPosition();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner.setSelection(this.deltaType);
// root.addView(spinner);
numberPicker = new NumberPicker(root.getContext(), null);
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, textWatcher);
numberPicker.setOnValueChangedListener(value -> this.value = value);
LinearLayout l = new LinearLayout(root.getContext());
l.setOrientation(LinearLayout.VERTICAL);
l.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
l.addView(spinner);
l.addView(numberPicker);
root.addView(l);
}
public InputDelta setValue(double value, int type) {
this.value = value;
this.deltaType = type;
if (numberPicker != null)
numberPicker.setValue(value);
return this;
}
public double getValue() {
return value;
}
public int getDeltaType() {
return deltaType;
}
public static List<String> labels() {
List<String> list = new ArrayList<>();
list.add(MainApp.gs(R.string.delta));
list.add(MainApp.gs(R.string.short_avgdelta));
list.add(MainApp.gs(R.string.long_avgdelta));
return list;
}
}

View file

@ -0,0 +1,220 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.support.v4.app.FragmentManager;
import android.widget.LinearLayout;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerDelta extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private double minValue = 0d;
private double maxValue = 1d;
private double step = 1;
private DecimalFormat decimalFormat = new DecimalFormat("1");
private String units = ProfileFunctions.getInstance().getProfileUnits();
private int deltaType = 0; // 0 is delta, 1 is short average delta, 2 is long average delta
private InputDelta value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType);
private Comparator comparator = new Comparator();
public TriggerDelta() {
super();
setUnits();
}
private TriggerDelta(TriggerDelta triggerDelta) {
super();
setUnits();
value = triggerDelta.value;
lastRun = triggerDelta.lastRun;
}
public double getValue() {
return value.getValue();
}
public double getType() { return value.getDeltaType(); }
public String getUnits() {
return this.units;
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (glucoseStatus == null)
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
return true;
else
return false;
// Setting type of delta
double delta;
if (deltaType == 1)
delta = glucoseStatus.short_avgdelta;
else if (deltaType == 2)
delta = glucoseStatus.long_avgdelta;
else
delta = glucoseStatus.delta;
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
if (glucoseStatus == null && comparator.getValue().equals(Comparator.Compare.IS_NOT_AVAILABLE)) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: delta is " + delta + friendlyDescription());
return true;
}
boolean doRun = comparator.getValue().check(delta, Profile.toMgdl(value.getValue(), this.units));
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: delta is " + delta + " " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerDelta.class.getName());
JSONObject data = new JSONObject();
data.put("value", getValue());
data.put("units", units);
data.put("lastRun", lastRun);
data.put("type", getType());
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
units = JsonHelper.safeGetString(d, "units");
deltaType = JsonHelper.safeGetInt(d, "type");
value.setValue(JsonHelper.safeGetDouble(d, "value"), deltaType);
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
}
return this;
}
@Override
public int friendlyName() {
return R.string.deltalabel;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.deltacompared, MainApp.gs(comparator.getValue().getStringRes()), getValue(), typeToString(deltaType));
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.as); // TODO: Icon for delta
}
@Override
public Trigger duplicate() {
return new TriggerDelta(this);
}
TriggerDelta setValue(double requestedValue) {
this.value.setValue(requestedValue, deltaType);
return this;
}
TriggerDelta setUnits(String units) {
this.units = units;
return this;
}
void setUnits(){
if (this.units.equals(Constants.MMOL)) {
this.maxValue = 4d;
this.minValue = 0.1d;
this.step = 0.1d;
this.decimalFormat = new DecimalFormat("0.1");
this.deltaType = 0;
} else {
this.maxValue = 72d;
this.minValue = 2d;
this.step = 1d;
this.deltaType = 0;
}
value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType);
}
TriggerDelta lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerDelta comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.deltalabel))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.deltalabel) + ": ", "", value))
.build(root);
}
public String typeToString( int type ) {
switch (type) {
case 0:
return MainApp.gs(R.string.delta);
case 1:
return MainApp.gs(R.string.short_avgdelta);
case 2:
return MainApp.gs(R.string.long_avgdelta);
default:
return MainApp.gs(R.string.delta);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1400,6 +1400,8 @@
<string name="notexists">not exists</string>
<string name="temptargetcompared">Temp target %1$s</string>
<string name="wifissidcompared">WiFi SSID %1$s %2$s</string>
<string name="deltacompared">BG %3$s %1$s %2$s</string>
<string name="deltalabel">BG difference</string>
<string name="currentlocation">Current Location</string>
<string name="location">Location</string>
<string name="latitude_short">Lat:</string>
@ -1420,4 +1422,4 @@
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>
</plurals>
</resources>
</resources>

View file

@ -0,0 +1,151 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import com.google.common.base.Optional;
import com.squareup.otto.Bus;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.Before;
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 java.util.ArrayList;
import java.util.List;
import info.AAPSMocker;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, Bus.class, ProfileFunctions.class, DateUtil.class, IobCobCalculatorPlugin.class, GlucoseStatus.class})
public class TriggerDeltaTest {
long now = 1514766900000L;
@Test
public void shouldRunTest() {
when(IobCobCalculatorPlugin.getPlugin().getBgReadings()).thenReturn(generateValidBgData());
TriggerDelta t = new TriggerDelta().setUnits(Constants.MGDL).setValue(73d).comparator(Comparator.Compare.IS_EQUAL);
Assert.assertFalse(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MGDL).setValue(-2d).comparator(Comparator.Compare.IS_EQUAL);
Assert.assertTrue(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MGDL).setValue(-3d).comparator(Comparator.Compare.IS_EQUAL_OR_GREATER);
Assert.assertTrue(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MGDL).setValue(2d).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER);
Assert.assertTrue(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MGDL).setValue(2d).comparator(Comparator.Compare.IS_EQUAL);
Assert.assertFalse(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MMOL).setValue(0.3d).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER);
Assert.assertTrue(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MMOL).setValue(0.1d).comparator(Comparator.Compare.IS_EQUAL_OR_GREATER);
Assert.assertFalse(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MMOL).setValue(-0.5d).comparator(Comparator.Compare.IS_EQUAL_OR_GREATER);
Assert.assertTrue(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MMOL).setValue(-0.2d).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER);
Assert.assertFalse(t.shouldRun());
when(IobCobCalculatorPlugin.getPlugin().getBgReadings()).thenReturn(new ArrayList<>());
t = new TriggerDelta().setUnits(Constants.MGDL).setValue(213).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER);
Assert.assertFalse(t.shouldRun());
t = new TriggerDelta().comparator(Comparator.Compare.IS_NOT_AVAILABLE);
Assert.assertTrue(t.shouldRun());
t = new TriggerDelta().setUnits(Constants.MGDL).setValue(214).comparator(Comparator.Compare.IS_EQUAL).lastRun(now - 1);
Assert.assertFalse(t.shouldRun());
}
@Test
public void copyConstructorTest() {
TriggerDelta t = new TriggerDelta().setUnits(Constants.MGDL).setValue(213).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER);
TriggerDelta t1 = (TriggerDelta) t.duplicate();
Assert.assertEquals(213d, t1.getValue(), 0.01d);
Assert.assertEquals(Constants.MGDL, t1.getUnits());
Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.getComparator().getValue());
}
@Test
public void executeTest() {
TriggerDelta t = new TriggerDelta().setUnits(Constants.MGDL).setValue(213).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER);
t.executed(1);
Assert.assertEquals(1l, t.getLastRun());
}
String deltaJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"lastRun\":0,\"units\":\"mmol\",\"type\":0,\"value\":4.1},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\"}";
@Test
public void toJSONTest() {
TriggerDelta t = new TriggerDelta().setUnits(Constants.MMOL).setValue(4.1d).comparator(Comparator.Compare.IS_EQUAL);
Assert.assertEquals(deltaJson, t.toJSON());
}
@Test
public void fromJSONTest() throws JSONException {
TriggerDelta t = new TriggerDelta().setUnits(Constants.MMOL).setValue(4.1d).comparator(Comparator.Compare.IS_EQUAL);
TriggerDelta t2 = (TriggerDelta) Trigger.instantiate(new JSONObject(t.toJSON()));
Assert.assertEquals(Comparator.Compare.IS_EQUAL, t2.getComparator().getValue());
Assert.assertEquals(4.1d, t2.getValue(), 0.01d);
Assert.assertEquals(Constants.MMOL, t2.getUnits());
Assert.assertEquals(0d, t2.getType(), 0.01d);
}
@Test
public void iconTest() {
Assert.assertEquals(Optional.of(R.drawable.as), new TriggerDelta().icon());
}
@Test
public void typeToStringTest() {
TriggerDelta t = new TriggerDelta();
Assert.assertEquals(MainApp.gs(R.string.delta), t.typeToString(0));
Assert.assertEquals(MainApp.gs(R.string.short_avgdelta), t.typeToString(1));
Assert.assertEquals(MainApp.gs(R.string.long_avgdelta), t.typeToString(2));
}
@Before
public void mock() {
AAPSMocker.mockMainApp();
AAPSMocker.mockBus();
AAPSMocker.mockIobCobCalculatorPlugin();
AAPSMocker.mockProfileFunctions();
AAPSMocker.mockApplicationContext();
PowerMockito.mockStatic(DateUtil.class);
when(DateUtil.now()).thenReturn(now);
}
List<BgReading> generateValidBgData() {
List<BgReading> list = new ArrayList<>();
try {
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":214,\"mills\":1514766900000,\"direction\":\"Flat\"}"))));
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":216,\"mills\":1514766600000,\"direction\":\"Flat\"}")))); // +2
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":219,\"mills\":1514766300000,\"direction\":\"Flat\"}")))); // +3
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":223,\"mills\":1514766000000,\"direction\":\"Flat\"}")))); // +4
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":222,\"mills\":1514765700000,\"direction\":\"Flat\"}"))));
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":224,\"mills\":1514765400000,\"direction\":\"Flat\"}"))));
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":226,\"mills\":1514765100000,\"direction\":\"Flat\"}"))));
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":228,\"mills\":1514764800000,\"direction\":\"Flat\"}"))));
} catch (JSONException e) {
e.printStackTrace();
}
return list;
}
}