Skip to content

Commit

Permalink
DisplayGlucose methods and noise improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
jamorham committed Nov 13, 2016
1 parent 6c883df commit 4c9cb7b
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 36 deletions.
94 changes: 78 additions & 16 deletions app/src/main/java/com/eveningoutpost/dexdrip/BestGlucose.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.eveningoutpost.dexdrip;

import android.content.SharedPreferences;
import android.graphics.Color;
import android.preference.PreferenceManager;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.util.Log;

import com.eveningoutpost.dexdrip.Models.BgReading;
Expand All @@ -28,22 +32,31 @@
public class BestGlucose {

final static String TAG = "BestGlucose";
final static boolean d = true; // debug flag
private static SharedPreferences prefs;

public static class DisplayGlucose {
public double mgdl = -1;
public double delta_mgdl = 0;
public int warning = -1;
private Boolean stale = null;
private Double highMark = null;
private Double lowMark = null;

public double mgdl = -1; // displayable mgdl figure
public double unitized_value = -1; // in local units
public double delta_mgdl = 0; // displayable delta mgdl figure
public int warning = -1; // warning level
public long mssince = -1;
public long timestamp = -1;
public boolean stale = true;
public long timestamp = -1; // timestamp of reading
public String unitized = "void";
public String unitized_delta = "";
public String unitized_delta_no_units = "";
public String delta_arrow = "";
public String delta_arrow = ""; // unicode delta arrow
public String delta_name = "";
public String extra_string = "";
public String plugin_name = "";
public boolean from_plugin = false;
public String plugin_name = ""; // plugin which generated this data
public boolean from_plugin = false; // whether a plugin was used


// Display getters - built in caching where appropriate

public String minutesAgo() {
return minutesAgo(false);
Expand All @@ -54,6 +67,53 @@ public String minutesAgo(boolean include_words) {
return Integer.toString(minutes) + (include_words ? (((minutes == 1) ? xdrip.getAppContext().getString(R.string.space_minute_ago) : xdrip.getAppContext().getString(R.string.space_minutes_ago))) : "");
}

// return boolean if data would be considered stale
public boolean isStale() {
if (this.stale == null) {
this.stale = this.mssince > Home.stale_data_millis();
}
return this.stale;
}

// is this value above the "High" preference value
public boolean isHigh() {
if (this.highMark == null)
this.highMark = JoH.tolerantParseDouble(prefs.getString("highValue", "170"));
return this.unitized_value >= this.highMark;
}

// is this value below the "Low" preference value
public boolean isLow() {
if (this.lowMark == null)
this.lowMark = JoH.tolerantParseDouble(prefs.getString("lowValue", "70"));
return this.unitized_value <= this.lowMark;
}

// return strikeout string if data is high/low / stale
public SpannableString spannableString(String str) {
return spannableString(str, false);
}

// return a coloured strikeout string based on boolean
public SpannableString spannableString(String str, boolean color) {
final SpannableString ret = new SpannableString((str != null) ? str : "");
if (isStale()) wholeSpan(ret, new StrikethroughSpan());
if (color) {
if (isLow()) {
// TODO should colors be configurable?
wholeSpan(ret, new ForegroundColorSpan(Color.parseColor("#C30909")));
} else if (isHigh()) {
wholeSpan(ret, new ForegroundColorSpan(Color.parseColor("#FFBB33")));
} // else default to whatever default is?
}
return ret;
}

// set the whole spannable string to whatever this span is
private void wholeSpan(SpannableString ret, Object what) {
ret.setSpan(what, 0, ret.length(), 0);
}

}

// note we don't support the original depreciated "predictive" mode
Expand All @@ -63,13 +123,16 @@ public String minutesAgo(boolean include_words) {
// TODO internalize delta handling to handle irregular periods and missing data plugins etc
// TODO see getSlopeArrowSymbolBeforeCalibration for calculation method for arbitary slope
// TODO option to process noise or not
// TODO check what happens if there is only a single entry, especially regarding delta


public static DisplayGlucose getDisplayGlucose() {

final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(xdrip.getAppContext());
if (prefs == null)
prefs = PreferenceManager.getDefaultSharedPreferences(xdrip.getAppContext());
final DisplayGlucose dg = new DisplayGlucose(); // return value
final boolean doMgdl = (prefs.getString("units", "mgdl").equals("mgdl"));
final boolean is_follower = Home.get_follower();
final DisplayGlucose dg = new DisplayGlucose(); // return value

List<BgReading> last_2 = BgReading.latest(2);

Expand Down Expand Up @@ -99,8 +162,6 @@ public static DisplayGlucose getDisplayGlucose() {
dg.mssince = JoH.msSince(lastBgReading.timestamp);

dg.timestamp = lastBgReading.timestamp;
// TODO set stale or use getter maybe
dg.stale = dg.mssince > Home.stale_data_millis();

// if we are actively using a plugin, get the glucose calculation from there
if ((plugin != null) && ((pcalibration = plugin.getCalibrationData()) != null) && (Home.getPreferencesBoolean("display_glucose_from_plugin", false))) {
Expand All @@ -125,6 +186,7 @@ public static DisplayGlucose getDisplayGlucose() {
double estimated_delta = 0;

// TODO refresh bggraph if needed based on cache - observe
BgGraphBuilder.refreshNoiseIfOlderThan(dg.timestamp); // should this be conditional on whether bg_compensate_noise is set?

boolean bg_from_filtered = prefs.getBoolean("bg_from_filtered", false);
// if noise has settled down then switch off filtered mode
Expand Down Expand Up @@ -166,7 +228,7 @@ public static DisplayGlucose getDisplayGlucose() {
//slope_arrow = lastBgReading.slopeArrow(); // internalize this for plugins
double slope = calculateSlope(estimate, timestamp, previous_estimate, previous_timestamp);
slope_arrow = BgReading.slopeToArrowSymbol(slope * 60000); // slope by minute
slope_name = BgReading.slopeName(slope*60000);
slope_name = BgReading.slopeName(slope * 60000);
Log.d(TAG, "No noise option slope by minute: " + (slope * 60000));
}

Expand All @@ -176,8 +238,7 @@ public static DisplayGlucose getDisplayGlucose() {
warning_level = 2;
}



dg.unitized_value = BgGraphBuilder.unitized(estimate, doMgdl);
final String stringEstimate = BgGraphBuilder.unitized_string(estimate, doMgdl);
if ((lastBgReading.hide_slope) || (bg_from_filtered)) {
slope_arrow = "";
Expand All @@ -192,7 +253,8 @@ public static DisplayGlucose getDisplayGlucose() {
dg.extra_string = extrastring;
dg.delta_name = slope_name;

Log.d(TAG, "dg result: " + dg.unitized);
if (d)
Log.d(TAG, "dg result: " + dg.unitized + " previous: " + BgGraphBuilder.unitized_string(previous_estimate, doMgdl));
return dg;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public class BgGraphBuilder {
public static double low_occurs_at = -1;
public static double previous_low_occurs_at = -1;
private static double low_occurs_at_processed_till_timestamp = -1;
private static long noise_processed_till_timestamp = -1;
private final static String TAG = "jamorham graph";
//private final static int pluginColor = Color.parseColor("#AA00FFFF"); // temporary

Expand Down Expand Up @@ -157,6 +158,7 @@ public class BgGraphBuilder {
private final List<PointValue> noisePolyBgValues = new ArrayList<PointValue>();
private final List<PointValue> activityValues = new ArrayList<PointValue>();
private final List<PointValue> annotationValues = new ArrayList<>();
private static TrendLine noisePoly;
public static double last_noise = -99999;
public static double original_value = -99999;
public static double best_bg_estimate = -99999;
Expand Down Expand Up @@ -203,7 +205,6 @@ public BgGraphBuilder(Context context, long start, long end, int numValues, bool

if ((end - start) > 80000000) {
try {
// TODO something about this means it never seems to get to 100% maybe int rounding or timing related.
capturePercentage = ((bgReadings.size() * 100) / ((end - start) / 300000));
//Log.d(TAG, "CPTIMEPERIOD: " + Long.toString(end - start) + " percentage: " + JoH.qs(capturePercentage));
} catch (Exception e) {
Expand Down Expand Up @@ -831,7 +832,7 @@ private synchronized void addBgReadingValues(final boolean simple) {

final double bgScale = bgScale();
final double now = JoH.ts();
long highest_bgreading_timestamp = -1;
long highest_bgreading_timestamp = -1; // most recent bgreading timestamp we have
double trend_start_working = now - (1000 * 60 * 12); // 10 minutes // TODO MAKE PREFERENCE?
if (bgReadings.size() > 0) {
highest_bgreading_timestamp = bgReadings.get(0).timestamp;
Expand All @@ -847,7 +848,7 @@ private synchronized void addBgReadingValues(final boolean simple) {
double oldest_noise_timestamp = now;
double newest_noise_timestamp = 0;
TrendLine[] polys = new TrendLine[5];
TrendLine noisePoly = new PolyTrendLine(2);

polys[0] = new PolyTrendLine(1);
// polys[1] = new PolyTrendLine(2);
polys[1] = new Forecast.LogTrendLine();
Expand Down Expand Up @@ -949,7 +950,7 @@ private synchronized void addBgReadingValues(final boolean simple) {
}

// noise calculator
if (!simple && (bgReading.timestamp > noise_trendstart) && (bgReading.timestamp > last_calibration)) {
if ((!simple || (noise_processed_till_timestamp < highest_bgreading_timestamp)) && (bgReading.timestamp > noise_trendstart) && (bgReading.timestamp > last_calibration)) {
if (has_filtered && (bgReading.filtered_calculated_value > 0) && (bgReading.filtered_calculated_value != bgReading.calculated_value)) {
final double shifted_timestamp = bgReading.timestamp - timeshift;

Expand Down Expand Up @@ -1001,13 +1002,16 @@ private synchronized void addBgReadingValues(final boolean simple) {
}


if (!simple) {
// always calculate noise if needed
if (noise_processed_till_timestamp < highest_bgreading_timestamp) {
// noise evaluate
try {
Log.d(TAG, "Noise: Processing new data for noise: " + JoH.dateTimeText(noise_processed_till_timestamp) + " vs now: " + JoH.dateTimeText(highest_bgreading_timestamp));

try {
if (d) Log.d(TAG, "noise Poly list size: " + noise_polyxList.size());
// TODO Impossible to satisfy noise evaluation size with only raw data do we want it with raw only??
if (noise_polyxList.size() > 5) {
noisePoly = new PolyTrendLine(2);
final double[] noise_polyys = PolyTrendLine.toPrimitiveFromList(noise_polyyList);
final double[] noise_polyxs = PolyTrendLine.toPrimitiveFromList(noise_polyxList);
noisePoly.setValues(noise_polyys, noise_polyxs);
Expand All @@ -1019,18 +1023,23 @@ private synchronized void addBgReadingValues(final boolean simple) {
best_bg_estimate = -99;
last_bg_estimate = -99;
}
Log.i(TAG, "Noise Poly Error Varience: " + JoH.qs(last_noise, 5));
Log.i(TAG, "Noise: Poly Error Varience: " + JoH.qs(last_noise, 5));
} else {
Log.i(TAG, "Not enough data to get sensible noise value");
Log.i(TAG, "Noise: Not enough data to get sensible noise value");
noisePoly = null;
last_noise = -9999;
best_bg_estimate = -9999;
last_bg_estimate = -9999;
}
noise_processed_till_timestamp = highest_bgreading_timestamp; // store that we have processed up to this timestamp
} catch (Exception e) {
Log.e(TAG, " Error with noise poly trend: " + e.toString());
}
} else {
Log.d(TAG, "Noise Cached noise timestamp: " + JoH.dateTimeText(noise_processed_till_timestamp));
}

if (!simple) {
// momentum
try {
if (d) Log.d(TAG, "moment Poly list size: " + polyxList.size());
Expand Down Expand Up @@ -1414,6 +1423,14 @@ public static synchronized double getCurrentLowOccursAt() {
return low_occurs_at;
}

public static synchronized void refreshNoiseIfOlderThan(long timestamp) {
if (noise_processed_till_timestamp < timestamp) {
Log.d(TAG, "Refreshing Noise as Older: " + JoH.dateTimeText((long) noise_processed_till_timestamp) + " vs " + JoH.dateTimeText(timestamp));
// new only the last hour worth of data for this, simple mode should work for this calculation
(new BgGraphBuilder(xdrip.getAppContext(), System.currentTimeMillis() - 60 * 60 * 1000, System.currentTimeMillis() + 5 * 60 * 1000, 24, true)).addBgReadingValues(true);
}
}

public Line avg1Line() {
List<PointValue> myLineValues = new ArrayList<PointValue>();
myLineValues.add(new PointValue((float) avg1startfuzzed, (float) unitized(avg1value)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,8 @@ public synchronized Notification createOngoingNotification(BgGraphBuilder bgGrap
//b.setOngoing(true);
b.setCategory(NotificationCompat.CATEGORY_STATUS);
final BestGlucose.DisplayGlucose dg = (use_best_glucose) ? BestGlucose.getDisplayGlucose() : null;
final SpannableString titleString = new SpannableString(lastReading == null ? "BG Reading Unavailable" : (dg != null) ? dg.unitized + " " + dg.delta_arrow
final boolean use_color_in_notification = false; // could be preference option
final SpannableString titleString = new SpannableString(lastReading == null ? "BG Reading Unavailable" : (dg != null) ? (dg.spannableString(dg.unitized + " " + dg.delta_arrow,use_color_in_notification))
: (lastReading.displayValue(mContext) + " " + lastReading.slopeArrow()));
b.setContentTitle(titleString)
.setContentText("xDrip Data collection service is running.")
Expand All @@ -555,14 +556,9 @@ public synchronized Notification createOngoingNotification(BgGraphBuilder bgGrap
if (lastReading != null) {

b.setWhen(lastReading.timestamp);
final SpannableString deltaString = new SpannableString("Delta: " + ((dg != null) ? dg.unitized_delta + (dg.from_plugin ? " "+context.getString(R.string.p_in_circle) : "")
final SpannableString deltaString = new SpannableString("Delta: " + ((dg != null) ? (dg.spannableString(dg.unitized_delta + (dg.from_plugin ? " "+context.getString(R.string.p_in_circle) : "")))
: bgGraphBuilder.unitizedDeltaString(true, true)));

if ((dg != null) && (dg.stale)) {
deltaString.setSpan(new StrikethroughSpan(), 0, deltaString.length(), 0);
titleString.setSpan(new StrikethroughSpan(), 0, titleString.length(), 0); // reference updatable
}

b.setContentText(deltaString);
iconBitmap = new BgSparklineBuilder(mContext)
.setHeight(64)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.eveningoutpost.dexdrip.utils.DexCollectionType;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.eveningoutpost.dexdrip.UtilityModels.ColorCache.getCol;

/**
Expand Down Expand Up @@ -144,6 +143,7 @@ public void onDreamingStarted() {
}

mBouncer.addView(inflatedLayout, new FrameLayout.LayoutParams(widget_width, widget_height));

setContentView(mBouncer);

}
Expand All @@ -161,10 +161,9 @@ private long updateData() {
final BestGlucose.DisplayGlucose dg = BestGlucose.getDisplayGlucose();
if (dg != null) {
// TODO Coloring
// TODO Strikethrough et al
widgetbg.setText(dg.unitized);
widgetArrow.setText(dg.delta_arrow);
widgetDelta.setText(dg.unitized_delta);
widgetbg.setText(dg.spannableString(dg.unitized,true));
widgetArrow.setText(dg.isStale() ? "" : dg.spannableString(dg.delta_arrow,true));
widgetDelta.setText(dg.spannableString(dg.unitized_delta));
widgetReadingAge.setText(dg.minutesAgo(true));
widgetStatusLine.setText("");
// try to align our minute updates with 10 seconds after reading should arrive to show
Expand Down

0 comments on commit 4c9cb7b

Please sign in to comment.