diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java index bf61df4564..a076608ed2 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java @@ -327,7 +327,7 @@ public class HistoryBrowseActivity extends AppCompatActivity { } if (showIob) - secondGraphData.addIob(fromTime, toTime, useIobForScale, 1d); + secondGraphData.addIob(fromTime, toTime, useIobForScale, 1d, showPrediction); if (showCob) secondGraphData.addCob(fromTime, toTime, useCobForScale, useCobForScale ? 1d : 0.5d); if (showDev) diff --git a/app/src/main/java/info/nightscout/androidaps/data/Intervals.java b/app/src/main/java/info/nightscout/androidaps/data/Intervals.java index eb1b7154d3..efb3b76aea 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Intervals.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Intervals.java @@ -22,7 +22,7 @@ public abstract class Intervals { rawData = new LongSparseArray(); } - public synchronized Intervals reset() { + public synchronized Intervals reset() { rawData = new LongSparseArray(); return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java b/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java index 73f75b9c7d..79885e297f 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java +++ b/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java @@ -9,10 +9,12 @@ import org.slf4j.LoggerFactory; import java.util.Date; +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface; +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.Round; -public class IobTotal { +public class IobTotal implements DataPointWithLabelInterface { private static Logger log = LoggerFactory.getLogger(IobTotal.class); public double iob; @@ -133,4 +135,52 @@ public class IobTotal { return json; } + // DataPoint interface + + int color; + + @Override + public double getX() { + return time; + } + + @Override + public double getY() { + return iob; + } + + @Override + public void setY(double y) { + + } + + @Override + public String getLabel() { + return null; + } + + @Override + public long getDuration() { + return 0; + } + + @Override + public PointsWithLabelGraphSeries.Shape getShape() { + return PointsWithLabelGraphSeries.Shape.IOBPREDICTION; + } + + @Override + public float getSize() { + return 0.5f; + } + + @Override + public int getColor() { + return color; + } + + public IobTotal setColor(int color) { + this.color = color; + return this; + } } diff --git a/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java b/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java index 1a5c81036c..37be1dc6e9 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java +++ b/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java @@ -31,7 +31,7 @@ public class ProfileIntervals { rawData = other.rawData.clone(); } - public synchronized ProfileIntervals reset() { + public synchronized ProfileIntervals reset() { rawData = new LongSparseArray<>(); return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java b/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java index 2f11b752c8..25d2c308c1 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java +++ b/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java @@ -18,12 +18,14 @@ import java.util.Objects; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.IobTotal; +import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; @@ -219,7 +221,7 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface { IobTotal result = new IobTotal(time); InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin(); - int realDuration = getDurationToTime(time); + double realDuration = getDurationToTime(time); if (realDuration > 0) { double dia_ago = time - dia * 60 * 60 * 1000; @@ -247,6 +249,56 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface { return result; } + public IobTotal iobCalc(long time, Profile profile, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { + IobTotal result = new IobTotal(time); + InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin(); + + double realDuration = getDurationToTime(time); + double netBasalAmount = 0d; + + double sensitivityRatio = lastAutosensResult.ratio; + double normalTarget = 100; + + if (exercise_mode && isTempTarget && profile.getTarget() >= normalTarget + 5) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + double c = half_basal_exercise_target - normalTarget; + sensitivityRatio = c / (c + profile.getTarget() - normalTarget); + } + + if (realDuration > 0) { + double netBasalRate; + double dia_ago = time - dia * 60 * 60 * 1000; + int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d); + double spacing = realDuration / aboutFiveMinIntervals; + + for (long j = 0L; j < aboutFiveMinIntervals; j++) { + // find middle of the interval + long calcdate = (long) (date + j * spacing * 60 * 1000 + 0.5d * spacing * 60 * 1000); + + double basalRate = profile.getBasal(calcdate); + double basalRateCorrection = basalRate * (sensitivityRatio - 1); + + + netBasalRate = absoluteRate() - basalRateCorrection; + + if (calcdate > dia_ago && calcdate <= time) { + double tempBolusSize = netBasalRate * spacing / 60d; + + Treatment tempBolusPart = new Treatment(); + tempBolusPart.insulin = tempBolusSize; + tempBolusPart.date = calcdate; + + Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia); + result.iob += aIOB.iobContrib; + result.activity += aIOB.activityContrib; + result.extendedBolusInsulin += tempBolusPart.insulin; + } + } + } + return result; + } + public int getRealDuration() { return getDurationToTime(System.currentTimeMillis()); } diff --git a/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java b/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java index 28e768946f..f2a10cf4a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java +++ b/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java @@ -17,6 +17,7 @@ import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; @@ -241,7 +242,7 @@ public class TemporaryBasal implements Interval, DbObjectBase { double netBasalAmount = 0d; if (realDuration > 0) { - double netBasalRate = 0d; + double netBasalRate; double dia = profile.getDia(); double dia_ago = time - dia * 60 * 60 * 1000; int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d); @@ -251,10 +252,8 @@ public class TemporaryBasal implements Interval, DbObjectBase { // find middle of the interval long calcdate = (long) (date + j * tempBolusSpacing * 60 * 1000 + 0.5d * tempBolusSpacing * 60 * 1000); - Double basalRate = profile.getBasal(calcdate); + double basalRate = profile.getBasal(calcdate); - if (basalRate == null) - continue; if (isAbsolute) { netBasalRate = absoluteRate - basalRate; } else { @@ -284,6 +283,73 @@ public class TemporaryBasal implements Interval, DbObjectBase { return result; } + public IobTotal iobCalc(long time, Profile profile, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { + + if (isFakeExtended) { + log.error("iobCalc should only be called on Extended boluses separately"); + return new IobTotal(time); + } + + IobTotal result = new IobTotal(time); + InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin(); + + double realDuration = getDurationToTime(time); + double netBasalAmount = 0d; + + double sensitivityRatio = lastAutosensResult.ratio; + double normalTarget = 100; + + if (exercise_mode && isTempTarget && profile.getTarget() >= normalTarget + 5) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + double c = half_basal_exercise_target - normalTarget; + sensitivityRatio = c / (c + profile.getTarget() - normalTarget); + } + + if (realDuration > 0) { + double netBasalRate; + double dia = profile.getDia(); + double dia_ago = time - dia * 60 * 60 * 1000; + int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d); + double tempBolusSpacing = realDuration / aboutFiveMinIntervals; + + for (long j = 0L; j < aboutFiveMinIntervals; j++) { + // find middle of the interval + long calcdate = (long) (date + j * tempBolusSpacing * 60 * 1000 + 0.5d * tempBolusSpacing * 60 * 1000); + + double basalRate = profile.getBasal(calcdate); + basalRate *= sensitivityRatio; + + if (isAbsolute) { + netBasalRate = absoluteRate - basalRate; + } else { + double abs = percentRate / 100d * profile.getBasal(calcdate); + netBasalRate = abs - basalRate; + } + + if (calcdate > dia_ago && calcdate <= time) { + double tempBolusSize = netBasalRate * tempBolusSpacing / 60d; + netBasalAmount += tempBolusSize; + + Treatment tempBolusPart = new Treatment(); + tempBolusPart.insulin = tempBolusSize; + tempBolusPart.date = calcdate; + + Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia); + result.basaliob += aIOB.iobContrib; + result.activity += aIOB.activityContrib; + result.netbasalinsulin += tempBolusPart.insulin; + if (tempBolusPart.insulin > 0) { + result.hightempinsulin += tempBolusPart.insulin; + } + } + result.netRatio = netBasalRate; // ratio at the end of interval + } + } + result.netInsulin = netBasalAmount; + return result; + } + public int getRealDuration() { return getDurationToTime(System.currentTimeMillis()); } @@ -339,8 +405,10 @@ public class TemporaryBasal implements Interval, DbObjectBase { if (isFakeExtended) { Profile profile = ProfileFunctions.getInstance().getProfile(); + if (profile == null) + return "null"; Double currentBasalRate = profile.getBasal(); - double rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); + double rate = currentBasalRate + netExtendedRate; return getCalcuatedPercentageIfNeeded() + DecimalFormatter.to2Decimal(rate) + "U/h (" + DecimalFormatter.to2Decimal(netExtendedRate) + "E) @" + DateUtil.timeString(date) + " " + getRealDuration() + "/" + durationInMinutes + "'"; @@ -358,12 +426,14 @@ public class TemporaryBasal implements Interval, DbObjectBase { public String toStringShort() { if (isAbsolute || isFakeExtended) { - double rate = 0d; + double rate; if (isFakeExtended) { Profile profile = ProfileFunctions.getInstance().getProfile(); - Double currentBasalRate = profile.getBasal(); - rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); - } else if (isAbsolute) { + if (profile == null) + return "null"; + double currentBasalRate = profile.getBasal(); + rate = currentBasalRate + netExtendedRate; + } else { rate = absoluteRate; } @@ -383,24 +453,25 @@ public class TemporaryBasal implements Interval, DbObjectBase { } private String getCalcuatedPercentageIfNeeded() { + Profile profile = ProfileFunctions.getInstance().getProfile(); + + if (profile == null) + return "null"; + if (isAbsolute || isFakeExtended) { - double rate = 0d; + double rate; if (isFakeExtended) { - Profile profile = ProfileFunctions.getInstance().getProfile(); - Double currentBasalRate = profile.getBasal(); - rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); - } else if (isAbsolute) { + double currentBasalRate = profile.getBasal(); + rate = currentBasalRate + netExtendedRate; + } else { rate = absoluteRate; } if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && SP.getBoolean(R.string.key_danar_useextended, false)) { - Profile profile = ProfileFunctions.getInstance().getProfile(); - if (profile != null) { - double basal = profile.getBasal(); - if (basal != 0) { - return Math.round(rate * 100d / basal) + "% "; - } + double basal = profile.getBasal(); + if (basal != 0) { + return Math.round(rate * 100d / basal) + "% "; } } } @@ -408,14 +479,18 @@ public class TemporaryBasal implements Interval, DbObjectBase { } public String toStringVeryShort() { + Profile profile = ProfileFunctions.getInstance().getProfile(); + + if (profile == null) + return "null"; + if (isAbsolute || isFakeExtended) { - double rate = 0d; + double rate; if (isFakeExtended) { - Profile profile = ProfileFunctions.getInstance().getProfile(); - Double currentBasalRate = profile.getBasal(); - rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); - } else if (isAbsolute) { + double currentBasalRate = profile.getBasal(); + rate = currentBasalRate + netExtendedRate; + } else { rate = absoluteRate; } return DecimalFormatter.to2Decimal(rate) + "U/h "; diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java index 0bec22661c..43661b117a 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java @@ -26,7 +26,7 @@ public interface TreatmentsInterface { IobTotal getLastCalculationTreatments(); IobTotal getCalculationToTimeTreatments(long time); IobTotal getLastCalculationTempBasals(); - IobTotal getCalculationToTimeTempBasals(long time, Profile profile); + IobTotal getCalculationToTimeTempBasals(long time); MealData getMealData(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java index 728e3145d6..c0508e141a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java @@ -139,11 +139,7 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr long start = System.currentTimeMillis(); long startPart = System.currentTimeMillis(); - IobTotal[] iobArray = IobCobCalculatorPlugin.getPlugin().calculateIobArrayForSMB(profile); - if (L.isEnabled(L.APS)) - Profiler.log(log, "calculateIobArrayInDia()", startPart); - startPart = System.currentTimeMillis(); MealData mealData = TreatmentsPlugin.getPlugin().getMealData(); if (L.isEnabled(L.APS)) Profiler.log(log, "getMealData()", startPart); @@ -190,6 +186,11 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr lastAutosensResult.sensResult = "autosens disabled"; } + IobTotal[] iobArray = IobCobCalculatorPlugin.getPlugin().calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget); + if (L.isEnabled(L.APS)) + Profiler.log(log, "calculateIobArrayInDia()", startPart); + + startPart = System.currentTimeMillis(); Constraint smbAllowed = new Constraint<>(!tempBasalFallback); MainApp.getConstraintChecker().isSMBModeEnabled(smbAllowed); inputConstraints.copyReasons(smbAllowed); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java index 3e93aa7b10..46fd37d8fd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java @@ -1506,7 +1506,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } if (SP.getBoolean("showiob", true)) - secondGraphData.addIob(fromTime, now, useIobForScale, 1d); + secondGraphData.addIob(fromTime, now, useIobForScale, 1d, SP.getBoolean("showprediction", false)); if (SP.getBoolean("showcob", true)) secondGraphData.addCob(fromTime, now, useCobForScale, useCobForScale ? 1d : 0.5d); if (SP.getBoolean("showdeviations", false)) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java index 29e190055a..0e2a7ead25 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java @@ -29,13 +29,11 @@ import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.logging.L; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.BasalData; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.aps.loop.APSResult; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; +import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults; +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.AreaGraphSeries; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DoubleDataPoint; @@ -44,8 +42,13 @@ import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Point import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TimeAsXAxisLabelFormatter; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.BasalData; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; +import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.Round; import info.nightscout.androidaps.utils.SP; @@ -363,7 +366,7 @@ public class GraphData { total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile); act = total.activity; - if(time<=now) + if (time <= now) actArrayHist.add(new ScaledDataPoint(time, act, actScale)); else actArrayPred.add(new ScaledDataPoint(time, act, actScale)); @@ -400,7 +403,7 @@ public class GraphData { } // scale in % of vertical size (like 0.3) - public void addIob(long fromTime, long toTime, boolean useForScale, double scale) { + public void addIob(long fromTime, long toTime, boolean useForScale, double scale, boolean showPrediction) { FixedLineGraphSeries iobSeries; List iobArray = new ArrayList<>(); Double maxIobValueFound = Double.MIN_VALUE; @@ -429,6 +432,42 @@ public class GraphData { iobSeries.setColor(MainApp.gc(R.color.iob)); iobSeries.setThickness(3); + if (showPrediction) { + AutosensResult lastAutosensResult; + AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensDataSynchronized("GraphData"); + if (autosensData == null) + lastAutosensResult = new AutosensResult(); + else + lastAutosensResult = autosensData.autosensResult; + boolean isTempTarget = TreatmentsPlugin.getPlugin().getTempTargetFromHistory(System.currentTimeMillis()) != null; + + List iobPred = new ArrayList<>(); + IobTotal[] iobPredArray = IobCobCalculatorPlugin.getPlugin().calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget); + for (IobTotal i : iobPredArray) { + iobPred.add(i.setColor(MainApp.gc(R.color.iobPredAS))); + maxIobValueFound = Math.max(maxIobValueFound, Math.abs(i.iob)); + } + DataPointWithLabelInterface[] iobp = new DataPointWithLabelInterface[iobPred.size()]; + iobp = iobPred.toArray(iobp); + addSeries(new PointsWithLabelGraphSeries<>(iobp)); + + + List iobPred2 = new ArrayList<>(); + IobTotal[] iobPredArray2 = IobCobCalculatorPlugin.getPlugin().calculateIobArrayForSMB(new AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget); + for (IobTotal i : iobPredArray2) { + iobPred2.add(i.setColor(MainApp.gc(R.color.iobPred))); + maxIobValueFound = Math.max(maxIobValueFound, Math.abs(i.iob)); + } + DataPointWithLabelInterface[] iobp2 = new DataPointWithLabelInterface[iobPred2.size()]; + iobp2 = iobPred2.toArray(iobp2); + addSeries(new PointsWithLabelGraphSeries<>(iobp2)); + + if (L.isEnabled(L.AUTOSENS)) { + log.debug("IOB pred for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + IobCobCalculatorPlugin.getPlugin().iobArrayToString(iobPredArray)); + log.debug("IOB pred for AS=" + DecimalFormatter.to2Decimal(1) + ": " + IobCobCalculatorPlugin.getPlugin().iobArrayToString(iobPredArray2)); + } + } + if (useForScale) { maxY = maxIobValueFound; minY = -maxIobValueFound; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java index aaa38359a0..eb981e9329 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java @@ -79,7 +79,8 @@ public class PointsWithLabelGraphSeries e EXERCISE, GENERAL, GENERALWITHDURATION, - COBFAILOVER + COBFAILOVER, + IOBPREDICTION } /** @@ -206,6 +207,11 @@ public class PointsWithLabelGraphSeries e mPaint.setStyle(Paint.Style.FILL); mPaint.setStrokeWidth(0); canvas.drawCircle(endX, endY, value.getSize() * scaledPxSize, mPaint); + } else if (value.getShape() == Shape.BG || value.getShape() == Shape.IOBPREDICTION) { + mPaint.setColor(value.getColor()); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setStrokeWidth(0); + canvas.drawCircle(endX, endY, value.getSize() * scaledPxSize, mPaint); } else if (value.getShape() == Shape.PREDICTION) { mPaint.setColor(value.getColor()); mPaint.setStyle(Paint.Style.FILL); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java index 5b6b9d0f28..444b2db67a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java @@ -39,6 +39,7 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin; import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; +import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.T; import static info.nightscout.androidaps.utils.DateUtil.now; @@ -346,6 +347,12 @@ public class IobCobCalculatorPlugin extends PluginBase { } } + public IobTotal calculateFromTreatmentsAndTempsSynchronized(long time, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { + synchronized (dataLock) { + return calculateFromTreatmentsAndTemps(time, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); + } + } + public IobTotal calculateFromTreatmentsAndTemps(long time, Profile profile) { long now = System.currentTimeMillis(); time = roundUpTime(time); @@ -356,7 +363,7 @@ public class IobCobCalculatorPlugin extends PluginBase { //log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString()); } IobTotal bolusIob = TreatmentsPlugin.getPlugin().getCalculationToTimeTreatments(time).round(); - IobTotal basalIob = TreatmentsPlugin.getPlugin().getCalculationToTimeTempBasals(time, profile, true, now).round(); + IobTotal basalIob = TreatmentsPlugin.getPlugin().getCalculationToTimeTempBasals(time, true, now).round(); if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS)) { // Add expected zero temp basal for next 240 mins IobTotal basalIobWithZeroTemp = basalIob.copy(); @@ -379,6 +386,32 @@ public class IobCobCalculatorPlugin extends PluginBase { return iobTotal; } + public IobTotal calculateFromTreatmentsAndTemps(long time, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { + long now = DateUtil.now(); + + IobTotal bolusIob = TreatmentsPlugin.getPlugin().getCalculationToTimeTreatments(time).round(); + IobTotal basalIob = TreatmentsPlugin.getPlugin().getCalculationToTimeTempBasals(time, now, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget).round(); + if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS)) { + // Add expected zero temp basal for next 240 mins + IobTotal basalIobWithZeroTemp = basalIob.copy(); + TemporaryBasal t = new TemporaryBasal() + .date(now + 60 * 1000L) + .duration(240) + .absolute(0); + if (t.date < time) { + Profile profile = ProfileFunctions.getInstance().getProfile(t.date); + if (profile != null) { + IobTotal calc = t.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); + basalIobWithZeroTemp.plus(calc); + } + } + + basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round(); + } + + return IobTotal.combine(bolusIob, basalIob).round(); + } + @Nullable public Long findPreviousTimeFromBucketedData(long time) { if (bucketed_data == null) @@ -554,22 +587,32 @@ public class IobCobCalculatorPlugin extends PluginBase { return array; } - public IobTotal[] calculateIobArrayForSMB(Profile profile) { + public IobTotal[] calculateIobArrayForSMB(AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { // predict IOB out to DIA plus 30m - long time = System.currentTimeMillis(); - time = roundUpTime(time); + long now = DateUtil.now(); int len = (4 * 60) / 5; IobTotal[] array = new IobTotal[len]; int pos = 0; for (int i = 0; i < len; i++) { - long t = time + i * 5 * 60000; - IobTotal iob = calculateFromTreatmentsAndTempsSynchronized(t, profile); + long t = now + i * 5 * 60000; + IobTotal iob = calculateFromTreatmentsAndTempsSynchronized(t, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); array[pos] = iob; pos++; } return array; } + public String iobArrayToString(IobTotal[] array) { + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (IobTotal i : array) { + sb.append(DecimalFormatter.to2Decimal(i.iob)); + sb.append(", "); + } + sb.append("]"); + return sb.toString(); + } + public AutosensResult detectSensitivityWithLock(long fromTime, long toTime) { synchronized (dataLock) { return ConfigBuilderPlugin.getPlugin().getActiveSensitivity().detectSensitivity(this, fromTime, toTime); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index 4fed34a2b2..a9284dd366 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -49,6 +49,7 @@ import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperAc import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin; @@ -404,11 +405,11 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } @Override - public IobTotal getCalculationToTimeTempBasals(long time, Profile profile) { - return getCalculationToTimeTempBasals(time, profile, false, 0); + public IobTotal getCalculationToTimeTempBasals(long time) { + return getCalculationToTimeTempBasals(time, false, 0); } - public IobTotal getCalculationToTimeTempBasals(long time, Profile profile, boolean truncate, long truncateTime) { + public IobTotal getCalculationToTimeTempBasals(long time, boolean truncate, long truncateTime) { IobTotal total = new IobTotal(time); InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin(); @@ -420,6 +421,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface TemporaryBasal t = tempBasals.get(pos); if (t.date > time) continue; IobTotal calc; + Profile profile = ProfileFunctions.getInstance().getProfile(t.date); + if (profile == null) continue; if (truncate && t.end() > truncateTime) { TemporaryBasal dummyTemp = new TemporaryBasal(); dummyTemp.copyFrom(t); @@ -439,6 +442,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface ExtendedBolus e = extendedBoluses.get(pos); if (e.date > time) continue; IobTotal calc; + Profile profile = ProfileFunctions.getInstance().getProfile(e.date); + if (profile == null) continue; if (truncate && e.end() > truncateTime) { ExtendedBolus dummyExt = new ExtendedBolus(); dummyExt.copyFrom(e); @@ -460,11 +465,65 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface return total; } + public IobTotal getCalculationToTimeTempBasals(long time, long truncateTime, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { + IobTotal total = new IobTotal(time); + + InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin(); + if (insulinInterface == null) + return total; + + synchronized (tempBasals) { + for (int pos = 0; pos < tempBasals.size(); pos++) { + TemporaryBasal t = tempBasals.get(pos); + if (t.date > time) continue; + IobTotal calc; + Profile profile = ProfileFunctions.getInstance().getProfile(t.date); + if (profile == null) continue; + if (t.end() > truncateTime) { + TemporaryBasal dummyTemp = new TemporaryBasal(); + dummyTemp.copyFrom(t); + dummyTemp.cutEndTo(truncateTime); + calc = dummyTemp.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); + } else { + calc = t.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); + } + //log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basaliob); + total.plus(calc); + } + } + if (ConfigBuilderPlugin.getPlugin().getActivePump().isFakingTempsByExtendedBoluses()) { + IobTotal totalExt = new IobTotal(time); + synchronized (extendedBoluses) { + for (int pos = 0; pos < extendedBoluses.size(); pos++) { + ExtendedBolus e = extendedBoluses.get(pos); + if (e.date > time) continue; + IobTotal calc; + Profile profile = ProfileFunctions.getInstance().getProfile(e.date); + if (profile == null) continue; + if (e.end() > truncateTime) { + ExtendedBolus dummyExt = new ExtendedBolus(); + dummyExt.copyFrom(e); + dummyExt.cutEndTo(truncateTime); + calc = dummyExt.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); + } else { + calc = e.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); + } + totalExt.plus(calc); + } + } + // Convert to basal iob + totalExt.basaliob = totalExt.iob; + totalExt.iob = 0d; + totalExt.netbasalinsulin = totalExt.extendedBolusInsulin; + totalExt.hightempinsulin = totalExt.extendedBolusInsulin; + total.plus(totalExt); + } + return total; + } + @Override public void updateTotalIOBTempBasals() { - Profile profile = ProfileFunctions.getInstance().getProfile(); - if (profile != null) - lastTempBasalsCalculation = getCalculationToTimeTempBasals(DateUtil.now(), profile); + lastTempBasalsCalculation = getCalculationToTimeTempBasals(DateUtil.now()); } @Nullable diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f67a6a3ead..00453fa459 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,7 +3,9 @@ #ff00ff #00ffff #1e88e5 + #00d2d2 #1ea3e5 + #1ea3e5 #FFFB8C00 #FFFB8C00 #c9bd60