Show Absolute insulin
This commit is contained in:
parent
228bd76e78
commit
2517a10a5c
|
@ -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()
|
||||||
|
|
|
@ -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 })
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue