Merge branch 'meallink' into meallink_ValueWithUnit

# Conflicts:
#	app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt
This commit is contained in:
Philoul 2021-03-31 22:18:50 +02:00
commit 3d9ef71045
26 changed files with 3409 additions and 240 deletions

View file

@ -17,6 +17,7 @@ abstract class ReceiversModule {
@ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver @ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver
@ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver @ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver
@ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver @ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver
@ContributesAndroidInjector abstract fun contributesKeepAliveWorker(): KeepAliveReceiver.KeepAliveWorker
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver @ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
@ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver @ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver @ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver

View file

@ -37,6 +37,7 @@ import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
@ -53,6 +54,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.buildDeviceStatus
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -84,7 +86,8 @@ open class LoopPlugin @Inject constructor(
private val nsUpload: NSUpload, private val nsUpload: NSUpload,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val uel: UserEntryLogger, private val uel: UserEntryLogger,
private val repository: AppRepository private val repository: AppRepository,
private val runningConfiguration: RunningConfiguration
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.LOOP) .mainType(PluginType.LOOP)
.fragmentClass(LoopFragment::class.java.name) .fragmentClass(LoopFragment::class.java.name)
@ -322,7 +325,12 @@ open class LoopPlugin @Inject constructor(
lastRun!!.lastTBRRequest = 0 lastRun!!.lastTBRRequest = 0
lastRun!!.lastSMBEnact = 0 lastRun!!.lastSMBEnact = 0
lastRun!!.lastSMBRequest = 0 lastRun!!.lastSMBRequest = 0
nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION) buildDeviceStatus(dateUtil, this, iobCobCalculatorPlugin, profileFunction,
activePlugin.activePump, receiverStatusStore, runningConfiguration,
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also {
repository.insert(it)
}
if (isSuspended) { if (isSuspended) {
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended)) aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended))
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended))) rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)))
@ -495,7 +503,6 @@ open class LoopPlugin @Inject constructor(
fun acceptChangeRequest() { fun acceptChangeRequest() {
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
val lp = this
applyTBRRequest(lastRun!!.constraintsProcessed, profile, object : Callback() { applyTBRRequest(lastRun!!.constraintsProcessed, profile, object : Callback() {
override fun run() { override fun run() {
if (result.enacted) { if (result.enacted) {
@ -503,7 +510,11 @@ open class LoopPlugin @Inject constructor(
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
lastRun!!.lastTBREnact = DateUtil.now() lastRun!!.lastTBREnact = DateUtil.now()
lastRun!!.lastOpenModeAccept = DateUtil.now() lastRun!!.lastOpenModeAccept = DateUtil.now()
nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION) buildDeviceStatus(dateUtil, this@LoopPlugin, iobCobCalculatorPlugin, profileFunction,
activePlugin.activePump, receiverStatusStore, runningConfiguration,
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also {
repository.insert(it)
}
sp.incInt(R.string.key_ObjectivesmanualEnacts) sp.incInt(R.string.key_ObjectivesmanualEnacts)
} }
rxBus.send(EventAcceptOpenLoopChange()) rxBus.send(EventAcceptOpenLoopChange())

View file

@ -13,6 +13,7 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -38,6 +39,7 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var dataSyncSelector: DataSyncSelector
private val compositeDisposable = CompositeDisposable() private val compositeDisposable = CompositeDisposable()
@ -66,6 +68,7 @@ class MaintenanceFragment : DaggerFragment() {
fromAction { fromAction {
databaseHelper.resetDatabases() databaseHelper.resetDatabases()
repository.clearDatabases() repository.clearDatabases()
dataSyncSelector.resetToNextFullSync()
} }
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.nsclient
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.DeviceStatus
import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.entities.*
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DataSyncSelector import info.nightscout.androidaps.interfaces.DataSyncSelector
@ -28,6 +29,7 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.remove(R.string.key_ns_bolus_last_synced_id) sp.remove(R.string.key_ns_bolus_last_synced_id)
sp.remove(R.string.key_ns_carbs_last_synced_id) sp.remove(R.string.key_ns_carbs_last_synced_id)
sp.remove(R.string.key_ns_bolus_calculator_result_last_synced_id) sp.remove(R.string.key_ns_bolus_calculator_result_last_synced_id)
sp.remove(R.string.key_ns_device_status_last_synced_id)
} }
override fun confirmLastBolusIdIfGreater(lastSynced: Long) { override fun confirmLastBolusIdIfGreater(lastSynced: Long) {
@ -294,4 +296,34 @@ class DataSyncSelectorImplementation @Inject constructor(
return false return false
} }
override fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced")
sp.putLong(R.string.key_ns_device_status_last_synced_id, lastSynced)
}
}
override fun changedDeviceStatuses(): List<DeviceStatus> {
val startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
return appRepository.getModifiedDeviceStatusDataFromId(startId).blockingGet().also {
aapsLogger.debug(LTag.NSCLIENT, "Loading DeviceStatus data for sync from $startId. Records ${it.size}")
}
}
override fun processChangedDeviceStatusesCompat(): Boolean {
val startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
aapsLogger.info(LTag.DATABASE, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}")
when {
// without nsId = create new
deviceStatus.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("devicestatus", deviceStatus.toJson(), deviceStatus)
// with nsId = ignore
deviceStatus.interfaceIDs.nightscoutId != null -> Any()
}
return true
}
return false
}
} }

View file

@ -32,10 +32,11 @@ import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.database.AppRepository; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.Carbs; import info.nightscout.androidaps.database.entities.DeviceStatus;
import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusCalculatorResultTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusCalculatorResultTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdCarbsTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdCarbsTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdDeviceStatusTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdFoodTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdFoodTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdGlucoseValueTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdGlucoseValueTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdTemporaryTargetTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdTemporaryTargetTransaction;
@ -339,6 +340,22 @@ public class NSClientService extends DaggerService {
dataSyncSelector.processChangedBolusCalculatorResultsCompat(); dataSyncSelector.processChangedBolusCalculatorResultsCompat();
return; return;
} }
if (ack.getOriginalObject() instanceof DeviceStatus) {
DeviceStatus deviceStatus = (DeviceStatus) ack.getOriginalObject();
deviceStatus.getInterfaceIDs().setNightscoutId(ack.getId());
disposable.add(repository.runTransactionForResult(new UpdateNsIdDeviceStatusTransaction(deviceStatus))
.observeOn(aapsSchedulers.getIo())
.subscribe(
result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of DeviceStatus " + deviceStatus),
error -> aapsLogger.error(LTag.DATABASE, "Updated ns id of DeviceStatus failed", error)
));
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.getId());
rxBus.send(new EventNSClientNewLog("DBADD", "Acked DeviceStatus" + deviceStatus.getInterfaceIDs().getNightscoutId()));
// Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResultsCompat();
return;
}
// old way // old way
if (ack.nsClientID != null) { if (ack.nsClientID != null) {
uploadQueue.removeByNsClientIdIfExists(ack.json); uploadQueue.removeByNsClientIdIfExists(ack.json);
@ -977,6 +994,7 @@ public class NSClientService extends DaggerService {
dataSyncSelector.processChangedTempTargetsCompat(); dataSyncSelector.processChangedTempTargetsCompat();
dataSyncSelector.processChangedFoodsCompat(); dataSyncSelector.processChangedFoodsCompat();
dataSyncSelector.processChangedTherapyEventsCompat(); dataSyncSelector.processChangedTherapyEventsCompat();
dataSyncSelector.processChangedDeviceStatusesCompat();
if (uploadQueue.size() == 0) if (uploadQueue.size() == 0)
return; return;

View file

@ -3,13 +3,19 @@ package info.nightscout.androidaps.receivers
import android.app.AlarmManager import android.app.AlarmManager
import android.app.PendingIntent import android.app.PendingIntent
import android.app.PendingIntent.CanceledException import android.app.PendingIntent.CanceledException
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.PowerManager
import android.os.SystemClock import android.os.SystemClock
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import dagger.android.DaggerBroadcastReceiver import dagger.android.DaggerBroadcastReceiver
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.events.EventProfileNeedsUpdate import info.nightscout.androidaps.events.EventProfileNeedsUpdate
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
@ -18,55 +24,124 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.queue.commands.Command
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.LocalAlertUtils import info.nightscout.androidaps.utils.LocalAlertUtils
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.buildDeviceStatus
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
class KeepAliveReceiver : DaggerBroadcastReceiver() { class KeepAliveReceiver : DaggerBroadcastReceiver() {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var localAlertUtils: LocalAlertUtils
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
@Inject lateinit var config: Config
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var dateUtil: DateUtil
companion object { companion object {
private val KEEP_ALIVE_MILLISECONDS = T.mins(5).msecs() private val KEEP_ALIVE_MILLISECONDS = T.mins(5).msecs()
private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs()
private val IOB_UPDATE_FREQUENCY_IN_MINS = 5L
private var lastReadStatus: Long = 0
private var lastRun: Long = 0
private var lastIobUpload: Long = 0
} }
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent) super.onReceive(context, intent)
aapsLogger.debug(LTag.CORE, "KeepAlive received") aapsLogger.debug(LTag.CORE, "KeepAlive received")
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
val wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:KeepAliveReceiver") WorkManager.getInstance(context)
wl.acquire(T.mins(2).msecs()) .enqueue(OneTimeWorkRequest.Builder(KeepAliveWorker::class.java).build())
localAlertUtils.shortenSnoozeInterval() }
localAlertUtils.checkStaleBGAlert()
checkPump() class KeepAliveWorker(
checkAPS() context: Context,
wl.release() params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var localAlertUtils: LocalAlertUtils
@Inject lateinit var repository: AppRepository
@Inject lateinit var config: Config
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var runningConfiguration: RunningConfiguration
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var fabricPrivacy: FabricPrivacy
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
companion object {
private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs()
private const val IOB_UPDATE_FREQUENCY_IN_MINUTES = 5L
private var lastReadStatus: Long = 0
private var lastRun: Long = 0
private var lastIobUpload: Long = 0
}
override fun doWork(): Result {
localAlertUtils.shortenSnoozeInterval()
localAlertUtils.checkStaleBGAlert()
checkPump()
checkAPS()
return Result.success()
}
// Usually deviceStatus is uploaded through LoopPlugin after every loop cycle.
// if there is no BG available, we have to upload anyway to have correct
// IOB displayed in NS
private fun checkAPS() {
var shouldUploadStatus = false
if (config.NSCLIENT) return
if (config.PUMPCONTROL) shouldUploadStatus = true
else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
shouldUploadStatus = true
else if (DateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true
if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINUTES) && shouldUploadStatus) {
lastIobUpload = dateUtil._now()
buildDeviceStatus(dateUtil, loopPlugin, iobCobCalculatorPlugin, profileFunction,
activePlugin.activePump, receiverStatusStore, runningConfiguration,
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also {
repository.insert(it)
}
}
}
private fun checkPump() {
val pump = activePlugin.activePump
val profile = profileFunction.getProfile() ?: return
val lastConnection = pump.lastDataTime()
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()
val isBasalOutdated = abs(profile.basal - pump.baseBasalRate) > pump.pumpDescription.basalStep
aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
// sometimes keep alive broadcast stops
// as as workaround test if readStatus was requested before an alarm is generated
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected)
}
if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) {
rxBus.send(EventProfileNeedsUpdate())
} else if (isStatusOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Status outdated.", null)
} else if (isBasalOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Basal outdated.", null)
}
if (lastRun != 0L && System.currentTimeMillis() - lastRun > T.mins(10).msecs()) {
aapsLogger.error(LTag.CORE, "KeepAlive fail")
fabricPrivacy.logCustom("KeepAliveFail")
}
lastRun = System.currentTimeMillis()
}
} }
class KeepAliveManager @Inject constructor( class KeepAliveManager @Inject constructor(
@ -82,7 +157,7 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
localAlertUtils.preSnoozeAlarms() localAlertUtils.preSnoozeAlarms()
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val i = Intent(context, KeepAliveReceiver::class.java) val i = Intent(context, KeepAliveReceiver::class.java)
val pi = PendingIntent.getBroadcast(context, 0, i, 0) val pi = PendingIntent.getBroadcast(context, 0, i, FLAG_IMMUTABLE)
try { try {
pi.send() pi.send()
} catch (e: CanceledException) { } catch (e: CanceledException) {
@ -94,53 +169,9 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
fun cancelAlarm(context: Context) { fun cancelAlarm(context: Context) {
aapsLogger.debug(LTag.CORE, "KeepAlive canceled") aapsLogger.debug(LTag.CORE, "KeepAlive canceled")
val intent = Intent(context, KeepAliveReceiver::class.java) val intent = Intent(context, KeepAliveReceiver::class.java)
val sender = PendingIntent.getBroadcast(context, 0, intent, 0) val sender = PendingIntent.getBroadcast(context, 0, intent, FLAG_IMMUTABLE)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.cancel(sender) alarmManager.cancel(sender)
} }
} }
// Usually deviceStatus is uploaded through LoopPlugin after every loop cycle.
// if there is no BG available, we have to upload anyway to have correct
// IOB displayed in NS
private fun checkAPS() {
var shouldUploadStatus = false
if (config.NSCLIENT) return
if (config.PUMPCONTROL) shouldUploadStatus = true
else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
shouldUploadStatus = true
else if (DateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true
if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINS) && shouldUploadStatus) {
lastIobUpload = DateUtil.now()
nsUpload.uploadDeviceStatus(loopPlugin, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)
}
}
private fun checkPump() {
val pump = activePlugin.activePump
val profile = profileFunction.getProfile() ?: return
val lastConnection = pump.lastDataTime()
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()
val isBasalOutdated = abs(profile.basal - pump.baseBasalRate) > pump.pumpDescription.basalStep
aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
// sometimes keep alive broadcast stops
// as as workaround test if readStatus was requested before an alarm is generated
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected)
}
if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) {
rxBus.send(EventProfileNeedsUpdate())
} else if (isStatusOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Status outdated.", null)
} else if (isBasalOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Basal outdated.", null)
}
if (lastRun != 0L && System.currentTimeMillis() - lastRun > T.mins(10).msecs()) {
aapsLogger.error(LTag.CORE, "KeepAlive fail")
fabricPrivacy.logCustom("KeepAliveFail")
}
lastRun = System.currentTimeMillis()
}
} }

View file

@ -43,6 +43,7 @@
<string name="key_ns_bolus_calculator_result_last_synced_id" translatable="false">ns_bolus_calculator_result_last_synced_id</string> <string name="key_ns_bolus_calculator_result_last_synced_id" translatable="false">ns_bolus_calculator_result_last_synced_id</string>
<string name="key_ns_carbs_last_synced_id" translatable="false">ns_carbs_last_synced_id</string> <string name="key_ns_carbs_last_synced_id" translatable="false">ns_carbs_last_synced_id</string>
<string name="key_ns_bolus_last_synced_id" translatable="false">ns_bolus_last_synced_id</string> <string name="key_ns_bolus_last_synced_id" translatable="false">ns_bolus_last_synced_id</string>
<string name="key_ns_device_status_last_synced_id" translatable="false">ns_device_status_last_synced_id</string>
<string name="treatmentssafety_title">Treatments safety</string> <string name="treatmentssafety_title">Treatments safety</string>
<string name="treatmentssafety_maxbolus_title">Max allowed bolus [U]</string> <string name="treatmentssafety_maxbolus_title">Max allowed bolus [U]</string>

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.interfaces package info.nightscout.androidaps.interfaces
import info.nightscout.androidaps.database.entities.DeviceStatus
import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.entities.*
interface DataSyncSelector { interface DataSyncSelector {
@ -48,4 +49,9 @@ interface DataSyncSelector {
fun changedFoods() : List<Food> fun changedFoods() : List<Food>
// Until NS v3 // Until NS v3
fun processChangedFoodsCompat(): Boolean fun processChangedFoodsCompat(): Boolean
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long)
fun changedDeviceStatuses() : List<DeviceStatus>
// Until NS v3
fun processChangedDeviceStatusesCompat(): Boolean
} }

View file

@ -38,6 +38,12 @@ interface PumpInterface {
val reservoirLevel: Double val reservoirLevel: Double
val batteryLevel: Int // in percent as integer val batteryLevel: Int // in percent as integer
/**
* Request a bolus to be delivered, carbs to be stored on pump or both.
*
* @param detailedBolusInfo it's the caller's responsibility to ensure the request can be satisfied by the pump,
* e.g. DBI will not contain carbs if the pump can't store carbs.
*/
fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult
fun stopBolusDelivering() fun stopBolusDelivering()
fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult

View file

@ -1,35 +1,22 @@
package info.nightscout.androidaps.plugins.general.nsclient; package info.nightscout.androidaps.plugins.general.nsclient;
import android.os.Build;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Date;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import info.nightscout.androidaps.core.R; import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.database.entities.TherapyEvent; import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.db.DbRequest;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.IobCobCalculator;
import info.nightscout.androidaps.interfaces.LoopInterface;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.UploadQueueInterface; import info.nightscout.androidaps.interfaces.UploadQueueInterface;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.DeviceStatus;
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration; import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration;
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -165,70 +152,6 @@ public class NSUpload {
} }
} }
public void uploadDeviceStatus(LoopInterface loopPlugin, IobCobCalculator iobCobCalculatorPlugin, ProfileFunction profileFunction, PumpInterface pumpInterface, ReceiverStatusStore receiverStatusStore, String version) {
Profile profile = profileFunction.getProfile();
String profileName = profileFunction.getProfileName();
if (profile == null) {
aapsLogger.error("Profile is null. Skipping upload");
return;
}
DeviceStatus deviceStatus = new DeviceStatus(aapsLogger);
try {
LoopInterface.LastRun lastRun = loopPlugin.getLastRun();
if (lastRun != null && lastRun.getLastAPSRun() > System.currentTimeMillis() - 300 * 1000L) {
// do not send if result is older than 1 min
APSResult apsResult = lastRun.getRequest();
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.getLastAPSRun()));
deviceStatus.suggested = apsResult.json();
deviceStatus.iob = lastRun.getRequest().getIob().json();
deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.getLastAPSRun()));
JSONObject requested = new JSONObject();
if (lastRun.getTbrSetByPump() != null && lastRun.getTbrSetByPump().getEnacted()) { // enacted
deviceStatus.enacted = lastRun.getRequest().json();
deviceStatus.enacted.put("rate", lastRun.getTbrSetByPump().json(profile).get("rate"));
deviceStatus.enacted.put("duration", lastRun.getTbrSetByPump().json(profile).get("duration"));
deviceStatus.enacted.put("recieved", true);
requested.put("duration", lastRun.getRequest().getDuration());
requested.put("rate", lastRun.getRequest().getRate());
requested.put("temp", "absolute");
deviceStatus.enacted.put("requested", requested);
}
if (lastRun.getTbrSetByPump() != null && lastRun.getTbrSetByPump().getEnacted()) { // enacted
if (deviceStatus.enacted == null) {
deviceStatus.enacted = lastRun.getRequest().json();
}
deviceStatus.enacted.put("smb", lastRun.getTbrSetByPump().getBolusDelivered());
requested.put("smb", lastRun.getRequest().getSmb());
deviceStatus.enacted.put("requested", requested);
}
} else {
aapsLogger.debug(LTag.NSCLIENT, "OpenAPS data too old to upload, sending iob only");
IobTotal[] iob = iobCobCalculatorPlugin.calculateIobArrayInDia(profile);
if (iob.length > 0) {
deviceStatus.iob = iob[0].json();
deviceStatus.iob.put("time", DateUtil.toISOString(dateUtil._now()));
}
}
deviceStatus.device = "openaps://" + Build.MANUFACTURER + " " + Build.MODEL;
JSONObject pumpstatus = pumpInterface.getJSONStatus(profile, profileName, version);
deviceStatus.pump = pumpstatus;
deviceStatus.uploaderBattery = receiverStatusStore.getBatteryLevel();
deviceStatus.created_at = DateUtil.toISOString(new Date());
deviceStatus.configuration = runningConfiguration.configuration();
uploadQueue.add(new DbRequest("dbAdd", "devicestatus", deviceStatus.mongoRecord(), System.currentTimeMillis()));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
}
public void uploadTreatmentRecord(DetailedBolusInfo detailedBolusInfo) { public void uploadTreatmentRecord(DetailedBolusInfo detailedBolusInfo) {
throw new IllegalStateException("DO NOT USE"); throw new IllegalStateException("DO NOT USE");

View file

@ -1,12 +1,88 @@
package info.nightscout.androidaps.plugins.aps.loop; package info.nightscout.androidaps.utils.extensions
import org.json.JSONException; import android.os.Build
import org.json.JSONObject; import info.nightscout.androidaps.database.entities.DeviceStatus
import org.slf4j.Logger; import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.LoopInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpInterface
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONObject
import info.nightscout.androidaps.logging.AAPSLogger; fun DeviceStatus.toJson(): JSONObject =
import info.nightscout.androidaps.logging.LTag; JSONObject()
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; .put("created_at", DateUtil.toISOString(timestamp))
.also {
if (device != null) it.put("device", device)
if (pump != null) it.put("pump", JSONObject(pump))
it.put("openaps", JSONObject().also { openaps ->
if (enacted != null) openaps.put("enacted", JSONObject(enacted))
if (suggested != null) openaps.put("suggested", JSONObject(suggested))
if (iob != null) openaps.put("iob", iob)
})
if (uploaderBattery != 0) it.put("uploaderBattery", uploaderBattery)
if (configuration != null) it.put("configuration", JSONObject(configuration))
}
fun buildDeviceStatus(
dateUtil: DateUtil,
loopPlugin: LoopInterface,
iobCobCalculatorPlugin: IobCobCalculator,
profileFunction: ProfileFunction,
pumpInterface: PumpInterface,
receiverStatusStore: ReceiverStatusStore,
runningConfiguration: RunningConfiguration,
version: String
): DeviceStatus? {
val profile = profileFunction.getProfile() ?: return null
val profileName = profileFunction.getProfileName() ?: return null
val lastRun = loopPlugin.lastRun
var apsResult: JSONObject? = null
var iob: JSONObject? = null
var enacted: JSONObject? = null
if (lastRun != null && lastRun.lastAPSRun > dateUtil._now() - 300 * 1000L) {
// do not send if result is older than 1 min
apsResult = lastRun.request?.json()?.also {
it.put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun))
}
iob = lastRun.request?.iob?.json()?.also {
it.put("time", DateUtil.toISOString(lastRun.lastAPSRun))
}
val requested = JSONObject()
if (lastRun.tbrSetByPump?.enacted == true) { // enacted
enacted = lastRun.request?.json()?.also {
it.put("rate", lastRun.tbrSetByPump!!.json(profile)["rate"])
it.put("duration", lastRun.tbrSetByPump!!.json(profile)["duration"])
it.put("received", true)
}
requested.put("duration", lastRun.request?.duration)
requested.put("rate", lastRun.request?.rate)
requested.put("temp", "absolute")
requested.put("smb", lastRun.request?.smb)
enacted?.put("requested", requested)
enacted?.put("smb", lastRun.tbrSetByPump?.bolusDelivered)
}
} else {
val calcIob = iobCobCalculatorPlugin.calculateIobArrayInDia(profile)
if (calcIob.isNotEmpty()) {
iob = calcIob[0].json()
iob.put("time", DateUtil.toISOString(dateUtil._now()))
}
}
return DeviceStatus(
timestamp = dateUtil._now(),
suggested = apsResult?.toString(),
iob = iob?.toString(),
enacted = enacted?.toString(),
device = "openaps://" + Build.MANUFACTURER + " " + Build.MODEL,
pump = pumpInterface.getJSONStatus(profile, profileName, version).toString(),
uploaderBattery = receiverStatusStore.batteryLevel,
configuration = runningConfiguration.configuration().toString()
)
}
/* /*
{ {
@ -364,41 +440,3 @@ import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
"created_at": "2016-06-24T09:27:49.230Z" "created_at": "2016-06-24T09:27:49.230Z"
} }
*/ */
public class DeviceStatus {
private final AAPSLogger aapsLogger;
public String device = null;
public JSONObject pump = null;
public JSONObject enacted = null;
public JSONObject suggested = null;
public JSONObject iob = null;
public int uploaderBattery = 0;
public String created_at = null;
public JSONObject configuration = null;
public DeviceStatus(AAPSLogger aapsLogger) {
this.aapsLogger = aapsLogger;
}
public JSONObject mongoRecord() {
JSONObject record = new JSONObject();
try {
if (device != null) record.put("device", device);
if (pump != null) record.put("pump", pump);
JSONObject openaps = new JSONObject();
if (enacted != null) openaps.put("enacted", enacted);
if (suggested != null) openaps.put("suggested", suggested);
if (iob != null) openaps.put("iob", iob);
record.put("openaps", openaps);
if (uploaderBattery != 0) record.put("uploaderBattery", uploaderBattery);
if (created_at != null) record.put("created_at", created_at);
if (configuration != null) record.put("configuration", configuration);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return record;
}
}

View file

@ -71,7 +71,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
PumpSync pumpSync, PumpSync pumpSync,
FabricPrivacy fabricPrivacy FabricPrivacy fabricPrivacy
) { ) {
super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil); super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync);
this.aapsLogger = aapsLogger; this.aapsLogger = aapsLogger;
this.context = context; this.context = context;
this.resourceHelper = resourceHelper; this.resourceHelper = resourceHelper;

View file

@ -24,6 +24,7 @@ import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.CommandQueueProvider;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpSync;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -69,9 +70,10 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
CommandQueueProvider commandQueue, CommandQueueProvider commandQueue,
DetailedBolusInfoStorage detailedBolusInfoStorage, DetailedBolusInfoStorage detailedBolusInfoStorage,
DateUtil dateUtil, DateUtil dateUtil,
FabricPrivacy fabricPrivacy FabricPrivacy fabricPrivacy,
PumpSync pumpSync
) { ) {
super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil); super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync);
this.aapsLogger = aapsLogger; this.aapsLogger = aapsLogger;
this.context = context; this.context = context;
this.resourceHelper = resourceHelper; this.resourceHelper = resourceHelper;

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.danaRv2.comm
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.danar.R import info.nightscout.androidaps.danar.R
import info.nightscout.androidaps.danar.comm.MessageBase import info.nightscout.androidaps.danar.comm.MessageBase
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.db.ExtendedBolus import info.nightscout.androidaps.db.ExtendedBolus
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.db.TemporaryBasal
@ -91,26 +90,26 @@ class MsgHistoryEvents_v2 constructor(
info.nightscout.androidaps.dana.DanaPump.BOLUS -> { info.nightscout.androidaps.dana.DanaPump.BOLUS -> {
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0) val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0)
?: DetailedBolusInfo() val newRecord = pumpSync.syncBolusWithPumpId(
detailedBolusInfo.bolusTimestamp = datetime timestamp = datetime,
detailedBolusInfo.pumpType = PumpType.DANA_RV2 amount = param1 / 100.0,
detailedBolusInfo.pumpSerial = danaPump.serialNumber type = detailedBolusInfo?.bolusType,
detailedBolusInfo.bolusPumpId = datetime pumpId = datetime,
detailedBolusInfo.insulin = param1 / 100.0 pumpType = PumpType.DANA_RV2,
val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) pumpSerial = danaPump.serialNumber)
aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT BOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min") aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT BOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min")
status = "BOLUS " + dateUtil.timeString(datetime) status = "BOLUS " + dateUtil.timeString(datetime)
} }
info.nightscout.androidaps.dana.DanaPump.DUALBOLUS -> { info.nightscout.androidaps.dana.DanaPump.DUALBOLUS -> {
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0) val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0)
?: DetailedBolusInfo() val newRecord = pumpSync.syncBolusWithPumpId(
detailedBolusInfo.bolusTimestamp = datetime timestamp = datetime,
detailedBolusInfo.pumpType = PumpType.DANA_RV2 amount = param1 / 100.0,
detailedBolusInfo.pumpSerial = danaPump.serialNumber type = detailedBolusInfo?.bolusType,
detailedBolusInfo.bolusPumpId = datetime pumpId = datetime,
detailedBolusInfo.insulin = param1 / 100.0 pumpType = PumpType.DANA_RV2,
val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) pumpSerial = danaPump.serialNumber)
aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT DUALBOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min") aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT DUALBOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min")
status = "DUALBOLUS " + dateUtil.timeString(datetime) status = "DUALBOLUS " + dateUtil.timeString(datetime)
} }
@ -155,13 +154,12 @@ class MsgHistoryEvents_v2 constructor(
} }
info.nightscout.androidaps.dana.DanaPump.CARBS -> { info.nightscout.androidaps.dana.DanaPump.CARBS -> {
val emptyCarbsInfo = DetailedBolusInfo() val newRecord = pumpSync.syncCarbsWithTimestamp(
emptyCarbsInfo.carbs = param1.toDouble() timestamp = datetime,
emptyCarbsInfo.carbsTimestamp = datetime amount = param1.toDouble(),
emptyCarbsInfo.pumpType = PumpType.DANA_RV2 pumpId = datetime,
emptyCarbsInfo.pumpSerial = danaPump.serialNumber pumpType = PumpType.DANA_RV2,
emptyCarbsInfo.carbsPumpId = datetime pumpSerial = danaPump.serialNumber)
val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(emptyCarbsInfo, false)
aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT CARBS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Carbs: " + param1 + "g") aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT CARBS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Carbs: " + param1 + "g")
status = "CARBS " + dateUtil.timeString(datetime) status = "CARBS " + dateUtil.timeString(datetime)
} }

View file

@ -29,6 +29,7 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.PumpPluginBase; import info.nightscout.androidaps.interfaces.PumpPluginBase;
import info.nightscout.androidaps.interfaces.PumpSync;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -64,6 +65,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
protected SP sp; protected SP sp;
protected DateUtil dateUtil; protected DateUtil dateUtil;
protected AapsSchedulers aapsSchedulers; protected AapsSchedulers aapsSchedulers;
protected PumpSync pumpSync;
protected AbstractDanaRPlugin( protected AbstractDanaRPlugin(
HasAndroidInjector injector, HasAndroidInjector injector,
@ -76,7 +78,8 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
RxBusWrapper rxBus, RxBusWrapper rxBus,
ActivePluginProvider activePlugin, ActivePluginProvider activePlugin,
SP sp, SP sp,
DateUtil dateUtil DateUtil dateUtil,
PumpSync pumpSync
) { ) {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.PUMP) .mainType(PluginType.PUMP)
@ -95,6 +98,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
this.sp = sp; this.sp = sp;
this.dateUtil = dateUtil; this.dateUtil = dateUtil;
this.aapsSchedulers = aapsSchedulers; this.aapsSchedulers = aapsSchedulers;
this.pumpSync = pumpSync;
} }
@Override protected void onStart() { @Override protected void onStart() {

View file

@ -25,6 +25,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.CommandQueueProvider;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpSync;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -34,6 +35,7 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.Round; import info.nightscout.androidaps.utils.Round;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers; import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -63,9 +65,10 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
CommandQueueProvider commandQueue, CommandQueueProvider commandQueue,
DanaPump danaPump, DanaPump danaPump,
DateUtil dateUtil, DateUtil dateUtil,
FabricPrivacy fabricPrivacy FabricPrivacy fabricPrivacy,
PumpSync pumpSync
) { ) {
super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil); super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync);
this.aapsLogger = aapsLogger; this.aapsLogger = aapsLogger;
this.context = context; this.context = context;
this.resourceHelper = resourceHelper; this.resourceHelper = resourceHelper;
@ -176,7 +179,21 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.getBolusDelivered()); aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.getBolusDelivered());
detailedBolusInfo.insulin = t.insulin; detailedBolusInfo.insulin = t.insulin;
detailedBolusInfo.timestamp = System.currentTimeMillis(); detailedBolusInfo.timestamp = System.currentTimeMillis();
activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false); if (detailedBolusInfo.insulin > 0)
pumpSync.syncBolusWithPumpId(
detailedBolusInfo.timestamp,
detailedBolusInfo.insulin,
detailedBolusInfo.getBolusType(),
dateUtil._now(),
PumpType.DANA_R,
serialNumber());
if (detailedBolusInfo.carbs > 0)
pumpSync.syncCarbsWithTimestamp(
detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime).msecs(),
detailedBolusInfo.carbs,
null,
PumpType.DANA_R,
serialNumber());
return result; return result;
} else { } else {
PumpEnactResult result = new PumpEnactResult(getInjector()); PumpEnactResult result = new PumpEnactResult(getInjector());

File diff suppressed because it is too large Load diff

View file

@ -6,14 +6,14 @@ import androidx.room.TypeConverters
import info.nightscout.androidaps.database.daos.* import info.nightscout.androidaps.database.daos.*
import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.entities.*
const val DATABASE_VERSION = 9 const val DATABASE_VERSION = 10
@Database(version = DATABASE_VERSION, @Database(version = DATABASE_VERSION,
entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class, entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class,
EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class, EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class,
TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class, TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class,
MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class,
Food::class], Food::class, DeviceStatus::class],
exportSchema = true) exportSchema = true)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
internal abstract class AppDatabase : RoomDatabase() { internal abstract class AppDatabase : RoomDatabase() {
@ -54,4 +54,6 @@ internal abstract class AppDatabase : RoomDatabase() {
abstract val foodDao: FoodDao abstract val foodDao: FoodDao
abstract val deviceStatusDao: DeviceStatusDao
} }

View file

@ -312,7 +312,6 @@ open class AppRepository @Inject internal constructor(
// CARBS // CARBS
val timeBackForExpand = 8 * 60 * 60 * 1000
private fun expandCarbs(carbs: Carbs): List<Carbs> = private fun expandCarbs(carbs: Carbs): List<Carbs> =
if (carbs.duration == 0L) { if (carbs.duration == 0L) {
listOf(carbs) listOf(carbs)
@ -330,6 +329,8 @@ open class AppRepository @Inject internal constructor(
private fun Single<List<Carbs>>.expand() = this.map { it.map(::expandCarbs).flatten() } private fun Single<List<Carbs>>.expand() = this.map { it.map(::expandCarbs).flatten() }
private fun Single<List<Carbs>>.filterOutExtended() = this.map { it.filter { c -> c.duration == 0L } } private fun Single<List<Carbs>>.filterOutExtended() = this.map { it.filter { c -> c.duration == 0L } }
private fun Single<List<Carbs>>.fromTo(from: Long, to: Long) = this.map { it.filter { c -> c.timestamp in from..to } } private fun Single<List<Carbs>>.fromTo(from: Long, to: Long) = this.map { it.filter { c -> c.timestamp in from..to } }
private fun Single<List<Carbs>>.until(to: Long) = this.map { it.filter { c -> c.timestamp <= to } }
private fun Single<List<Carbs>>.from(start: Long) = this.map { it.filter { c -> c.timestamp >= start } }
private fun Single<List<Carbs>>.sort() = this.map { it.sortedBy { c -> c.timestamp } } private fun Single<List<Carbs>>.sort() = this.map { it.sortedBy { c -> c.timestamp } }
/* /*
@ -375,8 +376,9 @@ open class AppRepository @Inject internal constructor(
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getCarbsDataFromTimeExpanded(timestamp: Long, ascending: Boolean): Single<List<Carbs>> = fun getCarbsDataFromTimeExpanded(timestamp: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsFromTime(timestamp - timeBackForExpand) database.carbsDao.getCarbsFromTimeExpandable(timestamp)
.expand() .expand()
.from(timestamp)
.map { if (!ascending) it.reversed() else it } .map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@ -386,7 +388,7 @@ open class AppRepository @Inject internal constructor(
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getCarbsDataFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> = fun getCarbsDataFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsFromTimeToTime(from - timeBackForExpand, to) database.carbsDao.getCarbsFromTimeToTimeExpandable(from, to)
.expand() .expand()
.fromTo(from, to) .fromTo(from, to)
.sort() .sort()
@ -394,12 +396,19 @@ open class AppRepository @Inject internal constructor(
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getCarbsIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single<List<Carbs>> = fun getCarbsIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsIncludingInvalidFromTime(timestamp - timeBackForExpand) database.carbsDao.getCarbsIncludingInvalidFromTime(timestamp)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getCarbsIncludingInvalidFromTimeExpanded(timestamp: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsIncludingInvalidFromTimeExpandable(timestamp)
.expand()
.from(timestamp)
.map { if (!ascending) it.reversed() else it } .map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getCarbsIncludingInvalidFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> = fun getCarbsIncludingInvalidFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsIncludingInvalidFromTimeToTime(from - timeBackForExpand, to) database.carbsDao.getCarbsIncludingInvalidFromTimeToTimeExpandable(from, to)
.expand() .expand()
.fromTo(from, to) .fromTo(from, to)
.sort() .sort()
@ -446,6 +455,26 @@ open class AppRepository @Inject internal constructor(
fun deleteAllBolusCalculatorResults() = fun deleteAllBolusCalculatorResults() =
database.bolusCalculatorResultDao.deleteAllEntries() database.bolusCalculatorResultDao.deleteAllEntries()
// DEVICE STATUS
fun insert(deviceStatus: DeviceStatus) : Long =
database.deviceStatusDao.insert(deviceStatus)
/*
* 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 getNextSyncElementDeviceStatus(id: Long): Maybe<DeviceStatus> =
database.deviceStatusDao.getNextModifiedOrNewAfter(id)
.subscribeOn(Schedulers.io())
fun getModifiedDeviceStatusDataFromId(lastId: Long): Single<List<DeviceStatus>> =
database.deviceStatusDao.getModifiedFrom(lastId)
.subscribeOn(Schedulers.io())
} }
@Suppress("USELESS_CAST") @Suppress("USELESS_CAST")

View file

@ -24,5 +24,6 @@ internal class DelegatedAppDatabase(val changes: MutableList<DBEntry>, val datab
val userEntryDao: UserEntryDao = DelegatedUserEntryDao(changes, database.userEntryDao) val userEntryDao: UserEntryDao = DelegatedUserEntryDao(changes, database.userEntryDao)
val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao) val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao)
val foodDao: FoodDao = DelegatedFoodDao(changes, database.foodDao) val foodDao: FoodDao = DelegatedFoodDao(changes, database.foodDao)
val deviceStatusDao: DeviceStatusDao = DelegatedDeviceStatusDao(changes, database.deviceStatusDao)
fun clearAllTables() = database.clearAllTables() fun clearAllTables() = database.clearAllTables()
} }

View file

@ -5,11 +5,11 @@ const val TABLE_APS_RESULT_LINKS = "apsResultLinks"
const val TABLE_BOLUSES = "boluses" const val TABLE_BOLUSES = "boluses"
const val TABLE_BOLUS_CALCULATOR_RESULTS = "bolusCalculatorResults" const val TABLE_BOLUS_CALCULATOR_RESULTS = "bolusCalculatorResults"
const val TABLE_CARBS = "carbs" const val TABLE_CARBS = "carbs"
const val TABLE_DEVICE_STATUS = "deviceStatus"
const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches" const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches"
const val TABLE_EXTENDED_BOLUSES = "extendedBoluses" const val TABLE_EXTENDED_BOLUSES = "extendedBoluses"
const val TABLE_GLUCOSE_VALUES = "glucoseValues" const val TABLE_GLUCOSE_VALUES = "glucoseValues"
const val TABLE_FOODS = "foods" const val TABLE_FOODS = "foods"
const val TABLE_MEAL_LINKS = "mealLinks"
const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks" const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks"
const val TABLE_PROFILE_SWITCHES = "profileSwitches" const val TABLE_PROFILE_SWITCHES = "profileSwitches"
const val TABLE_TEMPORARY_BASALS = "temporaryBasals" const val TABLE_TEMPORARY_BASALS = "temporaryBasals"
@ -18,4 +18,4 @@ const val TABLE_TOTAL_DAILY_DOSES = "totalDailyDoses"
const val TABLE_THERAPY_EVENTS = "therapyEvents" const val TABLE_THERAPY_EVENTS = "therapyEvents"
const val TABLE_PREFERENCE_CHANGES = "preferenceChanges" const val TABLE_PREFERENCE_CHANGES = "preferenceChanges"
const val TABLE_VERSION_CHANGES = "versionChanges" const val TABLE_VERSION_CHANGES = "versionChanges"
const val TABLE_USER_ENTRY = "userEntry" const val TABLE_USER_ENTRY = "userEntry"

View file

@ -35,15 +35,27 @@ internal interface CarbsDao : TraceableDao<Carbs> {
@Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsFromTime(timestamp: Long): Single<List<Carbs>> fun getCarbsFromTime(timestamp: Long): Single<List<Carbs>>
@Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp + duration >= :timestamp AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsFromTimeExpandable(timestamp: Long): Single<List<Carbs>>
@Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsFromTimeToTime(from: Long, to: Long): Single<List<Carbs>> fun getCarbsFromTimeToTime(from: Long, to: Long): Single<List<Carbs>>
@Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp + duration >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsFromTimeToTimeExpandable(from: Long, to: Long): Single<List<Carbs>>
@Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsIncludingInvalidFromTime(timestamp: Long): Single<List<Carbs>> fun getCarbsIncludingInvalidFromTime(timestamp: Long): Single<List<Carbs>>
@Query("SELECT * FROM $TABLE_CARBS WHERE timestamp + duration >= :timestamp AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsIncludingInvalidFromTimeExpandable(timestamp: Long): Single<List<Carbs>>
@Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsIncludingInvalidFromTimeToTime(from: Long, to: Long): Single<List<Carbs>> fun getCarbsIncludingInvalidFromTimeToTime(from: Long, to: Long): Single<List<Carbs>>
@Query("SELECT * FROM $TABLE_CARBS WHERE timestamp + duration >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC")
fun getCarbsIncludingInvalidFromTimeToTimeExpandable(from: Long, to: Long): Single<List<Carbs>>
// This query will be used with v3 to get all changed records // This query will be used with v3 to get all changed records
@Query("SELECT * FROM $TABLE_CARBS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_CARBS WHERE id > :id) ORDER BY id ASC") @Query("SELECT * FROM $TABLE_CARBS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_CARBS WHERE id > :id) ORDER BY id ASC")
fun getModifiedFrom(id: Long): Single<List<Carbs>> fun getModifiedFrom(id: Long): Single<List<Carbs>>

View file

@ -0,0 +1,41 @@
package info.nightscout.androidaps.database.daos
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import info.nightscout.androidaps.database.entities.DeviceStatus
import info.nightscout.androidaps.database.TABLE_DEVICE_STATUS
import io.reactivex.Maybe
import io.reactivex.Single
@Suppress("FunctionName")
@Dao
internal interface DeviceStatusDao {
@Insert
fun insert(entry: DeviceStatus): Long
@Update
fun update(entry: DeviceStatus)
@Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE id = :id")
fun findById(id: Long): DeviceStatus?
@Query("DELETE FROM $TABLE_DEVICE_STATUS")
fun deleteAllEntries()
@Query("DELETE FROM $TABLE_DEVICE_STATUS WHERE id NOT IN (SELECT MAX(id) FROM $TABLE_DEVICE_STATUS)")
fun deleteAllEntriesExceptLast()
@Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE nightscoutId = :nsId")
fun findByNSId(nsId: String): DeviceStatus?
// This query will be used with v3 to get all changed records
@Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE id > :id ORDER BY id ASC")
fun getModifiedFrom(id: Long): Single<List<DeviceStatus>>
// for WS we need 1 record only
@Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE id > :id ORDER BY id ASC limit 1")
fun getNextModifiedOrNewAfter(id: Long): Maybe<DeviceStatus>
}

View file

@ -0,0 +1,6 @@
package info.nightscout.androidaps.database.daos.delegated
import info.nightscout.androidaps.database.daos.DeviceStatusDao
import info.nightscout.androidaps.database.interfaces.DBEntry
internal class DelegatedDeviceStatusDao(changes: MutableList<DBEntry>, private val dao: DeviceStatusDao) : DelegatedDao(changes), DeviceStatusDao by dao

View file

@ -0,0 +1,44 @@
package info.nightscout.androidaps.database.entities
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import info.nightscout.androidaps.database.TABLE_DEVICE_STATUS
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.interfaces.DBEntryWithTime
import java.util.*
@Entity(tableName = TABLE_DEVICE_STATUS,
foreignKeys = [],
indices = [Index("timestamp")])
data class DeviceStatus(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
@Embedded
var interfaceIDs_backing: InterfaceIDs? = null,
override var timestamp: Long,
override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(),
var device: String? = null,
var pump: String? = null,
var enacted: String? = null,
var suggested: String? = null,
var iob: String? = null,
var uploaderBattery: Int = 0,
var configuration: String? = null
) : DBEntryWithTime {
var interfaceIDs: InterfaceIDs
get() {
var value = this.interfaceIDs_backing
if (value == null) {
value = InterfaceIDs()
interfaceIDs_backing = value
}
return value
}
set(value) {
interfaceIDs_backing = value
}
}

View file

@ -0,0 +1,12 @@
package info.nightscout.androidaps.database.transactions
import info.nightscout.androidaps.database.entities.DeviceStatus
class UpdateNsIdDeviceStatusTransaction(val deviceStatus: DeviceStatus) : Transaction<Unit>() {
override fun run() {
val current = database.deviceStatusDao.findById(deviceStatus.id)
if (current != null && current.interfaceIDs.nightscoutId != deviceStatus.interfaceIDs.nightscoutId)
database.deviceStatusDao.update(deviceStatus)
}
}