Merge pull request #46 from 0pen-dash/avereha/fixes

Avereha/fixes
This commit is contained in:
Andrei Vereha 2021-06-19 16:21:35 +02:00 committed by GitHub
commit d299b03ca2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 266 additions and 109 deletions

View file

@ -344,6 +344,22 @@ interface PumpSync {
**/ **/
fun invalidateTemporaryBasal(id: Long): Boolean fun invalidateTemporaryBasal(id: Long): Boolean
/**
* Invalidate of temporary basals that failed to start
* Dash specific, replace by setting duration to zero ????
*
* If exists, isValid is set false
* If db record doesn't exist data is ignored and false returned
*
*
* @param pumpId pumpId of temporary basal
* @param pumpType pump type like PumpType.ACCU_CHEK_COMBO
* @param pumpSerial pump serial number
* @return true if running record is found and invalidated
**/
fun invalidateTemporaryBasalWithPumpId(pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean
/** /**
* Invalidate of temporary basals that failed to start * Invalidate of temporary basals that failed to start
* MDT specific * MDT specific

View file

@ -330,6 +330,19 @@ class PumpSyncImplementation @Inject constructor(
} }
} }
override fun invalidateTemporaryBasalWithPumpId(pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean {
repository.runTransactionForResult(InvalidateTemporaryBasalTransactionWithPumpId(pumpId, pumpType.toDbPumpType(),
pumpSerial))
.doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating TemporaryBasal", it) }
.blockingGet()
.also { result ->
result.invalidated.forEach {
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
}
return result.invalidated.size > 0
}
}
override fun invalidateTemporaryBasalWithTempId(temporaryId: Long): Boolean { override fun invalidateTemporaryBasalWithTempId(temporaryId: Long): Boolean {
repository.runTransactionForResult(InvalidateTemporaryBasalWithTempIdTransaction(temporaryId)) repository.runTransactionForResult(InvalidateTemporaryBasalWithTempIdTransaction(temporaryId))
.doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating TemporaryBasal", it) } .doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating TemporaryBasal", it) }

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.database.transactions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.TemporaryBasal
class InvalidateTemporaryBasalTransactionWithPumpId(val pumpId: Long, val pumpType: InterfaceIDs.PumpType, val
pumpSerial:
String) :
Transaction<InvalidateTemporaryBasalTransactionWithPumpId.TransactionResult>() {
override fun run(): TransactionResult {
val result = TransactionResult()
val temporaryBasal = database.temporaryBasalDao.findByPumpIds(pumpId, pumpType, pumpSerial)
?: throw IllegalArgumentException("There is no such Temporary Basal with the specified temp ID.")
temporaryBasal.isValid = false
database.temporaryBasalDao.updateExistingEntry(temporaryBasal)
result.invalidated.add(temporaryBasal)
return result
}
class TransactionResult {
val invalidated = mutableListOf<TemporaryBasal>()
}
}

View file

@ -17,7 +17,7 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.* import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.*
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus
@ -57,6 +57,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
private val pumpSync: PumpSync, private val pumpSync: PumpSync,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val aapsSchedulers: AapsSchedulers, private val aapsSchedulers: AapsSchedulers,
private val bleManager: OmnipodDashBleManager,
// private val disposable: CompositeDisposable = CompositeDisposable(), // private val disposable: CompositeDisposable = CompositeDisposable(),
// private val aapsSchedulers: AapsSchedulers, // private val aapsSchedulers: AapsSchedulers,
@ -69,6 +70,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
@Volatile var bolusCanceled = false @Volatile var bolusCanceled = false
companion object { companion object {
private const val BOLUS_RETRY_INTERVAL_MS = 2000.toLong()
private const val BOLUS_RETRIES = 5 // numer of retries for cancel/get bolus status
private val pluginDescription = PluginDescription() private val pluginDescription = PluginDescription()
.mainType(PluginType.PUMP) .mainType(PluginType.PUMP)
@ -97,6 +100,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
} }
override fun isConnected(): Boolean { override fun isConnected(): Boolean {
return true return true
} }
@ -164,9 +168,9 @@ class OmnipodDashPumpPlugin @Inject constructor(
) )
} }
podStateManager.lastBolus?.run { podStateManager.lastBolus?.run {
if (!complete) { if (!deliveryComplete) {
val deliveredUnits = markComplete() val deliveredUnits = markComplete()
complete = true deliveryComplete = true
val bolusHistoryEntry = history.getById(historyId) val bolusHistoryEntry = history.getById(historyId)
val sync = pumpSync.syncBolusWithPumpId( val sync = pumpSync.syncBolusWithPumpId(
timestamp = bolusHistoryEntry.createdAt, timestamp = bolusHistoryEntry.createdAt,
@ -185,7 +189,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
override fun setNewBasalProfile(profile: Profile): PumpEnactResult { override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
if (!podStateManager.isActivationCompleted) { if (!podStateManager.isActivationCompleted) {
return PumpEnactResult(injector).success(true).enacted(false) return PumpEnactResult(injector).success(true).enacted(true)
} }
val basalProgram = mapProfileToBasalProgram(profile) val basalProgram = mapProfileToBasalProgram(profile)
return executeProgrammingCommand( return executeProgrammingCommand(
@ -194,7 +198,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
activeCommandEntry = { historyId -> activeCommandEntry = { historyId ->
podStateManager.createActiveCommand(historyId, basalProgram = basalProgram) podStateManager.createActiveCommand(historyId, basalProgram = basalProgram)
}, },
command = omnipodManager.setBasalProgram(basalProgram).ignoreElements(), command = omnipodManager.setBasalProgram(basalProgram, hasBasalBeepEnabled()).ignoreElements(),
post = failWhenUnconfirmed(), post = failWhenUnconfirmed(),
).toPumpEnactResult() ).toPumpEnactResult()
} }
@ -214,11 +218,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
else else
executeProgrammingCommand( executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY), historyEntry = history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY),
command = omnipodManager.suspendDelivery() command = omnipodManager.suspendDelivery(hasBasalBeepEnabled())
.filter { podEvent -> podEvent is PodEvent.CommandSent } .filter { podEvent -> podEvent.isCommandSent() }
.map { .map {
pumpSyncTempBasal( pumpSyncTempBasal(
it,
0.0, 0.0,
PodConstants.MAX_POD_LIFETIME.standardMinutes, PodConstants.MAX_POD_LIFETIME.standardMinutes,
PumpSync.TemporaryBasalType.PUMP_SUSPEND PumpSync.TemporaryBasalType.PUMP_SUSPEND
@ -290,16 +293,20 @@ class OmnipodDashPumpPlugin @Inject constructor(
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
try { try {
aapsLogger.info(LTag.PUMP, "Delivering treatment: $detailedBolusInfo") aapsLogger.info(LTag.PUMP, "Delivering treatment: $detailedBolusInfo")
val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false) val beepsConfigurationKey = if (detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB)
R.string.key_omnipod_common_smb_beeps_enabled
else
R.string.key_omnipod_common_bolus_beeps_enabled
val bolusBeeps = sp.getBoolean(beepsConfigurationKey, false)
R.string.key_omnipod_common_smb_beeps_enabled
if (detailedBolusInfo.carbs > 0 || if (detailedBolusInfo.carbs > 0 ||
detailedBolusInfo.insulin == 0.0 detailedBolusInfo.insulin == 0.0
) { ) {
// Accept only valid insulin requests
return PumpEnactResult(injector) return PumpEnactResult(injector)
.success(false) .success(false)
.enacted(false) .enacted(false)
.bolusDelivered(0.0) .bolusDelivered(0.0)
.carbsDelivered(0.0)
.comment("Invalid input") .comment("Invalid input")
} }
val requestedBolusAmount = detailedBolusInfo.insulin val requestedBolusAmount = detailedBolusInfo.insulin
@ -308,7 +315,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
.success(false) .success(false)
.enacted(false) .enacted(false)
.bolusDelivered(0.0) .bolusDelivered(0.0)
.carbsDelivered(0.0)
.comment("Not enough insulin in the reservoir") .comment("Not enough insulin in the reservoir")
} }
var deliveredBolusAmount = 0.0 var deliveredBolusAmount = 0.0
@ -336,10 +342,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
detailedBolusInfo.insulin, detailedBolusInfo.insulin,
bolusBeeps, bolusBeeps,
bolusBeeps bolusBeeps
).filter { podEvent -> podEvent is PodEvent.CommandSent } ).filter { podEvent -> podEvent.isCommandSent() }
.map { pumpSyncBolusStart(it, requestedBolusAmount, detailedBolusInfo.bolusType) } .map { pumpSyncBolusStart(requestedBolusAmount, detailedBolusInfo.bolusType) }
.ignoreElements(), .ignoreElements(),
post = waitForBolusDeliveryToComplete(5, requestedBolusAmount, detailedBolusInfo.bolusType) post = waitForBolusDeliveryToComplete(BOLUS_RETRIES, requestedBolusAmount, detailedBolusInfo.bolusType)
.map { .map {
deliveredBolusAmount = it deliveredBolusAmount = it
aapsLogger.info(LTag.PUMP, "deliverTreatment: deliveredBolusAmount=$deliveredBolusAmount") aapsLogger.info(LTag.PUMP, "deliverTreatment: deliveredBolusAmount=$deliveredBolusAmount")
@ -348,7 +354,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
).toSingleDefault( ).toSingleDefault(
PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(deliveredBolusAmount) PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(deliveredBolusAmount)
) )
.onErrorReturnItem(PumpEnactResult(injector).success(false).enacted(false)) .onErrorReturnItem(
// success if canceled
PumpEnactResult(injector).success(bolusCanceled).enacted(false)
)
.blockingGet() .blockingGet()
aapsLogger.info(LTag.PUMP, "deliverTreatment result: $ret") aapsLogger.info(LTag.PUMP, "deliverTreatment result: $ret")
return ret return ret
@ -365,12 +374,37 @@ class OmnipodDashPumpPlugin @Inject constructor(
} }
} }
private fun updateBolusProgressDialog(msg: String, percent: Int) {
val progressUpdateEvent = EventOverviewBolusProgress
val percent = percent
progressUpdateEvent.status = msg
progressUpdateEvent.percent = percent
rxBus.send(progressUpdateEvent)
}
private fun waitForBolusDeliveryToComplete( private fun waitForBolusDeliveryToComplete(
maxRetries: Int, maxRetries: Int,
requestedBolusAmount: Double, requestedBolusAmount: Double,
bolusType: DetailedBolusInfo.BolusType bolusType: DetailedBolusInfo.BolusType
): Single<Double> = Single.defer { ): Single<Double> = Single.defer {
// wait for bolus delivery confirmation, if possible
if (bolusCanceled && podStateManager.activeCommand != null) {
var errorGettingStatus: Throwable? = null
for (tries in 1..maxRetries) {
errorGettingStatus = getPodStatus().blockingGet()
if (errorGettingStatus != null) {
aapsLogger.debug(LTag.PUMP, "waitForBolusDeliveryToComplete errorGettingStatus=$errorGettingStatus")
Thread.sleep(BOLUS_RETRY_INTERVAL_MS) // retry every 2 sec
continue
}
}
if (errorGettingStatus != null) {
// requestedBolusAmount will be updated later, via pumpSync
// This state is: cancellation requested and getPodStatus failed 5 times.
return@defer Single.just(requestedBolusAmount)
}
}
val estimatedDeliveryTimeSeconds = estimateBolusDeliverySeconds(requestedBolusAmount) val estimatedDeliveryTimeSeconds = estimateBolusDeliverySeconds(requestedBolusAmount)
aapsLogger.info(LTag.PUMP, "estimatedDeliveryTimeSeconds: $estimatedDeliveryTimeSeconds") aapsLogger.info(LTag.PUMP, "estimatedDeliveryTimeSeconds: $estimatedDeliveryTimeSeconds")
var waited = 0 var waited = 0
@ -380,57 +414,67 @@ class OmnipodDashPumpPlugin @Inject constructor(
if (bolusType == DetailedBolusInfo.BolusType.SMB) { if (bolusType == DetailedBolusInfo.BolusType.SMB) {
continue continue
} }
val progressUpdateEvent = EventOverviewBolusProgress val percent = waited.toFloat() / estimatedDeliveryTimeSeconds
val percent = (100 * waited) / estimatedDeliveryTimeSeconds updateBolusProgressDialog(resourceHelper.gs(R.string.bolusdelivering, requestedBolusAmount), percent.toInt())
progressUpdateEvent.status = resourceHelper.gs(R.string.bolusdelivering, requestedBolusAmount)
progressUpdateEvent.percent = percent.toInt()
rxBus.send(progressUpdateEvent)
} }
for (tries in 1..maxRetries) { for (tries in 1..maxRetries) {
val errorGettingStatus = getPodStatus().blockingGet() val cmd = if (bolusCanceled)
cancelBolus()
else
getPodStatus()
val errorGettingStatus = cmd.blockingGet()
if (errorGettingStatus != null) { if (errorGettingStatus != null) {
Thread.sleep(3000) // retry every 3 sec aapsLogger.debug(LTag.PUMP, "waitForBolusDeliveryToComplete errorGettingStatus=$errorGettingStatus")
Thread.sleep(BOLUS_RETRY_INTERVAL_MS) // retry every 3 sec
continue continue
} }
if (podStateManager.deliveryStatus in val bolusDeliveringActive = podStateManager.deliveryStatus?.bolusDeliveringActive() ?: false
arrayOf(
DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE, if (bolusDeliveringActive) {
DeliveryStatus.BOLUS_AND_BASAL_ACTIVE
) &&
!bolusCanceled
) {
// delivery not complete yet // delivery not complete yet
val remainingUnits = podStateManager.lastBolus!!.bolusUnitsRemaining val remainingUnits = podStateManager.lastBolus!!.bolusUnitsRemaining
val progressUpdateEvent = EventOverviewBolusProgress
val percent = ((requestedBolusAmount - remainingUnits) / requestedBolusAmount) * 100 val percent = ((requestedBolusAmount - remainingUnits) / requestedBolusAmount) * 100
progressUpdateEvent.status = "Remaining: $remainingUnits units" updateBolusProgressDialog(
progressUpdateEvent.percent = percent.toInt() resourceHelper.gs(R.string.bolusdelivering, requestedBolusAmount),
Thread.sleep(estimateBolusDeliverySeconds(remainingUnits) * 1000.toLong()) percent.toInt()
)
val sleepSeconds = if (bolusCanceled)
BOLUS_RETRY_INTERVAL_MS
else
estimateBolusDeliverySeconds(remainingUnits)
Thread.sleep(sleepSeconds * 1000.toLong())
} else { } else {
// delivery is complete. If pod is Kaput, we are handling this in getPodStatus // delivery is complete. If pod is Kaput, we are handling this in getPodStatus
// TODO: race with cancel!!
return@defer Single.just(podStateManager.lastBolus!!.deliveredUnits()!!) return@defer Single.just(podStateManager.lastBolus!!.deliveredUnits()!!)
} }
} }
Single.just(requestedBolusAmount) // will be updated later! Single.just(requestedBolusAmount) // will be updated later!
} }
private fun cancelBolus(): Completable {
val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false)
return executeProgrammingCommand(
historyEntry = history.createRecord(commandType = OmnipodCommandType.CANCEL_BOLUS),
command = omnipodManager.stopBolus(bolusBeeps).ignoreElements()
)
}
private fun estimateBolusDeliverySeconds(requestedBolusAmount: Double): Long { private fun estimateBolusDeliverySeconds(requestedBolusAmount: Double): Long {
return ceil(requestedBolusAmount / 0.05).toLong() * 2 + 3 return ceil(requestedBolusAmount / 0.05).toLong() * 2 + 3
} }
private fun pumpSyncBolusStart( private fun pumpSyncBolusStart(
podEvent: PodEvent,
requestedBolusAmount: Double, requestedBolusAmount: Double,
bolusType: DetailedBolusInfo.BolusType bolusType: DetailedBolusInfo.BolusType
): Boolean { ): Boolean {
val activeCommand = podStateManager.activeCommand val activeCommand = podStateManager.activeCommand
if (activeCommand == null || podEvent !is PodEvent.CommandSent) { if (activeCommand == null) {
throw IllegalArgumentException( throw IllegalArgumentException(
"No active command or illegal podEvent: " + "No active command or illegal podEvent: " +
"activeCommand=$activeCommand" + "activeCommand=$activeCommand"
"podEvent=$podEvent"
) )
} }
val historyEntry = history.getById(activeCommand.historyId) val historyEntry = history.getById(activeCommand.historyId)
@ -449,18 +493,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
override fun stopBolusDelivering() { override fun stopBolusDelivering() {
aapsLogger.info(LTag.PUMP, "stopBolusDelivering called") aapsLogger.info(LTag.PUMP, "stopBolusDelivering called")
bolusCanceled = true bolusCanceled = true
for (tries in 1..10) {
val ret = executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.CANCEL_BOLUS),
command = omnipodManager.stopBolus().ignoreElements()
).subscribeOn(aapsSchedulers.io) // stopBolusDelivering is executed on the main thread
.toPumpEnactResult()
aapsLogger.info(LTag.PUMP, "stopBolusDelivering finished with result: $ret")
if (ret.success) {
return
}
Thread.sleep(500)
}
} }
override fun setTempBasalAbsolute( override fun setTempBasalAbsolute(
@ -470,7 +502,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
enforceNew: Boolean, enforceNew: Boolean,
tbrType: PumpSync.TemporaryBasalType tbrType: PumpSync.TemporaryBasalType
): PumpEnactResult { ): PumpEnactResult {
val tempBasalBeeps = sp.getBoolean(R.string.key_omnipod_common_tbr_beeps_enabled, false) val tempBasalBeeps = hasTempBasalBeepEnabled()
aapsLogger.info( aapsLogger.info(
LTag.PUMP, LTag.PUMP,
"setTempBasalAbsolute: duration=$durationInMinutes min, rate=$absoluteRate U/h :: " + "setTempBasalAbsolute: duration=$durationInMinutes min, rate=$absoluteRate U/h :: " +
@ -498,30 +530,31 @@ class OmnipodDashPumpPlugin @Inject constructor(
durationInMinutes.toShort(), durationInMinutes.toShort(),
tempBasalBeeps tempBasalBeeps
) )
.filter { podEvent -> podEvent is PodEvent.CommandSent } .filter { podEvent -> podEvent.isCommandSent() }
.map { pumpSyncTempBasal(it, absoluteRate, durationInMinutes.toLong(), tbrType) } .map { pumpSyncTempBasal(absoluteRate, durationInMinutes.toLong(), tbrType) }
.ignoreElements(), .ignoreElements(),
).toPumpEnactResult() ).toPumpEnactResult()
if (ret.success && ret.enacted) {
ret.isPercent(false).absolute(absoluteRate).duration(durationInMinutes)
}
aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute: result=$ret") aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute: result=$ret")
return ret return ret
} }
private fun pumpSyncTempBasal( private fun pumpSyncTempBasal(
podEvent: PodEvent,
absoluteRate: Double, absoluteRate: Double,
durationInMinutes: Long, durationInMinutes: Long,
tbrType: PumpSync.TemporaryBasalType tbrType: PumpSync.TemporaryBasalType
): Boolean { ): Boolean {
val activeCommand = podStateManager.activeCommand val activeCommand = podStateManager.activeCommand
if (activeCommand == null || podEvent !is PodEvent.CommandSent) { if (activeCommand == null) {
throw IllegalArgumentException( throw IllegalArgumentException(
"No active command or illegal podEvent: " + "No active command: " +
"activeCommand=$activeCommand" + "activeCommand=$activeCommand"
"podEvent=$podEvent"
) )
} }
val historyEntry = history.getById(activeCommand.historyId) val historyEntry = history.getById(activeCommand.historyId)
aapsLogger.debug(LTag.PUMP, "pumpSyncTempBasal: absoluteRate=$absoluteRate, durationInMinutes=$durationInMinutes")
val ret = pumpSync.syncTemporaryBasalWithPumpId( val ret = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = historyEntry.createdAt, timestamp = historyEntry.createdAt,
rate = absoluteRate, rate = absoluteRate,
@ -558,7 +591,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
aapsLogger.info(LTag.PUMP, "Canceling existing temp basal") aapsLogger.info(LTag.PUMP, "Canceling existing temp basal")
executeProgrammingCommand( executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL), historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
command = omnipodManager.stopTempBasal().ignoreElements() command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements()
) )
} }
} }
@ -583,20 +616,29 @@ class OmnipodDashPumpPlugin @Inject constructor(
.comment("Omnipod Dash driver does not support extended boluses") .comment("Omnipod Dash driver does not support extended boluses")
} }
private fun hasTempBasalBeepEnabled(): Boolean {
return sp.getBoolean(R.string.key_omnipod_common_tbr_beeps_enabled, false)
}
private fun hasBasalBeepEnabled(): Boolean {
return sp.getBoolean(R.string.key_omnipod_common_basal_beeps_enabled, false)
}
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
if (!podStateManager.tempBasalActive && if (!podStateManager.tempBasalActive &&
pumpSync.expectedPumpState().temporaryBasal == null) { pumpSync.expectedPumpState().temporaryBasal == null
) {
// nothing to cancel // nothing to cancel
return PumpEnactResult(injector).success(true).enacted(false) return PumpEnactResult(injector).success(true).enacted(false)
} }
return executeProgrammingCommand( return executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL), historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
command = omnipodManager.stopTempBasal().ignoreElements(), command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements(),
).toPumpEnactResult() ).toPumpEnactResult()
} }
fun Completable.toPumpEnactResult(): PumpEnactResult { private fun Completable.toPumpEnactResult(): PumpEnactResult {
return this.toSingleDefault(PumpEnactResult(injector).success(true).enacted(true)) return this.toSingleDefault(PumpEnactResult(injector).success(true).enacted(true))
.doOnError { throwable -> .doOnError { throwable ->
aapsLogger.error(LTag.PUMP, "toPumpEnactResult, error executing command: $throwable") aapsLogger.error(LTag.PUMP, "toPumpEnactResult, error executing command: $throwable")
@ -699,11 +741,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
private fun suspendDelivery(): PumpEnactResult { private fun suspendDelivery(): PumpEnactResult {
return executeProgrammingCommand( return executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY), historyEntry = history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY),
command = omnipodManager.suspendDelivery() command = omnipodManager.suspendDelivery(hasBasalBeepEnabled())
.filter { podEvent -> podEvent is PodEvent.CommandSent } .filter { podEvent -> podEvent.isCommandSent() }
.map { .map {
pumpSyncTempBasal( pumpSyncTempBasal(
it,
0.0, 0.0,
PodConstants.MAX_POD_LIFETIME.standardMinutes, PodConstants.MAX_POD_LIFETIME.standardMinutes,
PumpSync.TemporaryBasalType.PUMP_SUSPEND PumpSync.TemporaryBasalType.PUMP_SUSPEND
@ -726,16 +767,20 @@ class OmnipodDashPumpPlugin @Inject constructor(
executeProgrammingCommand( executeProgrammingCommand(
pre = observeDeliverySuspended(), pre = observeDeliverySuspended(),
historyEntry = history.createRecord(OmnipodCommandType.RESUME_DELIVERY), historyEntry = history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
command = omnipodManager.setBasalProgram(mapProfileToBasalProgram(it)).ignoreElements() command = omnipodManager.setBasalProgram(mapProfileToBasalProgram(it), hasBasalBeepEnabled()).ignoreElements()
).toPumpEnactResult() ).toPumpEnactResult()
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n } ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n
} }
private fun deactivatePod(): PumpEnactResult { private fun deactivatePod(): PumpEnactResult {
return executeProgrammingCommand( val ret = executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.DEACTIVATE_POD), historyEntry = history.createRecord(OmnipodCommandType.DEACTIVATE_POD),
command = omnipodManager.deactivatePod().ignoreElements() command = omnipodManager.deactivatePod().ignoreElements()
).toPumpEnactResult() ).toPumpEnactResult()
if (podStateManager.activeCommand != null) {
ret.success(false)
}
return ret
} }
private fun handleTimeChange(): PumpEnactResult { private fun handleTimeChange(): PumpEnactResult {
@ -783,11 +828,12 @@ class OmnipodDashPumpPlugin @Inject constructor(
{ historyId -> podStateManager.createActiveCommand(historyId) }, { historyId -> podStateManager.createActiveCommand(historyId) },
command: Completable, command: Completable,
post: Completable = Completable.complete(), post: Completable = Completable.complete(),
checkNoActiveCommand: Boolean = true
): Completable { ): Completable {
return Completable.concat( return Completable.concat(
listOf( listOf(
pre, pre,
podStateManager.observeNoActiveCommand().ignoreElements(), podStateManager.observeNoActiveCommand(checkNoActiveCommand).ignoreElements(),
historyEntry historyEntry
.flatMap { activeCommandEntry(it) } .flatMap { activeCommandEntry(it) }
.ignoreElement(), .ignoreElement(),
@ -847,7 +893,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
// This treatment was synced before sending the command // This treatment was synced before sending the command
if (!confirmation.success) { if (!confirmation.success) {
aapsLogger.info(LTag.PUMPCOMM, "temporary basal denied. PumpId: ${historyEntry.pumpId()}") aapsLogger.info(LTag.PUMPCOMM, "temporary basal denied. PumpId: ${historyEntry.pumpId()}")
pumpSync.invalidateTemporaryBasal(historyEntry.pumpId()) pumpSync.invalidateTemporaryBasalWithPumpId(
historyEntry.pumpId(),
PumpType.OMNIPOD_DASH,
serialNumber()
)
} else { } else {
podStateManager.tempBasal = command.tempBasal podStateManager.tempBasal = command.tempBasal
} }
@ -855,7 +905,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
OmnipodCommandType.SUSPEND_DELIVERY -> { OmnipodCommandType.SUSPEND_DELIVERY -> {
if (!confirmation.success) { if (!confirmation.success) {
pumpSync.invalidateTemporaryBasal(historyEntry.pumpId()) pumpSync.invalidateTemporaryBasalWithPumpId(historyEntry.pumpId(), PumpType.OMNIPOD_DASH, serialNumber())
} else { } else {
podStateManager.tempBasal = null podStateManager.tempBasal = null
} }
@ -916,7 +966,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
aapsLogger.warn( aapsLogger.warn(
LTag.PUMP, LTag.PUMP,
"Will not sync confirmed command of type: $historyEntry and " + "Will not sync confirmed command of type: $historyEntry and " +
"succes: ${confirmation.success}" "success: ${confirmation.success}"
) )
} }
} }

View file

@ -18,19 +18,19 @@ interface OmnipodDashManager {
fun getStatus(type: ResponseType.StatusResponseType): Observable<PodEvent> fun getStatus(type: ResponseType.StatusResponseType): Observable<PodEvent>
fun setBasalProgram(basalProgram: BasalProgram): Observable<PodEvent> fun setBasalProgram(basalProgram: BasalProgram, hasBasalBeepEnabled: Boolean): Observable<PodEvent>
fun suspendDelivery(): Observable<PodEvent> fun suspendDelivery(hasBasalBeepEnabled: Boolean): Observable<PodEvent>
fun setTime(): 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(): Observable<PodEvent> fun stopTempBasal(hasTempBasalBeepEnabled: Boolean): Observable<PodEvent>
fun bolus(units: Double, confirmationBeeps: Boolean, completionBeeps: Boolean): Observable<PodEvent> fun bolus(units: Double, confirmationBeeps: Boolean, completionBeeps: Boolean): Observable<PodEvent>
fun stopBolus(): Observable<PodEvent> fun stopBolus(beep: Boolean): Observable<PodEvent>
fun playBeep(beepType: BeepType): Observable<PodEvent> fun playBeep(beepType: BeepType): Observable<PodEvent>

View file

@ -157,7 +157,7 @@ class OmnipodDashManagerImpl @Inject constructor(
} }
} }
private fun observeSendProgramBasalCommand(basalProgram: BasalProgram): Observable<PodEvent> { private fun observeSendProgramBasalCommand(basalProgram: BasalProgram, hasBasalBeepEnabled: Boolean): Observable<PodEvent> {
return Observable.defer { return Observable.defer {
val currentTime = Date() val currentTime = Date()
logger.debug(LTag.PUMPCOMM, "Programming basal. currentTime={}, basalProgram={}", currentTime, basalProgram) logger.debug(LTag.PUMPCOMM, "Programming basal. currentTime={}, basalProgram={}", currentTime, basalProgram)
@ -166,7 +166,7 @@ class OmnipodDashManagerImpl @Inject constructor(
.setUniqueId(podStateManager.uniqueId!!.toInt()) .setUniqueId(podStateManager.uniqueId!!.toInt())
.setSequenceNumber(podStateManager.messageSequenceNumber) .setSequenceNumber(podStateManager.messageSequenceNumber)
.setNonce(NONCE) .setNonce(NONCE)
.setProgramReminder(ProgramReminder(atStart = false, atEnd = false, atInterval = 0)) .setProgramReminder(ProgramReminder(atStart = hasBasalBeepEnabled, atEnd = false, atInterval = 0))
.setBasalProgram(basalProgram) .setBasalProgram(basalProgram)
.setCurrentTime(currentTime) .setCurrentTime(currentTime)
.build(), .build(),
@ -399,7 +399,7 @@ class OmnipodDashManagerImpl @Inject constructor(
} }
if (podStateManager.activationProgress.isBefore(ActivationProgress.PROGRAMMED_BASAL)) { if (podStateManager.activationProgress.isBefore(ActivationProgress.PROGRAMMED_BASAL)) {
observables.add( observables.add(
observeSendProgramBasalCommand(basalProgram) observeSendProgramBasalCommand(basalProgram, false)
.doOnComplete(ActivationProgressUpdater(ActivationProgress.PROGRAMMED_BASAL)) .doOnComplete(ActivationProgressUpdater(ActivationProgress.PROGRAMMED_BASAL))
) )
} }
@ -419,11 +419,11 @@ class OmnipodDashManagerImpl @Inject constructor(
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
} }
override fun setBasalProgram(basalProgram: BasalProgram): Observable<PodEvent> { override fun setBasalProgram(basalProgram: BasalProgram, hasBasalBeepEnabled: Boolean): Observable<PodEvent> {
return Observable.concat( return Observable.concat(
observePodRunning, observePodRunning,
observeConnectToPod, observeConnectToPod,
observeSendProgramBasalCommand(basalProgram) observeSendProgramBasalCommand(basalProgram, hasBasalBeepEnabled)
) )
// TODO these would be common for any observable returned in a public function in this class // TODO these would be common for any observable returned in a public function in this class
.doOnNext(PodEventInterceptor()) .doOnNext(PodEventInterceptor())
@ -431,25 +431,34 @@ class OmnipodDashManagerImpl @Inject constructor(
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
} }
private fun observeSendStopDeliveryCommand(deliveryType: StopDeliveryCommand.DeliveryType): Observable<PodEvent> { private fun observeSendStopDeliveryCommand(
deliveryType: StopDeliveryCommand.DeliveryType,
beepEnabled: Boolean
): Observable<PodEvent> {
return Observable.defer { return Observable.defer {
val beepType = if (!beepEnabled)
BeepType.SILENT
else
BeepType.LONG_SINGLE_BEEP
bleManager.sendCommand( bleManager.sendCommand(
StopDeliveryCommand.Builder() StopDeliveryCommand.Builder()
.setSequenceNumber(podStateManager.messageSequenceNumber) .setSequenceNumber(podStateManager.messageSequenceNumber)
.setUniqueId(podStateManager.uniqueId!!.toInt()) .setUniqueId(podStateManager.uniqueId!!.toInt())
.setNonce(NONCE) .setNonce(NONCE)
.setDeliveryType(deliveryType) .setDeliveryType(deliveryType)
.setBeepType(beepType)
.build(), .build(),
DefaultStatusResponse::class DefaultStatusResponse::class
) )
} }
} }
override fun suspendDelivery(): Observable<PodEvent> { override fun suspendDelivery(hasBasalBeepEnabled: Boolean): Observable<PodEvent> {
return Observable.concat( return Observable.concat(
observePodRunning, observePodRunning,
observeConnectToPod, observeConnectToPod,
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.ALL) observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.ALL, hasBasalBeepEnabled)
) )
// TODO these would be common for any observable returned in a public function in this class // TODO these would be common for any observable returned in a public function in this class
.doOnNext(PodEventInterceptor()) .doOnNext(PodEventInterceptor())
@ -491,11 +500,11 @@ class OmnipodDashManagerImpl @Inject constructor(
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
} }
override fun stopTempBasal(): Observable<PodEvent> { override fun stopTempBasal(hasTempBasalBeepEnabled: Boolean): Observable<PodEvent> {
return Observable.concat( return Observable.concat(
observePodRunning, observePodRunning,
observeConnectToPod, observeConnectToPod,
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.TEMP_BASAL) observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.TEMP_BASAL, hasTempBasalBeepEnabled)
) )
// TODO these would be common for any observable returned in a public function in this class // TODO these would be common for any observable returned in a public function in this class
.doOnNext(PodEventInterceptor()) .doOnNext(PodEventInterceptor())
@ -520,11 +529,11 @@ class OmnipodDashManagerImpl @Inject constructor(
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
} }
override fun stopBolus(): Observable<PodEvent> { override fun stopBolus(beep: Boolean): Observable<PodEvent> {
return Observable.concat( return Observable.concat(
observePodRunning, observePodRunning,
observeConnectToPod, observeConnectToPod,
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.BOLUS) observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.BOLUS, beep)
) )
// TODO these would be common for any observable returned in a public function in this class // TODO these would be common for any observable returned in a public function in this class
.doOnNext(PodEventInterceptor()) .doOnNext(PodEventInterceptor())

View file

@ -44,6 +44,14 @@ class OmnipodDashBleManagerImpl @Inject constructor(
val session = assertSessionEstablished() val session = assertSessionEstablished()
emitter.onNext(PodEvent.CommandSending(cmd)) emitter.onNext(PodEvent.CommandSending(cmd))
/*
if (Random.nextBoolean()) {
// XXX use this to test "failed to confirm" commands
emitter.onNext(PodEvent.CommandSendNotConfirmed(cmd))
emitter.tryOnError(MessageIOException("XXX random failure to test unconfirmed commands"))
return@create
}
*/
when (session.sendCommand(cmd)) { when (session.sendCommand(cmd)) {
is CommandSendErrorSending -> { is CommandSendErrorSending -> {
emitter.tryOnError(CouldNotSendCommandException()) emitter.tryOnError(CouldNotSendCommandException())
@ -55,7 +63,12 @@ class OmnipodDashBleManagerImpl @Inject constructor(
is CommandSendErrorConfirming -> is CommandSendErrorConfirming ->
emitter.onNext(PodEvent.CommandSendNotConfirmed(cmd)) emitter.onNext(PodEvent.CommandSendNotConfirmed(cmd))
} }
/*
if (Random.nextBoolean()) {
// XXX use this commands confirmed with success
emitter.tryOnError(MessageIOException("XXX random failure to test unconfirmed commands"))
return@create
}*/
when (val readResult = session.readAndAckResponse(responseType)) { when (val readResult = session.readAndAckResponse(responseType)) {
is CommandReceiveSuccess -> is CommandReceiveSuccess ->
emitter.onNext(PodEvent.ResponseReceived(cmd, readResult.result)) emitter.onNext(PodEvent.ResponseReceived(cmd, readResult.result))
@ -84,7 +97,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
} }
override fun getStatus(): ConnectionState { override fun getStatus(): ConnectionState {
return connection?.let { getStatus() } return connection?.let { it.connectionState() }
?: NotConnected ?: NotConnected
} }

View file

@ -65,4 +65,8 @@ sealed class PodEvent {
return "ResponseReceived(command=$command, response=$response)" return "ResponseReceived(command=$command, response=$response)"
} }
} }
fun isCommandSent(): Boolean {
return this is CommandSent || this is CommandSendNotConfirmed
}
} }

View file

@ -11,4 +11,16 @@ enum class DeliveryStatus(override val value: Byte) : HasValue {
BOLUS_AND_BASAL_ACTIVE(0x05.toByte()), BOLUS_AND_BASAL_ACTIVE(0x05.toByte()),
BOLUS_AND_TEMP_BASAL_ACTIVE(0x06.toByte()), BOLUS_AND_TEMP_BASAL_ACTIVE(0x06.toByte()),
UNKNOWN(0xff.toByte()); UNKNOWN(0xff.toByte());
fun bolusDeliveringActive(): Boolean {
return value in arrayOf(BOLUS_AND_BASAL_ACTIVE.value, BOLUS_AND_TEMP_BASAL_ACTIVE.value)
}
fun tempBasalActive(): Boolean {
return value in arrayOf(BOLUS_AND_TEMP_BASAL_ACTIVE.value, TEMP_BASAL_ACTIVE.value)
}
fun suspended(): Boolean {
return value == SUSPENDED.value
}
} }

View file

@ -84,7 +84,7 @@ interface OmnipodDashPodStateManager {
requestedBolus: Double? = null requestedBolus: Double? = null
): Single<ActiveCommand> ): Single<ActiveCommand>
fun updateActiveCommand(): Maybe<CommandConfirmed> fun updateActiveCommand(): Maybe<CommandConfirmed>
fun observeNoActiveCommand(): Observable<PodEvent> fun observeNoActiveCommand(b: Boolean): Observable<PodEvent>
fun getCommandConfirmationFromState(): CommandConfirmationFromState fun getCommandConfirmationFromState(): CommandConfirmationFromState
fun createLastBolus(requestedUnits: Double, historyId: String, bolusType: DetailedBolusInfo.BolusType) fun createLastBolus(requestedUnits: Double, historyId: String, bolusType: DetailedBolusInfo.BolusType)
@ -108,13 +108,13 @@ interface OmnipodDashPodStateManager {
val startTime: Long, val startTime: Long,
val requestedUnits: Double, val requestedUnits: Double,
var bolusUnitsRemaining: Double, var bolusUnitsRemaining: Double,
var complete: Boolean, var deliveryComplete: Boolean,
val historyId: String, val historyId: String,
val bolusType: DetailedBolusInfo.BolusType val bolusType: DetailedBolusInfo.BolusType
) { ) {
fun deliveredUnits(): Double? { fun deliveredUnits(): Double? {
return if (complete) { return if (deliveryComplete) {
requestedUnits - bolusUnitsRemaining requestedUnits - bolusUnitsRemaining
} else { } else {
null null
@ -122,7 +122,7 @@ interface OmnipodDashPodStateManager {
} }
fun markComplete(): Double { fun markComplete(): Double {
this.complete = true this.deliveryComplete = true
return requestedUnits - bolusUnitsRemaining return requestedUnits - bolusUnitsRemaining
} }
} }

View file

@ -208,7 +208,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
startTime = System.currentTimeMillis(), startTime = System.currentTimeMillis(),
requestedUnits = requestedUnits, requestedUnits = requestedUnits,
bolusUnitsRemaining = requestedUnits, bolusUnitsRemaining = requestedUnits,
complete = false, // cancelled, delivered 100% or pod failure deliveryComplete = false, // cancelled, delivered 100% or pod failure
historyId = historyId, historyId = historyId,
bolusType = bolusType bolusType = bolusType
) )
@ -219,7 +219,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
val lastBolus = podState.lastBolus val lastBolus = podState.lastBolus
lastBolus?.run { lastBolus?.run {
this.complete = true this.deliveryComplete = true
} }
?: logger.error(LTag.PUMP, "Trying to mark null bolus as complete") ?: logger.error(LTag.PUMP, "Trying to mark null bolus as complete")
@ -231,7 +231,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
val remainingUnits = bolusPulsesRemaining.toDouble() * 0.05 val remainingUnits = bolusPulsesRemaining.toDouble() * 0.05
this.bolusUnitsRemaining = remainingUnits this.bolusUnitsRemaining = remainingUnits
if (remainingUnits == 0.0) { if (remainingUnits == 0.0) {
this.complete = true this.deliveryComplete = true
} }
} }
} }
@ -269,9 +269,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
} }
@Synchronized @Synchronized
override fun observeNoActiveCommand(): Observable<PodEvent> { override fun observeNoActiveCommand(check: Boolean): Observable<PodEvent> {
return Observable.defer { return Observable.defer {
if (activeCommand == null) { if (activeCommand == null || !check) {
Observable.empty() Observable.empty()
} else { } else {
logger.warn(LTag.PUMP, "Active command already existing: $activeCommand") logger.warn(LTag.PUMP, "Active command already existing: $activeCommand")
@ -427,6 +427,11 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
podState.uniqueId = response.uniqueIdReceivedInCommand podState.uniqueId = response.uniqueIdReceivedInCommand
podState.lastUpdatedSystem = System.currentTimeMillis() podState.lastUpdatedSystem = System.currentTimeMillis()
// TODO: what is considered to be the pod activation time?
// LTK negotiation ?
// setUniqueId?
// compute it from the number of "minutesOnPod"?
podState.activationTime = System.currentTimeMillis()
store() store()
rxBus.send(EventOmnipodDashPumpValuesChanged()) rxBus.send(EventOmnipodDashPumpValuesChanged())

View file

@ -14,6 +14,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.activati
import info.nightscout.androidaps.plugins.pump.omnipod.dash.R import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
import info.nightscout.androidaps.plugins.pump.omnipod.dash.databinding.OmnipodDashPodManagementBinding import info.nightscout.androidaps.plugins.pump.omnipod.dash.databinding.OmnipodDashPodManagementBinding
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.activation.DashPodActivationWizardActivity import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.activation.DashPodActivationWizardActivity
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.deactivation.DashPodDeactivationWizardActivity import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.deactivation.DashPodDeactivationWizardActivity
@ -124,7 +125,8 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() {
binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED) binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)
binding.buttonDeactivatePod.isEnabled = binding.buttonDeactivatePod.isEnabled =
podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) ||
podStateManager.podStatus == PodStatus.ALARM
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) { if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) {
if (commandQueue.isCustomCommandInQueue(CommandPlayTestBeep::class.java)) { if (commandQueue.isCustomCommandInQueue(CommandPlayTestBeep::class.java)) {

View file

@ -24,6 +24,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.Comm
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig
import info.nightscout.androidaps.plugins.pump.omnipod.dash.EventOmnipodDashPumpValuesChanged import info.nightscout.androidaps.plugins.pump.omnipod.dash.EventOmnipodDashPumpValuesChanged
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.dash.R import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
@ -274,6 +275,13 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
*/ */
// TODO // TODO
if (podStateManager.activeCommand != null) {
podInfoBinding.podExpiryDate.setTextColor(Color.RED)
podInfoBinding.podExpiryDate.text = "Active command"
} else {
podInfoBinding.podExpiryDate.text = PLACEHOLDER
podInfoBinding.podExpiryDate.setTextColor(Color.WHITE)
}
/* /*
val expiresAt = podStateManager.expiresAt val expiresAt = podStateManager.expiresAt
@ -409,8 +417,9 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
resourceHelper.gs(R.string.omnipod_common_pod_status_suspended) resourceHelper.gs(R.string.omnipod_common_pod_status_suspended)
} else { } else {
resourceHelper.gs(R.string.omnipod_common_pod_status_running) + resourceHelper.gs(R.string.omnipod_common_pod_status_running) +
if (BuildConfig.DEBUG)
podStateManager.deliveryStatus?.let { " " + podStateManager.deliveryStatus.toString() } podStateManager.deliveryStatus?.let { " " + podStateManager.deliveryStatus.toString() }
// TODO Display deliveryStatus in a nice way else ""
} }
// TODO // TODO
/* /*
@ -465,7 +474,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
resourceHelper.gs(R.string.insulin_unit_shortname), resourceHelper.gs(R.string.insulin_unit_shortname),
readableDuration(Duration(it.startTime, System.currentTimeMillis())) readableDuration(Duration(it.startTime, System.currentTimeMillis()))
) )
if (!it.complete) { if (!it.deliveryComplete) {
textColor = Color.YELLOW textColor = Color.YELLOW
} }
podInfoBinding.lastBolus.text = text podInfoBinding.lastBolus.text = text
@ -554,9 +563,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
private fun updateSuspendDeliveryButton() { private fun updateSuspendDeliveryButton() {
// If the Pod is currently suspended, we show the Resume delivery button instead. // If the Pod is currently suspended, we show the Resume delivery button instead.
// TODO: isSuspendDeliveryButtonEnabled doesn't work if (isSuspendDeliveryButtonEnabled() &&
val isSuspendDeliveryButtonEnabled = true
if (isSuspendDeliveryButtonEnabled &&
podStateManager.isPodRunning && podStateManager.isPodRunning &&
(!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java)) (!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java))
) { ) {
@ -585,7 +592,8 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
} }
private fun isSuspendDeliveryButtonEnabled(): Boolean { private fun isSuspendDeliveryButtonEnabled(): Boolean {
return sp.getBoolean(R.string.omnipod_common_preferences_suspend_delivery_button_enabled, false) R.string.key_omnipod_common_basal_beeps_enabled
return sp.getBoolean(R.string.key_omnipod_common_suspend_delivery_button_enabled, false)
} }
private fun displayErrorDialog(title: String, message: String, withSound: Boolean) { private fun displayErrorDialog(title: String, message: String, withSound: Boolean) {