Automatic timeZone and DST handling
This commit is contained in:
parent
201fb5768a
commit
19b9ca1da4
15 changed files with 189 additions and 14 deletions
|
@ -136,6 +136,7 @@ open class Notification {
|
|||
const val BLUETOOTH_NOT_ENABLED = 82
|
||||
const val PATCH_NOT_ACTIVE = 83
|
||||
const val PUMP_SETTINGS_FAILED = 84
|
||||
const val PUMP_TIMEZONE_UPDATE_FAILED = 85
|
||||
|
||||
const val USER_MESSAGE = 1000
|
||||
|
||||
|
|
|
@ -9,4 +9,5 @@ interface Medtrum {
|
|||
fun setUserOptions(): PumpEnactResult // set user settings
|
||||
fun clearAlarms(): PumpEnactResult // clear alarms
|
||||
fun deactivate(): PumpEnactResult // deactivate patch
|
||||
fun updateTime(): PumpEnactResult // update time
|
||||
}
|
|
@ -30,6 +30,7 @@ abstract class Command(
|
|||
STOP_PUMP,
|
||||
CLEAR_ALARMS, // so far only Medtrum specific
|
||||
DEACTIVATE, // so far only Medtrum specific
|
||||
UPDATE_TIME, // so far only Medtrum specific
|
||||
INSIGHT_SET_TBR_OVER_ALARM, // insight only
|
||||
CUSTOM_COMMAND
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ interface CommandQueue {
|
|||
fun loadEvents(callback: Callback?): Boolean
|
||||
fun clearAlarms(callback: Callback?): Boolean
|
||||
fun deactivate(callback: Callback?): Boolean
|
||||
fun updateTime(callback: Callback?): Boolean
|
||||
fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean
|
||||
fun isCustomCommandRunning(customCommandType: Class<out CustomCommand>): Boolean
|
||||
fun isCustomCommandInQueue(customCommandType: Class<out CustomCommand>): Boolean
|
||||
|
|
|
@ -395,6 +395,7 @@
|
|||
<string name="load_events">LOAD EVENTS</string>
|
||||
<string name="clear_alarms">CLEAR_ALARMS</string>
|
||||
<string name="deactivate">DEACTIVATE</string>
|
||||
<string name="update_time">UPDATE TIME</string>
|
||||
<string name="load_history">LOAD HISTORY %1$d</string>
|
||||
<string name="load_tdds">LOAD TDDs</string>
|
||||
<string name="set_profile">SET PROFILE</string>
|
||||
|
|
|
@ -22,6 +22,7 @@ import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNot
|
|||
import info.nightscout.implementation.queue.commands.CommandLoadEvents
|
||||
import info.nightscout.implementation.queue.commands.CommandLoadHistory
|
||||
import info.nightscout.implementation.queue.commands.CommandLoadTDDs
|
||||
import info.nightscout.implementation.queue.commands.CommandUpdateTime
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
|
@ -36,6 +37,7 @@ abstract class CommandQueueModule {
|
|||
@ContributesAndroidInjector abstract fun commandLoadEventsInjector(): CommandLoadEvents
|
||||
@ContributesAndroidInjector abstract fun commandClearAlarmsInjector(): CommandClearAlarms
|
||||
@ContributesAndroidInjector abstract fun commandDeactivateInjector(): CommandDeactivate
|
||||
@ContributesAndroidInjector abstract fun commandUpdateTimeInjector(): CommandUpdateTime
|
||||
@ContributesAndroidInjector abstract fun commandLoadHistoryInjector(): CommandLoadHistory
|
||||
@ContributesAndroidInjector abstract fun commandLoadTDDsInjector(): CommandLoadTDDs
|
||||
@ContributesAndroidInjector abstract fun commandReadStatusInjector(): CommandReadStatus
|
||||
|
|
|
@ -38,6 +38,7 @@ import info.nightscout.implementation.queue.commands.CommandStartPump
|
|||
import info.nightscout.implementation.queue.commands.CommandStopPump
|
||||
import info.nightscout.implementation.queue.commands.CommandTempBasalAbsolute
|
||||
import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
|
||||
import info.nightscout.implementation.queue.commands.CommandUpdateTime
|
||||
import info.nightscout.interfaces.AndroidPermission
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
|
@ -564,6 +565,19 @@ class CommandQueueImplementation @Inject constructor(
|
|||
return true
|
||||
}
|
||||
|
||||
override fun updateTime(callback: Callback?): Boolean {
|
||||
if (isRunning(CommandType.UPDATE_TIME)) {
|
||||
callback?.result(executingNowError())?.run()
|
||||
return false
|
||||
}
|
||||
// remove all unfinished
|
||||
removeAll(CommandType.UPDATE_TIME)
|
||||
// add new command to queue
|
||||
add(CommandUpdateTime(injector, callback))
|
||||
notifyAboutNewCommand()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean {
|
||||
if (isCustomCommandInQueue(customCommand.javaClass)) {
|
||||
callback?.result(executingNowError())?.run()
|
||||
|
|
|
@ -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 CommandUpdateTime(
|
||||
injector: HasAndroidInjector,
|
||||
callback: Callback?
|
||||
) : Command(injector, CommandType.UPDATE_TIME, 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.updateTime()
|
||||
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.update_time)
|
||||
|
||||
override fun log(): String = "UPDATE TIME"
|
||||
override fun cancel() {
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
|
||||
callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
|
||||
}
|
||||
}
|
|
@ -247,6 +247,10 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
commandQueue.deactivate(null)
|
||||
Assertions.assertEquals(6, commandQueue.size())
|
||||
|
||||
// add updateTime
|
||||
commandQueue.updateTime(null)
|
||||
Assertions.assertEquals(7, commandQueue.size())
|
||||
|
||||
commandQueue.clear()
|
||||
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
|
||||
commandQueue.pickup()
|
||||
|
@ -395,6 +399,22 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isUpdateTimeCommandInQueue() {
|
||||
// given
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.updateTime(null)
|
||||
|
||||
// then
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.UPDATE_TIME))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.updateTime(null)
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isLoadTDDsCommandInQueue() {
|
||||
// given
|
||||
|
|
|
@ -29,6 +29,7 @@ import info.nightscout.interfaces.pump.actions.CustomActionType
|
|||
import info.nightscout.interfaces.pump.defs.ManufacturerType
|
||||
import info.nightscout.interfaces.pump.defs.PumpDescription
|
||||
import info.nightscout.interfaces.pump.defs.PumpType
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.CommandQueue
|
||||
import info.nightscout.interfaces.queue.CustomCommand
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
|
@ -394,10 +395,6 @@ import kotlin.math.round
|
|||
return PumpEnactResult(injector) // Note: Can implement this if we implement history fully (no priority)
|
||||
}
|
||||
|
||||
override fun canHandleDST(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getCustomActions(): List<CustomAction>? {
|
||||
return null
|
||||
}
|
||||
|
@ -409,7 +406,20 @@ import kotlin.math.round
|
|||
return null
|
||||
}
|
||||
|
||||
override fun canHandleDST(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
||||
medtrumPump.needTimeUpdate = true
|
||||
// Update status to sync time with pump
|
||||
if (isInitialized()) {
|
||||
commandQueue.updateTime(object : Callback() {
|
||||
override fun run() {
|
||||
medtrumService?.timeUpdateNotification(this.result.success)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Medtrum interface
|
||||
|
@ -452,4 +462,14 @@ import kotlin.math.round
|
|||
val connectionOK = medtrumService?.deactivatePatch() ?: false
|
||||
return PumpEnactResult(injector).success(connectionOK)
|
||||
}
|
||||
|
||||
override fun updateTime(): PumpEnactResult {
|
||||
if (!isInitialized()) {
|
||||
val result = PumpEnactResult(injector).success(false)
|
||||
result.comment = "pump not initialized"
|
||||
return result
|
||||
}
|
||||
val connectionOK = medtrumService?.updateTime() ?: false
|
||||
return PumpEnactResult(injector).success(connectionOK)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,10 +194,19 @@ class MedtrumPump @Inject constructor(
|
|||
sp.putLong(R.string.key_patch_start_time, value)
|
||||
}
|
||||
|
||||
private var _pumpTimeZoneOffset = 0 // As reported by pump
|
||||
var pumpTimeZoneOffset: Int
|
||||
get() = _pumpTimeZoneOffset
|
||||
set(value) {
|
||||
_pumpTimeZoneOffset = value
|
||||
sp.putInt(R.string.key_pump_time_zone_offset, value)
|
||||
}
|
||||
|
||||
private var _pumpSN = 0L
|
||||
val pumpSN: Long
|
||||
get() = _pumpSN
|
||||
|
||||
var needTimeUpdate = false
|
||||
var lastTimeReceivedFromPump = 0L // Time in ms! // TODO: Consider removing as is not used?
|
||||
var suspendTime = 0L // Time in ms!
|
||||
var patchAge = 0L // Time in seconds?! // TODO: Not used
|
||||
|
@ -255,6 +264,7 @@ class MedtrumPump @Inject constructor(
|
|||
_deviceType = sp.getInt(R.string.key_device_type, 0)
|
||||
_swVersion = sp.getString(R.string.key_sw_version, "")
|
||||
_patchStartTime = sp.getLong(R.string.key_patch_start_time, 0L)
|
||||
_pumpTimeZoneOffset = sp.getInt(R.string.key_pump_time_zone_offset, 0)
|
||||
|
||||
loadActiveAlarms()
|
||||
|
||||
|
@ -267,9 +277,9 @@ class MedtrumPump @Inject constructor(
|
|||
}
|
||||
|
||||
fun pumpType(): PumpType =
|
||||
when(deviceType) {
|
||||
when (deviceType) {
|
||||
80, 88 -> PumpType.MEDTRUM_NANO
|
||||
else -> PumpType.MEDTRUM_UNTESTED
|
||||
else -> PumpType.MEDTRUM_UNTESTED
|
||||
}
|
||||
|
||||
fun loadUserSettingsFromSP() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_TIME_ZONE
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||
|
@ -10,6 +11,9 @@ import javax.inject.Inject
|
|||
class SetTimeZonePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
|
||||
var offsetMins: Int = 0
|
||||
|
||||
init {
|
||||
opCode = SET_TIME_ZONE.code
|
||||
|
@ -17,8 +21,16 @@ class SetTimeZonePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
|
|||
|
||||
override fun getRequest(): ByteArray {
|
||||
val time = MedtrumTimeUtil().getCurrentTimePumpSeconds()
|
||||
var offsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now())
|
||||
offsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now())
|
||||
if (offsetMins < 0) offsetMins += 65536
|
||||
return byteArrayOf(opCode) + offsetMins.toByteArray(2) + time.toByteArray(4)
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
medtrumPump.pumpTimeZoneOffset = offsetMins
|
||||
}
|
||||
return success
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,10 +189,44 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
|||
}
|
||||
|
||||
fun readPumpStatus() {
|
||||
// Update pump events
|
||||
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
|
||||
// Update time if needed
|
||||
if (medtrumPump.needTimeUpdate || medtrumPump.pumpTimeZoneOffset != dateUtil.getTimeZoneOffsetMinutes(dateUtil.now())) {
|
||||
aapsLogger.warn(LTag.PUMPCOMM, "Pump time update from readPumpStatus")
|
||||
timeUpdateNotification(updateTime(false))
|
||||
}
|
||||
// Update history
|
||||
loadEvents()
|
||||
}
|
||||
|
||||
fun timeUpdateNotification(updateSuccess: Boolean) {
|
||||
if (updateSuccess) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Pump time updated")
|
||||
medtrumPump.needTimeUpdate = false
|
||||
uiInteraction.addNotification(
|
||||
Notification.INSIGHT_DATE_TIME_UPDATED, // :---)
|
||||
rh.gs(info.nightscout.core.ui.R.string.pump_time_updated),
|
||||
Notification.INFO,
|
||||
)
|
||||
} else {
|
||||
aapsLogger.error(LTag.PUMPCOMM, "Failed to update pump time")
|
||||
uiInteraction.addNotification(
|
||||
Notification.PUMP_TIMEZONE_UPDATE_FAILED,
|
||||
rh.gs(R.string.pump_time_update_failed),
|
||||
Notification.URGENT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTime(needLoadHistory: Boolean = true): Boolean {
|
||||
var result = sendPacketAndGetResponse(SetTimePacket(injector))
|
||||
if (result) result = sendPacketAndGetResponse(SetTimeZonePacket(injector))
|
||||
if (needLoadHistory) {
|
||||
if (result) result = loadEvents()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun loadEvents(): Boolean {
|
||||
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
|
||||
// Sync records (based on the info we have from the sync)
|
||||
|
@ -785,6 +819,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
|||
// Succes!
|
||||
responseHandled = true
|
||||
responseSuccess = true
|
||||
medtrumPump.needTimeUpdate = false
|
||||
timeUpdateNotification(true)
|
||||
toState(SynchronizeState())
|
||||
} else if (mPacket?.failed == true) {
|
||||
// Failure
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<string name="key_actual_basal_profile" translatable="false">actual_basal_profile</string>
|
||||
<string name="key_current_sequence_number" translatable="false">current_sequence_number</string>
|
||||
<string name="key_synced_sequence_number" translatable="false">synced_sequence_number</string>
|
||||
<string name="key_pump_time_zone_offset" translatable="false">pump_time_zone_offset</string>
|
||||
|
||||
<string name="medtrum">Medtrum</string>
|
||||
<string name="medtrum_pump_shortname">MT</string>
|
||||
|
@ -74,6 +75,7 @@
|
|||
<string name="alarm_base_fault">Base fault</string>
|
||||
<string name="alarm_battery_out">Battery out</string>
|
||||
<string name="alarm_no_calibration">No calibration</string>
|
||||
<string name="pump_time_update_failed">Failed to update pump timezone, snooze message and refresh manually.</string>
|
||||
|
||||
<!-- wizard-->
|
||||
<string name="string_start_complete">Complete</string>
|
||||
|
|
|
@ -38,4 +38,19 @@ class SetTimeZonePacketTest : MedtrumTestBase() {
|
|||
assertEquals(7, result.size)
|
||||
assertEquals(expectedByteArray.contentToString(), result.contentToString())
|
||||
}
|
||||
|
||||
@Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
|
||||
// Inputs
|
||||
val response = byteArrayOf(7, 10, 3, 0, 0, 0, -38)
|
||||
|
||||
// Call
|
||||
val packet = SetTimeZonePacket(packetInjector)
|
||||
val result = packet.handleResponse(response)
|
||||
|
||||
// Expected values
|
||||
val expectedOffsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now())
|
||||
|
||||
assertTrue(result)
|
||||
assertEquals(expectedOffsetMins, medtrumPump.pumpTimeZoneOffset)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue