From c460d1d3ef87f238fe4d2f5ded47d5d25f9d1a38 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sun, 16 Jun 2019 20:12:10 +0100 Subject: [PATCH] - Process Suspend delivery items --- app/build.gradle | 2 +- .../androidaps/db/DatabaseHelper.java | 22 ++ .../pump/common/utils/DateTimeUtil.java | 8 + .../medtronic/data/MedtronicHistoryData.java | 276 ++++++++++++++++-- .../data/dto/TempBasalProcessDTO.java | 6 + .../pump/common/utils/DateTimeUtilUTest.java | 26 ++ 6 files changed, 307 insertions(+), 33 deletions(-) create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtilUTest.java diff --git a/app/build.gradle b/app/build.gradle index c4331b7ddd..c50b1ea0b4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,7 +105,7 @@ android { multiDexEnabled true versionCode 1500 // dev_version: 2.3.1-dev - version "medtronic-0.10" + version "medtronic-0.11.0-SNAPSHOT" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"' diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index d278db98a0..076818d0a1 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -1124,6 +1124,28 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { return null; } + + public TemporaryBasal findTempBasalByPumpId(Long pumpId) { + try { + QueryBuilder queryBuilder = null; + queryBuilder = getDaoTemporaryBasal().queryBuilder(); + Where where = queryBuilder.where(); + where.eq("pumpId", pumpId); + PreparedQuery preparedQuery = queryBuilder.prepare(); + List list = getDaoTemporaryBasal().query(preparedQuery); + + if (list.size() != 1) { + return null; + } else { + return list.get(0); + } + } catch (SQLException e) { + log.error("Unhandled exception", e); + } + return null; + } + + // ------------ ExtendedBolus handling --------------- public boolean createOrUpdate(ExtendedBolus extendedBolus) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtil.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtil.java index a5b559d38d..7a391443d9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtil.java @@ -7,6 +7,7 @@ package info.nightscout.androidaps.plugins.pump.common.utils; import android.util.Log; import org.joda.time.LocalDateTime; +import org.joda.time.Minutes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -211,4 +212,11 @@ public class DateTimeUtil { return d.getTime(); } + + public static int getATechDateDiferenceAsMinutes(Long date1, Long date2) { + + Minutes minutes = Minutes.minutesBetween(toLocalDateTime(date1), toLocalDateTime(date2)); + + return minutes.getMinutes(); + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java index 9f4e13ddf0..6fb8c274d2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java @@ -10,11 +10,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import info.nightscout.androidaps.MainApp; @@ -64,7 +66,7 @@ public class MedtronicHistoryData { private Long lastHistoryRecordTime; private boolean isInit = false; - private Gson gsonPretty; + private Gson gson; //private List fakeTBRs; private DatabaseHelper databaseHelper = MainApp.getDbHelper(); @@ -73,10 +75,10 @@ public class MedtronicHistoryData { public MedtronicHistoryData() { this.allHistory = new ArrayList<>(); - this.gsonPretty = MedtronicUtil.gsonInstance; + this.gson = MedtronicUtil.gsonInstance; - if (this.gsonPretty == null) { - this.gsonPretty = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + if (this.gson == null) { + this.gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); } } @@ -101,21 +103,22 @@ public class MedtronicHistoryData { this.newHistory = newEntries; - showLogs("List of history (before filtering): [" + this.newHistory.size() + "]", gsonPretty.toJson(this.newHistory)); + showLogs("List of history (before filtering): [" + this.newHistory.size() + "]", gson.toJson(this.newHistory)); } - public static void showLogs(String header, String data) { + private static void showLogs(String header, String data) { + + if (!isLogEnabled()) + return; if (header != null) { - if (isLogEnabled()) - LOG.debug(header); + LOG.debug(header); } if (StringUtils.isNotBlank(data)) { for (final String token : StringUtil.splitString(data, 3500)) { - if (isLogEnabled()) - LOG.debug("{}", token); + LOG.debug("{}", token); } } else { LOG.debug("No data."); @@ -178,7 +181,8 @@ public class MedtronicHistoryData { if (isLogEnabled()) LOG.debug("New History entries found: {}", this.newHistory.size()); - showLogs("List of history (after filtering): [" + this.newHistory.size() + "]", gsonPretty.toJson(this.newHistory)); + + showLogs("List of history (after filtering): [" + this.newHistory.size() + "]", gson.toJson(this.newHistory)); } @@ -369,7 +373,7 @@ public class MedtronicHistoryData { // TDD List tdds = getFilteredItems(PumpHistoryEntryType.EndResultTotals, getTDDType()); - LOG.debug("ProcessHistoryData: TDD [count={}, items={}]", tdds.size(), gsonPretty.toJson(tdds)); + LOG.debug("ProcessHistoryData: TDD [count={}, items={}]", tdds.size(), gson.toJson(tdds)); if (!isCollectionEmpty(tdds)) { processTDDs(tdds); @@ -380,7 +384,7 @@ public class MedtronicHistoryData { // Bolus List treatments = getFilteredItems(PumpHistoryEntryType.Bolus); - LOG.debug("ProcessHistoryData: Bolus [count={}, items={}]", treatments.size(), gsonPretty.toJson(treatments)); + LOG.debug("ProcessHistoryData: Bolus [count={}, items={}]", treatments.size(), gson.toJson(treatments)); if (treatments.size() > 0) { processEntries(treatments, ProcessHistoryRecord.Bolus); @@ -389,20 +393,20 @@ public class MedtronicHistoryData { // TBR List tbrs = getFilteredItems(PumpHistoryEntryType.TempBasalCombined); - LOG.debug("ProcessHistoryData: TBRs NOT Processed [count={}, items={}]", tbrs.size(), gsonPretty.toJson(tbrs)); + LOG.debug("ProcessHistoryData: TBRs NOT Processed [count={}, items={}]", tbrs.size(), gson.toJson(tbrs)); if (tbrs.size() > 0) { //processEntries(tbrs, ProcessHistoryRecord.TBR); } - // Suspends (for suspends/resume, fakeTBR) - List suspends = getSuspends(); + // 'Delivery Suspend' + List suspends = getSuspends(); - LOG.debug("ProcessHistoryData: FakeTBRs (suspend/resume) NOT Processed [count={}, items={}]", suspends.size(), - gsonPretty.toJson(suspends)); + LOG.debug("ProcessHistoryData: 'Delivery Suspend' Processed [count={}, items={}]", suspends.size(), + gson.toJson(suspends)); if (suspends.size() > 0) { - // processSuspends(treatments); + processSuspends(suspends); } } @@ -412,7 +416,7 @@ public class MedtronicHistoryData { List tdds = filterTDDs(tddsIn); if (isLogEnabled()) - LOG.debug(getLogPrefix() + "TDDs found: {}.\n{}", tdds.size(), gsonPretty.toJson(tdds)); + LOG.debug(getLogPrefix() + "TDDs found: {}.\n{}", tdds.size(), gson.toJson(tdds)); List tddsDb = databaseHelper.getTDDsForLastXDays(3); @@ -601,7 +605,7 @@ public class MedtronicHistoryData { if (min == 0 && sec == 10 && outList.size() > 1) { if (isLogEnabled()) LOG.error("Too many entries (with too small diff): (timeDiff=[min={},sec={}],count={},list={})", - min, sec, outList.size(), gsonPretty.toJson(outList)); + min, sec, outList.size(), gson.toJson(outList)); } } } @@ -624,16 +628,14 @@ public class MedtronicHistoryData { private List getDatabaseEntries(int dateDifference, ProcessHistoryRecord processHistoryRecord) { if (processHistoryRecord == ProcessHistoryRecord.Bolus) { - List treatmentsFromHistory = TreatmentsPlugin.getPlugin().getTreatmentsFromHistoryXMinutesAgo( + return TreatmentsPlugin.getPlugin().getTreatmentsFromHistoryXMinutesAgo( dateDifference); - return treatmentsFromHistory; } else { GregorianCalendar gc = new GregorianCalendar(); gc.add(Calendar.MINUTE, (-1) * dateDifference); - List tbrsFromHistory = databaseHelper.getTemporaryBasalsDataFromTime(gc.getTimeInMillis(), true); - return tbrsFromHistory; + return databaseHelper.getTemporaryBasalsDataFromTime(gc.getTimeInMillis(), true); } } @@ -785,22 +787,232 @@ public class MedtronicHistoryData { LOG.debug(operation + " - [date={},pumpId={}, rate={} {}, duration={}]", // temporaryBasalDb.date, // temporaryBasalDb.pumpId, // - temporaryBasalDb.isAbsolute ? String.format("%.2f", temporaryBasalDb.absoluteRate) : - String.format("%d", temporaryBasalDb.percentRate), // + temporaryBasalDb.isAbsolute ? String.format(Locale.ENGLISH, "%.2f", temporaryBasalDb.absoluteRate) : + String.format(Locale.ENGLISH, "%d", temporaryBasalDb.percentRate), // temporaryBasalDb.isAbsolute ? "U/h" : "%", // temporaryBasalDb.durationInMinutes); } - // TODO needs to be implemented - public void processSuspends(List treatments) { + public void processSuspends(List tempBasalProcessList) { + + for (TempBasalProcessDTO tempBasalProcess : tempBasalProcessList) { + + TemporaryBasal tempBasal = databaseHelper.findTempBasalByPumpId(tempBasalProcess.itemOne.getPumpId()); + + if (tempBasal == null) { + // add + tempBasal = new TemporaryBasal(); + tempBasal.date = tryToGetByLocalTime(tempBasalProcess.itemOne.atechDateTime); + + tempBasal.source = Source.PUMP; + tempBasal.pumpId = tempBasalProcess.itemOne.getPumpId(); + tempBasal.durationInMinutes = tempBasalProcess.getDuration(); + tempBasal.absoluteRate = 0.0d; + tempBasal.isAbsolute = true; + + tempBasalProcess.itemOne.setLinkedObject(tempBasal); + tempBasalProcess.itemTwo.setLinkedObject(tempBasal); + + databaseHelper.createOrUpdate(tempBasal); + + } else { + continue; + } + + } } - // TODO needs to be implemented - public List getSuspends() { - return new ArrayList(); + private List getSuspends() { + + List outList = new ArrayList<>(); + + // suspend/resume + outList.addAll(getSuspendResumeRecords()); + // no_delivery/prime & rewind/prime + outList.addAll(getNoDeliveryRewindPrimeRecords()); + + return outList; + } + + private List getSuspendResumeRecords() { + List filteredItems = getFilteredItems(this.newHistory, // + PumpHistoryEntryType.Suspend, // + PumpHistoryEntryType.Resume); + + List outList = new ArrayList<>(); + + if (filteredItems.size() > 0) { + + List filtered2Items = new ArrayList<>(); + + if ((filteredItems.size() % 2 == 0) && (filteredItems.get(0).getEntryType() == PumpHistoryEntryType.Resume)) { + // full resume suspends (S R S R) + filtered2Items.addAll(filteredItems); + } else if ((filteredItems.size() % 2 == 0) && (filteredItems.get(0).getEntryType() == PumpHistoryEntryType.Suspend)) { + // not full suspends, need to retrive one more record and discard first one (R S R S) -> ([S] R S R [xS]) + filteredItems.remove(0); + + PumpHistoryEntry oneMoreEntryFromHistory = getOneMoreEntryFromHistory(); + if (oneMoreEntryFromHistory != null) { + filteredItems.add(getOneMoreEntryFromHistory()); + } else { + filteredItems.remove(filteredItems.size() - 1); // remove last (unpaired R) + } + + filtered2Items.addAll(filteredItems); + } else { + if (filteredItems.get(0).getEntryType() == PumpHistoryEntryType.Resume) { + // get one more from history (R S R) -> ([S] R S R) + + PumpHistoryEntry oneMoreEntryFromHistory = getOneMoreEntryFromHistory(); + if (oneMoreEntryFromHistory != null) { + filteredItems.add(getOneMoreEntryFromHistory()); + } else { + filteredItems.remove(filteredItems.size() - 1); // remove last (unpaired R) + } + + filtered2Items.addAll(filteredItems); + } else { + // remove last and have paired items + filteredItems.remove(0); + filtered2Items.addAll(filteredItems); + } + } + + if (filtered2Items.size() > 0) { + sort(filtered2Items); + Collections.reverse(filtered2Items); + + for (int i = 0; i < filtered2Items.size(); i += 2) { + TempBasalProcessDTO dto = new TempBasalProcessDTO(); + + dto.itemOne = filtered2Items.get(i); + dto.itemTwo = filtered2Items.get(i + 1); + + dto.processOperation = TempBasalProcessDTO.Operation.Add; + + outList.add(dto); + } + } + } + + return outList; + } + + + private List getNoDeliveryRewindPrimeRecords() { + List primeItems = getFilteredItems(this.newHistory, // + PumpHistoryEntryType.Prime); + + List outList = new ArrayList<>(); + + if (primeItems.size() == 0) + return outList; + + List filteredItems = getFilteredItems(this.newHistory, // + PumpHistoryEntryType.Prime, + PumpHistoryEntryType.Rewind, + PumpHistoryEntryType.NoDeliveryAlarm, + PumpHistoryEntryType.Bolus, + PumpHistoryEntryType.TempBasalCombined + ); + + List tempData = new ArrayList<>(); + boolean startedItems = false; + boolean finishedItems = false; + + for (PumpHistoryEntry filteredItem : filteredItems) { + if (filteredItem.getEntryType() == PumpHistoryEntryType.Prime) { + startedItems = true; + } + + if (startedItems) { + if (filteredItem.getEntryType() == PumpHistoryEntryType.Bolus || + filteredItem.getEntryType() == PumpHistoryEntryType.TempBasalCombined) { + finishedItems = true; + } + + if (!finishedItems) { + tempData.add(filteredItem); + } + } + } + + + if (!finishedItems) { + + List filteredItemsOld = getFilteredItems(this.allHistory, // + PumpHistoryEntryType.Rewind, + PumpHistoryEntryType.NoDeliveryAlarm, + PumpHistoryEntryType.Bolus, + PumpHistoryEntryType.TempBasalCombined + ); + + for (PumpHistoryEntry filteredItem : filteredItemsOld) { + + if (filteredItem.getEntryType() == PumpHistoryEntryType.Bolus || + filteredItem.getEntryType() == PumpHistoryEntryType.TempBasalCombined) { + finishedItems = true; + } + + if (!finishedItems) { + tempData.add(filteredItem); + } + } + } + + + if (!finishedItems) + return outList; + + + showLogs("NoDeliveryRewindPrimeRecords: Records to evaluate: ", gson.toJson(tempData)); + + List items = getFilteredItems(tempData, // + PumpHistoryEntryType.Prime + ); + + + TempBasalProcessDTO processDTO = new TempBasalProcessDTO(); + + processDTO.itemTwo = items.get(0); + + items = getFilteredItems(tempData, // + PumpHistoryEntryType.NoDeliveryAlarm + ); + + if (items.size() > 0) { + + processDTO.itemOne = items.get(items.size() - 1); + processDTO.processOperation = TempBasalProcessDTO.Operation.Add; + + return Arrays.asList(processDTO); + } + + + items = getFilteredItems(tempData, // + PumpHistoryEntryType.Rewind + ); + + if (items.size() > 0) { + + processDTO.itemOne = items.get(0); + processDTO.processOperation = TempBasalProcessDTO.Operation.Add; + + return Arrays.asList(processDTO); + } + + return outList; + } + + + private PumpHistoryEntry getOneMoreEntryFromHistory() { + List filteredItems = getFilteredItems(this.allHistory, PumpHistoryEntryType.Suspend); + + return filteredItems.size() == 0 ? null : filteredItems.get(0); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java index 3bf59ca6b0..375170e0f9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry; public class TempBasalProcessDTO { @@ -9,6 +10,11 @@ public class TempBasalProcessDTO { public Operation processOperation = Operation.None; + public int getDuration() { + int difference = DateTimeUtil.getATechDateDiferenceAsMinutes(itemOne.atechDateTime, itemTwo.atechDateTime); + return difference; + } + public static enum Operation { None, diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtilUTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtilUTest.java new file mode 100644 index 0000000000..5d069f0345 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/pump/common/utils/DateTimeUtilUTest.java @@ -0,0 +1,26 @@ +package info.nightscout.androidaps.plugins.pump.common.utils; + +import android.util.Log; + +import junit.framework.Assert; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class DateTimeUtilUTest { + + @Test + public void getATechDateDiferenceAsMinutes() { + + long dt1 = 20191001182301L; + long dt2 = 20191001192805L; + + int aTechDateDiferenceAsMinutes = DateTimeUtil.getATechDateDiferenceAsMinutes(dt1, dt2); + + Assert.assertEquals(65, aTechDateDiferenceAsMinutes); + + Log.d("DateTimeUtilUTest", "Time difference: " + aTechDateDiferenceAsMinutes); + + } +} \ No newline at end of file