diff --git a/app/build.gradle b/app/build.gradle index 13710f83b2adda6231962da4fd5883ef4fe80932..a8b8c6dadedc0cf41970a355f31ff8b7a0592d5f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -51,8 +51,15 @@ def getBugfenderApiKey() { String bugfenderApiKey = System.getenv("BUGFENDER_API_KEY") if(bugfenderApiKey == null) { - logger.warn("Bugfender API key not set") - bugfenderApiKey = "" + File file = new File("app/bugfender.properties") + if (file.exists()) { + Properties properties = new Properties() + properties.load(new FileInputStream(file.getAbsolutePath().toString())) + bugfenderApiKey = properties.getProperty("apiKey", "") + } else { + logger.warn("Bugfender API key not set") + bugfenderApiKey = "" + } } return "\"" + bugfenderApiKey + "\"" diff --git a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java index f8f625ecdd33c35a36cdb1499af05e32011e1c9a..e458cdbb43aab20544dd8ef25a17bdf4cc3f5c47 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java +++ b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java @@ -109,6 +109,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc private Realm mRealm; private Realm storeRealm; private StatusMessageReceiver statusMessageReceiver = new StatusMessageReceiver(); + private UpdatePumpReceiver updatePumpReceiver = new UpdatePumpReceiver(); private UsbReceiver usbReceiver = new UsbReceiver(); private BatteryReceiver batteryReceiver = new BatteryReceiver(); @@ -183,7 +184,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc statusMessageReceiver, new IntentFilter(MedtronicCnlIntentService.Constants.ACTION_STATUS_MESSAGE)); LocalBroadcastManager.getInstance(this).registerReceiver( - new UpdatePumpReceiver(), + updatePumpReceiver, new IntentFilter(MedtronicCnlIntentService.Constants.ACTION_UPDATE_PUMP)); mEnableCgmService = Eula.show(this, prefs); @@ -207,7 +208,6 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc new IntentFilter(MedtronicCnlIntentService.Constants.ACTION_USB_REGISTER)); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - if (toolbar != null) { setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(false); @@ -590,11 +590,15 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc super.onDestroy(); + cancelDisplayRefreshLoop(); + + LocalBroadcastManager.getInstance(this).unregisterReceiver(statusMessageReceiver); + LocalBroadcastManager.getInstance(this).unregisterReceiver(updatePumpReceiver); + LocalBroadcastManager.getInstance(this).unregisterReceiver(usbReceiver); unregisterReceiver(usbReceiver); unregisterReceiver(batteryReceiver); PreferenceManager.getDefaultSharedPreferences(getBaseContext()).unregisterOnSharedPreferenceChangeListener(this); - cancelDisplayRefreshLoop(); if (!storeRealm.isClosed()) { storeRealm.close(); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java index 034d3914ca1093cbc75d4818afb0da21fcdd3b42..39f5e1413ed2d29f0a887a1c10d3dc7ca4cc4506 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java @@ -156,6 +156,7 @@ public class PumpStatusResponseMessage extends MedtronicSendMessageResponseMessa // Predictive low suspend // TODO - there is more status info in this byte other than just a boolean yes/no + // noted: 0x01=high 0x04=before high 0x08=before low 0x0A=low 0x80=suspend 0x92=suspend low lowSuspendActive = statusBuffer.get(0x3F) != 0; // Recent Bolus Wizard diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java index 0d0a80bd0594683632b323b0184f8f996f0e0218..d1a80edadf8b029d8aedefa861d07879285c2c9a 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java +++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java @@ -46,34 +46,43 @@ public class MedtronicCnlIntentService extends IntentService { public final static int USB_VID = 0x1a79; public final static int USB_PID = 0x6210; public final static long USB_WARMUP_TIME_MS = 5000L; + public final static long POLL_PERIOD_MS = 300000L; public final static long LOW_BATTERY_POLL_PERIOD_MS = 900000L; // Number of additional seconds to wait after the next expected CGM poll, so that we don't interfere with CGM radio comms. public final static long POLL_GRACE_PERIOD_MS = 30000L; + // Number of seconds before the next expected CGM poll that we will allow uploader comms to start public final static long POLL_PRE_GRACE_PERIOD_MS = 45000L; - - public static final String ICON_WARN = "{ion-alert-circled} "; - public static final String ICON_BGL = "{ion-waterdrop} "; - public static final String ICON_USB = "{ion-usb} "; - public static final String ICON_INFO = "{ion-information_circled} "; - public static final String ICON_HELP = "{ion-ios-lightbulb} "; - public static final String ICON_SETTING = "{ion-android-settings} "; - public static final String ICON_HEART = "{ion-heart} "; - public static final String ICON_LOW = "{ion-battery_low} "; - public static final String ICON_FULL = "{ion-battery_full} "; - public static final String ICON_RESV = "{ion-paintbucket} "; - public static final String ICON_CGM = "{ion-ios-pulse_strong} "; - public static final String ICON_MEDICAL = "{ion-ios-medical} "; - public static final String ICON_BOLUS = "{ion-erlenmeyer-flask} "; - public static final String ICON_BASAL = "{ion-ios-timer} "; - public static final String ICON_NOTE = "{ion_android_notifications} "; + // cgm n/a events to trigger anti clash poll timing + public final static int POLL_ANTI_CLASH = 3; + + // TODO - use a message type and insert icon as part of ui status message handling + public static final String ICON_WARN = "{ion_alert_circled} "; + public static final String ICON_BGL = "{ion_waterdrop} "; + public static final String ICON_USB = "{ion_usb} "; + public static final String ICON_INFO = "{ion_information_circled} "; + public static final String ICON_HELP = "{ion_ios_lightbulb} "; + public static final String ICON_SETTING = "{ion_android_settings} "; + public static final String ICON_HEART = "{ion_heart} "; + public static final String ICON_LOW = "{ion_battery_low} "; + public static final String ICON_FULL = "{ion_battery_full} "; + public static final String ICON_CGM = "{ion_ios_pulse_strong} "; + public static final String ICON_SUSPEND = "{ion_pause} "; + public static final String ICON_RESUME = "{ion_play} "; + public static final String ICON_BOLUS = "{ion_skip_forward} "; + public static final String ICON_BASAL = "{ion_skip_forward} "; + public static final String ICON_CHANGE = "{ion_android_hand} "; + public static final String ICON_BELL = "{ion_android_notifications} "; + public static final String ICON_NOTE = "{ion_clipboard} "; // show warning message after repeated errors private final static int ERROR_COMMS_AT = 4; - private final static int ERROR_CONNECT_AT = 8; - private final static int ERROR_SIGNAL_AT = 8; - private final static int ERROR_PUMPLOSTSENSOR_AT = 8; + private final static int ERROR_CONNECT_AT = 6; + private final static int ERROR_SIGNAL_AT = 6; + private final static int ERROR_PUMPLOSTSENSOR_AT = 6; + private final static int ERROR_PUMPBATTERY_AT = 3; private final static int ERROR_PUMPCLOCK_AT = 8; + private final static int ERROR_PUMPCLOCK_MS = 10 * 60 * 1000; private static final String TAG = MedtronicCnlIntentService.class.getSimpleName(); @@ -84,7 +93,7 @@ public class MedtronicCnlIntentService extends IntentService { private DataStore dataStore = DataStore.getInstance(); private ConfigurationStore configurationStore = ConfigurationStore.getInstance(); private DateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss", Locale.US); - private DateFormat dateFormatterNote = new SimpleDateFormat("HH:mm", Locale.US); + private DateFormat dateFormatterNote = new SimpleDateFormat("E HH:mm", Locale.US); private Realm realm; private long pumpOffset; @@ -153,6 +162,7 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received Log.d(TAG, "onHandleIntent called"); try { final long timePollStarted = System.currentTimeMillis(); + long pollInterval = configurationStore.getPollInterval(); realm = Realm.getDefaultInstance(); long due = checkPollTime(); @@ -162,21 +172,6 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received return; } - RealmResults<PumpStatusEvent> pumpresults = realm.where(PumpStatusEvent.class) - .greaterThan("eventDate", new Date(System.currentTimeMillis() - (6 * 60 * 60 * 1000))) - .findAllSorted("eventDate", Sort.DESCENDING); - long pollInterval = configurationStore.getPollInterval(); - if (pumpresults.size() > 0) { - short pumpBatteryLevel = pumpresults.first().getBatteryPercentage(); - if ((pumpBatteryLevel > 0) && (pumpBatteryLevel <= 25)) { - pollInterval = configurationStore.getLowBatteryPollInterval(); - sendStatus(ICON_WARN + "Warning: pump battery low"); - if (pollInterval != configurationStore.getPollInterval()) { - sendStatus(ICON_SETTING + "Low battery poll interval: " + (pollInterval / 60000) + " minutes"); - } - } - } - // TODO - throw, don't return if (!openUsbDevice()) return; @@ -243,14 +238,14 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received sendStatus(ICON_WARN + "Could not communicate with the pump. Is it nearby?"); Log.i(TAG, "Could not communicate with the pump. Is it nearby?"); dataStore.incCommsConnectError(); - pollInterval = configurationStore.getPollInterval() / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available + pollInterval = POLL_PERIOD_MS / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available } else if (cnlReader.getPumpSession().getRadioRSSIpercentage() < 5) { sendStatus(String.format(Locale.getDefault(), "Connected on channel %d RSSI: %d%%", (int) radioChannel, cnlReader.getPumpSession().getRadioRSSIpercentage())); sendStatus(ICON_WARN + "Warning: pump signal too weak. Is it nearby?"); Log.i(TAG, "Warning: pump signal too weak. Is it nearby?"); dataStore.incCommsConnectError(); dataStore.incCommsSignalError(); - pollInterval = configurationStore.getPollInterval() / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available + pollInterval = POLL_PERIOD_MS / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available } else { dataStore.decCommsConnectError(); if (cnlReader.getPumpSession().getRadioRSSIpercentage() < 20) @@ -273,14 +268,19 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received // TODO - this should not be necessary. We should reverse lookup the device name from PumpInfo pumpRecord.setDeviceName(deviceName); + if (radioChannel == 26) cnlReader.beginEHSMSession(); // gentle persuasion to leave channel 26 (weakest for CNL and causes Pebble to lose BT often) by using EHSM to influence pump channel change + long pumpTime = cnlReader.getPumpTime().getTime(); pumpOffset = pumpTime - System.currentTimeMillis(); Log.d(TAG, "Time offset between pump and device: " + pumpOffset + " millis."); pumpRecord.setPumpTimeOffset(pumpOffset); pumpRecord.setPumpDate(new Date(pumpTime)); + pumpRecord.setEventDate(new Date(System.currentTimeMillis())); cnlReader.updatePumpStatus(pumpRecord); + if (radioChannel == 26) cnlReader.endEHSMSession(); + validatePumpRecord(pumpRecord, activePump); activePump.getPumpHistory().add(pumpRecord); realm.commitTransaction(); @@ -288,6 +288,13 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received dataStore.incCommsSuccess(); dataStore.clearCommsError(); + if (pumpRecord.getBatteryPercentage() <= 25) { + dataStore.incPumpBatteryError(); + pollInterval = configurationStore.getLowBatteryPollInterval(); + } else { + dataStore.clearPumpBatteryError(); + } + if (pumpRecord.isCgmActive()) { dataStore.clearPumpCgmNA(); // poll clash detection dataStore.clearPumpLostSensorError(); @@ -296,30 +303,38 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received sendStatus(ICON_CGM + "sensor is in warm-up phase"); else if (pumpRecord.getCalibrationDueMinutes() == 0) sendStatus(ICON_CGM + "sensor calibration is due now!"); + else if (pumpRecord.getSgv() == 0 && pumpRecord.isCgmCalibrating()) + sendStatus(ICON_CGM + "sensor is calibrating"); else if (pumpRecord.getSgv() == 0) sendStatus(ICON_CGM + "sensor error (pump graph gap)"); else { dataStore.incCommsSgvSuccess(); + // TODO - don't convert SGV here, convert dynamically in ui status message handler sendStatus("SGV: " + MainActivity.strFormatSGV(pumpRecord.getSgv()) + " At: " + dateFormatter.format(pumpRecord.getCgmDate().getTime()) + " Pump: " + (pumpOffset > 0 ? "+" : "") + (pumpOffset / 1000L) + "sec"); + if (pumpRecord.isCgmCalibrating()) + sendStatus(ICON_CGM + "sensor is calibrating"); if (pumpRecord.isOldSgvWhenNewExpected()) { - sendStatus(ICON_WARN + "Pump sent old SGV event"); + sendStatus(ICON_CGM + "old SGV event received"); // pump may have missed sensor transmission or be delayed in posting to status message // in most cases the next scheduled poll will have latest sgv, occasionally it is available this period after a delay // if user selects double poll option we try again this period or wait until next - pollInterval = POLL_PERIOD_MS / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); + pollInterval = configurationStore.isReducePollOnPumpAway() ? 60000 : POLL_PERIOD_MS; } } } else { - sendStatus(ICON_CGM + "cgm n/a (pump lost sensor)"); dataStore.incPumpCgmNA(); // poll clash detection - if (dataStore.getCommsSgvSuccess() > 0) // only count errors if cgm is being used - dataStore.incPumpLostSensorError(); + if (dataStore.getCommsSgvSuccess() > 0) { + dataStore.incPumpLostSensorError(); // only count errors if cgm is being used + sendStatus(ICON_CGM + "cgm n/a (pump lost sensor)"); + } else { + sendStatus(ICON_CGM + "cgm n/a"); + } } - sendStatusTreatments(pumpRecord); + sendStatusNotifications(pumpRecord); // Tell the Main Activity we have new data sendMessage(Constants.ACTION_UPDATE_PUMP); @@ -366,32 +381,29 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received Log.e(TAG, "Could not close connection.", e); sendStatus(ICON_WARN + "Could not close connection: " + e.getMessage()); } finally { - - if (!realm.isClosed()) { - if (realm.isInTransaction()) { - // If we didn't commit the transaction, we've run into an error. Let's roll it back - realm.cancelTransaction(); - } - RemoveOutdatedRecords(); - - long nextpoll = requestPollTime(timePollStarted, pollInterval); - MedtronicCnlAlarmManager.setAlarm(nextpoll); - sendStatus("Next poll due at: " + dateFormatter.format(nextpoll)); - - realm.close(); + if (realm.isInTransaction()) { + // If we didn't commit the transaction, we've run into an error. Let's roll it back + realm.cancelTransaction(); } + long nextpoll = requestPollTime(timePollStarted, pollInterval); + MedtronicCnlAlarmManager.setAlarm(nextpoll); + sendStatus("Next poll due at: " + dateFormatter.format(nextpoll)); + + RemoveOutdatedRecords(); uploadPollResults(); sendStatusWarnings(); } } finally { + if (!realm.isClosed()) realm.close(); MedtronicCnlAlarmReceiver.completeWakefulIntent(intent); } } - private void sendStatusTreatments(PumpStatusEvent pumpRecord) { + private void sendStatusNotifications(PumpStatusEvent pumpRecord) { if (pumpRecord.isValidBGL()) + // TODO - don't convert BGL here, convert dynamically in ui status message handler sendStatus(ICON_BGL + "Recent finger BG: " + MainActivity.strFormatSGV(pumpRecord.getRecentBGL())); if (pumpRecord.isValidBolus()) { @@ -409,20 +421,35 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received else if (pumpRecord.getTempBasalMinutesRemaining() > 0) sendStatus(ICON_BASAL + "Temp basal: " + pumpRecord.getTempBasalRate() + "u Remaining: " + pumpRecord.getTempBasalMinutesRemaining() + " minutes"); else - sendStatus(ICON_BASAL + "Temp basal stopped"); + sendStatus(ICON_BASAL + "Temp basal: stopped before expected duration"); } + if (pumpRecord.isValidSUSPEND()) + sendStatus(ICON_SUSPEND + "Pump suspended insulin delivery approx: " + dateFormatterNote.format(pumpRecord.getSuspendAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getSuspendBeforeDate())); + if (pumpRecord.isValidSUSPENDOFF()) + sendStatus(ICON_RESUME + "Pump resumed insulin delivery approx: " + dateFormatterNote.format(pumpRecord.getSuspendAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getSuspendBeforeDate())); + if (pumpRecord.isValidSAGE()) - sendStatus(ICON_NOTE + "Sensor changed approx: " + dateFormatterNote.format(pumpRecord.getSageAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getSageBeforeDate())); + sendStatus(ICON_CHANGE + "Sensor changed approx: " + dateFormatterNote.format(pumpRecord.getSageAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getSageBeforeDate())); if (pumpRecord.isValidCAGE()) - sendStatus(ICON_NOTE + "Reservoir changed approx: " + dateFormatterNote.format(pumpRecord.getCageAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getCageBeforeDate())); + sendStatus(ICON_CHANGE + "Reservoir changed approx: " + dateFormatterNote.format(pumpRecord.getCageAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getCageBeforeDate())); if (pumpRecord.isValidBATTERY()) - sendStatus(ICON_NOTE + "Pump battery changed approx: " + dateFormatterNote.format(pumpRecord.getBatteryAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getBatteryBeforeDate())); + sendStatus(ICON_CHANGE + "Pump battery changed approx: " + dateFormatterNote.format(pumpRecord.getBatteryAfterDate()) + " - " + dateFormatterNote.format(pumpRecord.getBatteryBeforeDate())); + + if (pumpRecord.isValidALERT()) + sendStatus(ICON_BELL + "Active alert on pump At: " + dateFormatter.format(pumpRecord.getAlertDate())); } private void sendStatusWarnings() { - if (Math.abs(pumpOffset) > 10 * 60 * 1000) + if (dataStore.getPumpBatteryError() >= ERROR_PUMPBATTERY_AT) { + dataStore.clearPumpBatteryError(); + sendStatus(ICON_WARN + "Warning: pump battery low"); + if (configurationStore.getLowBatteryPollInterval() != configurationStore.getPollInterval()) + sendStatus(ICON_SETTING + "Low battery poll interval: " + (configurationStore.getLowBatteryPollInterval() / 60000) + " minutes"); + } + + if (Math.abs(pumpOffset) > ERROR_PUMPCLOCK_MS) dataStore.incPumpClockError(); if (dataStore.getPumpClockError() >= ERROR_PUMPCLOCK_AT) { dataStore.clearPumpClockError(); @@ -430,20 +457,24 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received + " Pump is over " + (Math.abs(pumpOffset) / 60000L) + " minutes " + (pumpOffset > 0 ? "ahead" : "behind") + " of time used by uploader."); sendStatus(ICON_HELP + "The uploader phone/device should have the current time provided by network. Pump clock drifts forward and needs to be set to correct time occasionally."); } + if (dataStore.getCommsError() >= ERROR_COMMS_AT) { sendStatus(ICON_WARN + "Warning: multiple comms/timeout errors detected."); sendStatus(ICON_HELP + "Try: disconnecting and reconnecting the Contour Next Link to phone / restarting phone / check pairing of CNL with Pump."); } + if (dataStore.getPumpLostSensorError() >= ERROR_PUMPLOSTSENSOR_AT) { dataStore.clearPumpLostSensorError(); sendStatus(ICON_WARN + "Warning: SGV is unavailable from pump often. The pump is missing transmissions from the sensor."); sendStatus(ICON_HELP + "Keep pump on same side of body as sensor. Avoid using body sensor locations that can block radio signal."); } + if (dataStore.getCommsConnectError() >= ERROR_CONNECT_AT * (configurationStore.isReducePollOnPumpAway() ? 2 : 1)) { dataStore.clearCommsConnectError(); sendStatus(ICON_WARN + "Warning: connecting to pump is failing often."); sendStatus(ICON_HELP + "Keep pump nearby to uploader phone/device. The body can block radio signals between pump and uploader."); } + if (dataStore.getCommsSignalError() >= ERROR_SIGNAL_AT) { dataStore.clearCommsSignalError(); sendStatus(ICON_WARN + "Warning: RSSI radio signal from pump is generally weak and may increase errors."); @@ -452,30 +483,37 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received } private void RemoveOutdatedRecords() { - final RealmResults<PumpStatusEvent> resultsx = + final RealmResults<PumpStatusEvent> results = realm.where(PumpStatusEvent.class) .lessThan("eventDate", new Date(System.currentTimeMillis() - (48 * 60 * 60 * 1000))) .findAll(); - if (resultsx.size() > 0) { + if (results.size() > 0) { realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { // Delete all matches - Log.d(TAG, "Deleting " + resultsx.size() + " records from realm"); - resultsx.deleteAllFromRealm(); + Log.d(TAG, "Deleting " + results.size() + " records from realm"); + results.deleteAllFromRealm(); } }); } } -// TODO fix square/dual bolus time after battery change as pump resets start time, use refs to work out actual time and duration? -// TODO for NS add temp basal at 0% when suspended? use 30 or 60 min blocks and cancel temp when resumed? -// TODO check on optimal use of Realm search+results as we make heavy use for validation + // TODO - check on optimal use of Realm search+results as we make heavy use for validation private void validatePumpRecord(PumpStatusEvent pumpRecord, PumpInfo activePump) { - // TODO cgm/sgv validation - handle sensor exceptions + int index; + Date uploaderStartDate = dataStore.getUploaderStartDate(); + + // TODO - pump validation is unused but will allow for future record manipulation when adding data from pump history message (gap fill) + + // validate that this contains a new PUMP record + pumpRecord.setValidPUMP(true); + + // TODO - cgm validation - handle sensor exceptions + // validate that this contains a new CGM record if (pumpRecord.isCgmActive()) { pumpRecord.setValidCGM(true); @@ -508,6 +546,8 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received } } + // TODO - square/dual stopped and new bolus started between poll snapshots, check realm history to handle this? + // validate that this contains a new BOLUS record RealmResults<PumpStatusEvent> lastbolus_results = activePump.getPumpHistory() .where() @@ -517,29 +557,42 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received .findAll(); if (lastbolus_results.size() == 0) { - pumpRecord.setValidBolus(true); - - if (pumpRecord.getBolusingReference() == pumpRecord.getLastBolusReference() - && pumpRecord.getBolusingMinutesRemaining() > 10) { - pumpRecord.setValidBolusDual(true); - } RealmResults<PumpStatusEvent> bolusing_results = activePump.getPumpHistory() .where() .equalTo("bolusingReference", pumpRecord.getLastBolusReference()) - .greaterThan("bolusingMinutesRemaining", 10) + .greaterThan("bolusingMinutesRemaining", 10) // if a manual normal bolus referred to here while square is being delivered it will show the remaining time for all bolusing .findAllSorted("eventDate", Sort.ASCENDING); - // note: if pump battery is changed during square/dual bolus period the last bolus time will be set to this time (pump asks user to resume/cancel bolus) - if (bolusing_results.size() > 0) { - pumpRecord.setValidBolusSquare(true); long start = pumpRecord.getLastBolusPumpDate().getTime(); + long start_bolusing = bolusing_results.first().getPumpDate().getTime(); + + // if pump battery is changed during square/dual bolus period the last bolus time will be set to this time (pump asks user to resume/cancel bolus) + // use bolusing start time when this is detected + if (start - start_bolusing > 10 * 60) + start = start_bolusing; + long end = pumpRecord.getPumpDate().getTime(); - long duration = bolusing_results.first().getPumpDate().getTime() - start + (bolusing_results.first().getBolusingMinutesRemaining() * 60000); + long duration = start_bolusing - start + (bolusing_results.first().getBolusingMinutesRemaining() * 60000); if (start + duration > end) // was square bolus stopped before expected duration? duration = end - start; - pumpRecord.setLastBolusDuration((short) (duration / 60000)); + + // check that this was a square bolus and not a normal bolus + if (duration > 10) { + pumpRecord.setValidBolus(true); + pumpRecord.setValidBolusSquare(true); + pumpRecord.setLastBolusDate(new Date (start)); + pumpRecord.setLastBolusDuration((short) (duration / 60000)); + } + } + + else if (pumpRecord.getLastBolusDate().getTime() >= uploaderStartDate.getTime()) { + pumpRecord.setValidBolus(true); + if (pumpRecord.getBolusingReference() == pumpRecord.getLastBolusReference() + && pumpRecord.getBolusingMinutesRemaining() > 10) { + pumpRecord.setValidBolusDual(true); + } } } @@ -550,7 +603,7 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received .greaterThan("eventDate", new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000))) .findAllSorted("eventDate", Sort.DESCENDING); if (pumpRecord.getTempBasalMinutesRemaining() > 0) { - int index = 0; + index = 0; if (tempbasal_results.size() > 1) { short minutes = pumpRecord.getTempBasalMinutesRemaining(); for (index = 0; index < tempbasal_results.size(); index++) { @@ -568,6 +621,7 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received tempbasal_results.get(index).getTempBasalRate() != pumpRecord.getTempBasalRate()) { pumpRecord.setValidTEMPBASAL(true); pumpRecord.setTempBasalAfterDate(tempbasal_results.get(index).getEventDate()); + pumpRecord.setTempBasalBeforeDate(pumpRecord.getEventDate()); } } else { // check if stopped before expected duration @@ -575,7 +629,67 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received if (pumpRecord.getPumpDate().getTime() - tempbasal_results.first().getPumpDate().getTime() - (tempbasal_results.first().getTempBasalMinutesRemaining() * 60 * 1000) < -60 * 1000) { pumpRecord.setValidTEMPBASAL(true); pumpRecord.setTempBasalAfterDate(tempbasal_results.first().getEventDate()); + pumpRecord.setTempBasalBeforeDate(pumpRecord.getEventDate()); + } + } + + // validate that this contains a new SUSPEND record + RealmResults<PumpStatusEvent> suspend_results = activePump.getPumpHistory() + .where() + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (2 * 60 * 60 * 1000))) + .equalTo("validSUSPEND", true) + .or() + .equalTo("validSUSPENDOFF", true) + .findAllSorted("eventDate", Sort.DESCENDING); + + if (suspend_results.size() > 0) { + // new valid suspend - set temp basal for 0u 60m in NS + if (pumpRecord.isSuspended() && suspend_results.first().isValidSUSPENDOFF()) { + pumpRecord.setValidSUSPEND(true); + } + // continuation valid suspend every 30m - set temp basal for 0u 60m in NS + else if (pumpRecord.isSuspended() && suspend_results.first().isValidSUSPEND() && + pumpRecord.getEventDate().getTime() - suspend_results.first().getEventDate().getTime() >= 30 * 60 * 1000) { + pumpRecord.setValidSUSPEND(true); + } + // valid suspendoff - set temp stopped in NS + else if (!pumpRecord.isSuspended() && suspend_results.first().isValidSUSPEND() && + pumpRecord.getEventDate().getTime() - suspend_results.first().getEventDate().getTime() <= 60 * 60 * 1000) { + pumpRecord.setValidSUSPENDOFF(true); + RealmResults<PumpStatusEvent> suspendended_results = activePump.getPumpHistory() + .where() + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (2 * 60 * 60 * 1000))) + .findAllSorted("eventDate", Sort.DESCENDING); + pumpRecord.setSuspendAfterDate(suspendended_results.first().getEventDate()); + pumpRecord.setSuspendBeforeDate(pumpRecord.getEventDate()); + } + } + else if (pumpRecord.isSuspended()) { + pumpRecord.setValidSUSPEND(true); + } + + // absolute suspend start time approx to after-before range + if (pumpRecord.isValidSUSPEND()) { + RealmResults<PumpStatusEvent> suspendstarted_results = activePump.getPumpHistory() + .where() + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (12 * 60 * 60 * 1000))) + .findAllSorted("eventDate", Sort.ASCENDING); + index = suspendstarted_results.size(); + if (index > 0) { + while (index > 0) { + index--; + if (!suspendstarted_results.get(index).isSuspended()) + break; } + pumpRecord.setSuspendAfterDate(suspendstarted_results.get(index).getEventDate()); + } + else { + pumpRecord.setSuspendAfterDate(pumpRecord.getEventDate()); + } + if (++index < suspendstarted_results.size()) + pumpRecord.setSuspendBeforeDate(suspendstarted_results.get(index).getEventDate()); + else + pumpRecord.setSuspendBeforeDate(pumpRecord.getEventDate()); } // validate that this contains a new SAGE record @@ -589,18 +703,18 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received pumpRecord.setValidSAGE(true); RealmResults<PumpStatusEvent> sagedate_results = activePump.getPumpHistory() .where() - .greaterThan("eventDate", new Date(System.currentTimeMillis() - (12 * 60 * 1000))) + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (6 * 60 * 60 * 1000))) .findAllSorted("eventDate", Sort.DESCENDING); pumpRecord.setSageAfterDate(sagedate_results.first().getEventDate()); pumpRecord.setSageBeforeDate(pumpRecord.getEventDate()); } - } else if (pumpRecord.isCgmActive() && pumpRecord.getTransmitterBattery() > 70) { - // note: transmitter battery can fluctuate when on the edge of a state change, usually low battery + } else if (pumpRecord.isCgmActive() && pumpRecord.getTransmitterBattery() == 100) { + // note: transmitter battery can fluctuate when on the edge of a state change RealmResults<PumpStatusEvent> sagebattery_results = activePump.getPumpHistory() .where() - .greaterThan("eventDate", new Date(System.currentTimeMillis() - (12 * 60 * 60 * 1000))) + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (6 * 60 * 60 * 1000))) .equalTo("cgmActive", true) - .lessThan("transmitterBattery", pumpRecord.getTransmitterBattery()) + .lessThan("transmitterBattery", 50) .findAllSorted("eventDate", Sort.DESCENDING); if (sagebattery_results.size() > 0) { RealmResults<PumpStatusEvent> sage_valid_results = activePump.getPumpHistory() @@ -619,7 +733,7 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received // validate that this contains a new CAGE record RealmResults<PumpStatusEvent> cage_results = activePump.getPumpHistory() .where() - .greaterThan("eventDate", new Date(System.currentTimeMillis() - (12 * 60 * 60 * 1000))) + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (6 * 60 * 60 * 1000))) .lessThan("reservoirAmount", pumpRecord.getReservoirAmount()) .findAllSorted("eventDate", Sort.DESCENDING); if (cage_results.size() > 0) { @@ -638,7 +752,7 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received // validate that this contains a new BATTERY record RealmResults<PumpStatusEvent> battery_results = activePump.getPumpHistory() .where() - .greaterThan("eventDate", new Date(System.currentTimeMillis() - (12 * 60 * 60 * 1000))) + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (6 * 60 * 60 * 1000))) .lessThan("batteryPercentage", pumpRecord.getBatteryPercentage()) .findAllSorted("eventDate", Sort.DESCENDING); if (battery_results.size() > 0) { @@ -654,6 +768,18 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received } } + // validate that this contains a new ALERT record + if (pumpRecord.getAlert() > 0) { + RealmResults<PumpStatusEvent> alert_results = activePump.getPumpHistory() + .where() + .greaterThan("eventDate", new Date(System.currentTimeMillis() - (6 * 60 * 60 * 1000))) + .findAllSorted("eventDate", Sort.DESCENDING); + if (alert_results.size() > 0) { + if (alert_results.first().getAlert() != pumpRecord.getAlert()) + pumpRecord.setValidALERT(true); + } + } + } // pollInterval: default = POLL_PERIOD_MS (time to pump cgm reading) @@ -692,8 +818,8 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received if (timeLastCGM == 0) nextRequestedPollTime += 15 * 1000; // push poll time forward to avoid potential clash when no previous poll time available to sync with - else if (pumpCgmNA > 2) - nextRequestedPollTime += ((pumpCgmNA - 2) % 3) * 30 * 1000; // adjust poll time in 30 second steps to avoid potential poll clash (adjustment: poll+30s / poll+60s / poll+0s) + else if (pumpCgmNA >= POLL_ANTI_CLASH) + nextRequestedPollTime += (((pumpCgmNA - POLL_ANTI_CLASH) % 3) + 1) * 30 * 1000; // adjust poll time in 30 second steps to avoid potential poll clash (adjustment: poll+30s / poll+60s / poll+90s) // check if requested poll time is too close to next actual poll time if (nextRequestedPollTime > nextActualPollTime - POLL_GRACE_PERIOD_MS - POLL_PRE_GRACE_PERIOD_MS diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java index 84b694314657ba3a50f16c5ecb189c8c6d165226..f0d9469626756391b0e1eea41125528b65cfa8e1 100644 --- a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java @@ -58,7 +58,6 @@ public class PumpStatusEvent extends RealmObject { private float lastBolusAmount; private Date lastBolusDate; private Date lastBolusPumpDate; - private byte lastBolusType; private short lastBolusDuration; private short lastBolusReference; private byte transmitterBattery; @@ -66,18 +65,23 @@ public class PumpStatusEvent extends RealmObject { private short calibrationDueMinutes; private float sensorRateOfChange; + private boolean oldSgvWhenNewExpected = false; + + private boolean validPUMP = false; private boolean validCGM = false; private boolean validSGV = false; private boolean validBGL = false; private boolean validBolus = false; private boolean validBolusDual = false; private boolean validBolusSquare = false; - private boolean validAlert = false; - - private boolean oldSgvWhenNewExpected = false; - + private boolean validALERT = false; + private boolean validSUSPEND = false; + private boolean validSUSPENDOFF = false; + private Date suspendAfterDate; + private Date suspendBeforeDate; private boolean validTEMPBASAL = false; private Date tempBasalAfterDate; + private Date tempBasalBeforeDate; private boolean validCAGE = false; private Date cageAfterDate; private Date cageBeforeDate; @@ -96,12 +100,14 @@ public class PumpStatusEvent extends RealmObject { this.eventDate = new Date(); } + public void setEventDate(Date eventDate) { + this.eventDate = eventDate; + } + public Date getEventDate() { return eventDate; } - // No EventDate setter. The eventDate is set at the time that the PumpStatusEvent is created. - public Date getPumpDate() { return pumpDate; } @@ -201,6 +207,14 @@ public class PumpStatusEvent extends RealmObject { this.oldSgvWhenNewExpected = oldSgvWhenNewExpected; } + public boolean isValidPUMP() { + return validPUMP; + } + + public void setValidPUMP(boolean validPUMP) { + this.validPUMP = validPUMP; + } + public boolean isValidCGM() { return validCGM; } @@ -249,14 +263,47 @@ public class PumpStatusEvent extends RealmObject { this.validBolusSquare = validBolusSquare; } - public boolean isValidAlert() { - return validAlert; + public boolean isValidALERT() { + return validALERT; + } + + public void setValidALERT(boolean validALERT) { + this.validALERT = validALERT; + } + + public boolean isValidSUSPEND() { + return validSUSPEND; + } + + public void setValidSUSPEND(boolean validSUSPEND) { + this.validSUSPEND = validSUSPEND; + } + + public boolean isValidSUSPENDOFF() { + return validSUSPENDOFF; } - public void setValidAlert(boolean validAlert) { - this.validAlert = validAlert; + public void setValidSUSPENDOFF(boolean validSUSPENDOFF) { + this.validSUSPENDOFF = validSUSPENDOFF; } + public Date getSuspendAfterDate() { + return suspendAfterDate; + } + + public void setSuspendAfterDate(Date suspendAfterDate) { + this.suspendAfterDate = suspendAfterDate; + } + + public Date getSuspendBeforeDate() { + return suspendBeforeDate; + } + + public void setSuspendBeforeDate(Date suspendBeforeDate) { + this.suspendBeforeDate = suspendBeforeDate; + } + + public boolean isValidTEMPBASAL() { return validTEMPBASAL; } @@ -273,6 +320,14 @@ public class PumpStatusEvent extends RealmObject { this.tempBasalAfterDate = tempBasalAfterDate; } + public Date getTempBasalBeforeDate() { + return tempBasalBeforeDate; + } + + public void setTempBasalBeforeDate(Date tempBasalBeforeDate) { + this.tempBasalBeforeDate = tempBasalBeforeDate; + } + public boolean isValidCAGE() { return validCAGE; } @@ -625,14 +680,6 @@ public class PumpStatusEvent extends RealmObject { this.lastBolusReference = lastBolusReference; } - public byte getLastBolusType() { - return lastBolusType; - } - - public void setLastBolusType(byte lastBolusType) { - this.lastBolusType = lastBolusType; - } - public short getLastBolusDuration() { return lastBolusDuration; } @@ -713,26 +760,35 @@ public class PumpStatusEvent extends RealmObject { ", recentBGL=" + recentBGL + ", alert=" + alert + ", alertDate=" + alertDate + + ", alertPumpDate=" + alertPumpDate + ", bolusingDelivered=" + bolusingDelivered + ", bolusingMinutesRemaining=" + bolusingMinutesRemaining + ", bolusingReference=" + bolusingReference + ", lastBolusAmount=" + lastBolusAmount + ", lastBolusDate=" + lastBolusDate + + ", lastBolusPumpDate=" + lastBolusPumpDate + + ", lastBolusDuration=" + lastBolusDuration + ", lastBolusReference=" + lastBolusReference + ", transmitterBattery=" + transmitterBattery + ", transmitterControl=" + transmitterControl + ", calibrationDueMinutes=" + calibrationDueMinutes + ", sensorRateOfChange=" + sensorRateOfChange + + ", oldSgvWhenNewExpected=" + oldSgvWhenNewExpected + + ", validPUMP=" + validPUMP + ", validCGM=" + validCGM + ", validSGV=" + validSGV + ", validBGL=" + validBGL + ", validBolus=" + validBolus + ", validBolusDual=" + validBolusDual + ", validBolusSquare=" + validBolusSquare + - ", validAlert=" + validAlert + - ", oldSgvWhenNewExpected=" + oldSgvWhenNewExpected + + ", validALERT=" + validALERT + + ", validSUSPEND=" + validSUSPEND + + ", validSUSPENDOFF=" + validSUSPENDOFF + + ", suspendAfterDate=" + suspendAfterDate + + ", suspendBeforeDate=" + suspendBeforeDate + ", validTEMPBASAL=" + validTEMPBASAL + ", tempBasalAfterDate=" + tempBasalAfterDate + + ", tempBasalBeforeDate=" + tempBasalBeforeDate + ", validCAGE=" + validCAGE + ", cageAfterDate=" + cageAfterDate + ", cageBeforeDate=" + cageBeforeDate + diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java index 0ce75df8e8be4b12119b3f33c8f676514dbb5bec..06f7f79eccf7b415c588be5e9a65e966f5cf113a 100644 --- a/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java +++ b/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java @@ -14,15 +14,16 @@ import info.nightscout.android.upload.nightscout.serializer.EntriesSerializer; import android.support.annotation.NonNull; +import info.nightscout.android.utils.ConfigurationStore; import info.nightscout.api.UploadApi; -import info.nightscout.api.GlucoseEndpoints; -import info.nightscout.api.GlucoseEndpoints.GlucoseEntry; -import info.nightscout.api.BolusEndpoints; -import info.nightscout.api.BolusEndpoints.BolusEntry; +import info.nightscout.api.SgvEndpoints; +import info.nightscout.api.SgvEndpoints.SgvEntry; +import info.nightscout.api.MbgEndpoints; +import info.nightscout.api.MbgEndpoints.MbgEntry; import info.nightscout.api.TreatmentEndpoints; import info.nightscout.api.TreatmentEndpoints.TreatmentEntry; -import info.nightscout.api.TempBasalAbsoluteEndpoints.TempBasalAbsoluteEntry; -import info.nightscout.api.TempBasalAbsoluteEndpoints; +import info.nightscout.api.TempBasalRateEndpoints.TempBasalRateEntry; +import info.nightscout.api.TempBasalRateEndpoints; import info.nightscout.api.TempBasalPercentEndpoints; import info.nightscout.api.TempBasalPercentEndpoints.TempBasalPercentEntry; import info.nightscout.api.TempBasalCancelEndpoints; @@ -38,6 +39,8 @@ import info.nightscout.api.DeviceEndpoints.DeviceStatus; import okhttp3.ResponseBody; import retrofit2.Response; +import static info.nightscout.android.medtronic.MainActivity.MMOLXLFACTOR; + class NightScoutUpload { private static final String TAG = NightscoutUploadIntentService.class.getSimpleName(); @@ -50,27 +53,29 @@ class NightScoutUpload { boolean doRESTUpload(String url, String secret, + boolean treatments, int uploaderBatteryLevel, List<PumpStatusEvent> records) throws Exception { - return isUploaded(records, url, secret, uploaderBatteryLevel); + return isUploaded(records, url, secret, treatments, uploaderBatteryLevel); } private boolean isUploaded(List<PumpStatusEvent> records, String baseURL, String secret, + boolean treatments, int uploaderBatteryLevel) throws Exception { UploadApi uploadApi = new UploadApi(baseURL, formToken(secret)); boolean eventsUploaded = uploadEvents( - uploadApi.getGlucoseEndpoints(), - uploadApi.getBolusEndpoints(), + uploadApi.getSgvEndpoints(), + uploadApi.getMbgEndpoints(), uploadApi.getTreatmentEndpoints(), - uploadApi.getTempBasalAbsoluteEndpoints(), + uploadApi.getTempBasalRateEndpoints(), uploadApi.getTempBasalPercentEndpoints(), uploadApi.getTempBasalCancelEndpoints(), uploadApi.getNoteEndpoints(), - records); + records, treatments); boolean deviceStatusUploaded = uploadDeviceStatus(uploadApi.getDeviceEndpoints(), uploaderBatteryLevel, records); @@ -78,20 +83,21 @@ class NightScoutUpload { return eventsUploaded && deviceStatusUploaded; } - private boolean uploadEvents(GlucoseEndpoints glucoseEndpoints, - BolusEndpoints bolusEndpoints, + private boolean uploadEvents(SgvEndpoints sgvEndpoints, + MbgEndpoints mbgEndpoints, TreatmentEndpoints treatmentEndpoints, - TempBasalAbsoluteEndpoints tempBasalAbsoluteEndpoints, + TempBasalRateEndpoints tempBasalRateEndpoints, TempBasalPercentEndpoints tempBasalPercentEndpoints, TempBasalCancelEndpoints tempBasalCancelEndpoints, NoteEndpoints noteEndpoints, - List<PumpStatusEvent> records) throws Exception { + List<PumpStatusEvent> records, + boolean treatments) throws Exception { - List<GlucoseEntry> glucoseEntries = new ArrayList<>(); - List<BolusEntry> bolusEntries = new ArrayList<>(); + List<SgvEntry> sgvEntries = new ArrayList<>(); + List<MbgEntry> mbgEntries = new ArrayList<>(); List<TreatmentEntry> treatmentEntries = new ArrayList<>(); - List<TempBasalAbsoluteEntry> tempBasalAbsoluteEntries = new ArrayList<>(); + List<TempBasalRateEntry> tempBasalRateEntries = new ArrayList<>(); List<TempBasalPercentEntry> tempBasalPercentEntries = new ArrayList<>(); List<TempBasalCancelEntry> tempBasalCancelEntries = new ArrayList<>(); List<NoteEntry> noteEntries = new ArrayList<>(); @@ -99,116 +105,166 @@ class NightScoutUpload { for (PumpStatusEvent record : records) { if (record.isValidSGV()) { - GlucoseEntry glucoseEntry = new GlucoseEntry(); - glucoseEntry.setType("sgv"); - glucoseEntry.setDirection(EntriesSerializer.getDirectionStringStatus(record.getCgmTrend())); - glucoseEntry.setDevice(record.getDeviceName()); - glucoseEntry.setSgv(record.getSgv()); - glucoseEntry.setDate(record.getCgmDate().getTime()); - glucoseEntry.setDateString(record.getCgmDate().toString()); - glucoseEntries.add(glucoseEntry); + SgvEntry sgvEntry = new SgvEntry(); + sgvEntry.setType("sgv"); + sgvEntry.setDirection(EntriesSerializer.getDirectionStringStatus(record.getCgmTrend())); + sgvEntry.setDevice(record.getDeviceName()); + sgvEntry.setSgv(record.getSgv()); + sgvEntry.setDate(record.getCgmDate().getTime()); + sgvEntry.setDateString(record.getCgmDate().toString()); + sgvEntries.add(sgvEntry); } if (record.isValidBGL()) { - BolusEntry bolusEntry = new BolusEntry(); - bolusEntry.setType("mbg"); - bolusEntry.setDate(record.getEventDate().getTime()); - bolusEntry.setDateString(record.getEventDate().toString()); - bolusEntry.setDevice(record.getDeviceName()); - bolusEntry.setMbg(record.getRecentBGL()); - bolusEntries.add(bolusEntry); + + MbgEntry mbgEntry = new MbgEntry(); + mbgEntry.setType("mbg"); + mbgEntry.setDate(record.getEventDate().getTime()); + mbgEntry.setDateString(record.getEventDate().toString()); + mbgEntry.setDevice(record.getDeviceName()); + mbgEntry.setMbg(record.getRecentBGL()); + mbgEntries.add(mbgEntry); + + // cgm offline or not in use (needed for NS to show bgl when no sgv data) + if (!record.isCgmActive() || record.isCgmWarmUp()) { + ConfigurationStore configurationStore = ConfigurationStore.getInstance(); + BigDecimal bgl; + String units; + if (configurationStore.isMmolxl()) { + bgl = new BigDecimal(record.getRecentBGL() / MMOLXLFACTOR).setScale(1, BigDecimal.ROUND_HALF_UP); + units = "mmol"; + } else { + bgl = new BigDecimal(record.getRecentBGL()).setScale(0); + units = "mg/dl"; + } + + TreatmentEntry treatmentEntry = new TreatmentEntry(); + treatmentEntry.setCreatedAt(ISO8601_DATE_FORMAT.format(record.getEventDate())); + treatmentEntry.setEventType("BG Check"); + treatmentEntry.setGlucoseType("Finger"); + treatmentEntry.setGlucose(bgl); + treatmentEntry.setUnits(units); + treatmentEntries.add(treatmentEntry); + } } - if (record.isValidBolus()) { - TreatmentEntry treatmentEntry = new TreatmentEntry(); - treatmentEntry.setCreatedAt(ISO8601_DATE_FORMAT.format(record.getLastBolusDate())); - if (record.isValidBolusDual()) { - treatmentEntry.setEventType("Bolus"); - treatmentEntry.setInsulin(record.getLastBolusAmount()); - treatmentEntry.setNotes("Dual bolus normal part delivered: " + record.getLastBolusAmount() + "u"); - - } else if (record.isValidBolusSquare()) { - treatmentEntry.setEventType("Combo Bolus"); - treatmentEntry.setDuration(record.getLastBolusDuration()); - treatmentEntry.setSplitNow("0"); - treatmentEntry.setSplitExt("100"); - treatmentEntry.setRelative(2); - treatmentEntry.setEnteredinsulin(String.valueOf(record.getLastBolusAmount())); + if (treatments) { + + if (record.isValidBolus()) { + + if (record.isValidBolusDual()) { + TreatmentEntry treatmentEntry = new TreatmentEntry(); + treatmentEntry.setCreatedAt(ISO8601_DATE_FORMAT.format(record.getLastBolusDate())); + treatmentEntry.setEventType("Bolus"); + treatmentEntry.setInsulin(record.getLastBolusAmount()); + treatmentEntry.setNotes("Dual bolus normal part delivered: " + record.getLastBolusAmount() + "u"); + treatmentEntries.add(treatmentEntry); + + } else if (record.isValidBolusSquare()) { + TreatmentEntry treatmentEntry = new TreatmentEntry(); + treatmentEntry.setCreatedAt(ISO8601_DATE_FORMAT.format(record.getLastBolusDate())); + treatmentEntry.setEventType("Combo Bolus"); + treatmentEntry.setDuration(record.getLastBolusDuration()); + treatmentEntry.setSplitNow("0"); + treatmentEntry.setSplitExt("100"); + treatmentEntry.setRelative(2); + treatmentEntry.setEnteredinsulin(String.valueOf(record.getLastBolusAmount())); + treatmentEntries.add(treatmentEntry); + + noteEntries.add(new NoteEntry( + "Announcement", + ISO8601_DATE_FORMAT.format(record.getLastBolusDate().getTime() + (record.getLastBolusDuration() * 60 * 1000)), + "Square bolus delivered: " + record.getLastBolusAmount() + "u Duration: " + record.getLastBolusDuration() + " minutes" + )); + + } else { + TreatmentEntry treatmentEntry = new TreatmentEntry(); + treatmentEntry.setCreatedAt(ISO8601_DATE_FORMAT.format(record.getLastBolusDate())); + treatmentEntry.setEventType("Bolus"); + treatmentEntry.setInsulin(record.getLastBolusAmount()); + treatmentEntries.add(treatmentEntry); + } + } - noteEntries.add(new NoteEntry( - "Announcement", - ISO8601_DATE_FORMAT.format(record.getLastBolusDate().getTime() + (record.getLastBolusDuration() * 60 * 1000)), - "Square bolus delivered: " + record.getLastBolusAmount() + "u Duration: " + record.getLastBolusDuration() + " minutes" - )); - } else { - treatmentEntry.setEventType("Bolus"); - treatmentEntry.setInsulin(record.getLastBolusAmount()); + if (record.isValidTEMPBASAL()) { + if (record.getTempBasalMinutesRemaining() > 0 && record.getTempBasalPercentage() > 0) { + tempBasalPercentEntries.add(new TempBasalPercentEntry( + ISO8601_DATE_FORMAT.format(record.getEventDate()), + "Temp Basal started approx: " + NOTE_DATE_FORMAT.format(record.getTempBasalAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getTempBasalBeforeDate()), + record.getTempBasalMinutesRemaining(), + record.getTempBasalPercentage() - 100 + )); + } else if (record.getTempBasalMinutesRemaining() > 0) { + tempBasalRateEntries.add(new TempBasalRateEntry( + ISO8601_DATE_FORMAT.format(record.getEventDate()), + "Temp Basal started approx: " + NOTE_DATE_FORMAT.format(record.getTempBasalAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getTempBasalBeforeDate()), + record.getTempBasalMinutesRemaining(), + record.getTempBasalRate() + )); + } else { + tempBasalCancelEntries.add(new TempBasalCancelEntry( + ISO8601_DATE_FORMAT.format(record.getEventDate()), + "Temp Basal stopped approx: " + NOTE_DATE_FORMAT.format(record.getTempBasalAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getTempBasalBeforeDate()) + )); + } } - treatmentEntries.add(treatmentEntry); - } - if (record.isValidTEMPBASAL()) { - if (record.getTempBasalMinutesRemaining() > 0 && record.getTempBasalPercentage() > 0) { - tempBasalPercentEntries.add(new TempBasalPercentEntry( - ISO8601_DATE_FORMAT.format(record.getEventDate()), - "Temp Basal started approx: " + NOTE_DATE_FORMAT.format(record.getTempBasalAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getEventDate()), - record.getTempBasalMinutesRemaining(), - record.getTempBasalPercentage() - 100 - )); - } else if (record.getTempBasalMinutesRemaining() > 0) { - tempBasalAbsoluteEntries.add(new TempBasalAbsoluteEntry( + if (record.isValidSUSPEND()) { + tempBasalRateEntries.add(new TempBasalRateEntry( ISO8601_DATE_FORMAT.format(record.getEventDate()), - "Temp Basal started approx: " + NOTE_DATE_FORMAT.format(record.getTempBasalAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getEventDate()), - record.getTempBasalMinutesRemaining(), - record.getTempBasalRate() + "Pump suspended insulin delivery approx: " + NOTE_DATE_FORMAT.format(record.getSuspendAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getSuspendBeforeDate()), + 60, + 0 )); - } else { + } + if (record.isValidSUSPENDOFF()) { tempBasalCancelEntries.add(new TempBasalCancelEntry( ISO8601_DATE_FORMAT.format(record.getEventDate()), - "Temp Basal stopped approx: " + NOTE_DATE_FORMAT.format(record.getTempBasalAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getEventDate()) + "Pump resumed insulin delivery approx: " + NOTE_DATE_FORMAT.format(record.getSuspendAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getSuspendBeforeDate()) + )); + } + + if (record.isValidSAGE()) { + noteEntries.add(new NoteEntry( + "Sensor Start", + ISO8601_DATE_FORMAT.format(record.getSageAfterDate().getTime() - (record.getSageAfterDate().getTime() - record.getSageBeforeDate().getTime()) / 2), + "Sensor changed approx: " + NOTE_DATE_FORMAT.format(record.getSageAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getSageBeforeDate()) + )); + } + if (record.isValidCAGE()) { + noteEntries.add(new NoteEntry( + "Site Change", + ISO8601_DATE_FORMAT.format(record.getCageAfterDate().getTime() - (record.getCageAfterDate().getTime() - record.getCageBeforeDate().getTime()) / 2), + "Reservoir changed approx: " + NOTE_DATE_FORMAT.format(record.getCageAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getCageBeforeDate()) + )); + } + if (record.isValidBATTERY()) { + noteEntries.add(new NoteEntry( + "Note", + ISO8601_DATE_FORMAT.format(record.getBatteryAfterDate().getTime() - (record.getBatteryAfterDate().getTime() - record.getBatteryBeforeDate().getTime()) / 2), + "Pump battery changed approx: " + NOTE_DATE_FORMAT.format(record.getBatteryAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getBatteryBeforeDate()) )); } - } - if (record.isValidSAGE()) { - noteEntries.add(new NoteEntry( - "Sensor Start", - ISO8601_DATE_FORMAT.format(record.getSageAfterDate().getTime() - (record.getSageAfterDate().getTime() - record.getSageBeforeDate().getTime()) / 2), - "Sensor changed approx: " + NOTE_DATE_FORMAT.format(record.getSageAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getSageBeforeDate()) - )); - } - if (record.isValidCAGE()) { - noteEntries.add(new NoteEntry( - "Site Change", - ISO8601_DATE_FORMAT.format(record.getCageAfterDate().getTime() - (record.getCageAfterDate().getTime() - record.getCageBeforeDate().getTime()) / 2), - "Reservoir changed approx: " + NOTE_DATE_FORMAT.format(record.getCageAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getCageBeforeDate()) - )); - } - if (record.isValidBATTERY()) { - noteEntries.add(new NoteEntry( - "Note", - ISO8601_DATE_FORMAT.format(record.getBatteryAfterDate().getTime() - (record.getBatteryAfterDate().getTime() - record.getBatteryBeforeDate().getTime()) / 2), - "Pump battery changed approx: " + NOTE_DATE_FORMAT.format(record.getBatteryAfterDate()) + " - " + NOTE_DATE_FORMAT.format(record.getBatteryBeforeDate()) - )); } } boolean uploaded = true; - if (glucoseEntries.size() > 0) { - Response<ResponseBody> result = glucoseEndpoints.sendEntries(glucoseEntries).execute(); + if (sgvEntries.size() > 0) { + Response<ResponseBody> result = sgvEndpoints.sendEntries(sgvEntries).execute(); uploaded = result.isSuccessful(); } - if (bolusEntries.size() > 0) { - Response<ResponseBody> result = bolusEndpoints.sendEntries(bolusEntries).execute(); + if (mbgEntries.size() > 0) { + Response<ResponseBody> result = mbgEndpoints.sendEntries(mbgEntries).execute(); uploaded = uploaded && result.isSuccessful(); } if (treatmentEntries.size() > 0) { Response<ResponseBody> result = treatmentEndpoints.sendEntries(treatmentEntries).execute(); uploaded = uploaded && result.isSuccessful(); } - if (tempBasalAbsoluteEntries.size() > 0) { - Response<ResponseBody> result = tempBasalAbsoluteEndpoints.sendEntries(tempBasalAbsoluteEntries).execute(); + if (tempBasalRateEntries.size() > 0) { + Response<ResponseBody> result = tempBasalRateEndpoints.sendEntries(tempBasalRateEntries).execute(); uploaded = uploaded && result.isSuccessful(); } if (tempBasalPercentEntries.size() > 0) { @@ -238,52 +294,81 @@ class NightScoutUpload { Battery battery = new Battery(record.getBatteryPercentage()); PumpStatus pumpstatus; + // shorten pump status when needed to accommodate mobile browsers + boolean shorten = false; + if ((record.isBolusingSquare() || record.isBolusingDual()) && record.isTempBasalActive()) + shorten = true; + String statusPUMP = "normal"; - if (record.isBolusingNormal()) + if (record.isBolusingNormal()) { statusPUMP = "bolusing"; - else if (record.isBolusingSquare()) - statusPUMP = "square>>" + record.getBolusingDelivered() + "u-" + (record.getBolusingMinutesRemaining() >= 60 ? record.getBolusingMinutesRemaining() / 60 + "h" : "") + record.getBolusingMinutesRemaining() % 60 + "m"; - else if (record.isBolusingDual()) - statusPUMP = "dual>>" + record.getBolusingDelivered() + "u-" + (record.getBolusingMinutesRemaining() >= 60 ? record.getBolusingMinutesRemaining() / 60 + "h" : "") + record.getBolusingMinutesRemaining() % 60 + "m"; - else if (record.isSuspended()) + } else if (record.isSuspended()) { statusPUMP = "suspended"; - else if (record.getTempBasalMinutesRemaining() > 0 & record.getTempBasalPercentage() != 0) - statusPUMP = "temp>>" + record.getTempBasalPercentage() + "%-" + (record.getTempBasalMinutesRemaining() >= 60 ? record.getTempBasalMinutesRemaining() / 60 + "h" : "") + record.getTempBasalMinutesRemaining() % 60 + "m"; - else if (record.getTempBasalMinutesRemaining() > 0) - statusPUMP = "temp>>" + record.getTempBasalRate() + "u-" + (record.getTempBasalMinutesRemaining() >= 60 ? record.getTempBasalMinutesRemaining() / 60 + "h" : "") + record.getTempBasalMinutesRemaining() % 60 + "m"; + } else { + if (record.isBolusingSquare()) { + if (shorten) + statusPUMP = "S>" + record.getBolusingDelivered() + "u-" + record.getBolusingMinutesRemaining() + "m"; + else + statusPUMP = "square>>" + record.getBolusingDelivered() + "u-" + (record.getBolusingMinutesRemaining() >= 60 ? record.getBolusingMinutesRemaining() / 60 + "h" : "") + record.getBolusingMinutesRemaining() % 60 + "m"; + shorten = true; + } else if (record.isBolusingDual()) { + if (shorten) + statusPUMP = "D>" + record.getBolusingDelivered() + "-" + record.getBolusingMinutesRemaining() + "m"; + else + statusPUMP = "dual>>" + record.getBolusingDelivered() + "u-" + (record.getBolusingMinutesRemaining() >= 60 ? record.getBolusingMinutesRemaining() / 60 + "h" : "") + record.getBolusingMinutesRemaining() % 60 + "m"; + shorten = true; + } + if (record.getTempBasalMinutesRemaining() > 0 & record.getTempBasalPercentage() != 0) { + if (shorten) + statusPUMP = " T>" + record.getTempBasalPercentage() + "%-" + record.getTempBasalMinutesRemaining() + "m"; + else + statusPUMP = "temp>>" + record.getTempBasalPercentage() + "%-" + (record.getTempBasalMinutesRemaining() >= 60 ? record.getTempBasalMinutesRemaining() / 60 + "h" : "") + record.getTempBasalMinutesRemaining() % 60 + "m"; + shorten = true; + } else if (record.getTempBasalMinutesRemaining() > 0) { + if (shorten) + statusPUMP = " T>" + record.getTempBasalRate() + "-" + record.getTempBasalMinutesRemaining() + "m"; + else + statusPUMP = "temp>>" + record.getTempBasalRate() + "u-" + (record.getTempBasalMinutesRemaining() >= 60 ? record.getTempBasalMinutesRemaining() / 60 + "h" : "") + record.getTempBasalMinutesRemaining() % 60 + "m"; + shorten = true; + } + } + if (record.getAlert() > 0) statusPUMP = "⚠ " + statusPUMP; String statusCGM = ""; - String statusCGMbattery = ""; if (record.isCgmActive()) { if (record.getTransmitterBattery() > 80) - statusCGMbattery = "::::"; + statusCGM = shorten ? "" : ":::: "; else if (record.getTransmitterBattery() > 55) - statusCGMbattery = ":::."; + statusCGM = shorten ? "" : ":::. "; else if (record.getTransmitterBattery() > 30) - statusCGMbattery = "::.."; + statusCGM = shorten ? "" : "::.. "; else if (record.getTransmitterBattery() > 10) - statusCGMbattery = ":..."; + statusCGM = shorten ? "" : ":... "; else - statusCGMbattery = "...."; + statusCGM = shorten ? "" : ".... "; if (record.isCgmCalibrating()) - statusCGM += " calibrating"; + statusCGM += shorten ? "cal" : "calibrating"; else if (record.isCgmCalibrationComplete()) - statusCGM += " cal.complete"; + statusCGM += shorten ? "cal" : "cal.complete"; else { if (record.isCgmWarmUp()) - statusCGM += "warmup "; - if (record.getCalibrationDueMinutes() > 0) - statusCGM += (record.getCalibrationDueMinutes() >= 60 ? record.getCalibrationDueMinutes() / 60 + "h" : "") + record.getCalibrationDueMinutes() % 60 + "m"; + statusCGM += shorten ? "WU" : "warmup "; + if (record.getCalibrationDueMinutes() > 0) { + if (shorten) + statusCGM += (record.getCalibrationDueMinutes() >= 120 ? record.getCalibrationDueMinutes() / 60 + "h" : record.getCalibrationDueMinutes() + "m"); + else + statusCGM += (record.getCalibrationDueMinutes() >= 60 ? record.getCalibrationDueMinutes() / 60 + "h" : "") + record.getCalibrationDueMinutes() % 60 + "m"; + } else - statusCGM += "calibrate now!"; + statusCGM += shorten ? "cal.now" : "calibrate now!"; } } else { - statusCGM+= "cgm n/a"; + statusCGM += shorten ? "n/a" : "cgm n/a"; } - pumpstatus = new PumpStatus(false, false, statusPUMP + " " + statusCGMbattery + " " + statusCGM); + pumpstatus = new PumpStatus(false, false, statusPUMP + " " + statusCGM); PumpInfo pumpInfo = new PumpInfo( ISO8601_DATE_FORMAT.format(record.getEventDate()), diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java index e191ecd0fbb5350a9eae61291998000884bb6562..30dcd7cdc73e1c3bddebe863d3af2c5201ade573 100644 --- a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java +++ b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java @@ -60,6 +60,8 @@ public class NightscoutUploadIntentService extends IntentService { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); Boolean enableRESTUpload = prefs.getBoolean("EnableRESTUpload", false); + Boolean enableTreatmentsUpload = prefs.getBoolean("EnableTreatmentsUpload", false); + try { if (enableRESTUpload) { long start = System.currentTimeMillis(); @@ -67,7 +69,7 @@ public class NightscoutUploadIntentService extends IntentService { String urlSetting = prefs.getString(mContext.getString(R.string.preference_nightscout_url), ""); String secretSetting = prefs.getString(mContext.getString(R.string.preference_api_secret), "YOURAPISECRET"); Boolean uploadSuccess = mNightScoutUpload.doRESTUpload(urlSetting, - secretSetting, DataStore.getInstance().getUploaderBatteryLevel(), records); + secretSetting, enableTreatmentsUpload, DataStore.getInstance().getUploaderBatteryLevel(), records); if (uploadSuccess) { mRealm.beginTransaction(); for (PumpStatusEvent updateRecord : records) { diff --git a/app/src/main/java/info/nightscout/android/utils/DataStore.java b/app/src/main/java/info/nightscout/android/utils/DataStore.java index e9a4e0339078630b4593e57f2c1bf0f22497903d..c6f24d69bfb4a71d813d6e54400edc5e92f9277a 100644 --- a/app/src/main/java/info/nightscout/android/utils/DataStore.java +++ b/app/src/main/java/info/nightscout/android/utils/DataStore.java @@ -1,6 +1,8 @@ package info.nightscout.android.utils; +import java.util.Date; + /** * Created by volker on 30.03.2017. */ @@ -8,8 +10,11 @@ package info.nightscout.android.utils; public class DataStore { private static DataStore instance; + private Date uploaderStartDate; + private long activePumpMac = 0; private int uploaderBatteryLevel = 0; + private int pumpCgmNA = 0; private int CommsSuccess = 0; @@ -19,6 +24,7 @@ public class DataStore { private int CommsSgvSuccess = 0; private int PumpLostSensorError = 0; private int PumpClockError = 0; + private int PumpBatteryError = 0; private DataStore() {} @@ -26,10 +32,15 @@ public class DataStore { if (DataStore.instance == null) { instance = new DataStore(); + instance.uploaderStartDate = new Date(); } return instance; } + public Date getUploaderStartDate() { + return uploaderStartDate; + } + public long getActivePumpMac() { return activePumpMac; } @@ -132,6 +143,16 @@ public class DataStore { this.PumpClockError = 0; } + public int getPumpBatteryError() { + return PumpBatteryError; + } + + public int incPumpBatteryError() { return PumpBatteryError++; } + + public void clearPumpBatteryError() { + this.PumpBatteryError = 0; + } + public void clearAllCommsErrors() { this.CommsSuccess = 0; this.CommsError = 0; @@ -139,5 +160,6 @@ public class DataStore { this.CommsSignalError = 0; this.PumpLostSensorError = 0; this.PumpClockError = 0; + this.PumpBatteryError = 0; } } diff --git a/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java index e8f056ed7e9845d3a3d9ec9ef6f494a2575587aa..22be13663c6931536562a3aa7ecb7ee20c4c4089 100644 --- a/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java +++ b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java @@ -53,7 +53,6 @@ public class XDripPlusUploadIntentService extends IntentService { Log.i(TAG, "onCreate called"); mContext = this.getBaseContext(); } -// check this stuff!!! pogman! @Override protected void onHandleIntent(Intent intent) { @@ -62,8 +61,9 @@ public class XDripPlusUploadIntentService extends IntentService { RealmResults<PumpStatusEvent> all_records = mRealm .where(PumpStatusEvent.class) - .notEqualTo("validSGV", false) -// .notEqualTo("sgv", 0) + .equalTo("validSGV", true) + .or() + .equalTo("validBGL", true) .findAllSorted("eventDate", Sort.DESCENDING); // get the most recent record and send that @@ -141,20 +141,22 @@ public class XDripPlusUploadIntentService extends IntentService { } private void addSgvEntry(JSONArray entriesArray, PumpStatusEvent pumpRecord) throws Exception { - JSONObject json = new JSONObject(); - // TODO replace with Retrofit/EntriesSerializer - json.put("sgv", pumpRecord.getSgv()); - json.put("direction", EntriesSerializer.getDirectionString(pumpRecord.getCgmTrend())); - json.put("device", pumpRecord.getDeviceName()); - json.put("type", "sgv"); - json.put("date", pumpRecord.getCgmDate().getTime()); - json.put("dateString", pumpRecord.getCgmDate()); - - entriesArray.put(json); + if (pumpRecord.isValidSGV()) { + JSONObject json = new JSONObject(); + // TODO replace with Retrofit/EntriesSerializer + json.put("sgv", pumpRecord.getSgv()); + json.put("direction", EntriesSerializer.getDirectionString(pumpRecord.getCgmTrend())); + json.put("device", pumpRecord.getDeviceName()); + json.put("type", "sgv"); + json.put("date", pumpRecord.getCgmDate().getTime()); + json.put("dateString", pumpRecord.getCgmDate()); + + entriesArray.put(json); + } } private void addMbgEntry(JSONArray entriesArray, PumpStatusEvent pumpRecord) throws Exception { - if (pumpRecord.hasRecentBolusWizard()) { + if (pumpRecord.isValidBGL()) { JSONObject json = new JSONObject(); // TODO replace with Retrofit/EntriesSerializer diff --git a/app/src/main/java/info/nightscout/api/BolusEndpoints.java b/app/src/main/java/info/nightscout/api/MbgEndpoints.java similarity index 63% rename from app/src/main/java/info/nightscout/api/BolusEndpoints.java rename to app/src/main/java/info/nightscout/api/MbgEndpoints.java index a1c2a56e35eacaa534b5e5ede7de4fca577672c8..9c443342275e0b708b7beaef4c8c489375483479 100644 --- a/app/src/main/java/info/nightscout/api/BolusEndpoints.java +++ b/app/src/main/java/info/nightscout/api/MbgEndpoints.java @@ -8,57 +8,36 @@ import retrofit2.http.Body; import retrofit2.http.Headers; import retrofit2.http.POST; -public interface BolusEndpoints { +public interface MbgEndpoints { - class BolusEntry { + class MbgEntry { String type; String dateString; long date; int mbg; String device; - public BolusEntry() { } - - public String getType() { - return type; - } + public MbgEntry() { } public void setType(String type) { this.type = type; } - public String getDateString() { - return dateString; - } - public void setDateString(String dateString) { this.dateString = dateString; } - public long getDate() { - return date; - } - public void setDate(long date) { this.date = date; } - public int getMbg() { - return mbg; - } - public void setMbg(int mbg) { this.mbg = mbg; } - public String getDevice() { - return device; - } - public void setDevice(String device) { this.device = device; } - } @Headers({ @@ -66,8 +45,7 @@ public interface BolusEndpoints { "Content-type: application/json" }) @POST("/api/v1/entries") - Call<ResponseBody> sendEntries(@Body List<BolusEntry> entries); - + Call<ResponseBody> sendEntries(@Body List<MbgEntry> entries); } diff --git a/app/src/main/java/info/nightscout/api/GlucoseEndpoints.java b/app/src/main/java/info/nightscout/api/SgvEndpoints.java similarity index 62% rename from app/src/main/java/info/nightscout/api/GlucoseEndpoints.java rename to app/src/main/java/info/nightscout/api/SgvEndpoints.java index d34c5e7abdae5efadc346bc560eb54aee252dacb..96dd7bb376d5e73ad325bea640d134ab66144ce5 100644 --- a/app/src/main/java/info/nightscout/api/GlucoseEndpoints.java +++ b/app/src/main/java/info/nightscout/api/SgvEndpoints.java @@ -8,10 +8,9 @@ import retrofit2.http.Body; import retrofit2.http.Headers; import retrofit2.http.POST; -public interface GlucoseEndpoints { - - class GlucoseEntry { +public interface SgvEndpoints { + class SgvEntry { String type; String dateString; long date; @@ -19,55 +18,31 @@ public interface GlucoseEndpoints { String direction; String device; - public String getType() { - return type; - } - public void setType(String type) { this.type = type; } - public String getDateString() { - return dateString; - } - public void setDateString(String dateString) { this.dateString = dateString; } - public long getDate() { - return date; - } - public void setDate(long date) { this.date = date; } - public int getSgv() { - return sgv; - } - public void setSgv(int sgv) { this.sgv = sgv; } - public String getDirection() { - return direction; - } - public void setDirection(String direction) { this.direction = direction; } - public String getDevice() { - return device; - } - public void setDevice(String device) { this.device = device; } - public GlucoseEntry() { } + public SgvEntry() { } } @Headers({ @@ -75,8 +50,7 @@ public interface GlucoseEndpoints { "Content-type: application/json" }) @POST("/api/v1/entries") - Call<ResponseBody> sendEntries(@Body List<GlucoseEntry> entries); - + Call<ResponseBody> sendEntries(@Body List<SgvEntry> entries); } diff --git a/app/src/main/java/info/nightscout/api/TempBasalAbsoluteEndpoints.java b/app/src/main/java/info/nightscout/api/TempBasalRateEndpoints.java similarity index 70% rename from app/src/main/java/info/nightscout/api/TempBasalAbsoluteEndpoints.java rename to app/src/main/java/info/nightscout/api/TempBasalRateEndpoints.java index d393223194a5fe2cd348e0121e9998d243387216..27f7d4ff9fbd7e91d4502ead0e14ebe93e494d5b 100644 --- a/app/src/main/java/info/nightscout/api/TempBasalAbsoluteEndpoints.java +++ b/app/src/main/java/info/nightscout/api/TempBasalRateEndpoints.java @@ -8,16 +8,16 @@ import retrofit2.http.Body; import retrofit2.http.Headers; import retrofit2.http.POST; -public interface TempBasalAbsoluteEndpoints { +public interface TempBasalRateEndpoints { - class TempBasalAbsoluteEntry { + class TempBasalRateEntry { String eventType = "Temp Basal"; String created_at; String notes; float duration; float absolute; - public TempBasalAbsoluteEntry(String created_at, String notes, float duration, float absolute) { + public TempBasalRateEntry(String created_at, String notes, float duration, float absolute) { this.created_at = created_at; this.notes = notes; this.duration = duration; @@ -30,5 +30,5 @@ public interface TempBasalAbsoluteEndpoints { "Content-type: application/json" }) @POST("/api/v1/treatments") - Call<ResponseBody> sendEntries(@Body List<TempBasalAbsoluteEntry> entries); + Call<ResponseBody> sendEntries(@Body List<TempBasalRateEntry> entries); } diff --git a/app/src/main/java/info/nightscout/api/TreatmentEndpoints.java b/app/src/main/java/info/nightscout/api/TreatmentEndpoints.java index 0ebb1b43325bb94bcd573e283f905587f04811bc..129af210241ddda4230f8401b41647a9ed4d69bf 100644 --- a/app/src/main/java/info/nightscout/api/TreatmentEndpoints.java +++ b/app/src/main/java/info/nightscout/api/TreatmentEndpoints.java @@ -1,7 +1,6 @@ package info.nightscout.api; -import android.support.annotation.Nullable; - +import java.math.BigDecimal; import java.util.List; import okhttp3.ResponseBody; @@ -18,92 +17,66 @@ public interface TreatmentEndpoints { String enteredinsulin; String splitNow; String splitExt; + String units; + String glucoseType; String notes; String device; float insulin; float duration; float relative; - - public String getEventType() { - return eventType; - } + BigDecimal glucose; public void setEventType(String eventType) { this.eventType = eventType; } - public String getCreatedAt() { - return created_at; - } - public void setCreatedAt(String created_at) { this.created_at = created_at; } - public String getDevice() { - return device; - } - public void setDevice(String device) { this.device = device; } - public float getInsulin() { - return insulin; - } - public void setInsulin(float insulin) { this.insulin = insulin; } - public float getDuration() { - return duration; + public void setGlucose(BigDecimal glucose) { + this.glucose = glucose; } public void setDuration(float duration) { this.duration = duration; } - public float getRelative() { - return relative; - } - public void setRelative(float relative) { this.relative = relative; } - public String getEnteredinsulin() { - return enteredinsulin; - } - public void setEnteredinsulin(String enteredinsulin) { this.enteredinsulin = enteredinsulin; } - public String getSplitNow() { - return splitNow; - } - public void setSplitNow(String splitNow) { this.splitNow = splitNow; } - public String getSplitExt() { - return splitExt; - } - public void setSplitExt(String splitExt) { this.splitExt = splitExt; } - public String getNotes() { - return notes; + public void setUnits(String units) { + this.units = units; + } + + public void setGlucoseType(String glucoseType) { + this.glucoseType = glucoseType; } public void setNotes(String notes) { this.notes = notes; } - } @Headers({ diff --git a/app/src/main/java/info/nightscout/api/UploadApi.java b/app/src/main/java/info/nightscout/api/UploadApi.java index 05e2520576e3b55474874d928bc883558b4634dc..70ce741c202ab545cbbd805b2fa429dab1887551 100644 --- a/app/src/main/java/info/nightscout/api/UploadApi.java +++ b/app/src/main/java/info/nightscout/api/UploadApi.java @@ -14,20 +14,20 @@ import retrofit2.converter.gson.GsonConverterFactory; public class UploadApi { private Retrofit retrofit; - private GlucoseEndpoints glucoseEndpoints; - private BolusEndpoints bolusEndpoints; + private SgvEndpoints sgvEndpoints; + private MbgEndpoints mbgEndpoints; private DeviceEndpoints deviceEndpoints; private TreatmentEndpoints treatmentEndpoints; - private TempBasalAbsoluteEndpoints tempBasalAbsoluteEndpoints; + private TempBasalRateEndpoints tempBasalRateEndpoints; private TempBasalPercentEndpoints tempBasalPercentEndpoints; private TempBasalCancelEndpoints tempBasalCancelEndpoints; private NoteEndpoints noteEndpoints; - public GlucoseEndpoints getGlucoseEndpoints() { - return glucoseEndpoints; + public SgvEndpoints getSgvEndpoints() { + return sgvEndpoints; } - public BolusEndpoints getBolusEndpoints() { - return bolusEndpoints; + public MbgEndpoints getMbgEndpoints() { + return mbgEndpoints; } public DeviceEndpoints getDeviceEndpoints() { return deviceEndpoints; @@ -35,8 +35,8 @@ public class UploadApi { public TreatmentEndpoints getTreatmentEndpoints() { return treatmentEndpoints; } - public TempBasalAbsoluteEndpoints getTempBasalAbsoluteEndpoints() { - return tempBasalAbsoluteEndpoints; + public TempBasalRateEndpoints getTempBasalRateEndpoints() { + return tempBasalRateEndpoints; } public TempBasalPercentEndpoints getTempBasalPercentEndpoints() { return tempBasalPercentEndpoints; @@ -88,11 +88,11 @@ public class UploadApi { .addConverterFactory(GsonConverterFactory.create()) .build(); - glucoseEndpoints = retrofit.create(GlucoseEndpoints.class); - bolusEndpoints = retrofit.create(BolusEndpoints.class); + sgvEndpoints = retrofit.create(SgvEndpoints.class); + mbgEndpoints = retrofit.create(MbgEndpoints.class); deviceEndpoints = retrofit.create(DeviceEndpoints.class); treatmentEndpoints = retrofit.create(TreatmentEndpoints.class); - tempBasalAbsoluteEndpoints = retrofit.create(TempBasalAbsoluteEndpoints.class); + tempBasalRateEndpoints = retrofit.create(TempBasalRateEndpoints.class); tempBasalPercentEndpoints = retrofit.create(TempBasalPercentEndpoints.class); tempBasalCancelEndpoints = retrofit.create(TempBasalCancelEndpoints.class); noteEndpoints = retrofit.create(NoteEndpoints.class); diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index ff89a6f2bb0e9027c0f4fc857a79595b7a6fe4d5..d590b78082d9dcf96ba6f0d30679d45121be3e77 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -19,12 +19,12 @@ android:switchTextOn="2" android:title="Decimals"/> <ListPreference - android:key="pollInterval" android:defaultValue="300000" - android:title="@string/preferences_poll_interval" - android:summary="%s" android:entries="@array/poll_interval" - android:entryValues="@array/poll_interval_millis"/> + android:entryValues="@array/poll_interval_millis" + android:key="pollInterval" + android:summary="%s" + android:title="@string/preferences_poll_interval" /> <info.nightscout.android.utils.CustomSwitchPreference android:disableDependentsState="false" android:key="doublePollOnPumpAway" @@ -70,6 +70,10 @@ android:dialogTitle="Enter your Nightscout API secret" android:key="@string/preference_api_secret" android:title="API Secret"/> + <CheckBoxPreference android:title="Treatments" + android:key="EnableTreatmentsUpload" + android:dependency="@string/preference_enable_rest_upload" + android:summary="Enable upload of treatments to Nightscout"/> <Preference android:title="scan NS-Autoconfig QR-Code" android:key="scanButton" android:dependency="@string/preference_enable_rest_upload"