Skip to content

Commit

Permalink
Improve device status handling
Browse files Browse the repository at this point in the history
  • Loading branch information
jamorham committed Jun 17, 2023
1 parent 745d695 commit ec2f90f
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 7 deletions.
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,12 @@
<intent-filter>
<action android:name="info.nightscout.client.NS_BRIDGE" />
</intent-filter>
<intent-filter>
<action android:name="info.nightscout.client.NEW_FOOD" />
</intent-filter>
<intent-filter>
<action android:name="info.nightscout.client.NEW_DEVICESTATUS" />
</intent-filter>
<intent-filter>
<action android:name="info.nightscout.client.NEW_SGV" />
</intent-filter>
Expand Down
16 changes: 10 additions & 6 deletions app/src/main/java/com/eveningoutpost/dexdrip/NSClientReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.preference.PreferenceManager;
import android.util.Log;

import com.eveningoutpost.dexdrip.insulin.aaps.AAPSStatusHandler;
import com.eveningoutpost.dexdrip.models.BgReading;
import com.eveningoutpost.dexdrip.models.JoH;
import com.eveningoutpost.dexdrip.models.Treatments;
Expand All @@ -19,7 +20,6 @@
import com.eveningoutpost.dexdrip.utilitymodels.Intents;
import com.eveningoutpost.dexdrip.utilitymodels.Pref;
import com.eveningoutpost.dexdrip.profileeditor.ImportAapsProfile;
import com.google.gson.GsonBuilder;

import org.json.JSONArray;
import org.json.JSONException;
Expand All @@ -28,7 +28,6 @@
import java.util.HashMap;
import java.util.UUID;

import info.nightscout.sdk.localmodel.devicestatus.NSDeviceStatus;
import lombok.val;


Expand Down Expand Up @@ -60,16 +59,15 @@ public void onReceive(Context context, Intent intent) {
if (action == null) return;

switch (action) {
case Intents.ACTION_NEW_DEVICESTATUS:
case Intents.ACTION_NS_BRIDGE:
if (bundle == null) break;
if (prefs.getBoolean("accept_nsclient_treatments", true)) {

final String device_status_json = bundle.getString("devicestatus", "");
if (!emptyString(device_status_json)) {
try {
val gson = new GsonBuilder().create(); // TODO optimize
val ds = gson.fromJson(device_status_json, NSDeviceStatus.class);
Log.e(TAG, "DEBUG: got device status: " + ds.toString());
AAPSStatusHandler.processDeviceStatus(device_status_json);
} catch (Exception e) {
Log.e(TAG, "Exception processing device status in NS_BRIDGE action: " + e);
}
Expand Down Expand Up @@ -104,6 +102,7 @@ public void onReceive(Context context, Intent intent) {
}
break;

case Intents.ACTION_NEW_FOOD: // action changed unexpectedly
case Intents.ACTION_NEW_TREATMENT:
if (bundle == null) break;
if (prefs.getBoolean("accept_nsclient_treatments", true)) {
Expand Down Expand Up @@ -281,7 +280,12 @@ private String toTreatmentJSON(HashMap<String, Object> trt_map) {
try {
// jsonObject.put("uuid", UUID.fromString(trt_map.get("_id").toString()).toString());

jsonObject.put("timestamp", trt_map.get("mills"));
Object ts = trt_map.get("mills");
if (ts == null) {
ts = trt_map.get("date"); // identifier changed at some point
}

jsonObject.put("timestamp", ts);
jsonObject.put("eventType", trt_map.get("eventType"));
jsonObject.put("enteredBy", trt_map.get("enteredBy"));
if (trt_map.containsKey("carbs")) {
Expand Down
47 changes: 46 additions & 1 deletion app/src/main/java/com/eveningoutpost/dexdrip/alert/Persist.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.eveningoutpost.dexdrip.alert;

import static com.eveningoutpost.dexdrip.models.JoH.msSince;
import static com.eveningoutpost.dexdrip.models.JoH.tsl;
import static com.eveningoutpost.dexdrip.utilitymodels.PersistentStore.getLong;
import static com.eveningoutpost.dexdrip.utilitymodels.PersistentStore.getString;
import static com.eveningoutpost.dexdrip.utilitymodels.PersistentStore.setLong;
Expand All @@ -9,12 +11,14 @@

/**
* JamOrHam
*
* <p>
* 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;
Expand All @@ -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;
}

}

}
Original file line number Diff line number Diff line change
@@ -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
* <p>
* 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;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}

}

0 comments on commit ec2f90f

Please sign in to comment.