From d559961c122fd8a76a245db7027dc3b628405555 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 28 Jan 2020 18:00:46 +0100 Subject: [PATCH] DataBroadcastPlugin --- .../info/nightscout/androidaps/MainApp.java | 3 + .../dataBroadcaster/DataBroadcastPlugin.kt | 213 ++++++++++++++++++ .../general/nsclient/data/NSDeviceStatus.java | 10 +- .../wearintegration/WatchUpdaterService.java | 19 +- .../androidaps/services/Intents.java | 3 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 227 insertions(+), 22 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index c3a5eb0ab6..d1906dc828 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -58,6 +58,7 @@ import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionChec import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin; import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin; +import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin; import info.nightscout.androidaps.plugins.general.food.FoodPlugin; import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils; import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin; @@ -146,6 +147,7 @@ public class MainApp extends DaggerApplication { @Inject DanaRSPlugin danaRSPlugin; @Inject DanaRv2Plugin danaRv2Plugin; @Inject DanaRKoreanPlugin danaRKoreanPlugin; + @Inject DataBroadcastPlugin dataBroadcastPlugin; @Inject DstHelperPlugin dstHelperPlugin; @Inject FoodPlugin foodPlugin; @Inject InsulinOrefFreePeakPlugin insulinOrefFreePeakPlugin; @@ -295,6 +297,7 @@ public class MainApp extends DaggerApplication { pluginsList.add(maintenancePlugin); pluginsList.add(automationPlugin); pluginsList.add(dstHelperPlugin); + pluginsList.add(dataBroadcastPlugin); pluginsList.add(configBuilderPlugin); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt new file mode 100644 index 0000000000..9245768538 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt @@ -0,0 +1,213 @@ +package info.nightscout.androidaps.plugins.general.dataBroadcaster + +import android.content.Context +import android.content.Intent +import android.content.pm.ResolveInfo +import android.os.Bundle +import dagger.Lazy +import info.nightscout.androidaps.Config +import info.nightscout.androidaps.R +import info.nightscout.androidaps.data.IobTotal +import info.nightscout.androidaps.db.BgReading +import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.events.EventExtendedBolusChange +import info.nightscout.androidaps.events.EventNewBasalProfile +import info.nightscout.androidaps.events.EventTempBasalChange +import info.nightscout.androidaps.events.EventTreatmentChange +import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.PluginBase +import info.nightscout.androidaps.interfaces.PluginDescription +import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.BundleLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin +import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction +import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.services.Intents +import info.nightscout.androidaps.utils.BatteryLevel +import info.nightscout.androidaps.utils.DefaultValueHelper +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.resources.ResourceHelper +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DataBroadcastPlugin @Inject constructor( + aapsLogger: AAPSLogger, + resourceHelper: ResourceHelper, + private val context: Context, + private val fabricPrivacy: FabricPrivacy, + private val rxBus: RxBusWrapper, + private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val profileFunction: ProfileFunction, + private val defaultValueHelper: DefaultValueHelper, + private val nsDeviceStatus: NSDeviceStatus, + private val lazyLoopPlugin: Lazy, + private val activePlugin: ActivePluginProvider + +) : PluginBase(PluginDescription() + .mainType(PluginType.GENERAL) + .pluginName(R.string.databroadcaster) + .alwaysEnabled(true) + .neverVisible(true) + .showInList(false), + aapsLogger, resourceHelper +) { + + private val disposable = CompositeDisposable() + override fun onStart() { + super.onStart() + disposable.add(rxBus + .toObservable(EventOpenAPSUpdateGui::class.java) + .observeOn(Schedulers.io()) + .subscribe({ sendData(it) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventExtendedBolusChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ sendData(it) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventTempBasalChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ sendData(it) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventTreatmentChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ sendData(it) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventNewBasalProfile::class.java) + .observeOn(Schedulers.io()) + .subscribe({ sendData(it) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventAutosensCalculationFinished::class.java) + .observeOn(Schedulers.io()) + .subscribe({ sendData(it) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventOverviewBolusProgress::class.java) + .observeOn(Schedulers.io()) + .subscribe({ sendData(it) }) { fabricPrivacy.logException(it) }) + } + + override fun onStop() { + disposable.clear() + super.onStop() + } + + private fun sendData(event: Event) { + val bundle = Bundle() + bgStatus(bundle) + iobCob(bundle) + loopStatus(bundle) + basalStatus(bundle) + pumpStatus(bundle) + + if (event is EventOverviewBolusProgress && !event.isSMB()) { + bundle.putInt("progressPercent", event.percent) + bundle.putString("progressStatus", event.status) + } + + //aapsLogger.debug("Prepared bundle:\n" + BundleLogger.log(bundle)) + sendBroadcast( + Intent(Intents.AAPS_BROADCAST) // "info.nightscout.androidaps.status" + .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) + .putExtras(bundle) + ) + } + + private fun bgStatus(bundle: Bundle) { + val lastBG: BgReading = iobCobCalculatorPlugin.lastBg() ?: return + val glucoseStatus = GlucoseStatus.getGlucoseStatusData() ?: return + + bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl + bundle.putLong("glucoseTimeStamp", lastBG.date) // timestamp + bundle.putString("units", profileFunction.getUnits()) // units used in AAPS "mg/dl" or "mmol" + bundle.putString("slopeArrow", lastBG.directionToSymbol()) // direction arrow as string + bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl + bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgdelta) // average bg delta + bundle.putDouble("high", defaultValueHelper.determineHighLine()) // predefined top value of in range (green area) + bundle.putDouble("low", defaultValueHelper.determineLowLine()) // predefined bottom value of in range + } + + private fun iobCob(bundle: Bundle) { + profileFunction.getProfile() ?: return + activePlugin.activeTreatments.updateTotalIOBTreatments() + val bolusIob: IobTotal = activePlugin.activeTreatments.lastCalculationTreatments.round() + activePlugin.activeTreatments.updateTotalIOBTempBasals() + val basalIob: IobTotal = activePlugin.activeTreatments.lastCalculationTempBasals.round() + bundle.putDouble("bolusIob", bolusIob.iob) + bundle.putDouble("basalIob", basalIob.basaliob) + bundle.putDouble("iob", bolusIob.iob + basalIob.basaliob) // total IOB + + val cob = iobCobCalculatorPlugin.getCobInfo(false, "broadcast") + bundle.putDouble("cob", cob.displayCob ?: -1.0) // COB [g] or -1 if N/A + bundle.putDouble("futureCarbs", cob.futureCarbs) // future scheduled carbs + } + + private fun loopStatus(bundle: Bundle) { + //batteries + bundle.putInt("phoneBattery", BatteryLevel.getBatteryLevel()) + bundle.putInt("rigBattery", nsDeviceStatus.uploaderStatus.replace("%","").trim { it <= ' ' }.toInt()) + + if (Config.APS && lazyLoopPlugin.get().lastRun?.lastEnact != null) { //we are AndroidAPS + bundle.putLong("suggestedTimeStamp", lazyLoopPlugin.get().lastRun?.lastAPSRun?.time + ?: -1L) + bundle.putString("suggested", lazyLoopPlugin.get().lastRun?.request?.json().toString()) + if (lazyLoopPlugin.get().lastRun.tbrSetByPump != null && lazyLoopPlugin.get().lastRun.tbrSetByPump.enacted) { + bundle.putLong("enactedTimeStamp", lazyLoopPlugin.get().lastRun?.lastEnact?.time + ?: -1L) + bundle.putString("enacted", lazyLoopPlugin.get().lastRun?.request?.json().toString()) + } + } else { //NSClient or remote + val data = NSDeviceStatus.deviceStatusOpenAPSData + if (data.clockSuggested != 0L && data.suggested != null) { + bundle.putLong("suggestedTimeStamp", data.clockSuggested) + bundle.putString("suggested", data.suggested.toString()) + } + if (data.clockEnacted != 0L && data.enacted != null) { + bundle.putLong("enactedTimeStamp", data.clockEnacted) + bundle.putString("enacted", data.enacted.toString()) + } + } + } + + private fun basalStatus(bundle: Bundle) { + val now = System.currentTimeMillis() + val profile = profileFunction.getProfile() ?: return + bundle.putLong("basalTimeStamp", now) + bundle.putDouble("baseBasal", profile.basal) + bundle.putString("profile", profileFunction.getProfileName()) + activePlugin.activeTreatments.getTempBasalFromHistory(now)?.let { + bundle.putLong("tempBasalStart", it.date) + bundle.putInt("tempBasalDurationInMinutes", it.durationInMinutes) + if (it.isAbsolute) bundle.putDouble("tempBasalAbsolute", it.absoluteRate) // U/h for absolute TBR + else bundle.putInt("tempBasalPercent", it.percentRate) // % for percent type TBR + bundle.putString("tempBasalString", it.toStringFull()) // user friendly string + } + } + + private fun pumpStatus(bundle: Bundle) { + val pump = activePlugin.activePump + bundle.putLong("pumpTimeStamp", pump.lastDataTime()) + bundle.putInt("pumpBattery", pump.batteryLevel) + bundle.putDouble("pumpReservoir", pump.reservoirLevel) + bundle.putString("pumpStatus", pump.shortStatus(false)) + } + + private fun sendBroadcast(intent: Intent) { + val receivers: List = context.packageManager.queryBroadcastReceivers(intent, 0) + for (resolveInfo in receivers) + resolveInfo.activityInfo.packageName?.let { + intent.setPackage(it) + context.sendBroadcast(intent) + aapsLogger.debug(LTag.CORE, "Sending broadcast " + intent.action + " to: " + it) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java index c099197c5a..08013c9801 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java @@ -282,13 +282,13 @@ public class NSDeviceStatus { // ********* OpenAPS data *********** - static DeviceStatusOpenAPSData deviceStatusOpenAPSData = new DeviceStatusOpenAPSData(); + public static DeviceStatusOpenAPSData deviceStatusOpenAPSData = new DeviceStatusOpenAPSData(); - static class DeviceStatusOpenAPSData { - long clockSuggested = 0L; - long clockEnacted = 0L; + public static class DeviceStatusOpenAPSData { + public long clockSuggested = 0L; + public long clockEnacted = 0L; - JSONObject suggested = null; + public JSONObject suggested = null; public JSONObject enacted = null; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java index bdb920c6b0..d9ebbf4f3c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java @@ -1,10 +1,7 @@ package info.nightscout.androidaps.plugins.general.wear.wearintegration; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.os.AsyncTask; -import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -53,6 +50,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; +import info.nightscout.androidaps.utils.BatteryLevel; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.DefaultValueHelper; import info.nightscout.androidaps.utils.ToastUtils; @@ -706,7 +704,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog //batteries - int phoneBattery = getBatteryLevel(getApplicationContext()); + int phoneBattery = BatteryLevel.getBatteryLevel(); String rigBattery = nsDeviceStatus.getUploaderStatus().trim(); @@ -848,17 +846,4 @@ public class WatchUpdaterService extends WearableListenerService implements Goog public static boolean shouldReportLoopStatus(boolean enabled) { return (lastLoopStatus != enabled); } - - public static int getBatteryLevel(Context context) { - Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - if (batteryIntent != null) { - int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - if (level == -1 || scale == -1) { - return 50; - } - return (int) (((float) level / (float) scale) * 100.0f); - } - return 50; - } } diff --git a/app/src/main/java/info/nightscout/androidaps/services/Intents.java b/app/src/main/java/info/nightscout/androidaps/services/Intents.java index 415f49b4f0..f8742bb8b6 100644 --- a/app/src/main/java/info/nightscout/androidaps/services/Intents.java +++ b/app/src/main/java/info/nightscout/androidaps/services/Intents.java @@ -34,4 +34,7 @@ public interface Intents { String POCTECH_BG = "com.china.poctech.data"; String TOMATO_BG = "com.fanqies.tomatofn.BgEstimate"; + + // Broadcast status + String AAPS_BROADCAST = "info.nightscout.androidaps.status"; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aa28b7b0ef..c5f9ea0694 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1695,5 +1695,6 @@ \"PhoneChecker\" Chart menu AS + Data Broadcaster