Show Absolute insulin

This commit is contained in:
Milos Kozak 2020-04-20 14:18:39 +02:00
parent 228bd76e78
commit 2517a10a5c
6 changed files with 120 additions and 2 deletions

View file

@ -19,6 +19,7 @@ import android.view.View
import android.view.View.OnLongClickListener import android.view.View.OnLongClickListener
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
@ -149,6 +150,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private var scheduledUpdate: ScheduledFuture<*>? = null private var scheduledUpdate: ScheduledFuture<*>? = null
private val secondaryGraphs = ArrayList<GraphView>() private val secondaryGraphs = ArrayList<GraphView>()
private val secondaryGraphsLabel = ArrayList<TextView>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
@ -485,8 +487,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
//aapsLogger.debug("New secondary graph count ${numOfGraphs-1}") //aapsLogger.debug("New secondary graph count ${numOfGraphs-1}")
// rebuild needed // rebuild needed
secondaryGraphs.clear() secondaryGraphs.clear()
secondaryGraphsLabel.clear()
overview_iobgraph.removeAllViews() overview_iobgraph.removeAllViews()
for (i in 1 until numOfGraphs) { for (i in 1 until numOfGraphs) {
val label = TextView(context)
label.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).also { it.setMargins(100, 0, 0, -50) }
overview_iobgraph.addView(label)
secondaryGraphsLabel.add(label)
val graph = GraphView(context) val graph = GraphView(context)
graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(100)).also { it.setMargins(0, 0, 0, resourceHelper.dpToPx(10)) } graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(100)).also { it.setMargins(0, 0, 0, resourceHelper.dpToPx(10)) }
graph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) graph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
@ -818,12 +825,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
var useRatioForScale = false var useRatioForScale = false
var useDSForScale = false var useDSForScale = false
var useIAForScale = false var useIAForScale = false
var useABSForScale = false
when { when {
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
} }
@ -832,6 +841,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0) if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0) if (overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8) if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, now, useABSForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0) if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
// set manual x bounds to have nice steps // set manual x bounds to have nice steps
@ -843,12 +853,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// finally enforce drawing of graphs in UI thread // finally enforce drawing of graphs in UI thread
graphData.performUpdate() graphData.performUpdate()
for (g in 0 until secondaryGraphs.size) { for (g in 0 until secondaryGraphs.size) {
secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1)
secondaryGraphs[g].visibility = ( secondaryGraphs[g].visibility = (
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] || overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] || overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] || overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] || overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] || overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
).toVisibility() ).toVisibility()
secondaryGraphsData[g].performUpdate() secondaryGraphsData[g].performUpdate()

View file

@ -70,12 +70,23 @@ class OverviewMenus @Inject constructor(
DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true), DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true),
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true), SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true),
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = true), ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = true),
ABS(R.string.overview_show_absinsulin, R.color.iob, primary = false, secondary = true),
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true) DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true)
} }
companion object { companion object {
const val MAX_GRAPHS = 5 // including main const val MAX_GRAPHS = 5 // including main
} }
fun enabledTypes(graph: Int): String {
val r = StringBuilder()
for (type in CharType.values()) if (setting[graph][type.ordinal]) {
r.append(type.name)
r.append(" ")
}
return r.toString()
}
var setting: MutableList<Array<Boolean>> = ArrayList() var setting: MutableList<Array<Boolean>> = ArrayList()
private fun storeGraphConfig() { private fun storeGraphConfig() {
@ -86,9 +97,15 @@ class OverviewMenus @Inject constructor(
private fun loadGraphConfig() { private fun loadGraphConfig() {
val sts = sp.getString(R.string.key_graphconfig, "") val sts = sp.getString(R.string.key_graphconfig, "")
if (sts.isNotEmpty()) if (sts.isNotEmpty()) {
setting = Gson().fromJson(sts, Array<Array<Boolean>>::class.java).toMutableList() setting = Gson().fromJson(sts, Array<Array<Boolean>>::class.java).toMutableList()
else { // reset when new CharType added
for (s in setting)
if (s.size != CharType.values().size) {
setting = ArrayList()
setting.add(Array(CharType.values().size) { true })
}
} else {
setting = ArrayList() setting = ArrayList()
setting.add(Array(CharType.values().size) { true }) setting.add(Array(CharType.values().size) { true })
} }

View file

@ -376,6 +376,40 @@ class GraphData(injector: HasAndroidInjector, private val graph: GraphView, priv
addSeries(iobSeries) addSeries(iobSeries)
} }
// scale in % of vertical size (like 0.3)
fun addAbsIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
val iobSeries: FixedLineGraphSeries<ScaledDataPoint?>
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
var maxIobValueFound = Double.MIN_VALUE
var lastIob = 0.0
val iobScale = Scale()
var time = fromTime
while (time <= toTime) {
val profile = profileFunction.getProfile(time)
var iob = 0.0
if (profile != null) iob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time, profile).iob
if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
iobArray.add(ScaledDataPoint(time, iob, iobScale))
maxIobValueFound = max(maxIobValueFound, abs(iob))
lastIob = iob
}
time += 5 * 60 * 1000L
}
iobSeries = FixedLineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also {
it.isDrawBackground = true
it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.iob) //50%
it.color = resourceHelper.gc(R.color.iob)
it.thickness = 3
}
if (useForScale) {
maxY = maxIobValueFound
minY = -maxIobValueFound
}
iobScale.setMultiplier(maxY * scale / maxIobValueFound)
addSeries(iobSeries)
}
// scale in % of vertical size (like 0.3) // scale in % of vertical size (like 0.3)
fun addCob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) { fun addCob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = ArrayList() val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = ArrayList()

View file

@ -71,6 +71,7 @@ public class IobCobCalculatorPlugin extends PluginBase {
private CompositeDisposable disposable = new CompositeDisposable(); private CompositeDisposable disposable = new CompositeDisposable();
private LongSparseArray<IobTotal> iobTable = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<IobTotal> iobTable = new LongSparseArray<>(); // oldest at index 0
private LongSparseArray<IobTotal> absIobTable = new LongSparseArray<>(); // oldest at index 0, absolute insulin in the body
private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0
@ -487,6 +488,27 @@ public class IobCobCalculatorPlugin extends PluginBase {
return iobTotal; return iobTotal;
} }
public IobTotal calculateAbsInsulinFromTreatmentsAndTempsSynchronized(long time, Profile profile) {
synchronized (dataLock) {
long now = System.currentTimeMillis();
time = roundUpTime(time);
if (time < now && absIobTable.get(time) != null) {
//og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
return absIobTable.get(time);
} else {
//log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
}
IobTotal bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round();
IobTotal basalIob = treatmentsPlugin.getAbsoluteIOBTempBasals(time).round();
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
if (time < System.currentTimeMillis()) {
absIobTable.put(time, iobTotal);
}
return iobTotal;
}
}
private IobTotal calculateFromTreatmentsAndTemps(long time, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { private IobTotal calculateFromTreatmentsAndTemps(long time, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) {
long now = DateUtil.now(); long now = DateUtil.now();
@ -809,6 +831,14 @@ public class IobCobCalculatorPlugin extends PluginBase {
break; break;
} }
} }
for (int index = absIobTable.size() - 1; index >= 0; index--) {
if (absIobTable.keyAt(index) > time) {
getAapsLogger().debug(LTag.AUTOSENS, "Removing from absIobTable: " + DateUtil.dateAndTimeString(absIobTable.keyAt(index)));
absIobTable.removeAt(index);
} else {
break;
}
}
for (int index = autosensDataTable.size() - 1; index >= 0; index--) { for (int index = autosensDataTable.size() - 1; index >= 0; index--) {
if (autosensDataTable.keyAt(index) > time) { if (autosensDataTable.keyAt(index) > time) {
getAapsLogger().debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + DateUtil.dateAndTimeString(autosensDataTable.keyAt(index))); getAapsLogger().debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + DateUtil.dateAndTimeString(autosensDataTable.keyAt(index)));

View file

@ -59,6 +59,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryDa
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
@ -442,6 +443,29 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return total; return total;
} }
public IobTotal getAbsoluteIOBTempBasals(long time) {
IobTotal total = new IobTotal(time);
PumpInterface pumpInterface = activePlugin.getActivePump();
for (long i = time - range(); i < time; i += T.mins(5).msecs()) {
Profile profile = profileFunction.getProfile(i);
double basal = profile.getBasal(i);
TemporaryBasal runningTBR = getTempBasalFromHistory(i);
double running = basal;
if (runningTBR != null) {
running = runningTBR.tempBasalConvertedToAbsolute(i, profile);
}
Treatment treatment = new Treatment();
treatment.date = i;
treatment.insulin = running * 5.0 / 60.0; // 5 min chunk
Iob iob = treatment.iobCalc(i, profile.getDia());
total.iob += iob.iobContrib;
total.activity += iob.activityContrib;
}
return total;
}
public IobTotal getCalculationToTimeTempBasals(long time, long truncateTime, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { public IobTotal getCalculationToTimeTempBasals(long time, long truncateTime, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) {
IobTotal total = new IobTotal(time); IobTotal total = new IobTotal(time);

View file

@ -1804,4 +1804,5 @@
<string name="overview_show_deviationslope">Deviation slope</string> <string name="overview_show_deviationslope">Deviation slope</string>
<string name="key_graphconfig" translatable="false">graphconfig</string> <string name="key_graphconfig" translatable="false">graphconfig</string>
<string name="authorizationfailed">Authorization failed</string> <string name="authorizationfailed">Authorization failed</string>
<string name="overview_show_absinsulin">Absolute insulin</string>
</resources> </resources>