From a51113cfdf1690743b5e4cec150b5c7925f014e1 Mon Sep 17 00:00:00 2001 From: Roumen Georgiev Date: Tue, 23 Apr 2019 10:07:32 +0300 Subject: [PATCH 001/322] try to calculate direction of BG if missing --- .../nightscout/androidaps/db/BgReading.java | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java index 6fafdc4b6d..254c2a7318 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java +++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java @@ -18,6 +18,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv; import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin; 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.GlucoseStatus; import info.nightscout.androidaps.utils.DecimalFormatter; @DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS) @@ -74,7 +75,8 @@ public class BgReading implements DataPointWithLabelInterface { public String directionToSymbol() { String symbol = ""; if (direction == null) { - symbol = "??"; + direction = calculateDirection(); + this.directionToSymbol(); // possible endless loop ?!? } else if (direction.compareTo("DoubleDown") == 0) { symbol = "\u21ca"; } else if (direction.compareTo("SingleDown") == 0) { @@ -246,4 +248,37 @@ public class BgReading implements DataPointWithLabelInterface { return isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction; } + + // Copied from xDrip+ + public String calculateDirection(){ + GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); + if (glucoseStatus == null || glucoseStatus.prev_glucose != 0) + return "??"; + +// double slope = glucoseStatus.delta / (glucoseStatus.previous_date - glucoseStatus.date); + double slope = (glucoseStatus.glucose - glucoseStatus.prev_glucose) / (glucoseStatus.previous_date - glucoseStatus.date); + log.debug("Slope is :"+slope+" delta "+glucoseStatus.delta+" date difference "+(glucoseStatus.date - glucoseStatus.previous_date)); + double slope_by_minute = slope * 60000; + String arrow = "NONE"; + + if (slope_by_minute <= (-3.5)) { + arrow = "DoubleDown"; + } else if (slope_by_minute <= (-2)) { + arrow = "SingleDown"; + } else if (slope_by_minute <= (-1)) { + arrow = "FortyFiveDown"; + } else if (slope_by_minute <= (1)) { + arrow = "Flat"; + } else if (slope_by_minute <= (2)) { + arrow = "FortyFiveUp"; + } else if (slope_by_minute <= (3.5)) { + arrow = "SingleUp"; + } else if (slope_by_minute <= (40)) { + arrow = "DoubleUp"; + } + log.debug("Direction set to: "+arrow); + return arrow; + + } + } From 87a6e006b2e6c5398a95429e888790937d664843 Mon Sep 17 00:00:00 2001 From: Roumen Georgiev Date: Tue, 23 Apr 2019 10:08:52 +0300 Subject: [PATCH 002/322] GlucoseStatus changes --- .../plugins/iob/iobCobCalculator/GlucoseStatus.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java index 191ce9e1cd..f2cb7502f0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java @@ -26,6 +26,8 @@ public class GlucoseStatus { public double short_avgdelta = 0d; public double long_avgdelta = 0d; public long date = 0L; + public long previous_date = 0L; + public double prev_glucose = 0d; public String log() { @@ -58,6 +60,8 @@ public class GlucoseStatus { // load 45min //long fromtime = DateUtil.now() - 60 * 1000L * 45; //List data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false); + long prevDate = 0; + double prevValue = 0; synchronized (IobCobCalculatorPlugin.getPlugin().getDataLock()) { @@ -94,6 +98,9 @@ public class GlucoseStatus { status.long_avgdelta = 0d; status.avgdelta = 0d; // for OpenAPS MA status.date = now_date; + status.previous_date = prevDate; // setting the previous value date for slope calculation + status.prev_glucose = prevValue; + if (L.isEnabled(L.GLUCOSE)) log.debug("sizeRecords==1"); return status.round(); @@ -118,6 +125,11 @@ public class GlucoseStatus { // multiply by 5 to get the same units as delta, i.e. mg/dL/5m change = now.value - then.value; avgdelta = change / minutesago * 5; + // save the value of date if it was 5 min ago or less than 10 min + if( minutesago >= 5 && minutesago < 10 ) { + prevDate = then_date; + prevValue = then.value; + } if (L.isEnabled(L.GLUCOSE)) log.debug(then.toString() + " minutesago=" + minutesago + " avgdelta=" + avgdelta); From 34969fdbfd1042e3696fb26730fdbf314448537c Mon Sep 17 00:00:00 2001 From: Roumen Georgiev Date: Thu, 25 Apr 2019 16:57:50 +0300 Subject: [PATCH 003/322] WIP: adding tests --- .../androidaps/db/BgReadingTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java diff --git a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java new file mode 100644 index 0000000000..3467205fba --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java @@ -0,0 +1,71 @@ +package info.nightscout.androidaps.db; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.logging.Logger; + +import info.AAPSMocker; +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.logging.L; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; +import info.nightscout.androidaps.utils.SP; + +import static org.junit.Assert.*; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({MainApp.class, Logger.class, L.class, SP.class}) +public class BgReadingTest { + private BgReading bgReading = new BgReading(); + @Mock + GlucoseStatus glucoseStatus; + + @Test + public void valueToUnits() { + bgReading.value = 18; + assertEquals(18, bgReading.valueToUnits(Constants.MGDL)*1, 0.01d); + assertEquals(1, bgReading.valueToUnits(Constants.MMOL)*1, 0.01d); + } + + @Test + public void directionToSymbol() { + bgReading = new BgReading(); + bgReading.direction = "DoubleDown"; + assertEquals("\u21ca", bgReading.directionToSymbol()); + bgReading.direction = "SingleDown"; + assertEquals("\u2193", bgReading.directionToSymbol()); + bgReading.direction = "FortyFiveDown"; + assertEquals("\u2198", bgReading.directionToSymbol()); + bgReading.direction = "Flat"; + assertEquals("\u2192", bgReading.directionToSymbol()); + bgReading.direction = "FortyFiveUp"; + assertEquals("\u2197", bgReading.directionToSymbol()); + bgReading.direction = "SingleUp"; + assertEquals("\u2191", bgReading.directionToSymbol()); + bgReading.direction = "DoubleUp"; + assertEquals("\u21c8", bgReading.directionToSymbol()); + bgReading.direction = "OUT OF RANGE"; + assertEquals("??", bgReading.directionToSymbol()); + + } + + @Test + public void calculateDirection() throws Exception { + assertEquals("??", bgReading.calculateDirection()); + + + } + + @Before + public void prepareMock() { + AAPSMocker.mockMainApp(); + AAPSMocker.mockApplicationContext(); + AAPSMocker.mockSP(); + AAPSMocker.mockL(); + } +} \ No newline at end of file From 85bf1fd6bd634463d8cb43887983049efff94deb Mon Sep 17 00:00:00 2001 From: Roumen Georgiev Date: Tue, 30 Apr 2019 15:07:43 +0300 Subject: [PATCH 004/322] Fix + more tests --- .../nightscout/androidaps/db/BgReading.java | 17 +++- .../androidaps/db/BgReadingTest.java | 83 +++++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java index 254c2a7318..6f87f232de 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java +++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java @@ -251,12 +251,16 @@ public class BgReading implements DataPointWithLabelInterface { // Copied from xDrip+ public String calculateDirection(){ - GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); - if (glucoseStatus == null || glucoseStatus.prev_glucose != 0) + GlucoseStatus glucoseStatus = getGlucoseStatus(); + double slope = 0; + if (glucoseStatus == null || glucoseStatus.prev_glucose == 0) return "??"; -// double slope = glucoseStatus.delta / (glucoseStatus.previous_date - glucoseStatus.date); - double slope = (glucoseStatus.glucose - glucoseStatus.prev_glucose) / (glucoseStatus.previous_date - glucoseStatus.date); + // Avoid division by 0 + if (glucoseStatus.date == glucoseStatus.previous_date) + slope = 0; + else + slope = (glucoseStatus.prev_glucose - glucoseStatus.glucose) / (glucoseStatus.previous_date - glucoseStatus.date); log.debug("Slope is :"+slope+" delta "+glucoseStatus.delta+" date difference "+(glucoseStatus.date - glucoseStatus.previous_date)); double slope_by_minute = slope * 60000; String arrow = "NONE"; @@ -281,4 +285,9 @@ public class BgReading implements DataPointWithLabelInterface { } + // Used for testing purpose + protected GlucoseStatus getGlucoseStatus() { + return GlucoseStatus.getGlucoseStatusData(); + } + } diff --git a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java index 3467205fba..4a43f9fb7a 100644 --- a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java +++ b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java @@ -4,9 +4,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import java.util.Date; import java.util.logging.Logger; import info.AAPSMocker; @@ -17,6 +19,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.utils.SP; import static org.junit.Assert.*; +import static org.powermock.api.mockito.PowerMockito.doReturn; @RunWith(PowerMockRunner.class) @PrepareForTest({MainApp.class, Logger.class, L.class, SP.class}) @@ -54,10 +57,90 @@ public class BgReadingTest { } + @Test + public void dateTest(){ + bgReading = new BgReading(); + long now = System.currentTimeMillis(); + bgReading.date = now; + Date nowDate = new Date(now); + assertEquals(now, bgReading.date(now).date); + assertEquals(now, bgReading.date(nowDate).date); + } + + @Test + public void valueTest(){ + bgReading = new BgReading(); + double valueToSet = 81; // 4.5 mmol + assertEquals(81d, bgReading.value(valueToSet).value, 0.01d); + } + + @Test + public void copyFromTest(){ + bgReading = new BgReading(); + BgReading copy = new BgReading(); + bgReading.value = 81; + long now = System.currentTimeMillis(); + bgReading.date = now; + copy.date = now; + + copy.copyFrom(bgReading); + + assertEquals(81, copy.value, 0.1d); + assertEquals(now, copy.date); + assertEquals(bgReading.directionToSymbol(), copy.directionToSymbol()); + } + + @Test + public void isEqualTest(){ + bgReading = new BgReading(); + BgReading copy = new BgReading(); + bgReading.value = 81; + long now = System.currentTimeMillis(); + bgReading.date = now; + copy.date = now; + + copy.copyFrom(bgReading); + + assertEquals(true, copy.isEqual(bgReading)); + assertEquals(false, copy.isEqual(new BgReading())); + } + @Test public void calculateDirection() throws Exception { assertEquals("??", bgReading.calculateDirection()); + bgReading = new BgReading(); + glucoseStatus = new GlucoseStatus(); + glucoseStatus.glucose = 0; + glucoseStatus.prev_glucose = 0; + glucoseStatus.date = 1000L * 60 * 12;; + glucoseStatus.previous_date = 1000L * 60 * 6; + BgReading newReading = Mockito.spy(new BgReading()); + doReturn(glucoseStatus).when(newReading).getGlucoseStatus(); + assertEquals("??", newReading.calculateDirection()); + glucoseStatus.glucose = 72; + glucoseStatus.prev_glucose = 10; + assertEquals("DoubleUp", newReading.calculateDirection()); + glucoseStatus.glucose = 72; + glucoseStatus.prev_glucose = 55; + assertEquals("SingleUp", newReading.calculateDirection()); + glucoseStatus.glucose = 72; + glucoseStatus.prev_glucose = 65; + assertEquals("FortyFiveUp", newReading.calculateDirection()); + glucoseStatus.glucose = 72; + glucoseStatus.prev_glucose = 70; + assertEquals("Flat", newReading.calculateDirection()); + glucoseStatus.glucose = 10; + glucoseStatus.prev_glucose = 72; + assertEquals("DoubleDown", newReading.calculateDirection()); + glucoseStatus.glucose = 55; + glucoseStatus.prev_glucose = 72; + assertEquals("SingleDown", newReading.calculateDirection()); + glucoseStatus.glucose = 65; + glucoseStatus.prev_glucose = 72; + assertEquals("FortyFiveDown", newReading.calculateDirection()); + + } From 62b2d83a1818c6e6ec70c6ff9e8850cf8fbeb05c Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 10 May 2019 08:47:32 +0200 Subject: [PATCH 005/322] cleanup (#68) --- .../nightscout/androidaps/db/BgReading.java | 51 +++++++++---------- .../iob/iobCobCalculator/GlucoseStatus.java | 6 ++- .../androidaps/db/BgReadingTest.java | 45 ++++++++-------- 3 files changed, 52 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java index 6f87f232de..bfedc94ad0 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java +++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java @@ -23,7 +23,7 @@ import info.nightscout.androidaps.utils.DecimalFormatter; @DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS) public class BgReading implements DataPointWithLabelInterface { - private static Logger log = LoggerFactory.getLogger(L.DATABASE); + private static Logger log = LoggerFactory.getLogger(L.GLUCOSE); @DatabaseField(id = true) public long date; @@ -74,10 +74,10 @@ public class BgReading implements DataPointWithLabelInterface { public String directionToSymbol() { String symbol = ""; - if (direction == null) { + if (direction == null) direction = calculateDirection(); - this.directionToSymbol(); // possible endless loop ?!? - } else if (direction.compareTo("DoubleDown") == 0) { + + if (direction.compareTo("DoubleDown") == 0) { symbol = "\u21ca"; } else if (direction.compareTo("SingleDown") == 0) { symbol = "\u2193"; @@ -97,18 +97,13 @@ public class BgReading implements DataPointWithLabelInterface { return symbol; } - public static boolean isSlopeNameInvalid(String direction) { - if (direction.compareTo("NOT_COMPUTABLE") == 0 || + private static boolean isSlopeNameInvalid(String direction) { + return direction.compareTo("NOT_COMPUTABLE") == 0 || direction.compareTo("NOT COMPUTABLE") == 0 || direction.compareTo("OUT_OF_RANGE") == 0 || direction.compareTo("OUT OF RANGE") == 0 || direction.compareTo("NONE") == 0 || - direction.compareTo("NotComputable") == 0 - ) { - return true; - } else { - return false; - } + direction.compareTo("NotComputable") == 0; } @@ -125,7 +120,8 @@ public class BgReading implements DataPointWithLabelInterface { public boolean isDataChanging(BgReading other) { if (date != other.date) { - log.error("Comparing different"); + if (L.isEnabled(L.GLUCOSE)) + log.error("Comparing different"); return false; } if (value != other.value) @@ -135,7 +131,8 @@ public class BgReading implements DataPointWithLabelInterface { public boolean isEqual(BgReading other) { if (date != other.date) { - log.error("Comparing different"); + if (L.isEnabled(L.GLUCOSE)) + log.error("Comparing different"); return false; } if (value != other.value) @@ -151,7 +148,8 @@ public class BgReading implements DataPointWithLabelInterface { public void copyFrom(BgReading other) { if (date != other.date) { - log.error("Copying different"); + if (L.isEnabled(L.GLUCOSE)) + log.error("Copying different"); return; } value = other.value; @@ -250,18 +248,21 @@ public class BgReading implements DataPointWithLabelInterface { // Copied from xDrip+ - public String calculateDirection(){ - GlucoseStatus glucoseStatus = getGlucoseStatus(); - double slope = 0; + String calculateDirection() { + GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); + double slope; if (glucoseStatus == null || glucoseStatus.prev_glucose == 0) - return "??"; + return "NONE"; // Avoid division by 0 if (glucoseStatus.date == glucoseStatus.previous_date) slope = 0; else slope = (glucoseStatus.prev_glucose - glucoseStatus.glucose) / (glucoseStatus.previous_date - glucoseStatus.date); - log.debug("Slope is :"+slope+" delta "+glucoseStatus.delta+" date difference "+(glucoseStatus.date - glucoseStatus.previous_date)); + + if (L.isEnabled(L.GLUCOSE)) + log.debug("Slope is :" + slope + " delta " + glucoseStatus.delta + " date difference " + (glucoseStatus.date - glucoseStatus.previous_date)); + double slope_by_minute = slope * 60000; String arrow = "NONE"; @@ -280,14 +281,8 @@ public class BgReading implements DataPointWithLabelInterface { } else if (slope_by_minute <= (40)) { arrow = "DoubleUp"; } - log.debug("Direction set to: "+arrow); + if (L.isEnabled(L.GLUCOSE)) + log.debug("Direction set to: " + arrow); return arrow; - } - - // Used for testing purpose - protected GlucoseStatus getGlucoseStatus() { - return GlucoseStatus.getGlucoseStatusData(); - } - } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java index f2cb7502f0..54cac18e70 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java @@ -98,8 +98,8 @@ public class GlucoseStatus { status.long_avgdelta = 0d; status.avgdelta = 0d; // for OpenAPS MA status.date = now_date; - status.previous_date = prevDate; // setting the previous value date for slope calculation - status.prev_glucose = prevValue; + status.previous_date = 0; // setting the previous value date for slope calculation + status.prev_glucose = 0; if (L.isEnabled(L.GLUCOSE)) log.debug("sizeRecords==1"); @@ -171,6 +171,8 @@ public class GlucoseStatus { status.long_avgdelta = average(long_deltas); status.avgdelta = status.short_avgdelta; // for OpenAPS MA + status.previous_date = prevDate; // setting the previous value date for slope calculation + status.prev_glucose = prevValue; if (L.isEnabled(L.GLUCOSE)) log.debug(status.log()); diff --git a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java index 4a43f9fb7a..b1b61285f4 100644 --- a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java +++ b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -18,21 +19,23 @@ import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.utils.SP; -import static org.junit.Assert.*; -import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; @RunWith(PowerMockRunner.class) -@PrepareForTest({MainApp.class, Logger.class, L.class, SP.class}) +@PrepareForTest({MainApp.class, Logger.class, L.class, SP.class, GlucoseStatus.class}) public class BgReadingTest { private BgReading bgReading = new BgReading(); - @Mock + GlucoseStatus glucoseStatus; @Test public void valueToUnits() { bgReading.value = 18; - assertEquals(18, bgReading.valueToUnits(Constants.MGDL)*1, 0.01d); - assertEquals(1, bgReading.valueToUnits(Constants.MMOL)*1, 0.01d); + assertEquals(18, bgReading.valueToUnits(Constants.MGDL) * 1, 0.01d); + assertEquals(1, bgReading.valueToUnits(Constants.MMOL) * 1, 0.01d); } @Test @@ -58,7 +61,7 @@ public class BgReadingTest { } @Test - public void dateTest(){ + public void dateTest() { bgReading = new BgReading(); long now = System.currentTimeMillis(); bgReading.date = now; @@ -68,14 +71,14 @@ public class BgReadingTest { } @Test - public void valueTest(){ + public void valueTest() { bgReading = new BgReading(); double valueToSet = 81; // 4.5 mmol assertEquals(81d, bgReading.value(valueToSet).value, 0.01d); } @Test - public void copyFromTest(){ + public void copyFromTest() { bgReading = new BgReading(); BgReading copy = new BgReading(); bgReading.value = 81; @@ -91,7 +94,7 @@ public class BgReadingTest { } @Test - public void isEqualTest(){ + public void isEqualTest() { bgReading = new BgReading(); BgReading copy = new BgReading(); bgReading.value = 81; @@ -101,23 +104,26 @@ public class BgReadingTest { copy.copyFrom(bgReading); - assertEquals(true, copy.isEqual(bgReading)); - assertEquals(false, copy.isEqual(new BgReading())); + assertTrue(copy.isEqual(bgReading)); + assertFalse(copy.isEqual(new BgReading())); } @Test - public void calculateDirection() throws Exception { - assertEquals("??", bgReading.calculateDirection()); + public void calculateDirection() { + assertEquals("NONE", bgReading.calculateDirection()); - bgReading = new BgReading(); glucoseStatus = new GlucoseStatus(); glucoseStatus.glucose = 0; glucoseStatus.prev_glucose = 0; - glucoseStatus.date = 1000L * 60 * 12;; + glucoseStatus.date = 1000L * 60 * 12; glucoseStatus.previous_date = 1000L * 60 * 6; - BgReading newReading = Mockito.spy(new BgReading()); - doReturn(glucoseStatus).when(newReading).getGlucoseStatus(); - assertEquals("??", newReading.calculateDirection()); + + BgReading newReading = new BgReading(); + + PowerMockito.mockStatic(GlucoseStatus.class); + when(GlucoseStatus.getGlucoseStatusData()).thenReturn(glucoseStatus); + + assertEquals("NONE", newReading.calculateDirection()); glucoseStatus.glucose = 72; glucoseStatus.prev_glucose = 10; assertEquals("DoubleUp", newReading.calculateDirection()); @@ -141,7 +147,6 @@ public class BgReadingTest { assertEquals("FortyFiveDown", newReading.calculateDirection()); - } @Before From 6e63d340cd29e23152b254e24d2be6f95b9817e5 Mon Sep 17 00:00:00 2001 From: Roumen Georgiev Date: Mon, 13 May 2019 14:18:10 +0300 Subject: [PATCH 006/322] reworked to use DBHelper --- .../nightscout/androidaps/db/BgReading.java | 25 ++++-- .../iob/iobCobCalculator/GlucoseStatus.java | 14 ---- .../androidaps/db/BgReadingTest.java | 81 ++++++++++--------- 3 files changed, 63 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java index bfedc94ad0..8f7782cff2 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java +++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java @@ -7,6 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; +import java.util.List; import java.util.Objects; import info.nightscout.androidaps.Constants; @@ -18,8 +19,8 @@ import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv; import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin; 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.GlucoseStatus; import info.nightscout.androidaps.utils.DecimalFormatter; +import info.nightscout.androidaps.utils.T; @DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS) public class BgReading implements DataPointWithLabelInterface { @@ -249,19 +250,29 @@ public class BgReading implements DataPointWithLabelInterface { // Copied from xDrip+ String calculateDirection() { - GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); - double slope; - if (glucoseStatus == null || glucoseStatus.prev_glucose == 0) + // Rework to get bgreaings from internal DB and calculate on that base + + List bgReadingsList = MainApp.getDbHelper().getAllBgreadingsDataFromTime(this.date - T.mins(10).msecs(), false); + if (bgReadingsList == null || bgReadingsList.size() < 2) return "NONE"; + BgReading current = bgReadingsList.get(1); + BgReading previous = bgReadingsList.get(0); + + if (bgReadingsList.get(1).date < bgReadingsList.get(0).date) { + current = bgReadingsList.get(0); + previous = bgReadingsList.get(1); + } + + double slope; // Avoid division by 0 - if (glucoseStatus.date == glucoseStatus.previous_date) + if (current.date == previous.date) slope = 0; else - slope = (glucoseStatus.prev_glucose - glucoseStatus.glucose) / (glucoseStatus.previous_date - glucoseStatus.date); + slope = (previous.value - current.value) / (previous.date - current.date); if (L.isEnabled(L.GLUCOSE)) - log.debug("Slope is :" + slope + " delta " + glucoseStatus.delta + " date difference " + (glucoseStatus.date - glucoseStatus.previous_date)); + log.debug("Slope is :" + slope + " delta " + (previous.value - current.value) + " date difference " + (current.date - previous.date)); double slope_by_minute = slope * 60000; String arrow = "NONE"; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java index 54cac18e70..191ce9e1cd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java @@ -26,8 +26,6 @@ public class GlucoseStatus { public double short_avgdelta = 0d; public double long_avgdelta = 0d; public long date = 0L; - public long previous_date = 0L; - public double prev_glucose = 0d; public String log() { @@ -60,8 +58,6 @@ public class GlucoseStatus { // load 45min //long fromtime = DateUtil.now() - 60 * 1000L * 45; //List data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false); - long prevDate = 0; - double prevValue = 0; synchronized (IobCobCalculatorPlugin.getPlugin().getDataLock()) { @@ -98,9 +94,6 @@ public class GlucoseStatus { status.long_avgdelta = 0d; status.avgdelta = 0d; // for OpenAPS MA status.date = now_date; - status.previous_date = 0; // setting the previous value date for slope calculation - status.prev_glucose = 0; - if (L.isEnabled(L.GLUCOSE)) log.debug("sizeRecords==1"); return status.round(); @@ -125,11 +118,6 @@ public class GlucoseStatus { // multiply by 5 to get the same units as delta, i.e. mg/dL/5m change = now.value - then.value; avgdelta = change / minutesago * 5; - // save the value of date if it was 5 min ago or less than 10 min - if( minutesago >= 5 && minutesago < 10 ) { - prevDate = then_date; - prevValue = then.value; - } if (L.isEnabled(L.GLUCOSE)) log.debug(then.toString() + " minutesago=" + minutesago + " avgdelta=" + avgdelta); @@ -171,8 +159,6 @@ public class GlucoseStatus { status.long_avgdelta = average(long_deltas); status.avgdelta = status.short_avgdelta; // for OpenAPS MA - status.previous_date = prevDate; // setting the previous value date for slope calculation - status.prev_glucose = prevValue; if (L.isEnabled(L.GLUCOSE)) log.debug(status.log()); diff --git a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java index b1b61285f4..991c2f7956 100644 --- a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java +++ b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java @@ -3,15 +3,16 @@ package info.nightscout.androidaps.db; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.logging.Logger; +import edu.emory.mathcs.backport.java.util.Arrays; import info.AAPSMocker; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; @@ -22,6 +23,8 @@ import info.nightscout.androidaps.utils.SP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; @RunWith(PowerMockRunner.class) @@ -110,41 +113,32 @@ public class BgReadingTest { @Test public void calculateDirection() { + List bgReadingsList = null; + AAPSMocker.mockDatabaseHelper(); + + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); assertEquals("NONE", bgReading.calculateDirection()); - - glucoseStatus = new GlucoseStatus(); - glucoseStatus.glucose = 0; - glucoseStatus.prev_glucose = 0; - glucoseStatus.date = 1000L * 60 * 12; - glucoseStatus.previous_date = 1000L * 60 * 6; - - BgReading newReading = new BgReading(); - - PowerMockito.mockStatic(GlucoseStatus.class); - when(GlucoseStatus.getGlucoseStatusData()).thenReturn(glucoseStatus); - - assertEquals("NONE", newReading.calculateDirection()); - glucoseStatus.glucose = 72; - glucoseStatus.prev_glucose = 10; - assertEquals("DoubleUp", newReading.calculateDirection()); - glucoseStatus.glucose = 72; - glucoseStatus.prev_glucose = 55; - assertEquals("SingleUp", newReading.calculateDirection()); - glucoseStatus.glucose = 72; - glucoseStatus.prev_glucose = 65; - assertEquals("FortyFiveUp", newReading.calculateDirection()); - glucoseStatus.glucose = 72; - glucoseStatus.prev_glucose = 70; - assertEquals("Flat", newReading.calculateDirection()); - glucoseStatus.glucose = 10; - glucoseStatus.prev_glucose = 72; - assertEquals("DoubleDown", newReading.calculateDirection()); - glucoseStatus.glucose = 55; - glucoseStatus.prev_glucose = 72; - assertEquals("SingleDown", newReading.calculateDirection()); - glucoseStatus.glucose = 65; - glucoseStatus.prev_glucose = 72; - assertEquals("FortyFiveDown", newReading.calculateDirection()); + bgReadingsList = setReadings(72,0); + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + assertEquals("DoubleUp", bgReading.calculateDirection()); + bgReadingsList = setReadings(76,60); + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + assertEquals("SingleUp", bgReading.calculateDirection()); + bgReadingsList = setReadings(74,65); + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + assertEquals("FortyFiveUp", bgReading.calculateDirection()); + bgReadingsList = setReadings(72,72); + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + assertEquals("Flat", bgReading.calculateDirection()); + bgReadingsList = setReadings(0,72); + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + assertEquals("DoubleDown", bgReading.calculateDirection()); + bgReadingsList = setReadings(60,76); + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + assertEquals("SingleDown", bgReading.calculateDirection()); + bgReadingsList = setReadings(65,74); + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + assertEquals("FortyFiveDown", bgReading.calculateDirection()); } @@ -155,5 +149,20 @@ public class BgReadingTest { AAPSMocker.mockApplicationContext(); AAPSMocker.mockSP(); AAPSMocker.mockL(); + AAPSMocker.mockDatabaseHelper(); + } + + public List setReadings(int current_value, int previous_value){ + BgReading now = new BgReading(); + now.value = current_value; + now.date = System.currentTimeMillis(); + BgReading previous = new BgReading(); + previous.value = previous_value; + previous.date = System.currentTimeMillis() - ( 6 * 60 * 1000L); + List bgReadings = new ArrayList() {{ + add(now); + add(previous); + }}; + return bgReadings; } } \ No newline at end of file From 453faf736d6b2b09164602d35f73e3e5bf3abc22 Mon Sep 17 00:00:00 2001 From: Roumen Georgiev Date: Wed, 19 Jun 2019 16:59:34 +0300 Subject: [PATCH 007/322] fix test moved the when().thenReturn to setReadings --- .../androidaps/db/BgReadingTest.java | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java index 991c2f7956..d8653d0914 100644 --- a/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java +++ b/app/src/test/java/info/nightscout/androidaps/db/BgReadingTest.java @@ -118,29 +118,20 @@ public class BgReadingTest { when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); assertEquals("NONE", bgReading.calculateDirection()); - bgReadingsList = setReadings(72,0); - when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + setReadings(72,0); assertEquals("DoubleUp", bgReading.calculateDirection()); - bgReadingsList = setReadings(76,60); - when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + setReadings(76,60); assertEquals("SingleUp", bgReading.calculateDirection()); - bgReadingsList = setReadings(74,65); - when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + setReadings(74,65); assertEquals("FortyFiveUp", bgReading.calculateDirection()); - bgReadingsList = setReadings(72,72); - when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + setReadings(72,72); assertEquals("Flat", bgReading.calculateDirection()); - bgReadingsList = setReadings(0,72); - when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + setReadings(0,72); assertEquals("DoubleDown", bgReading.calculateDirection()); - bgReadingsList = setReadings(60,76); - when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + setReadings(60,76); assertEquals("SingleDown", bgReading.calculateDirection()); - bgReadingsList = setReadings(65,74); - when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadingsList); + setReadings(65,74); assertEquals("FortyFiveDown", bgReading.calculateDirection()); - - } @Before @@ -152,7 +143,7 @@ public class BgReadingTest { AAPSMocker.mockDatabaseHelper(); } - public List setReadings(int current_value, int previous_value){ + public void setReadings(int current_value, int previous_value){ BgReading now = new BgReading(); now.value = current_value; now.date = System.currentTimeMillis(); @@ -163,6 +154,6 @@ public class BgReadingTest { add(now); add(previous); }}; - return bgReadings; + when(MainApp.getDbHelper().getAllBgreadingsDataFromTime(anyLong(),anyBoolean())).thenReturn(bgReadings); } } \ No newline at end of file From 450f4fabf0cbafd5329134879dbd86e9271fae36 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 8 Oct 2019 21:20:04 +0200 Subject: [PATCH 008/322] Survey --- app/build.gradle | 2 + app/google-services.json | 28 ++- app/src/main/AndroidManifest.xml | 1 + .../nightscout/androidaps/MainActivity.java | 4 + .../androidaps/activities/SurveyActivity.kt | 115 ++++++++++++ .../nightscout/androidaps/data/Profile.java | 2 +- .../data/defaultProfile/DefaultProfile.kt | 145 +++++++++++++++ .../androidaps/db/DatabaseHelper.java | 11 +- .../info/nightscout/androidaps/db/TDD.java | 6 + .../plugins/treatments/TreatmentsPlugin.java | 68 ++++--- .../fragments/ProfileViewerDialog.kt | 23 ++- .../TreatmentsProfileSwitchFragment.java | 5 +- .../info/nightscout/androidaps/utils/TIR.kt | 5 + .../androidaps/utils/TddCalculator.kt | 70 ++++++++ .../androidaps/utils/TirCalculator.kt | 9 + app/src/main/res/layout/survey_fragment.xml | 168 ++++++++++++++++++ app/src/main/res/menu/menu_main.xml | 4 + app/src/main/res/values/strings.xml | 12 ++ .../data/defaultProfile/DefaultProfileTest.kt | 26 +++ 19 files changed, 658 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/utils/TIR.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt create mode 100644 app/src/main/res/layout/survey_fragment.xml create mode 100644 app/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt diff --git a/app/build.gradle b/app/build.gradle index 8b2c15a042..097c8ebb5c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -226,6 +226,8 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.google.android.gms:play-services-wearable:17.0.0' implementation 'com.google.firebase:firebase-core:17.2.0' + implementation 'com.google.firebase:firebase-auth:19.1.0' + implementation 'com.google.firebase:firebase-database:19.1.0' implementation("com.crashlytics.sdk.android:crashlytics:2.9.9@aar") { transitive = true; } diff --git a/app/google-services.json b/app/google-services.json index 42db6f4289..507c792c93 100644 --- a/app/google-services.json +++ b/app/google-services.json @@ -13,7 +13,12 @@ "package_name": "info.nightscout.aapspumpcontrol" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" @@ -37,7 +42,12 @@ "package_name": "info.nightscout.androidaps" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" @@ -61,7 +71,12 @@ "package_name": "info.nightscout.nsclient" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" @@ -85,7 +100,12 @@ "package_name": "info.nightscout.nsclient2" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index aeeb53475d..062a67f101 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,6 +76,7 @@ + + profileList = profileStore?.profileList ?: return + val adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList) + survey_spinner.adapter = adapter + + val tdds = TddCalculator.calculate(7) + val averageTdd = TddCalculator.averageTDD(tdds) + survey_tdds.text = MainApp.gs(R.string.tdd) + ":\n" + TddCalculator.toText(tdds) + MainApp.gs(R.string.average) + ":\n" + TddCalculator.toText(averageTdd) + + survey_profile.setOnClickListener { + val age = SafeParse.stringToDouble(survey_age.text.toString()) + val weight = SafeParse.stringToDouble(survey_weight.text.toString()) + val tdd = SafeParse.stringToDouble(survey_tdd.text.toString()) + if (age < 1 || age > 120) { + ToastUtils.showToastInUiThread(this, R.string.invalidage) + return@setOnClickListener + } + if ((weight < 5 || weight > 150) && tdd == 0.0) { + ToastUtils.showToastInUiThread(this, R.string.invalidweight) + return@setOnClickListener + } + if ((tdd < 5 || tdd > 150) && weight == 0.0) { + ToastUtils.showToastInUiThread(this, R.string.invalidweight) + return@setOnClickListener + } + val profile = DefaultProfile().profile(age, tdd, weight, ProfileFunctions.getInstance().profileUnits) + val args = Bundle() + args.putLong("time", DateUtil.now()) + args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal) + args.putString("customProfile", profile.data.toString()) + args.putString("customProfileUnits", profile.units) + args.putString("customProfileName", "Age: $age TDD: $tdd Weight: $weight") + val pvd = ProfileViewerDialog() + pvd.arguments = args + pvd.show(supportFragmentManager, "ProfileViewDialog") + } + + survey_submit.setOnClickListener { + val r = FirebaseRecord() + r.id = InstanceId.instanceId() + r.age = SafeParse.stringToInt(survey_age.text.toString()) + r.weight = SafeParse.stringToInt(survey_weight.text.toString()) + if (r.age < 1 || r.age > 120) { + ToastUtils.showToastInUiThread(this, R.string.invalidage) + return@setOnClickListener + } + if (r.weight < 5 || r.weight > 150) { + ToastUtils.showToastInUiThread(this, R.string.invalidweight) + return@setOnClickListener + } + + if (survey_spinner.selectedItem == null) + return@setOnClickListener + val profileName = survey_spinner.selectedItem.toString() + val specificProfile = profileStore.getSpecificProfile(profileName) + + r.profileJson = specificProfile.toString() + + val auth = FirebaseAuth.getInstance() + auth.signInAnonymously() + .addOnCompleteListener(this) { task -> + if (task.isSuccessful) { + log.debug("signInAnonymously:success") + val user = auth.currentUser + + val database = FirebaseDatabase.getInstance().reference + database.child("survey").child(r.id).setValue(r) + } else { + log.error("signInAnonymously:failure", task.exception) + ToastUtils.showToastInUiThread(this, "Authentication failed.") + //updateUI(null) + } + + // ... + } + finish() + } + } + + inner class FirebaseRecord { + var id = "" + var age: Int = 0 + var weight: Int = 0 + var profileJson = "ghfg" + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java index 6f18ba7af5..1b183e2d08 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java @@ -393,7 +393,7 @@ public class Profile { return getIsfTimeFromMidnight(secondsFromMidnight(time)); } - double getIsfTimeFromMidnight(int timeAsSeconds) { + public double getIsfTimeFromMidnight(int timeAsSeconds) { if (isf_v == null) isf_v = convertToSparseArray(isf); return getValueToTime(isf_v, timeAsSeconds); diff --git a/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt new file mode 100644 index 0000000000..b121dbee02 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt @@ -0,0 +1,145 @@ +package info.nightscout.androidaps.data.defaultProfile + +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.utils.Round +import org.json.JSONArray +import org.json.JSONObject +import java.util.* + + +class DefaultProfile { + var oneToFive: TreeMap> = TreeMap() + var sixToEleven: TreeMap> = TreeMap() + var twelveToSeventeen: TreeMap> = TreeMap() + var eighteenToTwentyfor: TreeMap> = TreeMap() + + fun profile(age: Double, tdd: Double, weight: Double, units: String): Profile { + val profile = JSONObject() + if (age >= 1 && age < 6) { + val _tdd = if (tdd == 0.0) 0.6 * weight else tdd + closest(oneToFive, _tdd * 0.3)?.let { array -> profile.put("basal", arrayToJson(array)) } + val ic = Round.roundTo(250.0 / _tdd, 1.0) + profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -4.0, -1.0, -2.0, -4.0, 0.0, -4.0))) + val isf = Round.roundTo(200.0 / _tdd, 0.1) + profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -2.0, -0.0, -0.0, -2.0, 0.0, -2.0))) + } else if (age >= 6 && age < 12) { + val _tdd = if (tdd == 0.0) 0.8 * weight else tdd + closest(sixToEleven, _tdd * 0.4)?.let { array -> profile.put("basal", arrayToJson(array)) } + val ic = Round.roundTo(375.0 / _tdd, 1.0) + profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -3.0, 0.0, -1.0, -3.0, 0.0, -2.0))) + val isf = Round.roundTo(170.0 / _tdd, 0.1) + profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -1.0, -0.0, -0.0, -1.0, 0.0, -1.0))) + } else if (age >= 12 && age < 17) { + val _tdd = if (tdd == 0.0) 1.0 * weight else tdd + closest(twelveToSeventeen, _tdd * 0.5)?.let { array -> profile.put("basal", arrayToJson(array)) } + val ic = Round.roundTo(500.0 / _tdd, 1.0) + profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, -1.0))) + val isf = Round.roundTo(100.0 / _tdd, 0.1) + profile.put("sens", singleValueArray(isf, arrayOf( 0.2, 0.0, 0.2, 0.2, 0.0, 0.2, 0.2))) + } else if (age >= 18) { + + } + profile.put("dia", 5.0) + profile.put("carbs_hr", 20) // not used + profile.put("delay", 5.0) // not used + profile.put("timezone", TimeZone.getDefault().getID()) + profile.put("target_high", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units)))) + profile.put("target_low", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units)))) + return Profile(profile, units) + } + + init { + oneToFive[1.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050) + oneToFive[1.13] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050) + oneToFive[1.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050) + oneToFive[1.38] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050) + oneToFive[1.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.100, 0.100, 0.050, 0.050) + oneToFive[1.75] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050, 0.050, 0.060, 0.060, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050) + oneToFive[2.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.075, 0.050, 0.050, 0.065, 0.065, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050) + oneToFive[2.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.100, 0.100, 0.075, 0.060, 0.060, 0.070, 0.070, 0.100, 0.100, 0.050, 0.050, 0.050, 0.125, 0.150, 0.125, 0.065, 0.050) + oneToFive[2.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.125, 0.125, 0.100, 0.065, 0.065, 0.075, 0.075, 0.125, 0.125, 0.060, 0.060, 0.060, 0.150, 0.150, 0.150, 0.070, 0.060) + oneToFive[2.75] = arrayOf(0.075, 0.075, 0.075, 0.100, 0.100, 0.100, 0.125, 0.150, 0.125, 0.100, 0.070, 0.070, 0.080, 0.080, 0.150, 0.150, 0.070, 0.070, 0.070, 0.175, 0.175, 0.175, 0.080, 0.070) + oneToFive[3.25] = arrayOf(0.100, 0.100, 0.100, 0.125, 0.125, 0.125, 0.150, 0.150, 0.150, 0.100, 0.080, 0.080, 0.100, 0.100, 0.175, 0.175, 0.075, 0.075, 0.075, 0.200, 0.200, 0.200, 0.090, 0.080) + oneToFive[3.75] = arrayOf(0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.175, 0.175, 0.175, 0.100, 0.085, 0.085, 0.110, 0.110, 0.185, 0.185, 0.080, 0.080, 0.080, 0.225, 0.225, 0.225, 0.100, 0.090) + oneToFive[4.25] = arrayOf(0.125, 0.125, 0.130, 0.140, 0.140, 0.140, 0.200, 0.200, 0.200, 0.125, 0.090, 0.090, 0.120, 0.120, 0.200, 0.200, 0.100, 0.100, 0.100, 0.250, 0.250, 0.250, 0.125, 0.100) + oneToFive[4.75] = arrayOf(0.125, 0.130, 0.135, 0.150, 0.150, 0.150, 0.200, 0.225, 0.200, 0.125, 0.100, 0.100, 0.125, 0.125, 0.250, 0.200, 0.110, 0.125, 0.125, 0.275, 0.275, 0.275, 0.130, 0.125) + oneToFive[5.25] = arrayOf(0.150, 0.150, 0.150, 0.170, 0.170, 0.170, 0.225, 0.225, 0.225, 0.130, 0.125, 0.125, 0.140, 0.140, 0.250, 0.250, 0.150, 0.150, 0.150, 0.300, 0.300, 0.300, 0.150, 0.150) + oneToFive[6.00] = arrayOf(0.170, 0.170, 0.175, 0.200, 0.200, 0.200, 0.250, 0.250, 0.250, 0.150, 0.125, 0.125, 0.150, 0.150, 0.275, 0.275, 0.170, 0.150, 0.150, 0.350, 0.350, 0.350, 0.175, 0.150) + oneToFive[6.75] = arrayOf(0.200, 0.200, 0.200, 0.225, 0.225, 0.225, 0.275, 0.275, 0.275, 0.200, 0.130, 0.130, 0.175, 0.175, 0.300, 0.300, 0.170, 0.175, 0.175, 0.375, 0.375, 0.375, 0.200, 0.175) + oneToFive[7.50] = arrayOf(0.225, 0.230, 0.235, 0.250, 0.250, 0.250, 0.300, 0.300, 0.300, 0.250, 0.150, 0.150, 0.200, 0.200, 0.325, 0.325, 0.200, 0.200, 0.200, 0.400, 0.450, 0.400, 0.350, 0.200) + + sixToEleven[5.26] = arrayOf(0.18, 0.18, 0.18, 0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.18, 0.15, 0.13, 0.15, 0.15, 0.25, 0.25, 0.20, 0.15, 0.18, 0.25, 0.25, 0.25, 0.23, 0.20) + sixToEleven[5.61] = arrayOf(0.18, 0.20, 0.20, 0.23, 0.23, 0.25, 0.28, 0.28, 0.25, 0.20, 0.15, 0.13, 0.15, 0.18, 0.25, 0.25, 0.20, 0.15, 0.18, 0.28, 0.25, 0.25, 0.23, 0.20) + sixToEleven[5.93] = arrayOf(0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.30, 0.30, 0.30, 0.25, 0.15, 0.15, 0.18, 0.18, 0.28, 0.28, 0.20, 0.20, 0.20, 0.28, 0.28, 0.28, 0.25, 0.23) + sixToEleven[6.26] = arrayOf(0.20, 0.23, 0.23, 0.25, 0.25, 0.28, 0.33, 0.30, 0.30, 0.25, 0.18, 0.15, 0.18, 0.18, 0.28, 0.28, 0.23, 0.20, 0.20, 0.28, 0.30, 0.28, 0.25, 0.23) + sixToEleven[6.60] = arrayOf(0.23, 0.23, 0.25, 0.25, 0.25, 0.28, 0.33, 0.33, 0.33, 0.28, 0.18, 0.15, 0.18, 0.18, 0.30, 0.28, 0.23, 0.23, 0.20, 0.30, 0.30, 0.30, 0.25, 0.25) + sixToEleven[7.26] = arrayOf(0.23, 0.25, 0.28, 0.28, 0.30, 0.33, 0.38, 0.35, 0.35, 0.30, 0.18, 0.18, 0.18, 0.19, 0.33, 0.30, 0.25, 0.23, 0.23, 0.33, 0.33, 0.33, 0.30, 0.25) + sixToEleven[7.92] = arrayOf(0.25, 0.25, 0.28, 0.30, 0.33, 0.35, 0.38, 0.38, 0.38, 0.35, 0.20, 0.20, 0.23, 0.25, 0.35, 0.33, 0.30, 0.25, 0.25, 0.35, 0.35, 0.35, 0.33, 0.28) + sixToEleven[8.57] = arrayOf(0.28, 0.28, 0.30, 0.30, 0.33, 0.38, 0.40, 0.43, 0.40, 0.38, 0.25, 0.25, 0.25, 0.28, 0.38, 0.38, 0.33, 0.28, 0.28, 0.38, 0.40, 0.38, 0.35, 0.30) + sixToEleven[9.24] = arrayOf(0.30, 0.33, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.43, 0.40, 0.30, 0.25, 0.28, 0.28, 0.38, 0.40, 0.33, 0.30, 0.30, 0.40, 0.43, 0.40, 0.38, 0.35) + sixToEleven[9.89] = arrayOf(0.35, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.48, 0.45, 0.40, 0.30, 0.25, 0.28, 0.30, 0.40, 0.43, 0.35, 0.33, 0.33, 0.43, 0.45, 0.43, 0.40, 0.38) + sixToEleven[10.56] = arrayOf(0.38, 0.38, 0.40, 0.43, 0.45, 0.45, 0.48, 0.50, 0.48, 0.40, 0.35, 0.25, 0.30, 0.33, 0.43, 0.45, 0.35, 0.35, 0.35, 0.45, 0.48, 0.45, 0.43, 0.40) + sixToEleven[11.21] = arrayOf(0.40, 0.43, 0.43, 0.45, 0.48, 0.50, 0.53, 0.55, 0.50, 0.40, 0.35, 0.30, 0.33, 0.33, 0.45, 0.48, 0.38, 0.35, 0.37, 0.50, 0.50, 0.48, 0.45, 0.43) + sixToEleven[11.88] = arrayOf(0.43, 0.43, 0.45, 0.45, 0.48, 0.50, 0.55, 0.58, 0.50, 0.40, 0.35, 0.33, 0.33, 0.33, 0.48, 0.50, 0.40, 0.38, 0.38, 0.53, 0.53, 0.50, 0.48, 0.45) + sixToEleven[12.53] = arrayOf(0.45, 0.45, 0.48, 0.50, 0.53, 0.55, 0.60, 0.60, 0.60, 0.45, 0.40, 0.35, 0.35, 0.38, 0.50, 0.53, 0.40, 0.38, 0.38, 0.55, 0.58, 0.55, 0.50, 0.48) + sixToEleven[13.19] = arrayOf(0.48, 0.48, 0.50, 0.55, 0.58, 0.60, 0.65, 0.65, 0.65, 0.50, 0.45, 0.36, 0.38, 0.40, 0.55, 0.55, 0.45, 0.40, 0.40, 0.60, 0.60, 0.58, 0.55, 0.50) + sixToEleven[14.18] = arrayOf(0.53, 0.53, 0.55, 0.60, 0.65, 0.68, 0.70, 0.70, 0.68, 0.60, 0.55, 0.40, 0.40, 0.45, 0.60, 0.60, 0.50, 0.45, 0.45, 0.63, 0.65, 0.63, 0.60, 0.60) + sixToEleven[15.17] = arrayOf(0.55, 0.58, 0.60, 0.65, 0.70, 0.70, 0.75, 0.75, 0.70, 0.65, 0.60, 0.42, 0.42, 0.45, 0.65, 0.65, 0.60, 0.50, 0.50, 0.68, 0.68, 0.65, 0.63, 0.63) + sixToEleven[16.50] = arrayOf(0.60, 0.63, 0.65, 0.70, 0.70, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.45, 0.45, 0.50, 0.65, 0.70, 0.60, 0.55, 0.55, 0.75, 0.75, 0.70, 0.65, 0.65) + + twelveToSeventeen[10.70] = arrayOf(0.30, 0.30, 0.30, 0.30, 0.40, 0.40, 0.60, 0.60, 0.60, 0.40, 0.35, 0.30, 0.30, 0.35, 0.45, 0.50, 0.40, 0.30, 0.30, 0.40, 0.50, 0.40, 0.40, 0.30) + twelveToSeventeen[11.10] = arrayOf(0.30, 0.30, 0.30, 0.35, 0.40, 0.45, 0.60, 0.60, 0.60, 0.40, 0.40, 0.30, 0.35, 0.40, 0.50, 0.50, 0.30, 0.30, 0.30, 0.50, 0.50, 0.50, 0.30, 0.30) + twelveToSeventeen[11.60] = arrayOf(0.30, 0.30, 0.35, 0.45, 0.45, 0.50, 0.65, 0.65, 0.65, 0.45, 0.40, 0.40, 0.40, 0.40, 0.50, 0.55, 0.55, 0.45, 0.45, 0.50, 0.50, 0.50, 0.40, 0.40) + twelveToSeventeen[13.00] = arrayOf(0.40, 0.40, 0.40, 0.50, 0.55, 0.60, 0.70, 0.70, 0.70, 0.60, 0.50, 0.40, 0.40, 0.40, 0.50, 0.60, 0.60, 0.50, 0.50, 0.60, 0.60, 0.60, 0.40, 0.30) + twelveToSeventeen[15.60] = arrayOf(0.45, 0.50, 0.50, 0.60, 0.65, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.60, 0.50, 0.50, 0.60, 0.70, 0.70, 0.60, 0.60, 0.60, 0.70, 0.70, 0.50, 0.50) + twelveToSeventeen[17.00] = arrayOf(0.50, 0.55, 0.60, 0.70, 0.75, 0.80, 1.00, 1.00, 1.00, 0.80, 0.70, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.65, 0.65, 0.65, 0.70, 0.70, 0.60, 0.60) + twelveToSeventeen[18.00] = arrayOf(0.60, 0.65, 0.70, 0.80, 0.85, 0.90, 1.10, 1.10, 1.10, 0.90, 0.80, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.70, 0.65, 0.70, 0.75, 0.70, 0.60, 0.60) + twelveToSeventeen[20.20] = arrayOf(0.70, 0.75, 0.80, 0.90, 0.95, 1.00, 1.10, 1.10, 1.10, 0.90, 0.80, 0.70, 0.70, 0.70, 0.80, 0.90, 0.90, 0.75, 0.75, 0.75, 0.80, 0.80, 0.70, 0.70) + twelveToSeventeen[21.60] = arrayOf(0.75, 0.80, 0.90, 0.90, 1.00, 1.00, 1.20, 1.20, 1.20, 0.90, 0.80, 0.70, 0.70, 0.70, 0.90, 1.00, 1.00, 0.80, 0.80, 0.80, 0.80, 0.80, 0.70, 0.70) + twelveToSeventeen[23.80] = arrayOf(0.75, 0.80, 0.90, 1.00, 1.10, 1.10, 1.20, 1.20, 1.20, 1.00, 0.90, 0.80, 0.80, 0.80, 0.90, 1.10, 1.10, 0.90, 0.90, 0.90, 1.00, 1.00, 0.80, 0.80) + twelveToSeventeen[26.10] = arrayOf(0.80, 0.80, 0.90, 1.00, 1.20, 1.20, 1.30, 1.30, 1.30, 1.10, 1.00, 0.90, 0.90, 0.90, 1.00, 1.20, 1.10, 0.90, 0.90, 1.00, 1.00, 1.00, 0.90, 0.90) + twelveToSeventeen[28.00] = arrayOf(0.90, 0.90, 1.00, 1.10, 1.10, 1.20, 1.30, 1.30, 1.30, 1.20, 1.00, 1.00, 1.00, 1.00, 1.20, 1.20, 1.20, 1.00, 1.00, 1.10, 1.10, 1.10, 0.90, 0.90) + twelveToSeventeen[30.10] = arrayOf(1.00, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.50, 1.50, 1.30, 1.20, 1.00, 1.00, 1.00, 1.30, 1.40, 1.40, 1.00, 1.00, 1.15, 1.15, 1.10, 1.00, 1.00) + twelveToSeventeen[32.60] = arrayOf(1.10, 1.10, 1.20, 1.20, 1.40, 1.50, 1.50, 1.50, 1.50, 1.30, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.40, 1.10, 1.10, 1.20, 1.20, 1.20, 1.10, 1.10) + twelveToSeventeen[35.20] = arrayOf(1.20, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.70, 1.50, 1.40, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.60, 1.40, 1.20, 1.20, 1.30, 1.30, 1.20, 1.20) + twelveToSeventeen[39.00] = arrayOf(1.30, 1.30, 1.40, 1.60, 1.60, 1.60, 1.90, 1.90, 1.90, 1.50, 1.30, 1.20, 1.20, 1.30, 1.50, 1.60, 1.70, 1.80, 1.50, 1.50, 1.60, 1.60, 1.30, 1.30) + twelveToSeventeen[42.80] = arrayOf(1.40, 1.40, 1.50, 1.70, 1.80, 1.80, 2.00, 2.00, 2.00, 1.80, 1.80, 1.50, 1.50, 1.50, 1.60, 1.70, 1.80, 1.90, 1.60, 1.60, 1.70, 1.70, 1.50, 1.50) + twelveToSeventeen[47.30] = arrayOf(1.50, 1.50, 1.70, 1.70, 2.00, 2.00, 2.20, 2.30, 2.20, 2.00, 1.80, 1.60, 1.60, 1.60, 1.80, 2.00, 2.10, 1.90, 1.80, 1.80, 2.00, 2.00, 1.60, 1.60) + } + + private fun closest(map: TreeMap>, key: Double): Array? { + val low = map.floorEntry(key) + val high = map.ceilingEntry(key) + var res: Array? = null + if (low != null && high != null) { + res = if (Math.abs(key - low.key) < Math.abs(key - high.key)) + low.value + else + high.value + } else if (low != null || high != null) { + res = if (low != null) low.value else high.value + } + return res + } + + fun arrayToJson(b: Array): JSONArray { + val basals = JSONArray() + for (i in 0..23) { + val time = String.format(Locale.ENGLISH, "%02d:00", i) + basals.put(JSONObject().put("time", time).put("value", b[i].toString())) + } + return basals + } + + fun singleValueArray(value: Double, sample: Array): JSONArray { + val array = JSONArray() + array.put(JSONObject().put("time", "00:00").put("value", value + sample[0])) + array.put(JSONObject().put("time", "06:00").put("value", value + sample[1])) + array.put(JSONObject().put("time", "09:00").put("value", value + sample[2])) + array.put(JSONObject().put("time", "11:00").put("value", value + sample[3])) + array.put(JSONObject().put("time", "14:00").put("value", value + sample[4])) + array.put(JSONObject().put("time", "16:00").put("value", value + sample[5])) + array.put(JSONObject().put("time", "19:00").put("value", value + sample[6])) + return array + } +} \ No newline at end of file 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 9fa3ab9929..20bad315e8 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -1593,14 +1593,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { // ---------------- ProfileSwitch handling --------------- - public List getProfileSwitchData(boolean ascending) { + public List getProfileSwitchData(long from, boolean ascending) { try { Dao daoProfileSwitch = getDaoProfileSwitch(); List profileSwitches; QueryBuilder queryBuilder = daoProfileSwitch.queryBuilder(); queryBuilder.orderBy("date", ascending); queryBuilder.limit(100L); + Where where = queryBuilder.where(); + where.ge("date", from); + queryBuilder.setCountOf(true); PreparedQuery preparedQuery = queryBuilder.prepare(); + long count = daoProfileSwitch.countOf(preparedQuery); + // now do query of count + 1 + queryBuilder = daoProfileSwitch.queryBuilder(); + queryBuilder.orderBy("date", ascending); + queryBuilder.limit(count + 1); + preparedQuery = queryBuilder.prepare(); profileSwitches = daoProfileSwitch.query(preparedQuery); return profileSwitches; } catch (SQLException e) { diff --git a/app/src/main/java/info/nightscout/androidaps/db/TDD.java b/app/src/main/java/info/nightscout/androidaps/db/TDD.java index 93a228316c..0be693c5a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/TDD.java +++ b/app/src/main/java/info/nightscout/androidaps/db/TDD.java @@ -6,6 +6,8 @@ import com.j256.ormlite.table.DatabaseTable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; @@ -56,4 +58,8 @@ public class TDD { ", total=" + total + ']'; } + + public String toText() { + return MainApp.gs(R.string.tddformat, total, bolus, basal); + } } 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 195005e87a..480a387214 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 @@ -100,11 +100,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Override protected void onStart() { MainApp.bus().register(this); - initializeTempBasalData(); - initializeTreatmentData(); - initializeExtendedBolusData(); - initializeTempTargetData(); - initializeProfileSwitchData(); + initializeData(range()); super.onStart(); } @@ -118,61 +114,61 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface return this.service; } - private void initializeTreatmentData() { + private long range() { + double dia = Constants.defaultDIA; + if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) + dia = ProfileFunctions.getInstance().getProfile().getDia(); + return (long) (60 * 60 * 1000L * (24 + dia)); + } + + public void initializeData(long range) { + initializeTempBasalData(range); + initializeTreatmentData(range); + initializeExtendedBolusData(range); + initializeTempTargetData(range); + initializeProfileSwitchData(range); + } + + private void initializeTreatmentData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeTreatmentData"); - double dia = Constants.defaultDIA; - if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) - dia = ProfileFunctions.getInstance().getProfile().getDia(); - long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); synchronized (treatments) { treatments.clear(); - treatments.addAll(getService().getTreatmentDataFromTime(fromMills, false)); + treatments.addAll(getService().getTreatmentDataFromTime(DateUtil.now() - range, false)); } } - private void initializeTempBasalData() { + private void initializeTempBasalData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeTempBasalData"); - double dia = Constants.defaultDIA; - if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) - dia = ProfileFunctions.getInstance().getProfile().getDia(); - long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); - synchronized (tempBasals) { - tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(fromMills, false)); + tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(DateUtil.now() - range, false)); } } - private void initializeExtendedBolusData() { + private void initializeExtendedBolusData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeExtendedBolusData"); - double dia = Constants.defaultDIA; - if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) - dia = ProfileFunctions.getInstance().getProfile().getDia(); - long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); - synchronized (extendedBoluses) { - extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(fromMills, false)); + extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(DateUtil.now() - range, false)); } } - private void initializeTempTargetData() { + private void initializeTempTargetData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeTempTargetData"); synchronized (tempTargets) { - long fromMills = System.currentTimeMillis() - 60 * 60 * 1000L * 24; - tempTargets.reset().add(MainApp.getDbHelper().getTemptargetsDataFromTime(fromMills, false)); + tempTargets.reset().add(MainApp.getDbHelper().getTemptargetsDataFromTime(DateUtil.now() - range, false)); } } - private void initializeProfileSwitchData() { + private void initializeProfileSwitchData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeProfileSwitchData"); synchronized (profiles) { - profiles.reset().add(MainApp.getDbHelper().getProfileSwitchData(false)); + profiles.reset().add(MainApp.getDbHelper().getProfileSwitchData(DateUtil.now() - range, false)); } } @@ -222,7 +218,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface if (!pumpInterface.isFakingTempsByExtendedBoluses()) synchronized (extendedBoluses) { - for (Integer pos = 0; pos < extendedBoluses.size(); pos++) { + for (int pos = 0; pos < extendedBoluses.size(); pos++) { ExtendedBolus e = extendedBoluses.get(pos); if (e.date > time) continue; IobTotal calc = e.iobCalc(time); @@ -391,8 +387,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface public void onStatusEvent(final EventReloadTreatmentData ev) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("EventReloadTreatmentData"); - initializeTreatmentData(); - initializeExtendedBolusData(); + initializeTreatmentData(range()); + initializeExtendedBolusData(range()); updateTotalIOBTreatments(); MainApp.bus().post(ev.next); } @@ -402,7 +398,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface public void onStatusEvent(final EventReloadTempBasalData ev) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("EventReloadTempBasalData"); - initializeTempBasalData(); + initializeTempBasalData(range()); updateTotalIOBTempBasals(); } @@ -685,7 +681,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Subscribe @SuppressWarnings("unused") public void onStatusEvent(final EventTempTargetChange ev) { - initializeTempTargetData(); + initializeTempTargetData(range()); } @Nullable @@ -722,7 +718,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Subscribe @SuppressWarnings("unused") public void onStatusEvent(final EventReloadProfileSwitchData ev) { - initializeProfileSwitchData(); + initializeProfileSwitchData(range()); } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt index a27ebfb656..2256f6538e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment +import info.nightscout.androidaps.Constants import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile @@ -14,16 +15,21 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import kotlinx.android.synthetic.main.close.* import kotlinx.android.synthetic.main.profileviewer_fragment.* +import org.json.JSONObject class ProfileViewerDialog : DialogFragment() { private var time: Long = 0 enum class Mode(val i: Int) { RUNNING_PROFILE(1), - PUMP_PROFILE(2) + PUMP_PROFILE(2), + CUSTOM_PROFILE(3) } - private var mode: Mode = Mode.RUNNING_PROFILE; + private var mode: Mode = Mode.RUNNING_PROFILE + private var customProfileJson: String = "" + private var customProfileName: String = "" + private var customProfileUnits: String = Constants.MGDL override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -31,6 +37,9 @@ class ProfileViewerDialog : DialogFragment() { (savedInstanceState ?: arguments)?.let { bundle -> time = bundle.getLong("time", 0) mode = Mode.values()[bundle.getInt("mode", Mode.RUNNING_PROFILE.ordinal)] + customProfileJson = bundle.getString("customProfile", "") + customProfileUnits = bundle.getString("customProfileUnits", Constants.MGDL) + customProfileName = bundle.getString("customProfileName", "") } return inflater.inflate(R.layout.profileviewer_fragment, container, false) @@ -64,6 +73,13 @@ class ProfileViewerDialog : DialogFragment() { profileview_reload.visibility = View.VISIBLE profileview_datelayout.visibility = View.GONE } + Mode.CUSTOM_PROFILE -> { + profile = Profile(JSONObject(customProfileJson), customProfileUnits) + profileName = customProfileName + date = "" + profileview_reload.visibility = View.GONE + profileview_datelayout.visibility = View.GONE + } } profileview_noprofile.visibility = View.VISIBLE @@ -92,6 +108,9 @@ class ProfileViewerDialog : DialogFragment() { super.onSaveInstanceState(bundle) bundle.putLong("time", time) bundle.putInt("mode", mode.ordinal) + bundle.putString("customProfile", customProfileJson) + bundle.putString("customProfileName", customProfileName) + bundle.putString("customProfileUnits", customProfileUnits) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java index 71d8eb2b18..3b5e5bf56d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java @@ -40,6 +40,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.SP; +import info.nightscout.androidaps.utils.T; /** * Created by mike on 13/01/17. @@ -183,7 +184,7 @@ public class TreatmentsProfileSwitchFragment extends SubscriberFragment implemen llm = new LinearLayoutManager(view.getContext()); recyclerView.setLayoutManager(llm); - RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(false)); + RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(DateUtil.now() - T.days(30).msecs(), false)); recyclerView.setAdapter(adapter); refreshFromNS = (Button) view.findViewById(R.id.profileswitch_refreshfromnightscout); @@ -230,7 +231,7 @@ public class TreatmentsProfileSwitchFragment extends SubscriberFragment implemen activity.runOnUiThread(new Runnable() { @Override public void run() { - recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(false)), false); + recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(DateUtil.now() - T.days(30).msecs(),false)), false); } }); } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TIR.kt b/app/src/main/java/info/nightscout/androidaps/utils/TIR.kt new file mode 100644 index 0000000000..9d0d662f5e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/TIR.kt @@ -0,0 +1,5 @@ +package info.nightscout.androidaps.utils + +class TIR(val low: Double, val high: Double) { + +} diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt new file mode 100644 index 0000000000..de71bb3e51 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt @@ -0,0 +1,70 @@ +package info.nightscout.androidaps.utils + +import android.util.LongSparseArray +import info.nightscout.androidaps.MainApp +import info.nightscout.androidaps.R +import info.nightscout.androidaps.db.TDD +import info.nightscout.androidaps.logging.L +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import org.slf4j.LoggerFactory + +object TddCalculator : TreatmentsPlugin() { + private val log = LoggerFactory.getLogger(L.DATATREATMENTS) + + fun calculate(days: Long): LongSparseArray { + val range = T.days(days + 1).msecs() + val startTime = MidnightTime.calc(DateUtil.now()) - T.days(days).msecs() + val endTime = MidnightTime.calc(DateUtil.now()) + initializeData(range) + + + val result = LongSparseArray() + for (t in treatmentsFromHistory) { + if (!t.isValid) continue + if (t.date < startTime || t.date > endTime) continue + val midnight = MidnightTime.calc(t.date) + val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0) + tdd.bolus += t.insulin + result.put(midnight, tdd) + } + + for (t in startTime until endTime step T.mins(5).msecs()) { + val midnight = MidnightTime.calc(t) + val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0) + val tbr = getTempBasalFromHistory(t) + val profile = ProfileFunctions.getInstance().getProfile(t) ?: continue + val absoluteRate = tbr?.tempBasalConvertedToAbsolute(t, profile) ?: profile.getBasal(t) + tdd.basal += absoluteRate / 60.0 * 5.0 + result.put(midnight, tdd) + } + for (i in 0 until result.size()) { + val tdd = result.valueAt(i) + tdd.total = tdd.bolus + tdd.basal + } + log.debug(result.toString()) + return result + } + + fun averageTDD(tdds: LongSparseArray): TDD { + val totalTdd = TDD() + for (i in 0 until tdds.size()) { + val tdd = tdds.valueAt(i) + totalTdd.basal += tdd.basal + totalTdd.bolus += tdd.bolus + totalTdd.total += tdd.total + } + totalTdd.basal /= tdds.size().toDouble() + totalTdd.bolus /= tdds.size().toDouble() + totalTdd.total /= tdds.size().toDouble() + return totalTdd + } + + fun toText(tdds: LongSparseArray) : String { + var t = "" + for (i in 0 until tdds.size()) { + t += "${tdds.valueAt(i).toText()}\n" + } + return t + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt new file mode 100644 index 0000000000..3fb4bc6fa5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.utils + +import android.util.LongSparseArray + +object TirCalculator { + fun calculate(days: Long): LongSparseArray { + + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/survey_fragment.xml b/app/src/main/res/layout/survey_fragment.xml new file mode 100644 index 0000000000..7032dbe803 --- /dev/null +++ b/app/src/main/res/layout/survey_fragment.xml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +