From 3d94f3f84009da070f014a6d47a340339eaa6a1f Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Mon, 25 Oct 2021 14:32:21 +0200 Subject: [PATCH] NSClient: missing initial profile workaround --- .../dependencyInjection/AppModule.kt | 5 +- .../ProfileFunctionImplementation.kt | 21 +++- .../dataBroadcaster/DataBroadcastPlugin.kt | 4 +- .../general/nsclient/data/DeviceStatusData.kt | 41 ++++++++ .../general/nsclient/data/NSDeviceStatus.kt | 98 +++++++------------ .../general/overview/OverviewFragment.kt | 28 ++++-- 6 files changed, 120 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/DeviceStatusData.kt diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt index 8ec649b664..393b068e07 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt @@ -18,6 +18,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplement import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation +import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation @@ -76,11 +77,11 @@ open class AppModule { aapsLogger: AAPSLogger, sp: SP, rxBus: RxBus, resourceHelper: ResourceHelper, activePlugin: ActivePlugin, repository: AppRepository, dateUtil: DateUtil, config: Config, hardLimits: HardLimits, - aapsSchedulers: AapsSchedulers, fabricPrivacy: FabricPrivacy + aapsSchedulers: AapsSchedulers, fabricPrivacy: FabricPrivacy, deviceStatusData: DeviceStatusData ): ProfileFunction = ProfileFunctionImplementation( aapsLogger, sp, rxBus, resourceHelper, activePlugin, repository, dateUtil, - config, hardLimits, aapsSchedulers, fabricPrivacy + config, hardLimits, aapsSchedulers, fabricPrivacy, deviceStatusData ) @Module diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt index a7096aaef9..9cf9338901 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt @@ -14,6 +14,7 @@ import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HardLimits @@ -39,7 +40,8 @@ class ProfileFunctionImplementation @Inject constructor( private val config: Config, private val hardLimits: HardLimits, aapsSchedulers: AapsSchedulers, - private val fabricPrivacy: FabricPrivacy + private val fabricPrivacy: FabricPrivacy, + private val deviceStatusData: DeviceStatusData ) : ProfileFunction { val cache = LongSparseArray() @@ -113,6 +115,23 @@ class ProfileFunctionImplementation @Inject constructor( } return sealed } + // In NSClient mode effective profile may not be received if older than 2 days + // Try to get it from device status + // Remove this code after switch to api v3 + if (config.NSCLIENT && ps is ValueWrapper.Absent) { + deviceStatusData.pumpData?.activeProfileName?.let { activeProfile -> + activePlugin.activeProfileSource.profile?.getSpecificProfile(activeProfile)?.let { ap -> + val sealed = ProfileSealed.Pure(ap) + synchronized(cache) { + cache.put(rounded, sealed) + } + return sealed + } + + } + } + + return null } 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 index ef71575838..1ed528c1ff 100644 --- 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 @@ -15,6 +15,7 @@ import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData 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.GlucoseStatusProvider @@ -43,6 +44,7 @@ class DataBroadcastPlugin @Inject constructor( private val profileFunction: ProfileFunction, private val defaultValueHelper: DefaultValueHelper, private val nsDeviceStatus: NSDeviceStatus, + private val deviceStatusData: DeviceStatusData, private val loopPlugin: LoopPlugin, private val activePlugin: ActivePlugin, private var receiverStatusStore: ReceiverStatusStore, @@ -158,7 +160,7 @@ class DataBroadcastPlugin @Inject constructor( bundle.putString("enacted", loopPlugin.lastRun?.request?.json().toString()) } } else { //NSClient or remote - val data = nsDeviceStatus.deviceStatusOpenAPSData + val data = deviceStatusData.openAPSData if (data.clockSuggested != 0L && data.suggested != null) { bundle.putLong("suggestedTimeStamp", data.clockSuggested) bundle.putString("suggested", data.suggested.toString()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/DeviceStatusData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/DeviceStatusData.kt new file mode 100644 index 0000000000..9368d5a110 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/DeviceStatusData.kt @@ -0,0 +1,41 @@ +package info.nightscout.androidaps.plugins.general.nsclient.data + +import android.text.Spanned +import org.json.JSONObject +import java.util.HashMap +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DeviceStatusData @Inject constructor() { + + class PumpData { + var clock = 0L + var isPercent = false + var percent = 0 + var voltage = 0.0 + var status = "N/A" + var reservoir = 0.0 + var extended: Spanned? = null + var activeProfileName: String? = null + } + + var pumpData: PumpData? = null + + class Uploader { + var clock = 0L + var battery = 0 + } + + val uploaderMap = HashMap() + + class OpenAPSData { + var clockSuggested = 0L + var clockEnacted = 0L + var suggested: JSONObject? = null + var enacted: JSONObject? = null + } + + var openAPSData = OpenAPSData() +} + diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt index 5faa6861c1..8c7412dc44 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt @@ -10,6 +10,7 @@ import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.HtmlHelper.fromHtml +import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -80,12 +81,13 @@ class NSDeviceStatus @Inject constructor( private val nsSettingsStatus: NSSettingsStatus, private val config: Config, private val dateUtil: DateUtil, - private val runningConfiguration: RunningConfiguration + private val runningConfiguration: RunningConfiguration, + private val deviceStatusData: DeviceStatusData ) { private var data: JSONObject? = null fun handleNewData(deviceStatuses: JSONArray) { - aapsLogger.debug(LTag.NSCLIENT, "Got NS deviceStatus: \$deviceStatuses}") + aapsLogger.debug(LTag.NSCLIENT, "Got NS deviceStatus: \$deviceStatuses") try { for (i in 0 until deviceStatuses.length()) { val devicestatusJson = deviceStatuses.getJSONObject(i) @@ -145,16 +147,13 @@ class NSDeviceStatus @Inject constructor( } } - // ***** PUMP DATA ****** - private var deviceStatusPumpData: DeviceStatusPumpData? = null - val extendedPumpStatus: Spanned - get() = deviceStatusPumpData?.extended ?: fromHtml("") + get() = deviceStatusData.pumpData?.extended ?: fromHtml("") val pumpStatus: Spanned // test warning level // color get() { - val pumpData = deviceStatusPumpData ?: return fromHtml("") + val pumpData = deviceStatusData.pumpData ?: return fromHtml("") //String[] ALL_STATUS_FIELDS = {"reservoir", "battery", "clock", "status", "device"}; val string = StringBuilder() @@ -186,27 +185,16 @@ class NSDeviceStatus @Inject constructor( return fromHtml(string.toString()) } - internal class DeviceStatusPumpData { - - var clock = 0L - var isPercent = false - var percent = 0 - var voltage = 0.0 - var status = "N/A" - var reservoir = 0.0 - var extended: Spanned? = null - } - private fun updatePumpData() { try { val data = this.data ?: return val pump = if (data.has("pump")) data.getJSONObject("pump") else JSONObject() val clock = if (pump.has("clock")) dateUtil.fromISODateString(pump.getString("clock")) else 0L // check if this is new data - if (clock == 0L || deviceStatusPumpData != null && clock < deviceStatusPumpData!!.clock) return + if (clock == 0L || deviceStatusData.pumpData != null && clock < deviceStatusData.pumpData!!.clock) return // create new status and process data - val deviceStatusPumpData = DeviceStatusPumpData() + var deviceStatusPumpData = DeviceStatusData.PumpData() deviceStatusPumpData.clock = clock if (pump.has("status") && pump.getJSONObject("status").has("status")) deviceStatusPumpData.status = pump.getJSONObject("status").getString("status") if (pump.has("reservoir")) deviceStatusPumpData.reservoir = pump.getDouble("reservoir") @@ -227,21 +215,14 @@ class NSDeviceStatus @Inject constructor( extended.append("").append(key).append(": ").append(value).append("
") } deviceStatusPumpData.extended = fromHtml(extended.toString()) + deviceStatusPumpData.activeProfileName = JsonHelper.safeGetStringAllowNull(extendedJson, "ActiveProfile", null) } - this.deviceStatusPumpData = deviceStatusPumpData + deviceStatusData.pumpData = deviceStatusPumpData } catch (e: Exception) { aapsLogger.error("Unhandled exception", e) } } - class DeviceStatusOpenAPSData { - - var clockSuggested = 0L - var clockEnacted = 0L - var suggested: JSONObject? = null - var enacted: JSONObject? = null - } - private fun updateOpenApsData(jsonObject: JSONObject) { try { val openAps = if (jsonObject.has("openaps")) jsonObject.getJSONObject("openaps") else JSONObject() @@ -249,15 +230,15 @@ class NSDeviceStatus @Inject constructor( val enacted = if (openAps.has("enacted")) openAps.getJSONObject("enacted") else JSONObject() var clock = if (suggested.has("timestamp")) dateUtil.fromISODateString(suggested.getString("timestamp")) else 0L // check if this is new data - if (clock != 0L && clock > deviceStatusOpenAPSData.clockSuggested) { - deviceStatusOpenAPSData.suggested = suggested - deviceStatusOpenAPSData.clockSuggested = clock + if (clock != 0L && clock > deviceStatusData.openAPSData.clockSuggested) { + deviceStatusData.openAPSData.suggested = suggested + deviceStatusData.openAPSData.clockSuggested = clock } clock = if (enacted.has("timestamp")) dateUtil.fromISODateString(enacted.getString("timestamp")) else 0L // check if this is new data - if (clock != 0L && clock > deviceStatusOpenAPSData.clockEnacted) { - deviceStatusOpenAPSData.enacted = enacted - deviceStatusOpenAPSData.clockEnacted = clock + if (clock != 0L && clock > deviceStatusData.openAPSData.clockEnacted) { + deviceStatusData.openAPSData.enacted = enacted + deviceStatusData.openAPSData.clockEnacted = clock } } catch (e: Exception) { aapsLogger.error("Unhandled exception", e) @@ -273,12 +254,12 @@ class NSDeviceStatus @Inject constructor( // test warning level val level = when { - deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_urgent_staledatavalue, 31)).msecs() < dateUtil.now() -> Levels.URGENT - deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil.now() -> Levels.WARN + deviceStatusData.openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_urgent_staledatavalue, 31)).msecs() < dateUtil.now() -> Levels.URGENT + deviceStatusData.openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil.now() -> Levels.WARN else -> Levels.INFO } string.append("") - if (deviceStatusOpenAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ") + if (deviceStatusData.openAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(resourceHelper, deviceStatusData.openAPSData.clockSuggested)).append(" ") string.append("") // color return fromHtml(string.toString()) } @@ -287,8 +268,8 @@ class NSDeviceStatus @Inject constructor( get() { val string = StringBuilder() try { - if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append(" ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("
") - if (deviceStatusOpenAPSData.suggested != null) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("
") + if (deviceStatusData.openAPSData.enacted != null && deviceStatusData.openAPSData.clockEnacted != deviceStatusData.openAPSData.clockSuggested) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusData.openAPSData.clockEnacted)).append(" ").append(deviceStatusData.openAPSData.enacted!!.getString("reason")).append("
") + if (deviceStatusData.openAPSData.suggested != null) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusData.openAPSData.clockSuggested)).append(" ").append(deviceStatusData.openAPSData.suggested!!.getString("reason")).append("
") return fromHtml(string.toString()) } catch (e: JSONException) { aapsLogger.error("Unhandled exception", e) @@ -296,12 +277,6 @@ class NSDeviceStatus @Inject constructor( return fromHtml("") } - internal class Uploader { - - var clock = 0L - var battery = 0 - } - private fun updateUploaderData(jsonObject: JSONObject) { try { val clock = @@ -318,13 +293,13 @@ class NSDeviceStatus @Inject constructor( else -> 0 } - var uploader = uploaderMap[device] + var uploader = deviceStatusData.uploaderMap[device] // check if this is new data if (clock != 0L && battery != 0 && (uploader == null || clock > uploader.clock)) { - if (uploader == null) uploader = Uploader() + if (uploader == null) uploader = DeviceStatusData.Uploader() uploader.battery = battery uploader.clock = clock - uploaderMap[device] = uploader + deviceStatusData.uploaderMap[device] = uploader } } catch (e: Exception) { aapsLogger.error("Unhandled exception", e) @@ -333,11 +308,11 @@ class NSDeviceStatus @Inject constructor( val uploaderStatus: String get() { - val iterator: Iterator<*> = uploaderMap.entries.iterator() + val iterator: Iterator<*> = deviceStatusData.uploaderMap.entries.iterator() var minBattery = 100 while (iterator.hasNext()) { val pair = iterator.next() as Map.Entry<*, *> - val uploader = pair.value as Uploader + val uploader = pair.value as DeviceStatusData.Uploader if (minBattery > uploader.battery) minBattery = uploader.battery } return "$minBattery%" @@ -349,11 +324,11 @@ class NSDeviceStatus @Inject constructor( string.append("") string.append(resourceHelper.gs(R.string.uploader_short)) string.append(": ") - val iterator: Iterator<*> = uploaderMap.entries.iterator() + val iterator: Iterator<*> = deviceStatusData.uploaderMap.entries.iterator() var minBattery = 100 while (iterator.hasNext()) { val pair = iterator.next() as Map.Entry<*, *> - val uploader = pair.value as Uploader + val uploader = pair.value as DeviceStatusData.Uploader if (minBattery > uploader.battery) minBattery = uploader.battery } string.append(minBattery) @@ -364,33 +339,28 @@ class NSDeviceStatus @Inject constructor( val extendedUploaderStatus: Spanned get() { val string = StringBuilder() - val iterator: Iterator<*> = uploaderMap.entries.iterator() + val iterator: Iterator<*> = deviceStatusData.uploaderMap.entries.iterator() while (iterator.hasNext()) { val pair = iterator.next() as Map.Entry<*, *> - val uploader = pair.value as Uploader + val uploader = pair.value as DeviceStatusData.Uploader val device = pair.key as String string.append("").append(device).append(": ").append(uploader.battery).append("%
") } return fromHtml(string.toString()) } - // ********* OpenAPS data *********** - var deviceStatusOpenAPSData = DeviceStatusOpenAPSData() val openApsTimestamp: Long get() = - if (deviceStatusOpenAPSData.clockSuggested != 0L) { - deviceStatusOpenAPSData.clockSuggested + if (deviceStatusData.openAPSData.clockSuggested != 0L) { + deviceStatusData.openAPSData.clockSuggested } else { -1 } - // ********* Uploader data *********** - private val uploaderMap = HashMap() - fun getAPSResult(injector: HasAndroidInjector): APSResult { val result = APSResult(injector) - result.json = deviceStatusOpenAPSData.suggested - result.date = deviceStatusOpenAPSData.clockSuggested + result.json = deviceStatusData.openAPSData.suggested + result.date = deviceStatusData.openAPSData.clockSuggested return result } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index d22e13b982..af114e14de 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -636,18 +636,28 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList OverviewData.Property.PROFILE -> { val profileBackgroundColor = profileFunction.getProfile()?.let { - val profile = (it as ProfileSealed.EPS).value - if (profile.originalPercentage != 100 || profile.originalTimeshift != 0L || profile.originalDuration != 0L) - resourceHelper.gc(R.color.ribbonWarning) - else resourceHelper.gc(R.color.ribbonDefault) - } ?: resourceHelper.gc(R.color.ribbonTextDefault) + if (it is ProfileSealed.EPS) { + if (it.value.originalPercentage != 100 || it.value.originalTimeshift != 0L || it.value.originalDuration != 0L) + resourceHelper.gc(R.color.ribbonWarning) + else resourceHelper.gc(R.color.ribbonDefault) + } else if (it is ProfileSealed.PS) { + resourceHelper.gc(R.color.ribbonDefault) + } else { + resourceHelper.gc(R.color.ribbonDefault) + } + } ?: resourceHelper.gc(R.color.ribbonCritical) val profileTextColor = profileFunction.getProfile()?.let { - val profile = (it as ProfileSealed.EPS).value - if (profile.originalPercentage != 100 || profile.originalTimeshift != 0L || profile.originalDuration != 0L) - resourceHelper.gc(R.color.ribbonTextWarning) - else resourceHelper.gc(R.color.ribbonTextDefault) + if (it is ProfileSealed.EPS) { + if (it.value.originalPercentage != 100 || it.value.originalTimeshift != 0L || it.value.originalDuration != 0L) + resourceHelper.gc(R.color.ribbonTextWarning) + else resourceHelper.gc(R.color.ribbonTextDefault) + }else if (it is ProfileSealed.PS) { + resourceHelper.gc(R.color.ribbonTextDefault) + } else { + resourceHelper.gc(R.color.ribbonTextDefault) + } } ?: resourceHelper.gc(R.color.ribbonTextDefault) binding.activeProfile.text = profileFunction.getProfileNameWithRemainingTime()