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 {
// 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
@ -149,7 +149,7 @@ import kotlin.math.round
}
override fun connect(reason: String) {
if (medtrumPump.patchActivated) {
if (isInitialized()) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
if (medtrumService != null) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
@ -167,7 +167,10 @@ import kotlin.math.round
}
override fun stopConnecting() {
medtrumService?.stopConnecting()
if (isInitialized()) {
aapsLogger.debug(LTag.PUMP, "Medtrum stopConnecting")
medtrumService?.stopConnecting()
}
}
override fun getPumpStatus(reason: String) {

View file

@ -42,13 +42,6 @@ class MedtrumPump @Inject constructor(
_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
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
@ -57,6 +50,7 @@ class MedtrumPump @Inject constructor(
get() = _pumpState.value
set(value) {
_pumpState.value = value
sp.putInt(R.string.key_pump_state, value.state.toInt())
}
// Prime progress as state flow
@ -189,11 +183,11 @@ class MedtrumPump @Inject constructor(
init {
// Load stuff from SP
_patchActivated = sp.getBoolean(R.string.key_patch_activated, false)
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_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")
try {
@ -202,12 +196,6 @@ class MedtrumPump @Inject constructor(
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()
}
@ -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? {
val list = nsProfile.getBasalValues()
var basals = byteArrayOf()
@ -348,14 +322,16 @@ class MedtrumPump @Inject constructor(
LTag.PUMPCOMM,
"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(
timestamp = basalStartTime,
timestamp = dateUtil.now(),
rate = basalRate,
duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
pumpId = dateUtil.now(),
pumpType = pumpType,
pumpSerial = pumpSN.toString(radix = 16)
)

View file

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

View file

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

View file

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

View file

@ -36,8 +36,11 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
if (success) {
var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
medtrumPump.pumpState = 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 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")
if (currentState is IdleState) {
medtrumPump.connectionState = ConnectionState.CONNECTING
if (medtrumPump.patchActivated) {
if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
}
return bleComm.connect(from, medtrumPump.pumpSN)
@ -149,6 +149,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
}
if (result) result = sendPacketAndGetResponse(StopPatchPacket(injector))
// Synchronize after deactivation to get update status
if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
return result
}
@ -162,8 +164,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
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?
// 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
var result = sendPacketAndGetResponse(SynchronizePacket(injector))
if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
// Sync records (based on the info we have from the sync)
if (result) result = syncRecords()
@ -288,7 +293,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Note: medtrum app fetches all records when they sync?
if (medtrumPump.syncedSequenceNumber < 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
}
}
@ -375,7 +384,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun onDisconnected() {
aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected")
medtrumPump.connectionState = ConnectionState.DISCONNECTED
if (medtrumPump.patchActivated) {
if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
}
responseHandled = true
@ -645,7 +654,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
// Now we are fully connected and authenticated and we can start sending commands. Let AAPS know
medtrumPump.connectionState = ConnectionState.CONNECTED
if (medtrumPump.patchActivated) {
if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
}
}

View file

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

View file

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

View file

@ -104,12 +104,10 @@ class MedtrumViewModel @Inject constructor(
}
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
medtrumPump.setPatchActivatedState(true)
updateSetupStep(SetupStep.ACTIVATED)
}
MedtrumPumpState.STOPPED -> {
medtrumPump.setPatchActivatedState(false)
updateSetupStep(SetupStep.STOPPED)
}
@ -137,8 +135,7 @@ class MedtrumViewModel @Inject constructor(
}
// TODO: For DEACTIVATE STATE we might want to move to force cancel screen
if (oldPatchStep == PatchStep.START_DEACTIVATION || oldPatchStep == PatchStep.DEACTIVATE) {
// Deactivation was canceled
medtrumPump.setPatchActivatedStateTemp(true)
// What to do here?
}
}
@ -166,16 +163,16 @@ class MedtrumViewModel @Inject constructor(
}
fun preparePatch() {
if (medtrumPump.patchActivated == true) {
aapsLogger.warn(LTag.PUMP, "preparePatch: already activated! conflicting state?")
// In this case user could have removed the patch without deactivating it?
medtrumPump.setPatchActivatedState(false)
// New session, generate new session token, only do this when not connected
if (medtrumService?.isConnected == false) {
aapsLogger.info(LTag.PUMP, "preparePatch: new session")
medtrumPump.patchSessionToken = Crypt().generateRandomToken()
// Connect to pump
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
}
// New session, generate new session token
aapsLogger.info(LTag.PUMP, "preparePatch: new session")
medtrumPump.patchSessionToken = Crypt().generateRandomToken()
// Connect to pump
medtrumService?.connect("PreparePatch")
}
fun startPrime() {
@ -201,9 +198,6 @@ class MedtrumViewModel @Inject constructor(
}
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
if (medtrumService?.isConnected == true) {
updateSetupStep(SetupStep.READY_DEACTIVATE)
@ -218,8 +212,6 @@ class MedtrumViewModel @Inject constructor(
aapsLogger.info(LTag.PUMP, "deactivatePatch: success!")
} else {
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
updateSetupStep(SetupStep.ERROR)
}

View file

@ -3,7 +3,7 @@
<!-- MedtrumPump -->
<string name="key_snInput" translatable="false">snInput</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_patch_id" translatable="false">patch_id</string>
<string name="key_actual_basal_profile" translatable="false">actual_basal_profile</string>