2017-06-02 10:25:49 +02:00
|
|
|
package info.nightscout.androidaps.db;
|
|
|
|
|
2017-06-05 00:50:31 +02:00
|
|
|
import android.graphics.Color;
|
2019-10-01 00:00:22 +02:00
|
|
|
|
2019-10-01 20:10:09 +02:00
|
|
|
import androidx.annotation.NonNull;
|
2019-05-16 13:57:37 +02:00
|
|
|
import androidx.annotation.Nullable;
|
2017-06-05 00:50:31 +02:00
|
|
|
|
2017-06-02 10:25:49 +02:00
|
|
|
import com.j256.ormlite.field.DatabaseField;
|
|
|
|
import com.j256.ormlite.table.DatabaseTable;
|
|
|
|
|
2017-06-13 19:37:31 +02:00
|
|
|
import org.json.JSONObject;
|
2017-06-02 10:25:49 +02:00
|
|
|
|
2018-09-06 16:30:57 +02:00
|
|
|
import java.util.List;
|
2017-06-08 20:52:33 +02:00
|
|
|
import java.util.Objects;
|
2017-06-02 10:25:49 +02:00
|
|
|
|
2020-03-19 18:02:24 +01:00
|
|
|
import javax.inject.Inject;
|
|
|
|
|
|
|
|
import dagger.android.HasAndroidInjector;
|
2018-01-21 13:37:38 +01:00
|
|
|
import info.nightscout.androidaps.R;
|
2017-06-13 19:37:31 +02:00
|
|
|
import info.nightscout.androidaps.data.Profile;
|
2017-06-02 10:25:49 +02:00
|
|
|
import info.nightscout.androidaps.interfaces.Interval;
|
2020-03-19 18:02:24 +01:00
|
|
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
2018-07-30 15:46:20 +02:00
|
|
|
import info.nightscout.androidaps.logging.L;
|
2020-03-19 18:02:24 +01:00
|
|
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
2019-02-28 23:16:50 +01:00
|
|
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
|
|
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
|
|
|
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
|
|
|
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
|
|
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
|
2019-10-01 20:10:09 +02:00
|
|
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
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.T;
|
2020-03-19 18:02:24 +01:00
|
|
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
2017-06-02 10:25:49 +02:00
|
|
|
|
|
|
|
@DatabaseTable(tableName = DatabaseHelper.DATABASE_PROFILESWITCHES)
|
2017-06-02 12:27:21 +02:00
|
|
|
public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
|
2017-06-02 10:25:49 +02:00
|
|
|
|
|
|
|
@DatabaseField(id = true)
|
|
|
|
public long date;
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public boolean isValid = true;
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public int source = Source.NONE;
|
|
|
|
@DatabaseField
|
|
|
|
public String _id = null; // NS _id
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public boolean isCPP = false; // CPP NS="CircadianPercentageProfile"
|
|
|
|
@DatabaseField
|
|
|
|
public int timeshift = 0; // CPP NS="timeshift"
|
|
|
|
@DatabaseField
|
|
|
|
public int percentage = 100; // CPP NS="percentage"
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public String profileName = null;
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public String profileJson = null;
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public String profilePlugin = null; // NSProfilePlugin.class.getName();
|
|
|
|
|
|
|
|
@DatabaseField
|
|
|
|
public int durationInMinutes = 0;
|
|
|
|
|
2017-06-13 19:37:31 +02:00
|
|
|
private Profile profile = null;
|
|
|
|
|
2020-03-19 18:02:24 +01:00
|
|
|
HasAndroidInjector injector;
|
|
|
|
@Inject public TreatmentsPlugin treatmentsPlugin;
|
|
|
|
@Inject public AAPSLogger aapsLogger;
|
|
|
|
@Inject public RxBusWrapper rxBus;
|
|
|
|
@Inject public ResourceHelper resourceHelper;
|
|
|
|
|
|
|
|
public ProfileSwitch(HasAndroidInjector injector) {
|
|
|
|
injector.androidInjector().inject(this);
|
|
|
|
this.injector = injector;
|
|
|
|
}
|
|
|
|
|
2018-03-27 14:19:52 +02:00
|
|
|
public ProfileSwitch date(long date) {
|
|
|
|
this.date = date;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ProfileSwitch profileName(String profileName) {
|
|
|
|
this.profileName = profileName;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ProfileSwitch profile(Profile profile) {
|
|
|
|
this.profile = profile;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-10-01 00:00:22 +02:00
|
|
|
public ProfileSwitch source(int source) {
|
2018-03-27 14:19:52 +02:00
|
|
|
this.source = source;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-10-01 00:00:22 +02:00
|
|
|
public ProfileSwitch duration(int duration) {
|
2018-03-27 14:19:52 +02:00
|
|
|
this.durationInMinutes = duration;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2018-01-21 13:37:38 +01:00
|
|
|
@Nullable
|
2017-06-13 19:37:31 +02:00
|
|
|
public Profile getProfileObject() {
|
|
|
|
if (profile == null)
|
|
|
|
try {
|
2020-03-19 18:02:24 +01:00
|
|
|
profile = new Profile(injector, new JSONObject(profileJson), percentage, timeshift);
|
2018-01-21 13:37:38 +01:00
|
|
|
} catch (Exception e) {
|
2020-03-19 18:02:24 +01:00
|
|
|
aapsLogger.error("Unhandled exception", e);
|
|
|
|
aapsLogger.error("Unhandled exception: " + profileJson);
|
2017-06-13 19:37:31 +02:00
|
|
|
}
|
|
|
|
return profile;
|
|
|
|
}
|
|
|
|
|
2018-10-13 20:56:40 +02:00
|
|
|
/**
|
|
|
|
* Note: the name returned here is used as the PS name when uploading to NS. When such a PS is retrieved
|
2018-10-02 18:03:45 +02:00
|
|
|
* again from NS, the added parts must be removed again, see
|
2019-02-26 20:38:27 +01:00
|
|
|
* {@link info.nightscout.androidaps.utils.PercentageSplitter#pureName}
|
2018-10-13 20:56:40 +02:00
|
|
|
*/
|
2017-09-24 10:39:54 +02:00
|
|
|
public String getCustomizedName() {
|
2017-10-14 10:39:32 +02:00
|
|
|
String name = profileName;
|
2019-12-30 00:53:44 +01:00
|
|
|
if (LocalProfilePlugin.Companion.getLOCAL_PROFILE().equals(name)) {
|
2017-10-16 12:54:17 +02:00
|
|
|
name = DecimalFormatter.to2Decimal(getProfileObject().percentageBasalSum()) + "U ";
|
|
|
|
}
|
2018-06-25 11:53:11 +02:00
|
|
|
if (isCPP) {
|
|
|
|
name += "(" + percentage + "%";
|
|
|
|
if (timeshift != 0)
|
|
|
|
name += "," + timeshift + "h";
|
|
|
|
name += ")";
|
2017-09-24 10:39:54 +02:00
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2017-06-08 20:52:33 +02:00
|
|
|
public boolean isEqual(ProfileSwitch other) {
|
|
|
|
if (date != other.date) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (durationInMinutes != other.durationInMinutes)
|
|
|
|
return false;
|
|
|
|
if (percentage != other.percentage)
|
|
|
|
return false;
|
|
|
|
if (timeshift != other.timeshift)
|
|
|
|
return false;
|
|
|
|
if (isCPP != other.isCPP)
|
|
|
|
return false;
|
|
|
|
if (!Objects.equals(_id, other._id))
|
|
|
|
return false;
|
|
|
|
if (!Objects.equals(profilePlugin, other.profilePlugin))
|
|
|
|
return false;
|
|
|
|
if (!Objects.equals(profileJson, other.profileJson))
|
|
|
|
return false;
|
|
|
|
if (!Objects.equals(profileName, other.profileName))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void copyFrom(ProfileSwitch t) {
|
|
|
|
date = t.date;
|
|
|
|
_id = t._id;
|
|
|
|
durationInMinutes = t.durationInMinutes;
|
|
|
|
percentage = t.percentage;
|
|
|
|
timeshift = t.timeshift;
|
|
|
|
isCPP = t.isCPP;
|
|
|
|
profilePlugin = t.profilePlugin;
|
|
|
|
profileJson = t.profileJson;
|
|
|
|
profileName = t.profileName;
|
|
|
|
}
|
|
|
|
|
2017-06-02 10:25:49 +02:00
|
|
|
// -------- Interval interface ---------
|
|
|
|
|
2019-10-01 20:10:09 +02:00
|
|
|
private Long cuttedEnd = null;
|
2017-06-02 10:25:49 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isInProgress() {
|
2017-06-15 23:12:12 +02:00
|
|
|
return match(System.currentTimeMillis());
|
2017-06-02 10:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isEndingEvent() {
|
|
|
|
return durationInMinutes == 0;
|
|
|
|
}
|
|
|
|
|
2018-01-21 13:37:38 +01:00
|
|
|
@Override
|
|
|
|
public boolean isValid() {
|
|
|
|
boolean isValid = getProfileObject() != null && getProfileObject().isValid(DateUtil.dateAndTimeString(date));
|
2020-03-19 18:02:24 +01:00
|
|
|
ProfileSwitch active = treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now());
|
2019-10-01 20:10:09 +02:00
|
|
|
long activeProfileSwitchDate = active != null ? active.date : -1L;
|
|
|
|
if (!isValid && date == activeProfileSwitchDate)
|
2018-01-21 13:37:38 +01:00
|
|
|
createNotificationInvalidProfile(DateUtil.dateAndTimeString(date));
|
|
|
|
return isValid;
|
|
|
|
}
|
|
|
|
|
2019-10-01 20:10:09 +02:00
|
|
|
private void createNotificationInvalidProfile(String detail) {
|
2020-03-19 18:02:24 +01:00
|
|
|
Notification notification = new Notification(Notification.ZERO_VALUE_IN_PROFILE, resourceHelper.gs(R.string.zerovalueinprofile, detail), Notification.LOW, 5);
|
|
|
|
rxBus.send(new EventNewNotification(notification));
|
2018-01-21 13:37:38 +01:00
|
|
|
}
|
|
|
|
|
2020-03-19 18:02:24 +01:00
|
|
|
public static boolean isEvent5minBack(AAPSLogger aapsLogger, List<ProfileSwitch> list, long time, boolean zeroDurationOnly) {
|
2018-09-06 16:30:57 +02:00
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
|
|
ProfileSwitch event = list.get(i);
|
|
|
|
if (event.date <= time && event.date > (time - T.mins(5).msecs())) {
|
|
|
|
if (zeroDurationOnly) {
|
|
|
|
if (event.durationInMinutes == 0) {
|
|
|
|
if (L.isEnabled(L.DATABASE))
|
2020-03-19 18:02:24 +01:00
|
|
|
aapsLogger.debug("Found ProfileSwitch event for time: " + DateUtil.dateAndTimeString(time) + " " + event.toString());
|
2018-09-06 16:30:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (L.isEnabled(L.DATABASE))
|
2020-03-19 18:02:24 +01:00
|
|
|
aapsLogger.debug("Found ProfileSwitch event for time: " + DateUtil.dateAndTimeString(time) + " " + event.toString());
|
2018-09-06 16:30:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-06-02 10:25:49 +02:00
|
|
|
// -------- Interval interface end ---------
|
|
|
|
|
2017-06-02 12:27:21 +02:00
|
|
|
// ----------------- DataPointInterface --------------------
|
|
|
|
@Override
|
|
|
|
public double getX() {
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
|
|
|
|
// default when no sgv around available
|
|
|
|
private double yValue = 0;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double getY() {
|
|
|
|
return yValue;
|
|
|
|
}
|
|
|
|
|
2017-06-05 00:50:31 +02:00
|
|
|
@Override
|
|
|
|
public void setY(double y) {
|
|
|
|
yValue = y;
|
|
|
|
}
|
|
|
|
|
2017-06-02 12:27:21 +02:00
|
|
|
@Override
|
|
|
|
public String getLabel() {
|
2017-10-11 02:32:17 +02:00
|
|
|
return getCustomizedName();
|
2017-06-02 12:27:21 +02:00
|
|
|
}
|
|
|
|
|
2017-06-05 00:50:31 +02:00
|
|
|
@Override
|
|
|
|
public long getDuration() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public PointsWithLabelGraphSeries.Shape getShape() {
|
|
|
|
return PointsWithLabelGraphSeries.Shape.PROFILE;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public float getSize() {
|
|
|
|
return 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getColor() {
|
|
|
|
return Color.CYAN;
|
|
|
|
}
|
|
|
|
|
2019-10-01 20:10:09 +02:00
|
|
|
@NonNull
|
2017-06-12 13:11:16 +02:00
|
|
|
public String toString() {
|
2017-06-02 10:25:49 +02:00
|
|
|
return "ProfileSwitch{" +
|
|
|
|
"date=" + date +
|
|
|
|
"date=" + DateUtil.dateAndTimeString(date) +
|
|
|
|
", isValid=" + isValid +
|
|
|
|
", duration=" + durationInMinutes +
|
|
|
|
", profileName=" + profileName +
|
|
|
|
", percentage=" + percentage +
|
|
|
|
", timeshift=" + timeshift +
|
|
|
|
'}';
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|