commit
1c33b84bbf
|
@ -3,9 +3,11 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult
|
import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
|
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.common.ManufacturerType
|
import info.nightscout.androidaps.plugins.common.ManufacturerType
|
||||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
||||||
|
@ -15,7 +17,10 @@ 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.event.PodEvent
|
||||||
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.BasalProgram
|
||||||
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.PodConstants
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.CommandConfirmed
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.CommandConfirmed
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
|
@ -25,6 +30,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusTy
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.TempBasalRecord
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.TempBasalRecord
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
|
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.queue.commands.CustomCommand
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import info.nightscout.androidaps.utils.TimeChangeType
|
import info.nightscout.androidaps.utils.TimeChangeType
|
||||||
|
@ -48,6 +54,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val history: DashHistory,
|
private val history: DashHistory,
|
||||||
private val pumpSync: PumpSync,
|
private val pumpSync: PumpSync,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
|
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
|
@ -83,23 +91,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isConnected(): Boolean {
|
override fun isConnected(): Boolean {
|
||||||
// NOTE: Using connected state for unconfirmed commands
|
return true
|
||||||
|
|
||||||
// We are faking connection lost on unconfirmed commands.
|
|
||||||
// During normal execution, the activeCommand is set to null after a command was executed with success or we
|
|
||||||
// were not able to send that command.
|
|
||||||
// If we are not sure if the POD received the command or not, then we answer with "success" but keep this
|
|
||||||
// activeCommand set until we can confirm/deny it.
|
|
||||||
|
|
||||||
// In order to prevent AAPS from sending us other programming commands while the current command was not
|
|
||||||
// confirmed, we are simulating "connection lost".
|
|
||||||
// We need to prevent AAPS from sending other commands because they would overwrite the ID of the last
|
|
||||||
// programming command reported by the POD. And we using that ID to confirm/deny the activeCommand.
|
|
||||||
|
|
||||||
// The effect of answering with 'false' here is that AAPS will call connect() and will not sent any new
|
|
||||||
// commands. On connect(), we are calling getPodStatus where we are always trying to confirm/deny the
|
|
||||||
// activeCommand.
|
|
||||||
return podStateManager.activeCommand == null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isConnecting(): Boolean {
|
override fun isConnecting(): Boolean {
|
||||||
|
@ -117,12 +109,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun connect(reason: String) {
|
override fun connect(reason: String) {
|
||||||
// See:
|
// empty on purpose
|
||||||
// NOTE: Using connected state for unconfirmed commands
|
|
||||||
if (podStateManager.activeCommand == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
getPumpStatus("unconfirmed command")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun disconnect(reason: String) {
|
override fun disconnect(reason: String) {
|
||||||
|
@ -134,38 +121,81 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPumpStatus(reason: String) {
|
override fun getPumpStatus(reason: String) {
|
||||||
Observable.concat(
|
val throwable = Completable.concat(listOf(
|
||||||
omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE),
|
omnipodManager
|
||||||
history.updateFromState(podStateManager).toObservable(),
|
.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE)
|
||||||
podStateManager.updateActiveCommand().toObservable(),
|
.ignoreElements(),
|
||||||
).blockingSubscribeBy(
|
history.updateFromState(podStateManager),
|
||||||
onNext = { podEvent ->
|
podStateManager.updateActiveCommand()
|
||||||
aapsLogger.debug(
|
.map { handleCommandConfirmation(it) }
|
||||||
LTag.PUMP,
|
.ignoreElement(),
|
||||||
"Received PodEvent in getPumpStatus: $podEvent"
|
)).blockingGet()
|
||||||
)
|
if (throwable != null){
|
||||||
},
|
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable)
|
||||||
onError = { throwable ->
|
} else {
|
||||||
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable)
|
aapsLogger.info(LTag.PUMP, "getPumpStatus executed with success")
|
||||||
},
|
|
||||||
onComplete = {
|
}
|
||||||
aapsLogger.debug("getPumpStatus completed")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||||
|
val basalProgram = mapProfileToBasalProgram(profile)
|
||||||
return executeSimpleProgrammingCommand(
|
return executeSimpleProgrammingCommand(
|
||||||
history.createRecord(
|
pre = suspendDeliveryIfActive(),
|
||||||
commandType = OmnipodCommandType.SET_BASAL_PROFILE
|
historyEntry = history.createRecord(commandType = OmnipodCommandType.SET_BASAL_PROFILE),
|
||||||
),
|
command = omnipodManager.setBasalProgram(basalProgram).ignoreElements(),
|
||||||
omnipodManager.setBasalProgram(mapProfileToBasalProgram(profile)).ignoreElements()
|
basalProgram = basalProgram,
|
||||||
|
post = failWhenUnconfirmed(),
|
||||||
).toPumpEnactResult()
|
).toPumpEnactResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isThisProfileSet(profile: Profile): Boolean = podStateManager.basalProgram?.let {
|
private fun failWhenUnconfirmed(): Completable = Completable.defer{
|
||||||
it == mapProfileToBasalProgram(profile)
|
if (podStateManager.activeCommand != null) {
|
||||||
} ?: true
|
Completable.error(java.lang.IllegalStateException("Command not confirmed"))
|
||||||
|
}else {
|
||||||
|
Completable.complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun suspendDeliveryIfActive(): Completable = Completable.defer {
|
||||||
|
if (podStateManager.deliveryStatus == DeliveryStatus.SUSPENDED)
|
||||||
|
Completable.complete()
|
||||||
|
else
|
||||||
|
executeSimpleProgrammingCommand(
|
||||||
|
history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY),
|
||||||
|
omnipodManager.suspendDelivery()
|
||||||
|
.filter { podEvent -> podEvent is PodEvent.CommandSent }
|
||||||
|
.map {
|
||||||
|
pumpSyncTempBasal(
|
||||||
|
it,
|
||||||
|
0.0,
|
||||||
|
PodConstants.MAX_POD_LIFETIME.standardMinutes,
|
||||||
|
PumpSync.TemporaryBasalType.PUMP_SUSPEND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.ignoreElements(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeDeliverySuspended(): Completable = Completable.defer {
|
||||||
|
if (podStateManager.deliveryStatus == DeliveryStatus.SUSPENDED)
|
||||||
|
Completable.complete()
|
||||||
|
else {
|
||||||
|
Completable.error(java.lang.IllegalStateException("Expected suspended delivery"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||||
|
if (!podStateManager.isActivationCompleted) {
|
||||||
|
// prevent setBasal requests
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// TODO: what do we have to answer here if delivery is suspended?
|
||||||
|
val running = podStateManager.basalProgram
|
||||||
|
val equal = (mapProfileToBasalProgram(profile) == running)
|
||||||
|
aapsLogger.info(LTag.PUMP, "isThisProfileSet: $equal")
|
||||||
|
return equal
|
||||||
|
}
|
||||||
|
|
||||||
override fun lastDataTime(): Long {
|
override fun lastDataTime(): Long {
|
||||||
return podStateManager.lastUpdatedSystem
|
return podStateManager.lastUpdatedSystem
|
||||||
|
@ -270,7 +300,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
tempBasalBeeps
|
tempBasalBeeps
|
||||||
)
|
)
|
||||||
.filter { podEvent -> podEvent is PodEvent.CommandSent }
|
.filter { podEvent -> podEvent is PodEvent.CommandSent }
|
||||||
.map { pumpSyncTempBasal(it, tbrType) }
|
.map { pumpSyncTempBasal(it, absoluteRate, durationInMinutes.toLong(), tbrType) }
|
||||||
.ignoreElements(),
|
.ignoreElements(),
|
||||||
pre = observeNoActiveTempBasal()
|
pre = observeNoActiveTempBasal()
|
||||||
).toPumpEnactResult()
|
).toPumpEnactResult()
|
||||||
|
@ -278,6 +308,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
private fun pumpSyncTempBasal(
|
private fun pumpSyncTempBasal(
|
||||||
podEvent: PodEvent,
|
podEvent: PodEvent,
|
||||||
|
absoluteRate: Double,
|
||||||
|
durationInMinutes: Long,
|
||||||
tbrType: PumpSync.TemporaryBasalType
|
tbrType: PumpSync.TemporaryBasalType
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val activeCommand = podStateManager.activeCommand
|
val activeCommand = podStateManager.activeCommand
|
||||||
|
@ -289,14 +321,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val historyEntry = history.getById(activeCommand.historyId)
|
val historyEntry = history.getById(activeCommand.historyId)
|
||||||
val record = historyEntry.record
|
|
||||||
if (record == null || !(record is TempBasalRecord)) {
|
|
||||||
throw IllegalArgumentException("Illegal recording in history: $record. Expected a temp basal")
|
|
||||||
}
|
|
||||||
val ret = pumpSync.syncTemporaryBasalWithPumpId(
|
val ret = pumpSync.syncTemporaryBasalWithPumpId(
|
||||||
timestamp = historyEntry.createdAt,
|
timestamp = historyEntry.createdAt,
|
||||||
rate = record.rate,
|
rate = absoluteRate,
|
||||||
duration = T.mins(record.duration.toLong()).msecs(),
|
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||||
isAbsolute = true,
|
isAbsolute = true,
|
||||||
type = tbrType,
|
type = tbrType,
|
||||||
pumpId = historyEntry.pumpId(),
|
pumpId = historyEntry.pumpId(),
|
||||||
|
@ -325,8 +354,9 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeActiveTempBasal(): Completable {
|
private fun observeActiveTempBasal(): Completable {
|
||||||
|
|
||||||
return Completable.defer {
|
return Completable.defer {
|
||||||
if (podStateManager.tempBasalActive)
|
if (podStateManager.tempBasalActive || pumpSync.expectedPumpState().temporaryBasal != null)
|
||||||
Completable.complete()
|
Completable.complete()
|
||||||
else
|
else
|
||||||
Completable.error(
|
Completable.error(
|
||||||
|
@ -369,36 +399,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
.blockingGet()
|
.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleCommandConfirmation(confirmation: CommandConfirmed) {
|
|
||||||
val historyEntry = history.getById(confirmation.historyId)
|
|
||||||
when (historyEntry.commandType) {
|
|
||||||
OmnipodCommandType.CANCEL_TEMPORARY_BASAL ->
|
|
||||||
// We can't invalidate this command,
|
|
||||||
// and this is why it is pumpSync-ed at this point
|
|
||||||
if (confirmation.success) {
|
|
||||||
pumpSync.syncStopTemporaryBasalWithPumpId(
|
|
||||||
historyEntry.createdAt,
|
|
||||||
historyEntry.pumpId(),
|
|
||||||
PumpType.OMNIPOD_DASH,
|
|
||||||
serialNumber()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
OmnipodCommandType.SET_TEMPORARY_BASAL ->
|
|
||||||
// This treatment was synced before sending the command
|
|
||||||
if (!confirmation.success) {
|
|
||||||
// TODO: the ID here is the temp basal id, not the pumpId!!
|
|
||||||
pumpSync.invalidateTemporaryBasal(historyEntry.pumpId())
|
|
||||||
}
|
|
||||||
|
|
||||||
else ->
|
|
||||||
aapsLogger.warn(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Will not sync confirmed command of type: $historyEntry and " +
|
|
||||||
"succes: ${confirmation.success}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||||
// TODO i18n
|
// TODO i18n
|
||||||
return PumpEnactResult(injector).success(false).enacted(false)
|
return PumpEnactResult(injector).success(false).enacted(false)
|
||||||
|
@ -515,16 +515,35 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
private fun suspendDelivery(): PumpEnactResult {
|
private fun suspendDelivery(): PumpEnactResult {
|
||||||
return executeSimpleProgrammingCommand(
|
return executeSimpleProgrammingCommand(
|
||||||
history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
|
historyEntry = history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY),
|
||||||
omnipodManager.suspendDelivery().ignoreElements()
|
command = omnipodManager.suspendDelivery()
|
||||||
|
.filter { podEvent -> podEvent is PodEvent.CommandSent }
|
||||||
|
.map {
|
||||||
|
pumpSyncTempBasal(
|
||||||
|
it,
|
||||||
|
0.0,
|
||||||
|
PodConstants.MAX_POD_LIFETIME.standardMinutes,
|
||||||
|
PumpSync.TemporaryBasalType.PUMP_SUSPEND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.ignoreElements(),
|
||||||
|
pre = observeDeliveryActive(),
|
||||||
).toPumpEnactResult()
|
).toPumpEnactResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeDeliveryActive(): Completable = Completable.defer {
|
||||||
|
if (podStateManager.deliveryStatus != DeliveryStatus.SUSPENDED)
|
||||||
|
Completable.complete()
|
||||||
|
else
|
||||||
|
Completable.error(java.lang.IllegalStateException("Expected active delivery"))
|
||||||
|
}
|
||||||
|
|
||||||
private fun resumeDelivery(): PumpEnactResult {
|
private fun resumeDelivery(): PumpEnactResult {
|
||||||
return profileFunction.getProfile()?.let {
|
return profileFunction.getProfile()?.let {
|
||||||
executeSimpleProgrammingCommand(
|
executeSimpleProgrammingCommand(
|
||||||
history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
|
history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
|
||||||
omnipodManager.setBasalProgram(mapProfileToBasalProgram(it)).ignoreElements()
|
omnipodManager.setBasalProgram(mapProfileToBasalProgram(it)).ignoreElements(),
|
||||||
|
pre = observeDeliverySuspended(),
|
||||||
).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
|
||||||
}
|
}
|
||||||
|
@ -578,13 +597,15 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
historyEntry: Single<String>,
|
historyEntry: Single<String>,
|
||||||
command: Completable,
|
command: Completable,
|
||||||
pre: Completable = Completable.complete(),
|
pre: Completable = Completable.complete(),
|
||||||
|
basalProgram: BasalProgram? = null,
|
||||||
|
post: Completable = Completable.complete(),
|
||||||
): Completable {
|
): Completable {
|
||||||
return Completable.concat(
|
return Completable.concat(
|
||||||
listOf(
|
listOf(
|
||||||
pre,
|
pre,
|
||||||
podStateManager.observeNoActiveCommand().ignoreElements(),
|
podStateManager.observeNoActiveCommand().ignoreElements(),
|
||||||
historyEntry
|
historyEntry
|
||||||
.flatMap { podStateManager.createActiveCommand(it) }
|
.flatMap { podStateManager.createActiveCommand(it, basalProgram) }
|
||||||
.ignoreElement(),
|
.ignoreElement(),
|
||||||
command.doOnError {
|
command.doOnError {
|
||||||
podStateManager.activeCommand?.sendError = it
|
podStateManager.activeCommand?.sendError = it
|
||||||
|
@ -593,8 +614,69 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
history.updateFromState(podStateManager),
|
history.updateFromState(podStateManager),
|
||||||
podStateManager.updateActiveCommand()
|
podStateManager.updateActiveCommand()
|
||||||
.map { handleCommandConfirmation(it) }
|
.map { handleCommandConfirmation(it) }
|
||||||
.ignoreElement()
|
.ignoreElement(),
|
||||||
|
post,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleCommandConfirmation(confirmation: CommandConfirmed) {
|
||||||
|
val command = confirmation.command
|
||||||
|
val historyEntry = history.getById(command.historyId)
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "handling command confirmation: $confirmation")
|
||||||
|
when (historyEntry.commandType) {
|
||||||
|
OmnipodCommandType.CANCEL_TEMPORARY_BASAL,
|
||||||
|
OmnipodCommandType.RESUME_DELIVERY ->
|
||||||
|
// We can't invalidate this command,
|
||||||
|
// and this is why it is pumpSync-ed at this point
|
||||||
|
if (confirmation.success) {
|
||||||
|
pumpSync.syncStopTemporaryBasalWithPumpId(
|
||||||
|
historyEntry.createdAt,
|
||||||
|
historyEntry.pumpId(),
|
||||||
|
PumpType.OMNIPOD_DASH,
|
||||||
|
serialNumber()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
OmnipodCommandType.SET_BASAL_PROFILE -> {
|
||||||
|
if (confirmation.success) {
|
||||||
|
podStateManager.basalProgram = command.basalProgram
|
||||||
|
if (podStateManager.basalProgram == null) {
|
||||||
|
aapsLogger.warn(LTag.PUMP, "Saving null basal profile")
|
||||||
|
}
|
||||||
|
if (!commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) {
|
||||||
|
// we are late-confirming this command. before that, we answered with success:false
|
||||||
|
rxBus.send(EventProfileSwitchChanged())
|
||||||
|
}
|
||||||
|
pumpSync.syncStopTemporaryBasalWithPumpId(
|
||||||
|
historyEntry.createdAt,
|
||||||
|
historyEntry.pumpId(),
|
||||||
|
PumpType.OMNIPOD_DASH,
|
||||||
|
serialNumber()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OmnipodCommandType.SET_TEMPORARY_BASAL -> {
|
||||||
|
// This treatment was synced before sending the command
|
||||||
|
aapsLogger.info(LTag.PUMPCOMM, "temporary basal denied. PumpId: ${historyEntry.pumpId()}")
|
||||||
|
if (!confirmation.success) {
|
||||||
|
pumpSync.invalidateTemporaryBasal(historyEntry.pumpId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OmnipodCommandType.SUSPEND_DELIVERY -> {
|
||||||
|
if (!confirmation.success) {
|
||||||
|
pumpSync.invalidateTemporaryBasal(historyEntry.pumpId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else ->
|
||||||
|
aapsLogger.warn(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Will not sync confirmed command of type: $historyEntry and " +
|
||||||
|
"succes: ${confirmation.success}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.Reusable
|
import dagger.Reusable
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.DashHistory
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.DashHistory
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.DashHistoryDatabase
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.DashHistoryDatabase
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.HistoryRecordDao
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.HistoryRecordDao
|
||||||
|
@ -28,6 +29,6 @@ class OmnipodDashHistoryModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
internal fun provideDashHistory(dao: HistoryRecordDao, historyMapper: HistoryMapper) =
|
internal fun provideDashHistory(dao: HistoryRecordDao, historyMapper: HistoryMapper, logger: AAPSLogger) =
|
||||||
DashHistory(dao, historyMapper)
|
DashHistory(dao, historyMapper, logger)
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
DefaultStatusResponse::class
|
DefaultStatusResponse::class
|
||||||
)
|
)
|
||||||
}.doOnComplete {
|
}.doOnComplete {
|
||||||
|
// TODO: remove podStateManager.basalProgram?
|
||||||
podStateManager.basalProgram = basalProgram
|
podStateManager.basalProgram = basalProgram
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,6 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
?: Connection(podDevice, aapsLogger, context, podState)
|
?: Connection(podDevice, aapsLogger, context, podState)
|
||||||
connection = conn
|
connection = conn
|
||||||
if (conn.connectionState() is Connected) {
|
if (conn.connectionState() is Connected) {
|
||||||
podState.lastConnection = System.currentTimeMillis()
|
|
||||||
if (conn.session == null) {
|
if (conn.session == null) {
|
||||||
emitter.onNext(PodEvent.EstablishingSession)
|
emitter.onNext(PodEvent.EstablishingSession)
|
||||||
establishSession(1.toByte())
|
establishSession(1.toByte())
|
||||||
|
@ -116,7 +115,6 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
conn.connect()
|
conn.connect()
|
||||||
emitter.onNext(PodEvent.BluetoothConnected(podAddress))
|
emitter.onNext(PodEvent.BluetoothConnected(podAddress))
|
||||||
podState.lastConnection = System.currentTimeMillis()
|
|
||||||
emitter.onNext(PodEvent.EstablishingSession)
|
emitter.onNext(PodEvent.EstablishingSession)
|
||||||
establishSession(1.toByte())
|
establishSession(1.toByte())
|
||||||
emitter.onNext(PodEvent.Connected)
|
emitter.onNext(PodEvent.Connected)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||||
|
|
||||||
|
class CouldNotReadResponse
|
|
@ -17,7 +17,15 @@ class BasalProgram(
|
||||||
|
|
||||||
fun isZeroBasal() = segments.sumBy(Segment::basalRateInHundredthUnitsPerHour) == 0
|
fun isZeroBasal() = segments.sumBy(Segment::basalRateInHundredthUnitsPerHour) == 0
|
||||||
|
|
||||||
fun rateAt(date: Date): Double = 0.0 // TODO
|
fun rateAt(date: Date): Double {
|
||||||
|
val instance = Calendar.getInstance()
|
||||||
|
instance.time = date
|
||||||
|
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
||||||
|
val minuteOfHour = instance[Calendar.MINUTE]
|
||||||
|
val slotIndex = hourOfDay * 2 + minuteOfHour.div(30)
|
||||||
|
val slot = segments.find { it.startSlotIndex <= slotIndex && slotIndex< it.endSlotIndex }
|
||||||
|
return (slot?.basalRateInHundredthUnitsPerHour ?: 0).toDouble() / 100
|
||||||
|
}
|
||||||
|
|
||||||
class Segment(
|
class Segment(
|
||||||
val startSlotIndex: Short,
|
val startSlotIndex: Short,
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
import org.joda.time.Duration
|
||||||
|
|
||||||
|
class PodConstants {
|
||||||
|
companion object {
|
||||||
|
val MAX_POD_LIFETIME = Duration.standardHours(80)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
||||||
|
|
||||||
class CommandConfirmed(val historyId: String, val success: Boolean)
|
data class CommandConfirmed(val command: OmnipodDashPodStateManager.ActiveCommand, val success: Boolean)
|
||||||
|
|
|
@ -14,6 +14,13 @@ import io.reactivex.Single
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
sealed class CommandConfirmationFromState
|
||||||
|
object CommandSendingFailure : CommandConfirmationFromState()
|
||||||
|
object CommandSendingNotConfirmed : CommandConfirmationFromState()
|
||||||
|
object CommandConfirmationDenied : CommandConfirmationFromState()
|
||||||
|
object CommandConfirmationSuccess : CommandConfirmationFromState()
|
||||||
|
object NoActiveCommand : CommandConfirmationFromState()
|
||||||
|
|
||||||
interface OmnipodDashPodStateManager {
|
interface OmnipodDashPodStateManager {
|
||||||
|
|
||||||
var activationProgress: ActivationProgress
|
var activationProgress: ActivationProgress
|
||||||
|
@ -21,7 +28,6 @@ interface OmnipodDashPodStateManager {
|
||||||
val isActivationCompleted: Boolean
|
val isActivationCompleted: Boolean
|
||||||
val isSuspended: Boolean
|
val isSuspended: Boolean
|
||||||
val isPodRunning: Boolean
|
val isPodRunning: Boolean
|
||||||
var lastConnection: Long
|
|
||||||
var bluetoothConnectionState: BluetoothConnectionState
|
var bluetoothConnectionState: BluetoothConnectionState
|
||||||
|
|
||||||
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
||||||
|
@ -67,9 +73,10 @@ interface OmnipodDashPodStateManager {
|
||||||
fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
|
fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
|
||||||
fun reset()
|
fun reset()
|
||||||
|
|
||||||
fun createActiveCommand(historyId: String): Single<ActiveCommand>
|
fun createActiveCommand(historyId: String, basalProgram: BasalProgram? = null): Single<ActiveCommand>
|
||||||
fun updateActiveCommand(): Maybe<CommandConfirmed>
|
fun updateActiveCommand(): Maybe<CommandConfirmed>
|
||||||
fun observeNoActiveCommand(): Observable<PodEvent>
|
fun observeNoActiveCommand(): Observable<PodEvent>
|
||||||
|
fun getCommandConfirmationFromState(): CommandConfirmationFromState
|
||||||
|
|
||||||
data class ActiveCommand(
|
data class ActiveCommand(
|
||||||
val sequence: Short,
|
val sequence: Short,
|
||||||
|
@ -77,6 +84,7 @@ interface OmnipodDashPodStateManager {
|
||||||
var sentRealtime: Long = 0,
|
var sentRealtime: Long = 0,
|
||||||
val historyId: String,
|
val historyId: String,
|
||||||
var sendError: Throwable?,
|
var sendError: Throwable?,
|
||||||
|
var basalProgram: BasalProgram?
|
||||||
)
|
)
|
||||||
// TODO: set created to "now" on boot
|
// TODO: set created to "now" on boot
|
||||||
data class TempBasal(val startTime: Long, val rate: Double, val durationInMinutes: Short) : Serializable
|
data class TempBasal(val startTime: Long, val rate: Double, val durationInMinutes: Short) : Serializable
|
||||||
|
|
|
@ -53,18 +53,11 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
override val isSuspended: Boolean
|
override val isSuspended: Boolean
|
||||||
get() = podState.deliveryStatus?.equals(DeliveryStatus.SUSPENDED)
|
get() = podState.deliveryStatus?.equals(DeliveryStatus.SUSPENDED)
|
||||||
?: true
|
?: false
|
||||||
|
|
||||||
override val isPodRunning: Boolean
|
override val isPodRunning: Boolean
|
||||||
get() = podState.podStatus?.isRunning() ?: false
|
get() = podState.podStatus?.isRunning() ?: false
|
||||||
|
|
||||||
override var lastConnection: Long
|
|
||||||
get() = podState.lastConnection
|
|
||||||
set(lastConnection) {
|
|
||||||
podState.lastConnection = lastConnection
|
|
||||||
store()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val lastUpdatedSystem: Long
|
override val lastUpdatedSystem: Long
|
||||||
get() = podState.lastUpdatedSystem
|
get() = podState.lastUpdatedSystem
|
||||||
|
|
||||||
|
@ -148,7 +141,11 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
get() = podState.tempBasal
|
get() = podState.tempBasal
|
||||||
|
|
||||||
override val tempBasalActive: Boolean
|
override val tempBasalActive: Boolean
|
||||||
get() = podState.deliveryStatus in arrayOf(DeliveryStatus.TEMP_BASAL_ACTIVE, DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE)
|
get() = podState.deliveryStatus in
|
||||||
|
arrayOf(
|
||||||
|
DeliveryStatus.TEMP_BASAL_ACTIVE,
|
||||||
|
DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE
|
||||||
|
)
|
||||||
|
|
||||||
override var basalProgram: BasalProgram?
|
override var basalProgram: BasalProgram?
|
||||||
get() = podState.basalProgram
|
get() = podState.basalProgram
|
||||||
|
@ -191,27 +188,29 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
get() = podState.activeCommand
|
get() = podState.activeCommand
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun createActiveCommand(historyId: String): Single<OmnipodDashPodStateManager.ActiveCommand> {
|
override fun createActiveCommand(historyId: String, basalProgram: BasalProgram?):
|
||||||
return Single.create { source ->
|
Single<OmnipodDashPodStateManager.ActiveCommand> {
|
||||||
if (activeCommand == null) {
|
return Single.create { source ->
|
||||||
val command = OmnipodDashPodStateManager.ActiveCommand(
|
if (activeCommand == null) {
|
||||||
podState.messageSequenceNumber,
|
val command = OmnipodDashPodStateManager.ActiveCommand(
|
||||||
createdRealtime = SystemClock.elapsedRealtime(),
|
podState.messageSequenceNumber,
|
||||||
historyId = historyId,
|
createdRealtime = SystemClock.elapsedRealtime(),
|
||||||
sendError = null,
|
historyId = historyId,
|
||||||
)
|
sendError = null,
|
||||||
podState.activeCommand = command
|
basalProgram = basalProgram,
|
||||||
source.onSuccess(command)
|
|
||||||
} else {
|
|
||||||
source.onError(
|
|
||||||
java.lang.IllegalStateException(
|
|
||||||
"Trying to send a command " +
|
|
||||||
"and the last command was not confirmed"
|
|
||||||
)
|
)
|
||||||
)
|
podState.activeCommand = command
|
||||||
|
source.onSuccess(command)
|
||||||
|
} else {
|
||||||
|
source.onError(
|
||||||
|
java.lang.IllegalStateException(
|
||||||
|
"Trying to send a command " +
|
||||||
|
"and the last command was not confirmed"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun observeNoActiveCommand(): Observable<PodEvent> {
|
override fun observeNoActiveCommand(): Observable<PodEvent> {
|
||||||
|
@ -231,34 +230,72 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun updateActiveCommand() = Maybe.create<CommandConfirmed> { source ->
|
override fun updateActiveCommand() = Maybe.create<CommandConfirmed> { source ->
|
||||||
podState.activeCommand?.run {
|
val activeCommand = podState.activeCommand
|
||||||
logger.debug(
|
if (activeCommand == null) {
|
||||||
"Trying to confirm active command with parameters: $activeCommand " +
|
logger.error("No active command to update")
|
||||||
"lastResponse=$lastStatusResponseReceived " +
|
source.onComplete()
|
||||||
"$sequenceNumberOfLastProgrammingCommand $historyId"
|
return@create
|
||||||
)
|
}
|
||||||
|
val cmdConfirmation = getCommandConfirmationFromState()
|
||||||
if (sentRealtime < createdRealtime) { // command was not sent, clear it up
|
logger.info(LTag.PUMPCOMM, "Update active command with confirmation: $cmdConfirmation")
|
||||||
|
when (cmdConfirmation) {
|
||||||
|
CommandSendingFailure -> {
|
||||||
podState.activeCommand = null
|
podState.activeCommand = null
|
||||||
source.onError(
|
source.onError(
|
||||||
this.sendError
|
activeCommand?.sendError
|
||||||
?: java.lang.IllegalStateException(
|
?: java.lang.IllegalStateException(
|
||||||
"Could not send command and sendError is " +
|
"Could not send command and sendError is " +
|
||||||
"missing"
|
"missing"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else if (createdRealtime >= lastStatusResponseReceived)
|
|
||||||
// we did not receive a valid response yet
|
|
||||||
source.onComplete()
|
|
||||||
else {
|
|
||||||
podState.activeCommand = null
|
|
||||||
if (sequenceNumberOfLastProgrammingCommand == sequence)
|
|
||||||
source.onSuccess(CommandConfirmed(historyId, true))
|
|
||||||
else
|
|
||||||
source.onSuccess(CommandConfirmed(historyId, false))
|
|
||||||
}
|
}
|
||||||
} ?: source.onComplete()
|
|
||||||
// no active programming command
|
CommandSendingNotConfirmed -> {
|
||||||
|
// we did not receive a valid response yet
|
||||||
|
source.onComplete()
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandConfirmationDenied -> {
|
||||||
|
podState.activeCommand = null
|
||||||
|
source.onSuccess(CommandConfirmed(activeCommand, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandConfirmationSuccess -> {
|
||||||
|
podState.activeCommand = null
|
||||||
|
|
||||||
|
source.onSuccess(CommandConfirmed(activeCommand, true))
|
||||||
|
}
|
||||||
|
|
||||||
|
NoActiveCommand -> {
|
||||||
|
source.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun getCommandConfirmationFromState(): CommandConfirmationFromState {
|
||||||
|
return podState.activeCommand?.run {
|
||||||
|
logger.debug(
|
||||||
|
"Getting command state with parameters: $activeCommand " +
|
||||||
|
"lastResponse=$lastStatusResponseReceived " +
|
||||||
|
"$sequenceNumberOfLastProgrammingCommand $historyId"
|
||||||
|
)
|
||||||
|
when {
|
||||||
|
createdRealtime <= podState.lastStatusResponseReceived &&
|
||||||
|
sequence == podState.sequenceNumberOfLastProgrammingCommand ->
|
||||||
|
CommandConfirmationSuccess
|
||||||
|
createdRealtime <= podState.lastStatusResponseReceived &&
|
||||||
|
sequence != podState.sequenceNumberOfLastProgrammingCommand ->
|
||||||
|
CommandConfirmationDenied
|
||||||
|
// no response received after this point
|
||||||
|
createdRealtime <= sentRealtime ->
|
||||||
|
CommandSendingNotConfirmed
|
||||||
|
createdRealtime > sentRealtime ->
|
||||||
|
CommandSendingFailure
|
||||||
|
else -> // this can't happen, see the previous two conditions
|
||||||
|
NoActiveCommand
|
||||||
|
}
|
||||||
|
} ?: NoActiveCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun increaseEapAkaSequenceNumber(): ByteArray {
|
override fun increaseEapAkaSequenceNumber(): ByteArray {
|
||||||
|
@ -386,7 +423,6 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
class PodState : Serializable {
|
class PodState : Serializable {
|
||||||
|
|
||||||
var activationProgress: ActivationProgress = ActivationProgress.NOT_STARTED
|
var activationProgress: ActivationProgress = ActivationProgress.NOT_STARTED
|
||||||
var lastConnection: Long = 0
|
|
||||||
var lastUpdatedSystem: Long = 0
|
var lastUpdatedSystem: Long = 0
|
||||||
var lastStatusResponseReceived: Long = 0
|
var lastStatusResponseReceived: Long = 0
|
||||||
var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState =
|
var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState =
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.history
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.history
|
||||||
|
|
||||||
import com.github.guepardoapps.kulid.ULID
|
import com.github.guepardoapps.kulid.ULID
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
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.definition.OmnipodCommandType.SET_BOLUS
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_BOLUS
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_TEMPORARY_BASAL
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_TEMPORARY_BASAL
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusRecord
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusRecord
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.HistoryRecord
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.HistoryRecord
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.InitialResult
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.InitialResult
|
||||||
|
@ -20,7 +22,8 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class DashHistory @Inject constructor(
|
class DashHistory @Inject constructor(
|
||||||
private val dao: HistoryRecordDao,
|
private val dao: HistoryRecordDao,
|
||||||
private val historyMapper: HistoryMapper
|
private val historyMapper: HistoryMapper,
|
||||||
|
private val logger: AAPSLogger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private fun markSuccess(id: String): Completable = dao.markResolved(
|
private fun markSuccess(id: String): Completable = dao.markResolved(
|
||||||
|
@ -52,29 +55,29 @@ class DashHistory @Inject constructor(
|
||||||
bolusRecord: BolusRecord? = null,
|
bolusRecord: BolusRecord? = null,
|
||||||
resolveResult: ResolvedResult? = null,
|
resolveResult: ResolvedResult? = null,
|
||||||
resolvedAt: Long? = null
|
resolvedAt: Long? = null
|
||||||
): Single<String> {
|
): Single<String> = Single.defer {
|
||||||
val id = ULID.random()
|
val id = ULID.random()
|
||||||
|
|
||||||
when {
|
when {
|
||||||
commandType == SET_BOLUS && bolusRecord == null ->
|
commandType == SET_BOLUS && bolusRecord == null ->
|
||||||
return Single.error(IllegalArgumentException("bolusRecord missing on SET_BOLUS"))
|
Single.error(IllegalArgumentException("bolusRecord missing on SET_BOLUS"))
|
||||||
commandType == SET_TEMPORARY_BASAL && tempBasalRecord == null ->
|
commandType == SET_TEMPORARY_BASAL && tempBasalRecord == null ->
|
||||||
return Single.error(IllegalArgumentException("tempBasalRecord missing on SET_TEMPORARY_BASAL"))
|
Single.error(IllegalArgumentException("tempBasalRecord missing on SET_TEMPORARY_BASAL"))
|
||||||
|
else ->
|
||||||
|
dao.save(
|
||||||
|
HistoryRecordEntity(
|
||||||
|
id = id,
|
||||||
|
date = date,
|
||||||
|
createdAt = currentTimeMillis(),
|
||||||
|
commandType = commandType,
|
||||||
|
tempBasalRecord = tempBasalRecord,
|
||||||
|
bolusRecord = bolusRecord,
|
||||||
|
initialResult = initialResult,
|
||||||
|
resolvedResult = resolveResult,
|
||||||
|
resolvedAt = resolvedAt
|
||||||
|
)
|
||||||
|
).toSingle { id }
|
||||||
}
|
}
|
||||||
|
|
||||||
return dao.save(
|
|
||||||
HistoryRecordEntity(
|
|
||||||
id = id,
|
|
||||||
date = date,
|
|
||||||
createdAt = currentTimeMillis(),
|
|
||||||
commandType = commandType,
|
|
||||||
tempBasalRecord = tempBasalRecord,
|
|
||||||
bolusRecord = bolusRecord,
|
|
||||||
initialResult = initialResult,
|
|
||||||
resolvedResult = resolveResult,
|
|
||||||
resolvedAt = resolvedAt
|
|
||||||
)
|
|
||||||
).toSingle { id }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRecords(): Single<List<HistoryRecord>> =
|
fun getRecords(): Single<List<HistoryRecord>> =
|
||||||
|
@ -83,26 +86,23 @@ class DashHistory @Inject constructor(
|
||||||
fun getRecordsAfter(time: Long): Single<List<HistoryRecordEntity>> = dao.allSince(time)
|
fun getRecordsAfter(time: Long): Single<List<HistoryRecordEntity>> = dao.allSince(time)
|
||||||
|
|
||||||
fun updateFromState(podState: OmnipodDashPodStateManager) = Completable.defer {
|
fun updateFromState(podState: OmnipodDashPodStateManager) = Completable.defer {
|
||||||
podState.activeCommand?.run {
|
val historyId = podState.activeCommand?.historyId
|
||||||
when {
|
if (historyId == null) {
|
||||||
createdRealtime <= podState.lastStatusResponseReceived &&
|
logger.error(LTag.PUMP, "HistoryId not found to for updating from state")
|
||||||
sequence == podState.sequenceNumberOfLastProgrammingCommand ->
|
return@defer Completable.complete()
|
||||||
dao.setInitialResult(historyId, InitialResult.SENT)
|
}
|
||||||
.andThen(markSuccess(historyId))
|
when (podState.getCommandConfirmationFromState()) {
|
||||||
|
CommandSendingFailure ->
|
||||||
createdRealtime <= podState.lastStatusResponseReceived &&
|
dao.setInitialResult(historyId, InitialResult.FAILURE_SENDING)
|
||||||
sequence != podState.sequenceNumberOfLastProgrammingCommand ->
|
CommandSendingNotConfirmed ->
|
||||||
markFailure(historyId)
|
dao.setInitialResult(historyId, InitialResult.SENT)
|
||||||
|
CommandConfirmationDenied ->
|
||||||
// no response received after this point
|
markFailure(historyId)
|
||||||
createdRealtime <= sentRealtime ->
|
CommandConfirmationSuccess ->
|
||||||
dao.setInitialResult(historyId, InitialResult.SENT)
|
dao.setInitialResult(historyId, InitialResult.SENT)
|
||||||
|
.andThen(markSuccess(historyId))
|
||||||
createdRealtime > sentRealtime ->
|
NoActiveCommand ->
|
||||||
dao.setInitialResult(historyId, InitialResult.FAILURE_SENDING)
|
Completable.complete()
|
||||||
|
}
|
||||||
else -> Completable.error(IllegalStateException("This can't happen. Could not update history"))
|
|
||||||
}
|
|
||||||
} ?: Completable.complete() // no active programming command
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,7 +298,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// base basal rate
|
// base basal rate
|
||||||
podInfoBinding.baseBasalRate.text = if (podStateManager.basalProgram != null) {
|
podInfoBinding.baseBasalRate.text = if (podStateManager.basalProgram != null && !podStateManager.isSuspended) {
|
||||||
resourceHelper.gs(
|
resourceHelper.gs(
|
||||||
R.string.pump_basebasalrate,
|
R.string.pump_basebasalrate,
|
||||||
omnipodDashPumpPlugin.model()
|
omnipodDashPumpPlugin.model()
|
||||||
|
@ -357,7 +357,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
|
|
||||||
private fun updateLastConnection() {
|
private fun updateLastConnection() {
|
||||||
if (podStateManager.isUniqueIdSet) {
|
if (podStateManager.isUniqueIdSet) {
|
||||||
podInfoBinding.lastConnection.text = readableDuration(podStateManager.lastConnection)
|
podInfoBinding.lastConnection.text = readableDuration(podStateManager.lastUpdatedSystem)
|
||||||
val lastConnectionColor =
|
val lastConnectionColor =
|
||||||
if (omnipodDashPumpPlugin.isUnreachableAlertTimeoutExceeded(getPumpUnreachableTimeout().millis)) {
|
if (omnipodDashPumpPlugin.isUnreachableAlertTimeoutExceeded(getPumpUnreachableTimeout().millis)) {
|
||||||
Color.RED
|
Color.RED
|
||||||
|
@ -367,7 +367,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
podInfoBinding.lastConnection.setTextColor(lastConnectionColor)
|
podInfoBinding.lastConnection.setTextColor(lastConnectionColor)
|
||||||
} else {
|
} else {
|
||||||
podInfoBinding.lastConnection.setTextColor(Color.WHITE)
|
podInfoBinding.lastConnection.setTextColor(Color.WHITE)
|
||||||
podInfoBinding.lastConnection.text = readableDuration(podStateManager.lastConnection)
|
podInfoBinding.lastConnection.text = readableDuration(podStateManager.lastUpdatedSystem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +518,9 @@ 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.
|
||||||
if (isSuspendDeliveryButtonEnabled() &&
|
// TODO: isSuspendDeliveryButtonEnabled doesn't work
|
||||||
|
val isSuspendDeliveryButtonEnabled = true
|
||||||
|
if (isSuspendDeliveryButtonEnabled &&
|
||||||
podStateManager.isPodRunning &&
|
podStateManager.isPodRunning &&
|
||||||
(!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java))
|
(!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java))
|
||||||
) {
|
) {
|
||||||
|
|
Loading…
Reference in a new issue