migrate ProfileFunction

This commit is contained in:
Milos Kozak 2022-11-26 23:06:34 +01:00
parent 7f4c2bd87f
commit 6c86619a35
20 changed files with 536 additions and 475 deletions

View file

@ -58,7 +58,7 @@ import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.smsCommunicator.SmsCommunicator
import info.nightscout.interfaces.ui.IconsProvider
import info.nightscout.plugins.constraints.signatureVerifier.SignatureVerifierPlugin
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.events.EventAppExit
import info.nightscout.rx.events.EventInitializationChanged

View file

@ -53,7 +53,7 @@ import info.nightscout.plugins.source.IntelligoPlugin
import info.nightscout.plugins.source.PoctechPlugin
import info.nightscout.plugins.source.TomatoPlugin
import info.nightscout.plugins.sync.nsclient.NSClientPlugin
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.plugins.sync.tidepool.TidepoolPlugin
import info.nightscout.pump.combo.ComboPlugin

View file

@ -59,6 +59,7 @@ import javax.inject.Singleton
ImplementationModule.Bindings::class,
OpenHumansModule::class,
PluginsModule::class,
PluginsModule.Bindings::class,
RxModule::class,
SharedModule::class,
SharedImplModule::class,

View file

@ -10,7 +10,7 @@ import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.implementations.ActivityNamesImpl
import info.nightscout.androidaps.implementations.ConfigImpl
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImpl
import info.nightscout.implementation.profile.ProfileFunctionImpl
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
import info.nightscout.androidaps.workflow.CalculationWorkflowImpl
import info.nightscout.core.utils.fabric.FabricPrivacy
@ -38,7 +38,7 @@ import info.nightscout.plugins.general.autotune.AutotunePlugin
import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.plugins.sync.nsclient.DataSyncSelectorImplementation
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger

View file

@ -13,7 +13,7 @@ import info.nightscout.interfaces.maintenance.PrefFileListProvider
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP

View file

@ -78,8 +78,8 @@ import info.nightscout.plugins.general.overview.notifications.events.EventUpdate
import info.nightscout.plugins.skins.SkinProvider
import info.nightscout.plugins.source.DexcomPlugin
import info.nightscout.plugins.source.XdripPlugin
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.plugins.ui.StatusLightHandler
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus

View file

@ -16,7 +16,7 @@ import info.nightscout.interfaces.Config
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.profile.DefaultValueHelper
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.T

View file

@ -6,7 +6,7 @@ import info.nightscout.androidaps.TestBase
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.logging.LoggerUtils
import info.nightscout.interfaces.maintenance.PrefFileListProvider
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.junit.Assert

View file

@ -0,0 +1,13 @@
package info.nightscout.interfaces.nsclient
import android.content.Context
import org.json.JSONObject
interface NSSettingsStatus {
fun handleNewData(status: JSONObject)
fun getVersion(): String
fun extendedPumpSettings(setting: String?): Double
fun pumpExtendedSettingsFields(): String
fun copyStatusLightsNsSettings(context: Context?)
}

View file

@ -0,0 +1,75 @@
package info.nightscout.interfaces.nsclient
import android.text.Spanned
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.aps.APSResult
import org.json.JSONObject
interface ProcessedDeviceStatusData {
enum class Levels(val level: Int) {
URGENT(2),
WARN(1),
INFO(0);
fun toColor(): String =
when (level) {
INFO.level -> "white"
WARN.level -> "yellow"
URGENT.level -> "red"
else -> "white"
}
}
class PumpData {
var clock = 0L
var isPercent = false
var percent = 0
var voltage = 0.0
var status = "N/A"
var reservoir = 0.0
var reservoirDisplayOverride = ""
var extended: Spanned? = null
var activeProfileName: String? = null
}
var pumpData: PumpData?
data class Device(
val createdAt: Long,
val device: String?
)
var device: Device?
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
// test warning level // color
fun pumpStatus(nsSettingsStatus: NSSettingsStatus): Spanned
val extendedPumpStatus: Spanned
val extendedOpenApsStatus: Spanned
val openApsStatus: Spanned
val openApsTimestamp: Long
fun getAPSResult(injector: HasAndroidInjector): APSResult
val uploaderStatus: String
val uploaderStatusSpanned: Spanned
val extendedUploaderStatus: Spanned
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.configBuilder
package info.nightscout.implementation.profile
import info.nightscout.androidaps.extensions.fromConstant
import info.nightscout.core.main.R
@ -11,12 +11,12 @@ import info.nightscout.database.impl.transactions.InsertOrUpdateProfileSwitch
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.profile.ProfileStore
import info.nightscout.interfaces.utils.HardLimits
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventEffectiveProfileSwitchChanged
@ -206,4 +206,4 @@ class ProfileFunctionImpl @Inject constructor(
} else returnValue = false
return returnValue
}
}
}

View file

@ -1,6 +1,11 @@
package info.nightscout.plugins.di
import dagger.Binds
import dagger.Module
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatusImpl
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusDataImpl
@Module(
includes = [
@ -21,4 +26,12 @@ import dagger.Module
)
@Suppress("unused")
abstract class PluginsModule
abstract class PluginsModule {
@Module
interface Bindings {
@Binds fun bindProcessedDeviceStatusData(processedDeviceStatusDataImpl: ProcessedDeviceStatusDataImpl): ProcessedDeviceStatusData
@Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus
}
}

View file

@ -23,7 +23,7 @@ import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.receivers.Intents
import info.nightscout.plugins.R
import info.nightscout.plugins.aps.loop.events.EventLoopUpdateGui
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.Event

View file

@ -50,7 +50,7 @@ import info.nightscout.interfaces.utils.DecimalFormatter
import info.nightscout.interfaces.utils.HardLimits
import info.nightscout.interfaces.utils.TrendCalculator
import info.nightscout.plugins.R
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventMobileToWear

View file

@ -1,6 +1,7 @@
package info.nightscout.plugins.sync.nsclient.data
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.interfaces.utils.JsonHelper

View file

@ -1,252 +1,2 @@
package info.nightscout.plugins.sync.nsclient.data
import android.content.Context
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.core.events.EventNewNotification
import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.database.entities.UserEntry
import info.nightscout.database.entities.UserEntry.Action
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.profile.DefaultValueHelper
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.R
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
/*
{
"status": "ok",
"name": "Nightscout",
"version": "0.10.0-dev-20170423",
"versionNum": 1000,
"serverTime": "2017-06-12T07:46:56.006Z",
"apiEnabled": true,
"careportalEnabled": true,
"boluscalcEnabled": true,
"head": "96ee154",
"settings": {
"units": "mmol",
"timeFormat": 24,
"nightMode": false,
"editMode": true,
"showRawbg": "always",
"customTitle": "Bara's CGM",
"theme": "colors",
"alarmUrgentHigh": true,
"alarmUrgentHighMins": [30, 60, 90, 120],
"alarmHigh": true,
"alarmHighMins": [30, 60, 90, 120],
"alarmLow": true,
"alarmLowMins": [15, 30, 45, 60],
"alarmUrgentLow": true,
"alarmUrgentLowMins": [15, 30, 45],
"alarmUrgentMins": [30, 60, 90, 120],
"alarmWarnMins": [30, 60, 90, 120],
"alarmTimeagoWarn": true,
"alarmTimeagoWarnMins": 15,
"alarmTimeagoUrgent": true,
"alarmTimeagoUrgentMins": 30,
"language": "cs",
"scaleY": "linear",
"showPlugins": "careportal boluscalc food bwp cage sage iage iob cob basal ar2 delta direction upbat rawbg",
"showForecast": "ar2",
"focusHours": 3,
"heartbeat": 60,
"baseURL": "http:\/\/barascgm.sysop.cz:82",
"authDefaultRoles": "readable",
"thresholds": {
"bgHigh": 252,
"bgTargetTop": 180,
"bgTargetBottom": 72,
"bgLow": 71
},
"DEFAULT_FEATURES": ["bgnow", "delta", "direction", "timeago", "devicestatus", "upbat", "errorcodes", "profile"],
"alarmTypes": ["predict"],
"enable": ["careportal", "boluscalc", "food", "bwp", "cage", "sage", "iage", "iob", "cob", "basal", "ar2", "rawbg", "pushover", "bgi", "pump", "openaps", "pushover", "treatmentnotify", "bgnow", "delta", "direction", "timeago", "devicestatus", "upbat", "profile", "ar2"]
},
"extendedSettings": {
"pump": {
"fields": "reservoir battery clock",
"urgentBattP": 26,
"warnBattP": 51
},
"openaps": {
"enableAlerts": true
},
"cage": {
"alerts": true,
"display": "days",
"urgent": 96,
"warn": 72
},
"sage": {
"alerts": true,
"urgent": 336,
"warn": 168
},
"iage": {
"alerts": true,
"urgent": 150,
"warn": 120
},
"basal": {
"render": "default"
},
"profile": {
"history": true,
"multiple": true
},
"devicestatus": {
"advanced": true
}
},
"activeProfile": "2016 +30%"
}
*/
@OpenForTesting
@Singleton
class NSSettingsStatus @Inject constructor(
private val aapsLogger: AAPSLogger,
private val rh: ResourceHelper,
private val rxBus: RxBus,
private val defaultValueHelper: DefaultValueHelper,
private val sp: SP,
private val config: Config,
private val uel: UserEntryLogger
) {
// ***** PUMP STATUS ******
private var data: JSONObject? = null
/* Other received data to 2016/02/10
{
status: 'ok'
, name: env.name
, version: env.version
, versionNum: versionNum (for ver 1.2.3 contains 10203)
, serverTime: new Date().toISOString()
, apiEnabled: apiEnabled
, careportalEnabled: apiEnabled && env.settings.enable.indexOf('careportal') > -1
, boluscalcEnabled: apiEnabled && env.settings.enable.indexOf('boluscalc') > -1
, head: env.head
, settings: env.settings
, extendedSettings: ctx.plugins && ctx.plugins.extendedClientSettings ? ctx.plugins.extendedClientSettings(env.extendedSettings) : {}
, activeProfile ..... calculated from treatments or missing
}
*/
fun handleNewData(status: JSONObject) {
data = status
aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: ${getVersion()}")
if (getVersionNum() < config.SUPPORTEDNSVERSION) {
val notification = Notification(Notification.OLD_NS, rh.gs(R.string.unsupported_ns_version), Notification.NORMAL)
rxBus.send(EventNewNotification(notification))
} else {
rxBus.send(EventDismissNotification(Notification.OLD_NS))
}
data = status
aapsLogger.debug(LTag.NSCLIENT, "Received status: $status")
val targetHigh = getSettingsThreshold("bgTargetTop")
val targetlow = getSettingsThreshold("bgTargetBottom")
if (targetHigh != null) defaultValueHelper.bgTargetHigh = targetHigh
if (targetlow != null) defaultValueHelper.bgTargetLow = targetlow
if (config.NSCLIENT) copyStatusLightsNsSettings(null)
}
fun getVersion(): String =
JsonHelper.safeGetStringAllowNull(data, "version", null) ?: "UNKNOWN"
private fun getVersionNum(): Int =
JsonHelper.safeGetInt(data, "versionNum")
private fun getSettings() =
JsonHelper.safeGetJSONObject(data, "settings", null)
private fun getExtendedSettings(): JSONObject? =
JsonHelper.safeGetJSONObject(data, "extendedSettings", null)
// valid property is "warn" or "urgent"
// plugings "iage" "sage" "cage" "pbage"
private fun getExtendedWarnValue(plugin: String, property: String): Double? {
val extendedSettings = getExtendedSettings() ?: return null
val pluginJson = extendedSettings.optJSONObject(plugin) ?: return null
return try {
pluginJson.getDouble(property)
} catch (e: Exception) {
null
}
}
// "bgHigh": 252,
// "bgTargetTop": 180,
// "bgTargetBottom": 72,
// "bgLow": 71
private fun getSettingsThreshold(what: String): Double? {
val threshold = JsonHelper.safeGetJSONObject(getSettings(), "thresholds", null)
return JsonHelper.safeGetDoubleAllowNull(threshold, what)
}
/*
, warnClock: sbx.extendedSettings.warnClock || 30
, urgentClock: sbx.extendedSettings.urgentClock || 60
, warnRes: sbx.extendedSettings.warnRes || 10
, urgentRes: sbx.extendedSettings.urgentRes || 5
, warnBattV: sbx.extendedSettings.warnBattV || 1.35
, urgentBattV: sbx.extendedSettings.urgentBattV || 1.3
, warnBattP: sbx.extendedSettings.warnBattP || 30
, urgentBattP: sbx.extendedSettings.urgentBattP || 20
, enableAlerts: sbx.extendedSettings.enableAlerts || false
*/
fun extendedPumpSettings(setting: String?): Double {
try {
val pump = extendedPumpSettings()
return when (setting) {
"warnClock" -> JsonHelper.safeGetDouble(pump, setting, 30.0)
"urgentClock" -> JsonHelper.safeGetDouble(pump, setting, 60.0)
"warnRes" -> JsonHelper.safeGetDouble(pump, setting, 10.0)
"urgentRes" -> JsonHelper.safeGetDouble(pump, setting, 5.0)
"warnBattV" -> JsonHelper.safeGetDouble(pump, setting, 1.35)
"urgentBattV" -> JsonHelper.safeGetDouble(pump, setting, 1.3)
"warnBattP" -> JsonHelper.safeGetDouble(pump, setting, 30.0)
"urgentBattP" -> JsonHelper.safeGetDouble(pump, setting, 20.0)
else -> 0.0
}
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
return 0.0
}
private fun extendedPumpSettings(): JSONObject? =
JsonHelper.safeGetJSONObject(getExtendedSettings(), "pump", null)
fun pumpExtendedSettingsFields(): String =
JsonHelper.safeGetString(extendedPumpSettings(), "fields", "")
fun copyStatusLightsNsSettings(context: Context?) {
val action = Runnable {
getExtendedWarnValue("cage", "warn")?.let { sp.putDouble(R.string.key_statuslights_cage_warning, it) }
getExtendedWarnValue("cage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_cage_critical, it) }
getExtendedWarnValue("iage", "warn")?.let { sp.putDouble(R.string.key_statuslights_iage_warning, it) }
getExtendedWarnValue("iage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_iage_critical, it) }
getExtendedWarnValue("sage", "warn")?.let { sp.putDouble(R.string.key_statuslights_sage_warning, it) }
getExtendedWarnValue("sage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_sage_critical, it) }
getExtendedWarnValue("bage", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) }
getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, it) }
uel.log(Action.NS_SETTINGS_COPIED, UserEntry.Sources.NSClient)
}
if (context != null) OKDialog.showConfirmation(context, rh.gs(R.string.statuslights), rh.gs(R.string.copy_existing_values), action)
else action.run()
}
}

View file

@ -0,0 +1,253 @@
package info.nightscout.plugins.sync.nsclient.data
import android.content.Context
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.core.events.EventNewNotification
import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.database.entities.UserEntry
import info.nightscout.database.entities.UserEntry.Action
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.profile.DefaultValueHelper
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.R
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
/*
{
"status": "ok",
"name": "Nightscout",
"version": "0.10.0-dev-20170423",
"versionNum": 1000,
"serverTime": "2017-06-12T07:46:56.006Z",
"apiEnabled": true,
"careportalEnabled": true,
"boluscalcEnabled": true,
"head": "96ee154",
"settings": {
"units": "mmol",
"timeFormat": 24,
"nightMode": false,
"editMode": true,
"showRawbg": "always",
"customTitle": "Bara's CGM",
"theme": "colors",
"alarmUrgentHigh": true,
"alarmUrgentHighMins": [30, 60, 90, 120],
"alarmHigh": true,
"alarmHighMins": [30, 60, 90, 120],
"alarmLow": true,
"alarmLowMins": [15, 30, 45, 60],
"alarmUrgentLow": true,
"alarmUrgentLowMins": [15, 30, 45],
"alarmUrgentMins": [30, 60, 90, 120],
"alarmWarnMins": [30, 60, 90, 120],
"alarmTimeagoWarn": true,
"alarmTimeagoWarnMins": 15,
"alarmTimeagoUrgent": true,
"alarmTimeagoUrgentMins": 30,
"language": "cs",
"scaleY": "linear",
"showPlugins": "careportal boluscalc food bwp cage sage iage iob cob basal ar2 delta direction upbat rawbg",
"showForecast": "ar2",
"focusHours": 3,
"heartbeat": 60,
"baseURL": "http:\/\/barascgm.sysop.cz:82",
"authDefaultRoles": "readable",
"thresholds": {
"bgHigh": 252,
"bgTargetTop": 180,
"bgTargetBottom": 72,
"bgLow": 71
},
"DEFAULT_FEATURES": ["bgnow", "delta", "direction", "timeago", "devicestatus", "upbat", "errorcodes", "profile"],
"alarmTypes": ["predict"],
"enable": ["careportal", "boluscalc", "food", "bwp", "cage", "sage", "iage", "iob", "cob", "basal", "ar2", "rawbg", "pushover", "bgi", "pump", "openaps", "pushover", "treatmentnotify", "bgnow", "delta", "direction", "timeago", "devicestatus", "upbat", "profile", "ar2"]
},
"extendedSettings": {
"pump": {
"fields": "reservoir battery clock",
"urgentBattP": 26,
"warnBattP": 51
},
"openaps": {
"enableAlerts": true
},
"cage": {
"alerts": true,
"display": "days",
"urgent": 96,
"warn": 72
},
"sage": {
"alerts": true,
"urgent": 336,
"warn": 168
},
"iage": {
"alerts": true,
"urgent": 150,
"warn": 120
},
"basal": {
"render": "default"
},
"profile": {
"history": true,
"multiple": true
},
"devicestatus": {
"advanced": true
}
},
"activeProfile": "2016 +30%"
}
*/
@OpenForTesting
@Singleton
class NSSettingsStatusImpl @Inject constructor(
private val aapsLogger: AAPSLogger,
private val rh: ResourceHelper,
private val rxBus: RxBus,
private val defaultValueHelper: DefaultValueHelper,
private val sp: SP,
private val config: Config,
private val uel: UserEntryLogger
) : NSSettingsStatus {
// ***** PUMP STATUS ******
private var data: JSONObject? = null
/* Other received data to 2016/02/10
{
status: 'ok'
, name: env.name
, version: env.version
, versionNum: versionNum (for ver 1.2.3 contains 10203)
, serverTime: new Date().toISOString()
, apiEnabled: apiEnabled
, careportalEnabled: apiEnabled && env.settings.enable.indexOf('careportal') > -1
, boluscalcEnabled: apiEnabled && env.settings.enable.indexOf('boluscalc') > -1
, head: env.head
, settings: env.settings
, extendedSettings: ctx.plugins && ctx.plugins.extendedClientSettings ? ctx.plugins.extendedClientSettings(env.extendedSettings) : {}
, activeProfile ..... calculated from treatments or missing
}
*/
override fun handleNewData(status: JSONObject) {
data = status
aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: ${getVersion()}")
if (getVersionNum() < config.SUPPORTEDNSVERSION) {
val notification = Notification(Notification.OLD_NS, rh.gs(R.string.unsupported_ns_version), Notification.NORMAL)
rxBus.send(EventNewNotification(notification))
} else {
rxBus.send(EventDismissNotification(Notification.OLD_NS))
}
data = status
aapsLogger.debug(LTag.NSCLIENT, "Received status: $status")
val targetHigh = getSettingsThreshold("bgTargetTop")
val targetlow = getSettingsThreshold("bgTargetBottom")
if (targetHigh != null) defaultValueHelper.bgTargetHigh = targetHigh
if (targetlow != null) defaultValueHelper.bgTargetLow = targetlow
if (config.NSCLIENT) copyStatusLightsNsSettings(null)
}
override fun getVersion(): String =
JsonHelper.safeGetStringAllowNull(data, "version", null) ?: "UNKNOWN"
private fun getVersionNum(): Int =
JsonHelper.safeGetInt(data, "versionNum")
private fun getSettings() =
JsonHelper.safeGetJSONObject(data, "settings", null)
private fun getExtendedSettings(): JSONObject? =
JsonHelper.safeGetJSONObject(data, "extendedSettings", null)
// valid property is "warn" or "urgent"
// plugings "iage" "sage" "cage" "pbage"
private fun getExtendedWarnValue(plugin: String, property: String): Double? {
val extendedSettings = getExtendedSettings() ?: return null
val pluginJson = extendedSettings.optJSONObject(plugin) ?: return null
return try {
pluginJson.getDouble(property)
} catch (e: Exception) {
null
}
}
// "bgHigh": 252,
// "bgTargetTop": 180,
// "bgTargetBottom": 72,
// "bgLow": 71
private fun getSettingsThreshold(what: String): Double? {
val threshold = JsonHelper.safeGetJSONObject(getSettings(), "thresholds", null)
return JsonHelper.safeGetDoubleAllowNull(threshold, what)
}
/*
, warnClock: sbx.extendedSettings.warnClock || 30
, urgentClock: sbx.extendedSettings.urgentClock || 60
, warnRes: sbx.extendedSettings.warnRes || 10
, urgentRes: sbx.extendedSettings.urgentRes || 5
, warnBattV: sbx.extendedSettings.warnBattV || 1.35
, urgentBattV: sbx.extendedSettings.urgentBattV || 1.3
, warnBattP: sbx.extendedSettings.warnBattP || 30
, urgentBattP: sbx.extendedSettings.urgentBattP || 20
, enableAlerts: sbx.extendedSettings.enableAlerts || false
*/
override fun extendedPumpSettings(setting: String?): Double {
try {
val pump = extendedPumpSettings()
return when (setting) {
"warnClock" -> JsonHelper.safeGetDouble(pump, setting, 30.0)
"urgentClock" -> JsonHelper.safeGetDouble(pump, setting, 60.0)
"warnRes" -> JsonHelper.safeGetDouble(pump, setting, 10.0)
"urgentRes" -> JsonHelper.safeGetDouble(pump, setting, 5.0)
"warnBattV" -> JsonHelper.safeGetDouble(pump, setting, 1.35)
"urgentBattV" -> JsonHelper.safeGetDouble(pump, setting, 1.3)
"warnBattP" -> JsonHelper.safeGetDouble(pump, setting, 30.0)
"urgentBattP" -> JsonHelper.safeGetDouble(pump, setting, 20.0)
else -> 0.0
}
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
return 0.0
}
private fun extendedPumpSettings(): JSONObject? =
JsonHelper.safeGetJSONObject(getExtendedSettings(), "pump", null)
override fun pumpExtendedSettingsFields(): String =
JsonHelper.safeGetString(extendedPumpSettings(), "fields", "")
override fun copyStatusLightsNsSettings(context: Context?) {
val action = Runnable {
getExtendedWarnValue("cage", "warn")?.let { sp.putDouble(R.string.key_statuslights_cage_warning, it) }
getExtendedWarnValue("cage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_cage_critical, it) }
getExtendedWarnValue("iage", "warn")?.let { sp.putDouble(R.string.key_statuslights_iage_warning, it) }
getExtendedWarnValue("iage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_iage_critical, it) }
getExtendedWarnValue("sage", "warn")?.let { sp.putDouble(R.string.key_statuslights_sage_warning, it) }
getExtendedWarnValue("sage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_sage_critical, it) }
getExtendedWarnValue("bage", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) }
getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, it) }
uel.log(Action.NS_SETTINGS_COPIED, UserEntry.Sources.NSClient)
}
if (context != null) OKDialog.showConfirmation(context, rh.gs(R.string.statuslights), rh.gs(R.string.copy_existing_values), action)
else action.run()
}
}

View file

@ -1,211 +1,2 @@
package info.nightscout.plugins.sync.nsclient.data
import android.text.Spanned
import dagger.android.HasAndroidInjector
import info.nightscout.core.aps.APSResultObject
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.interfaces.utils.Round
import info.nightscout.plugins.R
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@Suppress("SpellCheckingInspection")
@Singleton
class ProcessedDeviceStatusData @Inject constructor(
private val rh: ResourceHelper,
private val dateUtil: DateUtil,
private val sp: SP
) {
enum class Levels(val level: Int) {
URGENT(2),
WARN(1),
INFO(0);
fun toColor(): String =
when (level) {
INFO.level -> "white"
WARN.level -> "yellow"
URGENT.level -> "red"
else -> "white"
}
}
class PumpData {
var clock = 0L
var isPercent = false
var percent = 0
var voltage = 0.0
var status = "N/A"
var reservoir = 0.0
var reservoirDisplayOverride = ""
var extended: Spanned? = null
var activeProfileName: String? = null
}
var pumpData: PumpData? = null
data class Device(
val createdAt: Long,
val device: String?
)
var device: Device? = 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()
// test warning level // color
fun pumpStatus(nsSettingsStatus: NSSettingsStatus): Spanned {
val pumpData = pumpData ?: return HtmlHelper.fromHtml("")
//String[] ALL_STATUS_FIELDS = {"reservoir", "battery", "clock", "status", "device"};
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.pump))
.append(": </span>")
// test warning level
val level = when {
pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil.now() -> Levels.URGENT
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> Levels.URGENT
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT
pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil.now() -> Levels.WARN
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> Levels.WARN
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> Levels.WARN
else -> Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
val insulinUnit = rh.gs(R.string.insulin_unit_shortname)
val fields = nsSettingsStatus.pumpExtendedSettingsFields()
if (pumpData.reservoirDisplayOverride != "")
string.append(pumpData.reservoirDisplayOverride).append("$insulinUnit ")
else if (fields.contains("reservoir")) string.append(pumpData.reservoir.toInt()).append("$insulinUnit ")
if (fields.contains("battery") && pumpData.isPercent) string.append(pumpData.percent).append("% ")
if (fields.contains("battery") && !pumpData.isPercent) string.append(Round.roundTo(pumpData.voltage, 0.001)).append(" ")
if (fields.contains("clock")) string.append(dateUtil.minAgo(rh, pumpData.clock)).append(" ")
if (fields.contains("status")) string.append(pumpData.status).append(" ")
if (fields.contains("device")) string.append(device).append(" ")
string.append("</span>") // color
return HtmlHelper.fromHtml(string.toString())
}
val extendedPumpStatus: Spanned get() = pumpData?.extended ?: HtmlHelper.fromHtml("")
val extendedOpenApsStatus: Spanned
get() {
val string = StringBuilder()
val enacted = openAPSData.enacted
val suggested = openAPSData.suggested
if (enacted != null && openAPSData.clockEnacted != openAPSData.clockSuggested) string
.append("<b>")
.append(dateUtil.minAgo(rh, openAPSData.clockEnacted))
.append("</b> ")
.append(JsonHelper.safeGetString(enacted, "reason"))
.append("<br>")
if (suggested != null) string
.append("<b>")
.append(dateUtil.minAgo(rh, openAPSData.clockSuggested))
.append("</b> ")
.append(JsonHelper.safeGetString(suggested, "reason"))
.append("<br>")
return HtmlHelper.fromHtml(string.toString())
}
val openApsStatus: Spanned
get() {
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.openaps_short))
.append(": </span>")
// test warning level
val level = when {
openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_ns_alarm_urgent_stale_data_value, 31)).msecs() < dateUtil.now() -> Levels.URGENT
openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_ns_alarm_stale_data_value, 16)).msecs() < dateUtil.now() -> Levels.WARN
else -> Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
if (openAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(rh, openAPSData.clockSuggested)).append(" ")
string.append("</span>") // color
return HtmlHelper.fromHtml(string.toString())
}
val openApsTimestamp: Long
get() = if (openAPSData.clockSuggested != 0L) openAPSData.clockSuggested else -1
fun getAPSResult(injector: HasAndroidInjector): APSResultObject {
val result = APSResultObject(injector)
result.json = openAPSData.suggested
result.date = openAPSData.clockSuggested
return result
}
val uploaderStatus: String
get() {
val iterator: Iterator<*> = uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
return "$minBattery%"
}
val uploaderStatusSpanned: Spanned
get() {
val string = StringBuilder()
string.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
string.append(rh.gs(R.string.uploader_short))
string.append(": </span>")
val iterator: Iterator<*> = uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
string.append(minBattery)
string.append("%")
return HtmlHelper.fromHtml(string.toString())
}
val extendedUploaderStatus: Spanned
get() {
val string = StringBuilder()
val iterator: Iterator<*> = uploaderMap.entries.iterator()
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as Uploader
val device = pair.key as String
string.append("<b>").append(device).append(":</b> ").append(uploader.battery).append("%<br>")
}
return HtmlHelper.fromHtml(string.toString())
}
}

View file

@ -0,0 +1,164 @@
package info.nightscout.plugins.sync.nsclient.data
import android.text.Spanned
import dagger.android.HasAndroidInjector
import info.nightscout.core.aps.APSResultObject
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.interfaces.utils.Round
import info.nightscout.plugins.R
import info.nightscout.shared.interfaces.ResourceHelper
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
@Suppress("SpellCheckingInspection")
@Singleton
class ProcessedDeviceStatusDataImpl @Inject constructor(
private val rh: ResourceHelper,
private val dateUtil: DateUtil,
private val sp: SP
) : ProcessedDeviceStatusData {
override var pumpData: ProcessedDeviceStatusData.PumpData? = null
override var device: ProcessedDeviceStatusData.Device? = null
override val uploaderMap = HashMap<String, ProcessedDeviceStatusData.Uploader>()
override var openAPSData = ProcessedDeviceStatusData.OpenAPSData()
// test warning level // color
override fun pumpStatus(nsSettingsStatus: NSSettingsStatus): Spanned {
val pumpData = pumpData ?: return HtmlHelper.fromHtml("")
//String[] ALL_STATUS_FIELDS = {"reservoir", "battery", "clock", "status", "device"};
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.pump))
.append(": </span>")
// test warning level
val level = when {
pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil.now() -> ProcessedDeviceStatusData.Levels.URGENT
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> ProcessedDeviceStatusData.Levels.URGENT
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> ProcessedDeviceStatusData.Levels.URGENT
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> ProcessedDeviceStatusData.Levels.URGENT
pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil.now() -> ProcessedDeviceStatusData.Levels.WARN
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> ProcessedDeviceStatusData.Levels.WARN
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> ProcessedDeviceStatusData.Levels.WARN
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> ProcessedDeviceStatusData.Levels.WARN
else -> ProcessedDeviceStatusData.Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
val insulinUnit = rh.gs(R.string.insulin_unit_shortname)
val fields = nsSettingsStatus.pumpExtendedSettingsFields()
if (pumpData.reservoirDisplayOverride != "")
string.append(pumpData.reservoirDisplayOverride).append("$insulinUnit ")
else if (fields.contains("reservoir")) string.append(pumpData.reservoir.toInt()).append("$insulinUnit ")
if (fields.contains("battery") && pumpData.isPercent) string.append(pumpData.percent).append("% ")
if (fields.contains("battery") && !pumpData.isPercent) string.append(Round.roundTo(pumpData.voltage, 0.001)).append(" ")
if (fields.contains("clock")) string.append(dateUtil.minAgo(rh, pumpData.clock)).append(" ")
if (fields.contains("status")) string.append(pumpData.status).append(" ")
if (fields.contains("device")) string.append(device).append(" ")
string.append("</span>") // color
return HtmlHelper.fromHtml(string.toString())
}
override val extendedPumpStatus: Spanned get() = pumpData?.extended ?: HtmlHelper.fromHtml("")
override val extendedOpenApsStatus: Spanned
get() {
val string = StringBuilder()
val enacted = openAPSData.enacted
val suggested = openAPSData.suggested
if (enacted != null && openAPSData.clockEnacted != openAPSData.clockSuggested) string
.append("<b>")
.append(dateUtil.minAgo(rh, openAPSData.clockEnacted))
.append("</b> ")
.append(JsonHelper.safeGetString(enacted, "reason"))
.append("<br>")
if (suggested != null) string
.append("<b>")
.append(dateUtil.minAgo(rh, openAPSData.clockSuggested))
.append("</b> ")
.append(JsonHelper.safeGetString(suggested, "reason"))
.append("<br>")
return HtmlHelper.fromHtml(string.toString())
}
override val openApsStatus: Spanned
get() {
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.openaps_short))
.append(": </span>")
// test warning level
val level = when {
openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_ns_alarm_urgent_stale_data_value, 31)).msecs() < dateUtil.now() -> ProcessedDeviceStatusData.Levels.URGENT
openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_ns_alarm_stale_data_value, 16)).msecs() < dateUtil.now() -> ProcessedDeviceStatusData.Levels.WARN
else -> ProcessedDeviceStatusData.Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
if (openAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(rh, openAPSData.clockSuggested)).append(" ")
string.append("</span>") // color
return HtmlHelper.fromHtml(string.toString())
}
override val openApsTimestamp: Long
get() = if (openAPSData.clockSuggested != 0L) openAPSData.clockSuggested else -1
override fun getAPSResult(injector: HasAndroidInjector): APSResultObject {
val result = APSResultObject(injector)
result.json = openAPSData.suggested
result.date = openAPSData.clockSuggested
return result
}
override val uploaderStatus: String
get() {
val iterator: Iterator<*> = uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as ProcessedDeviceStatusData.Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
return "$minBattery%"
}
override val uploaderStatusSpanned: Spanned
get() {
val string = StringBuilder()
string.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
string.append(rh.gs(R.string.uploader_short))
string.append(": </span>")
val iterator: Iterator<*> = uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as ProcessedDeviceStatusData.Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
string.append(minBattery)
string.append("%")
return HtmlHelper.fromHtml(string.toString())
}
override val extendedUploaderStatus: Spanned
get() {
val string = StringBuilder()
val iterator: Iterator<*> = uploaderMap.entries.iterator()
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as ProcessedDeviceStatusData.Uploader
val device = pair.key as String
string.append("<b>").append(device).append(":</b> ").append(uploader.battery).append("%<br>")
}
return HtmlHelper.fromHtml(string.toString())
}
}

View file

@ -42,7 +42,7 @@ import info.nightscout.plugins.sync.nsclient.acks.NSUpdateAck
import info.nightscout.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.plugins.sync.nsclient.data.NSAlarm
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddAckWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker