Add Clear alarms, new overview layout

This commit is contained in:
jbr7rr 2023-06-15 20:17:45 +02:00
parent cbc5a51f2c
commit 7b53630947
21 changed files with 796 additions and 295 deletions

View file

@ -7,4 +7,5 @@ interface Medtrum {
fun loadEvents(): PumpEnactResult // events history to build treatments from
fun setUserOptions(): PumpEnactResult // set user settings
fun clearAlarms(): PumpEnactResult // clear alarms
}

View file

@ -23,11 +23,12 @@ abstract class Command(
BASAL_PROFILE,
READSTATUS,
LOAD_HISTORY, // TDDs and so far only Dana specific
LOAD_EVENTS, // so far only Dana specific
LOAD_EVENTS,
LOAD_TDD,
SET_USER_SETTINGS, // so far only Dana specific,
START_PUMP,
STOP_PUMP,
CLEAR_ALARMS, // so far only Medtrum specific
INSIGHT_SET_TBR_OVER_ALARM, // insight only
CUSTOM_COMMAND
}

View file

@ -31,6 +31,7 @@ interface CommandQueue {
fun setUserOptions(callback: Callback?): Boolean
fun loadTDDs(callback: Callback?): Boolean
fun loadEvents(callback: Callback?): Boolean
fun clearAlarms(callback: Callback?): Boolean
fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean
fun isCustomCommandRunning(customCommandType: Class<out CustomCommand>): Boolean
fun isCustomCommandInQueue(customCommandType: Class<out CustomCommand>): Boolean

View file

@ -393,6 +393,7 @@
<string name="carbs_g">CARBS %1$d g</string>
<string name="extended_bolus_u_min">EXTENDED BOLUS %1$.2f U %2$d min</string>
<string name="load_events">LOAD EVENTS</string>
<string name="clear_alarms">CLEAR_ALARMS</string>
<string name="load_history">LOAD HISTORY %1$d</string>
<string name="load_tdds">LOAD TDDs</string>
<string name="set_profile">SET PROFILE</string>

View file

@ -14,6 +14,7 @@ import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
import info.nightscout.implementation.queue.commands.CommandBolus
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
import info.nightscout.implementation.queue.commands.CommandClearAlarms
import info.nightscout.implementation.queue.commands.CommandCustomCommand
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
@ -32,6 +33,7 @@ abstract class CommandQueueModule {
@ContributesAndroidInjector abstract fun commandExtendedBolusInjector(): CommandExtendedBolus
@ContributesAndroidInjector abstract fun commandInsightSetTBROverNotificationInjector(): CommandInsightSetTBROverNotification
@ContributesAndroidInjector abstract fun commandLoadEventsInjector(): CommandLoadEvents
@ContributesAndroidInjector abstract fun commandClearAlarmsInjector(): CommandClearAlarms
@ContributesAndroidInjector abstract fun commandLoadHistoryInjector(): CommandLoadHistory
@ContributesAndroidInjector abstract fun commandLoadTDDsInjector(): CommandLoadTDDs
@ContributesAndroidInjector abstract fun commandReadStatusInjector(): CommandReadStatus

View file

@ -22,6 +22,7 @@ import info.nightscout.implementation.R
import info.nightscout.implementation.queue.commands.CommandBolus
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
import info.nightscout.implementation.queue.commands.CommandClearAlarms
import info.nightscout.implementation.queue.commands.CommandCustomCommand
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
@ -535,6 +536,20 @@ class CommandQueueImplementation @Inject constructor(
return true
}
// returns true if command is queued
override fun clearAlarms(callback: Callback?): Boolean {
if (isRunning(CommandType.CLEAR_ALARMS)) {
callback?.result(executingNowError())?.run()
return false
}
// remove all unfinished
removeAll(CommandType.CLEAR_ALARMS)
// add new command to queue
add(CommandClearAlarms(injector, callback))
notifyAboutNewCommand()
return true
}
override fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean {
if (isCustomCommandInQueue(customCommand.javaClass)) {
callback?.result(executingNowError())?.run()

View file

@ -0,0 +1,39 @@
package info.nightscout.implementation.queue.commands
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.pump.Dana
import info.nightscout.interfaces.pump.Diaconn
import info.nightscout.interfaces.pump.Medtrum
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.queue.Callback
import info.nightscout.interfaces.queue.Command
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
class CommandClearAlarms(
injector: HasAndroidInjector,
callback: Callback?
) : Command(injector, CommandType.CLEAR_ALARMS, callback) {
@Inject lateinit var activePlugin: ActivePlugin
override fun execute() {
val pump = activePlugin.activePump
if (pump is Medtrum) {
val medtrumPump = pump as Medtrum
val r = medtrumPump.clearAlarms()
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
callback?.result(r)?.run()
}
}
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.clear_alarms)
override fun log(): String = "CLEAR ALAMRS"
override fun cancel() {
aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
}
}

View file

@ -238,6 +238,11 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
// add loadEvents
commandQueue.loadEvents(null)
Assertions.assertEquals(4, commandQueue.size())
// add clearAlarms
commandQueue.clearAlarms(null)
Assertions.assertEquals(5, commandQueue.size())
commandQueue.clear()
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
commandQueue.pickup()
@ -354,6 +359,22 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
Assertions.assertEquals(1, commandQueue.size())
}
@Test
fun isClearAlarmsCommandInQueue() {
// given
Assertions.assertEquals(0, commandQueue.size())
// when
commandQueue.clearAlarms(null)
// then
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.CLEAR_ALARMS))
Assertions.assertEquals(1, commandQueue.size())
// next should be ignored
commandQueue.clearAlarms(null)
Assertions.assertEquals(1, commandQueue.size())
}
@Test
fun isLoadTDDsCommandInQueue() {
// given

View file

@ -383,4 +383,14 @@ import kotlin.math.round
val connectionOK = medtrumService?.setUserSettings() ?: false
return PumpEnactResult(injector).success(connectionOK)
}
override fun clearAlarms(): PumpEnactResult {
if (!isInitialized()) {
val result = PumpEnactResult(injector).success(false)
result.comment = "pump not initialized"
return result
}
val connectionOK = medtrumService?.clearAlarms() ?: false
return PumpEnactResult(injector).success(connectionOK)
}
}

View file

@ -1,8 +1,7 @@
package info.nightscout.pump.medtrum.code
enum class EventType {
ACTIVATION_CLICKED,
DEACTIVATION_CLICKED,
CHANGE_PATCH_CLICKED,
INVALID_BASAL_RATE,
PROFILE_NOT_SET,
FINISH_ACTIVITY,

View file

@ -15,10 +15,12 @@ enum class CommandType(val code: Byte) {
SET_BASAL_PROFILE(21),
SET_TEMP_BASAL(24),
CANCEL_TEMP_BASAL(25),
RESUME_PUMP(29),
POLL_PATCH(30),
STOP_PATCH(31),
READ_BOLUS_STATE(34),
SET_PATCH(35),
SET_BOLUS_MOTOR(36),
GET_RECORD(99)
GET_RECORD(99),
CLEAR_ALARM(115)
}

View file

@ -0,0 +1,16 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.comm.enums.CommandType.CLEAR_ALARM
import info.nightscout.pump.medtrum.extension.toByteArray
class ClearPumpAlarmPacket(injector: HasAndroidInjector, val clearType: Int) : MedtrumPacket(injector) {
init {
opCode = CLEAR_ALARM.code
}
override fun getRequest(): ByteArray {
return byteArrayOf(opCode) + clearType.toByteArray(2)
}
}

View file

@ -0,0 +1,16 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.comm.enums.CommandType.RESUME_PUMP
import info.nightscout.pump.medtrum.extension.toByteArray
class ResumePumpPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
init {
opCode = RESUME_PUMP.code
}
override fun getRequest(): ByteArray {
return byteArrayOf(opCode)
}
}

View file

@ -6,6 +6,7 @@ import info.nightscout.pump.medtrum.comm.packets.ActivatePacket
import info.nightscout.pump.medtrum.comm.packets.AuthorizePacket
import info.nightscout.pump.medtrum.comm.packets.CancelBolusPacket
import info.nightscout.pump.medtrum.comm.packets.CancelTempBasalPacket
import info.nightscout.pump.medtrum.comm.packets.ClearPumpAlarmPacket
import info.nightscout.pump.medtrum.comm.packets.GetDeviceTypePacket
import info.nightscout.pump.medtrum.comm.packets.GetRecordPacket
import info.nightscout.pump.medtrum.comm.packets.GetTimePacket
@ -14,6 +15,7 @@ import info.nightscout.pump.medtrum.comm.packets.NotificationPacket
import info.nightscout.pump.medtrum.comm.packets.PollPatchPacket
import info.nightscout.pump.medtrum.comm.packets.PrimePacket
import info.nightscout.pump.medtrum.comm.packets.ReadBolusStatePacket
import info.nightscout.pump.medtrum.comm.packets.ResumePumpPacket
import info.nightscout.pump.medtrum.comm.packets.SetBasalProfilePacket
import info.nightscout.pump.medtrum.comm.packets.SetBolusMotorPacket
import info.nightscout.pump.medtrum.comm.packets.SetBolusPacket
@ -32,6 +34,7 @@ abstract class MedtrumCommModule {
@ContributesAndroidInjector abstract fun contributesAuthorizePacket(): AuthorizePacket
@ContributesAndroidInjector abstract fun contributesCancelBolusPacket(): CancelBolusPacket
@ContributesAndroidInjector abstract fun contributesCancelTempBasalPacket(): CancelTempBasalPacket
@ContributesAndroidInjector abstract fun contributesClearPumpAlarmPacket(): ClearPumpAlarmPacket
@ContributesAndroidInjector abstract fun contributesGetDeviceTypePacket(): GetDeviceTypePacket
@ContributesAndroidInjector abstract fun contributesGetRecordPacket(): GetRecordPacket
@ContributesAndroidInjector abstract fun contributesGetTimePacket(): GetTimePacket
@ -40,6 +43,7 @@ abstract class MedtrumCommModule {
@ContributesAndroidInjector abstract fun contributesPollPatchPacket(): PollPatchPacket
@ContributesAndroidInjector abstract fun contributesPrimePacket(): PrimePacket
@ContributesAndroidInjector abstract fun contributesReadBolusStatePacket(): ReadBolusStatePacket
@ContributesAndroidInjector abstract fun contributesResumePumpPacket(): ResumePumpPacket
@ContributesAndroidInjector abstract fun contributesSetBasalProfilePacket(): SetBasalProfilePacket
@ContributesAndroidInjector abstract fun contributesSetBolusMotorPacket(): SetBolusMotorPacket
@ContributesAndroidInjector abstract fun contributesSetBolusPacket(): SetBolusPacket

View file

@ -75,6 +75,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
private const val COMMAND_DEFAULT_TIMEOUT_SEC: Long = 60
private const val COMMAND_SYNC_TIMEOUT_SEC: Long = 120
private const val COMMAND_CONNECTING_TIMEOUT_SEC: Long = 30
private const val ALARM_HOURLY_MAX_CLEAR_CODE = 4
private const val ALARM_DAILY_MAX_CLEAR_CODE = 5
}
val timeUtil = MedtrumTimeUtil()
@ -155,11 +157,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
MedtrumPumpState.LOWBG_SUSPENDED,
MedtrumPumpState.LOWBG_SUSPENDED2,
MedtrumPumpState.AUTO_SUSPENDED,
MedtrumPumpState.HMAX_SUSPENDED,
MedtrumPumpState.DMAX_SUSPENDED,
MedtrumPumpState.SUSPENDED,
MedtrumPumpState.PAUSED -> {
// TODO: Message with reason
uiInteraction.addNotification(
Notification.PUMP_SUSPENDED,
rh.gs(R.string.pump_is_suspended),
@ -168,6 +167,23 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Pump will report proper TBR for this
}
MedtrumPumpState.HMAX_SUSPENDED -> {
uiInteraction.addNotification(
Notification.PUMP_SUSPENDED,
rh.gs(R.string.pump_is_suspended_hour_max),
Notification.NORMAL,
)
// Pump will report proper TBR for this
}
MedtrumPumpState.DMAX_SUSPENDED -> {
uiInteraction.addNotification(
Notification.PUMP_SUSPENDED,
rh.gs(R.string.pump_is_suspended_day_max),
Notification.NORMAL,
)
// Pump will report proper TBR for this
}
MedtrumPumpState.OCCLUSION,
MedtrumPumpState.EXPIRED,
MedtrumPumpState.RESERVOIR_EMPTY,
@ -250,18 +266,49 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun loadEvents(): Boolean {
// Send a poll patch, to workaround connection losses?
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
var result = sendPacketAndGetResponse(PollPatchPacket(injector))
// So just do a syncronize to make sure we have the latest data
if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
// Sync records (based on the info we have from the sync)
if (result) result = syncRecords()
if (!result) {
if (result) {
aapsLogger.debug(LTag.PUMPCOMM, "Events loaded")
medtrumPump.lastConnection = System.currentTimeMillis()
} else {
aapsLogger.error(LTag.PUMPCOMM, "Failed to sync records")
}
if (result) medtrumPump.lastConnection = System.currentTimeMillis()
aapsLogger.debug(LTag.PUMPCOMM, "Events loaded")
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
return result
}
fun clearAlarms(): Boolean {
var result = true
when (medtrumPump.pumpState) {
MedtrumPumpState.HMAX_SUSPENDED -> {
result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_HOURLY_MAX_CLEAR_CODE))
}
MedtrumPumpState.DMAX_SUSPENDED -> {
result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_DAILY_MAX_CLEAR_CODE))
}
else -> {
// Do nothing
// TODO: Remove me before release!!!
// Try to brute force the commands
aapsLogger.warn(LTag.PUMPCOMM, "Trying to clear alarms brutus!")
for (i in 0..100) {
result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, i))
if (result) {
aapsLogger.warn(LTag.PUMPCOMM, "Alarm cleared: $i")
break
}
}
}
}
// Resume suspended pump
// TODO: We might not want to do this for alarms which don't suspend the pump
if (result) result = sendPacketAndGetResponse(ResumePumpPacket(injector))
return result
}

View file

@ -12,6 +12,7 @@ import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.EventType
import info.nightscout.pump.medtrum.code.PatchStep
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
@ -43,18 +44,12 @@ class MedtrumOverviewFragment : MedtrumBaseFragment<FragmentMedtrumOverviewBindi
viewmodel?.apply {
eventHandler.observe(viewLifecycleOwner) { evt ->
when (evt.peekContent()) {
EventType.ACTIVATION_CLICKED -> requireContext().apply {
// TODO: Check what to do with this, and if we need this, it currently messes up patch is last registered as priming
// var step = convertToPatchStep(medtrumPump.pumpState)
// if (step == PatchStep.DEACTIVATION_COMPLETE) {
// // Reset
// step = PatchStep.PREPARE_PATCH
// }
startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH))
}
EventType.DEACTIVATION_CLICKED -> requireContext().apply {
startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.START_DEACTIVATION))
EventType.CHANGE_PATCH_CLICKED -> requireContext().apply {
if (medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED) {
startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.START_DEACTIVATION))
} else {
startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH))
}
}
else -> Unit
}

View file

@ -9,6 +9,7 @@ import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
import info.nightscout.pump.medtrum.ui.event.UIEvent
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
@ -34,7 +35,8 @@ class MedtrumOverviewViewModel @Inject constructor(
private val aapsSchedulers: AapsSchedulers,
private val fabricPrivacy: FabricPrivacy,
private val profileFunction: ProfileFunction,
private val medtrumPump: MedtrumPump
private val commandQueue: CommandQueue,
val medtrumPump: MedtrumPump
) : BaseViewModel<MedtrumBaseNavigator>() {
private val scope = CoroutineScope(Dispatchers.Default)
@ -43,29 +45,41 @@ class MedtrumOverviewViewModel @Inject constructor(
val eventHandler: LiveData<UIEvent<EventType>>
get() = _eventHandler
private val _canDoRefresh = SingleLiveEvent<Boolean>()
val canDoRefresh: LiveData<Boolean>
get() = _canDoRefresh
private val _canDoResetAlarms = SingleLiveEvent<Boolean>()
val canDoResetAlarms: LiveData<Boolean>
get() = _canDoResetAlarms
private val _bleStatus = SingleLiveEvent<String>()
val bleStatus: LiveData<String>
get() = _bleStatus
private val _isPatchActivated = SingleLiveEvent<Boolean>()
val isPatchActivated: LiveData<Boolean>
get() = _isPatchActivated
private val _lastConnected = SingleLiveEvent<String>()
val lastConnected: LiveData<String>
get() = _lastConnected
private val _pumpState = SingleLiveEvent<String>()
val pumpState: LiveData<String>
get() = _pumpState
private val _activeAlarms = SingleLiveEvent<String>()
val activeAlarms: LiveData<String>
get() = _activeAlarms
private val _basalType = SingleLiveEvent<String>()
val basalType: LiveData<String>
get() = _basalType
private val _pumpType = SingleLiveEvent<String>()
val pumpType: LiveData<String>
get() = _pumpType
private val _runningBasalRate = SingleLiveEvent<String>()
val runningBasalRate: LiveData<String>
get() = _runningBasalRate
private val _fwVersion = SingleLiveEvent<String>()
val fwVersion: LiveData<String>
get() = _fwVersion
private val _patchNo = SingleLiveEvent<String>()
val patchNo: LiveData<String>
get() = _patchNo
private val _reservoir = SingleLiveEvent<String>()
val reservoir: LiveData<String>
get() = _reservoir
private val _patchExpiry = SingleLiveEvent<String>()
val patchExpiry: LiveData<String>
get() = _patchExpiry
init {
scope.launch {
@ -74,14 +88,21 @@ class MedtrumOverviewViewModel @Inject constructor(
when (state) {
ConnectionState.CONNECTING -> {
_bleStatus.postValue("{fa-bluetooth-b spin}")
_canDoRefresh.postValue(false)
}
ConnectionState.CONNECTED -> {
_bleStatus.postValue("{fa-bluetooth}")
_canDoRefresh.postValue(false)
}
ConnectionState.DISCONNECTED -> {
_bleStatus.postValue("{fa-bluetooth-b}")
if (medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED) {
_canDoRefresh.postValue(true)
} else {
_canDoRefresh.postValue(false)
}
}
}
}
@ -89,37 +110,13 @@ class MedtrumOverviewViewModel @Inject constructor(
scope.launch {
medtrumPump.pumpStateFlow.collect { state ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
if (state > MedtrumPumpState.EJECTED && state < MedtrumPumpState.STOPPED) {
_isPatchActivated.postValue(true)
if (medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED) {
_canDoResetAlarms.postValue(true)
} else {
_isPatchActivated.postValue(false)
_canDoResetAlarms.postValue(false)
}
}
}
scope.launch {
medtrumPump.lastBasalRateFlow.collect { rate ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel runningBasalRateFlow: $rate")
_runningBasalRate.postValue(String.format(rh.gs(R.string.current_basal_rate), rate))
}
}
scope.launch {
medtrumPump.pumpStateFlow.collect { state ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
_pumpState.postValue(state.toString())
}
}
scope.launch {
medtrumPump.reservoirFlow.collect { reservoir ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel reservoirFlow: $reservoir")
_reservoir.postValue(String.format(rh.gs(R.string.reservoir_level), reservoir))
}
}
scope.launch {
medtrumPump.lastBasalTypeFlow.collect { basalType ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel basalTypeFlow: $basalType")
_basalType.postValue(basalType.toString())
}
}
}
override fun onCleared() {
@ -127,18 +124,22 @@ class MedtrumOverviewViewModel @Inject constructor(
scope.cancel()
}
fun onClickActivation() {
aapsLogger.debug(LTag.PUMP, "Start Patch clicked!")
fun onClickRefresh() {
commandQueue.readStatus(rh.gs(R.string.requested_by_user), null)
}
fun onClickResetAlarms() {
commandQueue.clearAlarms(null)
}
fun onClickChangePatch() {
aapsLogger.debug(LTag.PUMP, "ChangePatch Patch clicked!")
val profile = profileFunction.getProfile()
if (profile == null) {
_eventHandler.postValue(UIEvent(EventType.PROFILE_NOT_SET))
} else {
_eventHandler.postValue(UIEvent(EventType.ACTIVATION_CLICKED))
_eventHandler.postValue(UIEvent(EventType.CHANGE_PATCH_CLICKED))
}
}
fun onClickDeactivation() {
aapsLogger.debug(LTag.PUMP, "Stop Patch clicked!")
_eventHandler.postValue(UIEvent(EventType.DEACTIVATION_CLICKED))
}
}
}

View file

@ -27,235 +27,474 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:orientation="vertical"
android:paddingTop="2dp"
android:paddingBottom="5dp"
android:visibility="gone">
android:paddingBottom="5dp">
<TextView
android:id="@+id/text1"
<!-- BLE Status -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:gravity="center_vertical|center_horizontal"
android:text="@string/initializing"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
android:orientation="horizontal">
<View
android:layout_width="fill_parent"
android:layout_height="2dip"
android:layout_marginLeft="20dp"
android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/ble_status_label"
android:textSize="14sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/ble_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.bleStatus}"
android:textSize="14sp" />
</LinearLayout>
<!-- Last Connected -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/medtrum_ble_status"
android:textSize="16sp" />
android:orientation="horizontal">
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="16sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/last_connected_label"
android:textSize="14sp" />
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/medtrum_ble_status"
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/last_connected"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.lastConnected}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="2dip"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" />
<!-- Pump State -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.bleStatus}"
android:textColor="@android:color/white"
android:textSize="16sp" />
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/pump_state_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/pump_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.medtrumPump.pumpStateFlow.toString()}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- Basal Type -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/basal_type_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/basal_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.medtrumPump.lastBasalTypeFlow.toString()}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- Basal Rate -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/basal_rate_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/basal_rate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text='@{@string/current_basal_rate(viewmodel.medtrumPump.lastBasalRateFlow)}'
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- Reservoir -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/reservoir_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/reservoir"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text='@{@string/reservoir_level(viewmodel.medtrumPump.reservoirFlow)}'
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- Active Alarms -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/active_alarms_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/active_alarms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.activeAlarms}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="2dip"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" />
<!-- PumpType -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/pump_type_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/pump_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.pumpType}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- FW Version -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/fw_version_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/fw_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.fwVersion}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- Patch No -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/patch_no_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/patch_no"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.patchNo}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
<!-- Expiry? -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/patch_expiry_label"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp" />
<TextView
android:id="@+id/patch_expiry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.patchExpiry}"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="2dip"
android:layout_marginLeft="20dp"
android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/pump_state_label"
android:textSize="16sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="16sp" />
<TextView
android:id="@+id/pump_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.pumpState}"
android:textColor="@android:color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/current_basal_type_label"
android:textSize="16sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="16sp" />
<TextView
android:id="@+id/current_basal_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.basalType}"
android:textColor="@android:color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/current_basal_label"
android:textSize="16sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="16sp" />
<TextView
android:id="@+id/current_basal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.runningBasalRate}"
android:textColor="@android:color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/reservoir_label"
android:textSize="16sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="16sp" />
<TextView
android:id="@+id/reservoir_level"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@{viewmodel.reservoir}"
android:textColor="@android:color/white"
android:textSize="16sp" />
</LinearLayout>
<!-- Add other fields here as needed, like the ones above -->
</LinearLayout>
</ScrollView>
@ -267,26 +506,38 @@
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<!-- Refresh button -->
<Button
android:id="@+id/button1"
android:id="@+id/refreshButton"
style="@style/ButtonMediumFontStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:enabled="@{!viewmodel.isPatchActivated}"
android:text="@string/string_new_patch"
app:onSafeClick="@{() -> viewmodel.onClickActivation()}" />
android:enabled="@{viewmodel.canDoRefresh}"
android:text="@string/refresh_label"
app:onSafeClick="@{() -> viewmodel.onClickRefresh()}" />
<!-- Reset Alarms button -->
<Button
android:id="@+id/button2"
android:id="@+id/resetAlarmsButton"
style="@style/ButtonMediumFontStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:enabled="@{viewmodel.isPatchActivated}"
android:text="@string/string_stop_patch"
app:onSafeClick="@{() -> viewmodel.onClickDeactivation()}" />
android:text="@string/reset_alarms_label"
android:enabled="@{viewmodel.canDoResetAlarms}"
app:onSafeClick="@{() -> viewmodel.onClickResetAlarms()}" />
<!-- Change Patch button -->
<Button
android:id="@+id/changePatchButton"
style="@style/ButtonMediumFontStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/change_patch_label"
app:onSafeClick="@{() -> viewmodel.onClickChangePatch()}" />
</LinearLayout>
</RelativeLayout>
</layout>
</layout>

View file

@ -21,19 +21,29 @@
<string name="medtrumpump_settings">Medtrum pump settings</string>
<string name="pump_error">Pump error: %1$s !! </string>
<string name="pump_is_suspended">Pump is suspended</string>
<string name="pump_is_suspended_hour_max">Pump is suspended due to hourly max insulin exceeded</string>
<string name="pump_is_suspended_day_max">Pump is suspended due to daily max insulin exceeded</string>
<string name="patch_not_active">Patch not activated</string>
<string name="pump_setting_failed">Setting user settings to pump failed!</string>
<!-- overview fragment -->
<string name="medtrum_ble_status">BLE Status</string>
<string name="ble_status_label">BLE Status</string>
<string name="last_connected_label">Last connected</string>
<string name="pump_state_label">Pump state</string>
<string name="active_alarms_label">Active alarms</string>
<string name="reservoir_label"> Reservoir</string>
<string name="reservoir_level"> %.2f U</string>
<string name="current_basal_type_label">Basal type</string>
<string name="current_basal_label">Basal rate</string>
<string name="basal_type_label">Basal type</string>
<string name="basal_rate_label">Basal rate</string>
<string name="current_basal_rate"> %.2f U/h</string>
<string name="string_new_patch">Start new patch</string>
<string name="string_stop_patch">Stop patch</string>
<string name="pump_type_label">Pump type</string>
<string name="fw_version_label">FW version</string>
<string name="patch_no_label">Patch no</string>
<string name="patch_expiry_label">Patch expires</string>
<string name="refresh_label">Refresh</string>
<string name="reset_alarms_label">Reset alarms</string>
<string name="change_patch_label">Change patch</string>
<string name="requested_by_user" comment="26 characters max for translation">Requested by user</string>
<!-- wizard-->
<string name="string_change_patch">Discard/Change Patch</string> <!-- TODO check-->

View file

@ -0,0 +1,36 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
import info.nightscout.pump.medtrum.extension.toInt
import org.junit.jupiter.api.Test
import org.junit.Assert.*
class ClearPumpAlarmPacketTest : MedtrumTestBase() {
/** Test packet specific behavoir */
private val packetInjector = HasAndroidInjector {
AndroidInjector {
if (it is MedtrumPacket) {
it.aapsLogger = aapsLogger
}
}
}
@Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
// Inputs
val opCode = 115
val clearCode = 4
// Call
val packet = ClearPumpAlarmPacket(packetInjector, clearCode)
val result = packet.getRequest()
// Expected values
assertEquals(3, result.size)
assertEquals(opCode.toByte(), result[0])
assertEquals(clearCode, result.copyOfRange(1, 3).toInt())
}
}

View file

@ -0,0 +1,33 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
import org.junit.jupiter.api.Test
import org.junit.Assert.*
class ResumePumpPacketTest : MedtrumTestBase() {
/** Test packet specific behavoir */
private val packetInjector = HasAndroidInjector {
AndroidInjector {
if (it is MedtrumPacket) {
it.aapsLogger = aapsLogger
}
}
}
@Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
// Inputs
val opCode = 29
// Call
val packet = ResumePumpPacket(packetInjector)
val result = packet.getRequest()
// Expected values
assertEquals(1, result.size)
assertEquals(opCode.toByte(), result[0])
}
}