NSClient: missing initial profile workaround

This commit is contained in:
Milos Kozak 2021-10-25 14:32:21 +02:00
parent 60c14cda21
commit 3d94f3f840
6 changed files with 120 additions and 77 deletions

View file

@ -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

View file

@ -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<Profile>()
@ -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
}

View file

@ -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())

View file

@ -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<String, Uploader>()
class OpenAPSData {
var clockSuggested = 0L
var clockEnacted = 0L
var suggested: JSONObject? = null
var enacted: JSONObject? = null
}
var openAPSData = OpenAPSData()
}

View file

@ -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("<b>").append(key).append(":</b> ").append(value).append("<br>")
}
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("<span style=\"color:${level.toColor()}\">")
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("</span>") // 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("<b>").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append("</b> ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("<br>")
if (deviceStatusOpenAPSData.suggested != null) string.append("<b>").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append("</b> ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("<br>")
if (deviceStatusData.openAPSData.enacted != null && deviceStatusData.openAPSData.clockEnacted != deviceStatusData.openAPSData.clockSuggested) string.append("<b>").append(dateUtil.minAgo(resourceHelper, deviceStatusData.openAPSData.clockEnacted)).append("</b> ").append(deviceStatusData.openAPSData.enacted!!.getString("reason")).append("<br>")
if (deviceStatusData.openAPSData.suggested != null) string.append("<b>").append(dateUtil.minAgo(resourceHelper, deviceStatusData.openAPSData.clockSuggested)).append("</b> ").append(deviceStatusData.openAPSData.suggested!!.getString("reason")).append("<br>")
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("<span style=\"color:${resourceHelper.gcs(R.color.defaulttext)}\">")
string.append(resourceHelper.gs(R.string.uploader_short))
string.append(": </span>")
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("<b>").append(device).append(":</b> ").append(uploader.battery).append("%<br>")
}
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<String, Uploader>()
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
}
}

View file

@ -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()