OfflineEvent -> room
This commit is contained in:
parent
82cce81d0b
commit
6735d22934
63 changed files with 4653 additions and 409 deletions
|
@ -82,5 +82,9 @@ class CompatDBHelper @Inject constructor(
|
|||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged")
|
||||
rxBus.send(EventProfileSwitchChanged())
|
||||
}
|
||||
it.filterIsInstance<OfflineEvent>().firstOrNull()?.let {
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventOfflineChange")
|
||||
rxBus.send(EventOfflineChange())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -83,7 +83,7 @@ open class AppModule {
|
|||
@Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolderImpl): NotificationHolder
|
||||
@Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefsImpl): ImportExportPrefs
|
||||
@Binds fun bindIconsProviderInterface(iconsProvider: IconsProviderImplementation): IconsProvider
|
||||
@Binds fun bindLoopInterface(loopPlugin: LoopPlugin): LoopInterface
|
||||
@Binds fun bindLoopInterface(loopPlugin: LoopPlugin): Loop
|
||||
@Binds fun bindIobCobCalculatorInterface(iobCobCalculatorPlugin: IobCobCalculatorPlugin): IobCobCalculator
|
||||
@Binds fun bindSmsCommunicatorInterface(smsCommunicatorPlugin: SmsCommunicatorPlugin): SmsCommunicator
|
||||
@Binds fun bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
|
||||
|
|
|
@ -17,7 +17,7 @@ import info.nightscout.androidaps.database.entities.TemporaryTarget
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogCarbsBinding
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
|
@ -226,7 +226,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY),
|
||||
ValueWithUnit.fromGlucoseUnit(activityTT, units.asText),
|
||||
ValueWithUnit.Minute(activityTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.ACTIVITY,
|
||||
|
@ -245,7 +245,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
||||
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
||||
ValueWithUnit.Minute(eatingSoonTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
@ -264,7 +264,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA),
|
||||
ValueWithUnit.fromGlucoseUnit(hypoTT, units.asText),
|
||||
ValueWithUnit.Minute(hypoTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.HYPOGLYCEMIA,
|
||||
|
|
|
@ -16,7 +16,7 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit
|
|||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogInsulinBinding
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -186,7 +186,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
||||
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
||||
ValueWithUnit.Minute(eatingSoonTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
|
|
@ -12,9 +12,13 @@ import androidx.fragment.app.FragmentManager
|
|||
import dagger.android.support.DaggerDialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
|
@ -29,8 +33,13 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoopDialog : DaggerDialogFragment() {
|
||||
|
@ -48,6 +57,8 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var configBuilder: ConfigBuilder
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
private var showOkCancel: Boolean = true
|
||||
private var _binding: DialogLoopBinding? = null
|
||||
|
@ -58,6 +69,8 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
val disposable = CompositeDisposable()
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
@ -118,6 +131,7 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
super.onDestroyView()
|
||||
_binding = null
|
||||
loopHandler.removeCallbacksAndMessages(null)
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
var task: Runnable? = null
|
||||
|
@ -238,7 +252,6 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
fun onClick(v: View): Boolean {
|
||||
val profile = profileFunction.getProfile() ?: return true
|
||||
when (v.id) {
|
||||
R.id.overview_closeloop -> {
|
||||
uel.log(Action.CLOSED_LOOP_MODE, Sources.LoopDialog)
|
||||
|
@ -274,7 +287,13 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
}
|
||||
})
|
||||
loopPlugin.createOfflineEvent(24 * 60) // upload 24h, we don't know real duration
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.days(365).msecs(), OfflineEvent.Reason.DISABLE_LOOP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -284,13 +303,23 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
||||
configBuilder.storeSettings("EnablingLoop")
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_resume, R.id.overview_reconnect -> {
|
||||
uel.log(if (v.id == R.id.overview_resume) Action.RESUME else Action.RECONNECT, Sources.LoopDialog)
|
||||
loopPlugin.suspendTo(0L)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
|
@ -300,55 +329,96 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
})
|
||||
sp.putBoolean(R.string.key_objectiveusereconnect, true)
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_1h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
||||
loopPlugin.suspendLoop(60)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(1).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_2h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
||||
loopPlugin.suspendLoop(120)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(2).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_3h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
||||
loopPlugin.suspendLoop(180)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(3).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_10h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(10))
|
||||
loopPlugin.suspendLoop(600)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(10).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_15m -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(15))
|
||||
loopPlugin.disconnectPump(15, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(15).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_30m -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(30))
|
||||
loopPlugin.disconnectPump(30, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(30).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_1h -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
||||
loopPlugin.disconnectPump(60, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(60).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
|
@ -356,14 +426,26 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
|
||||
R.id.overview_disconnect_2h -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
||||
loopPlugin.disconnectPump(120, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(120).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_3h -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
||||
loopPlugin.disconnectPump(180, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(180).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import info.nightscout.androidaps.database.entities.TemporaryTarget
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogTemptargetBinding
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
|
@ -196,7 +196,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
} else {
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = eventTime,
|
||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||
reason = when (reason) {
|
||||
|
|
|
@ -16,18 +16,19 @@ import info.nightscout.androidaps.data.DetailedBolusInfo
|
|||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventNewBG
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface.LastRun
|
||||
import info.nightscout.androidaps.interfaces.Loop.LastRun
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -96,7 +97,7 @@ open class LoopPlugin @Inject constructor(
|
|||
.enableByDefault(config.APS)
|
||||
.description(R.string.description_loop),
|
||||
aapsLogger, resourceHelper, injector
|
||||
), LoopInterface {
|
||||
), Loop {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private var lastBgTriggeredRun: Long = 0
|
||||
|
@ -158,48 +159,19 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun suspendTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", false)
|
||||
sp.putBoolean("isDisconnected", false)
|
||||
override fun minutesToEndOfSuspend(): Int {
|
||||
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||
return if (offlineEventWrapped is ValueWrapper.Existing) T.msecs(offlineEventWrapped.value.timestamp + offlineEventWrapped.value.duration - dateUtil.now()).mins().toInt()
|
||||
else 0
|
||||
}
|
||||
|
||||
fun superBolusTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", true)
|
||||
sp.putBoolean("isDisconnected", false)
|
||||
}
|
||||
|
||||
private fun disconnectTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", false)
|
||||
sp.putBoolean("isDisconnected", true)
|
||||
}
|
||||
|
||||
fun minutesToEndOfSuspend(): Int {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return 0
|
||||
val now = System.currentTimeMillis()
|
||||
val millisDiff = loopSuspendedTill - now
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return 0
|
||||
}
|
||||
return (millisDiff / 60.0 / 1000.0).toInt()
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
override val isSuspended: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
get() = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
|
||||
|
||||
override var enabled: Boolean
|
||||
get() = isEnabled()
|
||||
set(value) { setPluginEnabled(PluginType.LOOP, value)}
|
||||
|
||||
val isLGS: Boolean
|
||||
get() {
|
||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||
|
@ -211,30 +183,16 @@ open class LoopPlugin @Inject constructor(
|
|||
return isLGS
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
val isSuperBolus: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return sp.getBoolean("isSuperBolus", false)
|
||||
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||
return offlineEventWrapped is ValueWrapper.Existing && offlineEventWrapped.value.reason == OfflineEvent.Reason.SUPER_BOLUS
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
val isDisconnected: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return sp.getBoolean("isDisconnected", false)
|
||||
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||
return offlineEventWrapped is ValueWrapper.Existing && offlineEventWrapped.value.reason == OfflineEvent.Reason.DISCONNECT_PUMP
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
|
@ -642,11 +600,17 @@ open class LoopPlugin @Inject constructor(
|
|||
return virtualPumpPlugin.isEnabled(PluginType.PUMP)
|
||||
}
|
||||
|
||||
fun disconnectPump(durationInMinutes: Int, profile: Profile?) {
|
||||
override fun goToZeroTemp(durationInMinutes: Int, profile: Profile, reason: OfflineEvent.Reason) {
|
||||
val pump = activePlugin.activePump
|
||||
disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), reason))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile!!, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
|
@ -654,7 +618,7 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
})
|
||||
} else {
|
||||
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile!!, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
|
@ -671,11 +635,16 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
})
|
||||
}
|
||||
createOfflineEvent(durationInMinutes)
|
||||
}
|
||||
|
||||
override fun suspendLoop(durationInMinutes: Int) {
|
||||
suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
|
@ -683,20 +652,6 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
})
|
||||
createOfflineEvent(durationInMinutes)
|
||||
}
|
||||
|
||||
override fun createOfflineEvent(durationInMinutes: Int) {
|
||||
disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
type = TherapyEvent.Type.APS_OFFLINE,
|
||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||
enteredBy = "openaps://" + "AndroidAPS",
|
||||
glucoseUnit = TherapyEvent.GlucoseUnit.MGDL
|
||||
)).subscribe(
|
||||
{ result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) }
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -39,6 +39,7 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
processChangedFoodsCompat()
|
||||
processChangedTherapyEventsCompat()
|
||||
processChangedDeviceStatusesCompat()
|
||||
processChangedOfflineEventsCompat()
|
||||
processChangedProfileStore()
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +56,7 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
sp.remove(R.string.key_ns_extended_bolus_last_synced_id)
|
||||
sp.remove(R.string.key_ns_therapy_event_last_synced_id)
|
||||
sp.remove(R.string.key_ns_profile_switch_last_synced_id)
|
||||
sp.remove(R.string.key_ns_offline_event_last_synced_id)
|
||||
sp.remove(R.string.key_ns_profile_store_last_synced_timestamp)
|
||||
}
|
||||
|
||||
|
@ -553,6 +555,49 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
return false
|
||||
}
|
||||
|
||||
override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
// Prepared for v3 (returns all modified after)
|
||||
override fun changedOfflineEvents(): List<OfflineEvent> {
|
||||
val startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
|
||||
return appRepository.getModifiedOfflineEventsDataFromId(startId).blockingGet().also {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Loading OfflineEvent data for sync from $startId. Records ${it.size}")
|
||||
}
|
||||
}
|
||||
|
||||
private var lastOeId = -1L
|
||||
private var lastOeTime = -1L
|
||||
override fun processChangedOfflineEventsCompat(): Boolean {
|
||||
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastOeId && dateUtil.now() - lastOeTime < 5000) return false
|
||||
lastOeId = startId
|
||||
lastOeTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading OfflineEvent data Start: $startId ID: ${oe.first.id} HistoryID: ${oe.second} ")
|
||||
when {
|
||||
// without nsId = create new
|
||||
oe.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", oe.first.toJson(true, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second), "$startId/$lastDbId")
|
||||
// existing with nsId = update
|
||||
oe.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", oe.first.interfaceIDs.nightscoutId, oe.first.toJson(false, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun confirmLastProfileStore(lastSynced: Long) {
|
||||
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
||||
}
|
||||
|
|
|
@ -251,6 +251,26 @@ class NSClientAddAckWorker(
|
|||
dataSyncSelector.confirmLastProfileStore(ack.originalObject.timestampSync)
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id))
|
||||
}
|
||||
|
||||
is PairOfflineEvent -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
repository.runTransactionForResult(UpdateNsIdOfflineEventTransaction(pair.value))
|
||||
.doOnError { error ->
|
||||
aapsLogger.error(LTag.DATABASE, "Updated ns id of OfflineEvent failed", error)
|
||||
ret = Result.failure((workDataOf("Error" to error.toString())))
|
||||
}
|
||||
.doOnSuccess {
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated ns id of OfflineEvent " + pair.value)
|
||||
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedOfflineEventsCompat()
|
||||
}
|
||||
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import info.nightscout.androidaps.receivers.DataWorker
|
|||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.JsonHelper
|
||||
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -194,7 +193,6 @@ class NSClientAddUpdateWorker(
|
|||
eventType == TherapyEvent.Type.ANNOUNCEMENT.text ||
|
||||
eventType == TherapyEvent.Type.QUESTION.text ||
|
||||
eventType == TherapyEvent.Type.EXERCISE.text ||
|
||||
eventType == TherapyEvent.Type.APS_OFFLINE.text ||
|
||||
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
|
||||
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT) {
|
||||
therapyEventFromJson(json)?.let { therapyEvent ->
|
||||
|
@ -341,6 +339,43 @@ class NSClientAddUpdateWorker(
|
|||
}
|
||||
} ?: aapsLogger.error("Error parsing ProfileSwitch json $json")
|
||||
}
|
||||
eventType == TherapyEvent.Type.APS_OFFLINE.text ->
|
||||
if (sp.getBoolean(R.string.key_ns_receive_offline_event, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||
offlineEventFromJson(json)?.let { offlineEvent ->
|
||||
repository.runTransactionForResult(SyncNsOfflineEventTransaction(offlineEvent, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach { oe ->
|
||||
uel.log(Action.LOOP_CHANGE, Sources.NSClient,
|
||||
ValueWithUnit.OfflineEventReason(oe.reason),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $oe")
|
||||
}
|
||||
result.invalidated.forEach { oe ->
|
||||
uel.log(Action.LOOP_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.OfflineEventReason(oe.reason),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated OfflineEvent $oe")
|
||||
}
|
||||
result.ended.forEach { oe ->
|
||||
uel.log(Action.LOOP_CHANGE, Sources.NSClient,
|
||||
ValueWithUnit.OfflineEventReason(oe.reason),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $oe")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId OfflineEvent $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing OfflineEvent json $json")
|
||||
}
|
||||
}
|
||||
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
|
||||
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
|
||||
|
|
|
@ -125,6 +125,15 @@ class NSClientUpdateRemoveAckWorker(
|
|||
dataSyncSelector.processChangedProfileSwitchesCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairOfflineEvent -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedOfflineEventsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -10,11 +10,7 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.database.entities.TemporaryBasal
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.*
|
||||
import info.nightscout.androidaps.extensions.*
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
|
@ -533,6 +529,11 @@ class OverviewData @Inject constructor(
|
|||
.map { EffectiveProfileSwitchDataPoint(it) }
|
||||
.forEach(filteredTreatments::add)
|
||||
|
||||
// OfflineEvent
|
||||
repository.getOfflineEventDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||
.map { TherapyEventDataPoint(TherapyEvent(timestamp = it.timestamp, duration = it.duration, type = TherapyEvent.Type.APS_OFFLINE, glucoseUnit = TherapyEvent.GlucoseUnit.MMOL), resourceHelper, profileFunction, translator) }
|
||||
.forEach(filteredTreatments::add)
|
||||
|
||||
// Extended bolus
|
||||
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
|
||||
repository.getExtendedBolusDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||
|
|
|
@ -139,9 +139,9 @@ class OverviewPlugin @Inject constructor(
|
|||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ overviewData.preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventProfileSwitchChanged::class.java)
|
||||
.toObservable(EventNewBasalProfile::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadProfile("EventProfileSwitchChanged") }, fabricPrivacy::logException))
|
||||
.subscribe({ loadProfile("EventNewBasalProfile") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
|
|
|
@ -11,25 +11,26 @@ import androidx.work.Worker
|
|||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
|
@ -41,7 +42,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
|
|||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -72,7 +72,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val commandQueue: CommandQueueProvider,
|
||||
private val loopPlugin: LoopPlugin,
|
||||
private val loop: Loop,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val xdripCalibrations: XdripCalibrations,
|
||||
private var otp: OneTimePassword,
|
||||
|
@ -340,14 +340,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
private fun processLOOP(divided: Array<String>, receivedSms: Sms) {
|
||||
when (divided[1].uppercase(Locale.getDefault())) {
|
||||
"DISABLE", "STOP" -> {
|
||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
if (loop.enabled) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopdisablereplywithcode), passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.LOOP_DISABLED, Sources.SMS)
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
||||
loop.enabled = false
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_STOP"))
|
||||
|
@ -364,14 +364,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
"ENABLE", "START" -> {
|
||||
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
if (!loop.enabled) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopenablereplywithcode), passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.LOOP_ENABLED, Sources.SMS)
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
||||
loop.enabled= true
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)))
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_START"))
|
||||
}
|
||||
|
@ -382,8 +382,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
"STATUS" -> {
|
||||
val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
if (loopPlugin.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
|
||||
val reply = if (loop.enabled) {
|
||||
if (loop.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loop.minutesToEndOfSuspend())
|
||||
else resourceHelper.gs(R.string.smscommunicator_loopisenabled)
|
||||
} else
|
||||
resourceHelper.gs(R.string.loopisdisabled)
|
||||
|
@ -398,7 +398,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.RESUME, Sources.SMS)
|
||||
loopPlugin.suspendTo(0L)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME"))
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
|
@ -409,7 +414,6 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
})
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loopresumed)))
|
||||
}
|
||||
})
|
||||
|
@ -434,8 +438,13 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (result.success) {
|
||||
loopPlugin.suspendTo(dateUtil.now() + anInteger() * 60L * 1000)
|
||||
loopPlugin.createOfflineEvent(anInteger() * 60)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(anInteger().toLong()).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_SUSPENDED"))
|
||||
val replyText = resourceHelper.gs(R.string.smscommunicator_loopsuspended) + " " +
|
||||
resourceHelper.gs(if (result.success) R.string.smscommunicator_tempbasalcanceled else R.string.smscommunicator_tempbasalcancelfailed)
|
||||
|
@ -512,10 +521,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
if (!result.success) {
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_pumpconnectfail)))
|
||||
} else {
|
||||
loopPlugin.suspendTo(0L)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_reconnect)))
|
||||
rxBus.send(EventRefreshOverview("SMS_PUMP_START"))
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -536,8 +549,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.DISCONNECT, Sources.SMS)
|
||||
val profile = profileFunction.getProfile()
|
||||
loopPlugin.disconnectPump(duration, profile)
|
||||
val profile = profileFunction.getProfile() ?: return
|
||||
loop.goToZeroTemp(duration, profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||
rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT"))
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_pumpdisconnected)))
|
||||
}
|
||||
|
@ -832,7 +845,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
currentProfile.units == GlucoseUnit.MMOL -> Constants.defaultEatingSoonTTmmol
|
||||
else -> Constants.defaultEatingSoonTTmgdl
|
||||
}
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
@ -979,7 +992,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
var tt = sp.getDouble(keyTarget, if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL)
|
||||
tt = Profile.toCurrentUnits(profileFunction, tt)
|
||||
tt = if (tt > 0) tt else if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
|
|
@ -20,7 +20,7 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
|||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.extensions.total
|
||||
import info.nightscout.androidaps.extensions.valueToUnits
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
|
@ -572,7 +572,7 @@ class ActionStringHandler @Inject constructor(
|
|||
|
||||
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
||||
if (duration != 0) {
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||
reason = TemporaryTarget.Reason.WEAR,
|
||||
|
|
|
@ -86,7 +86,6 @@ open class CommandQueue @Inject constructor(
|
|||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.failedupdatebasalprofile), R.raw.boluserror)
|
||||
}
|
||||
if (result.enacted) {
|
||||
rxBus.send(EventNewBasalProfile())
|
||||
repository.createEffectiveProfileSwitch(
|
||||
EffectiveProfileSwitch(
|
||||
timestamp = dateUtil.now(),
|
||||
|
@ -104,6 +103,7 @@ open class CommandQueue @Inject constructor(
|
|||
insulinConfiguration = it.insulinConfiguration
|
||||
)
|
||||
)
|
||||
rxBus.send(EventNewBasalProfile())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -12,6 +12,7 @@ import info.nightscout.androidaps.data.DetailedBolusInfo
|
|||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.BolusCalculatorResult
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
|
@ -374,7 +375,7 @@ class BolusWizard @Inject constructor(
|
|||
if (useSuperBolus) {
|
||||
uel.log(Action.SUPERBOLUS_TBR, Sources.WizardDialog)
|
||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
loopPlugin.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000)
|
||||
loopPlugin.goToZeroTemp(2 * 60, profile, OfflineEvent.Reason.SUPER_BOLUS)
|
||||
rxBus.send(EventRefreshOverview("WizardDialog"))
|
||||
}
|
||||
|
||||
|
@ -408,7 +409,7 @@ class BolusWizard @Inject constructor(
|
|||
context = ctx
|
||||
mgdlGlucose = Profile.toMgdl(bg, profile.units)
|
||||
glucoseType = DetailedBolusInfo.MeterType.MANUAL
|
||||
carbTime = this@BolusWizard.carbTime
|
||||
carbsTimestamp = dateUtil.now() + T.mins(this@BolusWizard.carbTime.toLong()).msecs()
|
||||
bolusCalculatorResult = createBolusCalculatorResult()
|
||||
notes = this@BolusWizard.notes
|
||||
if (insulin > 0 || carbs > 0) {
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<string name="key_ns_temporary_basal_last_synced_id" translatable="false">ns_temporary_basal_last_synced_id</string>
|
||||
<string name="key_ns_extended_bolus_last_synced_id" translatable="false">ns_extended_bolus_last_synced_id</string>
|
||||
<string name="key_ns_profile_switch_last_synced_id" translatable="false">profile_switch_last_synced_id</string>
|
||||
<string name="key_ns_offline_event_last_synced_id" translatable="false">ns_offline_event_last_synced_id</string>
|
||||
<string name="key_ns_profile_store_last_synced_timestamp" translatable="false">ns_profile_store_last_synced_timestamp</string>
|
||||
<string name="key_local_profile_last_change" translatable="false">local_profile_last_change</string>
|
||||
|
||||
|
@ -1137,8 +1138,11 @@
|
|||
<string name="ns_receive_temp_target">Receive temporary targets</string>
|
||||
<string name="ns_receive_temp_target_summary">Accept temporary targets entered through NS or NSClient</string>
|
||||
<string name="key_ns_receive_profile_switch" translatable="false">ns_receive_profile_switch</string>
|
||||
<string name="key_ns_receive_offline_event" translatable="false">ns_receive_offline_event</string>
|
||||
<string name="ns_receive_profile_switch">Receive profile switches</string>
|
||||
<string name="ns_receive_profile_switch_summary">Accept profile switches entered through NS or NSClient</string>
|
||||
<string name="ns_receive_offline_event">Receive APS offline events</string>
|
||||
<string name="ns_receive_offline_event_summary">Accept APS Offline events entered through NS or NSClient</string>
|
||||
<string name="key_ns_receive_insulin" translatable="false">ns_receive_insulin</string>
|
||||
<string name="ns_receive_insulin">Receive insulin</string>
|
||||
<string name="ns_receive_insulin_summary">Accept insulin entered through NS or NSClient (it\'s not delivered, only calculated towards IOB)</string>
|
||||
|
|
|
@ -78,6 +78,12 @@
|
|||
android:summary="@string/ns_receive_therapy_events_summary"
|
||||
android:title="@string/ns_receive_therapy_events" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_ns_receive_offline_event"
|
||||
android:summary="@string/ns_receive_offline_event_summary"
|
||||
android:title="@string/ns_receive_offline_event" />
|
||||
|
||||
</androidx.preference.PreferenceScreen>>
|
||||
|
||||
<androidx.preference.PreferenceScreen
|
||||
|
|
|
@ -5,7 +5,6 @@ package info.nightscout.androidaps.plugins.general.smsCommunicator
|
|||
import android.telephony.SmsManager
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.utils.buildHelper.ConfigImpl
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.TestBaseWithProfile
|
||||
|
@ -13,7 +12,10 @@ import info.nightscout.androidaps.data.IobTotal
|
|||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.database.transactions.Transaction
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
|
@ -26,13 +28,13 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
|
|||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentService
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.queue.CommandQueue
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.XdripCalibrations
|
||||
import info.nightscout.androidaps.utils.buildHelper.ConfigImpl
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.Single
|
||||
import org.junit.Assert
|
||||
|
@ -45,7 +47,6 @@ import org.mockito.Mockito
|
|||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.anyLong
|
||||
import org.mockito.invocation.InvocationOnMock
|
||||
import org.mockito.stubbing.Answer
|
||||
import org.powermock.api.mockito.PowerMockito
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest
|
||||
import org.powermock.modules.junit4.PowerMockRunner
|
||||
|
@ -107,8 +108,8 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
`when`(sp.getString(R.string.key_smscommunicator_allowednumbers, "")).thenReturn("1234;5678")
|
||||
|
||||
`when`(
|
||||
repository.runTransactionForResult(anyObject<InsertTemporaryTargetAndCancelCurrentTransaction>())
|
||||
).thenReturn(Single.just(InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult().apply {
|
||||
repository.runTransactionForResult(anyObject<InsertAndCancelCurrentTemporaryTargetTransaction>())
|
||||
).thenReturn(Single.just(InsertAndCancelCurrentTemporaryTargetTransaction.TransactionResult().apply {
|
||||
}))
|
||||
val glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtilMocked)
|
||||
|
||||
|
@ -309,7 +310,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
`when`(sp.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(true)
|
||||
|
||||
//LOOP STATUS : disabled
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(false)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(false)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP STATUS")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -318,7 +319,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
|
||||
//LOOP STATUS : suspended
|
||||
PowerMockito.`when`(loopPlugin.minutesToEndOfSuspend()).thenReturn(10)
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(true)
|
||||
PowerMockito.`when`(loopPlugin.isSuspended).thenReturn(true)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP STATUS")
|
||||
|
@ -327,7 +328,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
Assert.assertEquals("Suspended (10 m)", smsCommunicatorPlugin.messages[1].text)
|
||||
|
||||
//LOOP STATUS : enabled
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(true)
|
||||
PowerMockito.`when`(loopPlugin.isSuspended).thenReturn(false)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP STATUS")
|
||||
|
@ -337,7 +338,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
Assert.assertEquals("Loop is enabled", smsCommunicatorPlugin.messages[1].text)
|
||||
|
||||
//LOOP : wrong format
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(true)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -346,7 +347,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text)
|
||||
|
||||
//LOOP DISABLE : already disabled
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(false)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(false)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP DISABLE")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -356,11 +357,11 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
|
||||
//LOOP DISABLE : from enabled
|
||||
hasBeenRun = false
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true)
|
||||
PowerMockito.doAnswer(Answer {
|
||||
hasBeenRun = true
|
||||
null
|
||||
} as Answer<*>).`when`(loopPlugin).setPluginEnabled(PluginType.LOOP, false)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(true)
|
||||
// PowerMockito.doAnswer(Answer {
|
||||
// hasBeenRun = true
|
||||
// null
|
||||
// } as Answer<*>).`when`(loopPlugin).setPluginEnabled(PluginType.LOOP, false)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP DISABLE")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -371,10 +372,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
smsCommunicatorPlugin.processSms(Sms("1234", passCode))
|
||||
Assert.assertEquals(passCode, smsCommunicatorPlugin.messages[2].text)
|
||||
Assert.assertEquals("Loop has been disabled Temp basal canceled", smsCommunicatorPlugin.messages[3].text)
|
||||
Assert.assertTrue(hasBeenRun)
|
||||
//Assert.assertTrue(hasBeenRun)
|
||||
|
||||
//LOOP ENABLE : already enabled
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(true)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP ENABLE")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -384,11 +385,11 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
|
||||
//LOOP ENABLE : from disabled
|
||||
hasBeenRun = false
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(false)
|
||||
PowerMockito.doAnswer(Answer {
|
||||
hasBeenRun = true
|
||||
null
|
||||
} as Answer<*>).`when`(loopPlugin).setPluginEnabled(PluginType.LOOP, true)
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(false)
|
||||
// PowerMockito.doAnswer(Answer {
|
||||
// hasBeenRun = true
|
||||
// null
|
||||
// } as Answer<*>).`when`(loopPlugin).setPluginEnabled(PluginType.LOOP, true)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP ENABLE")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -399,9 +400,13 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
smsCommunicatorPlugin.processSms(Sms("1234", passCode))
|
||||
Assert.assertEquals(passCode, smsCommunicatorPlugin.messages[2].text)
|
||||
Assert.assertEquals("Loop has been enabled", smsCommunicatorPlugin.messages[3].text)
|
||||
Assert.assertTrue(hasBeenRun)
|
||||
//Assert.assertTrue(hasBeenRun)
|
||||
|
||||
//LOOP RESUME : already enabled
|
||||
`when`(
|
||||
repository.runTransactionForResult(anyObject<Transaction<CancelCurrentOfflineEventIfAnyTransaction.TransactionResult>>())
|
||||
).thenReturn(Single.just(CancelCurrentOfflineEventIfAnyTransaction.TransactionResult().apply {
|
||||
}))
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP RESUME")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -430,6 +435,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
Assert.assertEquals("Wrong duration", smsCommunicatorPlugin.messages[1].text)
|
||||
|
||||
//LOOP SUSPEND 100 : suspend for 100 min + correct answer
|
||||
`when`(
|
||||
repository.runTransactionForResult(anyObject<Transaction<InsertAndCancelCurrentOfflineEventTransaction.TransactionResult>>())
|
||||
).thenReturn(Single.just(InsertAndCancelCurrentOfflineEventTransaction.TransactionResult().apply {
|
||||
}))
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "LOOP SUSPEND 100")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -523,7 +532,11 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text)
|
||||
|
||||
//PUMP CONNECT
|
||||
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true)
|
||||
`when`(
|
||||
repository.runTransactionForResult(anyObject<Transaction<CancelCurrentOfflineEventIfAnyTransaction.TransactionResult>>())
|
||||
).thenReturn(Single.just(CancelCurrentOfflineEventIfAnyTransaction.TransactionResult().apply {
|
||||
}))
|
||||
PowerMockito.`when`(loopPlugin.enabled).thenReturn(true)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "PUMP CONNECT")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
@ -551,6 +564,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
|||
Assert.assertEquals("Wrong duration", smsCommunicatorPlugin.messages[1].text)
|
||||
|
||||
//PUMP DISCONNECT 30
|
||||
`when`(profileFunction.getProfile()).thenReturn(validProfile)
|
||||
smsCommunicatorPlugin.messages = ArrayList()
|
||||
sms = Sms("1234", "PUMP DISCONNECT 30")
|
||||
smsCommunicatorPlugin.processSms(sms)
|
||||
|
|
|
@ -8,7 +8,7 @@ import dagger.android.HasAndroidInjector
|
|||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
|
@ -45,7 +45,7 @@ class AutomationPlugin @Inject constructor(
|
|||
private val context: Context,
|
||||
private val sp: SP,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val loopPlugin: LoopInterface,
|
||||
private val loopPlugin: Loop,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val constraintChecker: ConstraintChecker,
|
||||
aapsLogger: AAPSLogger,
|
||||
|
|
|
@ -9,7 +9,7 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
|||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.ConfigBuilder
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -19,7 +19,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|||
import javax.inject.Inject
|
||||
|
||||
class ActionLoopDisable(injector: HasAndroidInjector) : Action(injector) {
|
||||
@Inject lateinit var loopPlugin: LoopInterface
|
||||
@Inject lateinit var loopPlugin: Loop
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var configBuilder: ConfigBuilder
|
||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
|
|
|
@ -8,7 +8,7 @@ import info.nightscout.androidaps.database.entities.UserEntry
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.interfaces.ConfigBuilder
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -20,7 +20,7 @@ import javax.inject.Inject
|
|||
class ActionLoopEnable(injector: HasAndroidInjector) : Action(injector) {
|
||||
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var loopPlugin: LoopInterface
|
||||
@Inject lateinit var loopPlugin: Loop
|
||||
@Inject lateinit var configBuilder: ConfigBuilder
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
|
|
@ -4,33 +4,46 @@ import androidx.annotation.DrawableRes
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.UserEntry
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.interfaces.ConfigBuilder
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class ActionLoopResume(injector: HasAndroidInjector) : Action(injector) {
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var loopPlugin: LoopInterface
|
||||
@Inject lateinit var loopPlugin: Loop
|
||||
@Inject lateinit var configBuilder: ConfigBuilder
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
|
||||
override fun friendlyName(): Int = R.string.resumeloop
|
||||
override fun shortDescription(): String = resourceHelper.gs(R.string.resumeloop)
|
||||
@DrawableRes override fun icon(): Int = R.drawable.ic_replay_24dp
|
||||
|
||||
val disposable = CompositeDisposable()
|
||||
|
||||
override fun doAction(callback: Callback) {
|
||||
if (loopPlugin.isSuspended) {
|
||||
loopPlugin.suspendTo(0)
|
||||
configBuilder.storeSettings("ActionLoopResume")
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("ActionLoopResume"))
|
||||
uel.log(UserEntry.Action.RESUME, Sources.Automation, title)
|
||||
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
|
||||
|
|
|
@ -9,7 +9,7 @@ import info.nightscout.androidaps.database.entities.UserEntry
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration
|
||||
|
@ -23,7 +23,7 @@ import javax.inject.Inject
|
|||
|
||||
class ActionLoopSuspend(injector: HasAndroidInjector) : Action(injector) {
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var loopPlugin: LoopInterface
|
||||
@Inject lateinit var loopPlugin: Loop
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import info.nightscout.androidaps.database.entities.TemporaryTarget
|
|||
import info.nightscout.androidaps.database.entities.UserEntry
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
|
@ -59,7 +59,7 @@ class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) {
|
|||
@DrawableRes override fun icon(): Int = R.drawable.ic_temptarget_high
|
||||
|
||||
override fun doAction(callback: Callback) {
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(tt()))
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(tt()))
|
||||
.subscribe({ result ->
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||
|
|
|
@ -4,7 +4,7 @@ import dagger.android.AndroidInjector
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.TestBase
|
||||
import info.nightscout.androidaps.interfaces.ConfigBuilder
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopEnable
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnectorTest
|
||||
|
@ -20,7 +20,7 @@ import org.powermock.modules.junit4.PowerMockRunner
|
|||
@RunWith(PowerMockRunner::class)
|
||||
class AutomationEventTest : TestBase() {
|
||||
|
||||
@Mock lateinit var loopPlugin: LoopInterface
|
||||
@Mock lateinit var loopPlugin: Loop
|
||||
@Mock lateinit var resourceHelper: ResourceHelper
|
||||
@Mock lateinit var configBuilder: ConfigBuilder
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions
|
||||
|
||||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.Transaction
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import io.reactivex.Single
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.powermock.modules.junit4.PowerMockRunner
|
||||
|
||||
|
@ -38,20 +41,30 @@ class ActionLoopResumeTest : ActionsTestBase() {
|
|||
|
||||
@Test fun doActionTest() {
|
||||
`when`(loopPlugin.isSuspended).thenReturn(true)
|
||||
val inserted = mutableListOf<TemporaryTarget>().apply {
|
||||
// insert all inserted TTs
|
||||
}
|
||||
val updated = mutableListOf<TemporaryTarget>().apply {
|
||||
// add(TemporaryTarget(id = 0, version = 0, dateCreated = 0, isValid = false, referenceId = null, interfaceIDs_backing = null, timestamp = 0, utcOffset = 0, reason =, highTarget = 0.0, lowTarget = 0.0, duration = 0))
|
||||
// insert all updated TTs
|
||||
}
|
||||
`when`(
|
||||
repository.runTransactionForResult(anyObject<Transaction<CancelCurrentOfflineEventIfAnyTransaction.TransactionResult>>())
|
||||
).thenReturn(Single.just(CancelCurrentOfflineEventIfAnyTransaction.TransactionResult().apply {
|
||||
inserted.addAll(inserted)
|
||||
updated.addAll(updated)
|
||||
}))
|
||||
|
||||
sut.doAction(object : Callback() {
|
||||
override fun run() {}
|
||||
})
|
||||
Mockito.verify(loopPlugin, Mockito.times(1)).suspendTo(0)
|
||||
Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopResume")
|
||||
Mockito.verify(loopPlugin, Mockito.times(1)).createOfflineEvent(0)
|
||||
//Mockito.verify(loopPlugin, Mockito.times(1)).suspendTo(0)
|
||||
|
||||
// another call should keep it resumed, , no new invocation
|
||||
`when`(loopPlugin.isSuspended).thenReturn(false)
|
||||
sut.doAction(object : Callback() {
|
||||
override fun run() {}
|
||||
})
|
||||
Mockito.verify(loopPlugin, Mockito.times(1)).suspendTo(0)
|
||||
Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopResume")
|
||||
Mockito.verify(loopPlugin, Mockito.times(1)).createOfflineEvent(0)
|
||||
//Mockito.verify(loopPlugin, Mockito.times(1)).suspendTo(0)
|
||||
}
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions
|
||||
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.database.transactions.Transaction
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration
|
||||
|
@ -14,7 +13,6 @@ import org.junit.Assert
|
|||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatcher
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.powermock.modules.junit4.PowerMockRunner
|
||||
|
@ -72,12 +70,12 @@ class ActionStartTempTargetTest : ActionsTestBase() {
|
|||
}
|
||||
|
||||
`when`(
|
||||
repository.runTransactionForResult(argThatKotlin<InsertTemporaryTargetAndCancelCurrentTransaction> {
|
||||
repository.runTransactionForResult(argThatKotlin<InsertAndCancelCurrentTemporaryTargetTransaction> {
|
||||
it.temporaryTarget
|
||||
.copy(timestamp = expectedTarget.timestamp, utcOffset = expectedTarget.utcOffset) // those can be different
|
||||
.contentEqualsTo(expectedTarget)
|
||||
})
|
||||
).thenReturn(Single.just(InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult().apply {
|
||||
).thenReturn(Single.just(InsertAndCancelCurrentTemporaryTargetTransaction.TransactionResult().apply {
|
||||
inserted.addAll(inserted)
|
||||
updated.addAll(updated)
|
||||
}))
|
||||
|
@ -87,7 +85,7 @@ class ActionStartTempTargetTest : ActionsTestBase() {
|
|||
Assert.assertTrue(result.success)
|
||||
}
|
||||
})
|
||||
Mockito.verify(repository, Mockito.times(1)).runTransactionForResult(anyObject<Transaction<InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult>>())
|
||||
Mockito.verify(repository, Mockito.times(1)).runTransactionForResult(anyObject<Transaction<InsertAndCancelCurrentTemporaryTargetTransaction.TransactionResult>>())
|
||||
}
|
||||
|
||||
@Test fun hasDialogTest() {
|
||||
|
|
|
@ -2,15 +2,15 @@ package info.nightscout.androidaps.plugins.general.automation.actions
|
|||
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.plugins.general.automation.TestBaseWithProfile
|
||||
import info.nightscout.androidaps.TestPumpPlugin
|
||||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.automation.TestBaseWithProfile
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -29,13 +29,20 @@ open class ActionsTestBase : TestBaseWithProfile() {
|
|||
pluginDescription: PluginDescription
|
||||
) : PluginBase(
|
||||
pluginDescription, aapsLogger, resourceHelper, injector
|
||||
), LoopInterface {
|
||||
), Loop {
|
||||
|
||||
private var suspended = false
|
||||
override var lastRun: LoopInterface.LastRun? = LoopInterface.LastRun()
|
||||
override var lastRun: Loop.LastRun? = Loop.LastRun()
|
||||
override val isSuspended: Boolean = suspended
|
||||
override fun suspendTo(endTime: Long) {}
|
||||
override fun createOfflineEvent(durationInMinutes: Int) {}
|
||||
override var enabled: Boolean
|
||||
get() = true
|
||||
set(value) {}
|
||||
|
||||
override fun minutesToEndOfSuspend(): Int = 0
|
||||
|
||||
override fun goToZeroTemp(durationInMinutes: Int, profile: Profile, reason: OfflineEvent.Reason) {
|
||||
}
|
||||
|
||||
override fun suspendLoop(durationInMinutes: Int) {}
|
||||
}
|
||||
|
||||
|
@ -102,6 +109,8 @@ open class ActionsTestBase : TestBaseWithProfile() {
|
|||
it.resourceHelper = resourceHelper
|
||||
it.configBuilder = configBuilder
|
||||
it.rxBus = rxBus
|
||||
it.repository = repository
|
||||
it.dateUtil = dateUtil
|
||||
it.uel = uel
|
||||
}
|
||||
if (it is ActionLoopEnable) {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
class EventOfflineChange : Event()
|
|
@ -11,6 +11,7 @@ fun BolusCalculatorResult.toJson(isAdd: Boolean, dateUtil: DateUtil): JSONObject
|
|||
JSONObject()
|
||||
.put("eventType", TherapyEvent.Type.BOLUS_WIZARD.text)
|
||||
.put("created_at", dateUtil.toISOString(timestamp))
|
||||
.put("isValid", isValid)
|
||||
.put("bolusCalculatorResult", Gson().toJson(this))
|
||||
.put("date", timestamp)
|
||||
.put("glucose", glucoseValue)
|
||||
|
|
|
@ -12,6 +12,7 @@ fun Carbs.toJson(isAdd: Boolean, dateUtil: DateUtil): JSONObject =
|
|||
.put("eventType", if (amount < 12) TherapyEvent.Type.CARBS_CORRECTION.text else TherapyEvent.Type.MEAL_BOLUS.text)
|
||||
.put("carbs", amount)
|
||||
.put("created_at", dateUtil.toISOString(timestamp))
|
||||
.put("isValid", isValid)
|
||||
.put("date", timestamp).also {
|
||||
if (duration != 0L) it.put("duration", duration)
|
||||
if (interfaceIDs.pumpId != null) it.put("pumpId", interfaceIDs.pumpId)
|
||||
|
|
|
@ -3,7 +3,7 @@ package info.nightscout.androidaps.extensions
|
|||
import android.os.Build
|
||||
import info.nightscout.androidaps.database.entities.DeviceStatus
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.interfaces.Pump
|
||||
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
|
||||
|
@ -28,7 +28,7 @@ fun DeviceStatus.toJson(dateUtil: DateUtil): JSONObject =
|
|||
|
||||
fun buildDeviceStatus(
|
||||
dateUtil: DateUtil,
|
||||
loopPlugin: LoopInterface,
|
||||
loopPlugin: Loop,
|
||||
iobCobCalculatorPlugin: IobCobCalculator,
|
||||
profileFunction: ProfileFunction,
|
||||
pump: Pump,
|
||||
|
|
|
@ -20,6 +20,7 @@ fun GlucoseValue.toJson(isAdd : Boolean, dateUtil: DateUtil): JSONObject =
|
|||
.put("device", sourceSensor.text)
|
||||
.put("date", timestamp)
|
||||
.put("dateString", dateUtil.toISOString(timestamp))
|
||||
.put("isValid", isValid)
|
||||
.put("sgv", value)
|
||||
.put("direction", trendArrow.text)
|
||||
.put("type", "sgv")
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package info.nightscout.androidaps.extensions
|
||||
|
||||
import info.nightscout.androidaps.database.embedments.InterfaceIDs
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.JsonHelper
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import org.json.JSONObject
|
||||
|
||||
fun OfflineEvent.toJson(isAdd: Boolean, dateUtil: DateUtil): JSONObject =
|
||||
JSONObject()
|
||||
.put("created_at", dateUtil.toISOString(timestamp))
|
||||
.put("enteredBy", "openaps://" + "AndroidAPS")
|
||||
.put("eventType", TherapyEvent.Type.APS_OFFLINE.text)
|
||||
.put("isValid", isValid)
|
||||
.put("duration", T.msecs(duration).mins())
|
||||
.put("reason", reason.name)
|
||||
.also {
|
||||
if (interfaceIDs.pumpId != null) it.put("pumpId", interfaceIDs.pumpId)
|
||||
if (interfaceIDs.pumpType != null) it.put("pumpType", interfaceIDs.pumpType!!.name)
|
||||
if (interfaceIDs.pumpSerial != null) it.put("pumpSerial", interfaceIDs.pumpSerial)
|
||||
if (isAdd && interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId)
|
||||
}
|
||||
|
||||
/* NS PS
|
||||
{
|
||||
"enteredBy": "undefined",
|
||||
"eventType": "OpenAPS Offline",
|
||||
"duration": 60,
|
||||
"created_at": "2021-05-27T15:11:52.230Z",
|
||||
"utcOffset": 0,
|
||||
"_id": "60afb6ba3c0d77e3e720f2fe",
|
||||
"mills": 1622128312230,
|
||||
"carbs": null,
|
||||
"insulin": null
|
||||
}
|
||||
*/
|
||||
fun offlineEventFromJson(jsonObject: JSONObject): OfflineEvent? {
|
||||
val timestamp = JsonHelper.safeGetLongAllowNull(jsonObject, "mills", null) ?: return null
|
||||
val duration = JsonHelper.safeGetLong(jsonObject, "duration")
|
||||
val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true)
|
||||
val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null)
|
||||
val pumpId = JsonHelper.safeGetLongAllowNull(jsonObject, "pumpId", null)
|
||||
val pumpType = InterfaceIDs.PumpType.fromString(JsonHelper.safeGetStringAllowNull(jsonObject, "pumpType", null))
|
||||
val pumpSerial = JsonHelper.safeGetStringAllowNull(jsonObject, "pumpSerial", null)
|
||||
val reason = OfflineEvent.Reason.fromString(JsonHelper.safeGetString(jsonObject, "reason", OfflineEvent.Reason.OTHER.name))
|
||||
|
||||
|
||||
|
||||
return OfflineEvent(
|
||||
timestamp = timestamp,
|
||||
duration = T.mins(duration).msecs(),
|
||||
isValid = isValid,
|
||||
reason = reason
|
||||
).also {
|
||||
it.interfaceIDs.nightscoutId = id
|
||||
it.interfaceIDs.pumpId = pumpId
|
||||
it.interfaceIDs.pumpType = pumpType
|
||||
it.interfaceIDs.pumpSerial = pumpSerial
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +21,7 @@ fun ProfileSwitch.toJson(isAdd: Boolean, dateUtil: DateUtil): JSONObject =
|
|||
JSONObject()
|
||||
.put("created_at", dateUtil.toISOString(timestamp))
|
||||
.put("enteredBy", "openaps://" + "AndroidAPS")
|
||||
.put("isValid", isValid)
|
||||
.put("eventType", TherapyEvent.Type.PROFILE_SWITCH.text)
|
||||
.put("duration", T.msecs(duration).mins())
|
||||
.put("profile", getCustomizedName())
|
||||
|
|
|
@ -67,6 +67,7 @@ fun TemporaryBasal.toJson(isAdd: Boolean, profile: Profile, dateUtil: DateUtil,
|
|||
.put("created_at", dateUtil.toISOString(timestamp))
|
||||
.put("enteredBy", "openaps://" + "AndroidAPS")
|
||||
.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.text)
|
||||
.put("isValid", isValid)
|
||||
.put("duration", T.msecs(duration).mins())
|
||||
.put("rate", rate)
|
||||
.put("type", type.name)
|
||||
|
|
|
@ -100,6 +100,7 @@ fun therapyEventFromJson(jsonObject: JSONObject): TherapyEvent? {
|
|||
fun TherapyEvent.toJson(isAdd: Boolean): JSONObject =
|
||||
JSONObject()
|
||||
.put("eventType", type.text)
|
||||
.put("isValid", isValid)
|
||||
.put("created_at", timestamp)
|
||||
.put("enteredBy", enteredBy)
|
||||
.put("units", if (glucoseUnit == TherapyEvent.GlucoseUnit.MGDL) Constants.MGDL else Constants.MMOL)
|
||||
|
|
|
@ -16,6 +16,7 @@ interface DataSyncSelector {
|
|||
data class PairTemporaryBasal(val value: TemporaryBasal, val updateRecordId: Long)
|
||||
data class PairExtendedBolus(val value: ExtendedBolus, val updateRecordId: Long)
|
||||
data class PairProfileSwitch(val value: ProfileSwitch, val updateRecordId: Long)
|
||||
data class PairOfflineEvent(val value: OfflineEvent, val updateRecordId: Long)
|
||||
data class PairProfileStore(val value: JSONObject, val timestampSync: Long)
|
||||
|
||||
fun doUpload()
|
||||
|
@ -77,6 +78,11 @@ interface DataSyncSelector {
|
|||
// Until NS v3
|
||||
fun processChangedProfileSwitchesCompat(): Boolean
|
||||
|
||||
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long)
|
||||
fun changedOfflineEvents() : List<OfflineEvent>
|
||||
// Until NS v3
|
||||
fun processChangedOfflineEventsCompat(): Boolean
|
||||
|
||||
fun confirmLastProfileStore(lastSynced: Long)
|
||||
fun processChangedProfileStore()
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package info.nightscout.androidaps.interfaces
|
||||
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||
|
||||
interface LoopInterface {
|
||||
interface Loop {
|
||||
|
||||
class LastRun {
|
||||
|
||||
|
@ -22,8 +23,9 @@ interface LoopInterface {
|
|||
|
||||
var lastRun: LastRun?
|
||||
val isSuspended: Boolean
|
||||
var enabled: Boolean
|
||||
|
||||
fun suspendTo(endTime: Long)
|
||||
fun createOfflineEvent(durationInMinutes: Int)
|
||||
fun minutesToEndOfSuspend(): Int
|
||||
fun goToZeroTemp(durationInMinutes: Int, profile: Profile, reason: OfflineEvent.Reason)
|
||||
fun suspendLoop(durationInMinutes: Int)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package info.nightscout.androidaps.utils
|
||||
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
|
@ -15,9 +16,6 @@ class Translator @Inject internal constructor(
|
|||
private val resourceHelper: ResourceHelper
|
||||
) {
|
||||
|
||||
@Deprecated("use type instead of string")
|
||||
fun translate(text: String): String = text
|
||||
|
||||
fun translate(action: Action): String = when (action) {
|
||||
Action.BOLUS -> resourceHelper.gs(R.string.uel_bolus)
|
||||
Action.SMB -> resourceHelper.gs(R.string.smb_shortname)
|
||||
|
@ -99,6 +97,8 @@ class Translator @Inject internal constructor(
|
|||
Action.EXIT_AAPS -> resourceHelper.gs(R.string.uel_exit_aaps)
|
||||
Action.PLUGIN_ENABLED -> resourceHelper.gs(R.string.uel_plugin_enabled)
|
||||
Action.PLUGIN_DISABLED -> resourceHelper.gs(R.string.uel_plugin_disabled)
|
||||
Action.LOOP_CHANGE -> resourceHelper.gs(R.string.uel_loop_change)
|
||||
Action.LOOP_REMOVED -> resourceHelper.gs(R.string.uel_loop_removed)
|
||||
Action.UNKNOWN -> resourceHelper.gs(R.string.unknown)
|
||||
}
|
||||
|
||||
|
@ -184,6 +184,15 @@ class Translator @Inject internal constructor(
|
|||
else -> resourceHelper.gs(R.string.unknown)
|
||||
}
|
||||
|
||||
fun translate(reason: OfflineEvent.Reason): String = when (reason) {
|
||||
OfflineEvent.Reason.SUSPEND -> resourceHelper.gs(R.string.uel_suspend)
|
||||
OfflineEvent.Reason.DISABLE_LOOP -> resourceHelper.gs(R.string.disableloop)
|
||||
OfflineEvent.Reason.DISCONNECT_PUMP -> resourceHelper.gs(R.string.uel_disconnect)
|
||||
OfflineEvent.Reason.OTHER -> resourceHelper.gs(R.string.uel_other)
|
||||
|
||||
else -> resourceHelper.gs(R.string.unknown)
|
||||
}
|
||||
|
||||
fun translate(source: Sources): String = when (source) {
|
||||
/*
|
||||
Sources.TreatmentDialog -> TODO()
|
||||
|
|
|
@ -123,6 +123,7 @@ class UserEntryPresentationHelper @Inject constructor(
|
|||
is ValueWithUnit.SimpleString -> valueWithUnit.value
|
||||
is ValueWithUnit.TherapyEventMeterType -> translator.translate(valueWithUnit.value)
|
||||
is ValueWithUnit.TherapyEventTTReason -> translator.translate(valueWithUnit.value)
|
||||
is ValueWithUnit.OfflineEventReason -> translator.translate(valueWithUnit.value)
|
||||
is ValueWithUnit.TherapyEventType -> translator.translate(valueWithUnit.value)
|
||||
is ValueWithUnit.Timestamp -> dateUtil.dateAndTimeAndSecondsString(valueWithUnit.value)
|
||||
|
||||
|
@ -165,7 +166,7 @@ class UserEntryPresentationHelper @Inject constructor(
|
|||
) + "\n"
|
||||
|
||||
private fun getCsvEntry(entry: UserEntry): String {
|
||||
val fullvalueWithUnitList = ArrayList(entry.values)
|
||||
val fullValueWithUnitList = ArrayList(entry.values)
|
||||
val timestampRec = entry.timestamp.toString()
|
||||
val dateTimestampRev = dateUtil.dateAndTimeAndSecondsString(entry.timestamp)
|
||||
val utcOffset = dateUtil.timeStringFromSeconds((entry.utcOffset / 1000).toInt())
|
||||
|
@ -184,7 +185,7 @@ class UserEntryPresentationHelper @Inject constructor(
|
|||
var minute = ""
|
||||
var noUnit = ""
|
||||
|
||||
for (valueWithUnit in fullvalueWithUnitList.filterNotNull()) {
|
||||
for (valueWithUnit in fullValueWithUnitList.filterNotNull()) {
|
||||
when (valueWithUnit) {
|
||||
is ValueWithUnit.Gram -> gram = valueWithUnit.value.toString()
|
||||
is ValueWithUnit.Hour -> hour = valueWithUnit.value.toString()
|
||||
|
@ -196,6 +197,7 @@ class UserEntryPresentationHelper @Inject constructor(
|
|||
is ValueWithUnit.SimpleString -> simpleString = simpleString.addWithSeparator(valueWithUnit.value)
|
||||
is ValueWithUnit.TherapyEventMeterType -> therapyEvent = therapyEvent.addWithSeparator(translator.translate(valueWithUnit.value))
|
||||
is ValueWithUnit.TherapyEventTTReason -> therapyEvent = therapyEvent.addWithSeparator(translator.translate(valueWithUnit.value))
|
||||
is ValueWithUnit.OfflineEventReason -> therapyEvent = therapyEvent.addWithSeparator(translator.translate(valueWithUnit.value))
|
||||
is ValueWithUnit.TherapyEventType -> therapyEvent = therapyEvent.addWithSeparator(translator.translate(valueWithUnit.value))
|
||||
is ValueWithUnit.Timestamp -> timestamp = dateUtil.dateAndTimeAndSecondsString(valueWithUnit.value)
|
||||
|
||||
|
|
|
@ -494,6 +494,9 @@
|
|||
<string name="ue_none">No Unit</string>
|
||||
<string name="ue_export_to_csv">Export User Entries to Excel (csv)</string>
|
||||
<string name="ue_csv_header" translatable="false">"%1$s;%2$s;%3$s;%4$s;%5$s;%6$s;%7$s;%8$s;%9$s;%10$s;%11$s;%12$s;%13$s;%14$s;%15$s;%16$s;%17$s"</string>
|
||||
<string name="uel_loop_change">LOOP CHANGED</string>
|
||||
<string name="uel_loop_removed">LOOP REMOVED</string>
|
||||
<string name="uel_other">OTHER</string>
|
||||
|
||||
<plurals name="days">
|
||||
<item quantity="one">%1$d day</item>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,14 +6,14 @@ import androidx.room.TypeConverters
|
|||
import info.nightscout.androidaps.database.daos.*
|
||||
import info.nightscout.androidaps.database.entities.*
|
||||
|
||||
const val DATABASE_VERSION = 20
|
||||
const val DATABASE_VERSION = 21
|
||||
|
||||
@Database(version = DATABASE_VERSION,
|
||||
entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class,
|
||||
EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class,
|
||||
TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class,
|
||||
MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class,
|
||||
Food::class, DeviceStatus::class],
|
||||
Food::class, DeviceStatus::class, OfflineEvent::class],
|
||||
exportSchema = true)
|
||||
@TypeConverters(Converters::class)
|
||||
internal abstract class AppDatabase : RoomDatabase() {
|
||||
|
@ -56,4 +56,6 @@ internal abstract class AppDatabase : RoomDatabase() {
|
|||
|
||||
abstract val deviceStatusDao: DeviceStatusDao
|
||||
|
||||
abstract val offlineEventDao: OfflineEventDao
|
||||
|
||||
}
|
|
@ -768,6 +768,64 @@ open class AppRepository @Inject internal constructor(
|
|||
database.extendedBolusDao.getLastId()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.toWrappedSingle()
|
||||
|
||||
// OFFLINE EVENT
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
* of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully.
|
||||
*
|
||||
* It is a Maybe as there might be no next element.
|
||||
* */
|
||||
fun getNextSyncElementOfflineEvent(id: Long): Maybe<Pair<OfflineEvent, Long>> =
|
||||
database.offlineEventDao.getNextModifiedOrNewAfter(id)
|
||||
.flatMap { nextIdElement ->
|
||||
val nextIdElemReferenceId = nextIdElement.referenceId
|
||||
if (nextIdElemReferenceId == null) {
|
||||
Maybe.just(nextIdElement to nextIdElement.id)
|
||||
} else {
|
||||
database.offlineEventDao.getCurrentFromHistoric(nextIdElemReferenceId)
|
||||
.map { it to nextIdElement.id }
|
||||
}
|
||||
}
|
||||
|
||||
fun compatGetOfflineEventData(): Single<List<OfflineEvent>> =
|
||||
database.offlineEventDao.getOfflineEventData()
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun getOfflineEventDataFromTime(timestamp: Long, ascending: Boolean): Single<List<OfflineEvent>> =
|
||||
database.offlineEventDao.getOfflineEventDataFromTime(timestamp)
|
||||
.map { if (!ascending) it.reversed() else it }
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun getOfflineEventDataIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single<List<OfflineEvent>> =
|
||||
database.offlineEventDao.getOfflineEventDataIncludingInvalidFromTime(timestamp)
|
||||
.map { if (!ascending) it.reversed() else it }
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun getOfflineEventDataFromTimeToTime(start: Long, end: Long, ascending: Boolean): Single<List<OfflineEvent>> =
|
||||
database.offlineEventDao.getOfflineEventDataFromTimeToTime(start, end)
|
||||
.map { if (!ascending) it.reversed() else it }
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun getModifiedOfflineEventsDataFromId(lastId: Long): Single<List<OfflineEvent>> =
|
||||
database.offlineEventDao.getModifiedFrom(lastId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun getOfflineEventActiveAt(timestamp: Long): Single<ValueWrapper<OfflineEvent>> =
|
||||
database.offlineEventDao.getOfflineEventActiveAt(timestamp)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.toWrappedSingle()
|
||||
|
||||
fun deleteAllOfflineEventEntries() =
|
||||
database.offlineEventDao.deleteAllEntries()
|
||||
|
||||
fun getLastOfflineEventIdWrapped(): Single<ValueWrapper<Long>> =
|
||||
database.offlineEventDao.getLastId()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.toWrappedSingle()
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Suppress("USELESS_CAST")
|
||||
|
|
|
@ -183,4 +183,9 @@ class Converters {
|
|||
return list
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromOfflineEventReason(reason: OfflineEvent.Reason?) = reason?.name
|
||||
|
||||
@TypeConverter
|
||||
fun toOfflineEventReason(reason: String?) = reason?.let { OfflineEvent.Reason.valueOf(it) }
|
||||
}
|
|
@ -26,13 +26,11 @@ open class DatabaseModule {
|
|||
// .addMigrations(migration6to7)
|
||||
// .addMigrations(migration7to8)
|
||||
// .addMigrations(migration11to12)
|
||||
.addMigrations(migration20to21)
|
||||
.addCallback(object : Callback() {
|
||||
override fun onOpen(db: SupportSQLiteDatabase) {
|
||||
super.onOpen(db)
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS `index_temporaryBasals_end` ON `temporaryBasals` (`timestamp` + `duration`)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS `index_extendedBoluses_end` ON `extendedBoluses` (`timestamp` + `duration`)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS `index_temporaryTargets_end` ON `temporaryTargets` (`timestamp` + `duration`)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS `index_carbs_end` ON `carbs` (`timestamp` + `duration`)")
|
||||
createCustomIndexes(db)
|
||||
}
|
||||
})
|
||||
.fallbackToDestructiveMigration()
|
||||
|
@ -41,43 +39,34 @@ open class DatabaseModule {
|
|||
@Qualifier
|
||||
annotation class DbFileName
|
||||
|
||||
private val migration5to6 = object : Migration(5, 6) {
|
||||
private fun createCustomIndexes(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_temporaryBasals_end` ON `temporaryBasals` (`timestamp` + `duration`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_extendedBoluses_end` ON `extendedBoluses` (`timestamp` + `duration`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_temporaryTargets_end` ON `temporaryTargets` (`timestamp` + `duration`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_carbs_end` ON `carbs` (`timestamp` + `duration`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_offlineEvents_end` ON `offlineEvents` (`timestamp` + `duration`)")
|
||||
}
|
||||
|
||||
private fun dropCustomIndexes(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_temporaryBasals_end`")
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_extendedBoluses_end`")
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_temporaryTargets_end`")
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_carbs_end`")
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_offlineEvents_end`")
|
||||
}
|
||||
|
||||
private val migration20to21 = object : Migration(20,21) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE IF EXISTS userEntry")
|
||||
database.execSQL("CREATE TABLE userEntry (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `s` TEXT NOT NULL, `values` TEXT NOT NULL)")
|
||||
database.execSQL("DROP TABLE IF EXISTS offlineEvents")
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS `offlineEvents` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `reason` TEXT NOT NULL, `duration` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `offlineEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_offlineEvents_id` ON offlineEvents (`id`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_offlineEvents_isValid` ON offlineEvents (`isValid`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_offlineEvents_nightscoutId` ON offlineEvents (`nightscoutId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_offlineEvents_referenceId` ON offlineEvents (`referenceId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_offlineEvents_timestamp` ON offlineEvents (`timestamp`)")
|
||||
// Custom indexes must be dropped on migration to pass room schema checking after upgrade
|
||||
dropCustomIndexes(database)
|
||||
}
|
||||
}
|
||||
|
||||
private val migration6to7 = object : Migration(6, 7) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE IF EXISTS foods")
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS foods (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `name` TEXT NOT NULL, `category` TEXT, `subCategory` TEXT, `portion` REAL NOT NULL, `carbs` INTEGER NOT NULL, `fat` INTEGER, `protein` INTEGER, `energy` INTEGER, `unit` TEXT NOT NULL, `gi` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `foods`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_foods_referenceId` ON `foods` (`referenceId`)")
|
||||
}
|
||||
}
|
||||
|
||||
private val migration7to8 = object : Migration(7, 8) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE IF EXISTS bolusCalculatorResults")
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS bolusCalculatorResults (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `targetBGLow` REAL NOT NULL, `targetBGHigh` REAL NOT NULL, `isf` REAL NOT NULL, `ic` REAL NOT NULL, `bolusIOB` REAL NOT NULL, `wasBolusIOBUsed` INTEGER NOT NULL, `basalIOB` REAL NOT NULL, `wasBasalIOBUsed` INTEGER NOT NULL, `glucoseValue` REAL NOT NULL, `wasGlucoseUsed` INTEGER NOT NULL, `glucoseDifference` REAL NOT NULL, `glucoseInsulin` REAL NOT NULL, `glucoseTrend` REAL NOT NULL, `wasTrendUsed` INTEGER NOT NULL, `trendInsulin` REAL NOT NULL, `cob` REAL NOT NULL, `wasCOBUsed` INTEGER NOT NULL, `cobInsulin` REAL NOT NULL, `carbs` REAL NOT NULL, `wereCarbsUsed` INTEGER NOT NULL, `carbsInsulin` REAL NOT NULL, `otherCorrection` REAL NOT NULL, `wasSuperbolusUsed` INTEGER NOT NULL, `superbolusInsulin` REAL NOT NULL, `wasTempTargetUsed` INTEGER NOT NULL, `totalInsulin` REAL NOT NULL, `percentageCorrection` INTEGER NOT NULL, `profileName` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `bolusCalculatorResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_referenceId` ON bolusCalculatorResults (`referenceId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_timestamp` ON bolusCalculatorResults (`timestamp`)")
|
||||
|
||||
database.execSQL("DROP TABLE IF EXISTS mealLinks")
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS mealLinks (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `bolusId` INTEGER, `carbsId` INTEGER, `bolusCalcResultId` INTEGER, `superbolusTempBasalId` INTEGER, `noteId` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`bolusId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`carbsId`) REFERENCES `carbs`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`bolusCalcResultId`) REFERENCES `bolusCalculatorResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`superbolusTempBasalId`) REFERENCES `temporaryBasals`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`noteId`) REFERENCES `therapyEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`referenceId`) REFERENCES `mealLinks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_referenceId` ON mealLinks (`referenceId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_bolusId` ON `mealLinks (`bolusId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_carbsId` ON mealLinks (`carbsId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_bolusCalcResultId` ON mealLinks (`bolusCalcResultId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_superbolusTempBasalId` ON mealLinks (`superbolusTempBasalId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_noteId` ON mealLinks (`noteId`)")
|
||||
}
|
||||
}
|
||||
|
||||
private val migration11to12 = object : Migration(11,12) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE IF EXISTS userEntry")
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS userEntry (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `source` TEXT NOT NULL, `note` TEXT NOT NULL, `values` TEXT NOT NULL)")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.database
|
|||
|
||||
import info.nightscout.androidaps.database.daos.*
|
||||
import info.nightscout.androidaps.database.daos.delegated.*
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.interfaces.DBEntry
|
||||
|
||||
internal class DelegatedAppDatabase(val changes: MutableList<DBEntry>, val database: AppDatabase) {
|
||||
|
@ -25,5 +26,6 @@ internal class DelegatedAppDatabase(val changes: MutableList<DBEntry>, val datab
|
|||
val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao)
|
||||
val foodDao: FoodDao = DelegatedFoodDao(changes, database.foodDao)
|
||||
val deviceStatusDao: DeviceStatusDao = DelegatedDeviceStatusDao(changes, database.deviceStatusDao)
|
||||
val offlineEventDao: OfflineEventDao = DelegatedOfflineEventDao(changes, database.offlineEventDao)
|
||||
fun clearAllTables() = database.clearAllTables()
|
||||
}
|
|
@ -14,6 +14,7 @@ const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks"
|
|||
const val TABLE_PROFILE_SWITCHES = "profileSwitches"
|
||||
const val TABLE_TEMPORARY_BASALS = "temporaryBasals"
|
||||
const val TABLE_TEMPORARY_TARGETS = "temporaryTargets"
|
||||
const val TABLE_OFFLINE_EVENTS = "offlineEvents"
|
||||
const val TABLE_TOTAL_DAILY_DOSES = "totalDailyDoses"
|
||||
const val TABLE_THERAPY_EVENTS = "therapyEvents"
|
||||
const val TABLE_PREFERENCE_CHANGES = "preferenceChanges"
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package info.nightscout.androidaps.database.daos
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import info.nightscout.androidaps.database.TABLE_OFFLINE_EVENTS
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
|
||||
@Suppress("FunctionName")
|
||||
@Dao
|
||||
internal interface OfflineEventDao : TraceableDao<OfflineEvent> {
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE id = :id")
|
||||
override fun findById(id: Long): OfflineEvent?
|
||||
|
||||
@Query("DELETE FROM $TABLE_OFFLINE_EVENTS")
|
||||
override fun deleteAllEntries()
|
||||
|
||||
@Query("SELECT id FROM $TABLE_OFFLINE_EVENTS ORDER BY id DESC limit 1")
|
||||
fun getLastId(): Maybe<Long>
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE nightscoutId = :nsId AND referenceId IS NULL")
|
||||
fun findByNSId(nsId: String): OfflineEvent?
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1")
|
||||
fun getOfflineEventActiveAt(timestamp: Long): Maybe<OfflineEvent>
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
|
||||
fun getOfflineEventDataFromTime(timestamp: Long): Single<List<OfflineEvent>>
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY timestamp ASC")
|
||||
fun getOfflineEventDataIncludingInvalidFromTime(timestamp: Long): Single<List<OfflineEvent>>
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE timestamp BETWEEN :start AND :end AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
|
||||
fun getOfflineEventDataFromTimeToTime(start: Long, end: Long): Single<List<OfflineEvent>>
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
|
||||
fun getOfflineEventData(): Single<List<OfflineEvent>>
|
||||
|
||||
// This query will be used with v3 to get all changed records
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_OFFLINE_EVENTS WHERE id > :id) ORDER BY id ASC")
|
||||
fun getModifiedFrom(id: Long): Single<List<OfflineEvent>>
|
||||
|
||||
// for WS we need 1 record only
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE id > :id ORDER BY id ASC limit 1")
|
||||
fun getNextModifiedOrNewAfter(id: Long): Maybe<OfflineEvent>
|
||||
|
||||
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE id = :referenceId")
|
||||
fun getCurrentFromHistoric(referenceId: Long): Maybe<OfflineEvent>
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package info.nightscout.androidaps.database.daos.delegated
|
||||
|
||||
import info.nightscout.androidaps.database.daos.OfflineEventDao
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.interfaces.DBEntry
|
||||
|
||||
internal class DelegatedOfflineEventDao(changes: MutableList<DBEntry>, private val dao: OfflineEventDao) : DelegatedDao(changes), OfflineEventDao by dao {
|
||||
|
||||
override fun insertNewEntry(entry: OfflineEvent): Long {
|
||||
changes.add(entry)
|
||||
return dao.insertNewEntry(entry)
|
||||
}
|
||||
|
||||
override fun updateExistingEntry(entry: OfflineEvent): Long {
|
||||
changes.add(entry)
|
||||
return dao.updateExistingEntry(entry)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package info.nightscout.androidaps.database.entities
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import info.nightscout.androidaps.database.TABLE_OFFLINE_EVENTS
|
||||
import info.nightscout.androidaps.database.embedments.InterfaceIDs
|
||||
import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration
|
||||
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry
|
||||
import java.util.*
|
||||
|
||||
@Entity(tableName = TABLE_OFFLINE_EVENTS,
|
||||
foreignKeys = [ForeignKey(
|
||||
entity = OfflineEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["referenceId"])],
|
||||
indices = [
|
||||
Index("id"),
|
||||
Index("isValid"),
|
||||
Index("nightscoutId"),
|
||||
Index("referenceId"),
|
||||
Index("timestamp")
|
||||
])
|
||||
data class OfflineEvent(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
override var id: Long = 0,
|
||||
override var version: Int = 0,
|
||||
override var dateCreated: Long = -1,
|
||||
override var isValid: Boolean = true,
|
||||
override var referenceId: Long? = null,
|
||||
@Embedded
|
||||
override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(),
|
||||
override var timestamp: Long,
|
||||
override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(),
|
||||
var reason: Reason,
|
||||
override var duration: Long // in millis
|
||||
) : TraceableDBEntry, DBEntryWithTimeAndDuration {
|
||||
|
||||
fun contentEqualsTo(other: OfflineEvent): Boolean =
|
||||
timestamp == other.timestamp &&
|
||||
utcOffset == other.utcOffset &&
|
||||
reason == other.reason &&
|
||||
duration == other.duration &&
|
||||
isValid == other.isValid
|
||||
|
||||
fun isRecordDeleted(other: OfflineEvent): Boolean =
|
||||
isValid && !other.isValid
|
||||
|
||||
enum class Reason {
|
||||
DISCONNECT_PUMP,
|
||||
SUSPEND,
|
||||
DISABLE_LOOP,
|
||||
SUPER_BOLUS,
|
||||
OTHER
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
||||
fun fromString(reason: String?) = values().firstOrNull { it.name == reason } ?: OTHER
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,6 +43,8 @@ data class UserEntry(
|
|||
OPEN_LOOP_MODE (ColorGroup.Loop),
|
||||
LOOP_DISABLED (ColorGroup.Loop),
|
||||
LOOP_ENABLED (ColorGroup.Loop),
|
||||
LOOP_CHANGE (ColorGroup.Loop),
|
||||
LOOP_REMOVED (ColorGroup.Loop),
|
||||
RECONNECT (ColorGroup.Pump),
|
||||
DISCONNECT (ColorGroup.Pump),
|
||||
RESUME (ColorGroup.Loop),
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package info.nightscout.androidaps.database.entities
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
sealed class ValueWithUnit {
|
||||
|
||||
object UNKNOWN : ValueWithUnit() // formerly None used as fallback
|
||||
|
@ -34,6 +32,8 @@ sealed class ValueWithUnit {
|
|||
|
||||
data class TherapyEventTTReason(val value: TemporaryTarget.Reason) : ValueWithUnit()
|
||||
|
||||
data class OfflineEventReason(val value: OfflineEvent.Reason) : ValueWithUnit()
|
||||
|
||||
fun value(): Any? {
|
||||
return when(this) {
|
||||
is Gram -> this.value
|
||||
|
@ -47,6 +47,7 @@ sealed class ValueWithUnit {
|
|||
is SimpleString -> this.value
|
||||
is TherapyEventMeterType -> this.value
|
||||
is TherapyEventTTReason -> this.value
|
||||
is OfflineEventReason -> this.value
|
||||
is TherapyEventType -> this.value
|
||||
is Timestamp -> this.value
|
||||
is UnitPerHour -> this.value
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package info.nightscout.androidaps.database.transactions
|
||||
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
|
||||
class CancelCurrentOfflineEventIfAnyTransaction(
|
||||
val timestamp: Long
|
||||
) : Transaction<CancelCurrentOfflineEventIfAnyTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
val current = database.offlineEventDao.getOfflineEventActiveAt(timestamp).blockingGet()
|
||||
if (current != null) {
|
||||
current.end = timestamp
|
||||
database.offlineEventDao.updateExistingEntry(current)
|
||||
result.updated.add(current)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class TransactionResult {
|
||||
|
||||
val updated = mutableListOf<OfflineEvent>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package info.nightscout.androidaps.database.transactions
|
||||
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
|
||||
class InsertAndCancelCurrentOfflineEventTransaction(
|
||||
val offlineEvent: OfflineEvent
|
||||
) : Transaction<InsertAndCancelCurrentOfflineEventTransaction.TransactionResult>() {
|
||||
|
||||
constructor(timestamp: Long, duration: Long, reason: OfflineEvent.Reason) :
|
||||
this(OfflineEvent(timestamp = timestamp, reason = reason, duration = duration))
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
val current = database.offlineEventDao.getOfflineEventActiveAt(offlineEvent.timestamp).blockingGet()
|
||||
if (current != null) {
|
||||
current.end = offlineEvent.timestamp
|
||||
database.offlineEventDao.updateExistingEntry(current)
|
||||
result.updated.add(current)
|
||||
}
|
||||
database.offlineEventDao.insertNewEntry(offlineEvent)
|
||||
result.inserted.add(offlineEvent)
|
||||
return result
|
||||
}
|
||||
|
||||
class TransactionResult {
|
||||
val inserted = mutableListOf<OfflineEvent>()
|
||||
val updated = mutableListOf<OfflineEvent>()
|
||||
}
|
||||
}
|
|
@ -3,9 +3,9 @@ package info.nightscout.androidaps.database.transactions
|
|||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
|
||||
class InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
class InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
val temporaryTarget: TemporaryTarget
|
||||
) : Transaction<InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult>() {
|
||||
) : Transaction<InsertAndCancelCurrentTemporaryTargetTransaction.TransactionResult>() {
|
||||
|
||||
constructor(timestamp: Long, duration: Long, reason: TemporaryTarget.Reason, lowTarget: Double, highTarget: Double) :
|
||||
this(TemporaryTarget(timestamp = timestamp, reason = reason, lowTarget = lowTarget, highTarget = highTarget, duration = duration))
|
|
@ -0,0 +1,10 @@
|
|||
package info.nightscout.androidaps.database.transactions
|
||||
|
||||
class InvalidateOfflineEventTransaction(val id: Long) : Transaction<Unit>() {
|
||||
override fun run() {
|
||||
val offlineEvent = database.offlineEventDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such OfflineEvent with the specified ID.")
|
||||
offlineEvent.isValid = false
|
||||
database.offlineEventDao.updateExistingEntry(offlineEvent)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package info.nightscout.androidaps.database.transactions
|
||||
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* Sync the OfflineEvent from NS
|
||||
*/
|
||||
class SyncNsOfflineEventTransaction(private val offlineEvent: OfflineEvent, private val invalidateByNsOnly: Boolean) : Transaction<SyncNsOfflineEventTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
|
||||
if (offlineEvent.duration != 0L) {
|
||||
// not ending event
|
||||
val current: OfflineEvent? =
|
||||
offlineEvent.interfaceIDs.nightscoutId?.let {
|
||||
database.offlineEventDao.findByNSId(it)
|
||||
}
|
||||
|
||||
if (current != null) {
|
||||
// nsId exists, allow only invalidation
|
||||
if (current.isValid && !offlineEvent.isValid) {
|
||||
current.isValid = false
|
||||
database.offlineEventDao.updateExistingEntry(current)
|
||||
result.invalidated.add(current)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
if (invalidateByNsOnly) return result
|
||||
|
||||
// not known nsId
|
||||
val running = database.offlineEventDao.getOfflineEventActiveAt(offlineEvent.timestamp).blockingGet()
|
||||
if (running != null && abs(running.timestamp - offlineEvent.timestamp) < 1000 && running.interfaceIDs.nightscoutId == null) { // allow missing milliseconds
|
||||
// the same record, update nsId only
|
||||
running.interfaceIDs.nightscoutId = offlineEvent.interfaceIDs.nightscoutId
|
||||
database.offlineEventDao.updateExistingEntry(running)
|
||||
result.updatedNsId.add(running)
|
||||
} else if (running != null) {
|
||||
// another running record. end current and insert new
|
||||
running.end = offlineEvent.timestamp
|
||||
database.offlineEventDao.updateExistingEntry(running)
|
||||
database.offlineEventDao.insertNewEntry(offlineEvent)
|
||||
result.ended.add(running)
|
||||
result.inserted.add(offlineEvent)
|
||||
} else {
|
||||
database.offlineEventDao.insertNewEntry(offlineEvent)
|
||||
result.inserted.add(offlineEvent)
|
||||
}
|
||||
return result
|
||||
|
||||
} else {
|
||||
// ending event
|
||||
val running = database.offlineEventDao.getOfflineEventActiveAt(offlineEvent.timestamp).blockingGet()
|
||||
if (running != null) {
|
||||
running.end = offlineEvent.timestamp
|
||||
database.offlineEventDao.updateExistingEntry(running)
|
||||
result.ended.add(running)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class TransactionResult {
|
||||
|
||||
val updatedNsId = mutableListOf<OfflineEvent>()
|
||||
val inserted = mutableListOf<OfflineEvent>()
|
||||
val invalidated = mutableListOf<OfflineEvent>()
|
||||
val ended = mutableListOf<OfflineEvent>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.database.transactions
|
||||
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
|
||||
class UpdateNsIdOfflineEventTransaction(val offlineEvent: OfflineEvent) : Transaction<Unit>() {
|
||||
|
||||
override fun run() {
|
||||
val current = database.offlineEventDao.findById(offlineEvent.id)
|
||||
if (current != null && current.interfaceIDs.nightscoutId != offlineEvent.interfaceIDs.nightscoutId)
|
||||
database.offlineEventDao.updateExistingEntry(offlineEvent)
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package info.nightscout.androidaps.database.transactions
|
||||
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
|
||||
class UpdateTemporaryTargetTransaction(val temporaryTarget: TemporaryTarget) : Transaction<Unit>() {
|
||||
override fun run() {
|
||||
database.temporaryTargetDao.updateExistingEntry(temporaryTarget)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue