TriggerBg

This commit is contained in:
Milos Kozak 2018-09-18 20:17:45 +02:00
parent ca7e9d2a7f
commit 2bf07eb0d4
9 changed files with 503 additions and 5 deletions

View file

@ -1,9 +1,13 @@
package info.nightscout.androidaps.plugins.general.automation; package info.nightscout.androidaps.plugins.general.automation;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.general.automation.actions.Action;
public class AutomationPlugin extends PluginBase { public class AutomationPlugin extends PluginBase {
@ -15,6 +19,8 @@ public class AutomationPlugin extends PluginBase {
return plugin; return plugin;
} }
List<Action> actions = new ArrayList<>();
private AutomationPlugin() { private AutomationPlugin() {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)

View file

@ -0,0 +1,6 @@
package info.nightscout.androidaps.plugins.general.automation.actions;
public abstract class Action {
abstract void doAction();
}

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps.plugins.general.automation.actions;
import java.util.ArrayList;
import java.util.List;
public class AutomationEvent {
Trigger trigger;
List<Action> actions = new ArrayList<>();
AutomationEvent() {
}
}

View file

@ -5,17 +5,26 @@ import org.json.JSONObject;
abstract class Trigger { abstract class Trigger {
protected static final int ISLOWER = -2;
protected static final int ISEQUALORLOWER = -1;
protected static final int ISEQUAL = 0;
protected static final int ISEQUALORGREATER = 1;
protected static final int ISGREATER = 2;
protected static final int NOTAVAILABLE = 10;
Trigger() { Trigger() {
} }
Trigger(String js) {
fromJSON(js);
}
abstract boolean shouldRun(); abstract boolean shouldRun();
abstract String toJSON(); abstract String toJSON();
abstract Trigger fromJSON(String data); abstract Trigger fromJSON(String data);
void notifyAboutRun(long time) {
}
static Trigger instantiate(JSONObject object) { static Trigger instantiate(JSONObject object) {
try { try {
String type = object.getString("type"); String type = object.getString("type");
@ -27,6 +36,6 @@ abstract class Trigger {
} }
return null; return null;
} }
} }

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.plugins.general.automation.actions;
import org.json.JSONException;
import org.json.JSONObject;
import info.nightscout.androidaps.data.GlucoseStatus;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.utils.JsonHelper;
public class TriggerBg extends Trigger {
double threshold;
int comparator = ISEQUAL;
String units = ProfileFunctions.getInstance().getProfileUnits();
@Override
synchronized boolean shouldRun() {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (glucoseStatus == null && comparator == NOTAVAILABLE)
return true;
if (glucoseStatus == null)
return false;
switch (comparator) {
case ISLOWER:
return glucoseStatus.glucose < Profile.toMgdl(threshold, units);
case ISEQUALORLOWER:
return glucoseStatus.glucose <= Profile.toMgdl(threshold, units);
case ISEQUAL:
return glucoseStatus.glucose == Profile.toMgdl(threshold, units);
case ISEQUALORGREATER:
return glucoseStatus.glucose >= Profile.toMgdl(threshold, units);
case ISGREATER:
return glucoseStatus.glucose > Profile.toMgdl(threshold, units);
}
return false;
}
@Override
synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerBg.class.getName());
JSONObject data = new JSONObject();
data.put("threshold", threshold);
data.put("comparator", comparator);
data.put("units", units);
o.put("data", data.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
threshold = JsonHelper.safeGetDouble(d, "threshold");
comparator = JsonHelper.safeGetInt(d, "comparator");
units = JsonHelper.safeGetString(d, "units");
} catch (JSONException e) {
e.printStackTrace();
}
return this;
}
TriggerBg threshold(double threshold) {
this.threshold = threshold;
return this;
}
TriggerBg comparator(int comparator) {
this.comparator = comparator;
return this;
}
TriggerBg units(String units) {
this.units = units;
return this;
}
}

View file

@ -0,0 +1,188 @@
package info.nightscout.androidaps.plugins.general.automation.actions;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Calendar;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.T;
public class TriggerTime extends Trigger {
long lastRun;
// Single execution
long runAt;
// Recurring
boolean recurring;
boolean monday = true;
boolean tuesday = true;
boolean wednesday = true;
boolean thursday = true;
boolean friday = true;
boolean saturday = true;
boolean sunday = true;
int hour;
int minute;
long validTo;
@Override
boolean shouldRun() {
if (recurring) {
if (validTo != 0 && DateUtil.now() > validTo)
return false;
Calendar c = Calendar.getInstance();
int scheduledDayOfWeek = c.get(Calendar.DAY_OF_WEEK);
Calendar scheduledCal = DateUtil.gregorianCalendar();
scheduledCal.set(Calendar.HOUR_OF_DAY, hour);
scheduledCal.set(Calendar.MINUTE, minute);
scheduledCal.set(Calendar.SECOND, 0);
long scheduled = scheduledCal.getTimeInMillis();
if (monday && scheduledDayOfWeek == Calendar.MONDAY ||
tuesday && scheduledDayOfWeek == Calendar.TUESDAY ||
wednesday && scheduledDayOfWeek == Calendar.WEDNESDAY ||
thursday && scheduledDayOfWeek == Calendar.THURSDAY ||
friday && scheduledDayOfWeek == Calendar.FRIDAY ||
saturday && scheduledDayOfWeek == Calendar.SATURDAY ||
sunday && scheduledDayOfWeek == Calendar.SUNDAY) {
if (DateUtil.now() >= scheduled && DateUtil.now() - scheduled < T.mins(5).msecs()) {
if (lastRun < scheduled)
return true;
}
}
return false;
} else {
long now = DateUtil.now();
if (now >= runAt && now - runAt < T.mins(5).msecs())
return true;
return false;
}
}
@Override
String toJSON() {
JSONObject object = new JSONObject();
JSONObject data = new JSONObject();
try {
data.put("lastRun", lastRun);
data.put("runAt", runAt);
data.put("recurring", recurring);
data.put("monday", monday);
data.put("tuesday", tuesday);
data.put("wednesday", wednesday);
data.put("thursday", thursday);
data.put("friday", friday);
data.put("saturday", saturday);
data.put("sunday", sunday);
data.put("hour", hour);
data.put("minute", minute);
data.put("validTo", validTo);
object.put("type", TriggerTime.class.getName());
object.put("data", data.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return object.toString();
}
@Override
Trigger fromJSON(String data) {
JSONObject o;
try {
o = new JSONObject(data);
lastRun = JsonHelper.safeGetLong(o, "lastRun");
runAt = JsonHelper.safeGetLong(o, "runAt");
recurring = JsonHelper.safeGetBoolean(o, "recurring");
monday = JsonHelper.safeGetBoolean(o, "monday");
tuesday = JsonHelper.safeGetBoolean(o, "tuesday");
wednesday = JsonHelper.safeGetBoolean(o, "wednesday");
thursday = JsonHelper.safeGetBoolean(o, "thursday");
friday = JsonHelper.safeGetBoolean(o, "friday");
saturday = JsonHelper.safeGetBoolean(o, "saturday");
sunday = JsonHelper.safeGetBoolean(o, "sunday");
hour = JsonHelper.safeGetInt(o, "hour");
minute = JsonHelper.safeGetInt(o, "minute");
validTo = JsonHelper.safeGetLong(o, "validTo");
} catch (JSONException e) {
e.printStackTrace();
}
return this;
}
@Override
void notifyAboutRun(long time) {
lastRun = time;
}
TriggerTime lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerTime runAt(long runAt) {
this.runAt = runAt;
return this;
}
TriggerTime recurring(boolean recurring) {
this.recurring = recurring;
return this;
}
TriggerTime monday(boolean monday) {
this.monday = monday;
return this;
}
TriggerTime tuesday(boolean tuesday) {
this.tuesday = tuesday;
return this;
}
TriggerTime wednesday(boolean wednesday) {
this.wednesday = wednesday;
return this;
}
TriggerTime thursday(boolean thursday) {
this.thursday = thursday;
return this;
}
TriggerTime friday(boolean friday) {
this.friday = friday;
return this;
}
TriggerTime saturday(boolean saturday) {
this.saturday = saturday;
return this;
}
TriggerTime sunday(boolean sunday) {
this.sunday = sunday;
return this;
}
TriggerTime validTo(long validTo) {
this.validTo = validTo;
return this;
}
TriggerTime hour(int hour) {
this.hour = hour;
return this;
}
TriggerTime minute(int minute) {
this.minute = minute;
return this;
}
}

View file

@ -183,4 +183,8 @@ public class DateUtil {
public static long roundDateToSec(long date) { public static long roundDateToSec(long date) {
return date - date % 1000; return date - date % 1000;
} }
public static GregorianCalendar gregorianCalendar() {
return new GregorianCalendar();
}
} }

View file

@ -0,0 +1,105 @@
package info.nightscout.androidaps.plugins.general.automation.actions;
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.db.BgReading;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.T;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, Bus.class, ProfileFunctions.class, DateUtil.class})
public class TriggerBgTest {
@Test
public void shouldRunTest() {
when(MainApp.getDbHelper().getBgreadingsDataFromTime(anyLong(), anyBoolean())).thenReturn(generateOneCurrentRecordBgData());
TriggerBg t = new TriggerBg().units(Constants.MMOL).threshold(4.1d).comparator(Trigger.ISEQUAL);
Assert.assertFalse(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(214).comparator(Trigger.ISEQUAL);
Assert.assertTrue(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(214).comparator(Trigger.ISEQUALORGREATER);
Assert.assertTrue(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(214).comparator(Trigger.ISEQUALORLOWER);
Assert.assertTrue(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(215).comparator(Trigger.ISEQUAL);
Assert.assertFalse(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(215).comparator(Trigger.ISEQUALORLOWER);
Assert.assertTrue(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(215).comparator(Trigger.ISEQUALORGREATER);
Assert.assertFalse(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(213).comparator(Trigger.ISEQUALORGREATER);
Assert.assertTrue(t.shouldRun());
t = new TriggerBg().units(Constants.MGDL).threshold(213).comparator(Trigger.ISEQUALORLOWER);
Assert.assertFalse(t.shouldRun());
when(MainApp.getDbHelper().getBgreadingsDataFromTime(anyLong(), anyBoolean())).thenReturn(new ArrayList<>());
t = new TriggerBg().units(Constants.MGDL).threshold(213).comparator(Trigger.ISEQUALORLOWER);
Assert.assertFalse(t.shouldRun());
t = new TriggerBg().comparator(Trigger.NOTAVAILABLE);
Assert.assertTrue(t.shouldRun());
}
String bgJson = "{\"data\":\"{\\\"comparator\\\":0,\\\"threshold\\\":4.1,\\\"units\\\":\\\"mmol\\\"}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerBg\"}";
@Test
public void toJSONTest() {
TriggerBg t = new TriggerBg().units(Constants.MMOL).threshold(4.1d).comparator(Trigger.ISEQUAL);
Assert.assertEquals(bgJson, t.toJSON());
}
@Test
public void fromJSONTest() throws JSONException {
TriggerBg t = new TriggerBg().units(Constants.MMOL).threshold(4.1d).comparator(Trigger.ISEQUAL);
TriggerBg t2 = (TriggerBg) Trigger.instantiate(new JSONObject(t.toJSON()));
Assert.assertEquals(Trigger.ISEQUAL, t2.comparator);
Assert.assertEquals(4.1d, t2.threshold, 0.01d);
Assert.assertEquals(Constants.MMOL, t2.units);
}
@Before
public void mock() {
AAPSMocker.mockMainApp();
AAPSMocker.mockBus();
AAPSMocker.mockDatabaseHelper();
AAPSMocker.mockProfileFunctions();
PowerMockito.mockStatic(DateUtil.class);
when(DateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs());
}
List<BgReading> generateOneCurrentRecordBgData() {
List<BgReading> list = new ArrayList<>();
try {
list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":214,\"mills\":1514766900000,\"direction\":\"Flat\"}"))));
} catch (JSONException e) {
e.printStackTrace();
}
return list;
}
}

View file

@ -0,0 +1,83 @@
package info.nightscout.androidaps.plugins.general.automation.actions;
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.GregorianCalendar;
import info.AAPSMocker;
import info.nightscout.androidaps.MainApp;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.T;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, Bus.class, DateUtil.class, GregorianCalendar.class})
public class TriggerTimeTest {
long now = 1514766900000L;
@Test
public void shouldRunTest() {
// scheduled 1 min before
TriggerTime t = new TriggerTime().runAt(now - T.mins(1).msecs());
Assert.assertTrue(t.shouldRun());
// scheduled 1 min in the future
t = new TriggerTime().runAt(now + T.mins(1).msecs());
Assert.assertFalse(t.shouldRun());
// limit by validTo
t = new TriggerTime().recurring(true).hour(1).minute(34).validTo(1);
Assert.assertFalse(t.shouldRun());
// scheduled 1 min before
t = new TriggerTime().recurring(true).hour(1).minute(34);
Assert.assertTrue(t.shouldRun());
// already run
t = new TriggerTime().recurring(true).hour(1).minute(34).lastRun(now - 1);
Assert.assertFalse(t.shouldRun());
}
String timeJson = "{\"data\":\"{\\\"saturday\\\":true,\\\"runAt\\\":1514766840000,\\\"lastRun\\\":0,\\\"recurring\\\":false,\\\"thursday\\\":true,\\\"minute\\\":0,\\\"sunday\\\":true,\\\"tuesday\\\":true,\\\"hour\\\":0,\\\"wednesday\\\":true,\\\"friday\\\":true,\\\"monday\\\":true,\\\"validTo\\\":0}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerTime\"}";
@Test
public void toJSONTest() {
TriggerTime t = new TriggerTime().runAt(now - T.mins(1).msecs());
Assert.assertEquals(timeJson, t.toJSON());
}
@Test
public void fromJSONTest() throws JSONException {
TriggerTime t = new TriggerTime().runAt(now - T.mins(1).msecs());
TriggerTime t2 = (TriggerTime) Trigger.instantiate(new JSONObject(t.toJSON()));
Assert.assertEquals(now - T.mins(1).msecs(), t2.runAt);
Assert.assertEquals(false, t2.recurring);
}
@Before
public void mock() {
AAPSMocker.mockMainApp();
AAPSMocker.mockBus();
PowerMockito.mockStatic(DateUtil.class);
when(DateUtil.now()).thenReturn(now);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(now);
when(DateUtil.gregorianCalendar()).thenReturn(calendar);
}
}