move XDripBroadcast to XdripPlugin

This commit is contained in:
Milos Kozak 2023-01-17 17:10:54 +01:00
parent d57ec150a5
commit 36153c9b49
19 changed files with 303 additions and 224 deletions

View file

@ -1,14 +1,87 @@
package info.nightscout.interfaces 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.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.JSONArray
import org.json.JSONObject import org.json.JSONObject
/**
* Send data to xDrip+ via Inter-app settings
*/
interface XDripBroadcast { interface XDripBroadcast {
/**
* Send calibration to xDrip+
* Accepting must be enabled in Inter-app settings - Accept Calibrations
*/
fun sendCalibration(bg: Double): Boolean fun sendCalibration(bg: Double): Boolean
fun send(glucoseValue: GlucoseValue) fun sendIn640gMode(glucoseValue: GlucoseValue)
fun sendProfile(profileStoreJson: JSONObject) fun sendProfile(profileStoreJson: JSONObject)
fun sendTreatments(addedOrUpdatedTreatments: JSONArray) fun sendTreatments(addedOrUpdatedTreatments: JSONArray)
fun sendSgvs(sgvs: JSONArray) fun sendSgvs(sgvs: JSONArray)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept Glucose
*/
fun send(gv: GlucoseValue)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept 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)
} }

View file

@ -10,6 +10,10 @@ interface Intents {
const val ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE" const val ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE"
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV" const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
const val EXTRA_STATUSLINE = "com.eveningoutpost.dexdrip.Extras.Statusline"
const val ACTION_NEW_EXTERNAL_STATUSLINE = "com.eveningoutpost.dexdrip.ExternalStatusline"
const val RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_EXTERNAL_STATUSLINE"
// AAPS -> xDrip 640G mode // AAPS -> xDrip 640G mode
const val XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR" const val XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR"

View file

@ -1,163 +0,0 @@
package info.nightscout.implementation
import android.content.Context
import android.content.Intent
import android.os.Bundle
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.receivers.Intents
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 org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton
@Suppress("SpellCheckingInspection")
@OpenForTesting
@Singleton
class XDripBroadcastImpl @Inject constructor(
private val context: Context,
private val aapsLogger: AAPSLogger,
private val sp: SP,
private val rh: ResourceHelper,
private val profileFunction: ProfileFunction
) : XDripBroadcast {
override fun sendCalibration(bg: Double): Boolean {
val bundle = Bundle()
bundle.putDouble("glucose_number", bg)
bundle.putString("units", if (profileFunction.getUnits() == GlucoseUnit.MGDL) "mgdl" else "mmol")
bundle.putLong("timestamp", System.currentTimeMillis())
val intent = Intent(Intents.ACTION_REMOTE_CALIBRATION)
intent.putExtras(bundle)
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
context.sendBroadcast(intent)
val q = context.packageManager.safeQueryBroadcastReceivers(intent, 0)
return if (q.isEmpty()) {
ToastUtils.errorToast(context, R.string.xdrip_not_installed)
aapsLogger.debug(rh.gs(R.string.xdrip_not_installed))
false
} else {
ToastUtils.errorToast(context, R.string.calibration_sent)
aapsLogger.debug(rh.gs(R.string.calibration_sent))
true
}
}
// sent in 640G mode
override fun send(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)
}
}
}
// 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()) })
}
)
}
}
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)
}
return ret
}
private fun broadcast(intent: Intent) {
context.packageManager.safeQueryBroadcastReceivers(intent, 0).forEach { resolveInfo ->
resolveInfo.activityInfo.packageName?.let {
intent.setPackage(it)
context.sendBroadcast(intent)
aapsLogger.debug(LTag.CORE, "Sending broadcast " + intent.action + " to: " + it)
}
}
}
}

View file

@ -10,7 +10,6 @@ import info.nightscout.implementation.LocalAlertUtilsImpl
import info.nightscout.implementation.TranslatorImpl import info.nightscout.implementation.TranslatorImpl
import info.nightscout.implementation.TrendCalculatorImpl import info.nightscout.implementation.TrendCalculatorImpl
import info.nightscout.implementation.UserEntryLoggerImpl import info.nightscout.implementation.UserEntryLoggerImpl
import info.nightscout.implementation.XDripBroadcastImpl
import info.nightscout.implementation.androidNotification.NotificationHolderImpl import info.nightscout.implementation.androidNotification.NotificationHolderImpl
import info.nightscout.implementation.db.PersistenceLayerImpl import info.nightscout.implementation.db.PersistenceLayerImpl
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
@ -40,7 +39,6 @@ import info.nightscout.implementation.userEntry.UserEntryPresentationHelperImpl
import info.nightscout.interfaces.LocalAlertUtils import info.nightscout.interfaces.LocalAlertUtils
import info.nightscout.interfaces.NotificationHolder import info.nightscout.interfaces.NotificationHolder
import info.nightscout.interfaces.Translator import info.nightscout.interfaces.Translator
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.db.PersistenceLayer import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.iob.GlucoseStatusProvider import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.logging.LoggerUtils import info.nightscout.interfaces.logging.LoggerUtils
@ -105,7 +103,6 @@ abstract class ImplementationModule {
@Binds fun bindTirCalculatorInterface(tirCalculator: TirCalculatorImpl): TirCalculator @Binds fun bindTirCalculatorInterface(tirCalculator: TirCalculatorImpl): TirCalculator
@Binds fun bindDexcomTirCalculatorInterface(dexcomTirCalculator: DexcomTirCalculatorImpl): DexcomTirCalculator @Binds fun bindDexcomTirCalculatorInterface(dexcomTirCalculator: DexcomTirCalculatorImpl): DexcomTirCalculator
@Binds fun bindPumpSyncInterface(pumpSyncImplementation: PumpSyncImplementation): PumpSync @Binds fun bindPumpSyncInterface(pumpSyncImplementation: PumpSyncImplementation): PumpSync
@Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XDripBroadcastImpl): XDripBroadcast
@Binds fun bindLocalAlertUtilsInterface(localAlertUtils: LocalAlertUtilsImpl): LocalAlertUtils @Binds fun bindLocalAlertUtilsInterface(localAlertUtils: LocalAlertUtilsImpl): LocalAlertUtils
@Binds fun bindIconsProviderInterface(iconsProvider: IconsProviderImplementation): IconsProvider @Binds fun bindIconsProviderInterface(iconsProvider: IconsProviderImplementation): IconsProvider
@Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolderImpl): NotificationHolder @Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolderImpl): NotificationHolder

View file

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="xdrip_not_installed">xDrip+ not installed</string>
<string name="calibration_sent">Calibration sent to xDrip+</string>
<string name="bg_label">BG</string> <string name="bg_label">BG</string>
<string name="executing_right_now">Command is executed right now</string> <string name="executing_right_now">Command is executed right now</string>

View file

@ -185,11 +185,11 @@ class DexcomPlugin @Inject constructor(
} }
} }
} }
xDripBroadcast.send(result.inserted[i]) xDripBroadcast.sendIn640gMode(result.inserted[i])
aapsLogger.debug(LTag.DATABASE, "Inserted bg ${result.inserted[i]}") aapsLogger.debug(LTag.DATABASE, "Inserted bg ${result.inserted[i]}")
} }
result.updated.forEach { result.updated.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Updated bg $it") aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
} }
result.sensorInsertionsInserted.forEach { result.sensorInsertionsInserted.forEach {

View file

@ -114,7 +114,7 @@ class EversensePlugin @Inject constructor(
.blockingGet() .blockingGet()
.also { savedValues -> .also { savedValues ->
savedValues.inserted.forEach { savedValues.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
} }

View file

@ -74,7 +74,7 @@ class GlimpPlugin @Inject constructor(
.blockingGet() .blockingGet()
.also { savedValues -> .also { savedValues ->
savedValues.inserted.forEach { savedValues.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
} }

View file

@ -148,7 +148,7 @@ class GlunovoPlugin @Inject constructor(
.blockingGet() .blockingGet()
.also { savedValues -> .also { savedValues ->
savedValues.inserted.forEach { savedValues.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
savedValues.calibrationsInserted.forEach { calibration -> savedValues.calibrationsInserted.forEach { calibration ->

View file

@ -159,7 +159,7 @@ class IntelligoPlugin @Inject constructor(
.blockingGet() .blockingGet()
.also { savedValues -> .also { savedValues ->
savedValues.inserted.forEach { savedValues.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
savedValues.calibrationsInserted.forEach { calibration -> savedValues.calibrationsInserted.forEach { calibration ->

View file

@ -90,7 +90,7 @@ class MM640gPlugin @Inject constructor(
.blockingGet() .blockingGet()
.also { savedValues -> .also { savedValues ->
savedValues.all().forEach { savedValues.all().forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
} }

View file

@ -150,7 +150,6 @@ class NSClientSourcePlugin @Inject constructor(
} }
} else if (sgvs is List<*>) { // V3 client } else if (sgvs is List<*>) { // V3 client
// xDripBroadcast.sendSgvs(sgvs)
for (i in 0 until sgvs.size) { for (i in 0 until sgvs.size) {
val sgv = toGv(sgvs[i] as NSSgvV3) val sgv = toGv(sgvs[i] as NSSgvV3)

View file

@ -83,7 +83,7 @@ class PoctechPlugin @Inject constructor(
.blockingGet() .blockingGet()
.also { savedValues -> .also { savedValues ->
savedValues.inserted.forEach { savedValues.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
} }

View file

@ -119,7 +119,7 @@ class RandomBgPlugin @Inject constructor(
disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
.subscribe({ savedValues -> .subscribe({ savedValues ->
savedValues.inserted.forEach { savedValues.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
}, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) } }, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) }

View file

@ -74,7 +74,7 @@ class TomatoPlugin @Inject constructor(
.blockingGet() .blockingGet()
.also { savedValues -> .also { savedValues ->
savedValues.inserted.forEach { savedValues.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
} }
} }

View file

@ -7,6 +7,7 @@ import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.Reusable import dagger.Reusable
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.nsclient.NSSettingsStatus import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.nsclient.StoreDataForDb
@ -32,6 +33,7 @@ import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
import info.nightscout.plugins.sync.tidepool.TidepoolFragment import info.nightscout.plugins.sync.tidepool.TidepoolFragment
import info.nightscout.plugins.sync.xdrip.XdripPlugin
@Module( @Module(
includes = [ includes = [
@ -80,6 +82,7 @@ abstract class SyncModule {
@Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus @Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus
@Binds fun bindDataSyncSelectorInterface(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector @Binds fun bindDataSyncSelectorInterface(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
@Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb @Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb
@Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast
} }
} }

View file

@ -163,19 +163,19 @@ class StoreDataForDbImpl @Inject constructor(
.also { result -> .also { result ->
glucoseValues.clear() glucoseValues.clear()
result.updated.forEach { result.updated.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
nsClientSource.detectSource(it) nsClientSource.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Updated bg $it") aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
updated.inc(GlucoseValue::class.java.simpleName) updated.inc(GlucoseValue::class.java.simpleName)
} }
result.inserted.forEach { result.inserted.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
nsClientSource.detectSource(it) nsClientSource.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
inserted.inc(GlucoseValue::class.java.simpleName) inserted.inc(GlucoseValue::class.java.simpleName)
} }
result.updatedNsId.forEach { result.updatedNsId.forEach {
xDripBroadcast.send(it) xDripBroadcast.sendIn640gMode(it)
nsClientSource.detectSource(it) nsClientSource.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Updated nsId bg $it") aapsLogger.debug(LTag.DATABASE, "Updated nsId bg $it")
nsIdUpdated.inc(GlucoseValue::class.java.simpleName) nsIdUpdated.inc(GlucoseValue::class.java.simpleName)

View file

@ -7,7 +7,21 @@ import dagger.android.HasAndroidInjector
import info.nightscout.core.extensions.toStringShort import info.nightscout.core.extensions.toStringShort
import info.nightscout.core.iob.generateCOBString import info.nightscout.core.iob.generateCOBString
import info.nightscout.core.iob.round import info.nightscout.core.iob.round
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.fabric.FabricPrivacy 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.GlucoseUnit
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
@ -15,23 +29,27 @@ import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Profile import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.receivers.Intents
import info.nightscout.interfaces.utils.DecimalFormatter import info.nightscout.interfaces.utils.DecimalFormatter
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppInitialized import info.nightscout.rx.events.EventAppInitialized
import info.nightscout.rx.events.EventAutosensCalculationFinished import info.nightscout.rx.events.EventAutosensCalculationFinished
import info.nightscout.rx.events.EventConfigBuilderChange import info.nightscout.rx.events.EventNewHistoryData
import info.nightscout.rx.events.EventExtendedBolusChange
import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.events.EventRefreshOverview import info.nightscout.rx.events.EventRefreshOverview
import info.nightscout.rx.events.EventTempBasalChange
import info.nightscout.rx.events.EventTreatmentChange
import info.nightscout.rx.logging.AAPSLogger 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.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign 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 javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -58,65 +76,40 @@ class XdripPlugin @Inject constructor(
.preferencesId(R.xml.pref_xdrip) .preferencesId(R.xml.pref_xdrip)
.description(R.string.description_xdrip), .description(R.string.description_xdrip),
aapsLogger, rh, injector aapsLogger, rh, injector
) { ), XDripBroadcast {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private var lastLoopStatus = false private var lastLoopStatus = false
companion object {
//broadcast related constants
@Suppress("SpellCheckingInspection")
private const val EXTRA_STATUSLINE = "com.eveningoutpost.dexdrip.Extras.Statusline"
@Suppress("SpellCheckingInspection")
private const val ACTION_NEW_EXTERNAL_STATUSLINE = "com.eveningoutpost.dexdrip.ExternalStatusline"
@Suppress("SpellCheckingInspection", "unused")
private const val RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_EXTERNAL_STATUSLINE"
}
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
disposable += rxBus.toObservable(EventRefreshOverview::class.java) disposable += rxBus.toObservable(EventRefreshOverview::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ if (lastLoopStatus != (loop as PluginBase).isEnabled()) sendStatus() }, fabricPrivacy::logException) .subscribe({ if (lastLoopStatus != loop.isEnabled()) sendStatusLine() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventExtendedBolusChange::class.java) disposable += rxBus.toObservable(EventNewHistoryData::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException) .subscribe({ sendStatusLine() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventTempBasalChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventTreatmentChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventConfigBuilderChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventAutosensCalculationFinished::class.java) disposable += rxBus.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException) .subscribe({ sendStatusLine() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventPreferenceChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventAppInitialized::class.java) disposable += rxBus.toObservable(EventAppInitialized::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException) .subscribe({ sendStatusLine() }, fabricPrivacy::logException)
} }
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
disposable.clear() disposable.clear()
sendStatus() sendStatusLine()
} }
private fun sendStatus() { private fun sendStatusLine() {
if (sp.getBoolean(R.string.key_xdrip_send_status, false)) { if (sp.getBoolean(R.string.key_xdrip_send_status, false)) {
val status = profileFunction.getProfile()?.let { buildStatusLine(it) } ?: "" val status = profileFunction.getProfile()?.let { buildStatusLine(it) } ?: ""
context.sendBroadcast( context.sendBroadcast(
Intent(ACTION_NEW_EXTERNAL_STATUSLINE).also { Intent(Intents.ACTION_NEW_EXTERNAL_STATUSLINE).also {
it.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) it.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
it.putExtras(Bundle().apply { putString(EXTRA_STATUSLINE, status) }) it.putExtras(Bundle().apply { putString(Intents.EXTRA_STATUSLINE, status) })
} }
) )
} }
@ -154,4 +147,176 @@ class XdripPlugin @Inject constructor(
status.append(" ").append(iobCobCalculator.getCobInfo("StatusLinePlugin").generateCOBString()) status.append(" ").append(iobCobCalculator.getCobInfo("StatusLinePlugin").generateCOBString())
return status.toString() return status.toString()
} }
override fun sendCalibration(bg: Double): Boolean {
val bundle = Bundle()
bundle.putDouble("glucose_number", bg)
bundle.putString("units", if (profileFunction.getUnits() == GlucoseUnit.MGDL) "mgdl" else "mmol")
bundle.putLong("timestamp", System.currentTimeMillis())
val intent = Intent(Intents.ACTION_REMOTE_CALIBRATION)
intent.putExtras(bundle)
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
context.sendBroadcast(intent)
val q = context.packageManager.safeQueryBroadcastReceivers(intent, 0)
return if (q.isEmpty()) {
ToastUtils.errorToast(context, R.string.xdrip_not_installed)
aapsLogger.debug(rh.gs(R.string.xdrip_not_installed))
false
} else {
ToastUtils.errorToast(context, R.string.calibration_sent)
aapsLogger.debug(rh.gs(R.string.calibration_sent))
true
}
}
// 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)
}
}
}
// 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)
}
return ret
}
private fun broadcast(intent: Intent) {
context.packageManager.safeQueryBroadcastReceivers(intent, 0).forEach { resolveInfo ->
resolveInfo.activityInfo.packageName?.let {
intent.setPackage(it)
context.sendBroadcast(intent)
aapsLogger.debug(LTag.CORE, "Sending broadcast " + intent.action + " to: " + it)
}
}
}
} }

View file

@ -165,6 +165,10 @@
<string name="disabled_loop">Loop Disabled</string> <string name="disabled_loop">Loop Disabled</string>
<string name="xdrip_send_status_title">Send Status line to xDrip+</string> <string name="xdrip_send_status_title">Send Status line to xDrip+</string>
<string name="xdrip_not_installed">xDrip+ not installed</string>
<string name="calibration_sent">Calibration sent to xDrip+</string>
<!-- DataBroadcast--> <!-- DataBroadcast-->
<string name="data_broadcaster" translatable="false">Data Broadcaster</string> <string name="data_broadcaster" translatable="false">Data Broadcaster</string>