* Generic persistence property helper class */ public class Persist { + private static final java.lang.String PREF_TIMEOUT = "TIMEOUT__"; + @RequiredArgsConstructor public static class String { private final java.lang.String pref; @@ -40,4 +44,45 @@ public void set(final long value) { setLong(pref, value); } } + + public static class LongTimeout extends Long { + + private final long millis; + + public LongTimeout(final java.lang.String pref, final long millis) { + super(pref); + this.millis = millis; + } + + public void set() { + set(tsl()); + } + + public boolean expired() { + return msSince(get()) > millis; + } + } + + public static class StringTimeout extends String { + + private final LongTimeout timeout; + + public StringTimeout(final java.lang.String pref, final long millis) { + super(pref); + timeout = new LongTimeout(PREF_TIMEOUT + pref, millis); + } + + @Override + public void set(final java.lang.String value) { + super.set(value); + timeout.set(); + } + + @Override + public java.lang.String get() { + return !timeout.expired() ? super.get() : null; + } + + } + } diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/insulin/aaps/AAPSStatusHandler.java b/app/src/main/java/com/eveningoutpost/dexdrip/insulin/aaps/AAPSStatusHandler.java new file mode 100644 index 0000000000..65fefbf46d --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/insulin/aaps/AAPSStatusHandler.java @@ -0,0 +1,75 @@ +package com.eveningoutpost.dexdrip.insulin.aaps; + +import com.eveningoutpost.dexdrip.alert.Persist; +import com.eveningoutpost.dexdrip.models.UserError.Log; +import com.eveningoutpost.dexdrip.utilitymodels.Constants; +import com.eveningoutpost.dexdrip.utilitymodels.PumpStatus; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import info.nightscout.sdk.localmodel.devicestatus.NSDeviceStatus; +import lombok.val; + +/** + * JamOrHam + *
+ * Handle processing of AAPS device status updates + */ + +public class AAPSStatusHandler { + + private static final String TAG = AAPSStatusHandler.class.getSimpleName(); + private static final Gson gson = new GsonBuilder().create(); + private static final Persist.StringTimeout store = + new Persist.StringTimeout("AAPS_DEVICE_STATUS", Constants.MINUTE_IN_MS * 21); + private static volatile NSDeviceStatus last; + + // process and store received json in to object and maintain persistent time limited cache + public static void processDeviceStatus(final String json) { + synchronized (AAPSStatusHandler.class) { + try { + last = gson.fromJson(json, NSDeviceStatus.class); + Log.d(TAG, "DEBUG: got device status: " + last.toString()); + if (last != null) { + store.set(json); + val pump = last.getPump(); + if (pump != null) { + val r = pump.getReservoir(); + if (r != null) { + PumpStatus.setReservoir(r); + } + val b = pump.getBattery(); + if (b != null) { + val pc = b.getPercent(); + if (pc != null) { + PumpStatus.setBattery(pc); + } + } + } + } + } catch (Exception e) { + Log.e(TAG, "Error processing device status: " + e); + } + } + } + + // get instance either from cache or persistent store if still valid + public static NSDeviceStatus get() { + synchronized (AAPSStatusHandler.class) { + val json = store.get(); // local copy + if (json != null) { + if (last == null) { + // needs reconstructing + try { + last = gson.fromJson(json, NSDeviceStatus.class); + } catch (Exception e) { + Log.wtf(TAG, "Unusual problem reconstructing device status: " + e); + } + } + return last; + } + return null; + } + } + +} diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java b/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java index 48bca899bd..67f316c86c 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java @@ -694,6 +694,10 @@ public static synchronized boolean pushTreatmentFromJson(String json, boolean fr Log.d(TAG, "Skipping Temp Basal msg"); return false; } + if (mytreatment.timestamp < 1) { + Log.e(TAG, "Invalid treatment timestamp or 0 or less"); + return false; + } if (mytreatment.uuid == null) { try { diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Intents.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Intents.java index 4bfb4078ba..c6ee4c6827 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Intents.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Intents.java @@ -37,6 +37,8 @@ public interface Intents { // From NS Android Client // send String ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT"; + String ACTION_NEW_FOOD = "info.nightscout.client.NEW_FOOD"; + String ACTION_NEW_DEVICESTATUS = "info.nightscout.client.NEW_DEVICESTATUS"; String ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT"; String ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT"; String ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE"; diff --git a/app/src/test/java/com/eveningoutpost/dexdrip/alert/PersistTest.java b/app/src/test/java/com/eveningoutpost/dexdrip/alert/PersistTest.java new file mode 100644 index 0000000000..35ee313ba4 --- /dev/null +++ b/app/src/test/java/com/eveningoutpost/dexdrip/alert/PersistTest.java @@ -0,0 +1,53 @@ +package com.eveningoutpost.dexdrip.alert; + + +import com.eveningoutpost.dexdrip.RobolectricTestWithConfig; +import com.eveningoutpost.dexdrip.models.JoH; +import com.eveningoutpost.dexdrip.utilitymodels.Constants; +import com.eveningoutpost.dexdrip.utilitymodels.PersistentStore; + +import static com.google.common.truth.Truth.assertWithMessage; + +import org.junit.Test; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowSystemClock; + +import java.time.Duration; + +import lombok.val; + +@Config(instrumentedPackages = {"com.eveningoutpost.dexdrip.models.JoH"}) +public class PersistTest extends RobolectricTestWithConfig { + + @Test + public void testTimeoutString() { + + val PREF_NAME = "TEST_TIMEOUT_STRING"; + val testString = "Hello world"; + + // setup + PersistentStore.removeItem(PREF_NAME); + ShadowSystemClock.advanceBy(Duration.ofHours(100)); + + val store = + new Persist.StringTimeout(PREF_NAME, Constants.MINUTE_IN_MS * 21); + + assertWithMessage("Time not zero").that(JoH.tsl()).isGreaterThan(Constants.HOUR_IN_MS); + assertWithMessage("test empty null").that(store.get()).isNull(); + + store.set(testString); + assertWithMessage("test ok 1").that(store.get()).isEqualTo(testString); + ShadowSystemClock.advanceBy(Duration.ofMinutes(1)); + assertWithMessage("test ok 2").that(store.get()).isEqualTo(testString); + ShadowSystemClock.advanceBy(Duration.ofMinutes(10)); + assertWithMessage("test ok 3").that(store.get()).isEqualTo(testString); + ShadowSystemClock.advanceBy(Duration.ofMinutes(11)); + assertWithMessage("test expired 4").that(store.get()).isNull(); + ShadowSystemClock.advanceBy(Duration.ofMinutes(11)); + assertWithMessage("test expired 5").that(store.get()).isNull(); + store.set(testString); + ShadowSystemClock.advanceBy(Duration.ofMinutes(10)); + assertWithMessage("test ok 4").that(store.get()).isEqualTo(testString); + } + +} \ No newline at end of file