cob display

This commit is contained in:
Milos Kozak 2017-04-26 23:45:40 +02:00
parent 638f6bc291
commit 5ef034b4fc
11 changed files with 363 additions and 96 deletions

View file

@ -4,6 +4,8 @@ package info.nightscout.androidaps;
* Created by mike on 07.06.2016. * Created by mike on 07.06.2016.
*/ */
public class Config { public class Config {
public static final boolean CACHECALCULATIONS = true;
// MAIN FUCTIONALITY // MAIN FUCTIONALITY
public static final boolean APS = BuildConfig.APS; public static final boolean APS = BuildConfig.APS;
// PLUGINS // PLUGINS

View file

@ -16,4 +16,5 @@ public interface TreatmentsInterface {
IobTotal getCalculationToTime(long time); IobTotal getCalculationToTime(long time);
MealData getMealData(); MealData getMealData();
List<Treatment> getTreatments(); List<Treatment> getTreatments();
List<Treatment> getTreatments5MinBack(long time);
} }

View file

@ -0,0 +1,20 @@
package info.nightscout.androidaps.plugins.IobCobCalculator;
import java.util.Date;
/**
* Created by mike on 25.04.2017.
*/
public class AutosensData {
String pastSensitivity = "";
double deviation = 0d;
double absorbed = 0d;
double carbsFromBolus = 0d;
public double cob = 0;
public String log(long time) {
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Deviation=" + deviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob;
}
}

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.IobCobCalculator;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -15,16 +16,23 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
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.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
import info.nightscout.androidaps.plugins.OpenAPSAMA.Autosens;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.SP;
/** /**
* Created by mike on 24.04.2017. * Created by mike on 24.04.2017.
@ -33,8 +41,8 @@ import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
public class IobCobCalculatorPlugin implements PluginBase { public class IobCobCalculatorPlugin implements PluginBase {
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class); private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
private static HashMap<Long, IobTotal> iobTable = new HashMap<Long, IobTotal>(); private static LongSparseArray<IobTotal> iobTable = new LongSparseArray<>();
private static HashMap<Long, MealData> mealDataTable = new HashMap<Long, MealData>(); private static LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>();
private static List<BgReading> bgReadings = null; // newest at index 0 private static List<BgReading> bgReadings = null; // newest at index 0
private static List<BgReading> bucketed_data = null; private static List<BgReading> bucketed_data = null;
@ -121,6 +129,13 @@ public class IobCobCalculatorPlugin implements PluginBase {
return -1; return -1;
} }
public static long roundUpTime(long time) {
if (time % 60000 == 0)
return time;
long rouded = (time / 60000 + 1) * 60000;
return rouded;
}
private void loadBgData() { private void loadBgData() {
onNewProfile(new EventNewBasalProfile(null)); onNewProfile(new EventNewBasalProfile(null));
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (new Date().getTime() - 60 * 60 * 1000L * (24 + dia)), false); bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (new Date().getTime() - 60 * 60 * 1000L * (24 + dia)), false);
@ -189,23 +204,139 @@ public class IobCobCalculatorPlugin implements PluginBase {
log.debug("Bucketed data created. Size: " + bucketed_data.size()); log.debug("Bucketed data created. Size: " + bucketed_data.size());
} }
public static IobTotal calulateFromTreatmentsAndTemps() { public void calculateSensitivityData() {
ConfigBuilderPlugin.getActiveTreatments().updateTotalIOB(); NSProfile profile = ConfigBuilderPlugin.getActiveProfile() != null ? ConfigBuilderPlugin.getActiveProfile().getProfile() : null;
IobTotal bolusIob = ConfigBuilderPlugin.getActiveTreatments().getLastCalculation().round();
ConfigBuilderPlugin.getActiveTempBasals().updateTotalIOB(); if (profile == null) {
IobTotal basalIob = ConfigBuilderPlugin.getActiveTempBasals().getLastCalculation().round(); log.debug("calculateSensitivityData: No profile available");
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round(); return;
return iobTotal; }
if (ConfigBuilderPlugin.getActiveTreatments() == null) {
log.debug("calculateSensitivityData: No treatments plugin");
return;
}
TreatmentsInterface treatmentsInterface = ConfigBuilderPlugin.getActiveTreatments();
if (bucketed_data == null || bucketed_data.size() < 3) {
log.debug("calculateSensitivityData: No bucketed data available");
return;
}
long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).timeIndex);
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
AutosensData previous = autosensDataTable.get(prevDataTime);
// start from oldest to be able sub cob
for (int i = bucketed_data.size() - 4; i >= 0; i--) {
// check if data already exists
long bgTime = bucketed_data.get(i).timeIndex;
bgTime = roundUpTime(bgTime);
AutosensData existing;
if ((existing = autosensDataTable.get(bgTime)) != null) {
previous = existing;
continue;
}
int secondsFromMidnight = NSProfile.secondsFromMidnight(bgTime);
double sens = NSProfile.toMgdl(profile.getIsf(secondsFromMidnight), profile.getUnits());
AutosensData autosensData = new AutosensData();
//console.error(bgTime , bucketed_data[i].glucose);
double bg;
double avgDelta;
double delta;
bg = bucketed_data.get(i).value;
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
log.error("! value < 39");
continue;
}
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
delta = (bg - bucketed_data.get(i + 1).value);
IobTotal iob = calulateFromTreatmentsAndTemps(bgTime);
double bgi = Math.round((-iob.activity * sens * 5) * 100) / 100d;
double deviation = delta - bgi;
List<Treatment> recentTreatments = treatmentsInterface.getTreatments5MinBack(bgTime);
for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
}
// if we absorbing carbs
if (previous != null && previous.cob > 0) {
// figure out how many carbs that represents
// but always assume at least 3mg/dL/5m (default) absorption
double ci = Math.max(deviation, SP.getDouble("openapsama_min_5m_carbimpact", 3.0));
autosensData.absorbed = ci * profile.getIc(secondsFromMidnight) / sens;
// and add that to the running total carbsAbsorbed
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
}
autosensData.cob += autosensData.carbsFromBolus;
// calculate autosens only without COB
if (autosensData.cob <= 0) {
if (deviation > 0) {
autosensData.pastSensitivity += "+";
} else if (deviation == 0) {
autosensData.pastSensitivity += "=";
} else {
autosensData.pastSensitivity += "-";
}
//avgDeltas[i] = avgDelta;
//bgis[i] = bgi;
autosensData.deviation = deviation;
} else {
autosensData.pastSensitivity += "C";
//console.error(bgTime);
}
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
previous = autosensData;
autosensDataTable.put(bgTime, autosensData);
log.debug(autosensData.log(bgTime));
}
} }
public static IobTotal calulateFromTreatmentsAndTemps(long time) { public static IobTotal calulateFromTreatmentsAndTemps(long time) {
long now = new Date().getTime();
time = roundUpTime(time);
if (Config.CACHECALCULATIONS && time < now && iobTable.get(time) != null) {
//log.debug(">>> Cache hit");
return iobTable.get(time);
} else {
//log.debug(">>> Cache miss " + new Date(time).toLocaleString());
}
IobTotal bolusIob = ConfigBuilderPlugin.getActiveTreatments().getCalculationToTime(time).round(); IobTotal bolusIob = ConfigBuilderPlugin.getActiveTreatments().getCalculationToTime(time).round();
IobTotal basalIob = ConfigBuilderPlugin.getActiveTempBasals().getCalculationToTime(time).round(); IobTotal basalIob = ConfigBuilderPlugin.getActiveTempBasals().getCalculationToTime(time).round();
/*
if (basalIob.basaliob > 0) { if (basalIob.basaliob > 0) {
log.debug(new Date(time).toLocaleString() + " basaliob: " + basalIob.basaliob ); log.debug(new Date(time).toLocaleString() + " basaliob: " + basalIob.basaliob );
} }
*/
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round(); IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
return iobTotal; if (Config.CACHECALCULATIONS && time < new Date().getTime()) {
iobTable.put(time, iobTotal);
}
return iobTotal;
}
public static AutosensData getAutosensData(long time) {
long now = new Date().getTime();
if (time > now )
return null;
time = roundUpTime(time);
AutosensData data = autosensDataTable.get(time);
if (Config.CACHECALCULATIONS && data != null) {
log.debug(">>> Cache hit " + data.log(time));
return data;
} else {
log.debug(">>> Cache miss " + new Date(time).toLocaleString());
return null;
}
} }
public static IobTotal[] calculateIobArrayInDia() { public static IobTotal[] calculateIobArrayInDia() {
@ -215,7 +346,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
int len = (int) ((profile.getDia() * 60 + 30) / 5); int len = (int) ((profile.getDia() * 60 + 30) / 5);
IobTotal[] array = new IobTotal[len]; IobTotal[] array = new IobTotal[len];
int pos = 0; int pos = 0;
for (int i = 0; i < len; i++){ for (int i = 0; i < len; i++) {
long t = time + i * 5 * 60000; long t = time + i * 5 * 60000;
IobTotal iob = calulateFromTreatmentsAndTemps(t); IobTotal iob = calulateFromTreatmentsAndTemps(t);
array[pos] = iob; array[pos] = iob;
@ -226,7 +357,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
public static JSONArray convertToJSONArray(IobTotal[] iobArray) { public static JSONArray convertToJSONArray(IobTotal[] iobArray) {
JSONArray array = new JSONArray(); JSONArray array = new JSONArray();
for (int i = 0; i < iobArray.length; i ++) { for (int i = 0; i < iobArray.length; i++) {
array.put(iobArray[i].determineBasalJson()); array.put(iobArray[i].determineBasalJson());
} }
return array; return array;
@ -239,6 +370,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
public void run() { public void run() {
loadBgData(); loadBgData();
createBucketedData(); createBucketedData();
calculateSensitivityData();
} }
}); });
} }
@ -253,4 +385,27 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
} }
// When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
@Subscribe
public void onNewHistoryData(EventNewHistoryData ev) {
long time = ev.time;
log.debug("Invalidating cached data to: " + new Date(time).toLocaleString());
for (int index = iobTable.size() - 1; index >= 0; index--) {
if (iobTable.keyAt(index) > time) {
log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
iobTable.removeAt(index);
} else {
break;
}
}
for (int index = autosensDataTable.size() - 1; index >= 0; index--) {
if (autosensDataTable.keyAt(index) > time) {
log.debug("Removing from autosensDataTable: " + new Date(autosensDataTable.keyAt(index)).toLocaleString());
autosensDataTable.removeAt(index);
} else {
break;
}
}
}
} }

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps.plugins.IobCobCalculator.events;
/**
* Created by mike on 26.04.2017.
*/
public class EventNewHistoryData {
public long time = 0;
public EventNewHistoryData(long time) {
this.time = time;
}
}

View file

@ -25,7 +25,6 @@ public class Autosens {
//console.error(mealTime); //console.error(mealTime);
double deviationSum = 0;
double carbsAbsorbed = 0; double carbsAbsorbed = 0;
List<BgReading> bucketed_data = IobCobCalculatorPlugin.getBucketedData(dataFromTime); List<BgReading> bucketed_data = IobCobCalculatorPlugin.getBucketedData(dataFromTime);
@ -33,8 +32,8 @@ public class Autosens {
return new AutosensResult(); return new AutosensResult();
//console.error(bucketed_data); //console.error(bucketed_data);
double[] avgDeltas = new double[bucketed_data.size() - 2]; //double[] avgDeltas = new double[bucketed_data.size() - 2];
double[] bgis = new double[bucketed_data.size() - 2]; //double[] bgis = new double[bucketed_data.size() - 2];
double[] deviations = new double[bucketed_data.size() - 2]; double[] deviations = new double[bucketed_data.size() - 2];
String pastSensitivity = ""; String pastSensitivity = "";
@ -81,10 +80,9 @@ public class Autosens {
} else { } else {
pastSensitivity += "-"; pastSensitivity += "-";
} }
avgDeltas[i] = avgDelta; //avgDeltas[i] = avgDelta;
bgis[i] = bgi; //bgis[i] = bgi;
deviations[i] = deviation; deviations[i] = deviation;
deviationSum += deviation;
} else { } else {
pastSensitivity += ">"; pastSensitivity += ">";
//console.error(bgTime); //console.error(bgTime);
@ -112,8 +110,8 @@ public class Autosens {
log.debug(pastSensitivity); log.debug(pastSensitivity);
//console.log(JSON.stringify(avgDeltas)); //console.log(JSON.stringify(avgDeltas));
//console.log(JSON.stringify(bgis)); //console.log(JSON.stringify(bgis));
Arrays.sort(avgDeltas); //Arrays.sort(avgDeltas);
Arrays.sort(bgis); //Arrays.sort(bgis);
Arrays.sort(deviations); Arrays.sort(deviations);
for (double i = 0.9; i > 0.1; i = i - 0.02) { for (double i = 0.9; i > 0.1; i = i - 0.02) {

View file

@ -50,6 +50,10 @@ import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
@ -76,6 +80,7 @@ import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialo
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.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification; import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
@ -155,6 +160,9 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
private static Handler sHandler; private static Handler sHandler;
private static HandlerThread sHandlerThread; private static HandlerThread sHandlerThread;
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledUpdate = null;
public OverviewFragment() { public OverviewFragment() {
super(); super();
if (sHandlerThread == null) { if (sHandlerThread == null) {
@ -272,19 +280,19 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
switch (buttonView.getId()) { switch (buttonView.getId()) {
case R.id.overview_showprediction: case R.id.overview_showprediction:
SP.putBoolean("showprediction", showPredictionView.isChecked()); SP.putBoolean("showprediction", showPredictionView.isChecked());
updateGUI("onPredictionCheckedChanged"); scheduleUpdateGUI("onPredictionCheckedChanged");
break; break;
case R.id.overview_showbasals: case R.id.overview_showbasals:
SP.putBoolean("showbasals", showPredictionView.isChecked()); SP.putBoolean("showbasals", showPredictionView.isChecked());
updateGUI("onBasalsCheckedChanged"); scheduleUpdateGUI("onBasalsCheckedChanged");
break; break;
case R.id.overview_showiob: case R.id.overview_showiob:
SP.putBoolean("showiob", showIobView.isChecked()); SP.putBoolean("showiob", showIobView.isChecked());
updateGUI("onIobCheckedChanged"); scheduleUpdateGUI("onIobCheckedChanged");
break; break;
case R.id.overview_showcob: case R.id.overview_showcob:
SP.putBoolean("showcob", showCobView.isChecked()); SP.putBoolean("showcob", showCobView.isChecked());
updateGUI("onCobCheckedChanged"); scheduleUpdateGUI("onCobCheckedChanged");
break; break;
} }
} }
@ -296,15 +304,17 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
activeloop.setFragmentEnabled(PluginBase.LOOP, false); activeloop.setFragmentEnabled(PluginBase.LOOP, false);
activeloop.setFragmentVisible(PluginBase.LOOP, false); activeloop.setFragmentVisible(PluginBase.LOOP, false);
MainApp.getConfigBuilder().storeSettings(); MainApp.getConfigBuilder().storeSettings();
scheduleUpdateGUI("suspendmenu");
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.enableloop))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.enableloop))) {
activeloop.setFragmentEnabled(PluginBase.LOOP, true); activeloop.setFragmentEnabled(PluginBase.LOOP, true);
activeloop.setFragmentVisible(PluginBase.LOOP, true); activeloop.setFragmentVisible(PluginBase.LOOP, true);
MainApp.getConfigBuilder().storeSettings(); MainApp.getConfigBuilder().storeSettings();
scheduleUpdateGUI("suspendmenu");
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.resume))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.resume))) {
activeloop.suspendTo(0L); activeloop.suspendTo(0L);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
sHandler.post(new Runnable() { sHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -317,23 +327,23 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor1h))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor1h))) {
activeloop.suspendTo(new Date().getTime() + 60L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 60L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor2h))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor2h))) {
activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor3h))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor3h))) {
activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor10h))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor10h))) {
activeloop.suspendTo(new Date().getTime() + 10 * 60L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 10 * 60L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor30m))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor30m))) {
activeloop.suspendTo(new Date().getTime() + 30L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 30L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
sHandler.post(new Runnable() { sHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -346,7 +356,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor1h))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor1h))) {
activeloop.suspendTo(new Date().getTime() + 1 * 60L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 1 * 60L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
sHandler.post(new Runnable() { sHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -359,7 +369,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor2h))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor2h))) {
activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
sHandler.post(new Runnable() { sHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -372,7 +382,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
return true; return true;
} else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor3h))) { } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor3h))) {
activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000); activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000);
updateGUI("suspendmenu"); scheduleUpdateGUI("suspendmenu");
sHandler.post(new Runnable() { sHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -461,7 +471,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
objectivesPlugin.saveProgress(); objectivesPlugin.saveProgress();
} }
} }
updateGUIIfVisible("onClickAcceptTemp"); scheduleUpdateGUI("onClickAcceptTemp");
} }
}); });
Answers.getInstance().logCustom(new CustomEvent("AcceptTemp")); Answers.getInstance().logCustom(new CustomEvent("AcceptTemp"));
@ -585,58 +595,58 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
sRefreshLoop = new Runnable() { sRefreshLoop = new Runnable() {
@Override @Override
public void run() { public void run() {
updateGUIIfVisible("refreshLoop"); scheduleUpdateGUI("refreshLoop");
sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L);
} }
}; };
sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L);
registerForContextMenu(apsModeView); registerForContextMenu(apsModeView);
updateGUIIfVisible("onResume"); updateGUI("onResume");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventInitializationChanged ev) { public void onStatusEvent(final EventInitializationChanged ev) {
updateGUIIfVisible("EventInitializationChanged"); scheduleUpdateGUI("EventInitializationChanged");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventPreferenceChange ev) { public void onStatusEvent(final EventPreferenceChange ev) {
updateGUIIfVisible("EventPreferenceChange"); scheduleUpdateGUI("EventPreferenceChange");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventRefreshGui ev) { public void onStatusEvent(final EventRefreshGui ev) {
updateGUIIfVisible("EventRefreshGui"); scheduleUpdateGUI("EventRefreshGui");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventTreatmentChange ev) { public void onStatusEvent(final EventTreatmentChange ev) {
updateGUIIfVisible("EventTreatmentChange"); scheduleUpdateGUI("EventTreatmentChange");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventTempBasalChange ev) { public void onStatusEvent(final EventTempBasalChange ev) {
updateGUIIfVisible("EventTempBasalChange"); scheduleUpdateGUI("EventTempBasalChange");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventNewBG ev) { public void onStatusEvent(final EventNewBG ev) {
updateGUIIfVisible("EventTempBasalChange"); scheduleUpdateGUI("EventTempBasalChange");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventNewOpenLoopNotification ev) { public void onStatusEvent(final EventNewOpenLoopNotification ev) {
updateGUIIfVisible("EventNewOpenLoopNotification"); scheduleUpdateGUI("EventNewOpenLoopNotification");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventNewBasalProfile ev) { public void onStatusEvent(final EventNewBasalProfile ev) {
updateGUIIfVisible("EventNewBasalProfile"); scheduleUpdateGUI("EventNewBasalProfile");
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventTempTargetRangeChange ev) { public void onStatusEvent(final EventTempTargetRangeChange ev) {
updateGUIIfVisible("EventTempTargetRangeChange"); scheduleUpdateGUI("EventTempTargetRangeChange");
} }
@Subscribe @Subscribe
@ -672,17 +682,6 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
}); });
} }
private void updateGUIIfVisible(final String from) {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
updateGUI(from);
}
});
}
private void updatePumpStatus(String status) { private void updatePumpStatus(String status) {
PumpInterface pump = MainApp.getConfigBuilder(); PumpInterface pump = MainApp.getConfigBuilder();
if (!status.equals("")) { if (!status.equals("")) {
@ -697,6 +696,29 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
} }
} }
public void scheduleUpdateGUI(final String from) {
class UpdateRunnable implements Runnable {
public void run() {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
updateGUI(from);
scheduledUpdate = null;
}
});
}
}
// prepare task for execution in 400 msec
// cancel waiting task to prevent multiple updates
if (scheduledUpdate != null)
scheduledUpdate.cancel(false);
Runnable task = new UpdateRunnable();
final int msec = 400;
scheduledUpdate = worker.schedule(task, msec, TimeUnit.MILLISECONDS);
}
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
public void updateGUI(String from) { public void updateGUI(String from) {
log.debug("updateGUI entered from: " + from); log.debug("updateGUI entered from: " + from);
@ -1044,7 +1066,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2); paint.setStrokeWidth(2);
paint.setPathEffect(new DashPathEffect(new float[]{2, 4}, 0)); paint.setPathEffect(new DashPathEffect(new float[]{2, 4}, 0));
paint.setColor(Color.CYAN); paint.setColor(MainApp.sResources.getColor(R.color.basal));
basalsLineSeries.setCustomPaint(paint); basalsLineSeries.setCustomPaint(paint);
} }
@ -1058,48 +1080,56 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
Date start = new Date(); Date start = new Date();
List<DataPoint> iobArray = new ArrayList<>(); List<DataPoint> iobArray = new ArrayList<>();
List<DataPoint> cobArray = new ArrayList<>(); List<DataPoint> cobArray = new ArrayList<>();
double lastIob = -1000; for (long time = fromTime; time <= now; time += 5 * 60 * 1000L) {
for (long time = fromTime; time <= endTime; time += 5 * 60 * 1000L) {
if (showIobView.isChecked()) { if (showIobView.isChecked()) {
IobTotal iob = IobCobCalculatorPlugin.calulateFromTreatmentsAndTemps(time); IobTotal iob = IobCobCalculatorPlugin.calulateFromTreatmentsAndTemps(time);
if (lastIob != iob.iob) { iobArray.add(new DataPoint(time, iob.iob));
iobArray.add(new DataPoint(time, iob.iob)); maxIobValueFound = Math.max(maxIobValueFound, Math.abs(iob.iob));
maxIobValueFound = Math.max(maxIobValueFound, Math.abs(iob.iob));
lastIob = iob.iob;
}
} }
if (showCobView.isChecked()) { if (showCobView.isChecked()) {
//MealData mealData = MainApp.getConfigBuilder().getActiveTreatments().getMealData(); AutosensData autosensData = IobCobCalculatorPlugin.getAutosensData(time);
//cobArray.add(new DataPoint(time, mealData.mealCOB)); if (autosensData != null) {
//maxCobValueFound = Math.max(maxCobValueFound, mealData.mealCOB); cobArray.add(new DataPoint(time, autosensData.cob));
maxCobValueFound = Math.max(maxCobValueFound, autosensData.cob);
}
} }
} }
Profiler.log(log,"IOB precessed", start); Profiler.log(log, "IOB processed", start);
DataPoint[] iobData = new DataPoint[iobArray.size()]; DataPoint[] iobData = new DataPoint[iobArray.size()];
iobData = iobArray.toArray(iobData); iobData = iobArray.toArray(iobData);
iobSeries = new FixedLineGraphSeries<>(iobData); iobSeries = new FixedLineGraphSeries<>(iobData);
iobSeries.setDrawBackground(true); iobSeries.setDrawBackground(true);
iobSeries.setBackgroundColor(0x80FFFFFF & MainApp.sResources.getColor(R.color.ioborange)); //50% iobSeries.setBackgroundColor(0x80FFFFFF & MainApp.sResources.getColor(R.color.iob)); //50%
iobSeries.setColor(MainApp.sResources.getColor(R.color.ioborange)); iobSeries.setColor(MainApp.sResources.getColor(R.color.iob));
iobSeries.setThickness(3); iobSeries.setThickness(3);
iobSeries.setTitle("IOB"); iobSeries.setTitle("IOB");
iobGraph.getGridLabelRenderer().setVerticalLabelsAlign(Paint.Align.LEFT); iobGraph.getGridLabelRenderer().setVerticalLabelsAlign(Paint.Align.LEFT);
if (showIobView.isChecked() && showCobView.isChecked()) {
List<DataPoint> cobArrayRescaled = new ArrayList<>();
for (int ci = 0; ci < cobArray.size(); ci++) {
cobArrayRescaled.add(new DataPoint(cobArray.get(ci).getX(), cobArray.get(ci).getY() * maxIobValueFound / maxCobValueFound / 2));
}
cobArray = cobArrayRescaled;
}
DataPoint[] cobData = new DataPoint[cobArray.size()]; DataPoint[] cobData = new DataPoint[cobArray.size()];
cobData = cobArray.toArray(cobData); cobData = cobArray.toArray(cobData);
cobSeries = new FixedLineGraphSeries<>(cobData); cobSeries = new FixedLineGraphSeries<>(cobData);
cobSeries.setDrawBackground(true); cobSeries.setDrawBackground(true);
cobSeries.setBackgroundColor(Color.RED); cobSeries.setBackgroundColor(0xB0FFFFFF & MainApp.sResources.getColor(R.color.cob)); //50%
cobSeries.setThickness(0); cobSeries.setColor(MainApp.sResources.getColor(R.color.cob));
cobSeries.setThickness(3);
cobSeries.setTitle("COB");
iobGraph.removeAllSeries(); iobGraph.removeAllSeries();
if (showIobView.isChecked()) { if (showIobView.isChecked()) {
iobGraph.addSeries(iobSeries); iobGraph.addSeries(iobSeries);
} }
if (showCobView.isChecked()) { if (showCobView.isChecked() && cobData.length > 0) {
iobGraph.getSecondScale().addSeries(cobSeries); iobGraph.addSeries(cobSeries);
iobGraph.getSecondScale().setLabelFormatter(new LabelFormatter() { /* iobGraph.getSecondScale().setLabelFormatter(new LabelFormatter() {
@Override @Override
public String formatLabel(double value, boolean isValueX) { public String formatLabel(double value, boolean isValueX) {
return ""; return "";
@ -1107,10 +1137,9 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
@Override @Override
public void setViewport(Viewport viewport) { public void setViewport(Viewport viewport) {
} }
}); });
} */ }
iobGraphLayout.setVisibility(View.VISIBLE); iobGraphLayout.setVisibility(View.VISIBLE);
} else { } else {
iobGraphLayout.setVisibility(View.GONE); iobGraphLayout.setVisibility(View.GONE);
@ -1194,7 +1223,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
bgGraph.addSeries(predSeries = new PointsGraphSeries<BgReading>(pred)); bgGraph.addSeries(predSeries = new PointsGraphSeries<BgReading>(pred));
predSeries.setShape(PointsGraphSeries.Shape.POINT); predSeries.setShape(PointsGraphSeries.Shape.POINT);
predSeries.setSize(4); predSeries.setSize(4);
predSeries.setColor(Color.MAGENTA); predSeries.setColor(MainApp.sResources.getColor(R.color.prediction));
} }
} }

View file

@ -5,6 +5,7 @@ import com.squareup.otto.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -163,6 +164,17 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
return treatments; return treatments;
} }
@Override
public List<Treatment> getTreatments5MinBack(long time) {
List<Treatment> in5minback = new ArrayList<>();
for (Integer pos = 0; pos < treatments.size(); pos++) {
Treatment t = treatments.get(pos);
if (t.created_at.getTime() <= time && t.created_at.getTime() > time - 5 * 60 * 1000)
in5minback.add(t);
}
return in5minback;
}
@Subscribe @Subscribe
public void onStatusEvent(final EventTreatmentChange ev) { public void onStatusEvent(final EventTreatmentChange ev) {
initializeData(); initializeData();

View file

@ -218,16 +218,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="80dip" /> android:layout_height="80dip" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:text="@string/iob"
android:textColor="@color/ioborange"
android:textStyle="bold" />
</RelativeLayout> </RelativeLayout>
</LinearLayout> </LinearLayout>
@ -237,30 +227,73 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/predictionshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/prediction"
android:textStyle="bold" />
<CheckBox <CheckBox
android:id="@+id/overview_showprediction" android:id="@+id/overview_showprediction"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:buttonTint="@color/magenta" /> android:layout_marginBottom="-5dp"
android:layout_marginTop="-9dp"
app:buttonTint="@color/prediction" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox <CheckBox
android:id="@+id/overview_showbasals" android:id="@+id/overview_showbasals"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:buttonTint="@color/cyan" /> android:layout_marginBottom="-5dp"
android:layout_marginTop="-9dp"
app:buttonTint="@color/basal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/iob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iob"
android:textStyle="bold" />
<CheckBox <CheckBox
android:id="@+id/overview_showiob" android:id="@+id/overview_showiob"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:buttonTint="@color/ioborange" /> android:layout_marginBottom="-5dp"
android:layout_marginTop="-9dp"
app:buttonTint="@color/iob" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/cob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/cob"
android:textStyle="bold" />
<CheckBox <CheckBox
android:id="@+id/overview_showcob" android:id="@+id/overview_showcob"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" android:layout_marginBottom="-5dp"
app:buttonTint="@color/cyan" /> android:layout_marginTop="-9dp"
app:buttonTint="@color/cob" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View file

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="magenta">#ff00ff</color> <color name="prediction">#ff00ff</color>
<color name="cyan">#00ffff</color> <color name="basal">#00ffff</color>
<color name="ioborange">#FFFB8C00</color> <color name="iob">#FFFB8C00</color>
<color name="cob">#fbf300</color>
<color name="colorPrimary">#3F51B5</color> <color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color> <color name="colorPrimaryDark">#303F9F</color>

View file

@ -593,4 +593,7 @@
<string name="enablesuperbolus">Enable superbolus in wizard</string> <string name="enablesuperbolus">Enable superbolus in wizard</string>
<string name="enablesuperbolus_summary">Enable superbolus functionality in wizard. Do not enable until you learn what it really does. IT MAY CAUSE INSULIN OVERDOSE IF USED BLINDLY!</string> <string name="enablesuperbolus_summary">Enable superbolus functionality in wizard. Do not enable until you learn what it really does. IT MAY CAUSE INSULIN OVERDOSE IF USED BLINDLY!</string>
<string name="iob">IOB</string> <string name="iob">IOB</string>
<string name="cob">COB</string>
<string name="predictionshortlabel">PRE</string>
<string name="basalshortlabel">BAS</string>
</resources> </resources>