Merge pull request #143 from 0pen-dash/avereha/status

status
This commit is contained in:
Andrei Vereha 2021-10-09 15:20:20 +02:00 committed by GitHub
commit 64e09aadbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 150 additions and 86 deletions

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.text.format.DateFormat
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.activities.ErrorHelperActivity.Companion.runAlarm
import info.nightscout.androidaps.data.DetailedBolusInfo
@ -11,6 +12,9 @@ import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventProfileSwitchChanged
import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.events.EventTempBasalChange
import info.nightscout.androidaps.extensions.convertedToAbsolute
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
import info.nightscout.androidaps.extensions.toStringFull
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
@ -40,6 +44,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.Constants
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
import info.nightscout.androidaps.queue.commands.Command
import info.nightscout.androidaps.queue.commands.CustomCommand
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.TimeChangeType
@ -51,6 +57,7 @@ import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.json.JSONObject
import java.lang.Exception
import java.time.Duration
import java.time.ZonedDateTime
import java.util.*
@ -73,6 +80,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
private val context: Context,
private val aapsSchedulers: AapsSchedulers,
private val fabricPrivacy: FabricPrivacy,
private val dateUtil: DateUtil,
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
@ -84,7 +92,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
private val handler: Handler = Handler(Looper.getMainLooper())
private lateinit var statusChecker: Runnable
var nextPodWarningCheck: Long = 0
private var nextPodWarningCheck: Long = 0
@Volatile var stopConnecting: CountDownLatch? = null
private var disposables: CompositeDisposable = CompositeDisposable()
@ -574,7 +582,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
).filter { podEvent -> podEvent.isCommandSent() }
.map { pumpSyncBolusStart(requestedBolusAmount, detailedBolusInfo.bolusType) }
.ignoreElements(),
post = waitForBolusDeliveryToComplete(BOLUS_RETRIES, requestedBolusAmount, detailedBolusInfo.bolusType)
post = waitForBolusDeliveryToComplete(requestedBolusAmount, detailedBolusInfo.bolusType)
.map {
deliveredBolusAmount = it
aapsLogger.info(LTag.PUMP, "deliverTreatment: deliveredBolusAmount=$deliveredBolusAmount")
@ -638,14 +646,13 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
private fun waitForBolusDeliveryToComplete(
maxTries: Int,
requestedBolusAmount: Double,
bolusType: DetailedBolusInfo.BolusType
): Single<Double> = Single.defer {
if (bolusCanceled && podStateManager.activeCommand != null) {
var errorGettingStatus: Throwable? = null
for (tries in 1..maxTries) {
for (tries in 1..BOLUS_RETRIES) {
errorGettingStatus = getPodStatus().blockingGet()
if (errorGettingStatus != null) {
aapsLogger.debug(LTag.PUMP, "waitForBolusDeliveryToComplete errorGettingStatus=$errorGettingStatus")
@ -676,7 +683,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
)
}
for (tryNumber in 1..maxTries) {
for (tryNumber in 1..BOLUS_RETRIES) {
updateBolusProgressDialog("Checking delivery status", 100)
val cmd = if (bolusCanceled)
@ -731,7 +738,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
requestedBolusAmount: Double,
bolusType: DetailedBolusInfo.BolusType
): Boolean {
require(requestedBolusAmount > 0) {"requestedBolusAmount has to be positive"}
require(requestedBolusAmount > 0) { "requestedBolusAmount has to be positive" }
val activeCommand = podStateManager.activeCommand
if (activeCommand == null) {
@ -778,7 +785,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
)
val ret = executeProgrammingCommand(
pre = observeNoActiveTempBasal(true),
pre = observeNoActiveTempBasal(),
historyEntry = history.createRecord(
commandType = OmnipodCommandType.SET_TEMPORARY_BASAL,
tempBasalRecord = TempBasalRecord(duration = durationInMinutes, rate = absoluteRate)
@ -848,38 +855,28 @@ class OmnipodDashPumpPlugin @Inject constructor(
return ret
}
private fun observeNoActiveTempBasal(enforceNew: Boolean): Completable {
private fun observeNoActiveTempBasal(): Completable {
return Completable.defer {
when {
podStateManager.deliveryStatus !in
arrayOf(DeliveryStatus.TEMP_BASAL_ACTIVE, DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE) -> {
// TODO: what happens if we try to cancel nonexistent temp basal?
aapsLogger.info(LTag.PUMP, "No temporary basal to cancel")
Completable.complete()
}
!enforceNew ->
Completable.error(
IllegalStateException(
"Temporary basal already active and enforceNew is not set."
)
if (podStateManager.deliveryStatus !in
arrayOf(DeliveryStatus.TEMP_BASAL_ACTIVE, DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE)
) {
// TODO: what happens if we try to cancel nonexistent temp basal?
aapsLogger.info(LTag.PUMP, "No temporary basal to cancel")
Completable.complete()
} else {
// enforceNew == true
aapsLogger.info(LTag.PUMP, "Canceling existing temp basal")
executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements()
).doOnComplete {
notifyOnUnconfirmed(
Notification.OMNIPOD_TBR_ALERTS,
"Cancelling temp basal might have failed." +
"If a temp basal was previously running, it might have been cancelled." +
"Please manually refresh the Pod status from the Omnipod tab.", // TODO: i8n
R.raw.boluserror,
)
else -> {
// enforceNew == true
aapsLogger.info(LTag.PUMP, "Canceling existing temp basal")
executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements()
).doOnComplete {
notifyOnUnconfirmed(
Notification.OMNIPOD_TBR_ALERTS,
"Cancelling temp basal might have failed." +
"If a temp basal was previously running, it might have been cancelled." +
"Please manually refresh the Pod status from the Omnipod tab.", // TODO: i8n
R.raw.boluserror,
)
}
}
}
}
@ -954,8 +951,53 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
// TODO
return JSONObject()
val now = System.currentTimeMillis()
if (podStateManager.lastUpdatedSystem + 60 * 60 * 1000L < now) {
return JSONObject()
}
val pumpJson = JSONObject()
val status = JSONObject()
val extended = JSONObject()
try {
val podStatus = when {
podStateManager.isPodRunning && podStateManager.isSuspended ->
"suspended"
podStateManager.isPodRunning ->
"normal"
else ->
"no active Pod"
}
status.put("status", podStatus)
status.put("timestamp", dateUtil.toISOString(podStateManager.lastUpdatedSystem))
extended.put("Version", version)
try {
extended.put("ActiveProfile", profileName)
} catch (ignored: Exception) {
}
val tb = pumpSync.expectedPumpState().temporaryBasal
tb?.run {
extended.put("TempBasalAbsoluteRate", this.convertedToAbsolute(now, profile))
extended.put("TempBasalStart", dateUtil.dateAndTimeString(this.timestamp))
extended.put("TempBasalRemaining", this.plannedRemainingMinutes)
}
podStateManager.lastBolus?.run {
extended.put("LastBolus", dateUtil.dateAndTimeString(this.startTime))
extended.put("LastBolusAmount", this.deliveredUnits() ?: this.requestedUnits)
}
extended.put("BaseBasalRate", baseBasalRate)
pumpJson.put("status", status)
pumpJson.put("extended", extended)
if (podStateManager.pulsesRemaining == null) {
pumpJson.put("reservoir_display_override", "50+")
}
pumpJson.put("reservoir", reservoirLevel.toInt())
pumpJson.put("clock", dateUtil.toISOString(now))
} catch (e: Exception) {
aapsLogger.error(LTag.PUMP, "Unhandled exception: $e")
}
return pumpJson
}
override val pumpDescription: PumpDescription = Companion.pumpDescription
@ -974,8 +1016,33 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
override fun shortStatus(veryShort: Boolean): String {
// TODO
return "TODO"
if (!podStateManager.isActivationCompleted) {
return resourceHelper.gs(R.string.omnipod_common_short_status_no_active_pod)
}
var ret = ""
if (podStateManager.lastUpdatedSystem != 0L) {
val agoMsec: Long = System.currentTimeMillis() - podStateManager.lastUpdatedSystem
val agoMin = (agoMsec / 60.0 / 1000.0).toInt()
ret += resourceHelper.gs(R.string.omnipod_common_short_status_last_connection, agoMin) + "\n"
}
podStateManager.lastBolus?.run {
ret += resourceHelper.gs(
R.string.omnipod_common_short_status_last_bolus, to2Decimal(this.deliveredUnits() ?: this.requestedUnits),
DateFormat.format("HH:mm", Date(this.startTime))
) + "\n"
}
val (temporaryBasal, extendedBolus, _, profile) = pumpSync.expectedPumpState()
temporaryBasal?.run {
ret += resourceHelper.gs(
R.string.omnipod_common_short_status_temp_basal,
this.toStringFull(dateUtil)
) + "\n"
}
ret += resourceHelper.gs(
R.string.omnipod_common_short_status_reservoir,
podStateManager.pulsesRemaining?.let { reservoirLevel.toString() } ?: "50+"
)
return ret.trim()
}
override val isFakingTempsByExtendedBoluses: Boolean
@ -1348,7 +1415,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
pumpId = historyEntry.pumpId(),
pumpType = PumpType.OMNIPOD_DASH,
pumpSerial = serialNumber(),
type = null // TODO: set the correct bolus type here!!!
type = null
)
}
rxBus.send(EventDismissNotification(Notification.OMNIPOD_UNCERTAIN_SMB))
@ -1358,7 +1425,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
if (confirmation.success) {
podStateManager.lastBolus?.run {
val deliveredUnits = markComplete()
if (deliveredUnits < 0){
if (deliveredUnits < 0) {
aapsLogger.error(LTag.PUMP, "Negative delivered units!!! $deliveredUnits")
return
}

View file

@ -9,9 +9,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.*
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.GetVersionCommand.Companion.DEFAULT_UNIQUE_ID
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.MAX_POD_LIFETIME
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS_DURATION
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_IMMINENT_ALERT_HOURS
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.*
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import info.nightscout.androidaps.utils.rx.AapsSchedulers

View file

@ -1,11 +1,10 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
import java.time.Duration
import java.util.concurrent.TimeUnit
class PodConstants {
companion object {
val MAX_POD_LIFETIME : Duration = Duration.ofHours(80)
val MAX_POD_LIFETIME: Duration = Duration.ofHours(80)
// Expiration alert time in minutes since activation and duration in minutes
const val POD_EXPIRATION_ALERT_HOURS = 72L
@ -18,6 +17,6 @@ class PodConstants {
const val POD_PULSE_BOLUS_UNITS = 0.05
// Reservoir units alert threshold
const val DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD : Short = 20
const val DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD: Short = 20
}
}

View file

@ -5,7 +5,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.AlertUtil
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.Flag
import java.nio.ByteBuffer
import java.util.*
import kotlin.experimental.and
@ -20,7 +19,7 @@ class DefaultStatusResponse(
private var last4bytes = ByteBuffer.wrap(byteArrayOf(encoded[6], encoded[7], encoded[8], encoded[9])).int
val podStatus: PodStatus = byValue((encoded[1] and 0x0f), PodStatus.UNKNOWN)
val deliveryStatus: DeliveryStatus = byValue(( (encoded[1].toInt() and 0xff) shr 4 and 0x0f).toByte(), DeliveryStatus.UNKNOWN)
val deliveryStatus: DeliveryStatus = byValue(((encoded[1].toInt() and 0xff) shr 4 and 0x0f).toByte(), DeliveryStatus.UNKNOWN)
val totalPulsesDelivered: Short = (first4bytes ushr 11 ushr 4 and 0x1FFF).toShort()
val sequenceNumberOfLastProgrammingCommand: Short = (first4bytes ushr 11 and 0X0F).toShort()

View file

@ -629,8 +629,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override fun connectionSuccessRatio(): Float {
if (connectionAttempts == 0) {
return 0.0F
}
else if (connectionAttempts <= successfulConnections) {
} else if (connectionAttempts <= successfulConnections) {
// Prevent bogus quality > 1 during initialisation
return 1.0F
}

View file

@ -32,8 +32,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.databinding.OmnipodD
import info.nightscout.androidaps.plugins.pump.omnipod.dash.databinding.OmnipodDashOverviewBluetoothStatusBinding
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.queue.events.EventQueueChanged
import info.nightscout.androidaps.utils.DateUtil

View file

@ -16,4 +16,4 @@ class Flag(var value: Int = 0) {
}
return 1
}
}
}

View file

@ -106,17 +106,17 @@ class DefaultStatusResponseTest {
}
/** response (hex) 1D990714201F0042ED8801DE
Status response: 29
Pod status: RUNNING_BELOW_MIN_VOLUME
Basal active: true
Temp Basal active: false
Immediate bolus active: false
Extended bolus active: true
Bolus pulses remaining: 31
sequence number of last programing command: 4
Total full pulses delivered: 3624
Full reservoir pulses remaining: 392
Time since activation: 4283
Status response: 29
Pod status: RUNNING_BELOW_MIN_VOLUME
Basal active: true
Temp Basal active: false
Immediate bolus active: false
Extended bolus active: true
Bolus pulses remaining: 31
sequence number of last programing command: 4
Total full pulses delivered: 3624
Full reservoir pulses remaining: 392
Time since activation: 4283
*/
@Test @Throws(DecoderException::class) fun testValidResponseReservoirPulsesRemaining() {
val encoded = Hex.decodeHex("1D990714201F0042ED8801DE")
@ -136,17 +136,17 @@ class DefaultStatusResponseTest {
}
/** response (hex) 1d68002601f400002bff0368
Status response: 29
Pod status: RUNNING_BELOW_MIN_VOLUME
Basal active: true
Temp Basal active: false
Immediate bolus active: false
Extended bolus active: true
Bolus pulses remaining: 31
sequence number of last programing command: 4
Total full pulses delivered: 3624
Full reservoir pulses remaining: 392
Time since activation: 4283
Status response: 29
Pod status: RUNNING_BELOW_MIN_VOLUME
Basal active: true
Temp Basal active: false
Immediate bolus active: false
Extended bolus active: true
Bolus pulses remaining: 31
sequence number of last programing command: 4
Total full pulses delivered: 3624
Full reservoir pulses remaining: 392
Time since activation: 4283
*/
@Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining3() {
val encoded = Hex.decodeHex("1d68002601f400002bff0368")
@ -157,17 +157,17 @@ class DefaultStatusResponseTest {
Assert.assertEquals(0, response.activeAlerts.size)
}
/** response (hex) 1d28002e91e400002fff8256
Status response: 29
Pod status: RUNNING_BELOW_MIN_VOLUME
Basal active: true
Temp Basal active: false
Immediate bolus active: false
Extended bolus active: true
Bolus pulses remaining: 31
sequence number of last programing command: 4
Total full pulses delivered: 3624
Full reservoir pulses remaining: 392
Time since activation: 4283
Status response: 29
Pod status: RUNNING_BELOW_MIN_VOLUME
Basal active: true
Temp Basal active: false
Immediate bolus active: false
Extended bolus active: true
Bolus pulses remaining: 31
sequence number of last programing command: 4
Total full pulses delivered: 3624
Full reservoir pulses remaining: 392
Time since activation: 4283
*/
@Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining4() {
val encoded = Hex.decodeHex("1d28002e91e400002fff8256")