code cleanup, set uuid properly

This commit is contained in:
Milos Kozak 2019-06-05 16:29:19 +02:00
parent a0c00273bc
commit 21a49f731c
14 changed files with 188 additions and 199 deletions

View file

@ -1387,6 +1387,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEvents(long start, long end, boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", start, end);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public void preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
OverlappingIntervals offlineEvents = new OverlappingIntervals();
for (int i = 0; i < list.size(); i++) {

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolS
import info.nightscout.androidaps.plugins.general.tidepool.utils.RateLimit
import info.nightscout.androidaps.receivers.ChargingStateReceiver
import info.nightscout.androidaps.utils.SP
import info.nightscout.androidaps.utils.T
import org.slf4j.LoggerFactory
import java.util.*
@ -63,7 +64,7 @@ object TidepoolPlugin : PluginBase(PluginDescription()
if (enabled()
&& (!SP.getBoolean(R.string.key_tidepool_only_while_charging, false) || ChargingStateReceiver.isCharging())
&& (!SP.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || wifiConnected)
&& RateLimit.ratelimit("tidepool-new-data-upload", 1200))
&& RateLimit.ratelimit("tidepool-new-data-upload", T.mins(4).secs().toInt()))
doUpload()
}

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.tidepool.comm
import info.nightscout.androidaps.logging.L
import okhttp3.Interceptor
import okhttp3.Response
import okio.Buffer
import org.slf4j.LoggerFactory
import java.io.IOException
@ -19,7 +20,12 @@ class InfoInterceptor(tag: String) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
if (request != null && request.body() != null) {
if (L.isEnabled(L.TIDEPOOL)) log.debug("Interceptor Body size: " + request.body()!!.contentLength())
if (L.isEnabled(L.TIDEPOOL)) {
log.debug("Interceptor Body size: " + request.body()!!.contentLength())
val requestBuffer = Buffer()
request.body()!!.writeTo(requestBuffer)
log.debug("Interceptor Body: " + requestBuffer.readUtf8())
}
}
return chain.proceed(request!!)
}

View file

@ -141,59 +141,38 @@ object TidepoolUploader {
extendWakeLock(60000)
session.iterations++
val chunk = UploadChunk.getNext(session)
if (chunk != null) {
if (chunk.length == 2) {
if (L.isEnabled(L.TIDEPOOL)) log.debug("Empty data set - marking as succeeded")
doCompleted()
} else {
val body = RequestBody.create(MediaType.parse("application/json"), chunk)
val call = session.service!!.doUpload(session.token!!, session.datasetReply!!.getUploadId()!!, body)
status("Uploading")
call.enqueue(TidepoolCallback<UploadReplyMessage>(session, "Data Upload", {
UploadChunk.setLastEnd(session.end)
if (OpenDatasetRequestMessage.isNormal()) {
doClose(session)
} else {
doCompleted()
}
}, { releaseWakeLock() }))
}
} else {
if (chunk == null) {
log.error("Upload chunk is null, cannot proceed")
releaseWakeLock()
} else if (chunk.length == 2) {
if (L.isEnabled(L.TIDEPOOL)) log.debug("Empty data set - marking as succeeded")
doCompletedAndReleaseWakelock()
} else {
val body = RequestBody.create(MediaType.parse("application/json"), chunk)
val call = session.service!!.doUpload(session.token!!, session.datasetReply!!.getUploadId()!!, body)
status("Uploading")
call.enqueue(TidepoolCallback<UploadReplyMessage>(session, "Data Upload", {
UploadChunk.setLastEnd(session.end)
doCompletedAndReleaseWakelock()
}, {
releaseWakeLock()
}))
}
}
private fun status(status: String) {
log.debug("New status: $status")
if (L.isEnabled(L.TIDEPOOL))
log.debug("New status: $status")
MainApp.bus().post(EventTidepoolStatus(status))
}
private fun doCompleted() {
private fun doCompletedAndReleaseWakelock() {
status("Completed OK")
if (L.isEnabled(L.TIDEPOOL)) log.debug("ALL COMPLETED OK!")
releaseWakeLock()
}
private fun doClose(session: Session) {
status("Closing")
extendWakeLock(20000)
val call = session.service!!.closeDataSet(session.token!!, session.datasetReply!!.getUploadId()!!, CloseDatasetRequestMessage().getBody())
call.enqueue(TidepoolCallback(session, "Session Stop", { closeSuccess() }, {}))
}
private fun closeSuccess() {
status("Closed")
if (L.isEnabled(L.TIDEPOOL)) log.debug("Close success")
releaseWakeLock()
}
private fun getDataSet(session: Session) {
val call = session.service!!.getDataSet(session.token!!, "bogus")
call.enqueue(TidepoolCallback(session, "Get Data", {}, {}))
}
fun deleteDataSet(session: Session) {
if (session.datasetReply?.id != null) {
val call = session.service?.deleteDataSet(session.token!!, session.datasetReply!!.id!!)

View file

@ -3,10 +3,8 @@ package info.nightscout.androidaps.plugins.general.tidepool.comm
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.general.tidepool.elements.*
import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance
import info.nightscout.androidaps.plugins.general.tidepool.utils.LogSlider
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.SP
@ -16,35 +14,32 @@ import java.util.*
object UploadChunk {
private val TAG = "TidepoolUploadChunk"
private val MAX_UPLOAD_SIZE = T.days(7).msecs() // don't change this
private val MAX_LATENCY_THRESHOLD_MINUTES: Long = 1440 // minutes per day
private val log = LoggerFactory.getLogger(L.TIDEPOOL)
fun getNext(session: Session): String? {
session.start = getLastEnd()
session.end = maxWindow(session.start)
session.end = Math.min(session.start + MAX_UPLOAD_SIZE, DateUtil.now())
val result = get(session.start, session.end)
if (result != null && result.length < 3) {
if (result.length < 3) {
if (L.isEnabled(L.TIDEPOOL)) log.debug("No records in this time period, setting start to best end time")
setLastEnd(Math.max(session.end, getOldestRecordTimeStamp()))
}
return result
}
operator fun get(start: Long, end: Long): String? {
operator fun get(start: Long, end: Long): String {
if (L.isEnabled(L.TIDEPOOL)) log.debug("Syncing data between: " + DateUtil.dateAndTimeFullString(start) + " -> " + DateUtil.dateAndTimeFullString(end))
if (end <= start) {
if (L.isEnabled(L.TIDEPOOL)) log.debug("End is <= start: " + DateUtil.dateAndTimeFullString(start) + " " + DateUtil.dateAndTimeFullString(end))
return null
return ""
}
if (end - start > MAX_UPLOAD_SIZE) {
if (L.isEnabled(L.TIDEPOOL)) log.debug("More than max range - rejecting")
return null
return ""
}
val records = LinkedList<BaseElement>()
@ -57,10 +52,6 @@ object UploadChunk {
return GsonInstance.defaultGsonInstance().toJson(records)
}
private fun maxWindow(last_end: Long): Long {
return Math.min(last_end + MAX_UPLOAD_SIZE, DateUtil.now())
}
fun getLastEnd(): Long {
val result = SP.getLong(R.string.key_tidepool_last_end, 0)
return Math.max(result, DateUtil.now() - T.months(2).msecs())
@ -75,80 +66,54 @@ object UploadChunk {
}
}
// numeric limits must match max time windows
private fun getOldestRecordTimeStamp(): Long {
// TODO we could make sure we include records older than the first bg record for completeness
val start: Long = 0
val end = DateUtil.now()
val bgReadingList = MainApp.getDbHelper().getBgreadingsDataFromTime(start, end, true)
return if (bgReadingList.size > 0)
bgReadingList[0].date
else -1
}
internal fun getTreatments(start: Long, end: Long): List<BaseElement> {
val result = LinkedList<BaseElement>()
val treatments = TreatmentsPlugin.getPlugin().service.getTreatmentDataFromTime(start, end, true)
for (treatment in treatments) {
if (treatment.carbs > 0) {
result.add(WizardElement.fromTreatment(treatment))
result.add(WizardElement(treatment))
} else if (treatment.insulin > 0) {
result.add(BolusElement.fromTreatment(treatment))
} else {
// note only TODO
result.add(BolusElement(treatment))
}
}
return result
}
// numeric limits must match max time windows
internal fun getOldestRecordTimeStamp(): Long {
// TODO we could make sure we include records older than the first bg record for completeness
val start: Long = 0
val end = DateUtil.now()
val bgReadingList = MainApp.getDbHelper().getBgreadingsDataFromTime(start, end, false)
return if (bgReadingList.size > 0)
bgReadingList[0].date
else -1
}
@Suppress("UNUSED_PARAMETER")
internal fun getBloodTests(start: Long, end: Long): List<BloodGlucoseElement> {
return ArrayList()
// return BloodGlucoseElement.fromBloodTests(BloodTest.latestForGraph(1800, start, end));
val readings = MainApp.getDbHelper().getCareportalEvents(start, end, true)
if (L.isEnabled(L.TIDEPOOL))
log.debug("${readings.size} CPs selected for upload")
return BloodGlucoseElement.fromCareportalEvents(readings)
}
internal fun getBgReadings(start: Long, end: Long): List<SensorGlucoseElement> {
val readings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, end, true)
if (L.isEnabled(L.TIDEPOOL))
log.debug("${readings.size} selected for upload")
log.debug("${readings.size} BGs selected for upload")
return SensorGlucoseElement.fromBgReadings(readings)
}
internal fun getBasals(start: Long, end: Long): List<BasalElement> {
val basals = LinkedList<BasalElement>()
val aplist = MainApp.getDbHelper().getTemporaryBasalsDataFromTime(start, end, true)
var current: BasalElement? = null
for (temporaryBasal in aplist) {
val this_rate = temporaryBasal.tempBasalConvertedToAbsolute(temporaryBasal.date, ProfileFunctions.getInstance().getProfile(temporaryBasal.date))
if (current != null) {
if (this_rate != current.rate) {
current.duration = temporaryBasal.date - current.timestamp
if (L.isEnabled(L.TIDEPOOL)) log.debug("Adding current: " + current.toS())
if (current.isValid()) {
basals.add(current)
} else {
if (L.isEnabled(L.TIDEPOOL)) log.debug("Current basal is invalid: " + current.toS())
}
current = null
} else {
if (L.isEnabled(L.TIDEPOOL)) log.debug("Same rate as previous basal record: " + current.rate + " " + temporaryBasal.toStringFull())
}
}
if (current == null) {
current = BasalElement().create(this_rate, temporaryBasal.date, 0, UUID.nameUUIDFromBytes(("tidepool-basal" + temporaryBasal.date).toByteArray()).toString()) // start duration is 0
}
}
return basals
}
private fun getLatencySliderValue(position: Int): Int {
return LogSlider.calc(0, 300, 15.0, MAX_LATENCY_THRESHOLD_MINUTES.toDouble(), position).toInt()
val tbrs = MainApp.getDbHelper().getTemporaryBasalsDataFromTime(start, end, true)
if (L.isEnabled(L.TIDEPOOL))
log.debug("${tbrs.size} TBRs selected for upload")
return BasalElement.fromTemporaryBasals(tbrs)
}
}

View file

@ -1,9 +1,12 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import java.util.*
class BasalElement : BaseElement() {
class BasalElement(tbr: TemporaryBasal)
: BaseElement(tbr.date, UUID.nameUUIDFromBytes(("AAPS-basal" + tbr.date).toByteArray()).toString()) {
internal var timestamp: Long = 0 // not exposed
@ -22,21 +25,18 @@ class BasalElement : BaseElement() {
init {
type = "basal";
timestamp = tbr.date
rate = tbr.tempBasalConvertedToAbsolute(tbr.date, ProfileFunctions.getInstance().getProfile(tbr.date))
duration = duration
}
fun create(rate: Double, timeStart: Long, duration: Long, uuid: String) : BasalElement {
this.timestamp = timeStart
this.rate = rate
this.duration = duration
populate(timeStart, uuid)
return this
}
internal fun isValid(): Boolean {
return rate > -1 && duration > 0
}
internal fun toS(): String {
return rate.toString() + " Start: " + DateUtil.dateAndTimeFullString(timestamp) + " for: " + DateUtil.niceTimeScalar(duration)
companion object {
internal fun fromTemporaryBasals(tbrList: List<TemporaryBasal>): List<BasalElement> {
val results = LinkedList<BasalElement>()
for (tbr in tbrList) {
results.add(BasalElement(tbr))
}
return results
}
}
}

View file

@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.utils.DateUtil
open class BaseElement {
open class BaseElement(timestamp: Long, uuid: String) {
@Expose
var deviceTime: String = ""
@Expose
@ -15,16 +15,13 @@ open class BaseElement {
@Expose
var origin: Origin? = null
internal fun populate(timestamp: Long, uuid: String): BaseElement {
init {
deviceTime = DateUtil.toISONoZone(timestamp)
time = DateUtil.toISOAsUTC(timestamp)
timezoneOffset = DateUtil.getTimeZoneOffsetMinutes(timestamp) // TODO
origin = Origin(uuid)
return this
}
inner class Origin internal constructor(@field:Expose
internal var id: String)
}

View file

@ -1,8 +1,15 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
import java.util.*
class BloodGlucoseElement : BaseElement() {
class BloodGlucoseElement(careportalEvent: CareportalEvent)
: BaseElement(careportalEvent.date, UUID.nameUUIDFromBytes(("AAPS-bg" + careportalEvent.date).toByteArray()).toString()) {
@Expose
var subType: String = "manual"
@ -11,23 +18,24 @@ class BloodGlucoseElement : BaseElement() {
@Expose
var value: Int = 0
/* TODO: from careportal ????
fun fromBloodTest(bloodtest: BloodTest): BloodGlucoseElement {
val bg = BloodGlucoseElement()
bg.populate(bloodtest.timestamp, bloodtest.uuid)
bg.subType = "manual" // TODO
bg.value = bloodtest.mgdl.toInt()
return bg
init {
subType = "manual" // TODO
var json = if (careportalEvent.json != null) JSONObject(careportalEvent.json) else JSONObject()
value = Profile.toMgdl(JsonHelper.safeGetDouble(json, "glucose"), JsonHelper.safeGetString(json, "units", Constants.MGDL)).toInt()
}
fun fromBloodTests(bloodTestList: List<BloodTest>?): List<BloodGlucoseElement>? {
if (bloodTestList == null) return null
val results = LinkedList<BloodGlucoseElement>()
for (bt in bloodTestList) {
results.add(fromBloodTest(bt))
companion object {
fun fromCareportalEvents(careportalList: List<CareportalEvent>): List<BloodGlucoseElement> {
val results = LinkedList<BloodGlucoseElement>()
for (bt in careportalList) {
if (bt.eventType == CareportalEvent.MBG || bt.eventType == CareportalEvent.BGCHECK) {
val bge = BloodGlucoseElement(bt)
if (bge.value > 0)
results.add(BloodGlucoseElement(bt))
}
}
return results
}
return results
}
*/
}

View file

@ -2,8 +2,11 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.plugins.treatments.Treatment
import java.util.*
class BolusElement(treatment: Treatment)
: BaseElement(treatment.date, UUID.nameUUIDFromBytes(("AAPS-bolus" + treatment.date).toByteArray()).toString()) {
class BolusElement : BaseElement() {
@Expose
var subType = "normal"
@Expose
@ -13,18 +16,7 @@ class BolusElement : BaseElement() {
init {
type = "bolus";
}
fun create(insulinDelivered: Double, timestamp: Long, uuid: String): BolusElement {
this.normal = insulinDelivered
this.expectedNormal = insulinDelivered
populate(timestamp, uuid)
return this
}
companion object {
fun fromTreatment(treatment: Treatment): BolusElement {
return BolusElement().create(treatment.insulin, treatment.date, "uuid-AAPS")
}
normal = treatment.insulin
expectedNormal = treatment.insulin
}
}

View file

@ -4,7 +4,8 @@ import com.google.gson.annotations.Expose
import info.nightscout.androidaps.db.BgReading
import java.util.*
class SensorGlucoseElement : BaseElement() {
class SensorGlucoseElement(bgReading: BgReading)
: BaseElement(bgReading.date, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.date).toByteArray()).toString()) {
@Expose
internal var units: String = "mg/dL"
@ -13,20 +14,14 @@ class SensorGlucoseElement : BaseElement() {
init {
this.type = "cbg"
value = bgReading.value.toInt()
}
companion object {
internal fun fromBgReading(bgReading: BgReading): SensorGlucoseElement {
val sensorGlucose = SensorGlucoseElement()
sensorGlucose.populate(bgReading.date, "uuid-AAPS")
sensorGlucose.value = bgReading.value.toInt()
return sensorGlucose
}
internal fun fromBgReadings(bgReadingList: List<BgReading>): List<SensorGlucoseElement> {
val results = LinkedList<SensorGlucoseElement>()
for (bgReading in bgReadingList) {
results.add(fromBgReading(bgReading))
results.add(SensorGlucoseElement(bgReading))
}
return results
}

View file

@ -1,10 +1,14 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.R2.string.result
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.treatments.Treatment
import org.json.JSONObject
import java.util.*
class WizardElement internal constructor() : BaseElement() {
class WizardElement(treatment: Treatment)
: BaseElement(treatment.date, UUID.nameUUIDFromBytes(("AAPS-wizard" + treatment.date).toByteArray()).toString()) {
@Expose
var units = "mg/dL"
@ -17,21 +21,51 @@ class WizardElement internal constructor() : BaseElement() {
init {
type = "wizard"
}
companion object {
fun fromTreatment(treatment: Treatment): WizardElement {
val result = WizardElement().populate(treatment.date, "uuid-AAPS") as WizardElement
result.carbInput = treatment.carbs
result.insulinCarbRatio = ProfileFunctions.getInstance().getProfile(treatment.date)!!.ic
if (treatment.insulin > 0) {
result.bolus = BolusElement().create(treatment.insulin, treatment.date, "uuid-AAPS")
} else {
result.bolus = BolusElement().create(0.0001, treatment.date, "uuid-AAPS") // fake insulin record
}
return result
carbInput = treatment.carbs
insulinCarbRatio = treatment.ic;
if (treatment.insulin > 0) {
bolus = BolusElement(treatment)
} else {
var fake = Treatment()
fake.insulin = 0.0001
fake.date = treatment.date;
bolus = BolusElement(fake) // fake insulin record
}
}
}
/* TODO fill the rest
{
"type": "wizard",
"bgInput": 16.152676653942503,
"bgTarget": {
"low": 3.6079861941795968,
"high": 6.938434988806917
},
"bolus": "22239d4d592b48ae920b28971cceb48b",
"carbInput": 57,
"insulinCarbRatio": 24,
"insulinOnBoard": 24.265,
"insulinSensitivity": 4.329583433015516,
"recommended": {
"carb": 2.5,
"correction": 2.25,
"net": 0
},
"units": "mmol/L",
"_active": true,
"_groupId": "abcdef",
"_schemaVersion": 0,
"_version": 0,
"clockDriftOffset": 0,
"conversionOffset": 0,
"createdTime": "2018-05-14T08:17:14.353Z",
"deviceId": "DevId0987654321",
"deviceTime": "2018-05-14T18:17:09",
"guid": "18d90ea0-5915-4e95-a8b2-cb22819ce696",
"id": "087c94ccdae84eb5a76b8205a244ec6b",
"time": "2018-05-14T08:17:09.353Z",
"timezoneOffset": 600,
"uploadId": "SampleUploadId"
}
*/

View file

@ -55,10 +55,6 @@ class OpenDatasetRequestMessage : BaseMessage() {
companion object {
internal val UPLOAD_TYPE = "continuous"
fun isNormal(): Boolean {
return UPLOAD_TYPE == "normal"
}
}
}

View file

@ -1,12 +0,0 @@
package info.nightscout.androidaps.plugins.general.tidepool.utils
object LogSlider {
// logarithmic slider with positions start - end representing values start - end, calculate value at selected position
fun calc(sliderStart: Int, sliderEnd: Int, start: Double, end: Double, position: Int): Double {
var valueStart = start
var valueEnd = end
valueStart = Math.log(Math.max(1.0, valueStart))
valueEnd = Math.log(Math.max(1.0, valueEnd))
return Math.exp(valueStart + (valueEnd - valueStart) / (sliderEnd - sliderStart) * (position - sliderStart))
}
}

View file

@ -16,9 +16,11 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
@ -142,6 +144,15 @@ public class Treatment implements DataPointWithLabelInterface {
return null;
}
public double getIc() {
JSONObject bw = getBoluscalc();
if (bw == null || !bw.has("ic")) {
Profile profile = ProfileFunctions.getInstance().getProfile(date);
return profile.getIc(date);
}
return JsonHelper.safeGetDouble(bw, "ic");
}
/*
* mealBolus, _id and isSMB cannot be known coming from pump. Only compare rest
* TODO: remove debug toasts