most new AMA code added

This commit is contained in:
Milos Kozak 2017-01-06 22:42:37 +01:00
parent 26102848f5
commit 25a3b678e9
22 changed files with 523 additions and 147 deletions

View file

@ -6,7 +6,7 @@ import com.j256.ormlite.stmt.query.In;
* Created by mike on 07.06.2016.
*/
public class Constants {
public static final String MGDL = "mg/dl"; // This is Nightscout representation
public static final String MGDL = "mg/dl"; // This is Nightscout's representation
public static final String MMOL = "mmol";
public static final double MMOLL_TO_MGDL = 18; // 18.0182;
@ -24,5 +24,17 @@ public class Constants {
public static final long keepAliveMsecs = 5 * 60 * 1000L;
// SMS COMMUNICATOR
public static final long remoteBolusMinDistance = 15 * 60 * 1000L;
// AMA
public static final int MAX_DAILY_SAFETY_MULTIPLIER = 3;
public static final int CURRENT_BASAL_SAFETY_MULTIPLIER = 4;
public static final int BOLUSSNOOZE_DIA_ADVISOR = 2;
public static final double AUTOSENS_MAX = 1.2d;
public static final double AUTOSENS_MIN = 0.7d;
public static final double MIN_5M_CARBIMPACT = 3d;
}

View file

@ -1,11 +1,21 @@
package info.nightscout.androidaps.data;
import android.support.annotation.Nullable;
import android.text.Html;
import android.text.Spanned;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
@ -17,35 +27,105 @@ public class GlucoseStatus {
public double glucose = 0d;
public double delta = 0d;
public double avgdelta = 0d;
public double short_avgdelta = 0d; // TODO: add calculation for AMA
public double long_avgdelta = 0d; // TODO: add calculation for AMA
public double short_avgdelta = 0d;
public double long_avgdelta = 0d;
@Override
public String toString() {
return MainApp.sResources.getString(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" +
MainApp.sResources.getString(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" +
MainApp.sResources.getString(R.string.avgdelta) + " " + DecimalFormatter.to2Decimal(avgdelta) + " mg/dl";
MainApp.sResources.getString(R.string.short_avgdelta) + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl\n" +
MainApp.sResources.getString(R.string.long_avgdelta) + " " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
}
public Spanned toSpanned() {
return Html.fromHtml("<b>" + MainApp.sResources.getString(R.string.glucose) + "</b>: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.delta) + "</b>: " + DecimalFormatter.to0Decimal(delta) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(avgdelta) + " mg/dl");
"<b>" + MainApp.sResources.getString(R.string.short_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.long_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl");
}
public GlucoseStatus() {
}
public GlucoseStatus(Double glucose, Double delta, Double avgdelta) {
this.glucose = glucose;
this.delta = delta;
this.avgdelta = avgdelta;
}
public GlucoseStatus round() {
this.glucose = Round.roundTo(this.glucose, 0.1);
this.delta = Round.roundTo(this.delta, 0.01);
this.avgdelta = Round.roundTo(this.avgdelta, 0.01);
this.short_avgdelta = Round.roundTo(this.short_avgdelta, 0.01);
this.long_avgdelta = Round.roundTo(this.long_avgdelta, 0.01);
return this;
}
@Nullable
public static GlucoseStatus getGlucoseStatusData() {
// load 45min
long fromtime = (long) (new Date().getTime() - 60 * 1000L * 45);
List<BgReading> data = MainApp.getDbHelper().getDataFromTime(fromtime, false);
int sizeRecords = data.size();
if (sizeRecords < 4 || data.get(0).timeIndex < new Date().getTime() - 7 * 60 * 1000L) {
return null;
}
BgReading now = data.get(0);
long now_date = now.timeIndex;
double change;
ArrayList<Double> last_deltas = new ArrayList<Double>();
ArrayList<Double> short_deltas = new ArrayList<Double>();
ArrayList<Double> long_deltas = new ArrayList<Double>();
for (int i = 1; i < data.size(); i++) {
if (data.get(i).value > 38) {
BgReading then = data.get(i);
long then_date = then.timeIndex;
double avgdelta = 0;
int minutesago;
minutesago = Math.round((now_date - then_date) / (1000 * 60));
// multiply by 5 to get the same units as delta, i.e. mg/dL/5m
change = now.value - then.value;
avgdelta = change / minutesago * 5;
// use the average of all data points in the last 2.5m for all further "now" calculations
if (0 < minutesago && minutesago < 2.5) {
now.value = (now.value + then.value) / 2;
now_date = (now_date + then_date) / 2;
// short_deltas are calculated from everything ~5-15 minutes ago
} else if (2.5 < minutesago && minutesago < 17.5) {
//console.error(minutesago, avgdelta);
short_deltas.add(avgdelta);
// last_deltas are calculated from everything ~5 minutes ago
if (2.5 < minutesago && minutesago < 7.5) {
last_deltas.add(avgdelta);
}
// long_deltas are calculated from everything ~20-40 minutes ago
} else if (17.5 < minutesago && minutesago < 42.5) {
long_deltas.add(avgdelta);
}
}
}
GlucoseStatus status = new GlucoseStatus();
status.glucose = now.value;
status.delta = average(last_deltas);
status.short_avgdelta = average(short_deltas);
status.long_avgdelta = average(long_deltas);
status.avgdelta = status.short_avgdelta; // for OpenAPS MA
return status.round();
}
public static double average(ArrayList<Double> array) {
double sum = 0d;
if (array.size() == 0)
return 0d;
for (Double value : array) {
sum += value;
}
return sum / array.size();
}
}

View file

@ -1,10 +1,14 @@
package info.nightscout.androidaps.data;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Date;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.Round;
@ -73,4 +77,62 @@ public class IobTotal {
}
return json;
}
public JSONObject determineBasalJson() {
JSONObject json = new JSONObject();
try {
json.put("iob", iob);
json.put("basaliob", basaliob);
json.put("bolussnooze", bolussnooze);
json.put("activity", activity);
json.put("time", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
public static IobTotal calulateFromTreatmentsAndTemps() {
ConfigBuilderPlugin.getActiveTreatments().updateTotalIOB();
IobTotal bolusIob = ConfigBuilderPlugin.getActiveTreatments().getLastCalculation().round();
if (bolusIob == null) bolusIob = new IobTotal();
ConfigBuilderPlugin.getActiveTempBasals().updateTotalIOB();
IobTotal basalIob = ConfigBuilderPlugin.getActiveTempBasals().getLastCalculation().round();
if (basalIob == null) basalIob = new IobTotal();
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
return iobTotal;
}
public static IobTotal calulateFromTreatmentsAndTemps(long time) {
IobTotal bolusIob = ConfigBuilderPlugin.getActiveTreatments().getCalculationToTime(time).round();
if (bolusIob == null) bolusIob = new IobTotal();
IobTotal basalIob = ConfigBuilderPlugin.getActiveTempBasals().getCalculationToTime(time).round();
if (basalIob == null) basalIob = new IobTotal();
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
return iobTotal;
}
public static IobTotal[] calculateIobArrayInDia() {
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
// predict IOB out to DIA plus 30m
long time = new Date().getTime();
int len = (int) ((profile.getDia() *60 + 30) / 5);
IobTotal[] array = new IobTotal[len];
int pos = 0;
for (int i = 0; i < len; i++){
long t = time + i * 5 * 60000;
IobTotal iob = calulateFromTreatmentsAndTemps(t);
array[pos] = iob;
pos++;
}
return array;
}
public static JSONArray convertToJSONArray(IobTotal[] iobArray) {
JSONArray array = new JSONArray();
for (int i = 0; i < iobArray.length; i ++) {
array.put(iobArray[i].determineBasalJson());
}
return array;
}
}

View file

@ -1,9 +1,13 @@
package info.nightscout.androidaps.data;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.OpenAPSAMA.Autosens;
import info.nightscout.androidaps.plugins.OpenAPSAMA.AutosensResult;
import info.nightscout.client.data.NSProfile;
/**
@ -14,16 +18,24 @@ public class MealData {
public double carbs = 0d;
public double mealCOB = 0.0d; // TODO: add calculation for AMA
public void addTreatment(Treatment treatment) {
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
if (profile == null) return;
// TODO: not sure how much data do i need for AMA
List<BgReading> bgReadings = MainApp.getDbHelper().getDataFromTime((long) (new Date().getTime() - 60 * 60 * 1000L * profile.getDia() * 2), false);
long now = new Date().getTime();
long dia_ago = now - (new Double(profile.getDia() * 60 * 60 * 1000l)).longValue();
long t = treatment.created_at.getTime();
if (t > dia_ago && t <= now) {
if (treatment.carbs >= 1) {
carbs += treatment.carbs;
AutosensResult result = Autosens.detectSensitivityandCarbAbsorption(bgReadings, t);
double myCarbsAbsorbed = result.carbsAbsorbed;
double myMealCOB = Math.max(0, carbs - myCarbsAbsorbed);
mealCOB = Math.max(mealCOB, myMealCOB);
}
if (treatment.insulin > 0 && treatment.mealBolus) {
boluses += treatment.insulin;

View file

@ -183,12 +183,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return null;
}
public List<BgReading> getDataFromTime(long mills) {
public List<BgReading> getDataFromTime(long mills, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("timeIndex", true);
queryBuilder.orderBy("timeIndex", ascending);
Where where = queryBuilder.where();
where.ge("timeIndex", mills).and().gt("value", 38);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
@ -200,63 +200,4 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<BgReading>();
}
/*
* Returns glucose_status for openAPS or null if no actual data available
*/
@Nullable
public GlucoseStatus getGlucoseStatusData() {
GlucoseStatus result = new GlucoseStatus();
try {
Dao<BgReading, Long> daoBgreadings = null;
daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("timeIndex", false);
queryBuilder.where().gt("value", 38);
queryBuilder.limit(4l);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
int sizeRecords = bgReadings.size();
if (sizeRecords < 4 || bgReadings.get(sizeRecords - 4).timeIndex < new Date().getTime() - 7 * 60 * 1000L) {
return null;
}
double minutes = 5;
double change;
double avg;
if (bgReadings.size() > 3) {
BgReading now = bgReadings.get(sizeRecords - 4);
BgReading last = bgReadings.get(sizeRecords - 3);
BgReading last1 = bgReadings.get(sizeRecords - 2);
BgReading last2 = bgReadings.get(sizeRecords - 1);
if (last2.value > 38) {
minutes = (now.timeIndex - last2.timeIndex)/(60d*1000);
change = now.value - last2.value;
} else if (last1.value > 38) {
minutes = (now.timeIndex - last1.timeIndex)/(60d*1000);;
change = now.value - last1.value;
} else if (last.value > 38) {
minutes = (now.timeIndex - last.timeIndex)/(60d*1000);
change = now.value - last.value;
} else {
change = 0;
}
//multiply by 5 to get the same unit as delta, i.e. mg/dL/5m
avg = change / minutes * 5;
result.glucose = now.value;
result.delta = (now.value - last.value)*5*60*1000/(now.getTimeIndex() - last.getTimeIndex());
result.avgdelta = avg;
}
} catch (SQLException e) {
e.printStackTrace();
return null;
}
result.round();
return result;
}
}

View file

@ -11,6 +11,7 @@ import info.nightscout.androidaps.data.IobTotal;
public interface TempBasalsInterface {
void updateTotalIOB();
IobTotal getLastCalculation();
IobTotal getCalculationToTime(long time);
TempBasal getTempBasal (Date time);
TempBasal getExtendedBolus (Date time);

View file

@ -13,6 +13,7 @@ public interface TreatmentsInterface {
void updateTotalIOB();
IobTotal getLastCalculation();
IobTotal getCalculationToTime(long time);
MealData getMealData();
List<Treatment> getTreatments();
}

View file

@ -0,0 +1,225 @@
package info.nightscout.androidaps.plugins.OpenAPSAMA;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.Round;
public class Autosens {
private static Logger log = LoggerFactory.getLogger(Autosens.class);
public static AutosensResult detectSensitivityandCarbAbsorption(List<BgReading> glucose_data, long mealTime) {
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
//console.error(mealTime);
double deviationSum = 0;
double carbsAbsorbed = 0;
List<BgReading> bucketed_data = new ArrayList<>();
bucketed_data.add(glucose_data.get(0));
int j = 0;
for (int i = 1; i < glucose_data.size(); ++i) {
long bgTime = glucose_data.get(i).getTimeIndex();
long lastbgTime = glucose_data.get(i - 1).getTimeIndex();
if (glucose_data.get(i).value < 39 || glucose_data.get(i - 1).value < 39) {
continue;
}
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
if (Math.abs(elapsed_minutes) > 8) {
// interpolate missing data points
double lastbg = glucose_data.get(i - 1).value;
elapsed_minutes = Math.abs(elapsed_minutes);
//console.error(elapsed_minutes);
long nextbgTime;
while (elapsed_minutes > 5) {
nextbgTime = lastbgTime + 5 * 60 * 1000;
j++;
BgReading newBgreading = new BgReading();
newBgreading.timeIndex = nextbgTime;
double gapDelta = glucose_data.get(i).value - lastbg;
//console.error(gapDelta, lastbg, elapsed_minutes);
double nextbg = lastbg + (5 / elapsed_minutes * gapDelta);
newBgreading.value = Math.round(nextbg);
//console.error("Interpolated", bucketed_data[j]);
bucketed_data.add(newBgreading);
elapsed_minutes = elapsed_minutes - 5;
lastbg = nextbg;
lastbgTime = nextbgTime;
}
} else if (Math.abs(elapsed_minutes) > 2) {
j++;
BgReading newBgreading = new BgReading();
newBgreading.value = glucose_data.get(i).value;
newBgreading.timeIndex = bgTime;
bucketed_data.add(newBgreading);
} else {
bucketed_data.get(j).value = (bucketed_data.get(j).value + glucose_data.get(i).value) / 2;
}
}
//console.error(bucketed_data);
double[] avgDeltas = new double[bucketed_data.size() - 2];
double[] bgis = new double[bucketed_data.size() - 2];
double[] deviations = new double[bucketed_data.size() - 2];
String debugString = "";
for (int i = 0; i < bucketed_data.size() - 3; ++i) {
long bgTime = bucketed_data.get(i).timeIndex;
int secondsFromMidnight = NSProfile.secondsFromMidnight(new Date(bgTime));
double sens = profile.getIsf(secondsFromMidnight);
//console.error(bgTime , bucketed_data[i].glucose);
double bg;
double avgDelta;
double delta;
bg = bucketed_data.get(i).value;
if (bg < 40 || bucketed_data.get(i + 3).value < 40) {
log.error("! value < 40");
continue;
}
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
delta = (bg - bucketed_data.get(i + 1).value);
// avgDelta = avgDelta.toFixed(2);
IobTotal iob = IobTotal.calulateFromTreatmentsAndTemps(bgTime);
double bgi = Math.round((-iob.activity * sens * 5) * 100) / 100;
// bgi = bgi.toFixed(2);
//console.error(delta);
double deviation = delta - bgi;
// deviation = deviation.toFixed(2);
//if (deviation < 0 && deviation > -2) { console.error("BG: "+bg+", avgDelta: "+avgDelta+", BGI: "+bgi+", deviation: "+deviation); }
// Exclude large positive deviations (carb absorption) from autosens
if (avgDelta - bgi < 6) {
if (deviation > 0) {
debugString += "+";
} else if (deviation == 0) {
debugString += "=";
} else {
debugString += "-";
}
avgDeltas[i] = avgDelta;
bgis[i] = bgi;
deviations[i] = deviation;
deviationSum += deviation;
} else {
debugString += ">";
//console.error(bgTime);
}
// if bgTime is more recent than mealTime
if (bgTime > mealTime) {
// figure out how many carbs that represents
// but always assume at least 3mg/dL/5m (default) absorption
double ci = Math.max(deviation, Constants.MIN_5M_CARBIMPACT);
double absorbed = ci * profile.getIc(secondsFromMidnight) / sens;
// and add that to the running total carbsAbsorbed
carbsAbsorbed += absorbed;
}
}
//console.error("");
log.debug(debugString);
//console.log(JSON.stringify(avgDeltas));
//console.log(JSON.stringify(bgis));
Arrays.sort(avgDeltas);
Arrays.sort(bgis);
Arrays.sort(deviations);
for (double i = 0.9; i > 0.1; i = i - 0.02) {
//console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2));
if (percentile(deviations, (i + 0.02)) >= 0 && percentile(deviations, i) < 0) {
//console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2));
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (target 45%-50%)");
}
}
double pSensitive = percentile(deviations, 0.50);
double pResistant = percentile(deviations, 0.45);
//p30 = percentile(deviations, 0.3);
// average = deviationSum / deviations.length;
//console.error("Mean deviation: "+average.toFixed(2));
double basalOff = 0;
if (pSensitive < 0) { // sensitive
basalOff = pSensitive * (60 / 5) / profile.getIsf(NSProfile.secondsFromMidnight());
log.debug("Excess insulin sensitivity detected: ");
} else if (pResistant > 0) { // resistant
basalOff = pResistant * (60 / 5) / profile.getIsf(NSProfile.secondsFromMidnight());
log.debug("Excess insulin resistance detected: ");
} else {
log.debug("Sensitivity normal.");
}
double ratio = 1 + (basalOff / profile.getMaxDailyBasal());
// don't adjust more than 1.5x
double rawRatio = ratio;
ratio = Math.max(ratio, Constants.AUTOSENS_MIN);
ratio = Math.min(ratio, Constants.AUTOSENS_MAX);
if (ratio != rawRatio) {
log.debug("Ratio limited from " + rawRatio + " to " + ratio);
}
double newisf = Math.round(profile.getIsf(NSProfile.secondsFromMidnight()) / ratio);
if (ratio != 1) {
log.debug("ISF adjusted from " + profile.getIsf(NSProfile.secondsFromMidnight()) + " to " + newisf);
}
//console.error("Basal adjustment "+basalOff.toFixed(2)+"U/hr");
//console.error("Ratio: "+ratio*100+"%: new ISF: "+newisf.toFixed(1)+"mg/dL/U");
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
output.carbsAbsorbed = Round.roundTo(carbsAbsorbed, 0.01);
return output;
}
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
// Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method
public static double percentile(double[] arr, double p) {
if (arr.length == 0) return 0;
if (p <= 0) return arr[0];
if (p >= 1) return arr[arr.length - 1];
double index = arr.length * p,
lower = Math.floor(index),
upper = lower + 1,
weight = index % 1;
if (upper >= arr.length) return arr[(int) lower];
return arr[(int) lower] * (1 - weight) + arr[(int) upper] * weight;
}
// Returns the percentile of the given value in a sorted numeric array.
public static double percentRank(double[] arr, double v) {
for (int i = 0, l = arr.length; i < l; i++) {
if (v <= arr[i]) {
while (i < l && v == arr[i]) i++;
if (i == 0) return 0;
if (v != arr[i - 1]) {
i += (v - arr[i - 1]) / (arr[i] - arr[i - 1]);
}
return i / l;
}
}
return 1;
}
}

View file

@ -0,0 +1,9 @@
package info.nightscout.androidaps.plugins.OpenAPSAMA;
/**
* Created by mike on 06.01.2017.
*/
public class AutosensResult {
public double ratio;
public double carbsAbsorbed;
}

View file

@ -13,9 +13,13 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.GlucoseStatus;
import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.client.data.NSProfile;
@ -28,10 +32,10 @@ public class DetermineBasalAdapterAMAJS {
V8 mV8rt;
private V8Object mProfile;
private V8Object mGlucoseStatus;
private V8Object mIobData;
private V8Array mIobData;
private V8Object mMealData;
private V8Object mCurrentTemp;
private V8Object mAutosensData = null;
private V8Object mAutosensData;
private final String PARAM_currentTemp = "currentTemp";
private final String PARAM_iobData = "iobData";
@ -73,8 +77,14 @@ public class DetermineBasalAdapterAMAJS {
mProfile.add("max_basal", 0);
mProfile.add("max_bg", 0);
mProfile.add("min_bg", 0);
mProfile.add("carbratio", 0);
mProfile.add("carb_ratio", 0);
mProfile.add("sens", 0);
mProfile.add("max_daily_safety_multiplier", Constants.MAX_DAILY_SAFETY_MULTIPLIER);
mProfile.add("current_basal_safety_multiplier", Constants.CURRENT_BASAL_SAFETY_MULTIPLIER);
mProfile.add("skip_neutral_temps", true);
mProfile.add("temptargetSet", false);
mProfile.add("autosens_adjust_targets", false);
mProfile.add("min_5m_carbimpact", 0);
mProfile.add("current_basal", 0);
mV8rt.add(PARAM_profile, mProfile);
// Current temp
@ -84,14 +94,8 @@ public class DetermineBasalAdapterAMAJS {
mCurrentTemp.add("rate", 0);
mV8rt.add(PARAM_currentTemp, mCurrentTemp);
// IOB data
mIobData = new V8Object(mV8rt);
mIobData.add("iob", 0); //netIob
mIobData.add("activity", 0); //netActivity
mIobData.add("bolussnooze", 0); //bolusIob
mIobData.add("basaliob", 0);
mIobData.add("netbasalinsulin", 0);
mIobData.add("hightempinsulin", 0);
mV8rt.add(PARAM_iobData, mIobData);
// mIobData = new V8Array(mV8rt);
// mV8rt.add(PARAM_iobData, mIobData);
// Glucose status
mGlucoseStatus = new V8Object(mV8rt);
mGlucoseStatus.add("glucose", 0);
@ -105,7 +109,9 @@ public class DetermineBasalAdapterAMAJS {
mMealData.add("mealCOB", 0.0d);
mV8rt.add(PARAM_meal_data, mMealData);
// Autosens data
mV8rt.executeVoidScript("autosens_data = undefined");
mAutosensData = new V8Object(mV8rt);
mMealData.add("ratio", 0.0d);
mV8rt.add(PARAM_autosens_data, mAutosensData);
}
public DetermineBasalResultAMA invoke() {
@ -149,8 +155,7 @@ public class DetermineBasalAdapterAMAJS {
storedCurrentTemp = mV8rt.executeStringScript("JSON.stringify(" + PARAM_currentTemp + ");");
storedProfile = mV8rt.executeStringScript("JSON.stringify(" + PARAM_profile + ");");
storedMeal_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_meal_data + ");");
if (mAutosensData != null)
storedAutosens_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_autosens_data + ");");
storedAutosens_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_autosens_data + ");");
return result;
}
@ -225,11 +230,15 @@ public class DetermineBasalAdapterAMAJS {
JavaVoidCallback callbackLog = new JavaVoidCallback() {
@Override
public void invoke(V8Object arg0, V8Array parameters) {
if (parameters.length() > 0) {
Object arg1 = parameters.get(0);
if (Config.logAPSResult)
log.debug("Input params: " + arg1);
int i = 0;
String s = "";
while (i < parameters.length()) {
Object arg = parameters.get(i);
s += arg + " ";
i++;
}
if (!s.equals("") && Config.logAPSResult)
log.debug("Script debug: " + s);
}
};
mV8rt.registerJavaMethod(callbackLog, "log");
@ -244,10 +253,12 @@ public class DetermineBasalAdapterAMAJS {
double maxBg,
double targetBg,
PumpInterface pump,
IobTotal iobData,
IobTotal[] iobArray,
GlucoseStatus glucoseStatus,
MealData mealData,
JSONObject autosensData) {
double autosensDataRatio,
boolean tempTargetSet,
double min_5m_carbimpact) {
String units = profile.getUnits();
@ -260,23 +271,21 @@ public class DetermineBasalAdapterAMAJS {
mProfile.add("min_bg", minBg);
mProfile.add("max_bg", maxBg);
mProfile.add("target_bg", targetBg);
mProfile.add("carbratio", profile.getIc(profile.secondsFromMidnight()));
mProfile.add("carb_ratio", profile.getIc(profile.secondsFromMidnight()));
mProfile.add("sens", NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()).doubleValue(), units));
mProfile.add("current_basal", pump.getBaseBasalRate());
mProfile.add("temptargetSet", tempTargetSet);
mProfile.add("autosens_adjust_targets", MainApp.getConfigBuilder().isAMAModeEnabled());
mProfile.add("min_5m_carbimpact", min_5m_carbimpact);
mCurrentTemp.add("duration", pump.getTempBasalRemainingMinutes());
mCurrentTemp.add("rate", pump.getTempBasalAbsoluteRate());
mIobData.add("iob", iobData.iob); //netIob
mIobData.add("activity", iobData.activity); //netActivity
mIobData.add("bolussnooze", iobData.bolussnooze); //bolusIob
mIobData.add("basaliob", iobData.basaliob);
mIobData.add("netbasalinsulin", iobData.netbasalinsulin);
mIobData.add("hightempinsulin", iobData.hightempinsulin);
mIobData = mV8rt.executeArrayScript(IobTotal.convertToJSONArray(iobArray).toString());
mV8rt.add(PARAM_iobData, mIobData);
mGlucoseStatus.add("glucose", glucoseStatus.glucose);
mGlucoseStatus.add("delta", glucoseStatus.delta);
mGlucoseStatus.add("avgdelta", glucoseStatus.avgdelta);
mGlucoseStatus.add("short_avgdelta", glucoseStatus.short_avgdelta);
mGlucoseStatus.add("long_avgdelta", glucoseStatus.long_avgdelta);
@ -284,12 +293,7 @@ public class DetermineBasalAdapterAMAJS {
mMealData.add("boluses", mealData.boluses);
mMealData.add("mealCOB", mealData.mealCOB);
if (autosensData != null) {
mAutosensData = new V8Object(mV8rt);
// TODO: add autosens data here for AMA
} else {
mV8rt.executeVoidScript("autosens_data = undefined");
}
mAutosensData.add("ratio", autosensDataRatio);
}

View file

@ -11,6 +11,8 @@ import android.widget.TextView;
import com.squareup.otto.Subscribe;
import org.json.JSONArray;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -110,7 +112,13 @@ public class OpenAPSAMAFragment extends Fragment implements View.OnClickListener
if (determineBasalAdapterAMAJS != null) {
glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getGlucoseStatusParam()));
currentTempView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getCurrentTempParam()));
iobDataView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getIobDataParam()));
try {
JSONArray iobArray = new JSONArray(determineBasalAdapterAMAJS.getIobDataParam());
iobDataView.setText(String.format(MainApp.sResources.getString(R.string.array_of_elements), iobArray.length()) + "\n" + JSONFormatter.format(iobArray.getString(0)));
} catch (JSONException e) {
e.printStackTrace();
iobDataView.setText("JSONException");
}
profileView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getProfileParam()));
mealDataView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getMealDataParam()));
}

View file

@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
@ -16,6 +17,7 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseStatus;
import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface;
@ -107,7 +109,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
return;
}
GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
PumpInterface pump = MainApp.getConfigBuilder();
@ -162,16 +164,9 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
minBg = Round.roundTo(minBg, 0.1d);
maxBg = Round.roundTo(maxBg, 0.1d);
TreatmentsInterface treatments = MainApp.getConfigBuilder().getActiveTreatments();
TempBasalsInterface tempBasals = MainApp.getConfigBuilder().getActiveTempBasals();
treatments.updateTotalIOB();
tempBasals.updateTotalIOB();
IobTotal bolusIob = treatments.getLastCalculation();
IobTotal basalIob = tempBasals.getLastCalculation();
IobTotal[] iobArray = IobTotal.calculateIobArrayInDia();
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
MealData mealData = treatments.getMealData();
MealData mealData = MainApp.getConfigBuilder().getActiveTreatments().getMealData();
maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob);
@ -188,7 +183,14 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, 10)) return;
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, 5)) return;
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobTotal, glucoseStatus, mealData, null);
List<BgReading> bgReadings = MainApp.getDbHelper().getDataFromTime((long) (new Date().getTime() - 60 * 60 * 1000L * (24 + profile.getDia())), false);
AutosensResult autosensResult = Autosens.detectSensitivityandCarbAbsorption(bgReadings, new Date().getTime());
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobArray, glucoseStatus, mealData,
autosensResult.ratio, //autosensDataRatio
false, // isTempTargetSet TODO: add when we start handling temp targets
Constants.MIN_5M_CARBIMPACT //min_5m_carbimpact
);
DetermineBasalResultAMA determineBasalResultAMA = determineBasalAdapterAMAJS.invoke();
@ -203,7 +205,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
determineBasalResultAMA.changeRequested = false;
}
determineBasalResultAMA.iob = iobTotal;
determineBasalResultAMA.iob = iobArray[0];
determineBasalAdapterAMAJS.release();

View file

@ -107,7 +107,7 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
return;
}
GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
PumpInterface pump = MainApp.getConfigBuilder();

View file

@ -513,8 +513,8 @@ public class OverviewFragment extends Fragment {
acceptTempLayout.setVisibility(View.GONE);
}
TempBasal activeTemp = pump.getTempBasal();
if (pump.isTempBasalInProgress()) {
TempBasal activeTemp = pump.getTempBasal();
cancelTempLayout.setVisibility(View.VISIBLE);
cancelTempButton.setText(MainApp.instance().getString(R.string.cancel) + ": " + activeTemp.toString());
runningTempView.setVisibility(View.VISIBLE);
@ -578,7 +578,7 @@ public class OverviewFragment extends Fragment {
if (lastBG != null && bgView != null) {
bgView.setText(lastBG.valueToUnitsToString(profile.getUnits()));
arrowView.setText(lastBG.directionToSymbol());
GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (glucoseStatus != null){
deltaView.setText("Δ " + NSProfile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units);
avgdeltaView.setText("øΔ " + NSProfile.toUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units) + " " + units);
@ -708,7 +708,7 @@ public class OverviewFragment extends Fragment {
bgGraph.getGridLabelRenderer().setNumHorizontalLabels(7); // only 7 because of the space
// **** BG graph ****
List<BgReading> bgReadingsArray = MainApp.getDbHelper().getDataFromTime(fromTime);
List<BgReading> bgReadingsArray = MainApp.getDbHelper().getDataFromTime(fromTime, true);
List<BgReading> inRangeArray = new ArrayList<BgReading>();
List<BgReading> outOfRangeArray = new ArrayList<BgReading>();

View file

@ -97,8 +97,8 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
if (profile == null) return absoluteRate;
if (absoluteRate < 0) absoluteRate = 0d;
Integer maxBasalMult = 4;
Integer maxBasalFromDaily = 3;
Integer maxBasalMult = Constants.CURRENT_BASAL_SAFETY_MULTIPLIER;
Integer maxBasalFromDaily = Constants.MAX_DAILY_SAFETY_MULTIPLIER;
// Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate;
if (absoluteRate > maxBasal) {
@ -136,8 +136,8 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
if (absoluteRate < 0) absoluteRate = 0d;
Integer maxBasalMult = 4;
Integer maxBasalFromDaily = 3;
Integer maxBasalMult = Constants.CURRENT_BASAL_SAFETY_MULTIPLIER;
Integer maxBasalFromDaily = Constants.MAX_DAILY_SAFETY_MULTIPLIER;
// Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate;
if (absoluteRate > maxBasal) {

View file

@ -213,7 +213,7 @@ public class SmsCommunicatorPlugin implements PluginBase {
} else if (lastBG != null) {
reply = MainApp.sResources.getString(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(MainApp.sResources.getString(R.string.sms_minago), agoMin) + ", ";
}
GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (glucoseStatus != null)
reply += MainApp.sResources.getString(R.string.sms_delta) + " " + NSProfile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", ";

View file

@ -197,10 +197,10 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
}
@Override
public void updateTotalIOB() {
public IobTotal getCalculationToTime(long time) {
checkForExpired(tempBasals);
checkForExpired(extendedBoluses);
Date now = new Date();
Date now = new Date(time);
IobTotal total = new IobTotal();
for (Integer pos = 0; pos < tempBasals.size(); pos++) {
TempBasal t = tempBasals.get(pos);
@ -214,6 +214,13 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
total.plus(calc);
}
}
return total;
}
@Override
public void updateTotalIOB() {
IobTotal total = getCalculationToTime(new Date().getTime());
lastCalculationTimestamp = new Date().getTime();
lastCalculation = total;
}

View file

@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
@ -22,6 +23,7 @@ import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.client.data.NSProfile;
/**
@ -112,28 +114,32 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
}
@Override
public void updateTotalIOB() {
public IobTotal getCalculationToTime(long time) {
IobTotal total = new IobTotal();
if (MainApp.getConfigBuilder() == null || MainApp.getConfigBuilder().getActiveProfile() == null) // app not initialized yet
return;
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
if (profile == null) {
lastCalculation = total;
return;
}
if (MainApp.getConfigBuilder() == null || ConfigBuilderPlugin.getActiveProfile() == null) // app not initialized yet
return total;
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
if (profile == null)
return total;
Double dia = profile.getDia();
Date now = new Date();
Date now = new Date(time);
for (Integer pos = 0; pos < treatments.size(); pos++) {
Treatment t = treatments.get(pos);
Iob tIOB = t.iobCalc(now, dia);
total.iob += tIOB.iobContrib;
total.activity += tIOB.activityContrib;
Iob bIOB = t.iobCalc(now, dia / 2);
Iob bIOB = t.iobCalc(now, dia / Constants.BOLUSSNOOZE_DIA_ADVISOR);
total.bolussnooze += bIOB.iobContrib;
}
return total;
}
@Override
public void updateTotalIOB() {
IobTotal total = getCalculationToTime(new Date().getTime());
lastCalculationTimestamp = new Date().getTime();
lastCalculation = total;

View file

@ -144,7 +144,7 @@ public class WatchUpdaterService extends WearableListenerService implements
BgReading lastBG = MainApp.getDbHelper().lastBg();
if (lastBG != null) {
GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); }
if (wear_integration) {
@ -254,8 +254,8 @@ public class WatchUpdaterService extends WearableListenerService implements
if (last_bg == null) return;
List<BgReading> graph_bgs = MainApp.getDbHelper().getDataFromTime(startTime);
GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
List<BgReading> graph_bgs = MainApp.getDbHelper().getDataFromTime(startTime, true);
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (!graph_bgs.isEmpty()) {
DataMap entries = dataMapSingleBG(last_bg, glucoseStatus);

View file

@ -102,7 +102,7 @@ public class PersistentNotificationPlugin implements PluginBase{
BgReading lastBG = MainApp.getDbHelper().lastBg();
GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if(profile != null && lastBG != null) {
line1 = lastBG.valueToUnitsToString(profile.getUnits());

View file

@ -17,7 +17,10 @@ public class JSONFormatter {
public static Spanned format(final String jsonString) {
final JsonVisitor visitor = new JsonVisitor(4, ' ');
try {
return Html.fromHtml(visitor.visit(new JSONObject(jsonString), 0));
if (jsonString.getBytes()[0] == '[')
return Html.fromHtml(visitor.visit(new JSONArray(jsonString), 0));
else
return Html.fromHtml(visitor.visit(new JSONObject(jsonString), 0));
} catch (JSONException e) {
e.printStackTrace();
return Html.fromHtml("");

View file

@ -398,4 +398,7 @@
<string name="sms_minago">%dmin ago</string>
<string name="localprofile">Local Profile</string>
<string name="openapsama">OpenAPS AMA</string>
<string name="short_avgdelta">Short avg. delta</string>
<string name="long_avgdelta">Long avg. delta</string>
<string name="array_of_elements">Array of %d elements.\nActual value:</string>
</resources>