2017-05-21 22:05:03 +02:00
|
|
|
package info.nightscout.androidaps.db;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Created by mike on 21.05.2017.
|
|
|
|
*/
|
|
|
|
|
2017-06-05 00:50:31 +02:00
|
|
|
import android.graphics.Color;
|
|
|
|
|
2017-05-21 22:05:03 +02:00
|
|
|
import com.j256.ormlite.field.DatabaseField;
|
|
|
|
import com.j256.ormlite.table.DatabaseTable;
|
|
|
|
|
2018-04-08 22:24:04 +02:00
|
|
|
import org.json.JSONObject;
|
2017-05-21 22:05:03 +02:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
2017-06-08 18:15:17 +02:00
|
|
|
import java.util.Objects;
|
2017-05-21 22:05:03 +02:00
|
|
|
|
|
|
|
import info.nightscout.androidaps.Constants;
|
|
|
|
import info.nightscout.androidaps.data.Iob;
|
|
|
|
import info.nightscout.androidaps.data.IobTotal;
|
2019-04-15 23:07:13 +02:00
|
|
|
import info.nightscout.androidaps.data.Profile;
|
2017-05-21 22:05:03 +02:00
|
|
|
import info.nightscout.androidaps.interfaces.InsulinInterface;
|
|
|
|
import info.nightscout.androidaps.interfaces.Interval;
|
2018-07-30 15:46:20 +02:00
|
|
|
import info.nightscout.androidaps.logging.L;
|
2019-02-28 23:16:50 +01:00
|
|
|
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;
|
2019-04-15 23:07:13 +02:00
|
|
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
2019-02-28 23:16:50 +01:00
|
|
|
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
2019-02-26 20:38:27 +01:00
|
|
|
import info.nightscout.androidaps.utils.DateUtil;
|
|
|
|
import info.nightscout.androidaps.utils.DecimalFormatter;
|
|
|
|
import info.nightscout.androidaps.utils.JsonHelper;
|
|
|
|
import info.nightscout.androidaps.utils.Round;
|
2017-05-21 22:05:03 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Created by mike on 21.05.2017.
|
|
|
|
*/
|
|
|
|
|
|
|
|
@DatabaseTable(tableName = DatabaseHelper.DATABASE_EXTENDEDBOLUSES)
|
2017-06-05 00:50:31 +02:00
|
|
|
public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
|
2018-07-30 15:46:20 +02:00
|
|
|
private static Logger log = LoggerFactory.getLogger(L.DATABASE);
|
2017-05-21 22:05:03 +02:00
|
|
|
|
|
|
|
@DatabaseField(id = true)
|
|
|
|
public long date;
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public boolean isValid = true;
|
|
|
|
|
2017-06-08 18:15:17 +02:00
|
|
|
@DatabaseField(index = true)
|
|
|
|
public long pumpId = 0;
|
|
|
|
|
2017-05-21 22:05:03 +02:00
|
|
|
@DatabaseField
|
|
|
|
public int source = Source.NONE;
|
|
|
|
@DatabaseField
|
|
|
|
public String _id = null; // NS _id
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public double insulin = 0d;
|
|
|
|
@DatabaseField
|
2017-05-26 08:54:48 +02:00
|
|
|
public int durationInMinutes = 0; // duration == 0 means end of extended bolus
|
2017-05-21 22:05:03 +02:00
|
|
|
|
|
|
|
@DatabaseField
|
2018-05-06 12:49:03 +02:00
|
|
|
public int insulinInterfaceID = InsulinInterface.OREF_RAPID_ACTING;
|
2017-05-21 22:05:03 +02:00
|
|
|
@DatabaseField
|
|
|
|
public double dia = Constants.defaultDIA;
|
|
|
|
|
2017-06-08 18:15:17 +02:00
|
|
|
public ExtendedBolus() {
|
|
|
|
}
|
|
|
|
|
|
|
|
public ExtendedBolus(long date) {
|
|
|
|
this.date = date;
|
|
|
|
}
|
|
|
|
|
2018-09-13 18:53:16 +02:00
|
|
|
public ExtendedBolus date(long date) {
|
|
|
|
this.date = date;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ExtendedBolus insulin(double insulin) {
|
|
|
|
this.insulin = insulin;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ExtendedBolus pumpId(long pumpId) {
|
|
|
|
this.pumpId = pumpId;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ExtendedBolus source(int source) {
|
|
|
|
this.source = source;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ExtendedBolus durationInMinutes(int durationInMinutes) {
|
|
|
|
this.durationInMinutes = durationInMinutes;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ExtendedBolus _id(String _id) {
|
|
|
|
this._id = _id;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2017-06-08 18:15:17 +02:00
|
|
|
public boolean isEqual(ExtendedBolus other) {
|
|
|
|
if (date != other.date) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (durationInMinutes != other.durationInMinutes)
|
|
|
|
return false;
|
|
|
|
if (insulin != other.insulin)
|
|
|
|
return false;
|
|
|
|
if (pumpId != other.pumpId)
|
|
|
|
return false;
|
|
|
|
if (!Objects.equals(_id, other._id))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void copyFrom(ExtendedBolus t) {
|
|
|
|
date = t.date;
|
|
|
|
_id = t._id;
|
|
|
|
durationInMinutes = t.durationInMinutes;
|
|
|
|
insulin = t.insulin;
|
|
|
|
pumpId = t.pumpId;
|
|
|
|
}
|
2017-05-21 22:05:03 +02:00
|
|
|
|
2018-04-08 22:24:04 +02:00
|
|
|
public static ExtendedBolus createFromJson(JSONObject json) {
|
2018-09-13 18:53:16 +02:00
|
|
|
ExtendedBolus extendedBolus = new ExtendedBolus()
|
|
|
|
.source(Source.NIGHTSCOUT)
|
|
|
|
.date(JsonHelper.safeGetLong(json, "mills"))
|
|
|
|
.durationInMinutes(JsonHelper.safeGetInt(json, "duration"))
|
|
|
|
.insulin(JsonHelper.safeGetDouble(json, "relative") / 60 * JsonHelper.safeGetInt(json, "duration"))
|
|
|
|
._id(JsonHelper.safeGetString(json, "_id"))
|
|
|
|
.pumpId(JsonHelper.safeGetLong(json, "pumpId"));
|
2018-04-08 22:24:04 +02:00
|
|
|
return extendedBolus;
|
|
|
|
}
|
2017-05-21 22:05:03 +02:00
|
|
|
// -------- Interval interface ---------
|
|
|
|
|
|
|
|
Long cuttedEnd = null;
|
|
|
|
|
|
|
|
public long durationInMsec() {
|
|
|
|
return durationInMinutes * 60 * 1000L;
|
|
|
|
}
|
|
|
|
|
|
|
|
public long start() {
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
|
|
|
|
// planned end time at time of creation
|
|
|
|
public long originalEnd() {
|
|
|
|
return date + durationInMinutes * 60 * 1000L;
|
|
|
|
}
|
|
|
|
|
|
|
|
// end time after cut
|
|
|
|
public long end() {
|
|
|
|
if (cuttedEnd != null)
|
|
|
|
return cuttedEnd;
|
|
|
|
return originalEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void cutEndTo(long end) {
|
|
|
|
cuttedEnd = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean match(long time) {
|
|
|
|
if (start() <= time && end() >= time)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean before(long time) {
|
|
|
|
if (end() < time)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean after(long time) {
|
|
|
|
if (start() > time)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-05-23 20:15:14 +02:00
|
|
|
@Override
|
|
|
|
public boolean isInProgress() {
|
2017-06-15 23:12:12 +02:00
|
|
|
return match(System.currentTimeMillis());
|
2017-05-23 20:15:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isEndingEvent() {
|
|
|
|
return durationInMinutes == 0;
|
|
|
|
}
|
|
|
|
|
2018-01-21 13:37:38 +01:00
|
|
|
@Override
|
|
|
|
public boolean isValid() {
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-23 20:15:14 +02:00
|
|
|
|
2017-05-21 22:05:03 +02:00
|
|
|
// -------- Interval interface end ---------
|
|
|
|
|
|
|
|
public String log() {
|
2018-09-10 23:55:52 +02:00
|
|
|
return "ExtendedBolus{" +
|
2017-05-21 22:05:03 +02:00
|
|
|
"date= " + date +
|
|
|
|
", date= " + DateUtil.dateAndTimeString(date) +
|
|
|
|
", isValid=" + isValid +
|
|
|
|
", _id= " + _id +
|
2017-06-08 18:15:17 +02:00
|
|
|
", pumpId= " + pumpId +
|
2017-05-21 22:05:03 +02:00
|
|
|
", insulin= " + insulin +
|
|
|
|
", durationInMinutes= " + durationInMinutes +
|
|
|
|
"}";
|
|
|
|
}
|
|
|
|
|
2017-05-22 20:58:05 +02:00
|
|
|
public double absoluteRate() {
|
2017-05-21 22:05:03 +02:00
|
|
|
return Round.roundTo(insulin / durationInMinutes * 60, 0.01);
|
|
|
|
}
|
|
|
|
|
2017-05-23 22:59:06 +02:00
|
|
|
public double insulinSoFar() {
|
|
|
|
return absoluteRate() * getRealDuration() / 60d;
|
|
|
|
}
|
|
|
|
|
2017-05-21 22:05:03 +02:00
|
|
|
public IobTotal iobCalc(long time) {
|
|
|
|
IobTotal result = new IobTotal(time);
|
2018-09-17 18:18:50 +02:00
|
|
|
InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
|
2017-05-21 22:05:03 +02:00
|
|
|
|
2019-04-15 23:07:13 +02:00
|
|
|
double realDuration = getDurationToTime(time);
|
2017-05-21 22:05:03 +02:00
|
|
|
|
|
|
|
if (realDuration > 0) {
|
2017-06-15 22:55:07 +02:00
|
|
|
double dia_ago = time - dia * 60 * 60 * 1000;
|
2017-05-21 22:05:03 +02:00
|
|
|
int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d);
|
|
|
|
double spacing = realDuration / aboutFiveMinIntervals;
|
|
|
|
|
2017-06-15 22:55:07 +02:00
|
|
|
for (long j = 0L; j < aboutFiveMinIntervals; j++) {
|
2017-05-21 22:05:03 +02:00
|
|
|
// find middle of the interval
|
2017-06-15 22:55:07 +02:00
|
|
|
long calcdate = (long) (date + j * spacing * 60 * 1000 + 0.5d * spacing * 60 * 1000);
|
2017-05-21 22:05:03 +02:00
|
|
|
|
|
|
|
if (calcdate > dia_ago && calcdate <= time) {
|
|
|
|
double tempBolusSize = absoluteRate() * spacing / 60d;
|
|
|
|
|
2017-08-19 19:56:16 +02:00
|
|
|
Treatment tempBolusPart = new Treatment();
|
2017-05-21 22:05:03 +02:00
|
|
|
tempBolusPart.insulin = tempBolusSize;
|
|
|
|
tempBolusPart.date = calcdate;
|
|
|
|
|
2017-06-13 15:06:41 +02:00
|
|
|
Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia);
|
2017-05-21 22:05:03 +02:00
|
|
|
result.iob += aIOB.iobContrib;
|
|
|
|
result.activity += aIOB.activityContrib;
|
2017-05-26 12:07:56 +02:00
|
|
|
result.extendedBolusInsulin += tempBolusPart.insulin;
|
2017-05-21 22:05:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2019-04-15 23:07:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2017-05-21 22:05:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public int getRealDuration() {
|
2017-06-15 23:12:12 +02:00
|
|
|
return getDurationToTime(System.currentTimeMillis());
|
2017-05-21 22:05:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private int getDurationToTime(long time) {
|
|
|
|
long endTime = Math.min(time, end());
|
|
|
|
long msecs = endTime - date;
|
|
|
|
return Math.round(msecs / 60f / 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getPlannedRemainingMinutes() {
|
2017-06-15 23:12:12 +02:00
|
|
|
float remainingMin = (end() - System.currentTimeMillis()) / 1000f / 60;
|
2017-05-21 22:05:03 +02:00
|
|
|
return (remainingMin < 0) ? 0 : Math.round(remainingMin);
|
|
|
|
}
|
|
|
|
|
|
|
|
public String toString() {
|
|
|
|
return "E " + DecimalFormatter.to2Decimal(absoluteRate()) + "U/h @" +
|
|
|
|
DateUtil.timeString(date) +
|
|
|
|
" " + getRealDuration() + "/" + durationInMinutes + "min";
|
|
|
|
}
|
|
|
|
|
|
|
|
public String toStringShort() {
|
|
|
|
return "E " + DecimalFormatter.to2Decimal(absoluteRate()) + "U/h ";
|
|
|
|
}
|
|
|
|
|
|
|
|
public String toStringMedium() {
|
|
|
|
return "E " + DecimalFormatter.to2Decimal(absoluteRate()) + "U/h ("
|
|
|
|
+ getRealDuration() + "/" + durationInMinutes + ") ";
|
|
|
|
}
|
2017-06-05 00:50:31 +02:00
|
|
|
|
2017-06-06 08:21:11 +02:00
|
|
|
public String toStringTotal() {
|
|
|
|
return DecimalFormatter.to2Decimal(insulin) + "U ( " +
|
|
|
|
DecimalFormatter.to2Decimal(absoluteRate()) + " U/h )";
|
|
|
|
}
|
|
|
|
|
2017-06-05 00:50:31 +02:00
|
|
|
// -------- DataPointWithLabelInterface --------
|
|
|
|
@Override
|
|
|
|
public double getX() {
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
|
|
|
|
// default when no sgv around available
|
|
|
|
private double yValue = 0;
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double getY() {
|
|
|
|
return yValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setY(double y) {
|
|
|
|
yValue = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getLabel() {
|
2017-06-06 08:21:11 +02:00
|
|
|
return toStringTotal();
|
2017-06-05 00:50:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long getDuration() {
|
|
|
|
return durationInMinutes * 60 * 1000L;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public PointsWithLabelGraphSeries.Shape getShape() {
|
|
|
|
return PointsWithLabelGraphSeries.Shape.EXTENDEDBOLUS;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public float getSize() {
|
|
|
|
return 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getColor() {
|
|
|
|
return Color.CYAN;
|
|
|
|
}
|
2017-08-21 15:36:52 +02:00
|
|
|
|
2017-05-21 22:05:03 +02:00
|
|
|
}
|