diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt index 006732d5aa..f2ecdbfac9 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.activities import android.annotation.SuppressLint import android.app.DatePickerDialog +import android.content.Context import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics @@ -33,6 +34,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCa import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy @@ -69,6 +71,8 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { @Inject lateinit var loop: Loop @Inject lateinit var nsDeviceStatus: NSDeviceStatus @Inject lateinit var translator: Translator + @Inject lateinit var context: Context + @Inject lateinit var dataWorker: DataWorker private val disposable = CompositeDisposable() @@ -106,7 +110,9 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, - repository + repository, + context, + dataWorker ) overviewData = OverviewData( @@ -336,11 +342,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { } private fun runCalculation(from: String) { - Thread { - iobCobCalculator.stopCalculation(from) - iobCobCalculator.stopCalculationTrigger = false - iobCobCalculator.runCalculation(from, overviewData.toTime, bgDataReload = true, limitDataToOldestAvailable = false, cause = EventCustomCalculationFinished()) - }.start() + iobCobCalculator.runCalculation(from, overviewData.toTime, bgDataReload = true, limitDataToOldestAvailable = false, cause = EventCustomCalculationFinished()) } @Volatile diff --git a/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt b/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt index 54036aa7d3..8f5746859f 100644 --- a/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt @@ -8,8 +8,8 @@ import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB import info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF.DetermineBasalAdapterSMBDynamicISFJS -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Worker +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOrefWorker @Module @Suppress("unused") @@ -21,6 +21,6 @@ abstract class APSModule { @ContributesAndroidInjector abstract fun determineBasalAdapterAMAJSInjector(): DetermineBasalAdapterAMAJS @ContributesAndroidInjector abstract fun determineBasalAdapterSMBJSInjector(): DetermineBasalAdapterSMBJS @ContributesAndroidInjector abstract fun determineBasalAdapterSMBAutoISFJSInjector(): DetermineBasalAdapterSMBDynamicISFJS - @ContributesAndroidInjector abstract fun iobCobThreadInjector(): IobCobThread - @ContributesAndroidInjector abstract fun iobCobOref1ThreadInjector(): IobCobOref1Thread + @ContributesAndroidInjector abstract fun iobCobWorkerInjector(): IobCobOrefWorker + @ContributesAndroidInjector abstract fun iobCobOref1WorkerInjector(): IobCobOref1Worker } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.kt index 970b047ddb..d5ea640f00 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.kt @@ -190,7 +190,7 @@ class NSClientService : DaggerService() { lastAckTime = dateUtil.now() dataWorker.enqueue( OneTimeWorkRequest.Builder(NSClientAddAckWorker::class.java) - .setInputData(dataWorker.storeInputData(ack, null)) + .setInputData(dataWorker.storeInputData(ack)) .build() ) } @@ -199,7 +199,7 @@ class NSClientService : DaggerService() { lastAckTime = dateUtil.now() dataWorker.enqueue( OneTimeWorkRequest.Builder(NSClientUpdateRemoveAckWorker::class.java) - .setInputData(dataWorker.storeInputData(ack, null)) + .setInputData(dataWorker.storeInputData(ack)) .build() ) } @@ -483,7 +483,7 @@ class NSClientService : DaggerService() { rxBus.send(EventNSClientNewLog("PROFILE", "profile received")) dataWorker.enqueue( OneTimeWorkRequest.Builder(LocalProfilePlugin.NSProfileWorker::class.java) - .setInputData(dataWorker.storeInputData(profileStoreJson, null)) + .setInputData(dataWorker.storeInputData(profileStoreJson)) .build() ) xDripBroadcast.sendProfile(profileStoreJson) @@ -502,7 +502,7 @@ class NSClientService : DaggerService() { if (addedOrUpdatedTreatments.length() > 0) { dataWorker.enqueue( OneTimeWorkRequest.Builder(NSClientAddUpdateWorker::class.java) - .setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments, null)) + .setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments)) .build() ) xDripBroadcast.sendTreatments(addedOrUpdatedTreatments) @@ -520,7 +520,7 @@ class NSClientService : DaggerService() { if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods")) dataWorker.enqueue( OneTimeWorkRequest.Builder(FoodWorker::class.java) - .setInputData(dataWorker.storeInputData(foods, null)) + .setInputData(dataWorker.storeInputData(foods)) .build() ) } @@ -529,7 +529,7 @@ class NSClientService : DaggerService() { if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs")) dataWorker.enqueue( OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java) - .setInputData(dataWorker.storeInputData(mbgArray, null)) + .setInputData(dataWorker.storeInputData(mbgArray)) .build() ) } @@ -546,7 +546,7 @@ class NSClientService : DaggerService() { sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true) dataWorker.enqueue( OneTimeWorkRequest.Builder(NSClientSourceWorker::class.java) - .setInputData(dataWorker.storeInputData(sgvs, null)) + .setInputData(dataWorker.storeInputData(sgvs)) .build() ) xDripBroadcast.sendSgvs(sgvs) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt index d7991a6707..8860bcc635 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt @@ -1,7 +1,12 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator +import android.content.Context import android.os.SystemClock import androidx.collection.LongSparseArray +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkInfo +import androidx.work.WorkManager import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R @@ -27,6 +32,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHi import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy @@ -62,7 +68,9 @@ class IobCobCalculatorPlugin @Inject constructor( private val sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, private val fabricPrivacy: FabricPrivacy, private val dateUtil: DateUtil, - private val repository: AppRepository + private val repository: AppRepository, + private val context: Context, + private val dataWorker: DataWorker ) : PluginBase( PluginDescription() .mainType(PluginType.GENERAL) @@ -81,9 +89,10 @@ class IobCobCalculatorPlugin @Inject constructor( override var ads: AutosensDataStore = AutosensDataStore() private val dataLock = Any() - var stopCalculationTrigger = false private var thread: Thread? = null + private val jobGroupName = "calculation" + override fun onStart() { super.onStart() // EventConfigBuilderChange @@ -168,10 +177,9 @@ class IobCobCalculatorPlugin @Inject constructor( return oldestTime } - fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long { + override fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long { val profile = profileFunction.getProfile(from) - var dia = Constants.defaultDIA - if (profile != null) dia = profile.dia + val dia = profile?.dia ?: Constants.defaultDIA val oldestDataAvailable = oldestDataAvailable() val getBGDataFrom: Long if (limitDataToOldestAvailable) { @@ -367,24 +375,31 @@ class IobCobCalculatorPlugin @Inject constructor( } fun stopCalculation(from: String) { - if (thread?.state != Thread.State.TERMINATED) { - stopCalculationTrigger = true - aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") - while (thread != null && thread?.state != Thread.State.TERMINATED) { - SystemClock.sleep(100) - } - aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") - } + aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") + WorkManager.getInstance(context).cancelUniqueWork(jobGroupName) + val workStatus = WorkManager.getInstance(context).getWorkInfosForUniqueWork(jobGroupName).get() + while (workStatus.size >= 1 && workStatus[0].state == WorkInfo.State.RUNNING) + SystemClock.sleep(100) + aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") } fun runCalculation(from: String, end: Long, bgDataReload: Boolean, limitDataToOldestAvailable: Boolean, cause: Event?) { - aapsLogger.debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeAndSecondsString(end)) - if (thread == null || thread?.state == Thread.State.TERMINATED) { - thread = - if (sensitivityOref1Plugin.isEnabled()) IobCobOref1Thread(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause) - else IobCobThread(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause) - thread?.start() - } + aapsLogger.debug(LTag.AUTOSENS, "Starting calculation worker: $from to ${dateUtil.dateAndTimeAndSecondsString(end)}") + + val iobCalculation = + if (sensitivityOref1Plugin.isEnabled()) + OneTimeWorkRequest.Builder(IobCobOref1Worker::class.java) + .setInputData( + dataWorker.storeInputData(IobCobOref1Worker.IobCobOref1WorkerData(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause)) + ).build() + else + OneTimeWorkRequest.Builder(IobCobOref1Worker::class.java) + .setInputData( + dataWorker.storeInputData(IobCobOrefWorker.IobCobOrefWorkerData(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause)) + ).build() + + WorkManager.getInstance(context) + .enqueueUniqueWork(jobGroupName, ExistingWorkPolicy.REPLACE, iobCalculation) } // Limit rate of EventNewHistoryData diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt similarity index 85% rename from app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt rename to app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt index 1e0abcd34c..7b47278a8e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt @@ -1,8 +1,10 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator import android.content.Context -import android.os.PowerManager import android.os.SystemClock +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R @@ -12,9 +14,8 @@ import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.extensions.target import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.shared.logging.AAPSLogger -import info.nightscout.shared.logging.LTag import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification @@ -23,6 +24,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy @@ -30,6 +32,8 @@ import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP import java.util.* import javax.inject.Inject @@ -38,15 +42,10 @@ import kotlin.math.max import kotlin.math.min import kotlin.math.roundToLong -class IobCobOref1Thread internal constructor( - private val injector: HasAndroidInjector, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance - private val from: String, - private val end: Long, - private val bgDataReload: Boolean, - private val limitDataToOldestAvailable: Boolean, - private val cause: Event? -) : Thread() { +class IobCobOref1Worker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var sp: SP @@ -62,48 +61,58 @@ class IobCobOref1Thread internal constructor( @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var dateUtil: DateUtil @Inject lateinit var repository: AppRepository - - private var mWakeLock: PowerManager.WakeLock? = null + @Inject lateinit var dataWorker: DataWorker init { - injector.androidInjector().inject(this) - mWakeLock = (context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, rh.gs(R.string.app_name) + ":iobCobThread") + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) } - override fun run() { + class IobCobOref1WorkerData( + val injector: HasAndroidInjector, + val iobCobCalculatorPlugin: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance + val from: String, + val end: Long, + val bgDataReload: Boolean, + val limitDataToOldestAvailable: Boolean, + val cause: Event? + ) + + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as IobCobOref1WorkerData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + val start = dateUtil.now() - mWakeLock?.acquire(T.mins(10).msecs()) try { - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from") + aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: ${data.from}") if (!profileFunction.isProfileValid("IobCobThread")) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): $from") - return // app still initializing + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): ${data.from}") + return Result.failure(workDataOf("Error" to "app still initializing")) } //log.debug("Locking calculateSensitivityData"); - val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable) - if (bgDataReload) { - iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus) - iobCobCalculatorPlugin.clearCache() + val oldestTimeWithData = data.iobCobCalculatorPlugin.calculateDetectionStart(data.end, data.limitDataToOldestAvailable) + if (data.bgDataReload) { + data.iobCobCalculatorPlugin.ads.loadBgData(data.end, repository, aapsLogger, dateUtil, rxBus) + data.iobCobCalculatorPlugin.clearCache() } // work on local copy and set back when finished - val ads = iobCobCalculatorPlugin.ads.clone() + val ads = data.iobCobCalculatorPlugin.ads.clone() val bucketedData = ads.bucketedData val autosensDataTable = ads.autosensDataTable if (bucketedData == null || bucketedData.size < 3) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") - return + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): ${data.from}") + return Result.failure(workDataOf("Error" to "Aborting calculation thread (No bucketed data available): ${data.from}")) } val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp) aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) var previous = autosensDataTable[prevDataTime] // start from oldest to be able sub cob for (i in bucketedData.size - 4 downTo 0) { - val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" - rxBus.send(EventIobCalculationProgress(progress, cause)) - if (iobCobCalculatorPlugin.stopCalculationTrigger) { - iobCobCalculatorPlugin.stopCalculationTrigger = false - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") - return + val progress = i.toString() + if (buildHelper.isDev()) " (${data.from})" else "" + rxBus.send(EventIobCalculationProgress(progress, data.cause)) + if (isStopped) { + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): ${data.from}") + return Result.failure(workDataOf("Error" to "Aborting calculation thread (trigger): ${data.from}")) } // check if data already exists var bgTime = bucketedData[i].timestamp @@ -116,12 +125,12 @@ class IobCobOref1Thread internal constructor( } val profile = profileFunction.getProfile(bgTime) if (profile == null) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from") + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): ${data.from}") continue // profile not set yet } - aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")") + aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: ${data.from} ($i/${bucketedData.size})") val sens = profile.getIsfMgdl(bgTime) - val autosensData = AutosensData(injector) + val autosensData = AutosensData(data.injector) autosensData.time = bgTime if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList() @@ -136,7 +145,7 @@ class IobCobOref1Thread internal constructor( autosensData.bg = bg delta = bg - bucketedData[i + 1].value avgDelta = (bg - bucketedData[i + 3].value) / 3 - val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) + val iob = data.iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) val bgi = -iob.activity * sens * 5 val deviation = delta - bgi val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0 @@ -312,22 +321,27 @@ class IobCobOref1Thread internal constructor( if (min in 0..4 && hours % 2 == 0) autosensData.extraDeviation.add(0.0) previous = autosensData if (bgTime < dateUtil.now()) autosensDataTable.put(bgTime, autosensData) - aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil)) + aapsLogger.debug( + LTag.AUTOSENS, + "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime( + dateUtil + ) + ) val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime) aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") autosensData.autosensResult = sensitivity aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) } - iobCobCalculatorPlugin.ads = ads + data.iobCobCalculatorPlugin.ads = ads Thread { SystemClock.sleep(1000) - rxBus.send(EventAutosensCalculationFinished(cause)) + rxBus.send(EventAutosensCalculationFinished(data.cause)) }.start() } finally { - mWakeLock?.release() - rxBus.send(EventIobCalculationProgress("", cause)) - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") + rxBus.send(EventIobCalculationProgress("", data.cause)) + aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: ${data.from}") profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start) } + return Result.success() } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOrefWorker.kt similarity index 81% rename from app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt rename to app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOrefWorker.kt index dd0309d03b..879c8c9680 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOrefWorker.kt @@ -1,8 +1,10 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator import android.content.Context -import android.os.PowerManager import android.os.SystemClock +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R @@ -10,9 +12,8 @@ import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.shared.logging.AAPSLogger -import info.nightscout.shared.logging.LTag import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification @@ -21,6 +22,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy @@ -28,23 +30,19 @@ import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP -import java.util.* import javax.inject.Inject import kotlin.math.abs import kotlin.math.max import kotlin.math.min import kotlin.math.roundToLong -class IobCobThread @Inject internal constructor( - private val injector: HasAndroidInjector, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance - private val from: String, - private val end: Long, - private val bgDataReload: Boolean, - private val limitDataToOldestAvailable: Boolean, - private val cause: Event? -) : Thread() { +class IobCobOrefWorker @Inject internal constructor( + context: Context, + params: WorkerParameters +) : Worker(context, params) { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var sp: SP @@ -60,48 +58,57 @@ class IobCobThread @Inject internal constructor( @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var dateUtil: DateUtil @Inject lateinit var repository: AppRepository - - private var mWakeLock: PowerManager.WakeLock? = null + @Inject lateinit var dataWorker: DataWorker init { - injector.androidInjector().inject(this) - mWakeLock = (context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, rh.gs(R.string.app_name) + ":iobCobThread") + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) } - override fun run() { + class IobCobOrefWorkerData( + val injector: HasAndroidInjector, + val iobCobCalculatorPlugin: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance + val from: String, + val end: Long, + val bgDataReload: Boolean, + val limitDataToOldestAvailable: Boolean, + val cause: Event? + ) + + override fun doWork(): Result { + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as IobCobOrefWorkerData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + val start = dateUtil.now() - mWakeLock?.acquire(T.mins(10).msecs()) try { - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from") + aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: ${data.from}") if (!profileFunction.isProfileValid("IobCobThread")) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): $from") - return // app still initializing + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): ${data.from}") + return Result.failure(workDataOf("Error" to "app still initializing")) } //log.debug("Locking calculateSensitivityData"); - val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable) - if (bgDataReload) { - iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus) - iobCobCalculatorPlugin.clearCache() + val oldestTimeWithData = data.iobCobCalculatorPlugin.calculateDetectionStart(data.end, data.limitDataToOldestAvailable) + if (data.bgDataReload) { + data.iobCobCalculatorPlugin.ads.loadBgData(data.end, repository, aapsLogger, dateUtil, rxBus) + data.iobCobCalculatorPlugin.clearCache() } // work on local copy and set back when finished - val ads = iobCobCalculatorPlugin.ads.clone() + val ads = data.iobCobCalculatorPlugin.ads.clone() val bucketedData = ads.bucketedData val autosensDataTable = ads.autosensDataTable if (bucketedData == null || bucketedData.size < 3) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") - return + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): ${data.from}") + return Result.failure(workDataOf("Error" to "Aborting calculation thread (No bucketed data available): ${data.from}")) } val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp) aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) var previous = autosensDataTable[prevDataTime] // start from oldest to be able sub cob for (i in bucketedData.size - 4 downTo 0) { - val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" - rxBus.send(EventIobCalculationProgress(progress, cause)) - if (iobCobCalculatorPlugin.stopCalculationTrigger) { - iobCobCalculatorPlugin.stopCalculationTrigger = false - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") - return + val progress = i.toString() + if (buildHelper.isDev()) " (${data.from})" else "" + rxBus.send(EventIobCalculationProgress(progress, data.cause)) + if (isStopped) { + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): ${data.from}") + return Result.failure(workDataOf("Error" to "Aborting calculation thread (trigger): ${data.from}")) } // check if data already exists var bgTime = bucketedData[i].timestamp @@ -114,12 +121,12 @@ class IobCobThread @Inject internal constructor( } val profile = profileFunction.getProfile(bgTime) if (profile == null) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from") + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): ${data.from}") continue // profile not set yet } - aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")") + aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: ${data.from} ($i/${bucketedData.size})") val sens = profile.getIsfMgdl(bgTime) - val autosensData = AutosensData(injector) + val autosensData = AutosensData(data.injector) autosensData.time = bgTime if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList() @@ -134,7 +141,7 @@ class IobCobThread @Inject internal constructor( autosensData.bg = bg delta = bg - bucketedData[i + 1].value avgDelta = (bg - bucketedData[i + 3].value) / 3 - val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) + val iob = data.iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) val bgi = -iob.activity * sens * 5 val deviation = delta - bgi val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0 @@ -158,7 +165,7 @@ class IobCobThread @Inject internal constructor( if (ad == null) { aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) - //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) + //aapsLogger.debug(LTag.AUTOSENS, data.iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) val notification = Notification(Notification.SEND_LOGFILES, rh.gs(R.string.sendlogfiles), Notification.LOW) rxBus.send(EventNewNotification(notification)) sp.putBoolean("log_AUTOSENS", true) @@ -181,7 +188,7 @@ class IobCobThread @Inject internal constructor( fabricPrivacy.logException(e) aapsLogger.debug(autosensDataTable.toString()) aapsLogger.debug(bucketedData.toString()) - //aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) + //aapsLogger.debug(data.iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) val notification = Notification(Notification.SEND_LOGFILES, rh.gs(R.string.sendlogfiles), Notification.LOW) rxBus.send(EventNewNotification(notification)) sp.putBoolean("log_AUTOSENS", true) @@ -258,22 +265,27 @@ class IobCobThread @Inject internal constructor( } previous = autosensData if (bgTime < dateUtil.now()) autosensDataTable.put(bgTime, autosensData) - aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil)) + aapsLogger.debug( + LTag.AUTOSENS, + "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime( + dateUtil + ) + ) val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime) aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") autosensData.autosensResult = sensitivity aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) } - iobCobCalculatorPlugin.ads = ads + data.iobCobCalculatorPlugin.ads = ads Thread { SystemClock.sleep(1000) - rxBus.send(EventAutosensCalculationFinished(cause)) + rxBus.send(EventAutosensCalculationFinished(data.cause)) }.start() } finally { - mWakeLock?.release() - rxBus.send(EventIobCalculationProgress("", cause)) - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") + rxBus.send(EventIobCalculationProgress("", data.cause)) + aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: ${data.from}") profiler.log(LTag.AUTOSENS, "IobCobThread", start) } + return Result.success() } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt index 7c75e0ebc8..7e738711a3 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt @@ -20,6 +20,8 @@ interface IobCobCalculator { fun calculateFromTreatmentsAndTemps(toTime: Long, profile: Profile): IobTotal + fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long + fun getBasalData(profile: Profile, fromTime: Long): BasalData fun calculateIobArrayInDia(profile: Profile): Array