commit
6c536d7eee
40 changed files with 1145 additions and 308 deletions
|
@ -0,0 +1,21 @@
|
|||
package info.nightscout.rx.events
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class EventXdripNewLog(val action: String, val logText: String?) : Event() {
|
||||
var date = System.currentTimeMillis()
|
||||
|
||||
private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
||||
|
||||
fun toPreparedHtml(): StringBuilder {
|
||||
val stringBuilder = StringBuilder()
|
||||
stringBuilder.append(timeFormat.format(date))
|
||||
stringBuilder.append(" <b>")
|
||||
stringBuilder.append(action)
|
||||
stringBuilder.append("</b> ")
|
||||
stringBuilder.append(logText)
|
||||
stringBuilder.append("<br>")
|
||||
return stringBuilder
|
||||
}
|
||||
}
|
|
@ -28,5 +28,6 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires
|
|||
UI("UI", defaultValue = false),
|
||||
WEAR("WEAR"),
|
||||
WIDGET("WIDGET"),
|
||||
WORKER("WORKER")
|
||||
WORKER("WORKER"),
|
||||
XDRIP("XDRIP")
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '1.8.0'
|
||||
kotlin_version = '1.8.10'
|
||||
core_version = '1.9.0'
|
||||
rxjava_version = '3.1.6'
|
||||
rxandroid_version = '3.0.2'
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
package info.nightscout.interfaces
|
||||
|
||||
import info.nightscout.database.entities.Bolus
|
||||
import info.nightscout.database.entities.Carbs
|
||||
import info.nightscout.database.entities.DeviceStatus
|
||||
import info.nightscout.database.entities.EffectiveProfileSwitch
|
||||
import info.nightscout.database.entities.ExtendedBolus
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.database.entities.OfflineEvent
|
||||
import info.nightscout.database.entities.ProfileSwitch
|
||||
import info.nightscout.database.entities.TemporaryBasal
|
||||
import info.nightscout.database.entities.TemporaryTarget
|
||||
import info.nightscout.database.entities.TherapyEvent
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import info.nightscout.interfaces.sync.DataSyncSelector
|
||||
|
||||
/**
|
||||
* Send data to xDrip+ via Inter-app settings
|
||||
|
@ -24,64 +12,19 @@ interface XDripBroadcast {
|
|||
* Accepting must be enabled in Inter-app settings - Accept Calibrations
|
||||
*/
|
||||
fun sendCalibration(bg: Double): Boolean
|
||||
fun sendIn640gMode(glucoseValue: GlucoseValue)
|
||||
fun sendProfile(profileStoreJson: JSONObject)
|
||||
fun sendTreatments(addedOrUpdatedTreatments: JSONArray)
|
||||
fun sendSgvs(sgvs: JSONArray)
|
||||
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept Glucose
|
||||
*
|
||||
* Accepting must be enabled in Inter-app settings - Accept Glucose/Treatments
|
||||
*/
|
||||
fun send(gv: GlucoseValue)
|
||||
fun sendToXdrip(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
|
||||
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*
|
||||
* Accepting must be enabled in Inter-app settings - Accept Glucose/Treatments
|
||||
*/
|
||||
fun send(bolus: Bolus)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(carbs: Carbs)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(tt: TemporaryTarget)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(te: TherapyEvent)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(deviceStatus: DeviceStatus)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(tb: TemporaryBasal)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(eb: ExtendedBolus)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(ps: ProfileSwitch)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(ps: EffectiveProfileSwitch)
|
||||
/**
|
||||
* Send data to xDrip+
|
||||
* Accepting must be enabled in Inter-app settings - Accept treatments
|
||||
*/
|
||||
fun send(ps: OfflineEvent)
|
||||
fun sendToXdrip(collection: String, dataPairs: List<DataSyncSelector.DataPair>, progress:
|
||||
String)
|
||||
}
|
|
@ -8,6 +8,8 @@ interface Intents {
|
|||
// AAPS -> Xdrip
|
||||
const val ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT"
|
||||
const val ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE"
|
||||
const val ACTION_NEW_DEVICE_STATUS = "info.nightscout.client.NEW_DEVICESTATUS"
|
||||
const val ACTION_NEW_FOOD = "info.nightscout.client.NEW_FOOD"
|
||||
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
|
||||
|
||||
const val EXTRA_STATUSLINE = "com.eveningoutpost.dexdrip.Extras.Statusline"
|
||||
|
|
|
@ -70,8 +70,7 @@
|
|||
<string name="key_autotune_additional_log" translatable="false">autotune_additional_log</string>
|
||||
<string name="key_autotune_plugin" translatable="false">key_autotune_plugin</string>
|
||||
<string name="key_autotune_last_run" translatable="false">key_autotune_last_run</string>
|
||||
<string name="key_dexcomg5_xdripupload" translatable="false">dexcomg5_xdripupload</string>
|
||||
<string name="key_nsclient_localbroadcasts" translatable="false">nsclient_localbroadcasts</string>
|
||||
<string name="key_xdrip_local_broadcasts" translatable="false">xdrip_local_broadcasts</string>
|
||||
<string name="key_usebolusreminder" translatable="false">use_bolus_reminder</string>
|
||||
<string name="key_carbs_button_increment_1" translatable="false">carbs_button_increment_1</string>
|
||||
<string name="key_carbs_button_increment_2" translatable="false">carbs_button_increment_2</string>
|
||||
|
|
|
@ -16,7 +16,6 @@ import info.nightscout.core.utils.worker.LoggingWorker
|
|||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.GlucoseUnit
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.notifications.Notification
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
|
@ -443,13 +442,11 @@ class ProfilePlugin @Inject constructor(
|
|||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var profilePlugin: ProfilePlugin
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
@Inject lateinit var instantiator: Instantiator
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
val profileJson = dataWorkerStorage.pickupJSONObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
xDripBroadcast.sendProfile(profileJson)
|
||||
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_store, true) || config.NSCLIENT) {
|
||||
val store = instantiator.provideProfileStore(profileJson)
|
||||
val createdAt = store.getStartDate()
|
||||
|
|
|
@ -201,7 +201,7 @@ class BGSourceFragment : DaggerFragment(), MenuProvider {
|
|||
R.string.tomato -> Sources.Tomato
|
||||
R.string.glunovo -> Sources.Glunovo
|
||||
R.string.intelligo -> Sources.Intelligo
|
||||
R.string.xdrip -> Sources.Xdrip
|
||||
R.string.source_xdrip -> Sources.Xdrip
|
||||
R.string.aidex -> Sources.Aidex
|
||||
else -> Sources.Unknown
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
|||
import info.nightscout.database.impl.transactions.InvalidateGlucoseValueTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
|
@ -91,7 +90,6 @@ class DexcomPlugin @Inject constructor(
|
|||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
|
@ -185,11 +183,9 @@ class DexcomPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
xDripBroadcast.sendIn640gMode(result.inserted[i])
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg ${result.inserted[i]}")
|
||||
}
|
||||
result.updated.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
|
||||
}
|
||||
result.sensorInsertionsInserted.forEach {
|
||||
|
|
|
@ -12,7 +12,6 @@ import info.nightscout.database.impl.AppRepository
|
|||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.impl.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
|
@ -61,7 +60,6 @@ class EversensePlugin @Inject constructor(
|
|||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
var ret = Result.success()
|
||||
|
@ -114,7 +112,6 @@ class EversensePlugin @Inject constructor(
|
|||
.blockingGet()
|
||||
.also { savedValues ->
|
||||
savedValues.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import info.nightscout.database.entities.GlucoseValue
|
|||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
|
@ -50,7 +49,6 @@ class GlimpPlugin @Inject constructor(
|
|||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var glimpPlugin: GlimpPlugin
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
var ret = Result.success()
|
||||
|
@ -74,7 +72,6 @@ class GlimpPlugin @Inject constructor(
|
|||
.blockingGet()
|
||||
.also { savedValues ->
|
||||
savedValues.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import info.nightscout.database.impl.AppRepository
|
|||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
|
@ -38,7 +37,6 @@ class GlunovoPlugin @Inject constructor(
|
|||
private val sp: SP,
|
||||
private val context: Context,
|
||||
private val repository: AppRepository,
|
||||
private val xDripBroadcast: XDripBroadcast,
|
||||
private val dateUtil: DateUtil,
|
||||
private val uel: UserEntryLogger,
|
||||
private val fabricPrivacy: FabricPrivacy
|
||||
|
@ -148,7 +146,6 @@ class GlunovoPlugin @Inject constructor(
|
|||
.blockingGet()
|
||||
.also { savedValues ->
|
||||
savedValues.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
savedValues.calibrationsInserted.forEach { calibration ->
|
||||
|
|
|
@ -16,7 +16,6 @@ import info.nightscout.database.impl.AppRepository
|
|||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
|
@ -41,7 +40,6 @@ class IntelligoPlugin @Inject constructor(
|
|||
private val sp: SP,
|
||||
private val context: Context,
|
||||
private val repository: AppRepository,
|
||||
private val xDripBroadcast: XDripBroadcast,
|
||||
private val dateUtil: DateUtil,
|
||||
private val uel: UserEntryLogger,
|
||||
private val fabricPrivacy: FabricPrivacy
|
||||
|
@ -159,7 +157,6 @@ class IntelligoPlugin @Inject constructor(
|
|||
.blockingGet()
|
||||
.also { savedValues ->
|
||||
savedValues.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
savedValues.calibrationsInserted.forEach { calibration ->
|
||||
|
|
|
@ -4,13 +4,11 @@ import android.content.Context
|
|||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||
import info.nightscout.core.utils.worker.LoggingWorker
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
|
@ -51,9 +49,7 @@ class MM640gPlugin @Inject constructor(
|
|||
@Inject lateinit var mM640gPlugin: MM640gPlugin
|
||||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
var ret = Result.success()
|
||||
|
@ -90,7 +86,6 @@ class MM640gPlugin @Inject constructor(
|
|||
.blockingGet()
|
||||
.also { savedValues ->
|
||||
savedValues.all().forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import info.nightscout.database.entities.GlucoseValue
|
|||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.notifications.Notification
|
||||
import info.nightscout.interfaces.nsclient.NSSgv
|
||||
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||
|
@ -95,7 +94,6 @@ class NSClientSourcePlugin @Inject constructor(
|
|||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var storeDataForDb: StoreDataForDb
|
||||
|
||||
|
@ -141,8 +139,6 @@ class NSClientSourcePlugin @Inject constructor(
|
|||
|
||||
try {
|
||||
if (sgvs is JSONArray) { // V1 client
|
||||
xDripBroadcast.sendSgvs(sgvs)
|
||||
|
||||
for (i in 0 until sgvs.length()) {
|
||||
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
|
||||
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
|
||||
|
|
|
@ -10,7 +10,6 @@ import info.nightscout.database.impl.AppRepository
|
|||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
|
@ -52,7 +51,6 @@ class PoctechPlugin @Inject constructor(
|
|||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var poctechPlugin: PoctechPlugin
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
var ret = Result.success()
|
||||
|
@ -83,7 +81,6 @@ class PoctechPlugin @Inject constructor(
|
|||
.blockingGet()
|
||||
.also { savedValues ->
|
||||
savedValues.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import info.nightscout.database.impl.AppRepository
|
|||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
|
@ -38,7 +37,6 @@ class RandomBgPlugin @Inject constructor(
|
|||
aapsLogger: AAPSLogger,
|
||||
private val sp: SP,
|
||||
private val repository: AppRepository,
|
||||
private val xDripBroadcast: XDripBroadcast,
|
||||
private val virtualPump: VirtualPump,
|
||||
private val config: Config
|
||||
) : PluginBase(
|
||||
|
@ -119,7 +117,6 @@ class RandomBgPlugin @Inject constructor(
|
|||
disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
|
||||
.subscribe({ savedValues ->
|
||||
savedValues.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
}, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) }
|
||||
|
|
|
@ -9,7 +9,6 @@ import info.nightscout.database.entities.GlucoseValue
|
|||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.database.impl.transactions.CgmSourceTransaction
|
||||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
|
@ -50,7 +49,6 @@ class TomatoPlugin @Inject constructor(
|
|||
@Inject lateinit var tomatoPlugin: TomatoPlugin
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
|
@ -74,7 +72,6 @@ class TomatoPlugin @Inject constructor(
|
|||
.blockingGet()
|
||||
.also { savedValues ->
|
||||
savedValues.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class XdripSourcePlugin @Inject constructor(
|
|||
.mainType(PluginType.BGSOURCE)
|
||||
.fragmentClass(BGSourceFragment::class.java.name)
|
||||
.pluginIcon((info.nightscout.core.main.R.drawable.ic_blooddrop_48))
|
||||
.pluginName(R.string.xdrip)
|
||||
.pluginName(R.string.source_xdrip)
|
||||
.description(R.string.description_source_xdrip),
|
||||
aapsLogger, rh, injector
|
||||
), BgSource, DoingOwnUploadSource, XDrip {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<string name="ns_client_bg">NSClient BG</string>
|
||||
<string name="ns_client_bg_short">NS BG</string>
|
||||
<string name="description_source_ns_client">Downloads BG data from Nightscout</string>
|
||||
<string name="xdrip">xDrip+</string>
|
||||
<string name="source_xdrip">xDrip+ BG</string>
|
||||
<string name="description_source_xdrip">Receive BG values from xDrip+.</string>
|
||||
<string name="dexcom_app_patched">BYODA</string>
|
||||
<string name="dexcom_short">BYODA</string>
|
||||
|
|
|
@ -12,12 +12,6 @@
|
|||
android:key="@string/key_do_ns_upload"
|
||||
android:title="@string/do_ns_upload_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_dexcomg5_xdripupload"
|
||||
android:summary="@string/do_xdrip_upload_summary"
|
||||
android:title="@string/do_xdrip_upload_title" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
|
@ -12,12 +12,6 @@
|
|||
android:key="@string/key_do_ns_upload"
|
||||
android:title="@string/do_ns_upload_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_dexcomg5_xdripupload"
|
||||
android:summary="@string/do_xdrip_upload_summary"
|
||||
android:title="@string/do_xdrip_upload_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_dexcom_log_ns_sensor_change"
|
||||
|
|
|
@ -33,7 +33,9 @@ import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
|
|||
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
|
||||
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
|
||||
import info.nightscout.plugins.sync.tidepool.TidepoolFragment
|
||||
import info.nightscout.plugins.sync.xdrip.XdripFragment
|
||||
import info.nightscout.plugins.sync.xdrip.XdripPlugin
|
||||
import info.nightscout.plugins.sync.xdrip.workers.XdripDataSyncWorker
|
||||
|
||||
@Module(
|
||||
includes = [
|
||||
|
@ -68,6 +70,8 @@ abstract class SyncModule {
|
|||
@ContributesAndroidInjector abstract fun contributesFoodWorker(): ProcessFoodWorker
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
||||
@ContributesAndroidInjector abstract fun contributesXdripFragment(): XdripFragment
|
||||
@ContributesAndroidInjector abstract fun contributesXdripDataSyncWorker(): XdripDataSyncWorker
|
||||
|
||||
@Module
|
||||
open class Provide {
|
||||
|
|
|
@ -48,7 +48,6 @@ import info.nightscout.database.impl.transactions.UpdateNsIdTherapyEventTransact
|
|||
import info.nightscout.database.transactions.TransactionGlucoseValue
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.notifications.Notification
|
||||
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||
|
@ -78,7 +77,6 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
private val dateUtil: DateUtil,
|
||||
private val config: Config,
|
||||
private val nsClientSource: NSClientSource,
|
||||
private val xDripBroadcast: XDripBroadcast,
|
||||
private val virtualPump: VirtualPump,
|
||||
private val uiInteraction: UiInteraction
|
||||
) : StoreDataForDb {
|
||||
|
@ -174,19 +172,16 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
.also { result ->
|
||||
glucoseValues.clear()
|
||||
result.updated.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
nsClientSource.detectSource(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
|
||||
updated.inc(GlucoseValue::class.java.simpleName)
|
||||
}
|
||||
result.inserted.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
nsClientSource.detectSource(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||
inserted.inc(GlucoseValue::class.java.simpleName)
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
xDripBroadcast.sendIn640gMode(it)
|
||||
nsClientSource.detectSource(it)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId bg $it")
|
||||
nsIdUpdated.inc(GlucoseValue::class.java.simpleName)
|
||||
|
|
|
@ -44,7 +44,6 @@ class NSClientAddUpdateWorker(
|
|||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||
@Inject lateinit var storeDataForDb: StoreDataForDb
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
|
@ -164,7 +163,6 @@ class NSClientAddUpdateWorker(
|
|||
}
|
||||
storeDataForDb.storeTreatmentsToDb()
|
||||
activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData)
|
||||
xDripBroadcast.sendTreatments(treatments)
|
||||
return ret
|
||||
}
|
||||
}
|
|
@ -626,6 +626,7 @@ class NSClientV3Plugin @Inject constructor(
|
|||
lastLoadedSrvModified = LastModified(LastModified.Collections())
|
||||
initialLoadFinished = false
|
||||
storeLastLoadedSrvModified()
|
||||
dataSyncSelector.resetToNextFullSync()
|
||||
}
|
||||
|
||||
override fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
|
||||
|
|
|
@ -0,0 +1,562 @@
|
|||
package info.nightscout.plugins.sync.xdrip
|
||||
|
||||
import dagger.Lazy
|
||||
import info.nightscout.database.ValueWrapper
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.sync.DataSyncSelector
|
||||
import info.nightscout.interfaces.utils.JsonHelper
|
||||
import info.nightscout.plugins.sync.R
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import info.nightscout.shared.utils.T
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class XdripDataSyncSelectorImplementation @Inject constructor(
|
||||
private val sp: SP,
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val dateUtil: DateUtil,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val xdripBroadcast: Lazy<XDripBroadcast>,
|
||||
private val appRepository: AppRepository
|
||||
) : DataSyncSelector {
|
||||
|
||||
class QueueCounter(
|
||||
var bolusesRemaining: Long = -1L,
|
||||
var carbsRemaining: Long = -1L,
|
||||
var bcrRemaining: Long = -1L,
|
||||
var ttsRemaining: Long = -1L,
|
||||
var foodsRemaining: Long = -1L,
|
||||
var gvsRemaining: Long = -1L,
|
||||
var tesRemaining: Long = -1L,
|
||||
var dssRemaining: Long = -1L,
|
||||
var tbrsRemaining: Long = -1L,
|
||||
var ebsRemaining: Long = -1L,
|
||||
var pssRemaining: Long = -1L,
|
||||
var epssRemaining: Long = -1L,
|
||||
var oesRemaining: Long = -1L
|
||||
) {
|
||||
|
||||
fun size(): Long =
|
||||
bolusesRemaining +
|
||||
carbsRemaining +
|
||||
bcrRemaining +
|
||||
ttsRemaining +
|
||||
foodsRemaining +
|
||||
gvsRemaining +
|
||||
tesRemaining +
|
||||
dssRemaining +
|
||||
tbrsRemaining +
|
||||
ebsRemaining +
|
||||
pssRemaining +
|
||||
epssRemaining +
|
||||
oesRemaining
|
||||
}
|
||||
|
||||
private val queueCounter = QueueCounter()
|
||||
private val isEnabled get() = sp.getBoolean(info.nightscout.core.utils.R.string.key_xdrip_local_broadcasts, false)
|
||||
private val xdripPlugin get() = xdripBroadcast.get()
|
||||
|
||||
private val maxAge get() = T.days(1).msecs()
|
||||
private fun isOld(timestamp: Long) = timestamp < dateUtil.now() - maxAge
|
||||
private val preparedEntries = mutableListOf<DataSyncSelector.DataPair>()
|
||||
private val preparedTreatments = mutableListOf<DataSyncSelector.DataPair>()
|
||||
private val preparedFoods = mutableListOf<DataSyncSelector.DataPair>()
|
||||
|
||||
override fun queueSize(): Long = queueCounter.size()
|
||||
|
||||
override fun doUpload() {
|
||||
if (isEnabled) {
|
||||
processChangedGlucoseValues()
|
||||
processChangedBoluses()
|
||||
processChangedCarbs()
|
||||
// not supported at the moment
|
||||
//processChangedBolusCalculatorResults()
|
||||
// not supported at the moment
|
||||
//processChangedTemporaryBasals()
|
||||
processChangedExtendedBoluses()
|
||||
processChangedProfileSwitches()
|
||||
// not supported at the moment
|
||||
//processChangedEffectiveProfileSwitches()
|
||||
processChangedTempTargets()
|
||||
// not supported at the moment
|
||||
//processChangedFoods()
|
||||
processChangedTherapyEvents()
|
||||
// not supported at the moment
|
||||
//processChangedDeviceStatuses()
|
||||
// not supported at the moment
|
||||
//processChangedOfflineEvents()
|
||||
// not supported at the moment
|
||||
//processChangedProfileStore()
|
||||
}
|
||||
}
|
||||
|
||||
override fun resetToNextFullSync() {
|
||||
sp.remove(R.string.key_xdrip_glucose_value_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_temporary_basal_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_temporary_target_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_extended_bolus_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_food_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_bolus_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_carbs_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_bolus_calculator_result_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_therapy_event_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_profile_switch_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_effective_profile_switch_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_offline_event_last_synced_id)
|
||||
sp.remove(R.string.key_xdrip_profile_store_last_synced_timestamp)
|
||||
|
||||
val lastDeviceStatusDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
|
||||
if (lastDeviceStatusDbIdWrapped is ValueWrapper.Existing) sp.putLong(R.string.key_xdrip_device_status_last_synced_id, lastDeviceStatusDbIdWrapped.value)
|
||||
else sp.remove(R.string.key_xdrip_device_status_last_synced_id)
|
||||
}
|
||||
|
||||
override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_glucose_value_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting GlucoseValue data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_glucose_value_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedGlucoseValues() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_glucose_value_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_glucose_value_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.gvsRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading GlucoseValue data Start: $startId ${gv.first} forID: ${gv.second.id} ")
|
||||
if (!isOld(gv.first.timestamp))
|
||||
preparedEntries.add(DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id))
|
||||
sendEntries(force = false, progress)
|
||||
confirmLastGlucoseValueIdIfGreater(gv.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendEntries(force = true, progress)
|
||||
}
|
||||
|
||||
private fun sendEntries(force: Boolean, progress: String) {
|
||||
if (preparedEntries.isNotEmpty() && (preparedEntries.size >= 100 || force)) {
|
||||
xdripPlugin.sendToXdrip("entries", preparedEntries, progress)
|
||||
preparedEntries.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendTreatments(force: Boolean, progress: String) {
|
||||
if (preparedTreatments.isNotEmpty() && (preparedTreatments.size >= 100 || force)) {
|
||||
xdripPlugin.sendToXdrip("treatments", preparedTreatments, progress)
|
||||
preparedTreatments.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendFoods(force: Boolean, progress: String) {
|
||||
if (preparedFoods.isNotEmpty() && (preparedFoods.size >= 100 || force)) {
|
||||
xdripPlugin.sendToXdrip("food", preparedFoods, progress)
|
||||
preparedFoods.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun confirmLastBolusIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_bolus_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting Bolus data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_bolus_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedBoluses() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_bolus_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_bolus_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.bolusesRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading Bolus data Start: $startId ${bolus.first} forID: ${bolus.second.id} ")
|
||||
if (!isOld(bolus.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairBolus(bolus.first, bolus.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastBolusIdIfGreater(bolus.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_carbs_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting Carbs data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_carbs_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedCarbs() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_carbs_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_carbs_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.carbsRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading Carbs data Start: $startId ${carb.first} forID: ${carb.second.id} ")
|
||||
if (!isOld(carb.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairCarbs(carb.first, carb.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastCarbsIdIfGreater(carb.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting BolusCalculatorResult data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedBolusCalculatorResults() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.bcrRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading BolusCalculatorResult data Start: $startId ${bolusCalculatorResult.first} forID: ${bolusCalculatorResult.second.id} ")
|
||||
if (!isOld(bolusCalculatorResult.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_temporary_target_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting TemporaryTarget data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_temporary_target_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedTempTargets() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_temporary_target_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_temporary_target_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.ttsRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading TemporaryTarget data Start: $startId ${tt.first} forID: ${tt.second.id} ")
|
||||
if (!isOld(tt.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastTempTargetsIdIfGreater(tt.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastFoodIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_food_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting Food data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_food_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedFoods() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_food_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_food_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.foodsRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading Food data Start: $startId ${food.first} forID: ${food.second.id} ")
|
||||
preparedFoods.add(DataSyncSelector.PairFood(food.first, food.second.id))
|
||||
sendFoods(force = false, progress)
|
||||
confirmLastFoodIdIfGreater(food.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendFoods(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_therapy_event_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting TherapyEvents data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_therapy_event_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedTherapyEvents() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_therapy_event_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_therapy_event_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.tesRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading TherapyEvents data Start: $startId ${te.first} forID: ${te.second.id} ")
|
||||
if (!isOld(te.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairTherapyEvent(te.first, te.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastTherapyEventIdIfGreater(te.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_device_status_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting DeviceStatus data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_device_status_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedDeviceStatuses() {
|
||||
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_device_status_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_device_status_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.dssRemaining = lastDbId - startId
|
||||
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading DeviceStatus data Start: $startId $deviceStatus")
|
||||
if (!isOld(deviceStatus.timestamp))
|
||||
xdripPlugin.sendToXdrip("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId), "$startId/$lastDbId")
|
||||
confirmLastDeviceStatusIdIfGreater(lastDbId)
|
||||
} ?: break
|
||||
}
|
||||
}
|
||||
|
||||
override fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_temporary_basal_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting TemporaryBasal data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_temporary_basal_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedTemporaryBasals() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_temporary_basal_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_temporary_basal_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.tbrsRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading TemporaryBasal data Start: $startId ${tb.first} forID: ${tb.second.id} ")
|
||||
if (!isOld(tb.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_extended_bolus_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting ExtendedBolus data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_extended_bolus_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedExtendedBoluses() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_extended_bolus_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_extended_bolus_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.ebsRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading ExtendedBolus data Start: $startId ${eb.first} forID: ${eb.second.id} ")
|
||||
val profile = profileFunction.getProfile(eb.first.timestamp)
|
||||
if (profile != null && !isOld(eb.first.timestamp)) {
|
||||
preparedTreatments.add(DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
} else
|
||||
aapsLogger.info(LTag.XDRIP, "Ignoring ExtendedBolus. No profile: ${eb.second.id} ")
|
||||
confirmLastExtendedBolusIdIfGreater(eb.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_profile_switch_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting ProfileSwitch data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_profile_switch_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedProfileSwitches() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_profile_switch_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_profile_switch_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.pssRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading ProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
|
||||
if (!isOld(ps.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastProfileSwitchIdIfGreater(ps.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting EffectiveProfileSwitch data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedEffectiveProfileSwitches() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.epssRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading EffectiveProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
|
||||
if (!isOld(ps.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_xdrip_offline_event_last_synced_id, 0)) {
|
||||
//aapsLogger.debug(LTag.XDRIP, "Setting OfflineEvent data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_xdrip_offline_event_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChangedOfflineEvents() {
|
||||
var progress: String
|
||||
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
while (true) {
|
||||
if (!isEnabled) return
|
||||
var startId = sp.getLong(R.string.key_xdrip_offline_event_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_xdrip_offline_event_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
queueCounter.oesRemaining = lastDbId - startId
|
||||
progress = "$startId/$lastDbId"
|
||||
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
|
||||
aapsLogger.info(LTag.XDRIP, "Loading OfflineEvent data Start: $startId ${oe.first} forID: ${oe.second.id} ")
|
||||
if (!isOld(oe.first.timestamp))
|
||||
preparedTreatments.add(DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id))
|
||||
sendTreatments(force = false, progress)
|
||||
confirmLastOfflineEventIdIfGreater(oe.second.id)
|
||||
} ?: break
|
||||
}
|
||||
sendTreatments(force = true, progress)
|
||||
}
|
||||
|
||||
override fun confirmLastProfileStore(lastSynced: Long) {
|
||||
sp.putLong(R.string.key_xdrip_profile_store_last_synced_timestamp, lastSynced)
|
||||
}
|
||||
|
||||
override fun processChangedProfileStore() {
|
||||
if (!isEnabled) return
|
||||
val lastSync = sp.getLong(R.string.key_xdrip_profile_store_last_synced_timestamp, 0)
|
||||
val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
|
||||
if (lastChange == 0L) return
|
||||
if (lastChange > lastSync) {
|
||||
if (activePlugin.activeProfileSource.profile?.allProfilesValid != true) return
|
||||
val profileStore = activePlugin.activeProfileSource.profile
|
||||
val profileJson = profileStore?.data ?: return
|
||||
// add for v3
|
||||
if (JsonHelper.safeGetLongAllowNull(profileJson, "date") == null)
|
||||
profileJson.put("date", profileStore.getStartDate())
|
||||
xdripPlugin.sendToXdrip("profile", DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package info.nightscout.plugins.sync.xdrip
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ScrollView
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.core.ui.dialogs.OKDialog
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginFragment
|
||||
import info.nightscout.plugins.sync.R
|
||||
import info.nightscout.plugins.sync.databinding.XdripFragmentBinding
|
||||
import info.nightscout.plugins.sync.xdrip.events.EventXdripUpdateGUI
|
||||
import info.nightscout.rx.AapsSchedulers
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class XdripFragment : DaggerFragment(), MenuProvider, PluginFragment {
|
||||
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var rh: ResourceHelper
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var dataSyncSelector: XdripDataSyncSelectorImplementation
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var xdripPlugin: XdripPlugin
|
||||
@Inject lateinit var config: Config
|
||||
|
||||
companion object {
|
||||
|
||||
const val ID_MENU_CLEAR_LOG = 511
|
||||
const val ID_MENU_FULL_SYNC = 512
|
||||
}
|
||||
|
||||
override var plugin: PluginBase? = null
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private var _binding: XdripFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
XdripFragmentBinding.inflate(inflater, container, false).also {
|
||||
_binding = it
|
||||
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||
}.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.autoscroll.isChecked = sp.getBoolean(R.string.key_ns_client_autoscroll, true)
|
||||
binding.autoscroll.setOnCheckedChangeListener { _, isChecked ->
|
||||
sp.putBoolean(R.string.key_ns_client_autoscroll, isChecked)
|
||||
updateGui()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
|
||||
menu.add(Menu.FIRST, ID_MENU_CLEAR_LOG, 0, rh.gs(R.string.clear_log)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||
menu.add(Menu.FIRST, ID_MENU_FULL_SYNC, 0, rh.gs(R.string.full_sync)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||
menu.setGroupDividerEnabled(true)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
ID_MENU_CLEAR_LOG -> {
|
||||
xdripPlugin.clearLog()
|
||||
true
|
||||
}
|
||||
|
||||
ID_MENU_FULL_SYNC -> {
|
||||
context?.let { context ->
|
||||
OKDialog.showConfirmation(
|
||||
context, rh.gs(R.string.ns_client), rh.gs(R.string.full_sync_comment),
|
||||
Runnable { dataSyncSelector.resetToNextFullSync() }
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable += rxBus
|
||||
.toObservable(EventXdripUpdateGUI::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
||||
updateGui()
|
||||
}
|
||||
|
||||
@Synchronized override fun onPause() {
|
||||
super.onPause()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
private fun updateGui() {
|
||||
if (_binding == null) return
|
||||
binding.log.text = xdripPlugin.textLog()
|
||||
if (sp.getBoolean(R.string.key_ns_client_autoscroll, true)) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
|
||||
val size = dataSyncSelector.queueSize()
|
||||
binding.queue.text = if (size >= 0) size.toString() else rh.gs(info.nightscout.core.ui.R.string.value_unavailable_short)
|
||||
}
|
||||
}
|
|
@ -3,23 +3,21 @@ package info.nightscout.plugins.sync.xdrip
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.text.Spanned
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.extensions.toJson
|
||||
import info.nightscout.core.extensions.toStringShort
|
||||
import info.nightscout.core.iob.generateCOBString
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.ui.toast.ToastUtils
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.database.entities.Bolus
|
||||
import info.nightscout.database.entities.Carbs
|
||||
import info.nightscout.database.entities.DeviceStatus
|
||||
import info.nightscout.database.entities.EffectiveProfileSwitch
|
||||
import info.nightscout.database.entities.ExtendedBolus
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.database.entities.OfflineEvent
|
||||
import info.nightscout.database.entities.ProfileSwitch
|
||||
import info.nightscout.database.entities.TemporaryBasal
|
||||
import info.nightscout.database.entities.TemporaryTarget
|
||||
import info.nightscout.database.entities.TherapyEvent
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.GlucoseUnit
|
||||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.aps.Loop
|
||||
|
@ -30,26 +28,35 @@ import info.nightscout.interfaces.plugin.PluginType
|
|||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.receivers.Intents
|
||||
import info.nightscout.interfaces.sync.DataSyncSelector
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
import info.nightscout.interfaces.utils.DecimalFormatter
|
||||
import info.nightscout.interfaces.utils.HtmlHelper
|
||||
import info.nightscout.plugins.sync.R
|
||||
import info.nightscout.plugins.sync.nsclient.extensions.toJson
|
||||
import info.nightscout.plugins.sync.xdrip.events.EventXdripUpdateGUI
|
||||
import info.nightscout.plugins.sync.xdrip.extensions.toXdripJson
|
||||
import info.nightscout.plugins.sync.xdrip.workers.XdripDataSyncWorker
|
||||
import info.nightscout.rx.AapsSchedulers
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.EventAppExit
|
||||
import info.nightscout.rx.events.EventAppInitialized
|
||||
import info.nightscout.rx.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.rx.events.EventNewBG
|
||||
import info.nightscout.rx.events.EventNewHistoryData
|
||||
import info.nightscout.rx.events.EventRefreshOverview
|
||||
import info.nightscout.rx.events.EventXdripNewLog
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.shared.extensions.safeQueryBroadcastReceivers
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -65,30 +72,56 @@ class XdripPlugin @Inject constructor(
|
|||
private val loop: Loop,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val rxBus: RxBus,
|
||||
private val uiInteraction: UiInteraction,
|
||||
private val dataSyncSelector: XdripDataSyncSelectorImplementation,
|
||||
private val dateUtil: DateUtil,
|
||||
aapsLogger: AAPSLogger
|
||||
) : PluginBase(
|
||||
) : XDripBroadcast, PluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.SYNC)
|
||||
.fragmentClass(XdripFragment::class.java.name)
|
||||
.pluginIcon((info.nightscout.core.main.R.drawable.ic_blooddrop_48))
|
||||
.pluginName(R.string.xdrip)
|
||||
.shortName(R.string.xdrip_shortname)
|
||||
.neverVisible(true)
|
||||
.preferencesId(R.xml.pref_xdrip)
|
||||
.description(R.string.description_xdrip),
|
||||
aapsLogger, rh, injector
|
||||
), XDripBroadcast {
|
||||
) {
|
||||
|
||||
@Suppress("PrivatePropertyName")
|
||||
private val XDRIP_JOB_NAME: String = this::class.java.simpleName
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
private val listLog: MutableList<EventXdripNewLog> = ArrayList()
|
||||
private var lastLoopStatus = false
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
disposable += rxBus.toObservable(EventRefreshOverview::class.java)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAppExit::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ if (lastLoopStatus != loop.isEnabled()) sendStatusLine() }, fabricPrivacy::logException)
|
||||
.subscribe({ WorkManager.getInstance(context).cancelUniqueWork(XDRIP_JOB_NAME) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventXdripNewLog::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event ->
|
||||
addToLog(event)
|
||||
aapsLogger.debug(LTag.XDRIP, event.action + " " + event.logText)
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventNewBG::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
sendStatusLine()
|
||||
delayAndScheduleExecution("NEW_BG")
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus.toObservable(EventNewHistoryData::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendStatusLine() }, fabricPrivacy::logException)
|
||||
.subscribe({
|
||||
sendStatusLine()
|
||||
delayAndScheduleExecution("NEW_DATA")
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendStatusLine() }, fabricPrivacy::logException)
|
||||
|
@ -99,8 +132,39 @@ class XdripPlugin @Inject constructor(
|
|||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
disposable.clear()
|
||||
sendStatusLine()
|
||||
}
|
||||
|
||||
fun clearLog() {
|
||||
handler.post {
|
||||
synchronized(listLog) { listLog.clear() }
|
||||
rxBus.send(EventXdripUpdateGUI())
|
||||
}
|
||||
}
|
||||
|
||||
private fun addToLog(ev: EventXdripNewLog) {
|
||||
synchronized(listLog) {
|
||||
listLog.add(ev)
|
||||
// remove the first line if log is too large
|
||||
if (listLog.size >= Constants.MAX_LOG_LINES) {
|
||||
listLog.removeAt(0)
|
||||
}
|
||||
}
|
||||
rxBus.send(EventXdripUpdateGUI())
|
||||
}
|
||||
|
||||
fun textLog(): Spanned {
|
||||
try {
|
||||
val newTextLog = StringBuilder()
|
||||
synchronized(listLog) {
|
||||
for (log in listLog) newTextLog.append(log.toPreparedHtml())
|
||||
}
|
||||
return HtmlHelper.fromHtml(newTextLog.toString())
|
||||
} catch (e: OutOfMemoryError) {
|
||||
uiInteraction.showToastAndNotification(context, "Out of memory!\nStop using this phone !!!", info.nightscout.core.ui.R.raw.error)
|
||||
}
|
||||
return HtmlHelper.fromHtml("")
|
||||
}
|
||||
|
||||
private fun sendStatusLine() {
|
||||
|
@ -115,6 +179,45 @@ class XdripPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun executeLoop(origin: String) {
|
||||
if (workIsRunning(arrayOf(XDRIP_JOB_NAME))) {
|
||||
rxBus.send(EventXdripNewLog("RUN", "Already running $origin"))
|
||||
return
|
||||
}
|
||||
rxBus.send(EventXdripNewLog("RUN", "Starting next round $origin"))
|
||||
WorkManager.getInstance(context)
|
||||
.beginUniqueWork(
|
||||
XDRIP_JOB_NAME,
|
||||
ExistingWorkPolicy.REPLACE,
|
||||
OneTimeWorkRequest.Builder(XdripDataSyncWorker::class.java).build()
|
||||
)
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun workIsRunning(workNames: Array<String>): Boolean {
|
||||
for (workName in workNames)
|
||||
for (workInfo in WorkManager.getInstance(context).getWorkInfosForUniqueWork(workName).get())
|
||||
if (workInfo.state == WorkInfo.State.BLOCKED || workInfo.state == WorkInfo.State.ENQUEUED || workInfo.state == WorkInfo.State.RUNNING)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
private val eventWorker = Executors.newSingleThreadScheduledExecutor()
|
||||
private var scheduledEventPost: ScheduledFuture<*>? = null
|
||||
private fun delayAndScheduleExecution(origin: String) {
|
||||
class PostRunnable : Runnable {
|
||||
|
||||
override fun run() {
|
||||
scheduledEventPost = null
|
||||
executeLoop(origin)
|
||||
}
|
||||
}
|
||||
// cancel waiting task to prevent sending multiple posts
|
||||
scheduledEventPost?.cancel(false)
|
||||
val task: Runnable = PostRunnable()
|
||||
scheduledEventPost = eventWorker.schedule(task, 10, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
private fun buildStatusLine(profile: Profile): String {
|
||||
val status = StringBuilder()
|
||||
@Suppress("LiftReturnOrAssignment")
|
||||
|
@ -169,145 +272,144 @@ class XdripPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// sent in 640G mode
|
||||
// com.eveningoutpost.dexdrip.NSEmulatorReceiver
|
||||
override fun sendIn640gMode(glucoseValue: GlucoseValue) {
|
||||
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_dexcomg5_xdripupload, false)) {
|
||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
|
||||
try {
|
||||
val entriesBody = JSONArray()
|
||||
val json = JSONObject()
|
||||
json.put("sgv", glucoseValue.value)
|
||||
json.put("direction", glucoseValue.trendArrow.text)
|
||||
json.put("device", "G5")
|
||||
json.put("type", "sgv")
|
||||
json.put("date", glucoseValue.timestamp)
|
||||
json.put("dateString", format.format(glucoseValue.timestamp))
|
||||
entriesBody.put(json)
|
||||
val bundle = Bundle()
|
||||
bundle.putString("action", "add")
|
||||
bundle.putString("collection", "entries")
|
||||
bundle.putString("data", entriesBody.toString())
|
||||
val intent = Intent(Intents.XDRIP_PLUS_NS_EMULATOR)
|
||||
intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
context.sendBroadcast(intent)
|
||||
val receivers = context.packageManager.safeQueryBroadcastReceivers(intent, 0)
|
||||
if (receivers.isEmpty()) {
|
||||
//NSUpload.log.debug("No xDrip receivers found. ")
|
||||
aapsLogger.debug(LTag.BGSOURCE, "No xDrip receivers found.")
|
||||
} else {
|
||||
aapsLogger.debug(LTag.BGSOURCE, "${receivers.size} xDrip receivers")
|
||||
/*
|
||||
// sent in 640G mode
|
||||
// com.eveningoutpost.dexdrip.NSEmulatorReceiver
|
||||
override fun sendIn640gMode(glucoseValue: GlucoseValue) {
|
||||
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_dexcomg5_xdripupload, false)) {
|
||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
|
||||
try {
|
||||
val entriesBody = JSONArray()
|
||||
val json = JSONObject()
|
||||
json.put("sgv", glucoseValue.value)
|
||||
json.put("direction", glucoseValue.trendArrow.text)
|
||||
json.put("device", "G5")
|
||||
json.put("type", "sgv")
|
||||
json.put("date", glucoseValue.timestamp)
|
||||
json.put("dateString", format.format(glucoseValue.timestamp))
|
||||
entriesBody.put(json)
|
||||
val bundle = Bundle()
|
||||
bundle.putString("action", "add")
|
||||
bundle.putString("collection", "entries")
|
||||
bundle.putString("data", entriesBody.toString())
|
||||
val intent = Intent(Intents.XDRIP_PLUS_NS_EMULATOR)
|
||||
intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
context.sendBroadcast(intent)
|
||||
val receivers = context.packageManager.safeQueryBroadcastReceivers(intent, 0)
|
||||
if (receivers.isEmpty()) {
|
||||
//NSUpload.log.debug("No xDrip receivers found. ")
|
||||
aapsLogger.debug(LTag.BGSOURCE, "No xDrip receivers found.")
|
||||
} else {
|
||||
aapsLogger.debug(LTag.BGSOURCE, "${receivers.size} xDrip receivers")
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.BGSOURCE, "Unhandled exception", e)
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.BGSOURCE, "Unhandled exception", e)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
override fun sendToXdrip(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
|
||||
when (collection) {
|
||||
"profile" -> sendProfileStore(dataPair = dataPair, progress = progress)
|
||||
"devicestatus" -> sendDeviceStatus(dataPair = dataPair, progress = progress)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
// sent in NSClient dbaccess mode
|
||||
override fun sendProfile(profileStoreJson: JSONObject) {
|
||||
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_nsclient_localbroadcasts, false))
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_PROFILE).apply {
|
||||
addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
putExtras(Bundle().apply { putString("profile", profileStoreJson.toString()) })
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// sent in NSClient dbaccess mode
|
||||
override fun sendTreatments(addedOrUpdatedTreatments: JSONArray) {
|
||||
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_nsclient_localbroadcasts, false))
|
||||
splitArray(addedOrUpdatedTreatments).forEach { part ->
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_TREATMENT).apply {
|
||||
addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
putExtras(Bundle().apply { putString("treatments", part.toString()) })
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// sent in NSClient dbaccess mode
|
||||
override fun sendSgvs(sgvs: JSONArray) {
|
||||
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_nsclient_localbroadcasts, false))
|
||||
splitArray(sgvs).forEach { part ->
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_SGV).apply {
|
||||
addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
putExtras(Bundle().apply { putString("sgvs", part.toString()) })
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun send(gv: GlucoseValue) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(bolus: Bolus) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(carbs: Carbs) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(tt: TemporaryTarget) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(te: TherapyEvent) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(deviceStatus: DeviceStatus) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(tb: TemporaryBasal) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(eb: ExtendedBolus) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(ps: ProfileSwitch) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(ps: EffectiveProfileSwitch) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun send(ps: OfflineEvent) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
private fun splitArray(array: JSONArray): List<JSONArray> {
|
||||
var ret: MutableList<JSONArray> = ArrayList()
|
||||
try {
|
||||
val size = array.length()
|
||||
var count = 0
|
||||
var newarr: JSONArray? = null
|
||||
for (i in 0 until size) {
|
||||
if (count == 0) {
|
||||
if (newarr != null) ret.add(newarr)
|
||||
newarr = JSONArray()
|
||||
count = 20
|
||||
}
|
||||
newarr?.put(array[i])
|
||||
--count
|
||||
}
|
||||
if (newarr != null && newarr.length() > 0) ret.add(newarr)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
ret = ArrayList()
|
||||
ret.add(array)
|
||||
override fun sendToXdrip(collection: String, dataPairs: List<DataSyncSelector.DataPair>, progress: String) {
|
||||
when (collection) {
|
||||
"entries" -> sendEntries(dataPairs = dataPairs, progress = progress)
|
||||
"food" -> sendFood(dataPairs = dataPairs, progress = progress)
|
||||
"treatments" -> sendTreatments(dataPairs = dataPairs, progress = progress)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
private fun sendProfileStore(dataPair: DataSyncSelector.DataPair, progress: String) {
|
||||
val data = (dataPair as DataSyncSelector.PairProfileStore).value
|
||||
rxBus.send(EventXdripNewLog("SENDING", "Sent 1 PROFILE ($progress)"))
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_PROFILE)
|
||||
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
.putExtras(Bundle().apply { putString("profile", data.toString()) })
|
||||
)
|
||||
dataSyncSelector.confirmLastProfileStore(dataPair.id)
|
||||
dataSyncSelector.processChangedProfileStore()
|
||||
}
|
||||
|
||||
private fun sendDeviceStatus(dataPair: DataSyncSelector.DataPair, progress: String) {
|
||||
val data = (dataPair as DataSyncSelector.PairDeviceStatus).value.toJson(dateUtil)
|
||||
rxBus.send(EventXdripNewLog("SENDING", "Sent 1 DEVICESTATUS ($progress)"))
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_DEVICE_STATUS)
|
||||
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
.putExtras(Bundle().apply { putString("devicestatus", data.toString()) })
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendEntries(dataPairs: List<DataSyncSelector.DataPair>, progress: String) {
|
||||
val array = JSONArray()
|
||||
for (dataPair in dataPairs) {
|
||||
val data = (dataPair as DataSyncSelector.PairGlucoseValue).value.toXdripJson()
|
||||
array.put(data)
|
||||
}
|
||||
rxBus.send(EventXdripNewLog("SENDING", "Sent ${array.length()} BGs ($progress)"))
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_SGV)
|
||||
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
.putExtras(Bundle().apply { putString("sgvs", array.toString()) })
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendFood(dataPairs: List<DataSyncSelector.DataPair>, progress: String) {
|
||||
val array = JSONArray()
|
||||
for (dataPair in dataPairs) {
|
||||
val data = (dataPair as DataSyncSelector.PairFood).value.toJson(true)
|
||||
array.put(data)
|
||||
}
|
||||
rxBus.send(EventXdripNewLog("SENDING", "Sent ${array.length()} FOODs ($progress)"))
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_FOOD)
|
||||
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
.putExtras(Bundle().apply { putString("foods", array.toString()) })
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendTreatments(dataPairs: List<DataSyncSelector.DataPair>, progress: String) {
|
||||
val array = JSONArray()
|
||||
for (dataPair in dataPairs) {
|
||||
when (dataPair) {
|
||||
is DataSyncSelector.PairBolus -> dataPair.value.toJson(true, dateUtil)
|
||||
is DataSyncSelector.PairCarbs -> dataPair.value.toJson(true, dateUtil)
|
||||
is DataSyncSelector.PairBolusCalculatorResult -> dataPair.value.toJson(true, dateUtil, profileFunction)
|
||||
is DataSyncSelector.PairTemporaryTarget -> dataPair.value.toJson(true, profileFunction.getUnits(), dateUtil)
|
||||
is DataSyncSelector.PairTherapyEvent -> dataPair.value.toJson(true, dateUtil)
|
||||
|
||||
is DataSyncSelector.PairTemporaryBasal -> {
|
||||
val profile = profileFunction.getProfile(dataPair.value.timestamp) ?: return
|
||||
dataPair.value.toJson(true, profile, dateUtil)
|
||||
}
|
||||
|
||||
is DataSyncSelector.PairExtendedBolus -> {
|
||||
val profile = profileFunction.getProfile(dataPair.value.timestamp) ?: return
|
||||
dataPair.value.toJson(true, profile, dateUtil)
|
||||
}
|
||||
|
||||
is DataSyncSelector.PairProfileSwitch -> dataPair.value.toJson(true, dateUtil)
|
||||
is DataSyncSelector.PairEffectiveProfileSwitch -> dataPair.value.toJson(true, dateUtil)
|
||||
is DataSyncSelector.PairOfflineEvent -> dataPair.value.toJson(true, dateUtil)
|
||||
else -> null
|
||||
}?.let {
|
||||
array.put(it)
|
||||
}
|
||||
}
|
||||
rxBus.send(EventXdripNewLog("SENDING", "Sent ${array.length()} TRs ($progress)"))
|
||||
broadcast(
|
||||
Intent(Intents.ACTION_NEW_FOOD)
|
||||
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
.putExtras(Bundle().apply { putString("treatments", array.toString()) })
|
||||
)
|
||||
}
|
||||
|
||||
private fun broadcast(intent: Intent) {
|
||||
|
@ -315,7 +417,10 @@ class XdripPlugin @Inject constructor(
|
|||
resolveInfo.activityInfo.packageName?.let {
|
||||
intent.setPackage(it)
|
||||
context.sendBroadcast(intent)
|
||||
aapsLogger.debug(LTag.CORE, "Sending broadcast " + intent.action + " to: " + it)
|
||||
aapsLogger.debug(LTag.XDRIP, "Sending broadcast " + intent.action + " to: " + it)
|
||||
rxBus.send(EventXdripNewLog("RECIPIENT", it))
|
||||
rxBus.send(EventXdripUpdateGUI())
|
||||
Thread.sleep(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.plugins.sync.xdrip.events
|
||||
|
||||
import info.nightscout.rx.events.EventUpdateGui
|
||||
|
||||
class EventXdripUpdateGUI : EventUpdateGui()
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.plugins.sync.xdrip.extensions
|
||||
|
||||
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.GlucoseUnit
|
||||
import info.nightscout.interfaces.iob.InMemoryGlucoseValue
|
||||
import info.nightscout.interfaces.utils.DecimalFormatter
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import org.json.JSONObject
|
||||
|
||||
fun GlucoseValue.toXdripJson(): JSONObject =
|
||||
JSONObject()
|
||||
.put("device", sourceSensor.text)
|
||||
.put("mills", timestamp)
|
||||
.put("isValid", isValid)
|
||||
.put("mgdl", value)
|
||||
.put("direction", trendArrow.text)
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package info.nightscout.plugins.sync.xdrip.workers
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.WorkerParameters
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.core.utils.worker.LoggingWorker
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.plugins.sync.xdrip.XdripDataSyncSelectorImplementation
|
||||
import info.nightscout.plugins.sync.xdrip.events.EventXdripUpdateGUI
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.EventXdripNewLog
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import javax.inject.Inject
|
||||
|
||||
@OpenForTesting
|
||||
class XdripDataSyncWorker(
|
||||
context: Context, params: WorkerParameters
|
||||
) : LoggingWorker(context, params, Dispatchers.IO) {
|
||||
|
||||
@Inject lateinit var dataSyncSelector: XdripDataSyncSelectorImplementation
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
rxBus.send(EventXdripNewLog("UPL", "Start"))
|
||||
dataSyncSelector.doUpload()
|
||||
rxBus.send(EventXdripNewLog("UPL", "End"))
|
||||
rxBus.send(EventXdripUpdateGUI())
|
||||
return Result.success()
|
||||
}
|
||||
}
|
64
plugins/sync/src/main/res/layout/xdrip_fragment.xml
Normal file
64
plugins/sync/src/main/res/layout/xdrip_fragment.xml
Normal file
|
@ -0,0 +1,64 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context="info.nightscout.plugins.sync.xdrip.XdripFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/autoscroll"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="@string/ns_client_autoscroll"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/queue" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/queue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/log_scrollview"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/log"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="" />
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
|
@ -106,8 +106,6 @@
|
|||
<string name="ns_alarm_stale_data_value_label">Stale data threshold [min]</string>
|
||||
<string name="ns_alarm_urgent_stale_data_value_label">Urgent stale data threshold [min]</string>
|
||||
<string name="ns_log_app_started_event">Log app start to NS</string>
|
||||
<string name="ns_local_broadcasts">Enable broadcasts to other apps (like xDrip+). Do not enable if you have more than one instance of AAPS or AAPSClient installed!</string>
|
||||
<string name="ns_local_broadcasts_title">Enable local Broadcasts.</string>
|
||||
<string name="copy_existing_values">Copy NS settings (if exists)?</string>
|
||||
|
||||
<!-- Tidepool -->
|
||||
|
@ -161,6 +159,24 @@
|
|||
<string name="xdrip_not_installed">xDrip+ not installed</string>
|
||||
<string name="calibration_sent">Calibration sent to xDrip+</string>
|
||||
|
||||
<string name="key_xdrip_temporary_target_last_synced_id" translatable="false">xdrip_temporary_target_last_sync</string>
|
||||
<string name="key_xdrip_glucose_value_last_synced_id" translatable="false">xdrip_glucose_value_last_sync</string>
|
||||
<string name="key_xdrip_food_last_synced_id" translatable="false">xdrip_food_last_sync</string>
|
||||
<string name="key_xdrip_therapy_event_last_synced_id" translatable="false">xdrip_therapy_event_last_sync</string>
|
||||
<string name="key_xdrip_bolus_calculator_result_last_synced_id" translatable="false">xdrip_bolus_calculator_result_last_synced_id</string>
|
||||
<string name="key_xdrip_carbs_last_synced_id" translatable="false">xdrip_carbs_last_synced_id</string>
|
||||
<string name="key_xdrip_bolus_last_synced_id" translatable="false">xdrip_bolus_last_synced_id</string>
|
||||
<string name="key_xdrip_device_status_last_synced_id" translatable="false">xdrip_device_status_last_synced_id</string>
|
||||
<string name="key_xdrip_temporary_basal_last_synced_id" translatable="false">xdrip_temporary_basal_last_synced_id</string>
|
||||
<string name="key_xdrip_extended_bolus_last_synced_id" translatable="false">xdrip_extended_bolus_last_synced_id</string>
|
||||
<string name="key_xdrip_profile_switch_last_synced_id" translatable="false">profile_switch_last_synced_id</string>
|
||||
<string name="key_xdrip_effective_profile_switch_last_synced_id" translatable="false">xdrip_effective_profile_switch_last_synced_id</string>
|
||||
<string name="key_xdrip_offline_event_last_synced_id" translatable="false">xdrip_offline_event_last_synced_id</string>
|
||||
<string name="key_xdrip_profile_store_last_synced_timestamp" translatable="false">xdrip_profile_store_last_synced_timestamp</string>
|
||||
|
||||
<string name="xdrip_local_broadcasts_summary">Send glucose and treatments data to xDrip+. Data Source \"xDrip+ Sync Follower\" must be selected and accepting of data must be enabled in Settings - Inter-app settings - Accept Glucose/Treatments</string>
|
||||
<string name="xdrip_local_broadcasts_title">Enable broadcasts to xDrip+.</string>
|
||||
|
||||
|
||||
<!-- DataBroadcast-->
|
||||
<string name="data_broadcaster" translatable="false">Data Broadcaster</string>
|
||||
|
|
|
@ -198,12 +198,6 @@
|
|||
android:summary="@string/ns_create_announcements_from_carbs_req_summary"
|
||||
android:title="@string/ns_create_announcements_from_carbs_req_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_nsclient_localbroadcasts"
|
||||
android:summary="@string/ns_local_broadcasts"
|
||||
android:title="@string/ns_local_broadcasts_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_ns_sync_slow"
|
||||
|
|
|
@ -204,12 +204,6 @@
|
|||
android:summary="@string/ns_create_announcements_from_carbs_req_summary"
|
||||
android:title="@string/ns_create_announcements_from_carbs_req_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_nsclient_localbroadcasts"
|
||||
android:summary="@string/ns_local_broadcasts"
|
||||
android:title="@string/ns_local_broadcasts_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_ns_sync_slow"
|
||||
|
|
|
@ -7,6 +7,12 @@
|
|||
android:title="@string/xdrip"
|
||||
app:initialExpandedChildrenCount="0">
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_xdrip_local_broadcasts"
|
||||
android:summary="@string/xdrip_local_broadcasts_summary"
|
||||
android:title="@string/xdrip_local_broadcasts_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_xdrip_send_status"
|
||||
|
|
|
@ -73,7 +73,7 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
|
|||
|
||||
@BeforeEach
|
||||
fun prepare() {
|
||||
storeDataForDb = StoreDataForDbImpl(aapsLogger, rxBus, repository, sp, uel, dateUtil, config, nsClientSource, xDripBroadcast, virtualPump, uiInteraction)
|
||||
storeDataForDb = StoreDataForDbImpl(aapsLogger, rxBus, repository, sp, uel, dateUtil, config, nsClientSource, virtualPump, uiInteraction)
|
||||
sut =
|
||||
NSClientV3Plugin(
|
||||
injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy,
|
||||
|
@ -98,6 +98,7 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
|
|||
"\"LastBolus\":\"02.01.23 15:24\",\"LastBolusAmount\":\"1\",\"TempBasalAbsoluteRate\":\"0\",\"TempBasalStart\":\"02.01.23 16:20\",\"TempBasalRemaining\":\"55\",\"BaseBasalRate\":\"0" +
|
||||
".41\",\"ActiveProfile\":\"L29_U200 IC\"},\"reservoir\":\"133\",\"clock\":\"2023-01-02T15:25:05.826Z\"}",
|
||||
uploaderBattery = 60,
|
||||
isCharging = false,
|
||||
configuration = "{\"insulin\":5,\"insulinConfiguration\":{},\"sensitivity\":2,\"sensitivityConfiguration\":{\"openapsama_min_5m_carbimpact\":8,\"absorption_cutoff\":4,\"autosens_max\":1.2,\"autosens_min\":0.7},\"overviewConfiguration\":{\"units\":\"mmol\",\"QuickWizard\":\"[]\",\"eatingsoon_duration\":60,\"eatingsoon_target\":4,\"activity_duration\":180,\"activity_target\":7.5,\"hypo_duration\":90,\"hypo_target\":8,\"low_mark\":3.9,\"high_mark\":10,\"statuslights_cage_warning\":72,\"statuslights_cage_critical\":96,\"statuslights_iage_warning\":120,\"statuslights_iage_critical\":150,\"statuslights_sage_warning\":168,\"statuslights_sage_critical\":336,\"statuslights_sbat_warning\":25,\"statuslights_sbat_critical\":5,\"statuslights_bage_warning\":720,\"statuslights_bage_critical\":800,\"statuslights_res_warning\":30,\"statuslights_res_critical\":10,\"statuslights_bat_warning\":50,\"statuslights_bat_critical\":25,\"boluswizard_percentage\":70},\"safetyConfiguration\":{\"age\":\"resistantadult\",\"treatmentssafety_maxbolus\":10,\"treatmentssafety_maxcarbs\":70}}"
|
||||
)
|
||||
val dataPair = DataSyncSelector.PairDeviceStatus(deviceStatus, 1000)
|
||||
|
|
|
@ -76,6 +76,7 @@ internal class DeviceStatusExtensionKtTest : TestBase() {
|
|||
".41\"," +
|
||||
"\"ActiveProfile\":\"L29_U200 IC\"},\"reservoir\":\"133\",\"clock\":\"2023-01-02T15:25:05.826Z\"}",
|
||||
uploaderBattery = 60,
|
||||
isCharging = false,
|
||||
configuration = "{\"insulin\":5,\"insulinConfiguration\":{},\"sensitivity\":2,\"sensitivityConfiguration\":{\"openapsama_min_5m_carbimpact\":8,\"absorption_cutoff\":4,\"autosens_max\":1.2,\"autosens_min\":0.7},\"overviewConfiguration\":{\"units\":\"mmol\",\"QuickWizard\":\"[]\",\"eatingsoon_duration\":60,\"eatingsoon_target\":4,\"activity_duration\":180,\"activity_target\":7.5,\"hypo_duration\":90,\"hypo_target\":8,\"low_mark\":3.9,\"high_mark\":10,\"statuslights_cage_warning\":72,\"statuslights_cage_critical\":96,\"statuslights_iage_warning\":120,\"statuslights_iage_critical\":150,\"statuslights_sage_warning\":168,\"statuslights_sage_critical\":336,\"statuslights_sbat_warning\":25,\"statuslights_sbat_critical\":5,\"statuslights_bage_warning\":720,\"statuslights_bage_critical\":800,\"statuslights_res_warning\":30,\"statuslights_res_critical\":10,\"statuslights_bat_warning\":50,\"statuslights_bat_critical\":25,\"boluswizard_percentage\":70},\"safetyConfiguration\":{\"age\":\"resistantadult\",\"treatmentssafety_maxbolus\":10,\"treatmentssafety_maxcarbs\":70}}"
|
||||
)
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.junit.jupiter.api.Assertions
|
|||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.anyLong
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.ArgumentMatchers.eq
|
||||
|
@ -124,7 +125,7 @@ internal class LoadBgWorkerTest : TestBase() {
|
|||
Assertions.assertTrue(result is ListenableWorker.Result.Success)
|
||||
Assertions.assertTrue(result.outputData.getString("Result") == "Load not enabled")
|
||||
Mockito.verify(workManager, Mockito.times(1)).enqueueUniqueWork(
|
||||
eq(NSClientV3Plugin.JOB_NAME),
|
||||
eq(nsClientV3Plugin.JOB_NAME),
|
||||
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
|
||||
any<OneTimeWorkRequest>()
|
||||
)
|
||||
|
@ -138,13 +139,13 @@ internal class LoadBgWorkerTest : TestBase() {
|
|||
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = 0L // first load
|
||||
nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries = now - 1000
|
||||
sut = TestListenableWorkerBuilder<LoadBgWorker>(context).build()
|
||||
Mockito.`when`(nsAndroidClient.getSgvsNewerThan(anyLong(), anyLong())).thenReturn(NSAndroidClient.ReadResponse(200, 0, emptyList()))
|
||||
Mockito.`when`(nsAndroidClient.getSgvsNewerThan(anyLong(), anyInt())).thenReturn(NSAndroidClient.ReadResponse(200, 0, emptyList()))
|
||||
|
||||
val result = sut.doWorkAndLog()
|
||||
Assertions.assertEquals(now - 1000, nsClientV3Plugin.lastLoadedSrvModified.collections.entries)
|
||||
Assertions.assertTrue(result is ListenableWorker.Result.Success)
|
||||
Mockito.verify(workManager, Mockito.times(1)).beginUniqueWork(
|
||||
eq(NSClientV3Plugin.JOB_NAME),
|
||||
eq(nsClientV3Plugin.JOB_NAME),
|
||||
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
|
||||
any<OneTimeWorkRequest>()
|
||||
)
|
||||
|
@ -175,12 +176,12 @@ internal class LoadBgWorkerTest : TestBase() {
|
|||
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = 0L // first load
|
||||
nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries = now - 1000
|
||||
sut = TestListenableWorkerBuilder<LoadBgWorker>(context).build()
|
||||
Mockito.`when`(nsAndroidClient.getSgvsNewerThan(anyLong(), anyLong())).thenReturn(NSAndroidClient.ReadResponse(200, 0, listOf(glucoseValue.toNSSvgV3())))
|
||||
Mockito.`when`(nsAndroidClient.getSgvsNewerThan(anyLong(), anyInt())).thenReturn(NSAndroidClient.ReadResponse(200, 0, listOf(glucoseValue.toNSSvgV3())))
|
||||
|
||||
val result = sut.doWorkAndLog()
|
||||
Assertions.assertTrue(result is ListenableWorker.Result.Success)
|
||||
Mockito.verify(workManager, Mockito.times(1)).beginUniqueWork(
|
||||
eq(NSClientV3Plugin.JOB_NAME),
|
||||
eq(nsClientV3Plugin.JOB_NAME),
|
||||
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
|
||||
any<OneTimeWorkRequest>()
|
||||
)
|
||||
|
@ -197,13 +198,13 @@ internal class LoadBgWorkerTest : TestBase() {
|
|||
nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries = now - 1000
|
||||
nsClientV3Plugin.newestDataOnServer?.collections?.entries = now - 2000
|
||||
sut = TestListenableWorkerBuilder<LoadBgWorker>(context).build()
|
||||
Mockito.`when`(nsAndroidClient.getSgvsNewerThan(anyLong(), anyLong())).thenReturn(NSAndroidClient.ReadResponse(200, 0, emptyList()))
|
||||
Mockito.`when`(nsAndroidClient.getSgvsNewerThan(anyLong(), anyInt())).thenReturn(NSAndroidClient.ReadResponse(200, 0, emptyList()))
|
||||
|
||||
val result = sut.doWorkAndLog()
|
||||
Assertions.assertEquals(now - 1000, nsClientV3Plugin.lastLoadedSrvModified.collections.entries)
|
||||
Assertions.assertTrue(result is ListenableWorker.Result.Success)
|
||||
Mockito.verify(workManager, Mockito.times(1)).beginUniqueWork(
|
||||
eq(NSClientV3Plugin.JOB_NAME),
|
||||
eq(nsClientV3Plugin.JOB_NAME),
|
||||
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
|
||||
any<OneTimeWorkRequest>()
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue