Improve activation flow

This commit is contained in:
jbr7rr 2023-06-08 11:27:55 +02:00
parent 932f651e57
commit bad4d7a7f4
11 changed files with 52 additions and 74 deletions

View file

@ -139,7 +139,7 @@ import kotlin.math.round
override fun isConnected(): Boolean { override fun isConnected(): Boolean {
// This is a workaround to prevent AAPS to trigger connects when we have no patch activated // This is a workaround to prevent AAPS to trigger connects when we have no patch activated
return if (!medtrumPump.patchActivated) true else medtrumService?.isConnected ?: false return if (!isInitialized()) true else medtrumService?.isConnected ?: false
} }
override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false
@ -149,7 +149,7 @@ import kotlin.math.round
} }
override fun connect(reason: String) { override fun connect(reason: String) {
if (medtrumPump.patchActivated) { if (isInitialized()) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason") aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
if (medtrumService != null) { if (medtrumService != null) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!") aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
@ -167,8 +167,11 @@ import kotlin.math.round
} }
override fun stopConnecting() { override fun stopConnecting() {
if (isInitialized()) {
aapsLogger.debug(LTag.PUMP, "Medtrum stopConnecting")
medtrumService?.stopConnecting() medtrumService?.stopConnecting()
} }
}
override fun getPumpStatus(reason: String) { override fun getPumpStatus(reason: String) {
aapsLogger.debug(LTag.PUMP, "Medtrum getPumpStatus - reason:$reason") aapsLogger.debug(LTag.PUMP, "Medtrum getPumpStatus - reason:$reason")

View file

@ -42,13 +42,6 @@ class MedtrumPump @Inject constructor(
_connectionState.value = value _connectionState.value = value
} }
/** Patch activated state, mainly for UI, but also controls the connection flow,
* if patch is not activated, AAPS cannot connect to the pump, we can then connect trough the activation flow.
* Note: this is also saved in SP, by the set functions
*/
private var _patchActivated = false
val patchActivated: Boolean
get() = _patchActivated
// Pump state flow // Pump state flow
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE) private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
@ -57,6 +50,7 @@ class MedtrumPump @Inject constructor(
get() = _pumpState.value get() = _pumpState.value
set(value) { set(value) {
_pumpState.value = value _pumpState.value = value
sp.putInt(R.string.key_pump_state, value.state.toInt())
} }
// Prime progress as state flow // Prime progress as state flow
@ -189,11 +183,11 @@ class MedtrumPump @Inject constructor(
init { init {
// Load stuff from SP // Load stuff from SP
_patchActivated = sp.getBoolean(R.string.key_patch_activated, false)
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L) _patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0) _currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L) _patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0) _syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
_pumpState.value = MedtrumPumpState.fromByte(sp.getInt(R.string.key_pump_state, MedtrumPumpState.NONE.state.toInt()).toByte())
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0") val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
try { try {
@ -202,12 +196,6 @@ class MedtrumPump @Inject constructor(
aapsLogger.error(LTag.PUMP, "Error decoding basal profile from SP: $encodedString") aapsLogger.error(LTag.PUMP, "Error decoding basal profile from SP: $encodedString")
} }
if (patchActivated) {
aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE")
// Set inital status as active will be updated on first connection
pumpState = MedtrumPumpState.ACTIVE
}
loadUserSettingsFromSP() loadUserSettingsFromSP()
} }
@ -225,20 +213,6 @@ class MedtrumPump @Inject constructor(
} }
} }
fun setPatchActivatedState(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedState: $activated")
_patchActivated = activated
sp.putBoolean(R.string.key_patch_activated, activated)
}
/** When the activation/deactivation screen, and the connection flow needs to be controlled,
* this can be used to set the ActivatedState without saving to SP, So when app is force closed the state is still maintained
*/
fun setPatchActivatedStateTemp(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedStateTemp: $activated")
_patchActivated = activated
}
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? { fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
val list = nsProfile.getBasalValues() val list = nsProfile.getBasalValues()
var basals = byteArrayOf() var basals = byteArrayOf()
@ -348,14 +322,16 @@ class MedtrumPump @Inject constructor(
LTag.PUMPCOMM, LTag.PUMPCOMM,
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal" "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal"
) )
} else if (basalType == BasalType.NONE && expectedTemporaryBasal?.pumpId != basalStartTime) { // Also some sort of suspend or unkown by pump } else if (basalType == BasalType.NONE && expectedTemporaryBasal?.rate != basalRate && expectedTemporaryBasal?.duration != T.mins(4800).msecs()) {
// Pump suspended, set fake TBR
// TODO: Maybe move this to separate function?
val newRecord = pumpSync.syncTemporaryBasalWithPumpId( val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime, timestamp = dateUtil.now(),
rate = basalRate, rate = basalRate,
duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
isAbsolute = true, isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND, type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime, pumpId = dateUtil.now(),
pumpType = pumpType, pumpType = pumpType,
pumpSerial = pumpSN.toString(radix = 16) pumpSerial = pumpSN.toString(radix = 16)
) )

View file

@ -44,10 +44,6 @@ enum class BasalType {
AUTO_MODE_EXERCISE_START, AUTO_MODE_EXERCISE_START,
AUTO_MODE_EXERCISE_EXIT; AUTO_MODE_EXERCISE_EXIT;
fun getValue(): Int {
return ordinal
}
fun isTempBasal(): Boolean { fun isTempBasal(): Boolean {
return this == ABSOLUTE_TEMP || this == RELATIVE_TEMP return this == ABSOLUTE_TEMP || this == RELATIVE_TEMP
} }

View file

@ -5,8 +5,4 @@ enum class BolusType {
NORMAL, NORMAL,
EXTEND, EXTEND,
COMBINATION; COMBINATION;
fun getValue(): Int {
return ordinal
}
} }

View file

@ -68,8 +68,10 @@ class NotificationPacket(val injector: HasAndroidInjector) {
val state = MedtrumPumpState.fromByte(notification[0]) val state = MedtrumPumpState.fromByte(notification[0])
aapsLogger.debug(LTag.PUMPCOMM, "Notification state: $state, current state: ${medtrumPump.pumpState}") aapsLogger.debug(LTag.PUMPCOMM, "Notification state: $state, current state: ${medtrumPump.pumpState}")
// TODO: Do we need to emit an event on state change? if (state != medtrumPump.pumpState) {
aapsLogger.debug(LTag.PUMPCOMM, "State changed from ${medtrumPump.pumpState} to $state")
medtrumPump.pumpState = state medtrumPump.pumpState = state
}
if (notification.size > NOTIF_STATE_END) { if (notification.size > NOTIF_STATE_END) {
handleMaskedMessage(notification.copyOfRange(NOTIF_STATE_END, notification.size)) handleMaskedMessage(notification.copyOfRange(NOTIF_STATE_END, notification.size))

View file

@ -36,8 +36,11 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
if (success) { if (success) {
var state = MedtrumPumpState.fromByte(data[RESP_STATE_START]) var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
medtrumPump.pumpState = state
aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: state: $state") aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: state: $state")
if (state != medtrumPump.pumpState) {
aapsLogger.debug(LTag.PUMPCOMM, "State changed from ${medtrumPump.pumpState} to $state")
medtrumPump.pumpState = state
}
var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt() var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size) var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)

View file

@ -123,7 +123,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMP, "connect: called from: $from") aapsLogger.debug(LTag.PUMP, "connect: called from: $from")
if (currentState is IdleState) { if (currentState is IdleState) {
medtrumPump.connectionState = ConnectionState.CONNECTING medtrumPump.connectionState = ConnectionState.CONNECTING
if (medtrumPump.patchActivated) { if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
} }
return bleComm.connect(from, medtrumPump.pumpSN) return bleComm.connect(from, medtrumPump.pumpSN)
@ -149,6 +149,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector)) result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
} }
if (result) result = sendPacketAndGetResponse(StopPatchPacket(injector)) if (result) result = sendPacketAndGetResponse(StopPatchPacket(injector))
// Synchronize after deactivation to get update status
if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
return result return result
} }
@ -162,8 +164,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun readPumpStatus() { fun readPumpStatus() {
// Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for? // Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for?
// Send a poll patch, to workaround connection losses?
var result = sendPacketAndGetResponse(PollPatchPacket(injector))
// So just do a syncronize to make sure we have the latest data // So just do a syncronize to make sure we have the latest data
var result = sendPacketAndGetResponse(SynchronizePacket(injector)) if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
// Sync records (based on the info we have from the sync) // Sync records (based on the info we have from the sync)
if (result) result = syncRecords() if (result) result = syncRecords()
@ -288,7 +293,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Note: medtrum app fetches all records when they sync? // Note: medtrum app fetches all records when they sync?
if (medtrumPump.syncedSequenceNumber < medtrumPump.currentSequenceNumber) { if (medtrumPump.syncedSequenceNumber < medtrumPump.currentSequenceNumber) {
for (sequence in (medtrumPump.syncedSequenceNumber + 1)..medtrumPump.currentSequenceNumber) { for (sequence in (medtrumPump.syncedSequenceNumber + 1)..medtrumPump.currentSequenceNumber) {
result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence)) // Send a poll patch, to workaround connection losses?
result = sendPacketAndGetResponse(PollPatchPacket(injector))
SystemClock.sleep(100)
// Get our record
if (result) result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
if (result == false) break if (result == false) break
} }
} }
@ -375,7 +384,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun onDisconnected() { fun onDisconnected() {
aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected") aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected")
medtrumPump.connectionState = ConnectionState.DISCONNECTED medtrumPump.connectionState = ConnectionState.DISCONNECTED
if (medtrumPump.patchActivated) { if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
} }
responseHandled = true responseHandled = true
@ -645,7 +654,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!") aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
// Now we are fully connected and authenticated and we can start sending commands. Let AAPS know // Now we are fully connected and authenticated and we can start sending commands. Let AAPS know
medtrumPump.connectionState = ConnectionState.CONNECTED medtrumPump.connectionState = ConnectionState.CONNECTED
if (medtrumPump.patchActivated) { if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
} }
} }

View file

@ -44,11 +44,11 @@ class MedtrumOverviewFragment : MedtrumBaseFragment<FragmentMedtrumOverviewBindi
eventHandler.observe(viewLifecycleOwner) { evt -> eventHandler.observe(viewLifecycleOwner) { evt ->
when (evt.peekContent()) { when (evt.peekContent()) {
EventType.ACTIVATION_CLICKED -> requireContext().apply { EventType.ACTIVATION_CLICKED -> requireContext().apply {
val step = convertToPatchStep(medtrumPump.pumpState) var step = convertToPatchStep(medtrumPump.pumpState)
// TODO is stil needed? if (step == PatchStep.DEACTIVATION_COMPLETE) {
// if (step != PatchStep.PREPARE_PATCH) { // Reset
// aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step") step = PatchStep.PREPARE_PATCH
// } }
startActivity(MedtrumActivity.createIntentFromMenu(this, step)) startActivity(MedtrumActivity.createIntentFromMenu(this, step))
} }

View file

@ -36,6 +36,7 @@ abstract class BaseViewModel<N : MedtrumBaseNavigator> : ViewModel() {
MedtrumPumpState.PRIMING -> PatchStep.PRIME MedtrumPumpState.PRIMING -> PatchStep.PRIME
MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> PatchStep.ATTACH_PATCH MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> PatchStep.ATTACH_PATCH
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> PatchStep.COMPLETE MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> PatchStep.COMPLETE
MedtrumPumpState.STOPPED -> PatchStep.DEACTIVATION_COMPLETE
else -> PatchStep.CANCEL else -> PatchStep.CANCEL
} }
} }

View file

@ -104,12 +104,10 @@ class MedtrumViewModel @Inject constructor(
} }
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> { MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
medtrumPump.setPatchActivatedState(true)
updateSetupStep(SetupStep.ACTIVATED) updateSetupStep(SetupStep.ACTIVATED)
} }
MedtrumPumpState.STOPPED -> { MedtrumPumpState.STOPPED -> {
medtrumPump.setPatchActivatedState(false)
updateSetupStep(SetupStep.STOPPED) updateSetupStep(SetupStep.STOPPED)
} }
@ -137,8 +135,7 @@ class MedtrumViewModel @Inject constructor(
} }
// TODO: For DEACTIVATE STATE we might want to move to force cancel screen // TODO: For DEACTIVATE STATE we might want to move to force cancel screen
if (oldPatchStep == PatchStep.START_DEACTIVATION || oldPatchStep == PatchStep.DEACTIVATE) { if (oldPatchStep == PatchStep.START_DEACTIVATION || oldPatchStep == PatchStep.DEACTIVATE) {
// Deactivation was canceled // What to do here?
medtrumPump.setPatchActivatedStateTemp(true)
} }
} }
@ -166,16 +163,16 @@ class MedtrumViewModel @Inject constructor(
} }
fun preparePatch() { fun preparePatch() {
if (medtrumPump.patchActivated == true) { // New session, generate new session token, only do this when not connected
aapsLogger.warn(LTag.PUMP, "preparePatch: already activated! conflicting state?") if (medtrumService?.isConnected == false) {
// In this case user could have removed the patch without deactivating it?
medtrumPump.setPatchActivatedState(false)
}
// New session, generate new session token
aapsLogger.info(LTag.PUMP, "preparePatch: new session") aapsLogger.info(LTag.PUMP, "preparePatch: new session")
medtrumPump.patchSessionToken = Crypt().generateRandomToken() medtrumPump.patchSessionToken = Crypt().generateRandomToken()
// Connect to pump // Connect to pump
medtrumService?.connect("PreparePatch") medtrumService?.connect("PreparePatch")
} else {
aapsLogger.error(LTag.PUMP, "preparePatch: Already connected when trying to prepare patch")
// Do nothing here, continue with old key and connection
}
} }
fun startPrime() { fun startPrime() {
@ -201,9 +198,6 @@ class MedtrumViewModel @Inject constructor(
} }
fun startDeactivation() { fun startDeactivation() {
// Set active already to false, so UI can control the pump connection instead of AAPS pumpqueue
medtrumPump.setPatchActivatedStateTemp(false)
// Start connecting if needed // Start connecting if needed
if (medtrumService?.isConnected == true) { if (medtrumService?.isConnected == true) {
updateSetupStep(SetupStep.READY_DEACTIVATE) updateSetupStep(SetupStep.READY_DEACTIVATE)
@ -218,8 +212,6 @@ class MedtrumViewModel @Inject constructor(
aapsLogger.info(LTag.PUMP, "deactivatePatch: success!") aapsLogger.info(LTag.PUMP, "deactivatePatch: success!")
} else { } else {
aapsLogger.info(LTag.PUMP, "deactivatePatch: failure!") aapsLogger.info(LTag.PUMP, "deactivatePatch: failure!")
// Check if this is needed, for now even when it failed, we assume the user will remove the patch and pumpbase
medtrumPump.setPatchActivatedStateTemp(true) // failed to activate, set activate state to true
// TODO: State to force forget the patch or try again // TODO: State to force forget the patch or try again
updateSetupStep(SetupStep.ERROR) updateSetupStep(SetupStep.ERROR)
} }

View file

@ -3,7 +3,7 @@
<!-- MedtrumPump --> <!-- MedtrumPump -->
<string name="key_snInput" translatable="false">snInput</string> <string name="key_snInput" translatable="false">snInput</string>
<string name="key_medtrumpump_settings" translatable="false">medtrumpump_settings</string> <string name="key_medtrumpump_settings" translatable="false">medtrumpump_settings</string>
<string name="key_patch_activated" translatable="false">medtrum_patch_activated</string> <string name="key_pump_state" translatable="false">pump_state</string>
<string name="key_session_token" translatable="false">medtrum_session_token</string> <string name="key_session_token" translatable="false">medtrum_session_token</string>
<string name="key_patch_id" translatable="false">patch_id</string> <string name="key_patch_id" translatable="false">patch_id</string>
<string name="key_actual_basal_profile" translatable="false">actual_basal_profile</string> <string name="key_actual_basal_profile" translatable="false">actual_basal_profile</string>