WIP on implementing OmnipodDashPumpPlugin + some autoformatting

This commit is contained in:
Bart Sopers 2021-03-31 11:18:58 +02:00
parent 811f136830
commit fe9c5d00a7
18 changed files with 469 additions and 86 deletions

View file

@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull;
import info.nightscout.androidaps.queue.commands.CustomCommand;
public final class CommandAcknowledgeAlerts implements CustomCommand {
public final class CommandSilenceAlerts implements CustomCommand {
@NotNull @Override public String getStatusDescription() {
return "ACKNOWLEDGE ALERTS";
}

View file

@ -11,13 +11,23 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
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.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.response.ResponseType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
import info.nightscout.androidaps.queue.commands.CustomCommand
import info.nightscout.androidaps.utils.TimeChangeType
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.Single
import io.reactivex.rxkotlin.blockingSubscribeBy
import io.reactivex.rxkotlin.subscribeBy
import org.json.JSONObject
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@ -25,6 +35,8 @@ import javax.inject.Singleton
class OmnipodDashPumpPlugin @Inject constructor(
private val omnipodManager: OmnipodDashManager,
private val podStateManager: OmnipodDashPodStateManager,
private val sp: SP,
private val profileFunction: ProfileFunction,
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
@ -51,19 +63,17 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
override fun isSuspended(): Boolean {
// TODO
return false
return podStateManager.isSuspended
}
override fun isBusy(): Boolean {
// prevents the queue from executing commands
// TODO
return true
return podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)
}
override fun isConnected(): Boolean {
// TODO
return false
return true
}
override fun isConnecting(): Boolean {
@ -93,40 +103,136 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
override fun getPumpStatus(reason: String) {
// TODO
// TODO history
omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE).blockingSubscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in getPumpStatus: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable)
},
onComplete = {
aapsLogger.debug("getPumpStatus completed")
}
)
}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
// TODO
return PumpEnactResult(injector).success(true).enacted(true)
// TODO history
return Single.create<PumpEnactResult> { source ->
omnipodManager.setBasalProgram(mapProfileToBasalProgram(profile)).subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in setNewBasalProfile: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in setNewBasalProfile", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("setNewBasalProfile completed")
source.onSuccess(PumpEnactResult(injector).success(true).enacted(true))
}
)
}.blockingGet()
}
override fun isThisProfileSet(profile: Profile): Boolean {
// TODO
return true
if (podStateManager.basalProgram == null) {
// We don't have an active Pod. Return true here because the next Pod will use the currently active profile
return true
}
return podStateManager.basalProgram!! == mapProfileToBasalProgram(profile)
}
override fun lastDataTime(): Long {
// TODO
return System.currentTimeMillis()
return podStateManager.lastConnection
}
override val baseBasalRate: Double
get() = 0.0 // TODO
get() {
if (podStateManager.basalProgram == null) {
return 0.0
}
return podStateManager.basalProgram!!.rateAt(Date())
}
override val reservoirLevel: Double
get() = 0.0 // TODO
get() {
if (podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)) {
return 0.0
}
// Omnipod only reports reservoir level when there's < 1023 pulses left
return podStateManager.pulsesRemaining?.let {
it * 0.05
} ?: 75.0
}
override val batteryLevel: Int
// Omnipod Dash doesn't report it's battery level. We return 0 here and hide related fields in the UI
get() = 0
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
// TODO
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
// TODO history
// TODO update Treatments (?)
// TODO bolus progress
// TODO report actual delivered amount after Pod Alarm and bolus cancellation
return Single.create<PumpEnactResult> { source ->
val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false)
omnipodManager.bolus(
detailedBolusInfo.insulin,
bolusBeeps,
bolusBeeps
).subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in deliverTreatment: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in deliverTreatment", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("deliverTreatment completed")
source.onSuccess(
PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(detailedBolusInfo.insulin)
.carbsDelivered(detailedBolusInfo.carbs)
)
}
)
}.blockingGet()
}
override fun stopBolusDelivering() {
// TODO
// TODO history
// TODO update Treatments (?)
omnipodManager.stopBolus().blockingSubscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in stopBolusDelivering: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in stopBolusDelivering", throwable)
},
onComplete = {
aapsLogger.debug("stopBolusDelivering completed")
}
)
}
override fun setTempBasalAbsolute(
@ -135,8 +241,33 @@ class OmnipodDashPumpPlugin @Inject constructor(
profile: Profile,
enforceNew: Boolean
): PumpEnactResult {
// TODO
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
// TODO history
// TODO update Treatments
return Single.create<PumpEnactResult> { source ->
omnipodManager.setTempBasal(
absoluteRate,
durationInMinutes.toShort()
).subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in setTempBasalAbsolute: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in setTempBasalAbsolute", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("setTempBasalAbsolute completed")
source.onSuccess(
PumpEnactResult(injector).success(true).enacted(true).absolute(absoluteRate)
.duration(durationInMinutes)
)
}
)
}.blockingGet()
}
override fun setTempBasalPercent(
@ -157,8 +288,29 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
// TODO
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
// TODO history
// TODO update Treatments
return Single.create<PumpEnactResult> { source ->
omnipodManager.stopTempBasal().subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in cancelTempBasal: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in cancelTempBasal", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("cancelTempBasal completed")
source.onSuccess(
PumpEnactResult(injector).success(true).enacted(true)
)
}
)
}.blockingGet()
}
override fun cancelExtendedBolus(): PumpEnactResult {
@ -183,8 +335,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
override fun serialNumber(): String {
// TODO
return "TODO"
return if (podStateManager.uniqueId == null) {
"n/a" // TODO i18n
} else {
podStateManager.uniqueId.toString()
}
}
override fun shortStatus(veryShort: Boolean): String {
@ -214,11 +369,190 @@ class OmnipodDashPumpPlugin @Inject constructor(
}
override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? {
if (customCommand is CommandSilenceAlerts) {
return silenceAlerts()
}
if (customCommand is CommandSuspendDelivery) {
return suspendDelivery()
}
if (customCommand is CommandResumeDelivery) {
return resumeDelivery()
}
if (customCommand is CommandDeactivatePod) {
return deactivatePod()
}
if (customCommand is CommandHandleTimeChange) {
return handleTimeChange()
}
if (customCommand is CommandUpdateAlertConfiguration) {
return updateAlertConfiguration()
}
if (customCommand is CommandPlayTestBeep) {
return playTestBeep()
}
aapsLogger.warn(LTag.PUMP, "Unsupported custom command: " + customCommand.javaClass.name)
return PumpEnactResult(injector).success(false).enacted(false).comment(
resourceHelper.gs(
R.string.omnipod_common_error_unsupported_custom_command,
customCommand.javaClass.name
)
)
}
private fun silenceAlerts(): PumpEnactResult {
// TODO history
// TODO filter alert types
return podStateManager.activeAlerts?.let {
Single.create<PumpEnactResult> { source ->
omnipodManager.silenceAlerts(it).subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in silenceAlerts: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in silenceAlerts", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("silenceAlerts completed")
source.onSuccess(PumpEnactResult(injector).success(true))
}
)
}.blockingGet()
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No active alerts") // TODO i18n
}
private fun suspendDelivery(): PumpEnactResult {
// TODO history
return Single.create<PumpEnactResult> { source ->
omnipodManager.suspendDelivery().subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in suspendDelivery: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in suspendDelivery", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("suspendDelivery completed")
source.onSuccess(PumpEnactResult(injector).success(true))
}
)
}.blockingGet()
}
private fun resumeDelivery(): PumpEnactResult {
// TODO history
return profileFunction.getProfile()?.let {
Single.create<PumpEnactResult> { source ->
omnipodManager.setBasalProgram(mapProfileToBasalProgram(it)).subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in resumeDelivery: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in resumeDelivery", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("resumeDelivery completed")
source.onSuccess(PumpEnactResult(injector).success(true))
}
)
}.blockingGet()
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n
}
private fun deactivatePod(): PumpEnactResult {
// TODO history
return Single.create<PumpEnactResult> { source ->
omnipodManager.deactivatePod().subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in deactivatePod: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in deactivatePod", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("deactivatePod completed")
source.onSuccess(PumpEnactResult(injector).success(true))
}
)
}.blockingGet()
}
private fun handleTimeChange(): PumpEnactResult {
// TODO
return null
return PumpEnactResult(injector).success(false).enacted(false).comment("NOT IMPLEMENTED")
}
private fun updateAlertConfiguration(): PumpEnactResult {
// TODO
return PumpEnactResult(injector).success(false).enacted(false).comment("NOT IMPLEMENTED")
}
private fun playTestBeep(): PumpEnactResult {
// TODO history
return Single.create<PumpEnactResult> { source ->
omnipodManager.playBeep(BeepType.LONG_SINGLE_BEEP).subscribeBy(
onNext = { podEvent ->
aapsLogger.debug(
LTag.PUMP,
"Received PodEvent in playTestBeep: $podEvent"
)
},
onError = { throwable ->
aapsLogger.error(LTag.PUMP, "Error in playTestBeep", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
},
onComplete = {
aapsLogger.debug("playTestBeep completed")
source.onSuccess(
PumpEnactResult(injector).success(true).enacted(true)
)
}
)
}.blockingGet()
}
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
// TODO
val eventHandlingEnabled = sp.getBoolean(R.string.key_omnipod_common_time_change_event_enabled, false)
aapsLogger.info(
LTag.PUMP,
"Time, Date and/or TimeZone changed. [timeChangeType=" + timeChangeType.name + ", eventHandlingEnabled=" + eventHandlingEnabled + "]"
)
if (timeChangeType == TimeChangeType.TimeChanged) {
aapsLogger.info(LTag.PUMP, "Ignoring time change because it is not a DST or TZ change")
return
} else if (!podStateManager.isPodRunning) {
aapsLogger.info(LTag.PUMP, "Ignoring time change because no Pod is active")
return
}
aapsLogger.info(LTag.PUMP, "Handling time change")
commandQueue.customCommand(CommandHandleTimeChange(false), null)
}
}

View file

@ -26,11 +26,11 @@ interface OmnipodDashManager {
fun setTempBasal(rate: Double, durationInMinutes: Short): Observable<PodEvent>
fun cancelTempBasal(): Observable<PodEvent>
fun stopTempBasal(): Observable<PodEvent>
fun bolus(units: Double, confirmationBeeps: Boolean, completionBeeps: Boolean): Observable<PodEvent>
fun cancelBolus(): Observable<PodEvent>
fun stopBolus(): Observable<PodEvent>
fun playBeep(beepType: BeepType): Observable<PodEvent>

View file

@ -170,6 +170,8 @@ class OmnipodDashManagerImpl @Inject constructor(
.build(),
DefaultStatusResponse::class
)
}.doOnComplete {
podStateManager.basalProgram = basalProgram
}
}
@ -483,7 +485,7 @@ class OmnipodDashManagerImpl @Inject constructor(
.subscribeOn(aapsSchedulers.io)
}
override fun cancelTempBasal(): Observable<PodEvent> {
override fun stopTempBasal(): Observable<PodEvent> {
return Observable.concat(
observePodRunning,
observeConnectToPod,
@ -512,7 +514,7 @@ class OmnipodDashManagerImpl @Inject constructor(
.subscribeOn(aapsSchedulers.io)
}
override fun cancelBolus(): Observable<PodEvent> {
override fun stopBolus(): Observable<PodEvent> {
return Observable.concat(
observePodRunning,
observeConnectToPod,

View file

@ -46,11 +46,13 @@ data class Id(val address: ByteArray) {
companion object {
private const val PERIPHERAL_NODE_INDEX = 1 // TODO: understand the meaning of this value. It comes from preferences
private const val PERIPHERAL_NODE_INDEX =
1 // TODO: understand the meaning of this value. It comes from preferences
fun fromInt(v: Int): Id {
return Id(ByteBuffer.allocate(4).putInt(v).array())
}
fun fromLong(v: Long): Id {
return Id(ByteBuffer.allocate(8).putLong(v).array().copyOfRange(4, 8))
}

View file

@ -16,6 +16,7 @@ class KeyExchange(
var pdmPrivate: ByteArray = X25519.generatePrivateKey(),
val pdmNonce: ByteArray = ByteArray(NONCE_SIZE)
) {
val pdmPublic = X25519.publicFromPrivate(pdmPrivate)
var podPublic = ByteArray(PUBLIC_KEY_SIZE)

View file

@ -50,7 +50,14 @@ sealed class EapAkaAttribute {
EapAkaAttributeType.AT_RAND ->
ret.add(EapAkaAttributeRand.parse(tail.copyOfRange(2, EapAkaAttributeRand.SIZE)))
EapAkaAttributeType.AT_CLIENT_ERROR_CODE ->
ret.add(EapAkaAttributeClientErrorCode.parse(tail.copyOfRange(2, EapAkaAttributeClientErrorCode.SIZE)))
ret.add(
EapAkaAttributeClientErrorCode.parse(
tail.copyOfRange(
2,
EapAkaAttributeClientErrorCode.SIZE
)
)
)
}
tail = tail.copyOfRange(size, tail.size)
}
@ -70,12 +77,14 @@ data class EapAkaAttributeRand(val payload: ByteArray) : EapAkaAttribute() {
}
companion object {
fun parse(payload: ByteArray): EapAkaAttribute {
if (payload.size < 2 + 16) {
throw MessageIOException("Could not parse RAND attribute: ${payload.toHex()}")
}
return EapAkaAttributeRand(payload.copyOfRange(2, 2 + 16))
}
const val SIZE = 20 // type, size, 2 reserved bytes, payload=16
}
}
@ -110,7 +119,12 @@ data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() {
}
override fun toByteArray(): ByteArray {
return byteArrayOf(EapAkaAttributeType.AT_RES.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, PAYLOAD_SIZE_BITS) + payload
return byteArrayOf(
EapAkaAttributeType.AT_RES.type,
(SIZE / SIZE_MULTIPLIER).toByte(),
0,
PAYLOAD_SIZE_BITS
) + payload
}
companion object {
@ -145,6 +159,7 @@ data class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute() {
}
return EapAkaAttributeCustomIV(payload.copyOfRange(2, 2 + 4))
}
const val SIZE = 8 // type, size, 2 reserved bytes, payload=4
}
}
@ -156,7 +171,12 @@ data class EapAkaAttributeClientErrorCode(val payload: ByteArray) : EapAkaAttrib
}
override fun toByteArray(): ByteArray {
return byteArrayOf(EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload
return byteArrayOf(
EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type,
(SIZE / SIZE_MULTIPLIER).toByte(),
0,
0
) + payload
}
companion object {

View file

@ -86,7 +86,11 @@ class SessionEstablisher(
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg")
if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) {
// TODO: special exception for this
throw SessionEstablishmentException("Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${eapMsg.attributes[0].toByteArray().toHex()}")
throw SessionEstablishmentException(
"Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${
eapMsg.attributes[0].toByteArray().toHex()
}"
)
}
throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}")
}

View file

@ -13,7 +13,7 @@ class ProgramInsulinCommand internal constructor(
multiCommandFlag: Boolean,
nonce: Int,
insulinProgramElements:
List<ShortInsulinProgramElement>,
List<ShortInsulinProgramElement>,
private val checksum: Short,
private val byte9: Byte,
private val byte10And11: Short,

View file

@ -47,7 +47,7 @@ interface OmnipodDashPodStateManager {
val tempBasal: TempBasal?
val tempBasalActive: Boolean
val basalProgram: BasalProgram?
var basalProgram: BasalProgram?
fun increaseMessageSequenceNumber()
fun increaseEapAkaSequenceNumber(): ByteArray

View file

@ -35,8 +35,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override var activationProgress: ActivationProgress
get() = podState.activationProgress
set(value) {
podState.activationProgress = value
set(activationProgress) {
podState.activationProgress = activationProgress
store()
}
@ -55,8 +55,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override var lastConnection: Long
get() = podState.lastConnection
set(value) {
podState.lastConnection = value
set(lastConnection) {
podState.lastConnection = lastConnection
store()
}
@ -145,8 +145,12 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override val tempBasalActive: Boolean
get() = tempBasal != null && tempBasal!!.startTime + tempBasal!!.durationInMinutes * 60 * 1000 > System.currentTimeMillis()
override val basalProgram: BasalProgram?
override var basalProgram: BasalProgram?
get() = podState.basalProgram
set(basalProgram) {
podState.basalProgram = basalProgram
store()
}
override fun increaseMessageSequenceNumber() {
podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort()
@ -155,15 +159,15 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override var eapAkaSequenceNumber: Long
get() = podState.eapAkaSequenceNumber
set(value) {
podState.eapAkaSequenceNumber = value
set(eapAkaSequenceNumber) {
podState.eapAkaSequenceNumber = eapAkaSequenceNumber
store()
}
override var ltk: ByteArray?
get() = podState.ltk
set(value) {
podState.ltk = value
set(ltk) {
podState.ltk = ltk
store()
}
@ -183,7 +187,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
podState.deliveryStatus = response.deliveryStatus
podState.podStatus = response.podStatus
podState.pulsesDelivered = response.totalPulsesDelivered
podState.pulsesRemaining = response.reservoirPulsesRemaining
if (response.reservoirPulsesRemaining < 1023) {
podState.pulsesRemaining = response.reservoirPulsesRemaining
}
podState.sequenceNumberOfLastProgrammingCommand = response.sequenceNumberOfLastProgrammingCommand
podState.minutesSinceActivation = response.minutesSinceActivation
podState.activeAlerts = response.activeAlerts

View file

@ -20,6 +20,7 @@ import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.queue.events.EventQueueChanged
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
@ -73,7 +74,6 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() {
}
binding.buttonPlayTestBeep.setOnClickListener {
// TODO
binding.buttonPlayTestBeep.isEnabled = false
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_playing_test_beep)
@ -114,7 +114,33 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() {
}
private fun refreshButtons() {
// TODO update button state from Pod state
// Only show the discard button to reset a cached unique ID before the unique ID has actually been set
// Otherwise, users should use the Deactivate Pod Wizard. In case proper deactivation fails,
// they will get an option to discard the Pod there
val discardButtonEnabled =
podStateManager.uniqueId != null && podStateManager.activationProgress.isBefore(ActivationProgress.SET_UNIQUE_ID)
binding.buttonDiscardPod.visibility = discardButtonEnabled.toVisibility()
binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)
binding.buttonDeactivatePod.isEnabled =
podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) {
if (commandQueue.isCustomCommandInQueue(CommandPlayTestBeep::class.java)) {
binding.buttonPlayTestBeep.isEnabled = false
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_playing_test_beep)
} else {
binding.buttonPlayTestBeep.isEnabled = true
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_play_test_beep)
}
} else {
binding.buttonPlayTestBeep.isEnabled = false
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_play_test_beep)
}
if (discardButtonEnabled) {
binding.buttonDiscardPod.isEnabled = true
}
}
private fun displayErrorDialog(title: String, message: String, @Suppress("SameParameterValue") withSound: Boolean) {

View file

@ -18,7 +18,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
@ -130,7 +130,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
buttonBinding.buttonSilenceAlerts.setOnClickListener {
disablePodActionButtons()
commandQueue.customCommand(
CommandAcknowledgeAlerts(),
CommandSilenceAlerts(),
DisplayResultDialogCallback(
resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts),
false
@ -486,7 +486,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
private fun updateSilenceAlertsButton() {
if (isAutomaticallySilenceAlertsEnabled() && podStateManager.isPodRunning && (podStateManager.activeAlerts!!.size > 0 || commandQueue.isCustomCommandInQueue(
CommandAcknowledgeAlerts::class.java
CommandSilenceAlerts::class.java
))) {
buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE
buttonBinding.buttonSilenceAlerts.isEnabled = isQueueEmpty()

View file

@ -3,40 +3,29 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.deactivat
import androidx.annotation.StringRes
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.common.R
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandDeactivatePod
import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.deactivation.viewmodel.action.DeactivatePodViewModel
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import info.nightscout.androidaps.queue.Callback
import io.reactivex.Single
import io.reactivex.rxkotlin.subscribeBy
import javax.inject.Inject
class DashDeactivatePodViewModel @Inject constructor(
private val omnipodManager: OmnipodDashManager,
private val podStateManager: OmnipodDashPodStateManager,
private val commandQueueProvider: CommandQueueProvider,
injector: HasAndroidInjector,
logger: AAPSLogger
) : DeactivatePodViewModel(injector, logger) {
override fun doExecuteAction(): Single<PumpEnactResult> = Single.create { source ->
omnipodManager.deactivatePod().subscribeBy(
onNext = { podEvent ->
logger.debug(
LTag.PUMP,
"Received PodEvent in Pod deactivation: $podEvent"
)
},
onError = { throwable ->
logger.error(LTag.PUMP, "Error in Pod deactivation", throwable)
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
},
onComplete = {
logger.debug("Pod deactivation completed")
source.onSuccess(PumpEnactResult(injector).success(true))
commandQueueProvider.customCommand(CommandDeactivatePod(), object : Callback() {
override fun run() {
source.onSuccess(result)
}
)
})
}
override fun discardPod() {

View file

@ -14,7 +14,6 @@
android:orientation="vertical">
<TextView
android:id="@+id/omnipod_eros_pod_management_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
@ -119,8 +118,7 @@
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<!-- FIXME visible for development -->
<info.nightscout.androidaps.utils.ui.SingleClickButton
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/button_discard_pod"
style="?android:attr/buttonStyle"
android:layout_width="0dp"
@ -128,7 +126,7 @@
android:drawableTop="@drawable/ic_pod_management_discard_pod"
android:text="@string/omnipod_common_pod_management_button_discard_pod"
android:textAllCaps="false"
android:visibility="visible"
android:visibility="gone"
app:layout_constrainedHeight="@+id/Actions_Row_2_horizontal_guideline"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toRightOf="@+id/Actions_Col_1_Row_2_vertical_guideline"

View file

@ -65,7 +65,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData;
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType;
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts;
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts;
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandDeactivatePod;
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange;
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandPlayTestBeep;
@ -253,7 +253,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
}
if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && podStateManager.isPodActivationCompleted() && !podStateManager.isPodDead() &&
podStateManager.getActiveAlerts().size() > 0 && !getCommandQueue().isCustomCommandInQueue(CommandAcknowledgeAlerts.class)) {
podStateManager.getActiveAlerts().size() > 0 && !getCommandQueue().isCustomCommandInQueue(CommandSilenceAlerts.class)) {
queueAcknowledgeAlertsCommand();
}
} else {
@ -410,7 +410,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
rxBus.send(new EventNewNotification(notification));
nsUpload.uploadError(notificationText);
if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && !getCommandQueue().isCustomCommandInQueue(CommandAcknowledgeAlerts.class)) {
if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && !getCommandQueue().isCustomCommandInQueue(CommandSilenceAlerts.class)) {
queueAcknowledgeAlertsCommand();
}
}
@ -437,7 +437,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
}
private void queueAcknowledgeAlertsCommand() {
getCommandQueue().customCommand(new CommandAcknowledgeAlerts(), new Callback() {
getCommandQueue().customCommand(new CommandSilenceAlerts(), new Callback() {
@Override public void run() {
if (result != null) {
aapsLogger.debug(LTag.PUMP, "Acknowledge alerts result: {} ({})", result.success, result.comment);
@ -827,7 +827,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
@Override
public PumpEnactResult executeCustomCommand(@NonNull CustomCommand command) {
if (command instanceof CommandAcknowledgeAlerts) {
if (command instanceof CommandSilenceAlerts) {
return executeCommand(OmnipodCommandType.ACKNOWLEDGE_ALERTS, aapsOmnipodErosManager::acknowledgeAlerts);
}
if (command instanceof CommandGetPodStatus) {

View file

@ -24,7 +24,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
@ -148,7 +148,8 @@ class OmnipodErosOverviewFragment : DaggerFragment() {
buttonBinding.buttonSilenceAlerts.setOnClickListener {
disablePodActionButtons()
commandQueue.customCommand(CommandAcknowledgeAlerts(),
commandQueue.customCommand(
CommandSilenceAlerts(),
DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts), false)
.messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_silenced_alerts))
.actionOnSuccess { rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_ALERTS)) })
@ -513,7 +514,8 @@ class OmnipodErosOverviewFragment : DaggerFragment() {
}
private fun updateSilenceAlertsButton() {
if (!omnipodManager.isAutomaticallyAcknowledgeAlertsEnabled && podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue(CommandAcknowledgeAlerts::class.java))) {
if (!omnipodManager.isAutomaticallyAcknowledgeAlertsEnabled && podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue(
CommandSilenceAlerts::class.java))) {
buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE
buttonBinding.buttonSilenceAlerts.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty()
} else {

View file

@ -14,7 +14,6 @@
android:orientation="vertical">
<TextView
android:id="@+id/omnipod_eros_pod_management_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
@ -125,7 +124,7 @@
android:orientation="horizontal"
app:layout_constraintGuide_percent="0" />
<info.nightscout.androidaps.utils.ui.SingleClickButton
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/button_play_test_beep"
style="?android:attr/buttonStyle"
android:layout_width="0dp"
@ -256,7 +255,7 @@
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<info.nightscout.androidaps.utils.ui.SingleClickButton
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/button_pulse_log"
style="?android:attr/buttonStyle"
android:layout_width="0dp"