Merge branch 'dev' of https://github.com/miyeongkim/AndroidAPS into dev
This commit is contained in:
commit
2c89d8f240
47 changed files with 2637 additions and 256 deletions
|
@ -48,6 +48,7 @@ import info.nightscout.androidaps.plugins.source.EversensePlugin
|
||||||
import info.nightscout.androidaps.plugins.source.GlimpPlugin
|
import info.nightscout.androidaps.plugins.source.GlimpPlugin
|
||||||
import info.nightscout.androidaps.plugins.source.PoctechPlugin
|
import info.nightscout.androidaps.plugins.source.PoctechPlugin
|
||||||
import info.nightscout.androidaps.plugins.source.TomatoPlugin
|
import info.nightscout.androidaps.plugins.source.TomatoPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.source.GlunovoPlugin
|
||||||
import info.nightscout.androidaps.utils.SafeParse
|
import info.nightscout.androidaps.utils.SafeParse
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
|
||||||
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||||
|
@ -90,6 +91,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
@Inject lateinit var glimpPlugin: GlimpPlugin
|
@Inject lateinit var glimpPlugin: GlimpPlugin
|
||||||
@Inject lateinit var poctechPlugin: PoctechPlugin
|
@Inject lateinit var poctechPlugin: PoctechPlugin
|
||||||
@Inject lateinit var tomatoPlugin: TomatoPlugin
|
@Inject lateinit var tomatoPlugin: TomatoPlugin
|
||||||
|
@Inject lateinit var glunovoPlugin: GlunovoPlugin
|
||||||
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
|
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
|
||||||
@Inject lateinit var statusLinePlugin: StatusLinePlugin
|
@Inject lateinit var statusLinePlugin: StatusLinePlugin
|
||||||
@Inject lateinit var tidepoolPlugin: TidepoolPlugin
|
@Inject lateinit var tidepoolPlugin: TidepoolPlugin
|
||||||
|
@ -160,6 +162,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
addPreferencesFromResourceIfEnabled(eversensePlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(eversensePlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(dexcomPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(dexcomPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(tomatoPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(tomatoPlugin, rootKey)
|
||||||
|
addPreferencesFromResourceIfEnabled(glunovoPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(poctechPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(poctechPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(glimpPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(glimpPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(loopPlugin, rootKey, config.APS)
|
addPreferencesFromResourceIfEnabled(loopPlugin, rootKey, config.APS)
|
||||||
|
|
|
@ -353,6 +353,12 @@ abstract class PluginsModule {
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@IntKey(470)
|
@IntKey(470)
|
||||||
|
abstract fun bindGlunovoPlugin(plugin: GlunovoPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(475)
|
||||||
abstract fun bindRandomBgPlugin(plugin: RandomBgPlugin): PluginBase
|
abstract fun bindRandomBgPlugin(plugin: RandomBgPlugin): PluginBase
|
||||||
|
|
||||||
// @Binds
|
// @Binds
|
||||||
|
|
|
@ -28,20 +28,22 @@ class StorageConstraintPlugin @Inject constructor(
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
rh: ResourceHelper,
|
rh: ResourceHelper,
|
||||||
private val rxBus: RxBus
|
private val rxBus: RxBus
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(
|
||||||
.mainType(PluginType.CONSTRAINTS)
|
PluginDescription()
|
||||||
.neverVisible(true)
|
.mainType(PluginType.CONSTRAINTS)
|
||||||
.alwaysEnabled(true)
|
.neverVisible(true)
|
||||||
.showInList(false)
|
.alwaysEnabled(true)
|
||||||
.pluginName(R.string.storage),
|
.showInList(false)
|
||||||
|
.pluginName(R.string.storage),
|
||||||
aapsLogger, rh, injector
|
aapsLogger, rh, injector
|
||||||
), Constraints {
|
), Constraints {
|
||||||
|
|
||||||
|
@Suppress("ReplaceGetOrSet")
|
||||||
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
val diskFree = availableInternalMemorySize()
|
val diskFree = availableInternalMemorySize()
|
||||||
aapsLogger.debug(LTag.CONSTRAINTS, "Internal storage free (Mb):$diskFree")
|
|
||||||
if (diskFree < Constants.MINIMUM_FREE_SPACE) {
|
if (diskFree < Constants.MINIMUM_FREE_SPACE) {
|
||||||
value[aapsLogger, false, rh.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE)] = this
|
aapsLogger.debug(LTag.CONSTRAINTS, "Internal storage free (Mb):$diskFree")
|
||||||
|
value.set(aapsLogger, false, rh.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE), this)
|
||||||
val notification = Notification(Notification.DISK_FULL, rh.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE), Notification.NORMAL)
|
val notification = Notification(Notification.DISK_FULL, rh.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE), Notification.NORMAL)
|
||||||
rxBus.send(EventNewNotification(notification))
|
rxBus.send(EventNewNotification(notification))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.general.nsclient.services
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.ResolveInfo
|
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
import com.google.common.base.Charsets
|
import com.google.common.base.Charsets
|
||||||
|
@ -17,7 +16,6 @@ import info.nightscout.androidaps.events.EventConfigBuilderChange
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
@ -41,12 +39,12 @@ import info.nightscout.androidaps.plugins.general.overview.notifications.Notific
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||||
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin.NSClientSourceWorker
|
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin.NSClientSourceWorker
|
||||||
import info.nightscout.androidaps.receivers.DataWorker
|
import info.nightscout.androidaps.receivers.DataWorker
|
||||||
import info.nightscout.androidaps.services.Intents
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
|
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
|
||||||
import info.nightscout.androidaps.utils.JsonHelper.safeGetStringAllowNull
|
import info.nightscout.androidaps.utils.JsonHelper.safeGetStringAllowNull
|
||||||
import info.nightscout.androidaps.utils.T.Companion.mins
|
import info.nightscout.androidaps.utils.T.Companion.mins
|
||||||
|
import info.nightscout.androidaps.utils.XDripBroadcast
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
@ -80,6 +78,7 @@ class NSClientService : DaggerService() {
|
||||||
@Inject lateinit var dataWorker: DataWorker
|
@Inject lateinit var dataWorker: DataWorker
|
||||||
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@Inject lateinit var xDripBroadcast: XDripBroadcast
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
@ -476,15 +475,7 @@ class NSClientService : DaggerService() {
|
||||||
OneTimeWorkRequest.Builder(LocalProfilePlugin.NSProfileWorker::class.java)
|
OneTimeWorkRequest.Builder(LocalProfilePlugin.NSProfileWorker::class.java)
|
||||||
.setInputData(dataWorker.storeInputData(profileStoreJson, null))
|
.setInputData(dataWorker.storeInputData(profileStoreJson, null))
|
||||||
.build())
|
.build())
|
||||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
xDripBroadcast.sendProfile(profileStoreJson)
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString("profile", profileStoreJson.toString())
|
|
||||||
bundle.putBoolean("delta", isDelta)
|
|
||||||
val intent = Intent(Intents.ACTION_NEW_PROFILE)
|
|
||||||
intent.putExtras(bundle)
|
|
||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
|
||||||
broadcast(intent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.has("treatments")) {
|
if (data.has("treatments")) {
|
||||||
|
@ -502,18 +493,7 @@ class NSClientService : DaggerService() {
|
||||||
OneTimeWorkRequest.Builder(NSClientAddUpdateWorker::class.java)
|
OneTimeWorkRequest.Builder(NSClientAddUpdateWorker::class.java)
|
||||||
.setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments, null))
|
.setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments, null))
|
||||||
.build())
|
.build())
|
||||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
xDripBroadcast.sendTreatments(addedOrUpdatedTreatments)
|
||||||
val splitted = splitArray(addedOrUpdatedTreatments)
|
|
||||||
for (part in splitted) {
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString("treatments", part.toString())
|
|
||||||
bundle.putBoolean("delta", isDelta)
|
|
||||||
val intent = Intent(Intents.ACTION_CHANGED_TREATMENT)
|
|
||||||
intent.putExtras(bundle)
|
|
||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
|
||||||
broadcast(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.has("devicestatus")) {
|
if (data.has("devicestatus")) {
|
||||||
|
@ -550,18 +530,7 @@ class NSClientService : DaggerService() {
|
||||||
dataWorker.enqueue(OneTimeWorkRequest.Builder(NSClientSourceWorker::class.java)
|
dataWorker.enqueue(OneTimeWorkRequest.Builder(NSClientSourceWorker::class.java)
|
||||||
.setInputData(dataWorker.storeInputData(sgvs, null))
|
.setInputData(dataWorker.storeInputData(sgvs, null))
|
||||||
.build())
|
.build())
|
||||||
val splitted = splitArray(sgvs)
|
xDripBroadcast.sendSgvs(sgvs)
|
||||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
|
||||||
for (part in splitted) {
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString("sgvs", part.toString())
|
|
||||||
bundle.putBoolean("delta", isDelta)
|
|
||||||
val intent = Intent(Intents.ACTION_NEW_SGV)
|
|
||||||
intent.putExtras(bundle)
|
|
||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
|
||||||
broadcast(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rxBus.send(EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
|
rxBus.send(EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
|
@ -675,40 +644,6 @@ class NSClientService : DaggerService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun splitArray(array: JSONArray): List<JSONArray> {
|
|
||||||
var ret: MutableList<JSONArray> = ArrayList()
|
|
||||||
try {
|
|
||||||
val size = array.length()
|
|
||||||
var count = 0
|
|
||||||
var newarr: JSONArray? = null
|
|
||||||
for (i in 0 until size) {
|
|
||||||
if (count == 0) {
|
|
||||||
if (newarr != null) ret.add(newarr)
|
|
||||||
newarr = JSONArray()
|
|
||||||
count = 20
|
|
||||||
}
|
|
||||||
newarr?.put(array[i])
|
|
||||||
--count
|
|
||||||
}
|
|
||||||
if (newarr != null && newarr.length() > 0) ret.add(newarr)
|
|
||||||
} catch (e: JSONException) {
|
|
||||||
aapsLogger.error("Unhandled exception", e)
|
|
||||||
ret = ArrayList()
|
|
||||||
ret.add(array)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun broadcast(intent: Intent) {
|
|
||||||
val receivers: List<ResolveInfo> = packageManager.queryBroadcastReceivers(intent, 0)
|
|
||||||
for (resolveInfo in receivers)
|
|
||||||
resolveInfo.activityInfo.packageName?.let {
|
|
||||||
intent.setPackage(it)
|
|
||||||
sendBroadcast(intent)
|
|
||||||
aapsLogger.debug(LTag.CORE, "Sending broadcast " + intent.action + " to: " + it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
val handlerThread = HandlerThread(NSClientService::class.java.simpleName + "Handler")
|
val handlerThread = HandlerThread(NSClientService::class.java.simpleName + "Handler")
|
||||||
|
|
|
@ -42,7 +42,6 @@ import info.nightscout.androidaps.interfaces.ActivePlugin;
|
||||||
import info.nightscout.androidaps.interfaces.Config;
|
import info.nightscout.androidaps.interfaces.Config;
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit;
|
import info.nightscout.androidaps.interfaces.GlucoseUnit;
|
||||||
import info.nightscout.androidaps.interfaces.IobCobCalculator;
|
import info.nightscout.androidaps.interfaces.IobCobCalculator;
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.interfaces.Profile;
|
import info.nightscout.androidaps.interfaces.Profile;
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
|
|
|
@ -537,7 +537,11 @@ class IobCobCalculatorPlugin @Inject constructor(
|
||||||
for (pos in extendedBoluses.indices) {
|
for (pos in extendedBoluses.indices) {
|
||||||
val e = extendedBoluses[pos]
|
val e = extendedBoluses[pos]
|
||||||
if (e.timestamp > toTime) continue
|
if (e.timestamp > toTime) continue
|
||||||
if (e.end > now) e.duration = now - e.timestamp
|
if (e.end > now) {
|
||||||
|
val newDuration = now - e.timestamp
|
||||||
|
e.amount *= newDuration.toDouble() / e.duration
|
||||||
|
e.duration = newDuration
|
||||||
|
}
|
||||||
val profile = profileFunction.getProfile(e.timestamp) ?: return total
|
val profile = profileFunction.getProfile(e.timestamp) ?: return total
|
||||||
val calc = e.iobCalc(toTime, profile, activePlugin.activeInsulin)
|
val calc = e.iobCalc(toTime, profile, activePlugin.activeInsulin)
|
||||||
total.plus(calc)
|
total.plus(calc)
|
||||||
|
@ -632,7 +636,11 @@ class IobCobCalculatorPlugin @Inject constructor(
|
||||||
val e = extendedBoluses[pos]
|
val e = extendedBoluses[pos]
|
||||||
if (e.timestamp > toTime) continue
|
if (e.timestamp > toTime) continue
|
||||||
val profile = profileFunction.getProfile(e.timestamp) ?: continue
|
val profile = profileFunction.getProfile(e.timestamp) ?: continue
|
||||||
if (e.end > now) e.duration = now - e.timestamp
|
if (e.end > now) {
|
||||||
|
val newDuration = now - e.timestamp
|
||||||
|
e.amount *= newDuration.toDouble() / e.duration
|
||||||
|
e.duration = newDuration
|
||||||
|
}
|
||||||
val calc = e.iobCalc(toTime, profile, activePlugin.activeInsulin)
|
val calc = e.iobCalc(toTime, profile, activePlugin.activeInsulin)
|
||||||
totalExt.plus(calc)
|
totalExt.plus(calc)
|
||||||
}
|
}
|
||||||
|
@ -667,7 +675,11 @@ class IobCobCalculatorPlugin @Inject constructor(
|
||||||
val e = extendedBoluses[pos]
|
val e = extendedBoluses[pos]
|
||||||
if (e.timestamp > toTime) continue
|
if (e.timestamp > toTime) continue
|
||||||
val profile = profileFunction.getProfile(e.timestamp) ?: continue
|
val profile = profileFunction.getProfile(e.timestamp) ?: continue
|
||||||
if (e.end > now) e.duration = now - e.timestamp
|
if (e.end > now) {
|
||||||
|
val newDuration = now - e.timestamp
|
||||||
|
e.amount *= newDuration.toDouble() / e.duration
|
||||||
|
e.duration = newDuration
|
||||||
|
}
|
||||||
val calc = e.iobCalc(toTime, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget, activePlugin.activeInsulin)
|
val calc = e.iobCalc(toTime, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget, activePlugin.activeInsulin)
|
||||||
totalExt.plus(calc)
|
totalExt.plus(calc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,7 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
R.string.nsclientbg -> Sources.NSClientSource
|
R.string.nsclientbg -> Sources.NSClientSource
|
||||||
R.string.poctech -> Sources.PocTech
|
R.string.poctech -> Sources.PocTech
|
||||||
R.string.tomato -> Sources.Tomato
|
R.string.tomato -> Sources.Tomato
|
||||||
|
R.string.glunovo -> Sources.Glunovo
|
||||||
R.string.xdrip -> Sources.Xdrip
|
R.string.xdrip -> Sources.Xdrip
|
||||||
else -> Sources.Unknown
|
else -> Sources.Unknown
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package info.nightscout.androidaps.plugins.source
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.HandlerThread
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Constants
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||||
|
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||||
|
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
|
||||||
|
import info.nightscout.androidaps.interfaces.BgSource
|
||||||
|
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.LTag
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.XDripBroadcast
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class GlunovoPlugin @Inject constructor(
|
||||||
|
injector: HasAndroidInjector,
|
||||||
|
resourceHelper: ResourceHelper,
|
||||||
|
aapsLogger: AAPSLogger,
|
||||||
|
private val sp: SP,
|
||||||
|
private val context: Context,
|
||||||
|
private val repository: AppRepository,
|
||||||
|
private val xDripBroadcast: XDripBroadcast,
|
||||||
|
private val dateUtil: DateUtil,
|
||||||
|
private val fabricPrivacy: FabricPrivacy
|
||||||
|
) : PluginBase(
|
||||||
|
PluginDescription()
|
||||||
|
.mainType(PluginType.BGSOURCE)
|
||||||
|
.fragmentClass(BGSourceFragment::class.java.name)
|
||||||
|
.pluginIcon(R.drawable.ic_glunovo)
|
||||||
|
.pluginName(R.string.glunovo)
|
||||||
|
.preferencesId(R.xml.pref_bgsource)
|
||||||
|
.shortName(R.string.glunovo)
|
||||||
|
.description(R.string.description_source_glunovo),
|
||||||
|
aapsLogger, resourceHelper, injector
|
||||||
|
), BgSource {
|
||||||
|
|
||||||
|
private val loopHandler: Handler = Handler(HandlerThread(this::class.java.simpleName + "Handler").also { it.start() }.looper)
|
||||||
|
private lateinit var refreshLoop: Runnable
|
||||||
|
|
||||||
|
private val contentUri: Uri = Uri.parse("content://$AUTHORITY/$TABLE_NAME")
|
||||||
|
|
||||||
|
init {
|
||||||
|
refreshLoop = Runnable {
|
||||||
|
try {
|
||||||
|
handleNewData()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
fabricPrivacy.logException(e)
|
||||||
|
aapsLogger.error("Error while processing data", e)
|
||||||
|
}
|
||||||
|
val lastReadTimestamp = sp.getLong(R.string.key_last_processed_glunovo_timestamp, 0L)
|
||||||
|
val differenceToNow = INTERVAL - (dateUtil.now() - lastReadTimestamp) % INTERVAL + T.secs(10).msecs()
|
||||||
|
loopHandler.postDelayed(refreshLoop, differenceToNow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
loopHandler.postDelayed(refreshLoop, T.secs(30).msecs()) // do not start immediately, app may be still starting
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
loopHandler.removeCallbacks(refreshLoop)
|
||||||
|
disposable.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleNewData() {
|
||||||
|
if (!isEnabled()) return
|
||||||
|
|
||||||
|
context.contentResolver.query(contentUri, null, null, null, null)?.let { cr ->
|
||||||
|
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||||
|
val calibrations = mutableListOf<CgmSourceTransaction.Calibration>()
|
||||||
|
cr.moveToFirst()
|
||||||
|
|
||||||
|
while (!cr.isAfterLast) {
|
||||||
|
val timestamp = cr.getLong(0)
|
||||||
|
val value = cr.getDouble(1) //value in mmol/l...
|
||||||
|
val curr = cr.getDouble(2)
|
||||||
|
|
||||||
|
// bypass already processed
|
||||||
|
if (timestamp < sp.getLong(R.string.key_last_processed_glunovo_timestamp, 0L)) {
|
||||||
|
cr.moveToNext()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestamp > dateUtil.now() || timestamp == 0L) {
|
||||||
|
aapsLogger.error(LTag.BGSOURCE, "Error in received data date/time $timestamp")
|
||||||
|
cr.moveToNext()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < 2 || value > 25) {
|
||||||
|
aapsLogger.error(LTag.BGSOURCE, "Error in received data value (value out of bounds) $value")
|
||||||
|
cr.moveToNext()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curr != 0.0)
|
||||||
|
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
||||||
|
timestamp = timestamp,
|
||||||
|
value = value * Constants.MMOLL_TO_MGDL,
|
||||||
|
raw = 0.0,
|
||||||
|
noise = null,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.NONE,
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.GLUNOVO_NATIVE
|
||||||
|
)
|
||||||
|
else
|
||||||
|
calibrations.add(
|
||||||
|
CgmSourceTransaction.Calibration(
|
||||||
|
timestamp = timestamp,
|
||||||
|
value = value,
|
||||||
|
glucoseUnit = TherapyEvent.GlucoseUnit.MMOL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
sp.putLong(R.string.key_last_processed_glunovo_timestamp, timestamp)
|
||||||
|
cr.moveToNext()
|
||||||
|
}
|
||||||
|
cr.close()
|
||||||
|
|
||||||
|
if (glucoseValues.isNotEmpty() || calibrations.isNotEmpty())
|
||||||
|
repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, null))
|
||||||
|
.doOnError {
|
||||||
|
aapsLogger.error(LTag.DATABASE, "Error while saving values from Glunovo App", it)
|
||||||
|
}
|
||||||
|
.blockingGet()
|
||||||
|
.also { savedValues ->
|
||||||
|
savedValues.inserted.forEach {
|
||||||
|
xDripBroadcast.send(it)
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean =
|
||||||
|
glucoseValue.sourceSensor == GlucoseValue.SourceSensor.GLUNOVO_NATIVE && sp.getBoolean(R.string.key_dexcomg5_nsupload, false)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
const val AUTHORITY = "alexpr.co.uk.infinivocgm.cgm_db.CgmExternalProvider/"
|
||||||
|
const val TABLE_NAME = "CgmReading"
|
||||||
|
const val INTERVAL = 180000L // 3 min
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,7 +60,6 @@ class QueueThread internal constructor(
|
||||||
//write time
|
//write time
|
||||||
sp.putLong(R.string.key_btwatchdog_lastbark, System.currentTimeMillis())
|
sp.putLong(R.string.key_btwatchdog_lastbark, System.currentTimeMillis())
|
||||||
//toggle BT
|
//toggle BT
|
||||||
pump.stopConnecting()
|
|
||||||
pump.disconnect("watchdog")
|
pump.disconnect("watchdog")
|
||||||
SystemClock.sleep(1000)
|
SystemClock.sleep(1000)
|
||||||
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
|
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
|
||||||
|
@ -112,14 +111,18 @@ class QueueThread internal constructor(
|
||||||
// Pickup 1st command and set performing variable
|
// Pickup 1st command and set performing variable
|
||||||
if (queue.size() > 0) {
|
if (queue.size() > 0) {
|
||||||
queue.pickup()
|
queue.pickup()
|
||||||
if (queue.performing() != null) {
|
val cont = queue.performing()?.let {
|
||||||
aapsLogger.debug(LTag.PUMPQUEUE, "performing " + queue.performing()?.status())
|
aapsLogger.debug(LTag.PUMPQUEUE, "performing " + it.status())
|
||||||
rxBus.send(EventQueueChanged())
|
rxBus.send(EventQueueChanged())
|
||||||
queue.performing()?.execute()
|
rxBus.send(EventPumpStatusChanged(it.status()))
|
||||||
|
it.execute()
|
||||||
queue.resetPerforming()
|
queue.resetPerforming()
|
||||||
rxBus.send(EventQueueChanged())
|
rxBus.send(EventQueueChanged())
|
||||||
lastCommandTime = System.currentTimeMillis()
|
lastCommandTime = System.currentTimeMillis()
|
||||||
SystemClock.sleep(100)
|
SystemClock.sleep(100)
|
||||||
|
true
|
||||||
|
} ?: false
|
||||||
|
if (cont) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,11 @@ interface Intents {
|
||||||
|
|
||||||
// AAPS -> Xdrip
|
// AAPS -> Xdrip
|
||||||
const val ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT"
|
const val ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT"
|
||||||
const val ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT"
|
|
||||||
const val ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT"
|
|
||||||
const val ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE"
|
const val ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE"
|
||||||
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
|
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
|
||||||
const val ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG"
|
|
||||||
const val ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL"
|
// AAPS -> xDrip 640G mode
|
||||||
|
const val XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR"
|
||||||
|
|
||||||
// xDrip -> AAPS
|
// xDrip -> AAPS
|
||||||
const val ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate"
|
const val ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate"
|
||||||
|
|
|
@ -7,6 +7,7 @@ import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.services.Intents
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
|
@ -24,6 +25,7 @@ class XDripBroadcast @Inject constructor(
|
||||||
private val sp: SP
|
private val sp: SP
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
// sent in 640G mode
|
||||||
fun send(glucoseValue: GlucoseValue) {
|
fun send(glucoseValue: GlucoseValue) {
|
||||||
if (sp.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
|
if (sp.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
|
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
|
||||||
|
@ -41,7 +43,7 @@ class XDripBroadcast @Inject constructor(
|
||||||
bundle.putString("action", "add")
|
bundle.putString("action", "add")
|
||||||
bundle.putString("collection", "entries")
|
bundle.putString("collection", "entries")
|
||||||
bundle.putString("data", entriesBody.toString())
|
bundle.putString("data", entriesBody.toString())
|
||||||
val intent = Intent(XDRIP_PLUS_NS_EMULATOR)
|
val intent = Intent(Intents.XDRIP_PLUS_NS_EMULATOR)
|
||||||
intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
context.sendBroadcast(intent)
|
context.sendBroadcast(intent)
|
||||||
val receivers = context.packageManager.queryBroadcastReceivers(intent, 0)
|
val receivers = context.packageManager.queryBroadcastReceivers(intent, 0)
|
||||||
|
@ -57,7 +59,75 @@ class XDripBroadcast @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
// sent in NSClient dbaccess mode
|
||||||
const val XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR"
|
fun sendProfile(profileStoreJson: JSONObject) {
|
||||||
|
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false))
|
||||||
|
broadcast(
|
||||||
|
Intent(Intents.ACTION_NEW_PROFILE).apply {
|
||||||
|
addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
|
putExtras(Bundle().apply { putString("profile", profileStoreJson.toString()) })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// sent in NSClient dbaccess mode
|
||||||
|
fun sendTreatments(addedOrUpdatedTreatments: JSONArray) {
|
||||||
|
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false))
|
||||||
|
splitArray(addedOrUpdatedTreatments).forEach { part ->
|
||||||
|
broadcast(
|
||||||
|
Intent(Intents.ACTION_NEW_TREATMENT).apply {
|
||||||
|
addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
|
putExtras(Bundle().apply { putString("treatments", part.toString()) })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sent in NSClient dbaccess mode
|
||||||
|
fun sendSgvs(sgvs: JSONArray) {
|
||||||
|
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false))
|
||||||
|
splitArray(sgvs).forEach { part ->
|
||||||
|
broadcast(
|
||||||
|
Intent(Intents.ACTION_NEW_SGV).apply {
|
||||||
|
addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
|
putExtras(Bundle().apply { putString("sgvs", part.toString()) })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun splitArray(array: JSONArray): List<JSONArray> {
|
||||||
|
var ret: MutableList<JSONArray> = ArrayList()
|
||||||
|
try {
|
||||||
|
val size = array.length()
|
||||||
|
var count = 0
|
||||||
|
var newarr: JSONArray? = null
|
||||||
|
for (i in 0 until size) {
|
||||||
|
if (count == 0) {
|
||||||
|
if (newarr != null) ret.add(newarr)
|
||||||
|
newarr = JSONArray()
|
||||||
|
count = 20
|
||||||
|
}
|
||||||
|
newarr?.put(array[i])
|
||||||
|
--count
|
||||||
|
}
|
||||||
|
if (newarr != null && newarr.length() > 0) ret.add(newarr)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
aapsLogger.error("Unhandled exception", e)
|
||||||
|
ret = ArrayList()
|
||||||
|
ret.add(array)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun broadcast(intent: Intent) {
|
||||||
|
context.packageManager.queryBroadcastReceivers(intent, 0).forEach { resolveInfo ->
|
||||||
|
resolveInfo.activityInfo.packageName?.let {
|
||||||
|
intent.setPackage(it)
|
||||||
|
context.sendBroadcast(intent)
|
||||||
|
aapsLogger.debug(LTag.CORE, "Sending broadcast " + intent.action + " to: " + it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -807,6 +807,8 @@
|
||||||
<string name="time_elapsed">Time elapsed</string>
|
<string name="time_elapsed">Time elapsed</string>
|
||||||
<string name="poctech">Poctech</string>
|
<string name="poctech">Poctech</string>
|
||||||
<string name="description_source_poctech">Receive BG values from Poctech app</string>
|
<string name="description_source_poctech">Receive BG values from Poctech app</string>
|
||||||
|
<string name="glunovo">Glunovo</string>
|
||||||
|
<string name="description_source_glunovo">Receive values from Glunovo app</string>
|
||||||
<string name="description_source_tomato">Receive BG values from Tomato app (MiaoMiao device)</string>
|
<string name="description_source_tomato">Receive BG values from Tomato app (MiaoMiao device)</string>
|
||||||
<string name="key_high_temptarget_raises_sensitivity" translatable="false">high_temptarget_raises_sensitivity</string>
|
<string name="key_high_temptarget_raises_sensitivity" translatable="false">high_temptarget_raises_sensitivity</string>
|
||||||
<string name="key_low_temptarget_lowers_sensitivity" translatable="false">low_temptarget_lowers_sensitivity</string>
|
<string name="key_low_temptarget_lowers_sensitivity" translatable="false">low_temptarget_lowers_sensitivity</string>
|
||||||
|
@ -1132,5 +1134,6 @@
|
||||||
<string name="data_status">BG data status</string>
|
<string name="data_status">BG data status</string>
|
||||||
<string name="recalculated_data_used">Recalculated data used</string>
|
<string name="recalculated_data_used">Recalculated data used</string>
|
||||||
<string name="bg_too_close">BG too close:\n%1$s\n%2$s</string>
|
<string name="bg_too_close">BG too close:\n%1$s\n%2$s</string>
|
||||||
|
<string name="key_last_processed_glunovo_timestamp" translatable="false">last_processed_glunovo_timestamp</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -46,4 +46,6 @@ class InputDuration(
|
||||||
this.value = value / 60
|
this.value = value / 60
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = "InputDuration: $value $unit"
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@ buildscript {
|
||||||
rxkotlin_version = '2.4.0'
|
rxkotlin_version = '2.4.0'
|
||||||
room_version = '2.3.0'
|
room_version = '2.3.0'
|
||||||
lifecycle_version = '2.3.1'
|
lifecycle_version = '2.3.1'
|
||||||
dagger_version = '2.40'
|
dagger_version = '2.40.1'
|
||||||
coroutinesVersion = '1.4.1'
|
coroutinesVersion = '1.4.1'
|
||||||
activityVersion = '1.3.1'
|
activityVersion = '1.3.1'
|
||||||
fragmentktx_version = '1.3.6'
|
fragmentktx_version = '1.3.6'
|
||||||
|
|
|
@ -110,7 +110,7 @@ fun extendedBolusFromJson(jsonObject: JSONObject): ExtendedBolus? {
|
||||||
val pumpSerial = JsonHelper.safeGetStringAllowNull(jsonObject, "pumpSerial", null)
|
val pumpSerial = JsonHelper.safeGetStringAllowNull(jsonObject, "pumpSerial", null)
|
||||||
|
|
||||||
if (timestamp == 0L) return null
|
if (timestamp == 0L) return null
|
||||||
if (duration == 0L) return null
|
if (duration == 0L && durationInMilliseconds == 0L) return null
|
||||||
if (amount == 0.0) return null
|
if (amount == 0.0) return null
|
||||||
|
|
||||||
return ExtendedBolus(
|
return ExtendedBolus(
|
||||||
|
@ -135,7 +135,7 @@ fun ExtendedBolus.iobCalc(time: Long, profile: Profile, insulinInterface: Insuli
|
||||||
val dia = profile.dia
|
val dia = profile.dia
|
||||||
val diaAgo = time - dia * 60 * 60 * 1000
|
val diaAgo = time - dia * 60 * 60 * 1000
|
||||||
val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt()
|
val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt()
|
||||||
val spacing = realDuration / aboutFiveMinIntervals
|
val spacing = realDuration / aboutFiveMinIntervals.toDouble()
|
||||||
for (j in 0L until aboutFiveMinIntervals) {
|
for (j in 0L until aboutFiveMinIntervals) {
|
||||||
// find middle of the interval
|
// find middle of the interval
|
||||||
val calcDate = (timestamp + j * spacing * 60 * 1000 + 0.5 * spacing * 60 * 1000).toLong()
|
val calcDate = (timestamp + j * spacing * 60 * 1000 + 0.5 * spacing * 60 * 1000).toLong()
|
||||||
|
|
|
@ -134,14 +134,14 @@ fun TemporaryBasal.toStringShort(): String =
|
||||||
|
|
||||||
fun TemporaryBasal.iobCalc(time: Long, profile: Profile, insulinInterface: Insulin): IobTotal {
|
fun TemporaryBasal.iobCalc(time: Long, profile: Profile, insulinInterface: Insulin): IobTotal {
|
||||||
val result = IobTotal(time)
|
val result = IobTotal(time)
|
||||||
val realDuration: Int = getPassedDurationToTimeInMinutes(time)
|
val realDuration = getPassedDurationToTimeInMinutes(time)
|
||||||
var netBasalAmount = 0.0
|
var netBasalAmount = 0.0
|
||||||
if (realDuration > 0) {
|
if (realDuration > 0) {
|
||||||
var netBasalRate: Double
|
var netBasalRate: Double
|
||||||
val dia = profile.dia
|
val dia = profile.dia
|
||||||
val diaAgo = time - dia * 60 * 60 * 1000
|
val diaAgo = time - dia * 60 * 60 * 1000
|
||||||
val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt()
|
val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt()
|
||||||
val tempBolusSpacing = (realDuration / aboutFiveMinIntervals).toDouble()
|
val tempBolusSpacing = realDuration / aboutFiveMinIntervals.toDouble()
|
||||||
for (j in 0L until aboutFiveMinIntervals) {
|
for (j in 0L until aboutFiveMinIntervals) {
|
||||||
// find middle of the interval
|
// find middle of the interval
|
||||||
val calcDate = (timestamp + j * tempBolusSpacing * 60 * 1000 + 0.5 * tempBolusSpacing * 60 * 1000).toLong()
|
val calcDate = (timestamp + j * tempBolusSpacing * 60 * 1000 + 0.5 * tempBolusSpacing * 60 * 1000).toLong()
|
||||||
|
@ -175,7 +175,7 @@ fun TemporaryBasal.iobCalc(time: Long, profile: Profile, insulinInterface: Insul
|
||||||
|
|
||||||
fun TemporaryBasal.iobCalc(time: Long, profile: Profile, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean, insulinInterface: Insulin): IobTotal {
|
fun TemporaryBasal.iobCalc(time: Long, profile: Profile, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean, insulinInterface: Insulin): IobTotal {
|
||||||
val result = IobTotal(time)
|
val result = IobTotal(time)
|
||||||
val realDuration: Double = getPassedDurationToTimeInMinutes(time).toDouble()
|
val realDuration = getPassedDurationToTimeInMinutes(time)
|
||||||
var netBasalAmount = 0.0
|
var netBasalAmount = 0.0
|
||||||
var sensitivityRatio = lastAutosensResult.ratio
|
var sensitivityRatio = lastAutosensResult.ratio
|
||||||
val normalTarget = 100.0
|
val normalTarget = 100.0
|
||||||
|
@ -190,7 +190,7 @@ fun TemporaryBasal.iobCalc(time: Long, profile: Profile, lastAutosensResult: Aut
|
||||||
val dia = profile.dia
|
val dia = profile.dia
|
||||||
val diaAgo = time - dia * 60 * 60 * 1000
|
val diaAgo = time - dia * 60 * 60 * 1000
|
||||||
val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt()
|
val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt()
|
||||||
val tempBolusSpacing = realDuration / aboutFiveMinIntervals
|
val tempBolusSpacing = realDuration / aboutFiveMinIntervals.toDouble()
|
||||||
for (j in 0L until aboutFiveMinIntervals) {
|
for (j in 0L until aboutFiveMinIntervals) {
|
||||||
// find middle of the interval
|
// find middle of the interval
|
||||||
val calcDate = (timestamp + j * tempBolusSpacing * 60 * 1000 + 0.5 * tempBolusSpacing * 60 * 1000).toLong()
|
val calcDate = (timestamp + j * tempBolusSpacing * 60 * 1000 + 0.5 * tempBolusSpacing * 60 * 1000).toLong()
|
||||||
|
|
|
@ -27,8 +27,13 @@ interface PumpSync {
|
||||||
*
|
*
|
||||||
* Call this function when new pump is paired to accept data from new pump
|
* Call this function when new pump is paired to accept data from new pump
|
||||||
* to prevent overlapping pump histories
|
* to prevent overlapping pump histories
|
||||||
|
* @param endRunning if true end previous running TBR and EB
|
||||||
*/
|
*/
|
||||||
fun connectNewPump()
|
|
||||||
|
// @JvmOverloads and default value impossible on interface
|
||||||
|
// replace by `fun connectNewPump(endRunning: Boolean = true)` after full conversion to kotlin
|
||||||
|
fun connectNewPump(endRunning: Boolean)
|
||||||
|
fun connectNewPump() = connectNewPump(true)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GENERAL STATUS
|
* GENERAL STATUS
|
||||||
|
@ -55,8 +60,29 @@ interface PumpSync {
|
||||||
*/
|
*/
|
||||||
data class PumpState(val temporaryBasal: TemporaryBasal?, val extendedBolus: ExtendedBolus?, val bolus: Bolus?, val profile: Profile?) {
|
data class PumpState(val temporaryBasal: TemporaryBasal?, val extendedBolus: ExtendedBolus?, val bolus: Bolus?, val profile: Profile?) {
|
||||||
|
|
||||||
data class TemporaryBasal(val timestamp: Long, val duration: Long, val rate: Double, val isAbsolute: Boolean, val type: TemporaryBasalType, val id: Long, val pumpId: Long?)
|
data class TemporaryBasal @JvmOverloads constructor(
|
||||||
data class ExtendedBolus(val timestamp: Long, val duration: Long, val amount: Double, val rate: Double)
|
val timestamp: Long,
|
||||||
|
val duration: Long,
|
||||||
|
val rate: Double,
|
||||||
|
val isAbsolute: Boolean,
|
||||||
|
val type: TemporaryBasalType,
|
||||||
|
val id: Long,
|
||||||
|
val pumpId: Long?,
|
||||||
|
// used only to cancel TBR on pump change
|
||||||
|
val pumpType: PumpType = PumpType.USER,
|
||||||
|
val pumpSerial: String = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ExtendedBolus @JvmOverloads constructor(
|
||||||
|
val timestamp: Long,
|
||||||
|
val duration: Long,
|
||||||
|
val amount: Double,
|
||||||
|
val rate: Double,
|
||||||
|
// used only to cancel EB on pump change
|
||||||
|
val pumpType: PumpType = PumpType.USER,
|
||||||
|
val pumpSerial: String = ""
|
||||||
|
)
|
||||||
|
|
||||||
data class Bolus(val timestamp: Long, val amount: Double)
|
data class Bolus(val timestamp: Long, val amount: Double)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@ class RunningConfiguration @Inject constructor(
|
||||||
|
|
||||||
// called in NSClient mode only
|
// called in NSClient mode only
|
||||||
fun apply(configuration: JSONObject) {
|
fun apply(configuration: JSONObject) {
|
||||||
|
assert(config.NSCLIENT)
|
||||||
|
|
||||||
if (configuration.has("version")) {
|
if (configuration.has("version")) {
|
||||||
rxBus.send(EventNSClientNewLog("VERSION", "Received AndroidAPS version ${configuration.getString("version")}"))
|
rxBus.send(EventNSClientNewLog("VERSION", "Received AndroidAPS version ${configuration.getString("version")}"))
|
||||||
if (config.VERSION_NAME.startsWith(configuration.getString("version")).not()) {
|
if (config.VERSION_NAME.startsWith(configuration.getString("version")).not()) {
|
||||||
|
@ -100,7 +102,7 @@ class RunningConfiguration @Inject constructor(
|
||||||
if (sp.getString(R.string.key_virtualpump_type, "fake") != pumpType) {
|
if (sp.getString(R.string.key_virtualpump_type, "fake") != pumpType) {
|
||||||
sp.putString(R.string.key_virtualpump_type, pumpType)
|
sp.putString(R.string.key_virtualpump_type, pumpType)
|
||||||
activePlugin.activePump.pumpDescription.fillFor(PumpType.getByDescription(pumpType))
|
activePlugin.activePump.pumpDescription.fillFor(PumpType.getByDescription(pumpType))
|
||||||
pumpSync.connectNewPump()
|
pumpSync.connectNewPump(endRunning = false) // do not end running TBRs, we call this only to accept data properly
|
||||||
aapsLogger.debug(LTag.CORE, "Changing pump type to $pumpType")
|
aapsLogger.debug(LTag.CORE, "Changing pump type to $pumpType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,15 @@ class PumpSyncImplementation @Inject constructor(
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
override fun connectNewPump() {
|
override fun connectNewPump(endRunning: Boolean) {
|
||||||
|
if (endRunning) {
|
||||||
|
expectedPumpState().temporaryBasal?.let {
|
||||||
|
syncStopTemporaryBasalWithPumpId(dateUtil.now(), dateUtil.now(), it.pumpType, it.pumpSerial)
|
||||||
|
}
|
||||||
|
expectedPumpState().extendedBolus?.let {
|
||||||
|
syncStopExtendedBolusWithPumpId(dateUtil.now(), dateUtil.now(), it.pumpType, it.pumpSerial)
|
||||||
|
}
|
||||||
|
}
|
||||||
sp.remove(R.string.key_active_pump_type)
|
sp.remove(R.string.key_active_pump_type)
|
||||||
sp.remove(R.string.key_active_pump_serial_number)
|
sp.remove(R.string.key_active_pump_serial_number)
|
||||||
sp.remove(R.string.key_active_pump_change_timestamp)
|
sp.remove(R.string.key_active_pump_change_timestamp)
|
||||||
|
@ -77,7 +85,7 @@ class PumpSyncImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun expectedPumpState(): PumpSync.PumpState {
|
override fun expectedPumpState(): PumpSync.PumpState {
|
||||||
val bolus = repository.getLastBolusRecordWrapped().blockingGet();
|
val bolus = repository.getLastBolusRecordWrapped().blockingGet()
|
||||||
val temporaryBasal = repository.getTemporaryBasalActiveAt(dateUtil.now()).blockingGet()
|
val temporaryBasal = repository.getTemporaryBasalActiveAt(dateUtil.now()).blockingGet()
|
||||||
val extendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet()
|
val extendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet()
|
||||||
|
|
||||||
|
@ -91,7 +99,9 @@ class PumpSyncImplementation @Inject constructor(
|
||||||
rate = temporaryBasal.value.rate,
|
rate = temporaryBasal.value.rate,
|
||||||
isAbsolute = temporaryBasal.value.isAbsolute,
|
isAbsolute = temporaryBasal.value.isAbsolute,
|
||||||
type = PumpSync.TemporaryBasalType.fromDbType(temporaryBasal.value.type),
|
type = PumpSync.TemporaryBasalType.fromDbType(temporaryBasal.value.type),
|
||||||
pumpId = temporaryBasal.value.interfaceIDs.pumpId
|
pumpId = temporaryBasal.value.interfaceIDs.pumpId,
|
||||||
|
pumpType = temporaryBasal.value.interfaceIDs.pumpType?.let { PumpType.fromDbPumpType(it)} ?: PumpType.USER,
|
||||||
|
pumpSerial = temporaryBasal.value.interfaceIDs.pumpSerial ?: "",
|
||||||
)
|
)
|
||||||
else null,
|
else null,
|
||||||
extendedBolus =
|
extendedBolus =
|
||||||
|
@ -100,7 +110,9 @@ class PumpSyncImplementation @Inject constructor(
|
||||||
timestamp = extendedBolus.value.timestamp,
|
timestamp = extendedBolus.value.timestamp,
|
||||||
duration = extendedBolus.value.duration,
|
duration = extendedBolus.value.duration,
|
||||||
amount = extendedBolus.value.amount,
|
amount = extendedBolus.value.amount,
|
||||||
rate = extendedBolus.value.rate
|
rate = extendedBolus.value.rate,
|
||||||
|
pumpType = extendedBolus.value.interfaceIDs.pumpType?.let { PumpType.fromDbPumpType(it)} ?: PumpType.USER,
|
||||||
|
pumpSerial = extendedBolus.value.interfaceIDs.pumpSerial ?: ""
|
||||||
)
|
)
|
||||||
else null,
|
else null,
|
||||||
bolus =
|
bolus =
|
||||||
|
|
|
@ -359,6 +359,41 @@ enum class PumpType {
|
||||||
|
|
||||||
fun getByDescription(desc: String): PumpType =
|
fun getByDescription(desc: String): PumpType =
|
||||||
values().firstOrNull { it.description == desc } ?: GENERIC_AAPS
|
values().firstOrNull { it.description == desc } ?: GENERIC_AAPS
|
||||||
|
|
||||||
|
fun fromDbPumpType(pt: InterfaceIDs.PumpType): PumpType =
|
||||||
|
when (pt) {
|
||||||
|
InterfaceIDs.PumpType.GENERIC_AAPS -> GENERIC_AAPS
|
||||||
|
InterfaceIDs.PumpType.CELLNOVO -> CELLNOVO
|
||||||
|
InterfaceIDs.PumpType.ACCU_CHEK_COMBO -> ACCU_CHEK_COMBO
|
||||||
|
InterfaceIDs.PumpType.ACCU_CHEK_SPIRIT -> ACCU_CHEK_SPIRIT
|
||||||
|
InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT -> ACCU_CHEK_INSIGHT_VIRTUAL
|
||||||
|
InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH -> ACCU_CHEK_INSIGHT
|
||||||
|
InterfaceIDs.PumpType.ACCU_CHEK_SOLO -> ACCU_CHEK_SOLO
|
||||||
|
InterfaceIDs.PumpType.ANIMAS_VIBE -> ANIMAS_VIBE
|
||||||
|
InterfaceIDs.PumpType.ANIMAS_PING -> ANIMAS_PING
|
||||||
|
InterfaceIDs.PumpType.DANA_R -> DANA_R
|
||||||
|
InterfaceIDs.PumpType.DANA_R_KOREAN -> DANA_R_KOREAN
|
||||||
|
InterfaceIDs.PumpType.DANA_RS -> DANA_RS
|
||||||
|
InterfaceIDs.PumpType.DANA_RS_KOREAN -> DANA_RS_KOREAN
|
||||||
|
InterfaceIDs.PumpType.DANA_RV2 -> DANA_RV2
|
||||||
|
InterfaceIDs.PumpType.DANA_I -> DANA_I
|
||||||
|
InterfaceIDs.PumpType.OMNIPOD_EROS -> OMNIPOD_EROS
|
||||||
|
InterfaceIDs.PumpType.OMNIPOD_DASH -> OMNIPOD_DASH
|
||||||
|
InterfaceIDs.PumpType.MEDTRONIC_512_517 -> MEDTRONIC_512_712
|
||||||
|
InterfaceIDs.PumpType.MEDTRONIC_515_715 -> MEDTRONIC_515_715
|
||||||
|
InterfaceIDs.PumpType.MEDTRONIC_522_722 -> MEDTRONIC_522_722
|
||||||
|
InterfaceIDs.PumpType.MEDTRONIC_523_723_REVEL -> MEDTRONIC_523_723_REVEL
|
||||||
|
InterfaceIDs.PumpType.MEDTRONIC_554_754_VEO -> MEDTRONIC_554_754_VEO
|
||||||
|
InterfaceIDs.PumpType.MEDTRONIC_640G -> MEDTRONIC_640G
|
||||||
|
InterfaceIDs.PumpType.TANDEM_T_SLIM -> TANDEM_T_SLIM
|
||||||
|
InterfaceIDs.PumpType.TANDEM_T_SLIM_G4 -> TANDEM_T_SLIM_G4
|
||||||
|
InterfaceIDs.PumpType.TANDEM_T_FLEX -> TANDEM_T_FLEX
|
||||||
|
InterfaceIDs.PumpType.TANDEM_T_SLIM_X2 -> TANDEM_T_SLIM_X2
|
||||||
|
InterfaceIDs.PumpType.YPSOPUMP -> YPSOPUMP
|
||||||
|
InterfaceIDs.PumpType.MDI -> MDI
|
||||||
|
InterfaceIDs.PumpType.USER -> USER
|
||||||
|
InterfaceIDs.PumpType.DIACONN_G8 -> DIACONN_G8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(description: String, model: String, parent: PumpType, pumpCapability: PumpCapability? = null, source: Sources? = null) {
|
constructor(description: String, model: String, parent: PumpType, pumpCapability: PumpCapability? = null, source: Sources? = null) {
|
||||||
|
|
|
@ -265,11 +265,11 @@ public class DateTimeUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static long getATDWithAddedMinutes(long atd, int minutesDiff) {
|
public static long getATDWithAddedSeconds(Long atd, int addedSeconds) {
|
||||||
GregorianCalendar oldestEntryTime = DateTimeUtil.toGregorianCalendar(atd);
|
GregorianCalendar oldestEntryTime = DateTimeUtil.toGregorianCalendar(atd);
|
||||||
oldestEntryTime.add(Calendar.MINUTE, minutesDiff);
|
oldestEntryTime.add(Calendar.SECOND, addedSeconds);
|
||||||
|
|
||||||
return oldestEntryTime.getTimeInMillis();
|
return toATechDate(oldestEntryTime.getTimeInMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,7 +279,6 @@ public class DateTimeUtil {
|
||||||
return toATechDate(oldestEntryTime);
|
return toATechDate(oldestEntryTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static long getTimeInFutureFromMinutes(long startTime, int minutes) {
|
public static long getTimeInFutureFromMinutes(long startTime, int minutes) {
|
||||||
return startTime + getTimeInMs(minutes);
|
return startTime + getTimeInMs(minutes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ class UserEntryPresentationHelper @Inject constructor(
|
||||||
Sources.NSClientSource -> R.drawable.ic_nsclient_bg
|
Sources.NSClientSource -> R.drawable.ic_nsclient_bg
|
||||||
Sources.PocTech -> R.drawable.ic_poctech
|
Sources.PocTech -> R.drawable.ic_poctech
|
||||||
Sources.Tomato -> R.drawable.ic_sensor
|
Sources.Tomato -> R.drawable.ic_sensor
|
||||||
|
Sources.Glunovo -> R.drawable.ic_glunovo
|
||||||
Sources.Xdrip -> R.drawable.ic_blooddrop_48
|
Sources.Xdrip -> R.drawable.ic_blooddrop_48
|
||||||
Sources.LocalProfile -> R.drawable.ic_local_profile
|
Sources.LocalProfile -> R.drawable.ic_local_profile
|
||||||
Sources.Loop -> R.drawable.ic_loop_closed_white
|
Sources.Loop -> R.drawable.ic_loop_closed_white
|
||||||
|
|
85
core/src/main/res/drawable/ic_glunovo.xml
Normal file
85
core/src/main/res/drawable/ic_glunovo.xml
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="64dp"
|
||||||
|
android:height="64dp"
|
||||||
|
android:viewportWidth="64"
|
||||||
|
android:viewportHeight="64">
|
||||||
|
<path
|
||||||
|
android:pathData="M51.787,23.533c-0.01,-10.925 -8.888,-19.787 -19.813,-19.777c-10.925,0.01 -19.787,8.889 -19.777,19.814l0.016,16.897c0.01,10.925 8.888,19.787 19.813,19.777c10.925,-0.01 19.787,-8.889 19.777,-19.814l-0.016,-16.897Z"
|
||||||
|
android:fillColor="#ebeae3"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M46.353,25.52c-0.007,-7.925 -6.447,-14.353 -14.372,-14.346c-7.925,0.008 -14.353,6.448 -14.346,14.373l0.015,16.092c0.006,6.181 5.029,11.195 11.21,11.19l6.318,-0.006c6.182,-0.006 11.196,-5.029 11.19,-11.211l-0.015,-16.092Z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:startY="31.4229"
|
||||||
|
android:startX="17.6405"
|
||||||
|
android:endY="30.819769"
|
||||||
|
android:endX="58.322098"
|
||||||
|
android:type="linear">
|
||||||
|
<item android:offset="0" android:color="#FFFFFFFF"/>
|
||||||
|
<item android:offset="1" android:color="#FFB3B3B3"/>
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:pathData="M22.928,44.362l-0.021,-22.414c-0.004,-4.01 3.249,-7.27 7.26,-7.273l3.634,-0.004c4.011,-0.003 7.27,3.25 7.274,7.261l0.02,22.413c-0.638,2.068 -1.683,3.934 -3.208,5.56l-11.85,0.011c-1.578,-1.46 -2.517,-3.384 -3.119,-5.554l0.01,-0Z"
|
||||||
|
android:strokeWidth="0.56"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#000"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M28.826,46.02l-2.759,0.002l-0.001,-0.899c-0,-0.158 0.008,-0.279 0.026,-0.362c0.022,-0.117 0.065,-0.216 0.129,-0.295c0.063,-0.079 0.152,-0.143 0.266,-0.191c0.114,-0.048 0.239,-0.073 0.376,-0.073c0.235,0 0.434,0.064 0.596,0.193c0.163,0.129 0.244,0.362 0.245,0.699l0,0.611l1.122,-0.001l0,0.316ZM27.378,45.706l-0,-0.616c-0,-0.204 -0.044,-0.349 -0.132,-0.434c-0.088,-0.086 -0.212,-0.129 -0.371,-0.129c-0.116,0.001 -0.214,0.026 -0.297,0.076c-0.082,0.051 -0.136,0.117 -0.162,0.2c-0.017,0.053 -0.025,0.151 -0.025,0.294l0.001,0.61l0.986,-0.001Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M27.48,43.896c-0.458,0.001 -0.816,-0.105 -1.076,-0.317c-0.259,-0.213 -0.389,-0.487 -0.389,-0.823c-0,-0.22 0.06,-0.418 0.182,-0.595c0.122,-0.177 0.291,-0.311 0.509,-0.404c0.217,-0.093 0.464,-0.14 0.74,-0.14c0.28,-0 0.531,0.048 0.752,0.146c0.221,0.097 0.388,0.235 0.502,0.414c0.114,0.179 0.171,0.371 0.171,0.578c-0,0.225 -0.063,0.425 -0.188,0.602c-0.125,0.177 -0.297,0.311 -0.514,0.402c-0.217,0.091 -0.446,0.137 -0.689,0.137ZM27.486,43.571c0.332,-0 0.594,-0.078 0.786,-0.232c0.191,-0.155 0.286,-0.349 0.286,-0.582c-0,-0.237 -0.097,-0.432 -0.29,-0.585c-0.194,-0.154 -0.468,-0.23 -0.823,-0.23c-0.225,0 -0.421,0.033 -0.588,0.099c-0.168,0.066 -0.298,0.162 -0.39,0.288c-0.092,0.127 -0.138,0.268 -0.138,0.425c0,0.224 0.089,0.416 0.267,0.576c0.178,0.161 0.474,0.241 0.89,0.241Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M27.853,39.51l0.092,-0.316c0.3,0.066 0.529,0.185 0.687,0.357c0.157,0.171 0.236,0.381 0.236,0.629c0.001,0.257 -0.06,0.466 -0.181,0.627c-0.121,0.161 -0.296,0.284 -0.526,0.368c-0.229,0.084 -0.476,0.127 -0.739,0.127c-0.288,0 -0.538,-0.047 -0.752,-0.142c-0.215,-0.094 -0.377,-0.229 -0.488,-0.404c-0.112,-0.175 -0.167,-0.368 -0.168,-0.578c0,-0.238 0.07,-0.439 0.211,-0.602c0.14,-0.162 0.338,-0.276 0.593,-0.34l0.085,0.311c-0.201,0.055 -0.347,0.135 -0.439,0.24c-0.091,0.106 -0.137,0.238 -0.137,0.397c0,0.183 0.051,0.336 0.153,0.459c0.102,0.123 0.238,0.21 0.41,0.259c0.171,0.05 0.348,0.075 0.53,0.075c0.234,-0.001 0.439,-0.03 0.614,-0.089c0.175,-0.06 0.306,-0.152 0.392,-0.276c0.087,-0.125 0.13,-0.26 0.13,-0.405c-0,-0.177 -0.059,-0.326 -0.177,-0.449c-0.118,-0.122 -0.294,-0.205 -0.526,-0.248Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M28.82,38.199l-2.434,0.002l0,0.785l-0.325,0l-0.002,-1.889l0.326,0l0,0.789l2.434,-0.003l0.001,0.316Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M28.174,36.055l0.043,-0.302c0.205,0.047 0.363,0.135 0.477,0.264c0.113,0.129 0.169,0.294 0.169,0.494c0.001,0.253 -0.089,0.453 -0.269,0.601c-0.18,0.148 -0.433,0.222 -0.758,0.223c-0.336,-0 -0.597,-0.075 -0.783,-0.224c-0.186,-0.149 -0.279,-0.343 -0.279,-0.582c-0,-0.231 0.09,-0.419 0.272,-0.566c0.182,-0.146 0.438,-0.22 0.768,-0.22c0.02,0 0.05,0.001 0.091,0.002l0.001,1.287c0.219,-0.011 0.387,-0.065 0.504,-0.161c0.117,-0.097 0.175,-0.217 0.175,-0.361c-0,-0.107 -0.033,-0.199 -0.098,-0.275c-0.066,-0.076 -0.17,-0.136 -0.313,-0.18ZM27.627,37.016l-0.001,-0.964c-0.168,0.013 -0.294,0.05 -0.378,0.111c-0.131,0.093 -0.196,0.214 -0.196,0.363c0,0.134 0.053,0.247 0.157,0.339c0.104,0.091 0.244,0.142 0.418,0.151Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M28.084,34.259l0.043,-0.288c0.23,0.031 0.41,0.112 0.54,0.241c0.13,0.129 0.195,0.288 0.195,0.477c0,0.236 -0.089,0.426 -0.268,0.57c-0.179,0.144 -0.435,0.216 -0.769,0.216c-0.216,0 -0.405,-0.031 -0.567,-0.092c-0.161,-0.062 -0.283,-0.156 -0.364,-0.282c-0.081,-0.126 -0.122,-0.263 -0.122,-0.412c0,-0.187 0.055,-0.341 0.164,-0.46c0.11,-0.119 0.266,-0.196 0.468,-0.23l0.051,0.285c-0.134,0.027 -0.235,0.075 -0.303,0.144c-0.067,0.069 -0.101,0.152 -0.101,0.249c-0,0.148 0.061,0.268 0.184,0.36c0.122,0.092 0.316,0.137 0.581,0.137c0.268,-0 0.463,-0.045 0.585,-0.134c0.122,-0.089 0.182,-0.205 0.182,-0.348c0,-0.115 -0.041,-0.21 -0.122,-0.287c-0.082,-0.077 -0.208,-0.126 -0.377,-0.146Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M28.816,33.72l-2.76,0.002l-0,-0.292l0.99,-0.001c-0.183,-0.136 -0.275,-0.309 -0.275,-0.517c-0,-0.128 0.029,-0.239 0.087,-0.333c0.058,-0.094 0.139,-0.162 0.242,-0.203c0.102,-0.04 0.252,-0.061 0.448,-0.061l1.267,-0.001l-0,0.292l-1.267,0.002c-0.17,-0 -0.293,0.032 -0.37,0.095c-0.077,0.063 -0.116,0.153 -0.116,0.269c0.001,0.087 0.027,0.168 0.079,0.245c0.052,0.076 0.123,0.13 0.212,0.163c0.089,0.032 0.212,0.048 0.369,0.048l1.094,-0.001l-0,0.293Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M27.844,29.206l0.092,-0.315c0.3,0.066 0.529,0.185 0.687,0.356c0.157,0.172 0.236,0.382 0.237,0.63c-0,0.257 -0.061,0.466 -0.182,0.627c-0.121,0.161 -0.296,0.283 -0.525,0.368c-0.23,0.084 -0.477,0.126 -0.74,0.126c-0.288,0.001 -0.538,-0.047 -0.752,-0.141c-0.214,-0.095 -0.377,-0.23 -0.488,-0.405c-0.112,-0.175 -0.167,-0.367 -0.167,-0.577c-0.001,-0.239 0.069,-0.439 0.21,-0.602c0.14,-0.163 0.338,-0.276 0.593,-0.34l0.085,0.31c-0.201,0.056 -0.347,0.136 -0.439,0.241c-0.091,0.105 -0.137,0.237 -0.137,0.397c0,0.183 0.051,0.336 0.153,0.459c0.102,0.123 0.238,0.209 0.41,0.259c0.171,0.05 0.348,0.074 0.53,0.074c0.234,-0 0.439,-0.03 0.614,-0.089c0.175,-0.059 0.306,-0.151 0.393,-0.276c0.086,-0.125 0.129,-0.26 0.129,-0.405c-0,-0.176 -0.059,-0.326 -0.177,-0.448c-0.118,-0.123 -0.294,-0.205 -0.526,-0.249Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M28.811,27.895l-2.434,0.002l0,0.786l-0.325,-0l-0.002,-1.889l0.326,-0l0,0.788l2.434,-0.002l0.001,0.315Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M27.982,26.833l-0.341,-0l-0.001,-0.899l0.341,-0l0.001,0.899Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M28.808,24.589l0,0.292l-2.159,0.002c0.078,0.07 0.156,0.163 0.234,0.277c0.077,0.114 0.136,0.217 0.175,0.308l-0.328,0c-0.089,-0.163 -0.197,-0.306 -0.324,-0.429c-0.127,-0.122 -0.25,-0.209 -0.369,-0.259l-0,-0.189l2.771,-0.002Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M27.446,23.84c-0.326,0.001 -0.589,-0.028 -0.788,-0.086c-0.199,-0.058 -0.352,-0.144 -0.46,-0.258c-0.108,-0.114 -0.162,-0.258 -0.163,-0.431c0,-0.128 0.03,-0.241 0.09,-0.337c0.059,-0.097 0.145,-0.176 0.257,-0.239c0.113,-0.063 0.249,-0.113 0.411,-0.149c0.161,-0.035 0.378,-0.054 0.652,-0.054c0.324,-0 0.585,0.028 0.784,0.086c0.199,0.057 0.353,0.143 0.461,0.257c0.109,0.114 0.163,0.259 0.164,0.433c-0,0.23 -0.095,0.41 -0.286,0.542c-0.23,0.157 -0.604,0.236 -1.122,0.236ZM27.446,23.54c0.453,-0.001 0.754,-0.047 0.904,-0.139c0.15,-0.091 0.225,-0.204 0.225,-0.339c-0,-0.134 -0.075,-0.247 -0.226,-0.338c-0.151,-0.092 -0.452,-0.137 -0.904,-0.137c-0.454,0 -0.756,0.046 -0.905,0.138c-0.15,0.092 -0.224,0.206 -0.224,0.343c0,0.134 0.066,0.241 0.198,0.321c0.168,0.101 0.479,0.151 0.932,0.151Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M27.445,21.989c-0.327,0 -0.589,-0.029 -0.788,-0.087c-0.199,-0.057 -0.353,-0.143 -0.461,-0.258c-0.108,-0.114 -0.162,-0.258 -0.162,-0.431c-0,-0.128 0.029,-0.24 0.089,-0.337c0.059,-0.096 0.145,-0.176 0.258,-0.239c0.112,-0.063 0.249,-0.112 0.41,-0.148c0.161,-0.036 0.379,-0.054 0.652,-0.054c0.324,-0.001 0.585,0.028 0.784,0.085c0.199,0.057 0.353,0.143 0.462,0.257c0.108,0.115 0.163,0.259 0.163,0.433c0,0.23 -0.095,0.411 -0.286,0.542c-0.229,0.157 -0.603,0.236 -1.121,0.237ZM27.444,21.688c0.453,-0 0.755,-0.046 0.905,-0.138c0.15,-0.092 0.225,-0.205 0.224,-0.339c0,-0.135 -0.075,-0.248 -0.226,-0.339c-0.15,-0.091 -0.452,-0.137 -0.904,-0.137c-0.454,0.001 -0.756,0.047 -0.905,0.139c-0.149,0.091 -0.224,0.205 -0.224,0.342c0,0.134 0.066,0.242 0.198,0.322c0.169,0.1 0.479,0.15 0.932,0.15Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M27.307,19.687c-0.051,0.121 -0.125,0.211 -0.22,0.27c-0.095,0.059 -0.21,0.088 -0.343,0.088c-0.2,0 -0.369,-0.062 -0.506,-0.186c-0.137,-0.125 -0.206,-0.291 -0.206,-0.498c0,-0.208 0.07,-0.375 0.21,-0.502c0.14,-0.127 0.31,-0.191 0.511,-0.191c0.128,0 0.239,0.029 0.334,0.087c0.095,0.058 0.168,0.146 0.219,0.264c0.056,-0.147 0.145,-0.258 0.267,-0.334c0.123,-0.077 0.27,-0.115 0.441,-0.115c0.236,-0.001 0.434,0.071 0.595,0.215c0.161,0.144 0.241,0.334 0.241,0.569c0.001,0.235 -0.08,0.425 -0.241,0.569c-0.161,0.144 -0.362,0.217 -0.603,0.217c-0.18,0 -0.33,-0.039 -0.451,-0.118c-0.121,-0.078 -0.204,-0.19 -0.248,-0.335ZM26.733,19.746c0.13,-0 0.237,-0.037 0.32,-0.109c0.083,-0.073 0.124,-0.167 0.124,-0.283c-0,-0.113 -0.041,-0.205 -0.124,-0.277c-0.082,-0.072 -0.183,-0.108 -0.302,-0.108c-0.124,0 -0.229,0.037 -0.313,0.112c-0.085,0.074 -0.127,0.166 -0.127,0.277c-0,0.111 0.041,0.204 0.124,0.278c0.083,0.073 0.182,0.11 0.298,0.11ZM28.007,19.839c0.097,0 0.191,-0.02 0.281,-0.059c0.09,-0.04 0.16,-0.099 0.21,-0.177c0.049,-0.078 0.074,-0.162 0.074,-0.252c-0,-0.14 -0.052,-0.255 -0.157,-0.346c-0.104,-0.091 -0.236,-0.136 -0.397,-0.136c-0.163,-0 -0.298,0.047 -0.405,0.141c-0.106,0.093 -0.16,0.211 -0.159,0.352c-0,0.137 0.053,0.251 0.158,0.342c0.106,0.09 0.237,0.135 0.395,0.135Z"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
</vector>
|
|
@ -1,7 +1,5 @@
|
||||||
package info.nightscout.androidaps.database.embedments
|
package info.nightscout.androidaps.database.embedments
|
||||||
|
|
||||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
|
||||||
|
|
||||||
data class InterfaceIDs(
|
data class InterfaceIDs(
|
||||||
var nightscoutSystemId: String? = null,
|
var nightscoutSystemId: String? = null,
|
||||||
var nightscoutId: String? = null,
|
var nightscoutId: String? = null,
|
||||||
|
|
|
@ -108,6 +108,7 @@ data class GlucoseValue(
|
||||||
GLIMP("Glimp"),
|
GLIMP("Glimp"),
|
||||||
LIBRE_2_NATIVE("Libre2"),
|
LIBRE_2_NATIVE("Libre2"),
|
||||||
POCTECH_NATIVE("Poctech"),
|
POCTECH_NATIVE("Poctech"),
|
||||||
|
GLUNOVO_NATIVE("Glunovo"),
|
||||||
MM_600_SERIES("MM600Series"),
|
MM_600_SERIES("MM600Series"),
|
||||||
EVERSENSE("Eversense"),
|
EVERSENSE("Eversense"),
|
||||||
RANDOM("Random"),
|
RANDOM("Random"),
|
||||||
|
|
|
@ -146,6 +146,7 @@ data class UserEntry(
|
||||||
NSClientSource,
|
NSClientSource,
|
||||||
PocTech,
|
PocTech,
|
||||||
Tomato,
|
Tomato,
|
||||||
|
Glunovo,
|
||||||
Xdrip,
|
Xdrip,
|
||||||
LocalProfile, //From LocalProfile plugin
|
LocalProfile, //From LocalProfile plugin
|
||||||
Loop, //From Loop plugin
|
Loop, //From Loop plugin
|
||||||
|
|
11
medtronic/Changelog.txt
Normal file
11
medtronic/Changelog.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
V1 - Medtronic initial implementation
|
||||||
|
... lots of changes
|
||||||
|
|
||||||
|
|
||||||
|
V2 - Rewrite into kotlin, new database (for v3.0)
|
||||||
|
0001 - initial version
|
||||||
|
0002 - some fixes
|
||||||
|
0003 - SMB fix (798)
|
||||||
|
0004 - Zero TBR Duration fix (798), refactoring of TempBasalProcessDTO
|
||||||
|
0005 - fixes to MedtronicHistoryEntry lateinit problem
|
|
@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.Riley
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask
|
||||||
|
import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryTBR
|
||||||
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil
|
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil
|
||||||
import info.nightscout.androidaps.plugins.pump.common.utils.ProfileUtil
|
import info.nightscout.androidaps.plugins.pump.common.utils.ProfileUtil
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
|
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
|
||||||
|
@ -111,7 +112,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
private var isBusy = false
|
private var isBusy = false
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
aapsLogger.debug(LTag.PUMP, deviceID() + " started.")
|
aapsLogger.debug(LTag.PUMP, deviceID() + " started. (V2.0005)")
|
||||||
serviceConnection = object : ServiceConnection {
|
serviceConnection = object : ServiceConnection {
|
||||||
override fun onServiceDisconnected(name: ComponentName) {
|
override fun onServiceDisconnected(name: ComponentName) {
|
||||||
aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is disconnected")
|
aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is disconnected")
|
||||||
|
@ -468,6 +469,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||||
aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.basalProfileStatus)
|
aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.basalProfileStatus)
|
||||||
if (!isInitialized) return true
|
if (!isInitialized) return true
|
||||||
|
@ -580,6 +582,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 0)
|
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun deliverBolus(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
override fun deliverBolus(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||||
aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - " + BolusDeliveryType.DeliveryPrepared)
|
aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - " + BolusDeliveryType.DeliveryPrepared)
|
||||||
setRefreshButtonEnabled(false)
|
setRefreshButtonEnabled(false)
|
||||||
|
@ -691,6 +694,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
// if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged),
|
// if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged),
|
||||||
// if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed
|
// if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed
|
||||||
|
@Synchronized
|
||||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
|
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
|
||||||
setRefreshButtonEnabled(false)
|
setRefreshButtonEnabled(false)
|
||||||
if (isPumpNotReachable) {
|
if (isPumpNotReachable) {
|
||||||
|
@ -742,6 +746,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
return PumpEnactResult(injector).success(false).enacted(false)
|
return PumpEnactResult(injector).success(false).enacted(false)
|
||||||
.comment(R.string.medtronic_cmd_cant_cancel_tbr_stop_op)
|
.comment(R.string.medtronic_cmd_cant_cancel_tbr_stop_op)
|
||||||
} else {
|
} else {
|
||||||
|
//cancelTBRWithTemporaryId()
|
||||||
aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - Current TBR cancelled.")
|
aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - Current TBR cancelled.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -760,8 +765,9 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
medtronicPumpStatus.tempBasalAmount = absoluteRate
|
medtronicPumpStatus.tempBasalAmount = absoluteRate
|
||||||
medtronicPumpStatus.tempBasalLength = durationInMinutes
|
medtronicPumpStatus.tempBasalLength = durationInMinutes
|
||||||
|
|
||||||
val tempData = info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryTBR(absoluteRate, true, durationInMinutes, tbrType)
|
val tempData = PumpDbEntryTBR(absoluteRate, true, durationInMinutes, tbrType)
|
||||||
|
|
||||||
|
medtronicPumpStatus.runningTBRWithTemp = tempData
|
||||||
pumpSyncStorage.addTemporaryBasalRateWithTempId(tempData, true, this)
|
pumpSyncStorage.addTemporaryBasalRateWithTempId(tempData, true, this)
|
||||||
|
|
||||||
incrementStatistics(MedtronicConst.Statistics.TBRsSet)
|
incrementStatistics(MedtronicConst.Statistics.TBRsSet)
|
||||||
|
@ -771,6 +777,63 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Not used, TBRs fixed in history, should be removed.")
|
||||||
|
private fun cancelTBRWithTemporaryId() {
|
||||||
|
val tbrs : MutableList<PumpDbEntryTBR> = pumpSyncStorage.getTBRs()
|
||||||
|
if (tbrs.size > 0 && medtronicPumpStatus.runningTBRWithTemp!=null) {
|
||||||
|
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTBRWithTemporaryId - TBR items: ${tbrs.size}")
|
||||||
|
|
||||||
|
var item : PumpDbEntryTBR? = null
|
||||||
|
|
||||||
|
if (tbrs.size==1) {
|
||||||
|
item = tbrs.get(0);
|
||||||
|
} else {
|
||||||
|
for (tbr in tbrs) {
|
||||||
|
if (tbr.date == medtronicPumpStatus.runningTBRWithTemp!!.date) {
|
||||||
|
item = tbr
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item!=null) {
|
||||||
|
|
||||||
|
aapsLogger.debug(LTag.PUMP, "DD: cancelTBRWithTemporaryId: tempIdEntry=${item}")
|
||||||
|
|
||||||
|
val differenceS = (System.currentTimeMillis() - item.date) / 1000
|
||||||
|
|
||||||
|
aapsLogger.debug(LTag.PUMP, "syncTemporaryBasalWithTempId " +
|
||||||
|
"[date=${item.date}, " +
|
||||||
|
"rate=${item.rate}, " +
|
||||||
|
"duration=${differenceS} s, " +
|
||||||
|
"isAbsolute=${!item.isAbsolute}, temporaryId=${item.temporaryId}, " +
|
||||||
|
"pumpId=NO, pumpType=${medtronicPumpStatus.pumpType}, " +
|
||||||
|
"pumpSerial=${medtronicPumpStatus.serialNumber}]")
|
||||||
|
|
||||||
|
val result = pumpSync.syncTemporaryBasalWithTempId(
|
||||||
|
timestamp = item.date,
|
||||||
|
rate = item.rate,
|
||||||
|
duration= differenceS * 1000L,
|
||||||
|
isAbsolute = item.isAbsolute,
|
||||||
|
temporaryId = item.temporaryId,
|
||||||
|
type = item.tbrType,
|
||||||
|
pumpId = null,
|
||||||
|
pumpType = medtronicPumpStatus.pumpType,
|
||||||
|
pumpSerial = medtronicPumpStatus.serialNumber)
|
||||||
|
|
||||||
|
aapsLogger.debug(LTag.PUMP, "syncTemporaryBasalWithTempId - Result: $result")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTBRWithTemporaryId - TBR items: ${tbrs.size}, runningTBRWithTemp=${medtronicPumpStatus.runningTBRWithTemp}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (medtronicPumpStatus.runningTBRWithTemp!=null) {
|
||||||
|
medtronicPumpStatus.runningTBRWithTemp = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
|
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
|
||||||
return if (percent == 0) {
|
return if (percent == 0) {
|
||||||
setTempBasalAbsolute(0.0, durationInMinutes, profile, enforceNew, tbrType)
|
setTempBasalAbsolute(0.0, durationInMinutes, profile, enforceNew, tbrType)
|
||||||
|
@ -966,6 +1029,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||||
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - started")
|
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - started")
|
||||||
if (isPumpNotReachable) {
|
if (isPumpNotReachable) {
|
||||||
|
@ -1001,7 +1065,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - Cancel TBR successful.")
|
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - Cancel TBR successful.")
|
||||||
|
|
||||||
val runningTBR = medtronicPumpStatus.runningTBR
|
val runningTBR = medtronicPumpStatus.runningTBR
|
||||||
|
// TODO
|
||||||
if (runningTBR != null) {
|
if (runningTBR != null) {
|
||||||
if (medtronicHistoryData.isTBRActive(runningTBR)) {
|
if (medtronicHistoryData.isTBRActive(runningTBR)) {
|
||||||
|
|
||||||
|
@ -1026,6 +1090,8 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cancelTBRWithTemporaryId()
|
||||||
|
|
||||||
PumpEnactResult(injector).success(true).enacted(true) //
|
PumpEnactResult(injector).success(true).enacted(true) //
|
||||||
.isTempCancel(true)
|
.isTempCancel(true)
|
||||||
}
|
}
|
||||||
|
@ -1043,6 +1109,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
return medtronicPumpStatus.serialNumber
|
return medtronicPumpStatus.serialNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||||
aapsLogger.info(LTag.PUMP, logPrefix + "setNewBasalProfile")
|
aapsLogger.info(LTag.PUMP, logPrefix + "setNewBasalProfile")
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,13 @@ import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil
|
||||||
*/
|
*/
|
||||||
abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface {
|
abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface {
|
||||||
|
|
||||||
lateinit var rawData: List<Byte>
|
var rawData: List<Byte> = listOf()
|
||||||
|
|
||||||
protected var sizes = IntArray(3)
|
protected var sizes = IntArray(3)
|
||||||
|
|
||||||
lateinit var head: ByteArray
|
var head: ByteArray = byteArrayOf()
|
||||||
lateinit var datetime: ByteArray
|
var datetime: ByteArray = byteArrayOf()
|
||||||
lateinit var body: ByteArray
|
var body: ByteArray = byteArrayOf()
|
||||||
|
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
|
@ -41,7 +41,13 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface {
|
||||||
/**
|
/**
|
||||||
* Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255)
|
* Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255)
|
||||||
*/
|
*/
|
||||||
open var pumpId: Long = 0L
|
var pumpId: Long = 0L
|
||||||
|
get() {
|
||||||
|
if (field == 0L) {
|
||||||
|
field = generatePumpId()
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's
|
* if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's
|
||||||
|
@ -158,7 +164,7 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface {
|
||||||
sb.append("]")
|
sb.append("]")
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
if (head.size != 0) {
|
if (head!=null && head.size != 0) {
|
||||||
sb.append(", head=")
|
sb.append(", head=")
|
||||||
sb.append(ByteUtil.shortHexString(head))
|
sb.append(ByteUtil.shortHexString(head))
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,14 +92,6 @@ class PumpHistoryEntry : MedtronicHistoryEntry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override var pumpId: Long = 0L
|
|
||||||
get() {
|
|
||||||
if (field == 0L) {
|
|
||||||
field = generatePumpId()
|
|
||||||
}
|
|
||||||
return field
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasBolusChanged(entry: PumpHistoryEntry): Boolean {
|
fun hasBolusChanged(entry: PumpHistoryEntry): Boolean {
|
||||||
if (entryType == PumpHistoryEntryType.Bolus) {
|
if (entryType == PumpHistoryEntryType.Bolus) {
|
||||||
val thisOne: BolusDTO = this.decodedData["Object"] as BolusDTO
|
val thisOne: BolusDTO = this.decodedData["Object"] as BolusDTO
|
||||||
|
|
|
@ -508,25 +508,25 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
|
|
||||||
if (temporaryId != null) {
|
if (temporaryId != null) {
|
||||||
val result = pumpSync.syncBolusWithTempId(
|
val result = pumpSync.syncBolusWithTempId(
|
||||||
tryToGetByLocalTime(bolus.atechDateTime),
|
timestamp = tryToGetByLocalTime(bolus.atechDateTime),
|
||||||
deliveredAmount,
|
amount = deliveredAmount,
|
||||||
temporaryId,
|
temporaryId = temporaryId,
|
||||||
type,
|
type = null,
|
||||||
bolus.pumpId,
|
pumpId = bolus.pumpId,
|
||||||
medtronicPumpStatus.pumpType,
|
pumpType = medtronicPumpStatus.pumpType,
|
||||||
medtronicPumpStatus.serialNumber)
|
pumpSerial = medtronicPumpStatus.serialNumber)
|
||||||
|
|
||||||
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithTempId [date=%d, temporaryId=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b",
|
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithTempId [date=%d, temporaryId=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b",
|
||||||
bolus.atechDateTime, temporaryId, bolus.pumpId, deliveredAmount,
|
bolus.atechDateTime, temporaryId, bolus.pumpId, deliveredAmount,
|
||||||
medtronicPumpStatus.serialNumber, result))
|
medtronicPumpStatus.serialNumber, result))
|
||||||
} else {
|
} else {
|
||||||
val result = pumpSync.syncBolusWithPumpId(
|
val result = pumpSync.syncBolusWithPumpId(
|
||||||
tryToGetByLocalTime(bolus.atechDateTime),
|
timestamp = tryToGetByLocalTime(bolus.atechDateTime),
|
||||||
deliveredAmount,
|
amount = deliveredAmount,
|
||||||
type,
|
type = null,
|
||||||
bolus.pumpId,
|
pumpId = bolus.pumpId,
|
||||||
medtronicPumpStatus.pumpType,
|
pumpType = medtronicPumpStatus.pumpType,
|
||||||
medtronicPumpStatus.serialNumber)
|
pumpSerial = medtronicPumpStatus.serialNumber)
|
||||||
|
|
||||||
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithPumpId [date=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b",
|
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithPumpId [date=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b",
|
||||||
bolus.atechDateTime, bolus.pumpId, deliveredAmount,
|
bolus.atechDateTime, bolus.pumpId, deliveredAmount,
|
||||||
|
@ -571,62 +571,42 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
private fun processTBREntries(entryList: MutableList<PumpHistoryEntry>) {
|
private fun processTBREntries(entryList: MutableList<PumpHistoryEntry>) {
|
||||||
entryList.reverse()
|
entryList.reverse()
|
||||||
val tbr = entryList[0].getDecodedDataEntry("Object") as TempBasalPair
|
val tbr = entryList[0].getDecodedDataEntry("Object") as TempBasalPair
|
||||||
var readOldItem = false
|
// var readOldItem = false
|
||||||
if (tbr.isCancelTBR) {
|
|
||||||
val oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.TempBasalCombined)
|
val oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.TempBasalCombined)
|
||||||
|
|
||||||
|
if (tbr.isCancelTBR) { // if we have cancel we need to limit previous TBR with this cancel
|
||||||
if (oneMoreEntryFromHistory != null) {
|
if (oneMoreEntryFromHistory != null) {
|
||||||
entryList.add(0, oneMoreEntryFromHistory)
|
entryList.add(0, oneMoreEntryFromHistory)
|
||||||
readOldItem = true
|
|
||||||
} else {
|
} else {
|
||||||
entryList.removeAt(0)
|
entryList.removeAt(0)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (oneMoreEntryFromHistory != null) {
|
||||||
|
val tbrPrev = oneMoreEntryFromHistory.getDecodedDataEntry("Object") as TempBasalPair
|
||||||
|
if (tbrPrev.isZeroTBR) { // if we had Zere TBR in last previous TBR, then we need to limit it, so we need to process it too
|
||||||
|
entryList.add(0, oneMoreEntryFromHistory)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val tbrRecords = pumpSyncStorage.getTBRs()
|
val tbrRecords = pumpSyncStorage.getTBRs()
|
||||||
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, ProcessHistoryRecord.TBR.description + " List (before filter): %s, FromDb=%s", gson.toJson(entryList),
|
|
||||||
tbrRecords))
|
val processList: MutableList<TempBasalProcessDTO> = createTBRProcessList(entryList);
|
||||||
var processDTO: TempBasalProcessDTO? = null
|
|
||||||
val processList: MutableList<TempBasalProcessDTO> = mutableListOf()
|
|
||||||
for (treatment in entryList) {
|
|
||||||
val tbr2 = treatment.getDecodedDataEntry("Object") as TempBasalPair
|
|
||||||
if (tbr2.isCancelTBR) {
|
|
||||||
if (processDTO != null) {
|
|
||||||
processDTO.itemTwo = treatment
|
|
||||||
processDTO.cancelPresent = true
|
|
||||||
if (readOldItem) {
|
|
||||||
processDTO.processOperation = TempBasalProcessDTO.Operation.Edit
|
|
||||||
readOldItem = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
aapsLogger.warn(LTag.PUMP, "processDTO was null - shouldn't happen, ignoring item. ItemTwo=$treatment")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (processDTO != null) {
|
|
||||||
processList.add(processDTO)
|
|
||||||
}
|
|
||||||
processDTO = TempBasalProcessDTO(
|
|
||||||
itemOne = treatment,
|
|
||||||
processOperation = TempBasalProcessDTO.Operation.Add,
|
|
||||||
aapsLogger = aapsLogger,
|
|
||||||
objectType = TempBasalProcessDTO.ObjectType.TemporaryBasal
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (processDTO != null) {
|
|
||||||
processList.add(processDTO)
|
|
||||||
}
|
|
||||||
if (processList.isNotEmpty()) {
|
if (processList.isNotEmpty()) {
|
||||||
for (tempBasalProcessDTO in processList) {
|
for (tempBasalProcessDTO in processList) {
|
||||||
|
|
||||||
aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemOne: " + gson.toJson(tempBasalProcessDTO.itemOne))
|
aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO: " + tempBasalProcessDTO.toTreatmentString())
|
||||||
aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemTwo: " + (if (tempBasalProcessDTO.itemTwo == null) "null" else gson.toJson(tempBasalProcessDTO.itemTwo!!)))
|
//aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemOne: " + gson.toJson(tempBasalProcessDTO.itemOne))
|
||||||
|
//aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemTwo: " + (if (tempBasalProcessDTO.itemTwo == null) "null" else gson.toJson(tempBasalProcessDTO.itemTwo!!)))
|
||||||
|
|
||||||
@Suppress("Unchecked_Cast")
|
@Suppress("Unchecked_Cast")
|
||||||
val entryWithTempId = findDbEntry(tempBasalProcessDTO.itemOne, tbrRecords as MutableList<PumpDbEntry>) as PumpDbEntryTBR?
|
val entryWithTempId = findDbEntry(tempBasalProcessDTO.itemOne, tbrRecords as MutableList<PumpDbEntry>) as PumpDbEntryTBR?
|
||||||
|
|
||||||
aapsLogger.debug(LTag.PUMP, "DD: entryWithTempId: " + (entryWithTempId?.toString() ?: "null"))
|
aapsLogger.debug(LTag.PUMP, "DD: entryWithTempId: " + (entryWithTempId?.toString() ?: "null"))
|
||||||
|
|
||||||
val tbrEntry = tempBasalProcessDTO.itemOneTbr //.getDecodedDataEntry("Object") as TempBasalPair
|
val tbrEntry = tempBasalProcessDTO.itemOneTbr
|
||||||
|
|
||||||
aapsLogger.debug(LTag.PUMP, String.format("DD: tbrEntry=%s, tempBasalProcessDTO=%s", gson.toJson(tbrEntry), gson.toJson(tempBasalProcessDTO)))
|
aapsLogger.debug(LTag.PUMP, String.format("DD: tbrEntry=%s, tempBasalProcessDTO=%s", gson.toJson(tbrEntry), gson.toJson(tempBasalProcessDTO)))
|
||||||
|
|
||||||
|
@ -649,7 +629,7 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime),
|
tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime),
|
||||||
tbrEntry.insulinRate,
|
tbrEntry.insulinRate,
|
||||||
tempBasalProcessDTO.durationAsSeconds * 1000L,
|
tempBasalProcessDTO.durationAsSeconds * 1000L,
|
||||||
!tbrEntry.isPercent,
|
isAbsolute = !tbrEntry.isPercent,
|
||||||
entryWithTempId.temporaryId,
|
entryWithTempId.temporaryId,
|
||||||
PumpSync.TemporaryBasalType.NORMAL,
|
PumpSync.TemporaryBasalType.NORMAL,
|
||||||
tempBasalProcessDTO.pumpId,
|
tempBasalProcessDTO.pumpId,
|
||||||
|
@ -705,10 +685,10 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
date = tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime),
|
date = tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime),
|
||||||
pumpType = medtronicPumpStatus.pumpType,
|
pumpType = medtronicPumpStatus.pumpType,
|
||||||
serialNumber = medtronicPumpStatus.serialNumber,
|
serialNumber = medtronicPumpStatus.serialNumber,
|
||||||
entry = PumpDbEntryTBR(rate = tbrEntry.insulinRate,
|
rate = tbrEntry.insulinRate,
|
||||||
isAbsolute = !tbrEntry.isPercent,
|
isAbsolute = !tbrEntry.isPercent,
|
||||||
durationInSeconds = tempBasalProcessDTO.durationAsSeconds,
|
durationInSeconds = tempBasalProcessDTO.durationAsSeconds,
|
||||||
tbrType = PumpSync.TemporaryBasalType.NORMAL),
|
tbrType = PumpSync.TemporaryBasalType.NORMAL,
|
||||||
pumpId = tempBasalProcessDTO.pumpId)
|
pumpId = tempBasalProcessDTO.pumpId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -720,6 +700,56 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
} // collection
|
} // collection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createTBRProcessList(entryList: MutableList<PumpHistoryEntry>) : MutableList<TempBasalProcessDTO> {
|
||||||
|
|
||||||
|
aapsLogger.debug(LTag.PUMP, "${ProcessHistoryRecord.TBR.description} List (before filter): ${gson.toJson(entryList)}")
|
||||||
|
|
||||||
|
var processDTO: TempBasalProcessDTO? = null
|
||||||
|
val processList: MutableList<TempBasalProcessDTO> = mutableListOf()
|
||||||
|
for (treatment in entryList) {
|
||||||
|
val tbr2 = treatment.getDecodedDataEntry("Object") as TempBasalPair
|
||||||
|
if (tbr2.isCancelTBR) {
|
||||||
|
if (processDTO != null) {
|
||||||
|
processDTO.itemTwo = treatment
|
||||||
|
} else {
|
||||||
|
aapsLogger.warn(LTag.PUMP, "processDTO was null - shouldn't happen, ignoring item. ItemTwo=$treatment")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (processDTO != null) {
|
||||||
|
processList.add(processDTO)
|
||||||
|
}
|
||||||
|
processDTO = TempBasalProcessDTO(
|
||||||
|
itemOne = treatment,
|
||||||
|
aapsLogger = aapsLogger,
|
||||||
|
objectType = TempBasalProcessDTO.ObjectType.TemporaryBasal
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (processDTO != null) {
|
||||||
|
processList.add(processDTO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var previousItem: TempBasalProcessDTO? = null
|
||||||
|
|
||||||
|
// fix for Zero TBRs
|
||||||
|
for (tempBasalProcessDTO in processList) {
|
||||||
|
if (previousItem!=null) {
|
||||||
|
|
||||||
|
var pheEnd = PumpHistoryEntry()
|
||||||
|
pheEnd.atechDateTime = DateTimeUtil.getATDWithAddedSeconds(tempBasalProcessDTO.itemOne.atechDateTime, -2)
|
||||||
|
pheEnd.addDecodedData("Object", TempBasalPair(0.0, false, 0))
|
||||||
|
|
||||||
|
previousItem.itemTwo = pheEnd
|
||||||
|
|
||||||
|
previousItem = null
|
||||||
|
}
|
||||||
|
if (tempBasalProcessDTO.itemOneTbr!!.isZeroTBR) {
|
||||||
|
previousItem = tempBasalProcessDTO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return processList
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun isTBRActive(dbEntry: PumpDbEntryTBR): Boolean {
|
fun isTBRActive(dbEntry: PumpDbEntryTBR): Boolean {
|
||||||
|
@ -881,7 +911,6 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
while (i < filtered2Items.size) {
|
while (i < filtered2Items.size) {
|
||||||
val tbrProcess = TempBasalProcessDTO(
|
val tbrProcess = TempBasalProcessDTO(
|
||||||
itemOne = filtered2Items[i],
|
itemOne = filtered2Items[i],
|
||||||
processOperation = TempBasalProcessDTO.Operation.Add,
|
|
||||||
aapsLogger = aapsLogger,
|
aapsLogger = aapsLogger,
|
||||||
objectType = TempBasalProcessDTO.ObjectType.Suspend)
|
objectType = TempBasalProcessDTO.ObjectType.Suspend)
|
||||||
|
|
||||||
|
@ -959,7 +988,6 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
if (items.size > 0) {
|
if (items.size > 0) {
|
||||||
val tbrProcess = TempBasalProcessDTO(
|
val tbrProcess = TempBasalProcessDTO(
|
||||||
itemOne = items[items.size - 1],
|
itemOne = items[items.size - 1],
|
||||||
processOperation = TempBasalProcessDTO.Operation.Add,
|
|
||||||
aapsLogger = aapsLogger,
|
aapsLogger = aapsLogger,
|
||||||
objectType = TempBasalProcessDTO.ObjectType.Suspend)
|
objectType = TempBasalProcessDTO.ObjectType.Suspend)
|
||||||
|
|
||||||
|
@ -975,7 +1003,6 @@ class MedtronicHistoryData @Inject constructor(
|
||||||
if (items.size > 0) {
|
if (items.size > 0) {
|
||||||
val tbrProcess = TempBasalProcessDTO(
|
val tbrProcess = TempBasalProcessDTO(
|
||||||
itemOne = items[0],
|
itemOne = items[0],
|
||||||
processOperation = TempBasalProcessDTO.Operation.Add,
|
|
||||||
aapsLogger = aapsLogger,
|
aapsLogger = aapsLogger,
|
||||||
objectType = TempBasalProcessDTO.ObjectType.Suspend)
|
objectType = TempBasalProcessDTO.ObjectType.Suspend)
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,9 @@ class TempBasalPair : TempBasalPair {
|
||||||
val isCancelTBR: Boolean
|
val isCancelTBR: Boolean
|
||||||
get() = MedtronicUtil.isSame(insulinRate, 0.0) && durationMinutes == 0
|
get() = MedtronicUtil.isSame(insulinRate, 0.0) && durationMinutes == 0
|
||||||
|
|
||||||
|
val isZeroTBR: Boolean
|
||||||
|
get() = MedtronicUtil.isSame(insulinRate, 0.0) && durationMinutes != 0
|
||||||
|
|
||||||
val description: String
|
val description: String
|
||||||
get() {
|
get() {
|
||||||
if (isCancelTBR) {
|
if (isCancelTBR) {
|
||||||
|
|
|
@ -4,9 +4,9 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil
|
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
|
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
|
||||||
|
import java.lang.StringBuilder
|
||||||
|
|
||||||
class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
|
class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
|
||||||
var processOperation: Operation = Operation.None,
|
|
||||||
var aapsLogger: AAPSLogger,
|
var aapsLogger: AAPSLogger,
|
||||||
var objectType: ObjectType = ObjectType.TemporaryBasal) {
|
var objectType: ObjectType = ObjectType.TemporaryBasal) {
|
||||||
|
|
||||||
|
@ -21,8 +21,6 @@ class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
|
||||||
var itemOneTbr: TempBasalPair? = null
|
var itemOneTbr: TempBasalPair? = null
|
||||||
var itemTwoTbr: TempBasalPair? = null
|
var itemTwoTbr: TempBasalPair? = null
|
||||||
|
|
||||||
var cancelPresent: Boolean = false
|
|
||||||
|
|
||||||
val atechDateTime: Long
|
val atechDateTime: Long
|
||||||
get() = itemOne.atechDateTime
|
get() = itemOne.atechDateTime
|
||||||
|
|
||||||
|
@ -31,26 +29,26 @@ class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
|
||||||
|
|
||||||
val durationAsSeconds: Int
|
val durationAsSeconds: Int
|
||||||
get() {
|
get() {
|
||||||
aapsLogger.debug(LTag.PUMP, "durationAsSeconds: [objectType=$objectType]")
|
//aapsLogger.debug(LTag.PUMP, "durationAsSeconds: [objectType=$objectType]")
|
||||||
if (objectType == ObjectType.TemporaryBasal) {
|
if (objectType == ObjectType.TemporaryBasal) {
|
||||||
if (itemTwo == null) {
|
if (itemTwo == null) {
|
||||||
if (itemOneTbr != null) {
|
if (itemOneTbr != null) {
|
||||||
aapsLogger.debug("TemporaryBasalPair - itemOneSingle: $itemOneTbr")
|
//aapsLogger.debug("TemporaryBasalPair - itemOneSingle: $itemOneTbr")
|
||||||
return itemOneTbr!!.durationMinutes * 60
|
return itemOneTbr!!.durationMinutes * 60
|
||||||
} else {
|
} else {
|
||||||
aapsLogger.error("Couldn't find TempBasalPair in entry: $itemOne")
|
//aapsLogger.error("Couldn't find TempBasalPair in entry: $itemOne")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
aapsLogger.debug(LTag.PUMP, "Found 2 items for duration: itemOne=$itemOne, itemTwo=$itemTwo")
|
//aapsLogger.debug(LTag.PUMP, "Found 2 items for duration: itemOne=$itemOne, itemTwo=$itemTwo")
|
||||||
val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime)
|
val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime)
|
||||||
aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff")
|
//aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff")
|
||||||
return secondsDiff
|
return secondsDiff
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
aapsLogger.debug(LTag.PUMP, "Found 2 items for duration (in SuspendMode): itemOne=$itemOne, itemTwo=$itemTwo")
|
//aapsLogger.debug(LTag.PUMP, "Found 2 items for duration (in SuspendMode): itemOne=$itemOne, itemTwo=$itemTwo")
|
||||||
val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime)
|
val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime)
|
||||||
aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff")
|
//aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff")
|
||||||
return secondsDiff
|
return secondsDiff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,8 +59,31 @@ class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toTreatmentString(): String {
|
||||||
|
val stringBuilder = StringBuilder()
|
||||||
|
|
||||||
|
stringBuilder.append(itemOne.DT)
|
||||||
|
|
||||||
|
if (itemTwo!=null) {
|
||||||
|
stringBuilder.append(" - ")
|
||||||
|
stringBuilder.append(itemTwo!!.DT)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dur = durationAsSeconds
|
||||||
|
|
||||||
|
stringBuilder.append(" " + durationAsSeconds + " s (" + durationAsSeconds/60 + ")")
|
||||||
|
|
||||||
|
if (itemTwoTbr!=null) {
|
||||||
|
stringBuilder.append(" " + itemOneTbr!!.insulinRate + " / " + itemTwoTbr!!.insulinRate)
|
||||||
|
} else {
|
||||||
|
stringBuilder.append(" " + itemOneTbr!!.insulinRate)
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "ItemOne: $itemOne, ItemTwo: $itemTwo, Duration: $durationAsSeconds, Operation: $processOperation, ObjectType: $objectType"
|
return "ItemOne: $itemOne, ItemTwo: $itemTwo, Duration: $durationAsSeconds, ObjectType: $objectType"
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Operation {
|
enum class Operation {
|
||||||
|
|
|
@ -34,6 +34,7 @@ class MedtronicPumpStatus @Inject constructor(private val rh: ResourceHelper,
|
||||||
var maxBolus: Double? = null
|
var maxBolus: Double? = null
|
||||||
var maxBasal: Double? = null
|
var maxBasal: Double? = null
|
||||||
var runningTBR: PumpDbEntryTBR? = null
|
var runningTBR: PumpDbEntryTBR? = null
|
||||||
|
var runningTBRWithTemp: PumpDbEntryTBR? = null
|
||||||
|
|
||||||
// statuses
|
// statuses
|
||||||
var pumpDeviceState = PumpDeviceState.NeverContacted
|
var pumpDeviceState = PumpDeviceState.NeverContacted
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.medtronic.data
|
||||||
|
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.google.gson.internal.LinkedTreeMap
|
||||||
|
import dagger.android.AndroidInjector
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.TestBase
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
|
import info.nightscout.androidaps.interfaces.PumpSync
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage
|
||||||
|
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.MedtronicPumpHistoryDecoder
|
||||||
|
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
|
||||||
|
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair
|
||||||
|
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus
|
||||||
|
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import org.hamcrest.Matchers.notNullValue
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.Mock
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
class MedtronicHistoryDataUTest : TestBase() {
|
||||||
|
|
||||||
|
@Mock lateinit var activePlugin: ActivePlugin
|
||||||
|
@Mock lateinit var medtronicUtil: MedtronicUtil
|
||||||
|
@Mock lateinit var medtronicPumpHistoryDecoder: MedtronicPumpHistoryDecoder
|
||||||
|
@Mock lateinit var medtronicPumpStatus: MedtronicPumpStatus
|
||||||
|
@Mock lateinit var pumpSync: PumpSync
|
||||||
|
@Mock lateinit var pumpSyncStorage: PumpSyncStorage
|
||||||
|
@Mock lateinit var sp: SP
|
||||||
|
|
||||||
|
|
||||||
|
private val packetInjector = HasAndroidInjector {
|
||||||
|
AndroidInjector {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTBRProcessList() {
|
||||||
|
|
||||||
|
var unitToTest = MedtronicHistoryData(packetInjector, aapsLogger, sp, activePlugin,
|
||||||
|
medtronicUtil, medtronicPumpHistoryDecoder,
|
||||||
|
medtronicPumpStatus,
|
||||||
|
pumpSync,
|
||||||
|
pumpSyncStorage)
|
||||||
|
|
||||||
|
|
||||||
|
val gson = Gson()
|
||||||
|
|
||||||
|
val fileText = ClassLoader.getSystemResource("tbr_data.json").readText()
|
||||||
|
|
||||||
|
val listType: Type = object : TypeToken<MutableList<PumpHistoryEntry?>?>() {}.getType()
|
||||||
|
val yourClassList: MutableList<PumpHistoryEntry> = gson.fromJson(fileText, listType)
|
||||||
|
|
||||||
|
for (pumpHistoryEntry in yourClassList) {
|
||||||
|
val stringObject = pumpHistoryEntry.decodedData["Object"] as LinkedTreeMap<String,Object>
|
||||||
|
|
||||||
|
val rate : Double = stringObject.get("insulinRate") as Double
|
||||||
|
val durationMinutes: Double = stringObject.get("durationMinutes") as Double
|
||||||
|
val durationMinutesInt : Int = durationMinutes.toInt()
|
||||||
|
|
||||||
|
var tmbPair = TempBasalPair(rate, false, durationMinutesInt)
|
||||||
|
|
||||||
|
pumpHistoryEntry.decodedData.remove("Object")
|
||||||
|
pumpHistoryEntry.addDecodedData("Object", tmbPair)
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("TBR Pre-Process List: " + gson.toJson(yourClassList))
|
||||||
|
|
||||||
|
val createTBRProcessList = unitToTest.createTBRProcessList(yourClassList)
|
||||||
|
|
||||||
|
System.out.println("TBR Process List: " + createTBRProcessList.size)
|
||||||
|
|
||||||
|
for (tempBasalProcessDTO in createTBRProcessList) {
|
||||||
|
System.out.println(tempBasalProcessDTO.toTreatmentString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
1761
medtronic/src/test/resources/tbr_data.json
Normal file
1761
medtronic/src/test/resources/tbr_data.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -235,7 +235,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
override fun connect(reason: String) {
|
override fun connect(reason: String) {
|
||||||
aapsLogger.info(LTag.PUMP, "connect reason=$reason")
|
aapsLogger.info(LTag.PUMP, "connect reason=$reason")
|
||||||
podStateManager.bluetoothConnectionState = OmnipodDashPodStateManager.BluetoothConnectionState.CONNECTING
|
podStateManager.bluetoothConnectionState = OmnipodDashPodStateManager.BluetoothConnectionState.CONNECTING
|
||||||
|
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
stopConnecting?.let {
|
stopConnecting?.let {
|
||||||
aapsLogger.warn(LTag.PUMP, "Already connecting: $stopConnecting")
|
aapsLogger.warn(LTag.PUMP, "Already connecting: $stopConnecting")
|
||||||
|
@ -244,7 +243,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
val stop = CountDownLatch(1)
|
val stop = CountDownLatch(1)
|
||||||
stopConnecting = stop
|
stopConnecting = stop
|
||||||
}
|
}
|
||||||
|
|
||||||
thread(
|
thread(
|
||||||
start = true,
|
start = true,
|
||||||
name = "ConnectionThread",
|
name = "ConnectionThread",
|
||||||
|
@ -253,6 +251,9 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
stopConnecting?.let {
|
stopConnecting?.let {
|
||||||
val error = omnipodManager.connect(it).ignoreElements().blockingGet()
|
val error = omnipodManager.connect(it).ignoreElements().blockingGet()
|
||||||
aapsLogger.info(LTag.PUMPCOMM, "connect error=$error")
|
aapsLogger.info(LTag.PUMPCOMM, "connect error=$error")
|
||||||
|
if (error == null) {
|
||||||
|
podStateManager.incrementSuccessfulConnectionAttemptsAfterRetries()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
|
@ -270,6 +271,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
override fun stopConnecting() {
|
override fun stopConnecting() {
|
||||||
aapsLogger.info(LTag.PUMP, "stopConnecting")
|
aapsLogger.info(LTag.PUMP, "stopConnecting")
|
||||||
|
podStateManager.incrementFailedConnectionsAfterRetries()
|
||||||
stopConnecting?.countDown()
|
stopConnecting?.countDown()
|
||||||
omnipodManager.disconnect(true)
|
omnipodManager.disconnect(true)
|
||||||
}
|
}
|
||||||
|
@ -340,15 +342,16 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
aapsLogger.info(LTag.PUMP, "syncBolusWithPumpId on CANCEL_BOLUS returned: $sync")
|
aapsLogger.info(LTag.PUMP, "syncBolusWithPumpId on CANCEL_BOLUS returned: $sync")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!podStateManager.alarmSynced) {
|
||||||
podStateManager.alarmType?.let {
|
podStateManager.alarmType?.let {
|
||||||
showNotification(
|
if (!commandQueue.isCustomCommandInQueue(CommandDeactivatePod::class.java)) {
|
||||||
Notification.OMNIPOD_POD_FAULT,
|
showNotification(
|
||||||
it.toString(),
|
Notification.OMNIPOD_POD_FAULT,
|
||||||
Notification.URGENT,
|
it.toString(),
|
||||||
R.raw.boluserror
|
Notification.URGENT,
|
||||||
)
|
R.raw.boluserror
|
||||||
if (!podStateManager.alarmSynced) {
|
)
|
||||||
|
}
|
||||||
pumpSync.insertAnnouncement(
|
pumpSync.insertAnnouncement(
|
||||||
error = it.toString(),
|
error = it.toString(),
|
||||||
pumpId = Random.Default.nextLong(),
|
pumpId = Random.Default.nextLong(),
|
||||||
|
@ -694,7 +697,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
val percent = (waited.toFloat() / estimatedDeliveryTimeSeconds) * 100
|
val percent = (waited.toFloat() / estimatedDeliveryTimeSeconds) * 100
|
||||||
updateBolusProgressDialog(
|
updateBolusProgressDialog(
|
||||||
rh.gs(R.string.bolusdelivering, requestedBolusAmount),
|
rh.gs(R.string.dash_bolusdelivering, requestedBolusAmount),
|
||||||
percent.toInt()
|
percent.toInt()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1191,7 +1194,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
private fun handleTimeChange(): PumpEnactResult {
|
private fun handleTimeChange(): PumpEnactResult {
|
||||||
return profileFunction.getProfile()?.let {
|
return profileFunction.getProfile()?.let {
|
||||||
setNewBasalProfile(it, OmnipodCommandType.SET_TIME)
|
setNewBasalProfile(it, OmnipodCommandType.SET_TIME)
|
||||||
} ?: PumpEnactResult(injector).success(true).enacted(false).comment("No profile active")
|
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateAlertConfiguration(): PumpEnactResult {
|
private fun updateAlertConfiguration(): PumpEnactResult {
|
||||||
|
|
|
@ -23,8 +23,6 @@ interface OmnipodDashManager {
|
||||||
|
|
||||||
fun suspendDelivery(hasBasalBeepEnabled: Boolean): Observable<PodEvent>
|
fun suspendDelivery(hasBasalBeepEnabled: Boolean): Observable<PodEvent>
|
||||||
|
|
||||||
fun setTime(): Observable<PodEvent>
|
|
||||||
|
|
||||||
fun setTempBasal(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable<PodEvent>
|
fun setTempBasal(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable<PodEvent>
|
||||||
|
|
||||||
fun stopTempBasal(hasTempBasalBeepEnabled: Boolean): Observable<PodEvent>
|
fun stopTempBasal(hasTempBasalBeepEnabled: Boolean): Observable<PodEvent>
|
||||||
|
|
|
@ -196,7 +196,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
DefaultStatusResponse::class
|
DefaultStatusResponse::class
|
||||||
)
|
)
|
||||||
}.doOnComplete {
|
}.doOnComplete {
|
||||||
podStateManager.timeZone = TimeZone.getDefault()
|
podStateManager.updateTimeZone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,12 +506,6 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
).interceptPodEvents()
|
).interceptPodEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTime(): Observable<PodEvent> {
|
|
||||||
// TODO
|
|
||||||
logger.error(LTag.PUMPCOMM, "NOT IMPLEMENTED: setTime()")
|
|
||||||
return Observable.empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeSendProgramTempBasalCommand(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable<PodEvent> {
|
private fun observeSendProgramTempBasalCommand(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable<PodEvent> {
|
||||||
return Observable.defer {
|
return Observable.defer {
|
||||||
bleManager.sendCommand(
|
bleManager.sendCommand(
|
||||||
|
|
|
@ -33,8 +33,11 @@ interface OmnipodDashPodStateManager {
|
||||||
var bluetoothConnectionState: BluetoothConnectionState
|
var bluetoothConnectionState: BluetoothConnectionState
|
||||||
var connectionAttempts: Int
|
var connectionAttempts: Int
|
||||||
var successfulConnections: Int
|
var successfulConnections: Int
|
||||||
|
val successfulConnectionAttemptsAfterRetries: Int
|
||||||
|
val failedConnectionsAfterRetries: Int
|
||||||
|
|
||||||
var timeZone: TimeZone
|
val timeZoneId: String?
|
||||||
|
val timeZoneUpdated: Long?
|
||||||
val sameTimeZone: Boolean // The TimeZone is the same on the phone and on the pod
|
val sameTimeZone: Boolean // The TimeZone is the same on the phone and on the pod
|
||||||
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
||||||
val lastStatusResponseReceived: Long
|
val lastStatusResponseReceived: Long
|
||||||
|
@ -85,6 +88,9 @@ interface OmnipodDashPodStateManager {
|
||||||
fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
|
fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
|
||||||
fun reset()
|
fun reset()
|
||||||
fun connectionSuccessRatio(): Float
|
fun connectionSuccessRatio(): Float
|
||||||
|
fun incrementSuccessfulConnectionAttemptsAfterRetries()
|
||||||
|
fun incrementFailedConnectionsAfterRetries()
|
||||||
|
fun updateTimeZone()
|
||||||
|
|
||||||
fun createActiveCommand(
|
fun createActiveCommand(
|
||||||
historyId: String,
|
historyId: String,
|
||||||
|
|
|
@ -23,6 +23,8 @@ import io.reactivex.Single
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZoneOffset
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -114,25 +116,35 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.successfulConnections = value
|
podState.successfulConnections = value
|
||||||
}
|
}
|
||||||
|
|
||||||
override var timeZone: TimeZone
|
override val successfulConnectionAttemptsAfterRetries: Int
|
||||||
get() = TimeZone.getTimeZone(podState.timeZone)
|
@Synchronized
|
||||||
set(tz) {
|
get() = podState.successfulConnectionAttemptsAfterRetries
|
||||||
podState.timeZone = tz.toZoneId().normalized().id
|
|
||||||
store()
|
@Synchronized
|
||||||
}
|
override fun incrementSuccessfulConnectionAttemptsAfterRetries() {
|
||||||
|
podState.successfulConnectionAttemptsAfterRetries++
|
||||||
|
}
|
||||||
|
|
||||||
|
override val failedConnectionsAfterRetries: Int
|
||||||
|
@Synchronized
|
||||||
|
get() = podState.failedConnectionsAfterRetries
|
||||||
|
|
||||||
|
override fun incrementFailedConnectionsAfterRetries() {
|
||||||
|
podState.failedConnectionsAfterRetries++
|
||||||
|
}
|
||||||
|
|
||||||
|
override val timeZoneId: String?
|
||||||
|
get() = podState.timeZone
|
||||||
|
|
||||||
override val sameTimeZone: Boolean
|
override val sameTimeZone: Boolean
|
||||||
get() {
|
get() {
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val currentTimezone = TimeZone.getDefault()
|
val currentTimezone = TimeZone.getDefault()
|
||||||
val currentOffset = currentTimezone.getOffset(now)
|
val currentOffset = currentTimezone.getOffset(now)
|
||||||
val podOffset = timeZone.getOffset(now)
|
val podOffset = podState.timeZoneOffset
|
||||||
logger.debug(
|
logger.debug(
|
||||||
LTag.PUMPCOMM,
|
LTag.PUMPCOMM,
|
||||||
"sameTimeZone currentTimezone=${currentTimezone.getDisplayName(
|
"sameTimeZone " +
|
||||||
true,
|
|
||||||
TimeZone.SHORT
|
|
||||||
)} " +
|
|
||||||
"currentOffset=$currentOffset " +
|
"currentOffset=$currentOffset " +
|
||||||
"podOffset=$podOffset"
|
"podOffset=$podOffset"
|
||||||
)
|
)
|
||||||
|
@ -219,8 +231,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
get() {
|
get() {
|
||||||
val minutesSinceActivation = podState.minutesSinceActivation
|
val minutesSinceActivation = podState.minutesSinceActivation
|
||||||
val activationTime = podState.activationTime
|
val activationTime = podState.activationTime
|
||||||
if ((activationTime != null) && (minutesSinceActivation != null)) {
|
val timeZoneOffset = podState.timeZoneOffset
|
||||||
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(activationTime), timeZone.toZoneId())
|
if ((activationTime != null) && (minutesSinceActivation != null) && (timeZoneOffset != null)) {
|
||||||
|
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(activationTime), ZoneId.ofOffset("", ZoneOffset.ofTotalSeconds(timeZoneOffset / 1000)))
|
||||||
.plusMinutes(minutesSinceActivation.toLong())
|
.plusMinutes(minutesSinceActivation.toLong())
|
||||||
.plus(Duration.ofMillis(System.currentTimeMillis() - lastUpdatedSystem))
|
.plus(Duration.ofMillis(System.currentTimeMillis() - lastUpdatedSystem))
|
||||||
}
|
}
|
||||||
|
@ -229,9 +242,25 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
override val timeDrift: Duration?
|
override val timeDrift: Duration?
|
||||||
get() {
|
get() {
|
||||||
return Duration.between(ZonedDateTime.now(), time)
|
return time?.let {
|
||||||
|
return Duration.between(ZonedDateTime.now(), it)
|
||||||
|
} ?: null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val timeZoneUpdated: Long?
|
||||||
|
get() {
|
||||||
|
return podState.timeZoneUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateTimeZone() {
|
||||||
|
val timeZone = TimeZone.getDefault()
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
|
||||||
|
podState.timeZoneOffset = timeZone.getOffset(now)
|
||||||
|
podState.timeZone = timeZone.id
|
||||||
|
podState.timeZoneUpdated = now
|
||||||
|
}
|
||||||
|
|
||||||
override val expiry: ZonedDateTime?
|
override val expiry: ZonedDateTime?
|
||||||
get() {
|
get() {
|
||||||
val podLifeInHours = podLifeInHours
|
val podLifeInHours = podLifeInHours
|
||||||
|
@ -627,13 +656,10 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun connectionSuccessRatio(): Float {
|
override fun connectionSuccessRatio(): Float {
|
||||||
if (connectionAttempts == 0) {
|
if (failedConnectionsAfterRetries + successfulConnectionAttemptsAfterRetries == 0) {
|
||||||
return 0.0F
|
return 0.0F
|
||||||
} else if (connectionAttempts <= successfulConnections) {
|
|
||||||
// Prevent bogus quality > 1 during initialisation
|
|
||||||
return 1.0F
|
|
||||||
}
|
}
|
||||||
return successfulConnections.toFloat() / connectionAttempts.toFloat()
|
return successfulConnectionAttemptsAfterRetries.toFloat() / (successfulConnectionAttemptsAfterRetries + failedConnectionsAfterRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() {
|
override fun reset() {
|
||||||
|
@ -675,6 +701,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
OmnipodDashPodStateManager.BluetoothConnectionState.DISCONNECTED
|
OmnipodDashPodStateManager.BluetoothConnectionState.DISCONNECTED
|
||||||
var connectionAttempts = 0
|
var connectionAttempts = 0
|
||||||
var successfulConnections = 0
|
var successfulConnections = 0
|
||||||
|
var successfulConnectionAttemptsAfterRetries = 0
|
||||||
|
var failedConnectionsAfterRetries = 0
|
||||||
var messageSequenceNumber: Short = 0
|
var messageSequenceNumber: Short = 0
|
||||||
var sequenceNumberOfLastProgrammingCommand: Short? = null
|
var sequenceNumberOfLastProgrammingCommand: Short? = null
|
||||||
var activationTime: Long? = null
|
var activationTime: Long? = null
|
||||||
|
@ -682,8 +710,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
var bluetoothAddress: String? = null
|
var bluetoothAddress: String? = null
|
||||||
var ltk: ByteArray? = null
|
var ltk: ByteArray? = null
|
||||||
var eapAkaSequenceNumber: Long = 1
|
var eapAkaSequenceNumber: Long = 1
|
||||||
var bolusPulsesRemaining: Short = 0
|
var timeZone: String? = null // TimeZone ID (e.g. "Europe/Amsterdam")
|
||||||
var timeZone: String = "" // TimeZone ID (e.g. "Europe/Amsterdam")
|
var timeZoneOffset: Int? = null
|
||||||
|
var timeZoneUpdated: Long? = null
|
||||||
var alarmSynced: Boolean = false
|
var alarmSynced: Boolean = false
|
||||||
|
|
||||||
var bleVersion: SoftwareVersion? = null
|
var bleVersion: SoftwareVersion? = null
|
||||||
|
|
|
@ -50,6 +50,7 @@ import org.apache.commons.lang3.StringUtils
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
@ -213,6 +214,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
disposables += rxBus
|
disposables += rxBus
|
||||||
.toObservable(EventPumpStatusChanged::class.java)
|
.toObservable(EventPumpStatusChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
|
.delay(30, TimeUnit.MILLISECONDS, aapsSchedulers.main)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
{
|
{
|
||||||
updateBluetoothConnectionStatus(it)
|
updateBluetoothConnectionStatus(it)
|
||||||
|
@ -254,17 +256,18 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
?: PLACEHOLDER
|
?: PLACEHOLDER
|
||||||
|
|
||||||
val connectionSuccessPercentage = podStateManager.connectionSuccessRatio() * 100
|
val connectionSuccessPercentage = podStateManager.connectionSuccessRatio() * 100
|
||||||
|
val connectionAttempts = podStateManager.failedConnectionsAfterRetries + podStateManager.successfulConnectionAttemptsAfterRetries
|
||||||
val successPercentageString = String.format("%.2f %%", connectionSuccessPercentage)
|
val successPercentageString = String.format("%.2f %%", connectionSuccessPercentage)
|
||||||
val quality =
|
val quality =
|
||||||
"${podStateManager.successfulConnections}/${podStateManager.connectionAttempts} :: $successPercentageString"
|
"${podStateManager.successfulConnectionAttemptsAfterRetries}/$connectionAttempts :: $successPercentageString"
|
||||||
bluetoothStatusBinding.omnipodDashBluetoothConnectionQuality.text = quality
|
bluetoothStatusBinding.omnipodDashBluetoothConnectionQuality.text = quality
|
||||||
val connectionStatsColor = when {
|
val connectionStatsColor = when {
|
||||||
connectionSuccessPercentage > 90 ->
|
connectionSuccessPercentage < 70 && podStateManager.successfulConnectionAttemptsAfterRetries > 50 ->
|
||||||
Color.WHITE
|
Color.RED
|
||||||
connectionSuccessPercentage > 60 ->
|
connectionSuccessPercentage < 90 && podStateManager.successfulConnectionAttemptsAfterRetries > 50 ->
|
||||||
Color.YELLOW
|
Color.YELLOW
|
||||||
else ->
|
else ->
|
||||||
Color.RED
|
Color.WHITE
|
||||||
}
|
}
|
||||||
bluetoothStatusBinding.omnipodDashBluetoothConnectionQuality.setTextColor(connectionStatsColor)
|
bluetoothStatusBinding.omnipodDashBluetoothConnectionQuality.setTextColor(connectionStatsColor)
|
||||||
bluetoothStatusBinding.omnipodDashDeliveryStatus.text = podStateManager.deliveryStatus?.let {
|
bluetoothStatusBinding.omnipodDashDeliveryStatus.text = podStateManager.deliveryStatus?.let {
|
||||||
|
@ -303,12 +306,20 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
podStateManager.bluetoothVersion.toString()
|
podStateManager.bluetoothVersion.toString()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Update time on Pod
|
val timeZone = podStateManager.timeZoneId?.let { timeZoneId ->
|
||||||
|
podStateManager.timeZoneUpdated?.let { timeZoneUpdated ->
|
||||||
|
val tz = TimeZone.getTimeZone(timeZoneId)
|
||||||
|
val inDST = tz.inDaylightTime(Date(timeZoneUpdated))
|
||||||
|
val locale = resources.configuration.locales.get(0)
|
||||||
|
tz.getDisplayName(inDST, TimeZone.SHORT, locale)
|
||||||
|
} ?: PLACEHOLDER
|
||||||
|
} ?: PLACEHOLDER
|
||||||
|
|
||||||
podInfoBinding.timeOnPod.text = podStateManager.time?.let {
|
podInfoBinding.timeOnPod.text = podStateManager.time?.let {
|
||||||
rh.gs(
|
rh.gs(
|
||||||
R.string.omnipod_common_time_with_timezone,
|
R.string.omnipod_common_time_with_timezone,
|
||||||
dateUtil.dateAndTimeString(it.toEpochSecond() * 1000),
|
dateUtil.dateAndTimeString(it.toEpochSecond() * 1000),
|
||||||
podStateManager.timeZone.getDisplayName(true, TimeZone.SHORT)
|
timeZone
|
||||||
)
|
)
|
||||||
} ?: PLACEHOLDER
|
} ?: PLACEHOLDER
|
||||||
|
|
||||||
|
|
|
@ -46,4 +46,5 @@
|
||||||
<string name="omnipod_dash_unknown">Unknown state for the command</string>
|
<string name="omnipod_dash_unknown">Unknown state for the command</string>
|
||||||
<string name="omnipod_common_history_tbr_value">Rate: %1$.2f U, duration: %2$d minutes</string>
|
<string name="omnipod_common_history_tbr_value">Rate: %1$.2f U, duration: %2$d minutes</string>
|
||||||
<string name="omnipod_common_history_bolus_value">%1$.2f U</string>
|
<string name="omnipod_common_history_bolus_value">%1$.2f U</string>
|
||||||
|
<string name="dash_bolusdelivering">Delivering %1$.2f U</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -50,7 +50,7 @@ public abstract class ErosPodStateManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void discardState() {
|
public final void discardState() {
|
||||||
this.podState = null;
|
this.podState = new PodState(this.podState.address);
|
||||||
storePodState();
|
storePodState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ErosInitializePodViewModel @Inject constructor(
|
||||||
|
|
||||||
override fun isPodDeactivatable(): Boolean = podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED)
|
override fun isPodDeactivatable(): Boolean = podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED)
|
||||||
|
|
||||||
override fun doExecuteAction(): Single<PumpEnactResult> = Single.just(aapsOmnipodManager.initializePod())
|
override fun doExecuteAction(): Single<PumpEnactResult> = Single.fromCallable { aapsOmnipodManager.initializePod() }
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
override fun getTitleId(): Int = R.string.omnipod_common_pod_activation_wizard_initialize_pod_title
|
override fun getTitleId(): Int = R.string.omnipod_common_pod_activation_wizard_initialize_pod_title
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ErosInsertCannulaViewModel @Inject constructor(
|
||||||
|
|
||||||
override fun isPodDeactivatable(): Boolean = podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED)
|
override fun isPodDeactivatable(): Boolean = podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED)
|
||||||
|
|
||||||
override fun doExecuteAction(): Single<PumpEnactResult> = Single.just(aapsOmnipodManager.insertCannula(profileFunction.getProfile()))
|
override fun doExecuteAction(): Single<PumpEnactResult> = Single.fromCallable { aapsOmnipodManager.insertCannula(profileFunction.getProfile()) }
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
override fun getTitleId(): Int = R.string.omnipod_common_pod_activation_wizard_insert_cannula_title
|
override fun getTitleId(): Int = R.string.omnipod_common_pod_activation_wizard_insert_cannula_title
|
||||||
|
|
|
@ -323,6 +323,7 @@ abstract class PumpPluginAbstract protected constructor(
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||||
return try {
|
return try {
|
||||||
if (detailedBolusInfo.insulin == 0.0 && detailedBolusInfo.carbs == 0.0) {
|
if (detailedBolusInfo.insulin == 0.0 && detailedBolusInfo.carbs == 0.0) {
|
||||||
|
|
Loading…
Reference in a new issue