Merge remote-tracking branch 'upstream/dev' into dash
This commit is contained in:
commit
b56a3d8132
537 changed files with 14988 additions and 14263 deletions
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gradle
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
target-branch: dev
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,6 +2,7 @@
|
|||
.gradle
|
||||
/local.properties
|
||||
.DS_Store
|
||||
*/jacoco.exec
|
||||
/build
|
||||
/captures
|
||||
*.apk
|
||||
|
|
106
app/build.gradle
106
app/build.gradle
|
@ -1,23 +1,18 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://plugins.gradle.org/m2/" } // jacoco 0.2
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4'
|
||||
classpath 'com.hiya:jacoco-android:0.2'
|
||||
}
|
||||
}
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
//apply plugin: 'jacoco-android'
|
||||
apply plugin: 'com.hiya.jacoco-android'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
apply from: "${project.rootDir}/gradle/android_dependencies.gradle"
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.3"
|
||||
toolVersion = "0.8.6"
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
jacoco.includeNoLocationClasses = true
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
@ -109,51 +104,20 @@ tasks.matching { it instanceof Test }.all {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
ndkVersion "21.1.6352462"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 28
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "2.8.2.1-dev"
|
||||
version "2.8.2.1-dev-b"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
|
||||
buildConfigField "String", "COMMITTED", '"' + allCommitted() + '"'
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
// if you change minSdkVersion to less than 11, you need to change executeTask for wear
|
||||
|
||||
ndk {
|
||||
moduleName "BleCommandUtil"
|
||||
}
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
disable 'MissingTranslation'
|
||||
disable 'ExtraTranslation'
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug {
|
||||
testCoverageEnabled(project.hasProperty('coverage'))
|
||||
}
|
||||
firebaseDisable {
|
||||
System.setProperty("disableFirebase", "true")
|
||||
ext.enableCrashlytics = false
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "standard"
|
||||
productFlavors {
|
||||
full {
|
||||
|
@ -197,28 +161,8 @@ android {
|
|||
]
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
returnDefaultValues = true
|
||||
includeAndroidResources = true
|
||||
|
||||
all {
|
||||
maxParallelForks = 10
|
||||
forkEvery = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useLibrary "org.apache.http.legacy"
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
@ -245,32 +189,9 @@ dependencies {
|
|||
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
|
||||
// https://github.com/DavidProdinger/Weekdays-Selector (used outdated 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1')
|
||||
implementation(name: 'weekdaysselector-1.1.1', ext: 'aar')
|
||||
|
||||
testImplementation "junit:junit:$junit_version"
|
||||
testImplementation 'org.json:json:20201115'
|
||||
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
|
||||
testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}"
|
||||
testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
|
||||
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
|
||||
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
|
||||
testImplementation "joda-time:joda-time:$jodatime_version"
|
||||
testImplementation('com.google.truth:truth:1.1.2') {
|
||||
exclude group: "com.google.guava", module: "guava"
|
||||
exclude group: "com.google.code.findbugs", module: "jsr305"
|
||||
}
|
||||
testImplementation "org.skyscreamer:jsonassert:1.5.0"
|
||||
testImplementation "org.hamcrest:hamcrest-all:1.3"
|
||||
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha03'
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidx_junit"
|
||||
androidTestImplementation "androidx.test:rules:$androidx_rules"
|
||||
androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
|
||||
/* Dagger2 - We are going to use dagger.android which includes
|
||||
* support for Activity and fragment injection so we need to include
|
||||
* the following dependencies */
|
||||
* support for Activity and fragment injection so we need to include
|
||||
* the following dependencies */
|
||||
|
||||
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
||||
|
@ -279,10 +200,11 @@ dependencies {
|
|||
|
||||
/* Dagger2 - default dependency */
|
||||
kapt "com.google.dagger:dagger-compiler:$dagger_version"
|
||||
|
||||
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
|
||||
}
|
||||
|
||||
apply from: "${project.rootDir}/gradle/test_dependencies.gradle"
|
||||
|
||||
|
||||
/*
|
||||
// Run 'adb' shell command to clear application data of main app for 'debug' variant
|
||||
task clearMainAppData(type: Exec) {
|
||||
|
|
BIN
app/jacoco.exec
BIN
app/jacoco.exec
Binary file not shown.
Binary file not shown.
|
@ -25,6 +25,7 @@
|
|||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="com.dexcom.cgm.EXTERNAL_PERMISSION" />
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
||||
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
||||
|
||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
|
@ -74,8 +75,12 @@
|
|||
<activity android:name=".activities.StatsActivity" />
|
||||
<activity
|
||||
android:name="com.google.firebase.auth.internal.FederatedSignInActivity"
|
||||
tools:replace="android:launchMode"
|
||||
android:launchMode="standard" />
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:permission="com.google.firebase.auth.api.gms.permission.LAUNCH_FEDERATED_SIGN_IN"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
tools:replace="android:launchMode" />
|
||||
|
||||
<!-- Receive new BG readings from other local apps -->
|
||||
<receiver
|
||||
|
|
|
@ -131,6 +131,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
// Default profile
|
||||
binding.copytolocalprofile.setOnClickListener {
|
||||
storeValues()
|
||||
val age = ageUsed[tabSelected]
|
||||
val weight = weightUsed[tabSelected]
|
||||
val tdd = tddUsed[tabSelected]
|
||||
|
@ -289,7 +290,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun setBackgroundColorOnSelected(tab: Int) {
|
||||
binding.menu1.setBackgroundColor(resourceHelper.gc(if (tab == 1) R.color.defaultbackground else R.color.tabBgColorSelected))
|
||||
binding.menu1.setBackgroundColor(resourceHelper.gc(if (tab == 1) R.color.defaultbackground else R.color.tempbasal))
|
||||
binding.menu2.setBackgroundColor(resourceHelper.gc(if (tab == 0) R.color.defaultbackground else R.color.examinedProfile))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.activities
|
|||
import android.os.Bundle
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.databinding.ActivityStatsBinding
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.stats.TddCalculator
|
||||
|
@ -14,6 +15,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
|
|||
@Inject lateinit var tddCalculator: TddCalculator
|
||||
@Inject lateinit var tirCalculator: TirCalculator
|
||||
@Inject lateinit var activityMonitor: ActivityMonitor
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private lateinit var binding: ActivityStatsBinding
|
||||
|
||||
|
@ -29,6 +31,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
|
|||
binding.ok.setOnClickListener { finish() }
|
||||
binding.reset.setOnClickListener {
|
||||
OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats)) {
|
||||
uel.log("STATS RESET")
|
||||
activityMonitor.reset()
|
||||
recreate()
|
||||
}
|
||||
|
|
|
@ -77,18 +77,13 @@ abstract class FragmentsModule {
|
|||
|
||||
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesTreatmentsExtendedBolusesFragment(): TreatmentsExtendedBolusesFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesTreatmentsCareportalFragment(): TreatmentsCareportalFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesTreatmentsProfileSwitchFragment(): TreatmentsProfileSwitchFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsExtendedBolusesFragment(): TreatmentsExtendedBolusesFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsCareportalFragment(): TreatmentsCareportalFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsProfileSwitchFragment(): TreatmentsProfileSwitchFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsUserEntryFragment(): TreatmentsUserEntryFragment
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesVirtualPumpFragment(): VirtualPumpFragment
|
||||
|
||||
|
|
|
@ -13,12 +13,13 @@ abstract class WizardModule {
|
|||
@ContributesAndroidInjector abstract fun swBreakInjector(): SWBreak
|
||||
@ContributesAndroidInjector abstract fun swButtonInjector(): SWButton
|
||||
@ContributesAndroidInjector abstract fun swEditNumberWithUnitsInjector(): SWEditNumberWithUnits
|
||||
@ContributesAndroidInjector abstract fun swEditNumberInjector(): SWEditNumber
|
||||
@ContributesAndroidInjector abstract fun swEditStringInjector(): SWEditString
|
||||
@ContributesAndroidInjector abstract fun swEditEncryptedPasswordInjector(): SWEditEncryptedPassword
|
||||
@ContributesAndroidInjector abstract fun swEditUrlInjector(): SWEditUrl
|
||||
@ContributesAndroidInjector abstract fun swFragmentInjector(): SWFragment
|
||||
@ContributesAndroidInjector abstract fun swHtmlLinkInjector(): SWHtmlLink
|
||||
@ContributesAndroidInjector abstract fun swInfotextInjector(): SWInfotext
|
||||
@ContributesAndroidInjector abstract fun swInfotextInjector(): SWInfoText
|
||||
@ContributesAndroidInjector abstract fun swItemInjector(): SWItem
|
||||
@ContributesAndroidInjector abstract fun swPluginInjector(): SWPlugin
|
||||
@ContributesAndroidInjector abstract fun swRadioButtonInjector(): SWRadioButton
|
||||
|
|
|
@ -11,6 +11,7 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.databinding.DialogCalibrationBinding
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.XdripCalibrations
|
||||
|
@ -26,6 +27,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var xdripCalibrations: XdripCalibrations
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var _binding: DialogCalibrationBinding? = null
|
||||
|
||||
|
@ -75,7 +77,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
|||
if (bg > 0) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
aapsLogger.debug("USER ENTRY: CALIBRATION $bg")
|
||||
uel.log("CALIBRATION", d1 = bg)
|
||||
xdripCalibrations.sendIntent(bg)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,16 +17,13 @@ import info.nightscout.androidaps.db.Source
|
|||
import info.nightscout.androidaps.db.TempTarget
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.extensions.formatColor
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
@ -46,6 +43,8 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||
@Inject lateinit var nsUpload: NSUpload
|
||||
@Inject lateinit var carbsGenerator: CarbsGenerator
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var carbTimer: CarbTimer
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -174,6 +173,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||
val actions: LinkedList<String?> = LinkedList()
|
||||
val unitLabel = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl)
|
||||
val useAlarm = binding.alarmCheckBox.isChecked
|
||||
|
||||
val activitySelected = binding.activityTt.isChecked
|
||||
if (activitySelected)
|
||||
|
@ -190,6 +190,8 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
val time = eventTime + timeOffset * 1000 * 60
|
||||
if (timeOffset != 0)
|
||||
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time))
|
||||
if (useAlarm && carbs > 0 && timeOffset > 0)
|
||||
actions.add(resourceHelper.gs(R.string.alarminxmin, timeOffset).formatColor(resourceHelper, R.color.info))
|
||||
val duration = binding.duration.value.toInt()
|
||||
if (duration > 0)
|
||||
actions.add(resourceHelper.gs(R.string.duration) + ": " + duration + resourceHelper.gs(R.string.shorthour))
|
||||
|
@ -210,7 +212,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
when {
|
||||
activitySelected -> {
|
||||
aapsLogger.debug("USER ENTRY: TEMPTARGET ACTIVITY $activityTT duration: $activityTTDuration")
|
||||
uel.log("TT ACTIVITY", d1 = activityTT, i1 = activityTTDuration)
|
||||
val tempTarget = TempTarget()
|
||||
.date(System.currentTimeMillis())
|
||||
.duration(activityTTDuration)
|
||||
|
@ -222,7 +224,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
|
||||
eatingSoonSelected -> {
|
||||
aapsLogger.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
|
||||
uel.log("TT EATING SOON", d1 = eatingSoonTT, i1 = eatingSoonTTDuration)
|
||||
val tempTarget = TempTarget()
|
||||
.date(System.currentTimeMillis())
|
||||
.duration(eatingSoonTTDuration)
|
||||
|
@ -234,7 +236,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
|
||||
hypoSelected -> {
|
||||
aapsLogger.debug("USER ENTRY: TEMPTARGET HYPO $hypoTT duration: $hypoTTDuration")
|
||||
uel.log("TT HYPO", d1 = hypoTT, i1 = hypoTTDuration)
|
||||
val tempTarget = TempTarget()
|
||||
.date(System.currentTimeMillis())
|
||||
.duration(hypoTTDuration)
|
||||
|
@ -247,14 +249,17 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
if (carbsAfterConstraints > 0) {
|
||||
if (duration == 0) {
|
||||
aapsLogger.debug("USER ENTRY: CARBS $carbsAfterConstraints time: $time")
|
||||
uel.log("CARBS", d1 = carbsAfterConstraints.toDouble(), i1 = timeOffset)
|
||||
carbsGenerator.createCarb(carbsAfterConstraints, time, CareportalEvent.CARBCORRECTION, notes)
|
||||
} else {
|
||||
aapsLogger.debug("USER ENTRY: CARBS $carbsAfterConstraints time: $time duration: $duration")
|
||||
uel.log("CARBS", d1 = carbsAfterConstraints.toDouble(), i1 = timeOffset, i2 = duration)
|
||||
carbsGenerator.generateCarbs(carbsAfterConstraints, time, duration, notes)
|
||||
nsUpload.uploadEvent(CareportalEvent.NOTE, DateUtil.now() - 2000, resourceHelper.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset))
|
||||
}
|
||||
}
|
||||
if (useAlarm && carbs > 0 && timeOffset > 0) {
|
||||
carbTimer.scheduleReminder(dateUtil._now() + T.mins(timeOffset.toLong()).msecs())
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
} else
|
||||
|
|
|
@ -17,6 +17,7 @@ import info.nightscout.androidaps.databinding.DialogCareBinding
|
|||
import info.nightscout.androidaps.db.CareportalEvent
|
||||
import info.nightscout.androidaps.db.Source
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
|
@ -37,6 +38,7 @@ class CareDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var nsUpload: NSUpload
|
||||
@Inject lateinit var translator: Translator
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
enum class EventType {
|
||||
BGCHECK,
|
||||
|
@ -220,7 +222,7 @@ class CareDialog : DialogFragmentWithDate() {
|
|||
EventType.ANNOUNCEMENT -> CareportalEvent.ANNOUNCEMENT
|
||||
}
|
||||
careportalEvent.json = json.toString()
|
||||
aapsLogger.debug("USER ENTRY: CAREPORTAL ${careportalEvent.eventType} json: ${careportalEvent.json}")
|
||||
uel.log("CAREPORTAL", careportalEvent.eventType)
|
||||
MainApp.getDbHelper().createOrUpdate(careportalEvent)
|
||||
nsUpload.uploadCareportalEntryToNS(json)
|
||||
}, null)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -13,6 +12,7 @@ import info.nightscout.androidaps.databinding.DialogExtendedbolusBinding
|
|||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
|
@ -32,6 +32,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var _binding: DialogExtendedbolusBinding? = null
|
||||
|
||||
|
@ -86,16 +87,11 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
aapsLogger.debug("USER ENTRY: EXTENDED BOLUS $insulinAfterConstraint duration: $durationInMinutes")
|
||||
uel.log("EXTENDED BOLUS", d1 = insulinAfterConstraint, i1 = durationInMinutes)
|
||||
commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -16,6 +15,7 @@ import info.nightscout.androidaps.db.Source
|
|||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
|
@ -37,6 +37,7 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var nsUpload: NSUpload
|
||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var _binding: DialogFillBinding? = null
|
||||
|
||||
|
@ -126,16 +127,16 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
if (insulinAfterConstraints > 0) {
|
||||
aapsLogger.debug("USER ENTRY: PRIME BOLUS $insulinAfterConstraints")
|
||||
uel.log("PRIME BOLUS", d1 = insulinAfterConstraints)
|
||||
requestPrimeBolus(insulinAfterConstraints, notes)
|
||||
}
|
||||
if (siteChange) {
|
||||
aapsLogger.debug("USER ENTRY: SITE CHANGE")
|
||||
uel.log("SITE CHANGE")
|
||||
nsUpload.generateCareportalEvent(CareportalEvent.SITECHANGE, eventTime, notes)
|
||||
}
|
||||
if (insulinChange) {
|
||||
// add a second for case of both checked
|
||||
aapsLogger.debug("USER ENTRY: INSULIN CHANGE")
|
||||
uel.log("INSULIN CHANGE")
|
||||
nsUpload.generateCareportalEvent(CareportalEvent.INSULINCHANGE, eventTime + 1000, notes)
|
||||
}
|
||||
}, null)
|
||||
|
@ -159,12 +160,7 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
|
@ -15,6 +14,7 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.databinding.DialogInsulinBinding
|
||||
import info.nightscout.androidaps.db.CareportalEvent
|
||||
import info.nightscout.androidaps.db.Source
|
||||
|
@ -23,6 +23,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
|||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.*
|
||||
|
@ -46,7 +47,9 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var ctx: Context
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -175,7 +178,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
if (eatingSoonChecked) {
|
||||
aapsLogger.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
|
||||
uel.log("TT EATING SOON", d1 = eatingSoonTT, i1 = eatingSoonTTDuration)
|
||||
val tempTarget = TempTarget()
|
||||
.date(System.currentTimeMillis())
|
||||
.duration(eatingSoonTTDuration)
|
||||
|
@ -193,21 +196,16 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
detailedBolusInfo.source = Source.USER
|
||||
detailedBolusInfo.notes = notes
|
||||
if (recordOnlyChecked) {
|
||||
aapsLogger.debug("USER ENTRY: BOLUS RECORD ONLY $insulinAfterConstraints")
|
||||
uel.log("BOLUS RECORD", d1 = insulinAfterConstraints, i1 = timeOffset)
|
||||
detailedBolusInfo.date = time
|
||||
activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false)
|
||||
} else {
|
||||
aapsLogger.debug("USER ENTRY: BOLUS $insulinAfterConstraints")
|
||||
uel.log("BOLUS", d1 = insulinAfterConstraints)
|
||||
detailedBolusInfo.date = DateUtil.now()
|
||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.view.LayoutInflater
|
||||
|
@ -14,14 +13,15 @@ import dagger.android.support.DaggerDialogFragment
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
|
@ -41,16 +41,17 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var loopPlugin: LoopPlugin
|
||||
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var showOkCancel: Boolean = true
|
||||
private var _binding: DialogLoopBinding? = null
|
||||
private var loopHandler = Handler()
|
||||
private var refreshDialog: Runnable? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
@ -104,7 +105,7 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
binding.cancel.setOnClickListener { dismiss() }
|
||||
|
||||
refreshDialog = Runnable {
|
||||
scheduleUpdateGUI("refreshDialog")
|
||||
scheduleUpdateGUI()
|
||||
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
|
||||
}
|
||||
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
|
||||
|
@ -119,11 +120,11 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
|
||||
var task: Runnable? = null
|
||||
|
||||
private fun scheduleUpdateGUI(from: String) {
|
||||
private fun scheduleUpdateGUI() {
|
||||
class UpdateRunnable : Runnable {
|
||||
|
||||
override fun run() {
|
||||
updateGUI(from)
|
||||
updateGUI("refreshDialog")
|
||||
task = null
|
||||
}
|
||||
}
|
||||
|
@ -137,8 +138,8 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
if (_binding == null) return
|
||||
aapsLogger.debug("UpdateGUI from $from")
|
||||
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
|
||||
val closedLoopAllowed = objectivesPlugin.isClosedLoopAllowed(Constraint(true))
|
||||
val lgsEnabled = objectivesPlugin.isLgsAllowed(Constraint(true))
|
||||
val closedLoopAllowed = constraintChecker.isClosedLoopAllowed(Constraint(true))
|
||||
val lgsEnabled = constraintChecker.isLgsAllowed(Constraint(true))
|
||||
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||
if (profileFunction.isProfileValid("LoopDialogUpdateGUI")) {
|
||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
|
@ -237,28 +238,28 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
val profile = profileFunction.getProfile() ?: return true
|
||||
when (v.id) {
|
||||
R.id.overview_closeloop -> {
|
||||
aapsLogger.debug("USER ENTRY: CLOSED LOOP MODE")
|
||||
uel.log("CLOSED LOOP MODE")
|
||||
sp.putString(R.string.key_aps_mode, "closed")
|
||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop)))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_lgsloop -> {
|
||||
aapsLogger.debug("USER ENTRY: LGS LOOP MODE")
|
||||
uel.log("LGS LOOP MODE")
|
||||
sp.putString(R.string.key_aps_mode, "lgs")
|
||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_openloop -> {
|
||||
aapsLogger.debug("USER ENTRY: OPEN LOOP MODE")
|
||||
uel.log("OPEN LOOP MODE")
|
||||
sp.putString(R.string.key_aps_mode, "open")
|
||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disable -> {
|
||||
aapsLogger.debug("USER ENTRY: LOOP DISABLED")
|
||||
uel.log("LOOP DISABLED")
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
||||
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
|
||||
configBuilderPlugin.storeSettings("DisablingLoop")
|
||||
|
@ -275,7 +276,7 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
R.id.overview_enable -> {
|
||||
aapsLogger.debug("USER ENTRY: LOOP ENABLED")
|
||||
uel.log("LOOP ENABLED")
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
||||
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
||||
configBuilderPlugin.storeSettings("EnablingLoop")
|
||||
|
@ -285,18 +286,13 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
R.id.overview_resume, R.id.overview_reconnect -> {
|
||||
aapsLogger.debug("USER ENTRY: RESUME")
|
||||
uel.log("RESUME")
|
||||
loopPlugin.suspendTo(0L)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -306,49 +302,49 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
R.id.overview_suspend_1h -> {
|
||||
aapsLogger.debug("USER ENTRY: SUSPEND 1h")
|
||||
uel.log("SUSPEND 1h")
|
||||
loopPlugin.suspendLoop(60)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_2h -> {
|
||||
aapsLogger.debug("USER ENTRY: SUSPEND 2h")
|
||||
uel.log("SUSPEND 2h")
|
||||
loopPlugin.suspendLoop(120)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_3h -> {
|
||||
aapsLogger.debug("USER ENTRY: SUSPEND 3h")
|
||||
uel.log("SUSPEND 3h")
|
||||
loopPlugin.suspendLoop(180)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_10h -> {
|
||||
aapsLogger.debug("USER ENTRY: SUSPEND 10h")
|
||||
uel.log("SUSPEND 10h")
|
||||
loopPlugin.suspendLoop(600)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_15m -> {
|
||||
aapsLogger.debug("USER ENTRY: DISCONNECT 15m")
|
||||
uel.log("DISCONNECT 15m")
|
||||
loopPlugin.disconnectPump(15, profile)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_30m -> {
|
||||
aapsLogger.debug("USER ENTRY: DISCONNECT 30m")
|
||||
uel.log("DISCONNECT 30m")
|
||||
loopPlugin.disconnectPump(30, profile)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_1h -> {
|
||||
aapsLogger.debug("USER ENTRY: DISCONNECT 1h")
|
||||
uel.log("DISCONNECT 1h")
|
||||
loopPlugin.disconnectPump(60, profile)
|
||||
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
|
@ -356,14 +352,14 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
R.id.overview_disconnect_2h -> {
|
||||
aapsLogger.debug("USER ENTRY: DISCONNECT 2h")
|
||||
uel.log("DISCONNECT 2h")
|
||||
loopPlugin.disconnectPump(120, profile)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_3h -> {
|
||||
aapsLogger.debug("USER ENTRY: DISCONNECT 3h")
|
||||
uel.log("DISCONNECT 3h")
|
||||
loopPlugin.disconnectPump(180, profile)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
|
|
|
@ -11,6 +11,7 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
|
@ -26,6 +27,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var profileIndex: Int? = null
|
||||
|
||||
|
@ -122,7 +124,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
aapsLogger.debug("USER ENTRY: PROFILE SWITCH $profile percent: $percent timeshift: $timeShift duration: $duration")
|
||||
uel.log("PROFILE SWITCH", d1 = percent.toDouble(), i1 = timeShift, i2 = duration)
|
||||
treatmentsPlugin.doProfileSwitch(profileStore, profile, duration, percent, timeShift, eventTime)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -15,6 +14,7 @@ import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
|||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.interfaces.PumpDescription
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
|
@ -35,6 +35,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var ctx: Context
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var isPercentPump = true
|
||||
|
||||
|
@ -119,20 +120,15 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
val callback: Callback = object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPercentPump) {
|
||||
aapsLogger.debug("USER ENTRY: TEMP BASAL $percent% duration: $durationInMinutes")
|
||||
uel.log("TEMP BASAL", d1 = percent.toDouble(), i1 = durationInMinutes)
|
||||
commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, callback)
|
||||
} else {
|
||||
aapsLogger.debug("USER ENTRY: TEMP BASAL $absolute duration: $durationInMinutes")
|
||||
uel.log("TEMP BASAL", d1 = absolute, i1 = durationInMinutes)
|
||||
commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, callback)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -15,6 +15,7 @@ import info.nightscout.androidaps.db.Source
|
|||
import info.nightscout.androidaps.db.TempTarget
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
|
@ -33,8 +34,9 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
lateinit var reasonList: List<String>
|
||||
private lateinit var reasonList: List<String>
|
||||
|
||||
private var _binding: DialogTemptargetBinding? = null
|
||||
|
||||
|
@ -162,7 +164,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
aapsLogger.debug("USER ENTRY: TEMP TARGET $target duration: $duration")
|
||||
uel.log("TT", d1 = target, i1 = duration)
|
||||
if (target == 0.0 || duration == 0) {
|
||||
val tempTarget = TempTarget()
|
||||
.date(eventTime)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
|
@ -19,6 +18,7 @@ import info.nightscout.androidaps.db.Source
|
|||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
|
@ -41,6 +41,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var ctx: Context
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private val textWatcher: TextWatcher = object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {}
|
||||
|
@ -128,7 +129,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
aapsLogger.debug("USER ENTRY: BOLUS insulin $insulin carbs: $carbs")
|
||||
uel.log("TREATMENT", d1 = insulin, i1 = carbs)
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION
|
||||
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
|
||||
|
@ -140,12 +141,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -270,7 +270,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
val end = start + T.hours(rangeToDisplay.toLong()).msecs()
|
||||
iobCobCalculatorPluginHistory.stopCalculation(from)
|
||||
iobCobCalculatorPluginHistory.clearCache()
|
||||
iobCobCalculatorPluginHistory.runCalculation(from, end, true, false, eventCustomCalculationFinished)
|
||||
iobCobCalculatorPluginHistory.runCalculation(from, end, bgDataReload = true, limitDataToOldestAvailable = false, cause = eventCustomCalculationFinished)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,24 +333,27 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
var useDevForScale = false
|
||||
var useRatioForScale = false
|
||||
var useDSForScale = false
|
||||
var useIAForScale = false
|
||||
var useBGIForScale = false
|
||||
var useABSForScale = false
|
||||
when {
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
|
||||
}
|
||||
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal])
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, toTime, useIAForScale, 0.8)
|
||||
val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
|
||||
val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
|
||||
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, toTime, useABSForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0, alignDevBgiScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, toTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1.0)
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
|
@ -362,7 +365,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
graphData.setNumVerticalLables()
|
||||
graphData.setNumVerticalLabels()
|
||||
graphData.formatAxis(fromTime, toTime)
|
||||
}
|
||||
// finally enforce drawing of graphs in UI thread
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.logger;
|
||||
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import info.nightscout.androidaps.db.StaticInjector;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
|
||||
/**
|
||||
* Created by adrian on 15/10/17.
|
||||
*/
|
||||
|
||||
|
||||
public class LoggerCallback extends ScriptableObject {
|
||||
|
||||
@Inject
|
||||
AAPSLogger aapsLogger;
|
||||
|
||||
private static StringBuffer errorBuffer = new StringBuffer();
|
||||
private static StringBuffer logBuffer = new StringBuffer();
|
||||
|
||||
|
||||
public LoggerCallback() {
|
||||
//empty constructor needed for Rhino
|
||||
errorBuffer = new StringBuffer();
|
||||
logBuffer = new StringBuffer();
|
||||
StaticInjector.Companion.getInstance().androidInjector().inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "LoggerCallback";
|
||||
}
|
||||
|
||||
public void jsConstructor() {
|
||||
//empty constructor on JS site; could work as setter
|
||||
}
|
||||
|
||||
public void jsFunction_log(Object obj1) {
|
||||
aapsLogger.debug(LTag.APS, obj1.toString().trim());
|
||||
logBuffer.append(obj1.toString());
|
||||
}
|
||||
|
||||
public void jsFunction_error(Object obj1) {
|
||||
aapsLogger.error(LTag.APS, obj1.toString().trim());
|
||||
errorBuffer.append(obj1.toString());
|
||||
}
|
||||
|
||||
|
||||
public static String getScriptDebug() {
|
||||
String ret = "";
|
||||
if (errorBuffer.length() > 0) {
|
||||
ret += "e:\n" + errorBuffer.toString();
|
||||
}
|
||||
if (ret.length() > 0 && logBuffer.length() > 0) ret += '\n';
|
||||
if (logBuffer.length() > 0) {
|
||||
ret += "d:\n" + logBuffer.toString();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package info.nightscout.androidaps.plugins.aps.logger
|
||||
|
||||
import info.nightscout.androidaps.db.StaticInjector
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import org.mozilla.javascript.ScriptableObject
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("unused", "FunctionName")
|
||||
class LoggerCallback : ScriptableObject() {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
|
||||
override fun getClassName(): String = "LoggerCallback"
|
||||
|
||||
fun jsConstructor() {
|
||||
//empty constructor on JS site; could work as setter
|
||||
}
|
||||
|
||||
fun jsFunction_log(obj1: Any) {
|
||||
aapsLogger.debug(LTag.APS, obj1.toString().trim { it <= ' ' })
|
||||
logBuffer.append(obj1.toString())
|
||||
}
|
||||
|
||||
fun jsFunction_error(obj1: Any) {
|
||||
aapsLogger.error(LTag.APS, obj1.toString().trim { it <= ' ' })
|
||||
errorBuffer.append(obj1.toString())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private var errorBuffer = StringBuffer()
|
||||
private var logBuffer = StringBuffer()
|
||||
val scriptDebug: String
|
||||
get() {
|
||||
var ret = ""
|
||||
if (errorBuffer.isNotEmpty()) {
|
||||
ret += """
|
||||
e:
|
||||
$errorBuffer
|
||||
""".trimIndent()
|
||||
}
|
||||
if (ret.isNotEmpty() && logBuffer.isNotEmpty()) ret += '\n'
|
||||
if (logBuffer.isNotEmpty()) {
|
||||
ret += """
|
||||
d:
|
||||
$logBuffer
|
||||
""".trimIndent()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
//empty constructor needed for Rhino
|
||||
errorBuffer = StringBuffer()
|
||||
logBuffer = StringBuffer()
|
||||
@Suppress("DEPRECATION")
|
||||
StaticInjector.Companion.getInstance().androidInjector().inject(this)
|
||||
}
|
||||
}
|
|
@ -15,11 +15,11 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
|||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoopFragment : DaggerFragment() {
|
||||
|
|
|
@ -1,880 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.loop;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.TaskStackBuilder;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Lazy;
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.BuildConfig;
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainActivity;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity;
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue;
|
||||
import info.nightscout.androidaps.db.CareportalEvent;
|
||||
import info.nightscout.androidaps.db.Source;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange;
|
||||
import info.nightscout.androidaps.events.EventNewBG;
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.interfaces.PumpDescription;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
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.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.queue.commands.Command;
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import info.nightscout.androidaps.utils.HardLimits;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
@Singleton
|
||||
public class LoopPlugin extends PluginBase implements LoopInterface {
|
||||
private final HasAndroidInjector injector;
|
||||
private final SP sp;
|
||||
private final RxBusWrapper rxBus;
|
||||
private final AapsSchedulers aapsSchedulers;
|
||||
private final ConstraintChecker constraintChecker;
|
||||
private final ResourceHelper resourceHelper;
|
||||
private final ProfileFunction profileFunction;
|
||||
private final Context context;
|
||||
private final CommandQueueProvider commandQueue;
|
||||
private final ActivePluginProvider activePlugin;
|
||||
private final TreatmentsPlugin treatmentsPlugin;
|
||||
private final VirtualPumpPlugin virtualPumpPlugin;
|
||||
private final Lazy<ActionStringHandler> actionStringHandler;
|
||||
private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||
private final ReceiverStatusStore receiverStatusStore;
|
||||
private final FabricPrivacy fabricPrivacy;
|
||||
private final NSUpload nsUpload;
|
||||
private final HardLimits hardLimits;
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private static final String CHANNEL_ID = "AndroidAPS-Openloop";
|
||||
|
||||
private long lastBgTriggeredRun = 0;
|
||||
|
||||
private long loopSuspendedTill; // end of manual loop suspend
|
||||
private boolean isSuperBolus;
|
||||
private boolean isDisconnected;
|
||||
|
||||
private long carbsSuggestionsSuspendedUntil = 0;
|
||||
private int prevCarbsreq = 0;
|
||||
|
||||
@Nullable private LastRun lastRun = null;
|
||||
|
||||
@Nullable @Override public LastRun getLastRun() {
|
||||
return lastRun;
|
||||
}
|
||||
|
||||
@Override public void setLastRun(@Nullable LastRun lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public LoopPlugin(
|
||||
HasAndroidInjector injector,
|
||||
AAPSLogger aapsLogger,
|
||||
AapsSchedulers aapsSchedulers,
|
||||
RxBusWrapper rxBus,
|
||||
SP sp,
|
||||
Config config,
|
||||
ConstraintChecker constraintChecker,
|
||||
ResourceHelper resourceHelper,
|
||||
ProfileFunction profileFunction,
|
||||
Context context,
|
||||
CommandQueueProvider commandQueue,
|
||||
ActivePluginProvider activePlugin,
|
||||
TreatmentsPlugin treatmentsPlugin,
|
||||
VirtualPumpPlugin virtualPumpPlugin,
|
||||
Lazy<ActionStringHandler> actionStringHandler, // TODO Adrian use RxBus instead of Lazy
|
||||
IobCobCalculatorPlugin iobCobCalculatorPlugin,
|
||||
ReceiverStatusStore receiverStatusStore,
|
||||
FabricPrivacy fabricPrivacy,
|
||||
NSUpload nsUpload,
|
||||
HardLimits hardLimits
|
||||
) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.LOOP)
|
||||
.fragmentClass(LoopFragment.class.getName())
|
||||
.pluginIcon(R.drawable.ic_loop_closed_white)
|
||||
.pluginName(R.string.loop)
|
||||
.shortName(R.string.loop_shortname)
|
||||
.preferencesId(R.xml.pref_loop)
|
||||
.enableByDefault(config.getAPS())
|
||||
.description(R.string.description_loop),
|
||||
aapsLogger, resourceHelper, injector
|
||||
);
|
||||
this.injector = injector;
|
||||
this.aapsSchedulers = aapsSchedulers;
|
||||
this.sp = sp;
|
||||
this.rxBus = rxBus;
|
||||
this.constraintChecker = constraintChecker;
|
||||
this.resourceHelper = resourceHelper;
|
||||
this.profileFunction = profileFunction;
|
||||
this.context = context;
|
||||
this.activePlugin = activePlugin;
|
||||
this.commandQueue = commandQueue;
|
||||
this.treatmentsPlugin = treatmentsPlugin;
|
||||
this.virtualPumpPlugin = virtualPumpPlugin;
|
||||
this.actionStringHandler = actionStringHandler;
|
||||
this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
|
||||
this.receiverStatusStore = receiverStatusStore;
|
||||
this.fabricPrivacy = fabricPrivacy;
|
||||
this.nsUpload = nsUpload;
|
||||
this.hardLimits = hardLimits;
|
||||
|
||||
loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L);
|
||||
isSuperBolus = sp.getBoolean("isSuperBolus", false);
|
||||
isDisconnected = sp.getBoolean("isDisconnected", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
createNotificationChannel();
|
||||
super.onStart();
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTempTargetChange.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> invoke("EventTempTargetChange", true), fabricPrivacy::logException)
|
||||
);
|
||||
/*
|
||||
This method is triggered once autosens calculation has completed, so the LoopPlugin
|
||||
has current data to work with. However, autosens calculation can be triggered by multiple
|
||||
sources and currently only a new BG should trigger a loop run. Hence we return early if
|
||||
the event causing the calculation is not EventNewBg.
|
||||
<p>
|
||||
*/
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
// Autosens calculation not triggered by a new BG
|
||||
if (!(event.getCause() instanceof EventNewBG)) return;
|
||||
|
||||
GlucoseValue glucoseValue = iobCobCalculatorPlugin.actualBg();
|
||||
// BG outdated
|
||||
if (glucoseValue == null) return;
|
||||
// already looped with that value
|
||||
if (glucoseValue.getTimestamp() <= lastBgTriggeredRun) return;
|
||||
|
||||
lastBgTriggeredRun = glucoseValue.getTimestamp();
|
||||
invoke("AutosenseCalculation for " + glucoseValue, true);
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
NotificationManager mNotificationManager =
|
||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
@SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
|
||||
CHANNEL_ID,
|
||||
NotificationManager.IMPORTANCE_HIGH);
|
||||
mNotificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
disposable.clear();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specialEnableCondition() {
|
||||
try {
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
return pump.getPumpDescription().isTempBasalCapable;
|
||||
} catch (Exception ignored) {
|
||||
// may fail during initialization
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void suspendTo(long endTime) {
|
||||
loopSuspendedTill = endTime;
|
||||
isSuperBolus = false;
|
||||
isDisconnected = false;
|
||||
sp.putLong("loopSuspendedTill", loopSuspendedTill);
|
||||
sp.putBoolean("isSuperBolus", isSuperBolus);
|
||||
sp.putBoolean("isDisconnected", isDisconnected);
|
||||
}
|
||||
|
||||
public void superBolusTo(long endTime) {
|
||||
loopSuspendedTill = endTime;
|
||||
isSuperBolus = true;
|
||||
isDisconnected = false;
|
||||
sp.putLong("loopSuspendedTill", loopSuspendedTill);
|
||||
sp.putBoolean("isSuperBolus", isSuperBolus);
|
||||
sp.putBoolean("isDisconnected", isDisconnected);
|
||||
}
|
||||
|
||||
private void disconnectTo(long endTime) {
|
||||
loopSuspendedTill = endTime;
|
||||
isSuperBolus = false;
|
||||
isDisconnected = true;
|
||||
sp.putLong("loopSuspendedTill", loopSuspendedTill);
|
||||
sp.putBoolean("isSuperBolus", isSuperBolus);
|
||||
sp.putBoolean("isDisconnected", isDisconnected);
|
||||
}
|
||||
|
||||
public int minutesToEndOfSuspend() {
|
||||
if (loopSuspendedTill == 0)
|
||||
return 0;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long msecDiff = loopSuspendedTill - now;
|
||||
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) (msecDiff / 60d / 1000d);
|
||||
}
|
||||
|
||||
public boolean isSuspended() {
|
||||
if (loopSuspendedTill == 0)
|
||||
return false;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isLGS() {
|
||||
Constraint<Boolean> closedLoopEnabled = constraintChecker.isClosedLoopAllowed();
|
||||
Double MaxIOBallowed = constraintChecker.getMaxIOBAllowed().value();
|
||||
String APSmode = sp.getString(R.string.key_aps_mode, "open");
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
boolean isLGS = false;
|
||||
|
||||
if (!isSuspended() && !pump.isSuspended())
|
||||
if (closedLoopEnabled.value())
|
||||
if ((MaxIOBallowed.equals(hardLimits.getMAXIOB_LGS())) || (APSmode.equals("lgs")))
|
||||
isLGS = true;
|
||||
|
||||
return isLGS;
|
||||
}
|
||||
|
||||
public boolean isSuperBolus() {
|
||||
if (loopSuspendedTill == 0)
|
||||
return false;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L);
|
||||
return false;
|
||||
}
|
||||
|
||||
return isSuperBolus;
|
||||
}
|
||||
|
||||
public boolean isDisconnected() {
|
||||
if (loopSuspendedTill == 0)
|
||||
return false;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L);
|
||||
return false;
|
||||
}
|
||||
return isDisconnected;
|
||||
}
|
||||
|
||||
public boolean treatmentTimethreshold(int duartionMinutes) {
|
||||
long threshold = System.currentTimeMillis() + (duartionMinutes * 60 * 1000);
|
||||
boolean bool = false;
|
||||
if (treatmentsPlugin.getLastBolusTime() > threshold || treatmentsPlugin.getLastCarbTime() > threshold)
|
||||
bool = true;
|
||||
|
||||
return bool;
|
||||
}
|
||||
|
||||
public synchronized void invoke(String initiator, boolean allowNotification) {
|
||||
invoke(initiator, allowNotification, false);
|
||||
}
|
||||
|
||||
public synchronized void invoke(String initiator, boolean allowNotification, boolean tempBasalFallback) {
|
||||
try {
|
||||
getAapsLogger().debug(LTag.APS, "invoke from " + initiator);
|
||||
Constraint<Boolean> loopEnabled = constraintChecker.isLoopInvocationAllowed();
|
||||
|
||||
if (!loopEnabled.value()) {
|
||||
String message = resourceHelper.gs(R.string.loopdisabled) + "\n" + loopEnabled.getReasons(getAapsLogger());
|
||||
getAapsLogger().debug(LTag.APS, message);
|
||||
rxBus.send(new EventLoopSetLastRunGui(message));
|
||||
return;
|
||||
}
|
||||
final PumpInterface pump = activePlugin.getActivePump();
|
||||
APSResult result = null;
|
||||
|
||||
if (!isEnabled(PluginType.LOOP))
|
||||
return;
|
||||
|
||||
Profile profile = profileFunction.getProfile();
|
||||
|
||||
if (profile == null || !profileFunction.isProfileValid("Loop")) {
|
||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if pump info is loaded
|
||||
if (pump.getBaseBasalRate() < 0.01d) return;
|
||||
|
||||
APSInterface usedAPS = activePlugin.getActiveAPS();
|
||||
if (((PluginBase) usedAPS).isEnabled(PluginType.APS)) {
|
||||
usedAPS.invoke(initiator, tempBasalFallback);
|
||||
result = usedAPS.getLastAPSResult();
|
||||
}
|
||||
|
||||
// Check if we have any result
|
||||
if (result == null) {
|
||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare for pumps using % basals
|
||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
||||
result.setUsePercent(true);
|
||||
}
|
||||
result.setPercent((int) (result.getRate() / profile.getBasal() * 100));
|
||||
|
||||
// check rate for constraints
|
||||
final APSResult resultAfterConstraints = result.newAndClone(injector);
|
||||
resultAfterConstraints.setRateConstraint(new Constraint<>(resultAfterConstraints.getRate()));
|
||||
resultAfterConstraints.setRate(constraintChecker.applyBasalConstraints(resultAfterConstraints.getRateConstraint(), profile).value());
|
||||
|
||||
resultAfterConstraints.setPercentConstraint(new Constraint<>(resultAfterConstraints.getPercent()));
|
||||
resultAfterConstraints.setPercent(constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.getPercentConstraint(), profile).value());
|
||||
|
||||
resultAfterConstraints.setSmbConstraint(new Constraint<>(resultAfterConstraints.getSmb()));
|
||||
resultAfterConstraints.setSmb(constraintChecker.applyBolusConstraints(resultAfterConstraints.getSmbConstraint()).value());
|
||||
|
||||
// safety check for multiple SMBs
|
||||
long lastBolusTime = treatmentsPlugin.getLastBolusTime();
|
||||
if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
|
||||
getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
|
||||
resultAfterConstraints.setSmb(0);
|
||||
}
|
||||
|
||||
if (lastRun != null && lastRun.getConstraintsProcessed() != null) {
|
||||
prevCarbsreq = lastRun.getConstraintsProcessed().getCarbsReq();
|
||||
}
|
||||
|
||||
if (lastRun == null) lastRun = new LastRun();
|
||||
lastRun.setRequest(result);
|
||||
lastRun.setConstraintsProcessed(resultAfterConstraints);
|
||||
lastRun.setLastAPSRun(DateUtil.now());
|
||||
lastRun.setSource(((PluginBase) usedAPS).getName());
|
||||
lastRun.setTbrSetByPump(null);
|
||||
lastRun.setSmbSetByPump(null);
|
||||
lastRun.setLastTBREnact(0);
|
||||
lastRun.setLastTBRRequest(0);
|
||||
lastRun.setLastSMBEnact(0);
|
||||
lastRun.setLastSMBRequest(0);
|
||||
|
||||
nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump(), receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
|
||||
|
||||
if (isSuspended()) {
|
||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended));
|
||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pump.isSuspended()) {
|
||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended));
|
||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended)));
|
||||
return;
|
||||
}
|
||||
|
||||
Constraint<Boolean> closedLoopEnabled = constraintChecker.isClosedLoopAllowed();
|
||||
|
||||
if (closedLoopEnabled.value()) {
|
||||
if (allowNotification) {
|
||||
if (resultAfterConstraints.isCarbsRequired()
|
||||
&& resultAfterConstraints.getCarbsReq() >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0)
|
||||
&& carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) {
|
||||
|
||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
Notification carbreqlocal = new Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.getCarbsRequiredText(), Notification.NORMAL);
|
||||
rxBus.send(new EventNewNotification(carbreqlocal));
|
||||
}
|
||||
if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) {
|
||||
nsUpload.uploadError(resultAfterConstraints.getCarbsRequiredText());
|
||||
}
|
||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
Intent intentAction5m = new Intent(context, CarbSuggestionReceiver.class);
|
||||
intentAction5m.putExtra("ignoreDuration", 5);
|
||||
PendingIntent pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
NotificationCompat.Action actionIgnore5m = new
|
||||
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m);
|
||||
|
||||
Intent intentAction15m = new Intent(context, CarbSuggestionReceiver.class);
|
||||
intentAction15m.putExtra("ignoreDuration", 15);
|
||||
PendingIntent pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
NotificationCompat.Action actionIgnore15m = new
|
||||
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m);
|
||||
|
||||
Intent intentAction30m = new Intent(context, CarbSuggestionReceiver.class);
|
||||
intentAction30m.putExtra("ignoreDuration", 30);
|
||||
PendingIntent pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
NotificationCompat.Action actionIgnore30m = new
|
||||
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
|
||||
builder.setSmallIcon(R.drawable.notif_icon)
|
||||
.setContentTitle(resourceHelper.gs(R.string.carbssuggestion))
|
||||
.setContentText(resultAfterConstraints.getCarbsRequiredText())
|
||||
.setAutoCancel(true)
|
||||
.setPriority(Notification.IMPORTANCE_HIGH)
|
||||
.setCategory(Notification.CATEGORY_ALARM)
|
||||
.addAction(actionIgnore5m)
|
||||
.addAction(actionIgnore15m)
|
||||
.addAction(actionIgnore30m)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
|
||||
|
||||
NotificationManager mNotificationManager =
|
||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(Constants.notificationID, builder.build());
|
||||
rxBus.send(new EventNewOpenLoopNotification());
|
||||
|
||||
//only send to wear if Native notifications are turned off
|
||||
if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
// Send to Wear
|
||||
actionStringHandler.get().handleInitiate("changeRequest");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
//If carbs were required previously, but are no longer needed, dismiss notifications
|
||||
if (prevCarbsreq > 0) {
|
||||
dismissSuggestion();
|
||||
rxBus.send(new EventDismissNotification(Notification.CARBS_REQUIRED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resultAfterConstraints.isChangeRequested()
|
||||
&& !commandQueue.bolusInQueue()
|
||||
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
||||
final PumpEnactResult waiting = new PumpEnactResult(getInjector());
|
||||
waiting.queued = true;
|
||||
if (resultAfterConstraints.getTempBasalRequested())
|
||||
lastRun.setTbrSetByPump(waiting);
|
||||
if (resultAfterConstraints.getBolusRequested())
|
||||
lastRun.setSmbSetByPump(waiting);
|
||||
rxBus.send(new EventLoopUpdateGui());
|
||||
fabricPrivacy.logCustom("APSRequest");
|
||||
applyTBRRequest(resultAfterConstraints, profile, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (result.enacted || result.success) {
|
||||
lastRun.setTbrSetByPump(result);
|
||||
lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
|
||||
lastRun.setLastTBREnact(DateUtil.now());
|
||||
rxBus.send(new EventLoopUpdateGui());
|
||||
applySMBRequest(resultAfterConstraints, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Callback is only called if a bolus was actually requested
|
||||
if (result.enacted || result.success) {
|
||||
lastRun.setSmbSetByPump(result);
|
||||
lastRun.setLastSMBRequest(lastRun.getLastAPSRun());
|
||||
lastRun.setLastSMBEnact(DateUtil.now());
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
SystemClock.sleep(1000);
|
||||
invoke("tempBasalFallback", allowNotification, true);
|
||||
}).start();
|
||||
}
|
||||
rxBus.send(new EventLoopUpdateGui());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
lastRun.setTbrSetByPump(result);
|
||||
lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
|
||||
}
|
||||
rxBus.send(new EventLoopUpdateGui());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
lastRun.setTbrSetByPump(null);
|
||||
lastRun.setSmbSetByPump(null);
|
||||
}
|
||||
} else {
|
||||
if (resultAfterConstraints.isChangeRequested() && allowNotification) {
|
||||
NotificationCompat.Builder builder =
|
||||
new NotificationCompat.Builder(context, CHANNEL_ID);
|
||||
builder.setSmallIcon(R.drawable.notif_icon)
|
||||
.setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion))
|
||||
.setContentText(resultAfterConstraints.toString())
|
||||
.setAutoCancel(true)
|
||||
.setPriority(Notification.IMPORTANCE_HIGH)
|
||||
.setCategory(Notification.CATEGORY_ALARM)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
|
||||
if (sp.getBoolean("wearcontrol", false)) {
|
||||
builder.setLocalOnly(true);
|
||||
}
|
||||
presentSuggestion(builder);
|
||||
} else if (allowNotification) {
|
||||
dismissSuggestion();
|
||||
}
|
||||
}
|
||||
|
||||
rxBus.send(new EventLoopUpdateGui());
|
||||
} finally {
|
||||
getAapsLogger().debug(LTag.APS, "invoke end");
|
||||
}
|
||||
}
|
||||
|
||||
public void disableCarbSuggestions(int durationMinutes) {
|
||||
carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + (durationMinutes * 60 * 1000);
|
||||
dismissSuggestion();
|
||||
}
|
||||
|
||||
private void presentSuggestion(NotificationCompat.Builder builder) {
|
||||
// Creates an explicit intent for an Activity in your app
|
||||
Intent resultIntent = new Intent(context, MainActivity.class);
|
||||
|
||||
// The stack builder object will contain an artificial back stack for the
|
||||
// started Activity.
|
||||
// This ensures that navigating backward from the Activity leads out of
|
||||
// your application to the Home screen.
|
||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
|
||||
stackBuilder.addParentStack(MainActivity.class);
|
||||
// Adds the Intent that starts the Activity to the top of the stack
|
||||
stackBuilder.addNextIntent(resultIntent);
|
||||
PendingIntent resultPendingIntent =
|
||||
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
builder.setContentIntent(resultPendingIntent);
|
||||
builder.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
|
||||
NotificationManager mNotificationManager =
|
||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(Constants.notificationID, builder.build());
|
||||
rxBus.send(new EventNewOpenLoopNotification());
|
||||
|
||||
// Send to Wear
|
||||
actionStringHandler.get().handleInitiate("changeRequest");
|
||||
}
|
||||
|
||||
private void dismissSuggestion() {
|
||||
// dismiss notifications
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(Constants.notificationID);
|
||||
actionStringHandler.get().handleInitiate("cancelChangeRequest");
|
||||
}
|
||||
|
||||
public void acceptChangeRequest() {
|
||||
Profile profile = profileFunction.getProfile();
|
||||
final LoopPlugin lp = this;
|
||||
applyTBRRequest(lastRun.getConstraintsProcessed(), profile, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (result.enacted) {
|
||||
lastRun.setTbrSetByPump(result);
|
||||
lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
|
||||
lastRun.setLastTBREnact(DateUtil.now());
|
||||
lastRun.setLastOpenModeAccept(DateUtil.now());
|
||||
nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump(), receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
|
||||
sp.incInt(R.string.key_ObjectivesmanualEnacts);
|
||||
}
|
||||
rxBus.send(new EventAcceptOpenLoopChange());
|
||||
}
|
||||
});
|
||||
fabricPrivacy.logCustom("AcceptTemp");
|
||||
}
|
||||
|
||||
/**
|
||||
* expect absolute request and allow both absolute and percent response based on pump capabilities
|
||||
* TODO: update pump drivers to support APS request in %
|
||||
*/
|
||||
|
||||
private void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
|
||||
|
||||
if (!request.getTempBasalRequested()) {
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested))).run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
|
||||
if (!pump.isInitialized()) {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpNotInitialized));
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (pump.isSuspended()) {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpsuspended));
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + request.toString());
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(now);
|
||||
if (request.getUsePercent() && allowPercentage()) {
|
||||
if (request.getPercent() == 100 && request.getDuration() == 0) {
|
||||
if (activeTemp != null) {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
|
||||
commandQueue.cancelTempBasal(false, callback);
|
||||
} else {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent()).duration(0)
|
||||
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
|
||||
}
|
||||
}
|
||||
} else if (activeTemp != null
|
||||
&& activeTemp.getPlannedRemainingMinutes() > 5
|
||||
&& request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
|
||||
&& request.getPercent() == activeTemp.percentRate) {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent())
|
||||
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
|
||||
.comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
|
||||
}
|
||||
} else {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: tempBasalPercent()");
|
||||
commandQueue.tempBasalPercent(request.getPercent(), request.getDuration(), false, profile, callback);
|
||||
}
|
||||
} else {
|
||||
if ((request.getRate() == 0 && request.getDuration() == 0) || Math.abs(request.getRate() - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
|
||||
if (activeTemp != null) {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
|
||||
commandQueue.cancelTempBasal(false, callback);
|
||||
} else {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).absolute(request.getRate()).duration(0)
|
||||
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
|
||||
}
|
||||
}
|
||||
} else if (activeTemp != null
|
||||
&& activeTemp.getPlannedRemainingMinutes() > 5
|
||||
&& request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
|
||||
&& Math.abs(request.getRate() - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
|
||||
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
|
||||
.comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
|
||||
}
|
||||
} else {
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()");
|
||||
commandQueue.tempBasalAbsolute(request.getRate(), request.getDuration(), false, profile, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applySMBRequest(APSResult request, Callback callback) {
|
||||
if (!request.getBolusRequested()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
|
||||
long lastBolusTime = treatmentsPlugin.getLastBolusTime();
|
||||
if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
|
||||
getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector())
|
||||
.comment(resourceHelper.gs(R.string.smb_frequency_exceeded))
|
||||
.enacted(false).success(false)).run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pump.isInitialized()) {
|
||||
getAapsLogger().debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpNotInitialized));
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (pump.isSuspended()) {
|
||||
getAapsLogger().debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpsuspended));
|
||||
if (callback != null) {
|
||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
getAapsLogger().debug(LTag.APS, "applySMBRequest: " + request.toString());
|
||||
|
||||
// deliver SMB
|
||||
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
|
||||
detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.getLastBolusTime();
|
||||
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
|
||||
detailedBolusInfo.insulin = request.getSmb();
|
||||
detailedBolusInfo.isSMB = true;
|
||||
detailedBolusInfo.source = Source.USER;
|
||||
detailedBolusInfo.deliverAt = request.getDeliverAt();
|
||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: bolus()");
|
||||
commandQueue.bolus(detailedBolusInfo, callback);
|
||||
}
|
||||
|
||||
private boolean allowPercentage() {
|
||||
return virtualPumpPlugin.isEnabled(PluginType.PUMP);
|
||||
}
|
||||
|
||||
public void disconnectPump(int durationInMinutes, Profile profile) {
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
|
||||
disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L);
|
||||
|
||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
commandQueue.tempBasalAbsolute(0, durationInMinutes, true, profile, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
||||
i.putExtra("soundid", R.raw.boluserror);
|
||||
i.putExtra("status", result.comment);
|
||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
||||
i.putExtra("soundid", R.raw.boluserror);
|
||||
i.putExtra("status", result.comment);
|
||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (pump.getPumpDescription().isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBoluslInProgress()) {
|
||||
commandQueue.cancelExtended(new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
||||
i.putExtra("soundid", R.raw.boluserror);
|
||||
i.putExtra("status", result.comment);
|
||||
i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror));
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
createOfflineEvent(durationInMinutes);
|
||||
}
|
||||
|
||||
public void suspendLoop(int durationInMinutes) {
|
||||
suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000);
|
||||
commandQueue.cancelTempBasal(true, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
||||
i.putExtra("soundid", R.raw.boluserror);
|
||||
i.putExtra("status", result.comment);
|
||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
createOfflineEvent(durationInMinutes);
|
||||
}
|
||||
|
||||
public void createOfflineEvent(int durationInMinutes) {
|
||||
JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("eventType", CareportalEvent.OPENAPSOFFLINE);
|
||||
data.put("duration", durationInMinutes);
|
||||
} catch (JSONException e) {
|
||||
getAapsLogger().error("Unhandled exception", e);
|
||||
}
|
||||
CareportalEvent event = new CareportalEvent(getInjector());
|
||||
event.date = DateUtil.now();
|
||||
event.source = Source.USER;
|
||||
event.eventType = CareportalEvent.OPENAPSOFFLINE;
|
||||
event.json = data.toString();
|
||||
MainApp.getDbHelper().createOrUpdate(event);
|
||||
nsUpload.uploadOpenAPSOffline(event);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,674 @@
|
|||
package info.nightscout.androidaps.plugins.aps.loop
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.TaskStackBuilder
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.SystemClock
|
||||
import androidx.core.app.NotificationCompat
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.*
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.db.CareportalEvent
|
||||
import info.nightscout.androidaps.db.Source
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||
import info.nightscout.androidaps.events.EventNewBG
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface.LastRun
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
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.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.queue.commands.Command
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.abs
|
||||
|
||||
@Singleton
|
||||
open class LoopPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger?,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val sp: SP,
|
||||
config: Config,
|
||||
private val constraintChecker: ConstraintChecker,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val context: Context,
|
||||
private val commandQueue: CommandQueueProvider,
|
||||
private val activePlugin: ActivePluginProvider,
|
||||
private val treatmentsPlugin: TreatmentsPlugin,
|
||||
private val virtualPumpPlugin: VirtualPumpPlugin,
|
||||
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||
private val receiverStatusStore: ReceiverStatusStore,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val nsUpload: NSUpload,
|
||||
private val hardLimits: HardLimits
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.LOOP)
|
||||
.fragmentClass(LoopFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_loop_closed_white)
|
||||
.pluginName(R.string.loop)
|
||||
.shortName(R.string.loop_shortname)
|
||||
.preferencesId(R.xml.pref_loop)
|
||||
.enableByDefault(config.APS)
|
||||
.description(R.string.description_loop),
|
||||
aapsLogger!!, resourceHelper, injector
|
||||
), LoopInterface {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private var lastBgTriggeredRun: Long = 0
|
||||
private var carbsSuggestionsSuspendedUntil: Long = 0
|
||||
private var prevCarbsreq = 0
|
||||
override var lastRun: LastRun? = null
|
||||
override fun onStart() {
|
||||
createNotificationChannel()
|
||||
super.onStart()
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTempTargetChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ invoke("EventTempTargetChange", true) }, fabricPrivacy::logException)
|
||||
)
|
||||
/*
|
||||
This method is triggered once autosens calculation has completed, so the LoopPlugin
|
||||
has current data to work with. However, autosens calculation can be triggered by multiple
|
||||
sources and currently only a new BG should trigger a loop run. Hence we return early if
|
||||
the event causing the calculation is not EventNewBg.
|
||||
<p>
|
||||
*/
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventAutosensCalculationFinished ->
|
||||
// Autosens calculation not triggered by a new BG
|
||||
if (event.cause !is EventNewBG) return@subscribe
|
||||
val glucoseValue = iobCobCalculatorPlugin.actualBg() ?: return@subscribe
|
||||
// BG outdated
|
||||
// already looped with that value
|
||||
if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe
|
||||
lastBgTriggeredRun = glucoseValue.timestamp
|
||||
invoke("AutosenseCalculation for $glucoseValue", true)
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
}
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
@SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID,
|
||||
CHANNEL_ID,
|
||||
NotificationManager.IMPORTANCE_HIGH)
|
||||
mNotificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
disposable.clear()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun specialEnableCondition(): Boolean {
|
||||
return try {
|
||||
val pump = activePlugin.activePump
|
||||
pump.pumpDescription.isTempBasalCapable
|
||||
} catch (ignored: Exception) {
|
||||
// may fail during initialization
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun suspendTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", false)
|
||||
sp.putBoolean("isDisconnected", false)
|
||||
}
|
||||
|
||||
fun superBolusTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", true)
|
||||
sp.putBoolean("isDisconnected", false)
|
||||
}
|
||||
|
||||
private fun disconnectTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", false)
|
||||
sp.putBoolean("isDisconnected", true)
|
||||
}
|
||||
|
||||
fun minutesToEndOfSuspend(): Int {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return 0
|
||||
val now = System.currentTimeMillis()
|
||||
val millisDiff = loopSuspendedTill - now
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return 0
|
||||
}
|
||||
return (millisDiff / 60.0 / 1000.0).toInt()
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
val isSuspended: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
val isLGS: Boolean
|
||||
get() {
|
||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||
val maxIobAllowed = constraintChecker.getMaxIOBAllowed().value()
|
||||
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||
val pump = activePlugin.activePump
|
||||
var isLGS = false
|
||||
if (!isSuspended && !pump.isSuspended()) if (closedLoopEnabled.value()) if (maxIobAllowed == hardLimits.MAXIOB_LGS || apsMode == "lgs") isLGS = true
|
||||
return isLGS
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
val isSuperBolus: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return sp.getBoolean("isSuperBolus", false)
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
val isDisconnected: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return sp.getBoolean("isDisconnected", false)
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun treatmentTimeThreshold(durationMinutes: Int): Boolean {
|
||||
val threshold = System.currentTimeMillis() + durationMinutes * 60 * 1000
|
||||
var bool = false
|
||||
if (treatmentsPlugin.lastBolusTime > threshold || treatmentsPlugin.lastCarbTime > threshold) bool = true
|
||||
return bool
|
||||
}
|
||||
|
||||
@Synchronized operator fun invoke(initiator: String, allowNotification: Boolean) {
|
||||
invoke(initiator, allowNotification, false)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
operator fun invoke(initiator: String, allowNotification: Boolean, tempBasalFallback: Boolean) {
|
||||
try {
|
||||
aapsLogger.debug(LTag.APS, "invoke from $initiator")
|
||||
val loopEnabled = constraintChecker.isLoopInvocationAllowed()
|
||||
if (!loopEnabled.value()) {
|
||||
val message = """
|
||||
${resourceHelper.gs(R.string.loopdisabled)}
|
||||
${loopEnabled.getReasons(aapsLogger)}
|
||||
""".trimIndent()
|
||||
aapsLogger.debug(LTag.APS, message)
|
||||
rxBus.send(EventLoopSetLastRunGui(message))
|
||||
return
|
||||
}
|
||||
val pump = activePlugin.activePump
|
||||
var apsResult: APSResult? = null
|
||||
if (!isEnabled(PluginType.LOOP)) return
|
||||
val profile = profileFunction.getProfile()
|
||||
if (profile == null || !profileFunction.isProfileValid("Loop")) {
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
|
||||
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)))
|
||||
return
|
||||
}
|
||||
|
||||
// Check if pump info is loaded
|
||||
if (pump.baseBasalRate < 0.01) return
|
||||
val usedAPS = activePlugin.activeAPS
|
||||
if ((usedAPS as PluginBase).isEnabled(PluginType.APS)) {
|
||||
usedAPS.invoke(initiator, tempBasalFallback)
|
||||
apsResult = usedAPS.lastAPSResult
|
||||
}
|
||||
|
||||
// Check if we have any result
|
||||
if (apsResult == null) {
|
||||
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)))
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare for pumps using % basals
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
||||
apsResult.usePercent = true
|
||||
}
|
||||
apsResult.percent = (apsResult.rate / profile.basal * 100).toInt()
|
||||
|
||||
// check rate for constraints
|
||||
val resultAfterConstraints = apsResult.newAndClone(injector)
|
||||
resultAfterConstraints.rateConstraint = Constraint(resultAfterConstraints.rate)
|
||||
resultAfterConstraints.rate = constraintChecker.applyBasalConstraints(resultAfterConstraints.rateConstraint!!, profile).value()
|
||||
resultAfterConstraints.percentConstraint = Constraint(resultAfterConstraints.percent)
|
||||
resultAfterConstraints.percent = constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.percentConstraint!!, profile).value()
|
||||
resultAfterConstraints.smbConstraint = Constraint(resultAfterConstraints.smb)
|
||||
resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint!!).value()
|
||||
|
||||
// safety check for multiple SMBs
|
||||
val lastBolusTime = treatmentsPlugin.lastBolusTime
|
||||
if (lastBolusTime != 0L && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
|
||||
aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
|
||||
resultAfterConstraints.smb = 0.0
|
||||
}
|
||||
if (lastRun != null && lastRun!!.constraintsProcessed != null) {
|
||||
prevCarbsreq = lastRun!!.constraintsProcessed!!.carbsReq
|
||||
}
|
||||
if (lastRun == null) lastRun = LastRun()
|
||||
lastRun!!.request = apsResult
|
||||
lastRun!!.constraintsProcessed = resultAfterConstraints
|
||||
lastRun!!.lastAPSRun = DateUtil.now()
|
||||
lastRun!!.source = (usedAPS as PluginBase).name
|
||||
lastRun!!.tbrSetByPump = null
|
||||
lastRun!!.smbSetByPump = null
|
||||
lastRun!!.lastTBREnact = 0
|
||||
lastRun!!.lastTBRRequest = 0
|
||||
lastRun!!.lastSMBEnact = 0
|
||||
lastRun!!.lastSMBRequest = 0
|
||||
nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)
|
||||
if (isSuspended) {
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended))
|
||||
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)))
|
||||
return
|
||||
}
|
||||
if (pump.isSuspended()) {
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended))
|
||||
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended)))
|
||||
return
|
||||
}
|
||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||
if (closedLoopEnabled.value()) {
|
||||
if (allowNotification) {
|
||||
if (resultAfterConstraints.isCarbsRequired
|
||||
&& resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)) {
|
||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
val carbReqLocal = Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.carbsRequiredText, Notification.NORMAL)
|
||||
rxBus.send(EventNewNotification(carbReqLocal))
|
||||
}
|
||||
if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) {
|
||||
nsUpload.uploadError(resultAfterConstraints.carbsRequiredText)
|
||||
}
|
||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
val intentAction5m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||
intentAction5m.putExtra("ignoreDuration", 5)
|
||||
val pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val actionIgnore5m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m)
|
||||
val intentAction15m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||
intentAction15m.putExtra("ignoreDuration", 15)
|
||||
val pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val actionIgnore15m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m)
|
||||
val intentAction30m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||
intentAction30m.putExtra("ignoreDuration", 30)
|
||||
val pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val actionIgnore30m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m)
|
||||
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
builder.setSmallIcon(R.drawable.notif_icon)
|
||||
.setContentTitle(resourceHelper.gs(R.string.carbssuggestion))
|
||||
.setContentText(resultAfterConstraints.carbsRequiredText)
|
||||
.setAutoCancel(true)
|
||||
.setPriority(Notification.IMPORTANCE_HIGH)
|
||||
.setCategory(Notification.CATEGORY_ALARM)
|
||||
.addAction(actionIgnore5m)
|
||||
.addAction(actionIgnore15m)
|
||||
.addAction(actionIgnore30m)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
||||
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(Constants.notificationID, builder.build())
|
||||
rxBus.send(EventNewOpenLoopNotification())
|
||||
|
||||
//only send to wear if Native notifications are turned off
|
||||
if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
// Send to Wear
|
||||
rxBus.send(EventWearDoAction("changeRequest"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//If carbs were required previously, but are no longer needed, dismiss notifications
|
||||
if (prevCarbsreq > 0) {
|
||||
dismissSuggestion()
|
||||
rxBus.send(EventDismissNotification(Notification.CARBS_REQUIRED))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resultAfterConstraints.isChangeRequested
|
||||
&& !commandQueue.bolusInQueue()
|
||||
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
||||
val waiting = PumpEnactResult(injector)
|
||||
waiting.queued = true
|
||||
if (resultAfterConstraints.tempBasalRequested) lastRun!!.tbrSetByPump = waiting
|
||||
if (resultAfterConstraints.bolusRequested) lastRun!!.smbSetByPump = waiting
|
||||
rxBus.send(EventLoopUpdateGui())
|
||||
fabricPrivacy.logCustom("APSRequest")
|
||||
applyTBRRequest(resultAfterConstraints, profile, object : Callback() {
|
||||
override fun run() {
|
||||
if (result.enacted || result.success) {
|
||||
lastRun!!.tbrSetByPump = result
|
||||
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
|
||||
lastRun!!.lastTBREnact = DateUtil.now()
|
||||
rxBus.send(EventLoopUpdateGui())
|
||||
applySMBRequest(resultAfterConstraints, object : Callback() {
|
||||
override fun run() {
|
||||
// Callback is only called if a bolus was actually requested
|
||||
if (result.enacted || result.success) {
|
||||
lastRun!!.smbSetByPump = result
|
||||
lastRun!!.lastSMBRequest = lastRun!!.lastAPSRun
|
||||
lastRun!!.lastSMBEnact = DateUtil.now()
|
||||
} else {
|
||||
Thread {
|
||||
SystemClock.sleep(1000)
|
||||
invoke("tempBasalFallback", allowNotification, true)
|
||||
}.start()
|
||||
}
|
||||
rxBus.send(EventLoopUpdateGui())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
lastRun!!.tbrSetByPump = result
|
||||
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
|
||||
}
|
||||
rxBus.send(EventLoopUpdateGui())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
lastRun!!.tbrSetByPump = null
|
||||
lastRun!!.smbSetByPump = null
|
||||
}
|
||||
} else {
|
||||
if (resultAfterConstraints.isChangeRequested && allowNotification) {
|
||||
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
builder.setSmallIcon(R.drawable.notif_icon)
|
||||
.setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion))
|
||||
.setContentText(resultAfterConstraints.toString())
|
||||
.setAutoCancel(true)
|
||||
.setPriority(Notification.IMPORTANCE_HIGH)
|
||||
.setCategory(Notification.CATEGORY_ALARM)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
if (sp.getBoolean(R.string.key_wear_control, false)) {
|
||||
builder.setLocalOnly(true)
|
||||
}
|
||||
presentSuggestion(builder)
|
||||
} else if (allowNotification) {
|
||||
dismissSuggestion()
|
||||
}
|
||||
}
|
||||
rxBus.send(EventLoopUpdateGui())
|
||||
} finally {
|
||||
aapsLogger.debug(LTag.APS, "invoke end")
|
||||
}
|
||||
}
|
||||
|
||||
fun disableCarbSuggestions(durationMinutes: Int) {
|
||||
carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + durationMinutes * 60 * 1000
|
||||
dismissSuggestion()
|
||||
}
|
||||
|
||||
private fun presentSuggestion(builder: NotificationCompat.Builder) {
|
||||
// Creates an explicit intent for an Activity in your app
|
||||
val resultIntent = Intent(context, MainActivity::class.java)
|
||||
|
||||
// The stack builder object will contain an artificial back stack for the
|
||||
// started Activity.
|
||||
// This ensures that navigating backward from the Activity leads out of
|
||||
// your application to the Home screen.
|
||||
val stackBuilder = TaskStackBuilder.create(context)
|
||||
stackBuilder.addParentStack(MainActivity::class.java)
|
||||
// Adds the Intent that starts the Activity to the top of the stack
|
||||
stackBuilder.addNextIntent(resultIntent)
|
||||
val resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
builder.setContentIntent(resultPendingIntent)
|
||||
builder.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
||||
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(Constants.notificationID, builder.build())
|
||||
rxBus.send(EventNewOpenLoopNotification())
|
||||
|
||||
// Send to Wear
|
||||
rxBus.send(EventWearDoAction("changeRequest"))
|
||||
}
|
||||
|
||||
private fun dismissSuggestion() {
|
||||
// dismiss notifications
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.cancel(Constants.notificationID)
|
||||
rxBus.send(EventWearDoAction("cancelChangeRequest"))
|
||||
}
|
||||
|
||||
fun acceptChangeRequest() {
|
||||
val profile = profileFunction.getProfile()
|
||||
val lp = this
|
||||
applyTBRRequest(lastRun!!.constraintsProcessed, profile, object : Callback() {
|
||||
override fun run() {
|
||||
if (result.enacted) {
|
||||
lastRun!!.tbrSetByPump = result
|
||||
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
|
||||
lastRun!!.lastTBREnact = DateUtil.now()
|
||||
lastRun!!.lastOpenModeAccept = DateUtil.now()
|
||||
nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)
|
||||
sp.incInt(R.string.key_ObjectivesmanualEnacts)
|
||||
}
|
||||
rxBus.send(EventAcceptOpenLoopChange())
|
||||
}
|
||||
})
|
||||
fabricPrivacy.logCustom("AcceptTemp")
|
||||
}
|
||||
|
||||
/**
|
||||
* expect absolute request and allow both absolute and percent response based on pump capabilities
|
||||
* TODO: update pump drivers to support APS request in %
|
||||
*/
|
||||
private fun applyTBRRequest(request: APSResult?, profile: Profile?, callback: Callback?) {
|
||||
if (!request!!.tempBasalRequested) {
|
||||
callback?.result(PumpEnactResult(injector).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested)))?.run()
|
||||
return
|
||||
}
|
||||
val pump = activePlugin.activePump
|
||||
if (!pump.isInitialized()) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
|
||||
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
|
||||
return
|
||||
}
|
||||
if (pump.isSuspended()) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpsuspended))
|
||||
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
|
||||
return
|
||||
}
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: $request")
|
||||
val now = System.currentTimeMillis()
|
||||
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(now)
|
||||
if (request.usePercent && allowPercentage()) {
|
||||
if (request.percent == 100 && request.duration == 0) {
|
||||
if (activeTemp != null) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
|
||||
commandQueue.cancelTempBasal(false, callback)
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0)
|
||||
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly)))?.run()
|
||||
}
|
||||
} else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.percentRate) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).percent(request.percent)
|
||||
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||
.comment(resourceHelper.gs(R.string.let_temp_basal_run)))?.run()
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: tempBasalPercent()")
|
||||
commandQueue.tempBasalPercent(request.percent, request.duration, false, profile!!, callback)
|
||||
}
|
||||
} else {
|
||||
if (request.rate == 0.0 && request.duration == 0 || abs(request.rate - pump.baseBasalRate) < pump.pumpDescription.basalStep) {
|
||||
if (activeTemp != null) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
|
||||
commandQueue.cancelTempBasal(false, callback)
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0)
|
||||
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly)))?.run()
|
||||
}
|
||||
} else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
|
||||
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||
.comment(resourceHelper.gs(R.string.let_temp_basal_run)))?.run()
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()")
|
||||
commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile!!, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applySMBRequest(request: APSResult, callback: Callback?) {
|
||||
if (!request.bolusRequested) {
|
||||
return
|
||||
}
|
||||
val pump = activePlugin.activePump
|
||||
val lastBolusTime = treatmentsPlugin.lastBolusTime
|
||||
if (lastBolusTime != 0L && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
|
||||
aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
|
||||
callback?.result(PumpEnactResult(injector)
|
||||
.comment(resourceHelper.gs(R.string.smb_frequency_exceeded))
|
||||
.enacted(false).success(false))?.run()
|
||||
return
|
||||
}
|
||||
if (!pump.isInitialized()) {
|
||||
aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
|
||||
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
|
||||
return
|
||||
}
|
||||
if (pump.isSuspended()) {
|
||||
aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpsuspended))
|
||||
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
|
||||
return
|
||||
}
|
||||
aapsLogger.debug(LTag.APS, "applySMBRequest: $request")
|
||||
|
||||
// deliver SMB
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.lastBolusTime
|
||||
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
|
||||
detailedBolusInfo.insulin = request.smb
|
||||
detailedBolusInfo.isSMB = true
|
||||
detailedBolusInfo.source = Source.USER
|
||||
detailedBolusInfo.deliverAt = request.deliverAt
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: bolus()")
|
||||
commandQueue.bolus(detailedBolusInfo, callback)
|
||||
}
|
||||
|
||||
private fun allowPercentage(): Boolean {
|
||||
return virtualPumpPlugin.isEnabled(PluginType.PUMP)
|
||||
}
|
||||
|
||||
fun disconnectPump(durationInMinutes: Int, profile: Profile?) {
|
||||
val pump = activePlugin.activePump
|
||||
disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L)
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile!!, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile!!, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if (pump.pumpDescription.isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
|
||||
commandQueue.cancelExtended(object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
createOfflineEvent(durationInMinutes)
|
||||
}
|
||||
|
||||
fun suspendLoop(durationInMinutes: Int) {
|
||||
suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000)
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
createOfflineEvent(durationInMinutes)
|
||||
}
|
||||
|
||||
fun createOfflineEvent(durationInMinutes: Int) {
|
||||
val data = JSONObject()
|
||||
try {
|
||||
data.put("eventType", CareportalEvent.OPENAPSOFFLINE)
|
||||
data.put("duration", durationInMinutes)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
val event = CareportalEvent(injector)
|
||||
event.date = DateUtil.now()
|
||||
event.source = Source.USER
|
||||
event.eventType = CareportalEvent.OPENAPSOFFLINE
|
||||
event.json = data.toString()
|
||||
MainApp.getDbHelper().createOrUpdate(event)
|
||||
nsUpload.uploadOpenAPSOffline(event)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val CHANNEL_ID = "AndroidAPS-OpenLoop"
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.loop;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ScriptReader {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public ScriptReader(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public byte[] readFile(String fileName) throws IOException {
|
||||
|
||||
AssetManager assetManager = mContext.getAssets();
|
||||
InputStream is = assetManager.open(fileName);
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
|
||||
while ((nRead = is.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
|
||||
buffer.flush();
|
||||
|
||||
byte[] bytes = buffer.toByteArray();
|
||||
is.close();
|
||||
buffer.close();
|
||||
|
||||
|
||||
return bytes;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package info.nightscout.androidaps.plugins.aps.loop
|
||||
|
||||
import android.content.Context
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
|
||||
class ScriptReader(private val context: Context) {
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun readFile(fileName: String): ByteArray {
|
||||
val assetManager = context.assets
|
||||
val `is` = assetManager.open(fileName)
|
||||
val buffer = ByteArrayOutputStream()
|
||||
var nRead: Int
|
||||
val data = ByteArray(16384)
|
||||
while (`is`.read(data, 0, data.size).also { nRead = it } != -1) {
|
||||
buffer.write(data, 0, nRead)
|
||||
}
|
||||
buffer.flush()
|
||||
val bytes = buffer.toByteArray()
|
||||
`is`.close()
|
||||
buffer.close()
|
||||
return bytes
|
||||
}
|
||||
}
|
|
@ -1,299 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSAMA;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Function;
|
||||
import org.mozilla.javascript.NativeJSON;
|
||||
import org.mozilla.javascript.NativeObject;
|
||||
import org.mozilla.javascript.RhinoException;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.mozilla.javascript.Undefined;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
public class DetermineBasalAdapterAMAJS {
|
||||
private final HasAndroidInjector injector;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject ConstraintChecker constraintChecker;
|
||||
@Inject SP sp;
|
||||
@Inject ProfileFunction profileFunction;
|
||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
||||
@Inject OpenHumansUploader openHumansUploader;
|
||||
|
||||
private final ScriptReader mScriptReader;
|
||||
|
||||
private JSONObject mProfile;
|
||||
private JSONObject mGlucoseStatus;
|
||||
private JSONArray mIobData;
|
||||
private JSONObject mMealData;
|
||||
private JSONObject mCurrentTemp;
|
||||
private JSONObject mAutosensData = null;
|
||||
|
||||
private String storedCurrentTemp = null;
|
||||
private String storedIobData = null;
|
||||
private String storedGlucoseStatus = null;
|
||||
private String storedProfile = null;
|
||||
private String storedMeal_data = null;
|
||||
private String storedAutosens_data = null;
|
||||
|
||||
private String scriptDebug = "";
|
||||
|
||||
DetermineBasalAdapterAMAJS(ScriptReader scriptReader, HasAndroidInjector injector) {
|
||||
injector.androidInjector().inject(this);
|
||||
mScriptReader = scriptReader;
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DetermineBasalResultAMA invoke() {
|
||||
|
||||
aapsLogger.debug(LTag.APS, ">>> Invoking detemine_basal <<<");
|
||||
aapsLogger.debug(LTag.APS, "Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString()));
|
||||
aapsLogger.debug(LTag.APS, "IOB data: " + (storedIobData = mIobData.toString()));
|
||||
aapsLogger.debug(LTag.APS, "Current temp: " + (storedCurrentTemp = mCurrentTemp.toString()));
|
||||
aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString()));
|
||||
aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString()));
|
||||
if (mAutosensData != null)
|
||||
aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = mAutosensData.toString()));
|
||||
else
|
||||
aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = "undefined"));
|
||||
|
||||
|
||||
DetermineBasalResultAMA determineBasalResultAMA = null;
|
||||
|
||||
Context rhino = Context.enter();
|
||||
Scriptable scope = rhino.initStandardObjects();
|
||||
// Turn off optimization to make Rhino Android compatible
|
||||
rhino.setOptimizationLevel(-1);
|
||||
|
||||
try {
|
||||
|
||||
//register logger callback for console.log and console.error
|
||||
ScriptableObject.defineClass(scope, LoggerCallback.class);
|
||||
Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null);
|
||||
scope.put("console2", scope, myLogger);
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null);
|
||||
|
||||
//set module parent
|
||||
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null);
|
||||
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null);
|
||||
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null);
|
||||
|
||||
//generate functions "determine_basal" and "setTempBasal"
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/determine-basal.js"), "JavaScript", 0, null);
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/basal-set-temp.js"), "setTempBasal.js", 0, null);
|
||||
Object determineBasalObj = scope.get("determine_basal", scope);
|
||||
Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope);
|
||||
|
||||
//call determine-basal
|
||||
if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) {
|
||||
Function determineBasalJS = (Function) determineBasalObj;
|
||||
|
||||
//prepare parameters
|
||||
Object[] params = new Object[]{
|
||||
makeParam(mGlucoseStatus, rhino, scope),
|
||||
makeParam(mCurrentTemp, rhino, scope),
|
||||
makeParamArray(mIobData, rhino, scope),
|
||||
makeParam(mProfile, rhino, scope),
|
||||
makeParam(mAutosensData, rhino, scope),
|
||||
makeParam(mMealData, rhino, scope),
|
||||
setTempBasalFunctionsObj};
|
||||
|
||||
NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params);
|
||||
scriptDebug = LoggerCallback.getScriptDebug();
|
||||
|
||||
// Parse the jsResult object to a JSON-String
|
||||
String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
|
||||
aapsLogger.debug(LTag.APS, "Result: " + result);
|
||||
try {
|
||||
JSONObject resultJson = new JSONObject(result);
|
||||
openHumansUploader.enqueueAMAData(mProfile, mGlucoseStatus, mIobData, mMealData, mCurrentTemp, mAutosensData, resultJson);
|
||||
determineBasalResultAMA = new DetermineBasalResultAMA(injector, jsResult, resultJson);
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error(LTag.APS, "Unhandled exception", e);
|
||||
}
|
||||
} else {
|
||||
aapsLogger.error(LTag.APS, "Problem loading JS Functions");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
aapsLogger.error(LTag.APS, "IOException");
|
||||
} catch (RhinoException e) {
|
||||
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString());
|
||||
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
aapsLogger.error(LTag.APS, e.toString());
|
||||
} finally {
|
||||
Context.exit();
|
||||
}
|
||||
|
||||
storedGlucoseStatus = mGlucoseStatus.toString();
|
||||
storedIobData = mIobData.toString();
|
||||
storedCurrentTemp = mCurrentTemp.toString();
|
||||
storedProfile = mProfile.toString();
|
||||
storedMeal_data = mMealData.toString();
|
||||
|
||||
return determineBasalResultAMA;
|
||||
|
||||
}
|
||||
|
||||
String getGlucoseStatusParam() {
|
||||
return storedGlucoseStatus;
|
||||
}
|
||||
|
||||
String getCurrentTempParam() {
|
||||
return storedCurrentTemp;
|
||||
}
|
||||
|
||||
String getIobDataParam() {
|
||||
return storedIobData;
|
||||
}
|
||||
|
||||
String getProfileParam() {
|
||||
return storedProfile;
|
||||
}
|
||||
|
||||
String getMealDataParam() {
|
||||
return storedMeal_data;
|
||||
}
|
||||
|
||||
String getAutosensDataParam() {
|
||||
return storedAutosens_data;
|
||||
}
|
||||
|
||||
String getScriptDebug() {
|
||||
return scriptDebug;
|
||||
}
|
||||
|
||||
public void setData(Profile profile,
|
||||
double maxIob,
|
||||
double maxBasal,
|
||||
double minBg,
|
||||
double maxBg,
|
||||
double targetBg,
|
||||
double basalrate,
|
||||
IobTotal[] iobArray,
|
||||
GlucoseStatus glucoseStatus,
|
||||
MealData mealData,
|
||||
double autosensDataRatio,
|
||||
boolean tempTargetSet) throws JSONException {
|
||||
|
||||
mProfile = new JSONObject();
|
||||
mProfile.put("max_iob", maxIob);
|
||||
mProfile.put("dia", Math.min(profile.getDia(), 3d));
|
||||
mProfile.put("type", "current");
|
||||
mProfile.put("max_daily_basal", profile.getMaxDailyBasal());
|
||||
mProfile.put("max_basal", maxBasal);
|
||||
mProfile.put("min_bg", minBg);
|
||||
mProfile.put("max_bg", maxBg);
|
||||
mProfile.put("target_bg", targetBg);
|
||||
mProfile.put("carb_ratio", profile.getIc());
|
||||
mProfile.put("sens", profile.getIsfMgdl());
|
||||
mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
|
||||
mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
|
||||
mProfile.put("skip_neutral_temps", true);
|
||||
mProfile.put("current_basal", basalrate);
|
||||
mProfile.put("temptargetSet", tempTargetSet);
|
||||
mProfile.put("autosens_adjust_targets", sp.getBoolean(R.string.key_openapsama_autosens_adjusttargets, true));
|
||||
//align with max-absorption model in AMA sensitivity
|
||||
if (mealData.usedMinCarbsImpact > 0) {
|
||||
mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
||||
} else {
|
||||
mProfile.put("min_5m_carbimpact", sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
||||
}
|
||||
|
||||
if (profileFunction.getUnits().equals(Constants.MMOL)) {
|
||||
mProfile.put("out_units", "mmol/L");
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now);
|
||||
|
||||
mCurrentTemp = new JSONObject();
|
||||
mCurrentTemp.put("temp", "absolute");
|
||||
mCurrentTemp.put("duration", tb != null ? tb.getPlannedRemainingMinutes() : 0);
|
||||
mCurrentTemp.put("rate", tb != null ? tb.tempBasalConvertedToAbsolute(now, profile) : 0d);
|
||||
|
||||
// as we have non default temps longer than 30 mintues
|
||||
TemporaryBasal tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis());
|
||||
if (tempBasal != null) {
|
||||
mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration());
|
||||
}
|
||||
|
||||
mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray);
|
||||
|
||||
mGlucoseStatus = new JSONObject();
|
||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose);
|
||||
|
||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
|
||||
} else {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.delta);
|
||||
}
|
||||
mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta);
|
||||
mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta);
|
||||
|
||||
mMealData = new JSONObject();
|
||||
mMealData.put("carbs", mealData.carbs);
|
||||
mMealData.put("boluses", mealData.boluses);
|
||||
mMealData.put("mealCOB", mealData.mealCOB);
|
||||
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
mAutosensData = new JSONObject();
|
||||
mAutosensData.put("ratio", autosensDataRatio);
|
||||
} else {
|
||||
mAutosensData = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
|
||||
|
||||
if (jsonObject == null) return Undefined.instance;
|
||||
|
||||
Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
||||
return param;
|
||||
}
|
||||
|
||||
private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
|
||||
//Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
|
||||
Object param = NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
||||
return param;
|
||||
}
|
||||
|
||||
private String readFile(String filename) throws IOException {
|
||||
byte[] bytes = mScriptReader.readFile(filename);
|
||||
String string = new String(bytes, StandardCharsets.UTF_8);
|
||||
if (string.startsWith("#!/usr/bin/env node")) {
|
||||
string = string.substring(20);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSAMA
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.data.MealData
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.mozilla.javascript.*
|
||||
import org.mozilla.javascript.Function
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.min
|
||||
|
||||
class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader, injector: HasAndroidInjector) {
|
||||
|
||||
private val injector: HasAndroidInjector
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
||||
|
||||
private val mScriptReader: ScriptReader
|
||||
private var profile = JSONObject()
|
||||
private var glucoseStatus = JSONObject()
|
||||
private var iobData: JSONArray? = null
|
||||
private var mealData = JSONObject()
|
||||
private var currentTemp = JSONObject()
|
||||
private var autosensData = JSONObject()
|
||||
|
||||
var currentTempParam: String? = null
|
||||
private set
|
||||
var iobDataParam: String? = null
|
||||
private set
|
||||
var glucoseStatusParam: String? = null
|
||||
private set
|
||||
var profileParam: String? = null
|
||||
private set
|
||||
var mealDataParam: String? = null
|
||||
private set
|
||||
var scriptDebug = ""
|
||||
private set
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
operator fun invoke(): DetermineBasalResultAMA? {
|
||||
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||
aapsLogger.debug(LTag.APS, "Glucose status: " + glucoseStatus.toString().also { glucoseStatusParam = it })
|
||||
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
|
||||
var determineBasalResultAMA: DetermineBasalResultAMA? = null
|
||||
val rhino = Context.enter()
|
||||
val scope: Scriptable = rhino.initStandardObjects()
|
||||
// Turn off optimization to make Rhino Android compatible
|
||||
rhino.optimizationLevel = -1
|
||||
try {
|
||||
|
||||
//register logger callback for console.log and console.error
|
||||
ScriptableObject.defineClass(scope, LoggerCallback::class.java)
|
||||
val myLogger = rhino.newObject(scope, "LoggerCallback", null)
|
||||
scope.put("console2", scope, myLogger)
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
|
||||
|
||||
//set module parent
|
||||
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
|
||||
|
||||
//generate functions "determine_basal" and "setTempBasal"
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/determine-basal.js"), "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/basal-set-temp.js"), "setTempBasal.js", 0, null)
|
||||
val determineBasalObj = scope["determine_basal", scope]
|
||||
val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
|
||||
|
||||
//call determine-basal
|
||||
if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
|
||||
|
||||
//prepare parameters
|
||||
val params = arrayOf(
|
||||
makeParam(glucoseStatus, rhino, scope),
|
||||
makeParam(currentTemp, rhino, scope),
|
||||
makeParamArray(iobData, rhino, scope),
|
||||
makeParam(profile, rhino, scope),
|
||||
makeParam(autosensData, rhino, scope),
|
||||
makeParam(mealData, rhino, scope),
|
||||
setTempBasalFunctionsObj)
|
||||
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||
scriptDebug = LoggerCallback.scriptDebug
|
||||
|
||||
// Parse the jsResult object to a JSON-String
|
||||
val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
|
||||
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||
try {
|
||||
val resultJson = JSONObject(result)
|
||||
openHumansUploader.enqueueAMAData(profile, glucoseStatus, iobData, mealData, currentTemp, autosensData, resultJson)
|
||||
determineBasalResultAMA = DetermineBasalResultAMA(injector, jsResult, resultJson)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||
}
|
||||
} else {
|
||||
aapsLogger.error(LTag.APS, "Problem loading JS Functions")
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
aapsLogger.error(LTag.APS, "IOException")
|
||||
} catch (e: RhinoException) {
|
||||
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
|
||||
} catch (e: IllegalAccessException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} catch (e: InstantiationException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} catch (e: InvocationTargetException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} finally {
|
||||
Context.exit()
|
||||
}
|
||||
glucoseStatusParam = glucoseStatus.toString()
|
||||
iobDataParam = iobData.toString()
|
||||
currentTempParam = currentTemp.toString()
|
||||
profileParam = profile.toString()
|
||||
mealDataParam = mealData.toString()
|
||||
return determineBasalResultAMA
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@Throws(JSONException::class) fun setData(profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean) {
|
||||
this.profile = JSONObject()
|
||||
this.profile.put("max_iob", maxIob)
|
||||
this.profile.put("dia", min(profile.dia, 3.0))
|
||||
this.profile.put("type", "current")
|
||||
this.profile.put("max_daily_basal", profile.maxDailyBasal)
|
||||
this.profile.put("max_basal", maxBasal)
|
||||
this.profile.put("min_bg", minBg)
|
||||
this.profile.put("max_bg", maxBg)
|
||||
this.profile.put("target_bg", targetBg)
|
||||
this.profile.put("carb_ratio", profile.ic)
|
||||
this.profile.put("sens", profile.isfMgdl)
|
||||
this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
|
||||
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
|
||||
this.profile.put("skip_neutral_temps", true)
|
||||
this.profile.put("current_basal", basalRate)
|
||||
this.profile.put("temptargetSet", tempTargetSet)
|
||||
this.profile.put("autosens_adjust_targets", sp.getBoolean(R.string.key_openapsama_autosens_adjusttargets, true))
|
||||
//align with max-absorption model in AMA sensitivity
|
||||
if (mealData.usedMinCarbsImpact > 0) {
|
||||
this.profile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact)
|
||||
} else {
|
||||
this.profile.put("min_5m_carbimpact", sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact))
|
||||
}
|
||||
if (profileFunction.getUnits() == Constants.MMOL) {
|
||||
this.profile.put("out_units", "mmol/L")
|
||||
}
|
||||
val now = System.currentTimeMillis()
|
||||
val tb = treatmentsPlugin.getTempBasalFromHistory(now)
|
||||
currentTemp = JSONObject()
|
||||
currentTemp.put("temp", "absolute")
|
||||
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
|
||||
currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0)
|
||||
|
||||
// as we have non default temps longer than 30 minutes
|
||||
val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
|
||||
if (tempBasal != null) {
|
||||
currentTemp.put("minutesrunning", tempBasal.realDuration)
|
||||
}
|
||||
iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
|
||||
this.glucoseStatus = JSONObject()
|
||||
this.glucoseStatus.put("glucose", glucoseStatus.glucose)
|
||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||
this.glucoseStatus.put("delta", glucoseStatus.shortAvgDelta)
|
||||
} else {
|
||||
this.glucoseStatus.put("delta", glucoseStatus.delta)
|
||||
}
|
||||
this.glucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
|
||||
this.glucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
|
||||
this.mealData = JSONObject()
|
||||
this.mealData.put("carbs", mealData.carbs)
|
||||
this.mealData.put("boluses", mealData.boluses)
|
||||
this.mealData.put("mealCOB", mealData.mealCOB)
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
autosensData.put("ratio", autosensDataRatio)
|
||||
} else {
|
||||
autosensData.put("ratio", 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||
return if (jsonObject == null) Undefined.instance else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||
}
|
||||
|
||||
private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
|
||||
return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||
}
|
||||
|
||||
@Throws(IOException::class) private fun readFile(filename: String): String {
|
||||
val bytes = mScriptReader.readFile(filename)
|
||||
var string = String(bytes, StandardCharsets.UTF_8)
|
||||
if (string.startsWith("#!/usr/bin/env node")) {
|
||||
string = string.substring(20)
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
mScriptReader = scriptReader
|
||||
this.injector = injector
|
||||
}
|
||||
}
|
|
@ -16,10 +16,10 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
|||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.JSONFormatter
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import javax.inject.Inject
|
||||
|
@ -114,7 +114,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
|||
if (openAPSAMAPlugin.lastAPSRun != 0L) {
|
||||
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun)
|
||||
}
|
||||
openAPSAMAPlugin.lastAutosensResult?.let {
|
||||
openAPSAMAPlugin.lastAutosensResult.let {
|
||||
binding.autosensdata.text = JSONFormatter.format(it.json())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,263 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSAMA;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import info.nightscout.androidaps.utils.HardLimits;
|
||||
import info.nightscout.androidaps.utils.Profiler;
|
||||
import info.nightscout.androidaps.utils.Round;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
|
||||
@Singleton
|
||||
public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
|
||||
private final AAPSLogger aapsLogger;
|
||||
private final RxBusWrapper rxBus;
|
||||
private final ConstraintChecker constraintChecker;
|
||||
private final ResourceHelper resourceHelper;
|
||||
private final ProfileFunction profileFunction;
|
||||
private final Context context;
|
||||
private final ActivePluginProvider activePlugin;
|
||||
private final TreatmentsPlugin treatmentsPlugin;
|
||||
private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||
private final HardLimits hardLimits;
|
||||
private final Profiler profiler;
|
||||
private final FabricPrivacy fabricPrivacy;
|
||||
|
||||
// last values
|
||||
DetermineBasalAdapterAMAJS lastDetermineBasalAdapterAMAJS = null;
|
||||
long lastAPSRun = 0;
|
||||
DetermineBasalResultAMA lastAPSResult = null;
|
||||
AutosensResult lastAutosensResult = null;
|
||||
|
||||
@Inject
|
||||
public OpenAPSAMAPlugin(
|
||||
HasAndroidInjector injector,
|
||||
AAPSLogger aapsLogger,
|
||||
RxBusWrapper rxBus,
|
||||
ConstraintChecker constraintChecker,
|
||||
ResourceHelper resourceHelper,
|
||||
ProfileFunction profileFunction,
|
||||
Context context,
|
||||
ActivePluginProvider activePlugin,
|
||||
TreatmentsPlugin treatmentsPlugin,
|
||||
IobCobCalculatorPlugin iobCobCalculatorPlugin,
|
||||
HardLimits hardLimits,
|
||||
Profiler profiler,
|
||||
FabricPrivacy fabricPrivacy
|
||||
) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.APS)
|
||||
.fragmentClass(OpenAPSAMAFragment.class.getName())
|
||||
.pluginIcon(R.drawable.ic_generic_icon)
|
||||
.pluginName(R.string.openapsama)
|
||||
.shortName(R.string.oaps_shortname)
|
||||
.preferencesId(R.xml.pref_openapsama)
|
||||
.description(R.string.description_ama),
|
||||
aapsLogger, resourceHelper, injector
|
||||
);
|
||||
this.aapsLogger = aapsLogger;
|
||||
this.rxBus = rxBus;
|
||||
this.constraintChecker = constraintChecker;
|
||||
this.resourceHelper = resourceHelper;
|
||||
this.profileFunction = profileFunction;
|
||||
this.context = context;
|
||||
this.activePlugin = activePlugin;
|
||||
this.treatmentsPlugin = treatmentsPlugin;
|
||||
this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
|
||||
this.hardLimits = hardLimits;
|
||||
this.profiler = profiler;
|
||||
this.fabricPrivacy = fabricPrivacy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specialEnableCondition() {
|
||||
try {
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
return pump.getPumpDescription().isTempBasalCapable;
|
||||
} catch (Exception ignored) {
|
||||
// may fail during initialization
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specialShowInListCondition() {
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
return pump.getPumpDescription().isTempBasalCapable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public APSResult getLastAPSResult() {
|
||||
return lastAPSResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastAPSRun() {
|
||||
return lastAPSRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String initiator, boolean tempBasalFallback) {
|
||||
aapsLogger.debug(LTag.APS, "invoke from " + initiator + " tempBasalFallback: " + tempBasalFallback);
|
||||
lastAPSResult = null;
|
||||
DetermineBasalAdapterAMAJS determineBasalAdapterAMAJS;
|
||||
determineBasalAdapterAMAJS = new DetermineBasalAdapterAMAJS(new ScriptReader(context), getInjector());
|
||||
|
||||
GlucoseStatus glucoseStatus = new GlucoseStatus(getInjector()).getGlucoseStatusData();
|
||||
Profile profile = profileFunction.getProfile();
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
|
||||
if (profile == null) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)));
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEnabled(PluginType.APS)) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)));
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled));
|
||||
return;
|
||||
}
|
||||
|
||||
if (glucoseStatus == null) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)));
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata));
|
||||
return;
|
||||
}
|
||||
|
||||
double maxBasal = constraintChecker.getMaxBasalAllowed(profile).value();
|
||||
double minBg = profile.getTargetLowMgdl();
|
||||
double maxBg = profile.getTargetHighMgdl();
|
||||
double targetBg = profile.getTargetMgdl();
|
||||
|
||||
minBg = Round.roundTo(minBg, 0.1d);
|
||||
maxBg = Round.roundTo(maxBg, 0.1d);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
long startPart = System.currentTimeMillis();
|
||||
IobTotal[] iobArray = iobCobCalculatorPlugin.calculateIobArrayInDia(profile);
|
||||
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart);
|
||||
|
||||
startPart = System.currentTimeMillis();
|
||||
MealData mealData = iobCobCalculatorPlugin.getMealData();
|
||||
profiler.log(LTag.APS, "getMealData()", startPart);
|
||||
|
||||
double maxIob = constraintChecker.getMaxIOBAllowed().value();
|
||||
|
||||
minBg = hardLimits.verifyHardLimits(minBg, "minBg", hardLimits.getVERY_HARD_LIMIT_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_MIN_BG()[1]);
|
||||
maxBg = hardLimits.verifyHardLimits(maxBg, "maxBg", hardLimits.getVERY_HARD_LIMIT_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_MAX_BG()[1]);
|
||||
targetBg = hardLimits.verifyHardLimits(targetBg, "targetBg", hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[1]);
|
||||
|
||||
boolean isTempTarget = false;
|
||||
TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis());
|
||||
if (tempTarget != null) {
|
||||
isTempTarget = true;
|
||||
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[1]);
|
||||
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[1]);
|
||||
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[1]);
|
||||
}
|
||||
|
||||
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, hardLimits.maxBasal()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, hardLimits.maxBasal()))
|
||||
return;
|
||||
|
||||
startPart = System.currentTimeMillis();
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin");
|
||||
if (autosensData == null) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)));
|
||||
return;
|
||||
}
|
||||
lastAutosensResult = autosensData.autosensResult;
|
||||
} else {
|
||||
lastAutosensResult = new AutosensResult();
|
||||
lastAutosensResult.sensResult = "autosens disabled";
|
||||
}
|
||||
profiler.log(LTag.APS, "detectSensitivityandCarbAbsorption()", startPart);
|
||||
profiler.log(LTag.APS, "AMA data gathering", start);
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
|
||||
lastAutosensResult.ratio, //autosensDataRatio
|
||||
isTempTarget
|
||||
);
|
||||
} catch (JSONException e) {
|
||||
fabricPrivacy.logException(e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DetermineBasalResultAMA determineBasalResultAMA = determineBasalAdapterAMAJS.invoke();
|
||||
profiler.log(LTag.APS, "AMA calculation", start);
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResultAMA == null) {
|
||||
aapsLogger.error(LTag.APS, "SMB calculation returned null");
|
||||
lastDetermineBasalAdapterAMAJS = null;
|
||||
lastAPSResult = null;
|
||||
lastAPSRun = 0;
|
||||
} else {
|
||||
if (determineBasalResultAMA.getRate() == 0d && determineBasalResultAMA.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
|
||||
determineBasalResultAMA.setTempBasalRequested(false);
|
||||
|
||||
determineBasalResultAMA.setIob(iobArray[0]);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
determineBasalResultAMA.getJson().put("timestamp", DateUtil.toISOString(now));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error(LTag.APS, "Unhandled exception", e);
|
||||
}
|
||||
|
||||
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS;
|
||||
lastAPSResult = determineBasalResultAMA;
|
||||
lastAPSRun = now;
|
||||
}
|
||||
rxBus.send(new EventOpenAPSUpdateGui());
|
||||
|
||||
//deviceStatus.suggested = determineBasalResultAMA.json;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSAMA
|
||||
|
||||
import android.content.Context
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.Profiler
|
||||
import info.nightscout.androidaps.utils.Round
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import org.json.JSONException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
open class OpenAPSAMAPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val constraintChecker: ConstraintChecker,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val context: Context,
|
||||
private val activePlugin: ActivePluginProvider,
|
||||
private val treatmentsPlugin: TreatmentsInterface,
|
||||
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||
private val hardLimits: HardLimits,
|
||||
private val profiler: Profiler,
|
||||
private val fabricPrivacy: FabricPrivacy
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.APS)
|
||||
.fragmentClass(OpenAPSAMAFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_generic_icon)
|
||||
.pluginName(R.string.openapsama)
|
||||
.shortName(R.string.oaps_shortname)
|
||||
.preferencesId(R.xml.pref_openapsama)
|
||||
.description(R.string.description_ama),
|
||||
aapsLogger, resourceHelper, injector
|
||||
), APSInterface {
|
||||
|
||||
// last values
|
||||
override var lastAPSRun: Long = 0
|
||||
override var lastAPSResult: DetermineBasalResultAMA? = null
|
||||
var lastDetermineBasalAdapterAMAJS: DetermineBasalAdapterAMAJS? = null
|
||||
var lastAutosensResult: AutosensResult = AutosensResult()
|
||||
|
||||
override fun specialEnableCondition(): Boolean {
|
||||
return try {
|
||||
val pump = activePlugin.activePump
|
||||
pump.pumpDescription.isTempBasalCapable
|
||||
} catch (ignored: Exception) {
|
||||
// may fail during initialization
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun specialShowInListCondition(): Boolean {
|
||||
val pump = activePlugin.activePump
|
||||
return pump.pumpDescription.isTempBasalCapable
|
||||
}
|
||||
|
||||
override fun invoke(initiator: String, tempBasalFallback: Boolean) {
|
||||
aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback")
|
||||
lastAPSResult = null
|
||||
val determineBasalAdapterAMAJS = DetermineBasalAdapterAMAJS(ScriptReader(context), injector)
|
||||
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
|
||||
val profile = profileFunction.getProfile()
|
||||
val pump = activePlugin.activePump
|
||||
if (profile == null) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)))
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
|
||||
return
|
||||
}
|
||||
if (!isEnabled(PluginType.APS)) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)))
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled))
|
||||
return
|
||||
}
|
||||
if (glucoseStatus == null) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)))
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata))
|
||||
return
|
||||
}
|
||||
val inputConstraints = Constraint(0.0) // fake. only for collecting all results
|
||||
val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
|
||||
inputConstraints.copyReasons(it)
|
||||
}.value()
|
||||
var start = System.currentTimeMillis()
|
||||
var startPart = System.currentTimeMillis()
|
||||
val iobArray = iobCobCalculatorPlugin.calculateIobArrayInDia(profile)
|
||||
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
|
||||
startPart = System.currentTimeMillis()
|
||||
val mealData = iobCobCalculatorPlugin.mealData
|
||||
profiler.log(LTag.APS, "getMealData()", startPart)
|
||||
val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
|
||||
inputConstraints.copyReasons(maxIOBAllowedConstraint)
|
||||
}.value()
|
||||
var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetLowMgdl, 0.1), "minBg", hardLimits.VERY_HARD_LIMIT_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MIN_BG[1].toDouble())
|
||||
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
|
||||
var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
|
||||
var isTempTarget = false
|
||||
treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
|
||||
isTempTarget = true
|
||||
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
|
||||
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||
}
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.isfMgdl, "sens", hardLimits.MINISF, hardLimits.MAXISF)) return
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.maxDailyBasal, "max_daily_basal", 0.02, hardLimits.maxBasal())) return
|
||||
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, "current_basal", 0.01, hardLimits.maxBasal())) return
|
||||
startPart = System.currentTimeMillis()
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin")
|
||||
if (autosensData == null) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
|
||||
return
|
||||
}
|
||||
lastAutosensResult = autosensData.autosensResult
|
||||
} else {
|
||||
lastAutosensResult.sensResult = "autosens disabled"
|
||||
}
|
||||
profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
|
||||
profiler.log(LTag.APS, "AMA data gathering", start)
|
||||
start = System.currentTimeMillis()
|
||||
try {
|
||||
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.activePump.baseBasalRate, iobArray, glucoseStatus, mealData,
|
||||
lastAutosensResult.ratio,
|
||||
isTempTarget
|
||||
)
|
||||
} catch (e: JSONException) {
|
||||
fabricPrivacy.logException(e)
|
||||
return
|
||||
}
|
||||
val determineBasalResultAMA = determineBasalAdapterAMAJS.invoke()
|
||||
profiler.log(LTag.APS, "AMA calculation", start)
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResultAMA == null) {
|
||||
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||
lastDetermineBasalAdapterAMAJS = null
|
||||
lastAPSResult = null
|
||||
lastAPSRun = 0
|
||||
} else {
|
||||
if (determineBasalResultAMA.rate == 0.0 && determineBasalResultAMA.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultAMA.tempBasalRequested = false
|
||||
determineBasalResultAMA.iob = iobArray[0]
|
||||
val now = System.currentTimeMillis()
|
||||
determineBasalResultAMA.json?.put("timestamp", DateUtil.toISOString(now))
|
||||
determineBasalResultAMA.inputConstraints = inputConstraints
|
||||
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS
|
||||
lastAPSResult = determineBasalResultAMA
|
||||
lastAPSRun = now
|
||||
}
|
||||
rxBus.send(EventOpenAPSUpdateGui())
|
||||
|
||||
//deviceStatus.suggested = determineBasalResultAMA.json;
|
||||
}
|
||||
}
|
|
@ -1,372 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSSMB;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Function;
|
||||
import org.mozilla.javascript.NativeJSON;
|
||||
import org.mozilla.javascript.NativeObject;
|
||||
import org.mozilla.javascript.RhinoException;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.mozilla.javascript.Undefined;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.SafeParse;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
|
||||
public class DetermineBasalAdapterSMBJS {
|
||||
private final HasAndroidInjector injector;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject ConstraintChecker constraintChecker;
|
||||
@Inject SP sp;
|
||||
@Inject ResourceHelper resourceHelper;
|
||||
@Inject ProfileFunction profileFunction;
|
||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
||||
@Inject ActivePluginProvider activePluginProvider;
|
||||
@Inject OpenHumansUploader openHumansUploader;
|
||||
|
||||
|
||||
private final ScriptReader mScriptReader;
|
||||
private JSONObject mProfile;
|
||||
private JSONObject mGlucoseStatus;
|
||||
private JSONArray mIobData;
|
||||
private JSONObject mMealData;
|
||||
private JSONObject mCurrentTemp;
|
||||
private JSONObject mAutosensData = null;
|
||||
private boolean mMicrobolusAllowed;
|
||||
private boolean mSMBAlwaysAllowed;
|
||||
private long mCurrentTime;
|
||||
private boolean mIsSaveCgmSource;
|
||||
|
||||
private String storedCurrentTemp = null;
|
||||
private String storedIobData = null;
|
||||
|
||||
private String storedGlucoseStatus = null;
|
||||
private String storedProfile = null;
|
||||
private String storedMeal_data = null;
|
||||
|
||||
private String scriptDebug = "";
|
||||
|
||||
/**
|
||||
* Main code
|
||||
*/
|
||||
|
||||
DetermineBasalAdapterSMBJS(ScriptReader scriptReader, HasAndroidInjector injector) {
|
||||
mScriptReader = scriptReader;
|
||||
this.injector = injector;
|
||||
injector.androidInjector().inject(this);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public DetermineBasalResultSMB invoke() {
|
||||
|
||||
|
||||
aapsLogger.debug(LTag.APS, ">>> Invoking detemine_basal <<<");
|
||||
aapsLogger.debug(LTag.APS, "Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString()));
|
||||
aapsLogger.debug(LTag.APS, "IOB data: " + (storedIobData = mIobData.toString()));
|
||||
aapsLogger.debug(LTag.APS, "Current temp: " + (storedCurrentTemp = mCurrentTemp.toString()));
|
||||
aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString()));
|
||||
aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString()));
|
||||
if (mAutosensData != null)
|
||||
aapsLogger.debug(LTag.APS, "Autosens data: " + mAutosensData.toString());
|
||||
else
|
||||
aapsLogger.debug(LTag.APS, "Autosens data: " + "undefined");
|
||||
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined");
|
||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + mMicrobolusAllowed);
|
||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + mSMBAlwaysAllowed);
|
||||
aapsLogger.debug(LTag.APS, "CurrentTime: " + mCurrentTime);
|
||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: " + mIsSaveCgmSource);
|
||||
|
||||
|
||||
DetermineBasalResultSMB determineBasalResultSMB = null;
|
||||
|
||||
Context rhino = Context.enter();
|
||||
Scriptable scope = rhino.initStandardObjects();
|
||||
// Turn off optimization to make Rhino Android compatible
|
||||
rhino.setOptimizationLevel(-1);
|
||||
|
||||
try {
|
||||
|
||||
//register logger callback for console.log and console.error
|
||||
ScriptableObject.defineClass(scope, LoggerCallback.class);
|
||||
Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null);
|
||||
scope.put("console2", scope, myLogger);
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null);
|
||||
|
||||
//set module parent
|
||||
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null);
|
||||
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null);
|
||||
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null);
|
||||
|
||||
//generate functions "determine_basal" and "setTempBasal"
|
||||
rhino.evaluateString(scope, readFile("OpenAPSSMB/determine-basal.js"), "JavaScript", 0, null);
|
||||
rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null);
|
||||
Object determineBasalObj = scope.get("determine_basal", scope);
|
||||
Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope);
|
||||
|
||||
//call determine-basal
|
||||
if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) {
|
||||
Function determineBasalJS = (Function) determineBasalObj;
|
||||
|
||||
//prepare parameters
|
||||
Object[] params = new Object[]{
|
||||
makeParam(mGlucoseStatus, rhino, scope),
|
||||
makeParam(mCurrentTemp, rhino, scope),
|
||||
makeParamArray(mIobData, rhino, scope),
|
||||
makeParam(mProfile, rhino, scope),
|
||||
makeParam(mAutosensData, rhino, scope),
|
||||
makeParam(mMealData, rhino, scope),
|
||||
setTempBasalFunctionsObj,
|
||||
Boolean.valueOf(mMicrobolusAllowed),
|
||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||
Long.valueOf(mCurrentTime),
|
||||
Boolean.valueOf(mIsSaveCgmSource)
|
||||
};
|
||||
|
||||
|
||||
NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params);
|
||||
scriptDebug = LoggerCallback.getScriptDebug();
|
||||
|
||||
// Parse the jsResult object to a JSON-String
|
||||
String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
|
||||
aapsLogger.debug(LTag.APS, "Result: " + result);
|
||||
try {
|
||||
JSONObject resultJson = new JSONObject(result);
|
||||
openHumansUploader.enqueueSMBData(mProfile, mGlucoseStatus, mIobData, mMealData, mCurrentTemp, mAutosensData, mMicrobolusAllowed, mSMBAlwaysAllowed, resultJson);
|
||||
determineBasalResultSMB = new DetermineBasalResultSMB(injector, resultJson);
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error(LTag.APS, "Unhandled exception", e);
|
||||
}
|
||||
} else {
|
||||
aapsLogger.error(LTag.APS, "Problem loading JS Functions");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
aapsLogger.error(LTag.APS, "IOException");
|
||||
} catch (RhinoException e) {
|
||||
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString());
|
||||
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
aapsLogger.error(LTag.APS, e.toString());
|
||||
} finally {
|
||||
Context.exit();
|
||||
}
|
||||
|
||||
storedGlucoseStatus = mGlucoseStatus.toString();
|
||||
storedIobData = mIobData.toString();
|
||||
storedCurrentTemp = mCurrentTemp.toString();
|
||||
storedProfile = mProfile.toString();
|
||||
storedMeal_data = mMealData.toString();
|
||||
|
||||
return determineBasalResultSMB;
|
||||
|
||||
}
|
||||
|
||||
String getGlucoseStatusParam() {
|
||||
return storedGlucoseStatus;
|
||||
}
|
||||
|
||||
String getCurrentTempParam() {
|
||||
return storedCurrentTemp;
|
||||
}
|
||||
|
||||
String getIobDataParam() {
|
||||
return storedIobData;
|
||||
}
|
||||
|
||||
String getProfileParam() {
|
||||
return storedProfile;
|
||||
}
|
||||
|
||||
String getMealDataParam() {
|
||||
return storedMeal_data;
|
||||
}
|
||||
|
||||
String getScriptDebug() {
|
||||
return scriptDebug;
|
||||
}
|
||||
|
||||
public void setData(Profile profile,
|
||||
double maxIob,
|
||||
double maxBasal,
|
||||
double minBg,
|
||||
double maxBg,
|
||||
double targetBg,
|
||||
double basalrate,
|
||||
IobTotal[] iobArray,
|
||||
GlucoseStatus glucoseStatus,
|
||||
MealData mealData,
|
||||
double autosensDataRatio,
|
||||
boolean tempTargetSet,
|
||||
boolean microBolusAllowed,
|
||||
boolean uamAllowed,
|
||||
boolean advancedFiltering,
|
||||
boolean isSaveCgmSource
|
||||
) throws JSONException {
|
||||
|
||||
PumpInterface pump = activePluginProvider.getActivePump();
|
||||
Double pumpbolusstep = pump.getPumpDescription().bolusStep;
|
||||
mProfile = new JSONObject();
|
||||
|
||||
mProfile.put("max_iob", maxIob);
|
||||
//mProfile.put("dia", profile.getDia());
|
||||
mProfile.put("type", "current");
|
||||
mProfile.put("max_daily_basal", profile.getMaxDailyBasal());
|
||||
mProfile.put("max_basal", maxBasal);
|
||||
mProfile.put("min_bg", minBg);
|
||||
mProfile.put("max_bg", maxBg);
|
||||
mProfile.put("target_bg", targetBg);
|
||||
mProfile.put("carb_ratio", profile.getIc());
|
||||
mProfile.put("sens", profile.getIsfMgdl());
|
||||
mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
|
||||
mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
|
||||
|
||||
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
||||
mProfile.put("high_temptarget_raises_sensitivity", false);
|
||||
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||
mProfile.put("low_temptarget_lowers_sensitivity", false);
|
||||
|
||||
|
||||
mProfile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target));
|
||||
mProfile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target));
|
||||
mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments);
|
||||
mProfile.put("exercise_mode", SMBDefaults.exercise_mode);
|
||||
mProfile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target);
|
||||
mProfile.put("maxCOB", SMBDefaults.maxCOB);
|
||||
mProfile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour());
|
||||
// min_5m_carbimpact is not used within SMB determinebasal
|
||||
//if (mealData.usedMinCarbsImpact > 0) {
|
||||
// mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
||||
//} else {
|
||||
// mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
||||
//}
|
||||
mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap);
|
||||
mProfile.put("enableUAM", uamAllowed);
|
||||
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
|
||||
|
||||
boolean smbEnabled = sp.getBoolean(R.string.key_use_smb, false);
|
||||
mProfile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval));
|
||||
mProfile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false));
|
||||
mProfile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false));
|
||||
mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
|
||||
mProfile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering);
|
||||
mProfile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering);
|
||||
mProfile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes));
|
||||
mProfile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes));
|
||||
//set the min SMB amount to be the amount set by the pump.
|
||||
mProfile.put("bolus_increment", pumpbolusstep);
|
||||
mProfile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold));
|
||||
|
||||
mProfile.put("current_basal", basalrate);
|
||||
mProfile.put("temptargetSet", tempTargetSet);
|
||||
mProfile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")));
|
||||
|
||||
if (profileFunction.getUnits().equals(Constants.MMOL)) {
|
||||
mProfile.put("out_units", "mmol/L");
|
||||
}
|
||||
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now);
|
||||
|
||||
mCurrentTemp = new JSONObject();
|
||||
mCurrentTemp.put("temp", "absolute");
|
||||
mCurrentTemp.put("duration", tb != null ? tb.getPlannedRemainingMinutes() : 0);
|
||||
mCurrentTemp.put("rate", tb != null ? tb.tempBasalConvertedToAbsolute(now, profile) : 0d);
|
||||
|
||||
// as we have non default temps longer than 30 mintues
|
||||
TemporaryBasal tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis());
|
||||
if (tempBasal != null) {
|
||||
mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration());
|
||||
}
|
||||
|
||||
mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray);
|
||||
|
||||
mGlucoseStatus = new JSONObject();
|
||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose);
|
||||
mGlucoseStatus.put("noise", glucoseStatus.noise);
|
||||
|
||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
|
||||
} else {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.delta);
|
||||
}
|
||||
mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta);
|
||||
mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta);
|
||||
mGlucoseStatus.put("date", glucoseStatus.date);
|
||||
|
||||
mMealData = new JSONObject();
|
||||
mMealData.put("carbs", mealData.carbs);
|
||||
mMealData.put("boluses", mealData.boluses);
|
||||
mMealData.put("mealCOB", mealData.mealCOB);
|
||||
mMealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation);
|
||||
mMealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation);
|
||||
mMealData.put("lastBolusTime", mealData.lastBolusTime);
|
||||
mMealData.put("lastCarbTime", mealData.lastCarbTime);
|
||||
|
||||
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
mAutosensData = new JSONObject();
|
||||
mAutosensData.put("ratio", autosensDataRatio);
|
||||
} else {
|
||||
mAutosensData = new JSONObject();
|
||||
mAutosensData.put("ratio", 1.0);
|
||||
}
|
||||
mMicrobolusAllowed = microBolusAllowed;
|
||||
mSMBAlwaysAllowed = advancedFiltering;
|
||||
|
||||
mCurrentTime = now;
|
||||
|
||||
mIsSaveCgmSource = isSaveCgmSource;
|
||||
}
|
||||
|
||||
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
|
||||
|
||||
if (jsonObject == null) return Undefined.instance;
|
||||
|
||||
return NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
||||
}
|
||||
|
||||
private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
|
||||
//Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
|
||||
return NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
||||
}
|
||||
|
||||
private String readFile(String filename) throws IOException {
|
||||
byte[] bytes = mScriptReader.readFile(filename);
|
||||
String string = new String(bytes, StandardCharsets.UTF_8);
|
||||
if (string.startsWith("#!/usr/bin/env node")) {
|
||||
string = string.substring(20);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSSMB
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.data.MealData
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.utils.SafeParse
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.mozilla.javascript.*
|
||||
import org.mozilla.javascript.Function
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import javax.inject.Inject
|
||||
|
||||
class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var activePluginProvider: ActivePluginProvider
|
||||
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
||||
|
||||
private var profile = JSONObject()
|
||||
private var mGlucoseStatus = JSONObject()
|
||||
private var iobData: JSONArray? = null
|
||||
private var mealData = JSONObject()
|
||||
private var currentTemp = JSONObject()
|
||||
private var autosensData = JSONObject()
|
||||
private var microBolusAllowed = false
|
||||
private var smbAlwaysAllowed = false
|
||||
private var currentTime: Long = 0
|
||||
private var saveCgmSource = false
|
||||
var currentTempParam: String? = null
|
||||
private set
|
||||
var iobDataParam: String? = null
|
||||
private set
|
||||
var glucoseStatusParam: String? = null
|
||||
private set
|
||||
var profileParam: String? = null
|
||||
private set
|
||||
var mealDataParam: String? = null
|
||||
private set
|
||||
var scriptDebug = ""
|
||||
private set
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
operator fun invoke(): DetermineBasalResultSMB? {
|
||||
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||
aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
|
||||
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
|
||||
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined")
|
||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
||||
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||
val rhino = Context.enter()
|
||||
val scope: Scriptable = rhino.initStandardObjects()
|
||||
// Turn off optimization to make Rhino Android compatible
|
||||
rhino.optimizationLevel = -1
|
||||
try {
|
||||
|
||||
//register logger callback for console.log and console.error
|
||||
ScriptableObject.defineClass(scope, LoggerCallback::class.java)
|
||||
val myLogger = rhino.newObject(scope, "LoggerCallback", null)
|
||||
scope.put("console2", scope, myLogger)
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
|
||||
|
||||
//set module parent
|
||||
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
|
||||
|
||||
//generate functions "determine_basal" and "setTempBasal"
|
||||
rhino.evaluateString(scope, readFile("OpenAPSSMB/determine-basal.js"), "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null)
|
||||
val determineBasalObj = scope["determine_basal", scope]
|
||||
val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
|
||||
|
||||
//call determine-basal
|
||||
if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
|
||||
|
||||
//prepare parameters
|
||||
val params = arrayOf(
|
||||
makeParam(mGlucoseStatus, rhino, scope),
|
||||
makeParam(currentTemp, rhino, scope),
|
||||
makeParamArray(iobData, rhino, scope),
|
||||
makeParam(profile, rhino, scope),
|
||||
makeParam(autosensData, rhino, scope),
|
||||
makeParam(mealData, rhino, scope),
|
||||
setTempBasalFunctionsObj,
|
||||
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||
java.lang.Long.valueOf(currentTime),
|
||||
java.lang.Boolean.valueOf(saveCgmSource)
|
||||
)
|
||||
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||
scriptDebug = LoggerCallback.scriptDebug
|
||||
|
||||
// Parse the jsResult object to a JSON-String
|
||||
val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
|
||||
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||
try {
|
||||
val resultJson = JSONObject(result)
|
||||
openHumansUploader.enqueueSMBData(profile, mGlucoseStatus, iobData, mealData, currentTemp, autosensData, microBolusAllowed, smbAlwaysAllowed, resultJson)
|
||||
determineBasalResultSMB = DetermineBasalResultSMB(injector, resultJson)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||
}
|
||||
} else {
|
||||
aapsLogger.error(LTag.APS, "Problem loading JS Functions")
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
aapsLogger.error(LTag.APS, "IOException")
|
||||
} catch (e: RhinoException) {
|
||||
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
|
||||
} catch (e: IllegalAccessException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} catch (e: InstantiationException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} catch (e: InvocationTargetException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} finally {
|
||||
Context.exit()
|
||||
}
|
||||
glucoseStatusParam = mGlucoseStatus.toString()
|
||||
iobDataParam = iobData.toString()
|
||||
currentTempParam = currentTemp.toString()
|
||||
profileParam = profile.toString()
|
||||
mealDataParam = mealData.toString()
|
||||
return determineBasalResultSMB
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection") fun setData(profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean,
|
||||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
) {
|
||||
val pump = activePluginProvider.activePump
|
||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||
this.profile.put("max_iob", maxIob)
|
||||
//mProfile.put("dia", profile.getDia());
|
||||
this.profile.put("type", "current")
|
||||
this.profile.put("max_daily_basal", profile.maxDailyBasal)
|
||||
this.profile.put("max_basal", maxBasal)
|
||||
this.profile.put("min_bg", minBg)
|
||||
this.profile.put("max_bg", maxBg)
|
||||
this.profile.put("target_bg", targetBg)
|
||||
this.profile.put("carb_ratio", profile.ic)
|
||||
this.profile.put("sens", profile.isfMgdl)
|
||||
this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
|
||||
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
|
||||
|
||||
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
||||
this.profile.put("high_temptarget_raises_sensitivity", false)
|
||||
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||
this.profile.put("low_temptarget_lowers_sensitivity", false)
|
||||
this.profile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target))
|
||||
this.profile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target))
|
||||
this.profile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments)
|
||||
this.profile.put("exercise_mode", SMBDefaults.exercise_mode)
|
||||
this.profile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target)
|
||||
this.profile.put("maxCOB", SMBDefaults.maxCOB)
|
||||
this.profile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour())
|
||||
// min_5m_carbimpact is not used within SMB determinebasal
|
||||
//if (mealData.usedMinCarbsImpact > 0) {
|
||||
// mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
||||
//} else {
|
||||
// mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
||||
//}
|
||||
this.profile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap)
|
||||
this.profile.put("enableUAM", uamAllowed)
|
||||
this.profile.put("A52_risk_enable", SMBDefaults.A52_risk_enable)
|
||||
val smbEnabled = sp.getBoolean(R.string.key_use_smb, false)
|
||||
this.profile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval))
|
||||
this.profile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false))
|
||||
this.profile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false))
|
||||
this.profile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false))
|
||||
this.profile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering)
|
||||
this.profile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering)
|
||||
this.profile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes))
|
||||
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
|
||||
//set the min SMB amount to be the amount set by the pump.
|
||||
this.profile.put("bolus_increment", pumpBolusStep)
|
||||
this.profile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold))
|
||||
this.profile.put("current_basal", basalRate)
|
||||
this.profile.put("temptargetSet", tempTargetSet)
|
||||
this.profile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")))
|
||||
if (profileFunction.getUnits() == Constants.MMOL) {
|
||||
this.profile.put("out_units", "mmol/L")
|
||||
}
|
||||
val now = System.currentTimeMillis()
|
||||
val tb = treatmentsPlugin.getTempBasalFromHistory(now)
|
||||
currentTemp.put("temp", "absolute")
|
||||
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
|
||||
currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0)
|
||||
|
||||
// as we have non default temps longer than 30 mintues
|
||||
val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
|
||||
if (tempBasal != null) {
|
||||
currentTemp.put("minutesrunning", tempBasal.realDuration)
|
||||
}
|
||||
iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
|
||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose)
|
||||
mGlucoseStatus.put("noise", glucoseStatus.noise)
|
||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.shortAvgDelta)
|
||||
} else {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.delta)
|
||||
}
|
||||
mGlucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
|
||||
mGlucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
|
||||
mGlucoseStatus.put("date", glucoseStatus.date)
|
||||
this.mealData.put("carbs", mealData.carbs)
|
||||
this.mealData.put("boluses", mealData.boluses)
|
||||
this.mealData.put("mealCOB", mealData.mealCOB)
|
||||
this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation)
|
||||
this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation)
|
||||
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
|
||||
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
autosensData.put("ratio", autosensDataRatio)
|
||||
} else {
|
||||
autosensData.put("ratio", 1.0)
|
||||
}
|
||||
this.microBolusAllowed = microBolusAllowed
|
||||
smbAlwaysAllowed = advancedFiltering
|
||||
currentTime = now
|
||||
saveCgmSource = isSaveCgmSource
|
||||
}
|
||||
|
||||
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||
return if (jsonObject == null) Undefined.instance
|
||||
else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||
}
|
||||
|
||||
private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
|
||||
return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||
}
|
||||
|
||||
@Throws(IOException::class) private fun readFile(filename: String): String {
|
||||
val bytes = scriptReader.readFile(filename)
|
||||
var string = String(bytes, StandardCharsets.UTF_8)
|
||||
if (string.startsWith("#!/usr/bin/env node")) {
|
||||
string = string.substring(20)
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
}
|
||||
}
|
|
@ -17,10 +17,10 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
|||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.JSONFormatter
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import javax.inject.Inject
|
||||
|
@ -117,7 +117,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
|||
if (openAPSSMBPlugin.lastAPSRun != 0L) {
|
||||
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun)
|
||||
}
|
||||
openAPSSMBPlugin.lastAutosensResult?.let {
|
||||
openAPSSMBPlugin.lastAutosensResult.let {
|
||||
binding.autosensdata.text = JSONFormatter.format(it.json())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,323 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSSMB;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import info.nightscout.androidaps.utils.HardLimits;
|
||||
import info.nightscout.androidaps.utils.Profiler;
|
||||
import info.nightscout.androidaps.utils.Round;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
@Singleton
|
||||
public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, ConstraintsInterface {
|
||||
private final ConstraintChecker constraintChecker;
|
||||
private final ResourceHelper resourceHelper;
|
||||
private final ProfileFunction profileFunction;
|
||||
private final Context context;
|
||||
private final RxBusWrapper rxBus;
|
||||
private final ActivePluginProvider activePlugin;
|
||||
private final TreatmentsPlugin treatmentsPlugin;
|
||||
private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||
private final HardLimits hardLimits;
|
||||
private final Profiler profiler;
|
||||
private final FabricPrivacy fabricPrivacy;
|
||||
private final SP sp;
|
||||
|
||||
// last values
|
||||
DetermineBasalAdapterSMBJS lastDetermineBasalAdapterSMBJS = null;
|
||||
long lastAPSRun = 0;
|
||||
DetermineBasalResultSMB lastAPSResult = null;
|
||||
AutosensResult lastAutosensResult = null;
|
||||
|
||||
@Inject
|
||||
public OpenAPSSMBPlugin(
|
||||
HasAndroidInjector injector,
|
||||
AAPSLogger aapsLogger,
|
||||
RxBusWrapper rxBus,
|
||||
ConstraintChecker constraintChecker,
|
||||
ResourceHelper resourceHelper,
|
||||
ProfileFunction profileFunction,
|
||||
Context context,
|
||||
ActivePluginProvider activePlugin,
|
||||
TreatmentsPlugin treatmentsPlugin,
|
||||
IobCobCalculatorPlugin iobCobCalculatorPlugin,
|
||||
HardLimits hardLimits,
|
||||
Profiler profiler,
|
||||
FabricPrivacy fabricPrivacy,
|
||||
SP sp
|
||||
) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.APS)
|
||||
.fragmentClass(OpenAPSSMBFragment.class.getName())
|
||||
.pluginIcon(R.drawable.ic_generic_icon)
|
||||
.pluginName(R.string.openapssmb)
|
||||
.shortName(R.string.smb_shortname)
|
||||
.preferencesId(R.xml.pref_openapssmb)
|
||||
.description(R.string.description_smb)
|
||||
.setDefault(),
|
||||
aapsLogger, resourceHelper, injector
|
||||
);
|
||||
this.constraintChecker = constraintChecker;
|
||||
this.resourceHelper = resourceHelper;
|
||||
this.profileFunction = profileFunction;
|
||||
this.rxBus = rxBus;
|
||||
this.context = context;
|
||||
this.activePlugin = activePlugin;
|
||||
this.treatmentsPlugin = treatmentsPlugin;
|
||||
this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
|
||||
this.hardLimits = hardLimits;
|
||||
this.profiler = profiler;
|
||||
this.fabricPrivacy = fabricPrivacy;
|
||||
this.sp = sp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specialEnableCondition() {
|
||||
try {
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
return pump.getPumpDescription().isTempBasalCapable;
|
||||
} catch (Exception ignored) {
|
||||
// may fail during initialization
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specialShowInListCondition() {
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
return pump.getPumpDescription().isTempBasalCapable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessPreferences(@NotNull PreferenceFragmentCompat preferenceFragment) {
|
||||
super.preprocessPreferences(preferenceFragment);
|
||||
boolean smbAlwaysEnabled = sp.getBoolean(R.string.key_enableSMB_always, false);
|
||||
|
||||
SwitchPreference withCOB = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_COB));
|
||||
if (withCOB != null) {
|
||||
withCOB.setVisible(!smbAlwaysEnabled);
|
||||
}
|
||||
SwitchPreference withTempTarget = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_temptarget));
|
||||
if (withTempTarget != null) {
|
||||
withTempTarget.setVisible(!smbAlwaysEnabled);
|
||||
}
|
||||
SwitchPreference afterCarbs = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_after_carbs));
|
||||
if (afterCarbs != null) {
|
||||
afterCarbs.setVisible(!smbAlwaysEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public APSResult getLastAPSResult() {
|
||||
return lastAPSResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastAPSRun() {
|
||||
return lastAPSRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String initiator, boolean tempBasalFallback) {
|
||||
getAapsLogger().debug(LTag.APS, "invoke from " + initiator + " tempBasalFallback: " + tempBasalFallback);
|
||||
lastAPSResult = null;
|
||||
DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS;
|
||||
determineBasalAdapterSMBJS = new DetermineBasalAdapterSMBJS(new ScriptReader(context), getInjector());
|
||||
|
||||
GlucoseStatus glucoseStatus = new GlucoseStatus(getInjector()).getGlucoseStatusData();
|
||||
Profile profile = profileFunction.getProfile();
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
|
||||
if (profile == null) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)));
|
||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEnabled(PluginType.APS)) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)));
|
||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled));
|
||||
return;
|
||||
}
|
||||
|
||||
if (glucoseStatus == null) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)));
|
||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata));
|
||||
return;
|
||||
}
|
||||
|
||||
Constraint<Double> inputConstraints = new Constraint<>(0d); // fake. only for collecting all results
|
||||
|
||||
Constraint<Double> maxBasalConstraint = constraintChecker.getMaxBasalAllowed(profile);
|
||||
inputConstraints.copyReasons(maxBasalConstraint);
|
||||
double maxBasal = maxBasalConstraint.value();
|
||||
double minBg = profile.getTargetLowMgdl();
|
||||
double maxBg = profile.getTargetHighMgdl();
|
||||
double targetBg = profile.getTargetMgdl();
|
||||
|
||||
minBg = Round.roundTo(minBg, 0.1d);
|
||||
maxBg = Round.roundTo(maxBg, 0.1d);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
long startPart = System.currentTimeMillis();
|
||||
|
||||
MealData mealData = iobCobCalculatorPlugin.getMealData();
|
||||
profiler.log(LTag.APS, "getMealData()", startPart);
|
||||
|
||||
Constraint<Double> maxIOBAllowedConstraint = constraintChecker.getMaxIOBAllowed();
|
||||
inputConstraints.copyReasons(maxIOBAllowedConstraint);
|
||||
double maxIob = maxIOBAllowedConstraint.value();
|
||||
|
||||
minBg = hardLimits.verifyHardLimits(minBg, "minBg", hardLimits.getVERY_HARD_LIMIT_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_MIN_BG()[1]);
|
||||
maxBg = hardLimits.verifyHardLimits(maxBg, "maxBg", hardLimits.getVERY_HARD_LIMIT_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_MAX_BG()[1]);
|
||||
targetBg = hardLimits.verifyHardLimits(targetBg, "targetBg", hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[1]);
|
||||
|
||||
boolean isTempTarget = false;
|
||||
TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis());
|
||||
if (tempTarget != null) {
|
||||
isTempTarget = true;
|
||||
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[1]);
|
||||
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[1]);
|
||||
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[1]);
|
||||
}
|
||||
|
||||
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, hardLimits.maxBasal()))
|
||||
return;
|
||||
if (!hardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, hardLimits.maxBasal()))
|
||||
return;
|
||||
|
||||
startPart = System.currentTimeMillis();
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin");
|
||||
if (autosensData == null) {
|
||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)));
|
||||
return;
|
||||
}
|
||||
lastAutosensResult = autosensData.autosensResult;
|
||||
} else {
|
||||
lastAutosensResult = new AutosensResult();
|
||||
lastAutosensResult.sensResult = "autosens disabled";
|
||||
}
|
||||
|
||||
IobTotal[] iobArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget);
|
||||
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart);
|
||||
|
||||
startPart = System.currentTimeMillis();
|
||||
Constraint<Boolean> smbAllowed = new Constraint<>(!tempBasalFallback);
|
||||
constraintChecker.isSMBModeEnabled(smbAllowed);
|
||||
inputConstraints.copyReasons(smbAllowed);
|
||||
|
||||
Constraint<Boolean> advancedFiltering = new Constraint<>(!tempBasalFallback);
|
||||
constraintChecker.isAdvancedFilteringEnabled(advancedFiltering);
|
||||
inputConstraints.copyReasons(advancedFiltering);
|
||||
|
||||
Constraint<Boolean> uam = new Constraint<>(true);
|
||||
constraintChecker.isUAMEnabled(uam);
|
||||
inputConstraints.copyReasons(uam);
|
||||
|
||||
profiler.log(LTag.APS, "detectSensitivityandCarbAbsorption()", startPart);
|
||||
profiler.log(LTag.APS, "SMB data gathering", start);
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
try {
|
||||
determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
|
||||
lastAutosensResult.ratio, //autosensDataRatio
|
||||
isTempTarget,
|
||||
smbAllowed.value(),
|
||||
uam.value(),
|
||||
advancedFiltering.value(),
|
||||
activePlugin.getActiveBgSource().getClass().getSimpleName().equals("DexcomPlugin")
|
||||
);
|
||||
} catch (JSONException e) {
|
||||
fabricPrivacy.logException(e);
|
||||
return;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
DetermineBasalResultSMB determineBasalResultSMB = determineBasalAdapterSMBJS.invoke();
|
||||
profiler.log(LTag.APS, "SMB calculation", start);
|
||||
if (determineBasalResultSMB == null) {
|
||||
getAapsLogger().error(LTag.APS, "SMB calculation returned null");
|
||||
lastDetermineBasalAdapterSMBJS = null;
|
||||
lastAPSResult = null;
|
||||
lastAPSRun = 0;
|
||||
} else {
|
||||
// TODO still needed with oref1?
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResultSMB.getRate() == 0d && determineBasalResultSMB.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
|
||||
determineBasalResultSMB.setTempBasalRequested(false);
|
||||
|
||||
determineBasalResultSMB.setIob(iobArray[0]);
|
||||
|
||||
try {
|
||||
determineBasalResultSMB.getJson().put("timestamp", DateUtil.toISOString(now));
|
||||
} catch (JSONException e) {
|
||||
getAapsLogger().error(LTag.APS, "Unhandled exception", e);
|
||||
}
|
||||
|
||||
determineBasalResultSMB.setInputConstraints(inputConstraints);
|
||||
|
||||
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
|
||||
lastAPSResult = determineBasalResultSMB;
|
||||
lastAPSRun = now;
|
||||
}
|
||||
rxBus.send(new EventOpenAPSUpdateGui());
|
||||
|
||||
//deviceStatus.suggested = determineBasalResultAMA.json;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Constraint<Boolean> isSuperBolusEnabled(Constraint<Boolean> value) {
|
||||
value.set(getAapsLogger(), false);
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSSMB
|
||||
|
||||
import android.content.Context
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.Profiler
|
||||
import info.nightscout.androidaps.utils.Round
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
open class OpenAPSSMBPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val constraintChecker: ConstraintChecker,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val context: Context,
|
||||
private val activePlugin: ActivePluginProvider,
|
||||
private val treatmentsPlugin: TreatmentsInterface,
|
||||
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||
private val hardLimits: HardLimits,
|
||||
private val profiler: Profiler,
|
||||
private val sp: SP
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.APS)
|
||||
.fragmentClass(OpenAPSSMBFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_generic_icon)
|
||||
.pluginName(R.string.openapssmb)
|
||||
.shortName(R.string.smb_shortname)
|
||||
.preferencesId(R.xml.pref_openapssmb)
|
||||
.description(R.string.description_smb)
|
||||
.setDefault(),
|
||||
aapsLogger, resourceHelper, injector
|
||||
), APSInterface, ConstraintsInterface {
|
||||
|
||||
// last values
|
||||
override var lastAPSRun: Long = 0
|
||||
override var lastAPSResult: DetermineBasalResultSMB? = null
|
||||
var lastDetermineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS? = null
|
||||
var lastAutosensResult = AutosensResult()
|
||||
|
||||
override fun specialEnableCondition(): Boolean {
|
||||
return try {
|
||||
activePlugin.activePump.pumpDescription.isTempBasalCapable
|
||||
} catch (ignored: Exception) {
|
||||
// may fail during initialization
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun specialShowInListCondition(): Boolean {
|
||||
val pump = activePlugin.activePump
|
||||
return pump.pumpDescription.isTempBasalCapable
|
||||
}
|
||||
|
||||
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
|
||||
super.preprocessPreferences(preferenceFragment)
|
||||
val smbAlwaysEnabled = sp.getBoolean(R.string.key_enableSMB_always, false)
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_enableSMB_with_COB))?.isVisible = !smbAlwaysEnabled
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_enableSMB_with_temptarget))?.isVisible = !smbAlwaysEnabled
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_enableSMB_after_carbs))?.isVisible = !smbAlwaysEnabled
|
||||
}
|
||||
|
||||
override fun invoke(initiator: String, tempBasalFallback: Boolean) {
|
||||
aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback")
|
||||
lastAPSResult = null
|
||||
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
|
||||
val profile = profileFunction.getProfile()
|
||||
val pump = activePlugin.activePump
|
||||
if (profile == null) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)))
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
|
||||
return
|
||||
}
|
||||
if (!isEnabled(PluginType.APS)) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)))
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled))
|
||||
return
|
||||
}
|
||||
if (glucoseStatus == null) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)))
|
||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata))
|
||||
return
|
||||
}
|
||||
|
||||
val inputConstraints = Constraint(0.0) // fake. only for collecting all results
|
||||
val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
|
||||
inputConstraints.copyReasons(it)
|
||||
}.value()
|
||||
var start = System.currentTimeMillis()
|
||||
var startPart = System.currentTimeMillis()
|
||||
profiler.log(LTag.APS, "getMealData()", startPart)
|
||||
val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
|
||||
inputConstraints.copyReasons(maxIOBAllowedConstraint)
|
||||
}.value()
|
||||
|
||||
var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetLowMgdl, 0.1), "minBg", hardLimits.VERY_HARD_LIMIT_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MIN_BG[1].toDouble())
|
||||
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
|
||||
var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
|
||||
var isTempTarget = false
|
||||
treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
|
||||
isTempTarget = true
|
||||
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
|
||||
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||
}
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.isfMgdl, "sens", hardLimits.MINISF, hardLimits.MAXISF)) return
|
||||
if (!hardLimits.checkOnlyHardLimits(profile.maxDailyBasal, "max_daily_basal", 0.02, hardLimits.maxBasal())) return
|
||||
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, "current_basal", 0.01, hardLimits.maxBasal())) return
|
||||
startPart = System.currentTimeMillis()
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin")
|
||||
if (autosensData == null) {
|
||||
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
|
||||
return
|
||||
}
|
||||
lastAutosensResult = autosensData.autosensResult
|
||||
} else {
|
||||
lastAutosensResult.sensResult = "autosens disabled"
|
||||
}
|
||||
val iobArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
|
||||
startPart = System.currentTimeMillis()
|
||||
val smbAllowed = Constraint(!tempBasalFallback).also {
|
||||
constraintChecker.isSMBModeEnabled(it)
|
||||
inputConstraints.copyReasons(it)
|
||||
}
|
||||
val advancedFiltering = Constraint(!tempBasalFallback).also {
|
||||
constraintChecker.isAdvancedFilteringEnabled(it)
|
||||
inputConstraints.copyReasons(it)
|
||||
}
|
||||
val uam = Constraint(true).also {
|
||||
constraintChecker.isUAMEnabled(it)
|
||||
inputConstraints.copyReasons(it)
|
||||
}
|
||||
profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
|
||||
profiler.log(LTag.APS, "SMB data gathering", start)
|
||||
start = System.currentTimeMillis()
|
||||
|
||||
DetermineBasalAdapterSMBJS(ScriptReader(context), injector).also { determineBasalAdapterSMBJS ->
|
||||
determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg,
|
||||
activePlugin.activePump.baseBasalRate,
|
||||
iobArray,
|
||||
glucoseStatus,
|
||||
iobCobCalculatorPlugin.mealData,
|
||||
lastAutosensResult.ratio,
|
||||
isTempTarget,
|
||||
smbAllowed.value(),
|
||||
uam.value(),
|
||||
advancedFiltering.value(),
|
||||
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin")
|
||||
val now = System.currentTimeMillis()
|
||||
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
||||
profiler.log(LTag.APS, "SMB calculation", start)
|
||||
if (determineBasalResultSMB == null) {
|
||||
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||
lastDetermineBasalAdapterSMBJS = null
|
||||
lastAPSResult = null
|
||||
lastAPSRun = 0
|
||||
} else {
|
||||
// TODO still needed with oref1?
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultSMB.tempBasalRequested = false
|
||||
determineBasalResultSMB.iob = iobArray[0]
|
||||
determineBasalResultSMB.json?.put("timestamp", DateUtil.toISOString(now))
|
||||
determineBasalResultSMB.inputConstraints = inputConstraints
|
||||
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS
|
||||
lastAPSResult = determineBasalResultSMB
|
||||
lastAPSRun = now
|
||||
}
|
||||
}
|
||||
rxBus.send(EventOpenAPSUpdateGui())
|
||||
}
|
||||
|
||||
override fun isSuperBolusEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
value[aapsLogger] = false
|
||||
return value
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ import info.nightscout.androidaps.interfaces.*
|
|||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
|
|
@ -9,9 +9,10 @@ import info.nightscout.androidaps.events.EventRebuildTabs
|
|||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import java.util.*
|
||||
|
@ -25,7 +26,8 @@ class ConfigBuilderPlugin @Inject constructor(
|
|||
resourceHelper: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val activePlugin: ActivePluginProvider
|
||||
private val activePlugin: ActivePluginProvider,
|
||||
private val uel: UserEntryLogger
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(ConfigBuilderFragment::class.java.name)
|
||||
|
@ -137,9 +139,10 @@ class ConfigBuilderPlugin @Inject constructor(
|
|||
if (allowHardwarePump || activity == null) {
|
||||
performPluginSwitch(changedPlugin, newState, type)
|
||||
} else {
|
||||
showConfirmation(activity, resourceHelper.gs(R.string.allow_hardware_pump_text), Runnable {
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.allow_hardware_pump_text), Runnable {
|
||||
performPluginSwitch(changedPlugin, newState, type)
|
||||
sp.putBoolean("allow_hardware_pump", true)
|
||||
uel.log("HW PUMP ALLOWED")
|
||||
aapsLogger.debug(LTag.PUMP, "First time HW pump allowed!")
|
||||
}, Runnable {
|
||||
rxBus.send(EventConfigBuilderUpdateGui())
|
||||
|
|
|
@ -22,6 +22,7 @@ import info.nightscout.androidaps.databinding.ObjectivesItemBinding
|
|||
import info.nightscout.androidaps.dialogs.NtpProgressDialog
|
||||
import info.nightscout.androidaps.events.EventNtpStatus
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
|
||||
|
@ -33,7 +34,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.SntpClient
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -52,6 +53,7 @@ class ObjectivesFragment : DaggerFragment() {
|
|||
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var sntpClient: SntpClient
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private val objectivesAdapter = ObjectivesAdapter()
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
@ -194,19 +196,19 @@ class ObjectivesFragment : DaggerFragment() {
|
|||
if (task.shouldBeIgnored()) continue
|
||||
// name
|
||||
val name = TextView(holder.binding.progress.context)
|
||||
name.text = resourceHelper.gs(task.task) + ":"
|
||||
name.text = "${resourceHelper.gs(task.task)}:"
|
||||
name.setTextColor(-0x1)
|
||||
holder.binding.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
// hint
|
||||
task.hints.forEach { h ->
|
||||
if (!task.isCompleted)
|
||||
holder.binding.progress.addView(h.generate(context))
|
||||
if (!task.isCompleted())
|
||||
context?.let { holder.binding.progress.addView(h.generate(it)) }
|
||||
}
|
||||
// state
|
||||
val state = TextView(holder.binding.progress.context)
|
||||
state.setTextColor(-0x1)
|
||||
val basicHTML = "<font color=\"%1\$s\"><b>%2\$s</b></font>"
|
||||
val formattedHTML = String.format(basicHTML, if (task.isCompleted) "#4CAF50" else "#FF9800", task.progress)
|
||||
val formattedHTML = String.format(basicHTML, if (task.isCompleted()) "#4CAF50" else "#FF9800", task.progress)
|
||||
state.text = HtmlHelper.fromHtml(formattedHTML)
|
||||
state.gravity = Gravity.END
|
||||
holder.binding.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
|
@ -305,6 +307,7 @@ class ObjectivesFragment : DaggerFragment() {
|
|||
holder.binding.unstart.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable {
|
||||
uel.log("OBJECTIVE UNSTARTED", i1 = position + 1)
|
||||
objective.startedOn = 0
|
||||
scrollToCurrentObjective()
|
||||
rxBus.send(EventObjectivesUpdateGui())
|
||||
|
@ -329,7 +332,7 @@ class ObjectivesFragment : DaggerFragment() {
|
|||
holder.binding.inputhint.visibility = View.VISIBLE
|
||||
holder.binding.enterbutton.setOnClickListener {
|
||||
val input = holder.binding.input.text.toString()
|
||||
objective.specialAction(activity, input)
|
||||
activity?.let { activity -> objective.specialAction(activity, input) }
|
||||
rxBus.send(EventObjectivesUpdateGui())
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -9,6 +9,7 @@ import info.nightscout.androidaps.Config
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
|
@ -25,8 +26,8 @@ class ObjectivesPlugin @Inject constructor(
|
|||
resourceHelper: ResourceHelper,
|
||||
private val activePlugin: ActivePluginProvider,
|
||||
private val sp: SP,
|
||||
private val config: Config
|
||||
|
||||
config: Config,
|
||||
private val uel: UserEntryLogger
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.CONSTRAINTS)
|
||||
.fragmentClass(ObjectivesFragment::class.qualifiedName)
|
||||
|
@ -141,6 +142,7 @@ class ObjectivesPlugin @Inject constructor(
|
|||
sp.putLong("Objectives_" + "auto" + "_accomplished", DateUtil.now())
|
||||
setupObjectives()
|
||||
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeaccepted))
|
||||
uel.log("OBJECTIVES SKIPPED")
|
||||
} else {
|
||||
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeinvalid))
|
||||
}
|
||||
|
@ -163,7 +165,7 @@ class ObjectivesPlugin @Inject constructor(
|
|||
return value
|
||||
}
|
||||
|
||||
fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
override fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
|
||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXBASAL_OBJECTIVE + 1), this)
|
||||
return value
|
||||
|
|
|
@ -80,28 +80,30 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
|||
// Options
|
||||
binding.examOptions.removeAllViews()
|
||||
task.options.forEach {
|
||||
val cb = it.generate(context)
|
||||
if (task.answered) {
|
||||
cb.isEnabled = false
|
||||
if (it.isCorrect)
|
||||
cb.isChecked = true
|
||||
context?.let { context ->
|
||||
val cb = it.generate(context)
|
||||
if (task.answered) {
|
||||
cb.isEnabled = false
|
||||
if (it.isCorrect)
|
||||
cb.isChecked = true
|
||||
}
|
||||
binding.examOptions.addView(cb)
|
||||
}
|
||||
binding.examOptions.addView(cb)
|
||||
}
|
||||
// Hints
|
||||
binding.examHints.removeAllViews()
|
||||
for (h in task.hints) {
|
||||
binding.examHints.addView(h.generate(context))
|
||||
context?.let { binding.examHints.addView(h.generate(it)) }
|
||||
}
|
||||
// Disabled to
|
||||
binding.examDisabledto.text = resourceHelper.gs(R.string.answerdisabledto, dateUtil.timeString(task.disabledTo))
|
||||
binding.examDisabledto.visibility = if (task.isEnabledAnswer) View.GONE else View.VISIBLE
|
||||
binding.examDisabledto.visibility = if (task.isEnabledAnswer()) View.GONE else View.VISIBLE
|
||||
// Buttons
|
||||
binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer
|
||||
binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer()
|
||||
binding.examVerify.setOnClickListener {
|
||||
var result = true
|
||||
for (o in task.options) {
|
||||
val option: Option = o as Option
|
||||
val option: Option = o
|
||||
result = result && option.evaluate()
|
||||
}
|
||||
task.answered = result
|
||||
|
@ -133,14 +135,14 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
|||
binding.nextUnansweredButton.isEnabled = !objective.isCompleted
|
||||
binding.nextUnansweredButton.setOnClickListener {
|
||||
for (i in (currentTask + 1) until objective.tasks.size) {
|
||||
if (!objective.tasks[i].isCompleted) {
|
||||
if (!objective.tasks[i].isCompleted()) {
|
||||
currentTask = i
|
||||
updateGui()
|
||||
return@setOnClickListener
|
||||
}
|
||||
}
|
||||
for (i in 0..currentTask) {
|
||||
if (!objective.tasks[i].isCompleted) {
|
||||
if (!objective.tasks[i].isCompleted()) {
|
||||
currentTask = i
|
||||
updateGui()
|
||||
return@setOnClickListener
|
||||
|
|
|
@ -1,295 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.text.util.Linkify;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
public abstract class Objective {
|
||||
@Inject public SP sp;
|
||||
@Inject public ResourceHelper resourceHelper;
|
||||
|
||||
private final String spName;
|
||||
@StringRes private final int objective;
|
||||
@StringRes private final int gate;
|
||||
private long startedOn;
|
||||
private long accomplishedOn;
|
||||
List<Task> tasks = new ArrayList<>();
|
||||
public boolean hasSpecialInput = false;
|
||||
|
||||
public Objective(HasAndroidInjector injector, String spName, @StringRes int objective, @StringRes int gate) {
|
||||
injector.androidInjector().inject(this);
|
||||
this.spName = spName;
|
||||
this.objective = objective;
|
||||
this.gate = gate;
|
||||
startedOn = sp.getLong("Objectives_" + spName + "_started", 0L);
|
||||
accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 0L);
|
||||
if ((accomplishedOn - DateUtil.now()) > T.hours(3).msecs() || (startedOn - DateUtil.now()) > T.hours(3).msecs()) { // more than 3 hours in the future
|
||||
startedOn = 0;
|
||||
accomplishedOn = 0;
|
||||
}
|
||||
setupTasks(tasks);
|
||||
for (Task task : tasks) task.objective = this;
|
||||
}
|
||||
|
||||
public boolean isCompleted() {
|
||||
for (Task task : tasks) {
|
||||
if (!task.shouldBeIgnored() && !task.isCompleted())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isCompleted(long trueTime) {
|
||||
for (Task task : tasks) {
|
||||
if (!task.shouldBeIgnored() && !task.isCompleted(trueTime))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAccomplished() {
|
||||
return accomplishedOn != 0 && accomplishedOn < DateUtil.now();
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return startedOn != 0;
|
||||
}
|
||||
|
||||
public long getStartedOn() {
|
||||
return startedOn;
|
||||
}
|
||||
|
||||
public int getObjective() {
|
||||
return objective;
|
||||
}
|
||||
|
||||
public int getGate() {
|
||||
return gate;
|
||||
}
|
||||
|
||||
public void setStartedOn(long startedOn) {
|
||||
this.startedOn = startedOn;
|
||||
sp.putLong("Objectives_" + spName + "_started", startedOn);
|
||||
}
|
||||
|
||||
public void setAccomplishedOn(long accomplishedOn) {
|
||||
this.accomplishedOn = accomplishedOn;
|
||||
sp.putLong("Objectives_" + spName + "_accomplished", accomplishedOn);
|
||||
}
|
||||
|
||||
public long getAccomplishedOn() {
|
||||
return accomplishedOn;
|
||||
}
|
||||
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
|
||||
}
|
||||
|
||||
public List<Task> getTasks() {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public boolean specialActionEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void specialAction(FragmentActivity activity, String input) {
|
||||
}
|
||||
|
||||
public abstract class Task {
|
||||
@StringRes
|
||||
private final int task;
|
||||
private Objective objective;
|
||||
ArrayList<Hint> hints = new ArrayList<>();
|
||||
|
||||
public Task(@StringRes int task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
public @StringRes int getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
protected Objective getObjective() {
|
||||
return objective;
|
||||
}
|
||||
|
||||
public abstract boolean isCompleted();
|
||||
|
||||
public boolean isCompleted(long trueTime) {
|
||||
return isCompleted();
|
||||
}
|
||||
|
||||
public String getProgress() {
|
||||
return resourceHelper.gs(isCompleted() ? R.string.completed_well_done : R.string.not_completed_yet);
|
||||
}
|
||||
|
||||
Task hint(Hint hint) {
|
||||
hints.add(hint);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ArrayList<Hint> getHints() {
|
||||
return hints;
|
||||
}
|
||||
|
||||
public boolean shouldBeIgnored() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class MinimumDurationTask extends Task {
|
||||
|
||||
private final long minimumDuration;
|
||||
|
||||
MinimumDurationTask(long minimumDuration) {
|
||||
super(R.string.time_elapsed);
|
||||
this.minimumDuration = minimumDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return getObjective().isStarted() && System.currentTimeMillis() - getObjective().getStartedOn() >= minimumDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompleted(long trueTime) {
|
||||
return getObjective().isStarted() && trueTime - getObjective().getStartedOn() >= minimumDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProgress() {
|
||||
return getDurationText(System.currentTimeMillis() - getObjective().getStartedOn())
|
||||
+ " / " + getDurationText(minimumDuration);
|
||||
}
|
||||
|
||||
private String getDurationText(long duration) {
|
||||
int days = (int) Math.floor((double) duration / T.days(1).msecs());
|
||||
int hours = (int) Math.floor((double) duration / T.hours(1).msecs());
|
||||
int minutes = (int) Math.floor((double) duration / T.mins(1).msecs());
|
||||
if (days > 0) return resourceHelper.gq(R.plurals.days, days, days);
|
||||
else if (hours > 0) return resourceHelper.gq(R.plurals.hours, hours, hours);
|
||||
else return resourceHelper.gq(R.plurals.minutes, minutes, minutes);
|
||||
}
|
||||
}
|
||||
|
||||
public class ExamTask extends Task {
|
||||
@StringRes
|
||||
int question;
|
||||
ArrayList<Option> options = new ArrayList<>();
|
||||
private final String spIdentifier;
|
||||
private boolean answered;
|
||||
private long disabledTo;
|
||||
|
||||
ExamTask(@StringRes int task, @StringRes int question, String spIdentifier) {
|
||||
super(task);
|
||||
this.question = question;
|
||||
this.spIdentifier = spIdentifier;
|
||||
answered = sp.getBoolean("ExamTask_" + spIdentifier, false);
|
||||
disabledTo = sp.getLong("DisabledTo_" + spIdentifier, 0L);
|
||||
}
|
||||
|
||||
public void setDisabledTo(long newState) {
|
||||
disabledTo = newState;
|
||||
sp.putLong("DisabledTo_" + spIdentifier, disabledTo);
|
||||
}
|
||||
|
||||
public long getDisabledTo() {
|
||||
return disabledTo;
|
||||
}
|
||||
|
||||
public boolean isEnabledAnswer() {
|
||||
return disabledTo < DateUtil.now();
|
||||
}
|
||||
|
||||
public void setAnswered(boolean newState) {
|
||||
answered = newState;
|
||||
sp.putBoolean("ExamTask_" + spIdentifier, answered);
|
||||
}
|
||||
|
||||
public boolean getAnswered() {
|
||||
return answered;
|
||||
}
|
||||
|
||||
ExamTask option(Option option) {
|
||||
options.add(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
public @StringRes int getQuestion() {
|
||||
return question;
|
||||
}
|
||||
|
||||
public List<Objective.Option> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return answered;
|
||||
}
|
||||
}
|
||||
|
||||
public class Option {
|
||||
@StringRes int option;
|
||||
boolean isCorrect;
|
||||
|
||||
CheckBox cb; // TODO: change it, this will block releasing memeory
|
||||
|
||||
Option(@StringRes int option, boolean isCorrect) {
|
||||
this.option = option;
|
||||
this.isCorrect = isCorrect;
|
||||
}
|
||||
|
||||
public boolean isCorrect() {
|
||||
return isCorrect;
|
||||
}
|
||||
|
||||
public CheckBox generate(Context context) {
|
||||
cb = new CheckBox(context);
|
||||
cb.setText(option);
|
||||
return cb;
|
||||
}
|
||||
|
||||
public boolean evaluate() {
|
||||
boolean selection = cb.isChecked();
|
||||
if (selection && isCorrect) return true;
|
||||
return !selection && !isCorrect;
|
||||
}
|
||||
}
|
||||
|
||||
public class Hint {
|
||||
@StringRes int hint;
|
||||
|
||||
Hint(@StringRes int hint) {
|
||||
this.hint = hint;
|
||||
}
|
||||
|
||||
public TextView generate(Context context) {
|
||||
TextView textView = new TextView(context);
|
||||
textView.setText(hint);
|
||||
textView.setAutoLinkMask(Linkify.WEB_URLS);
|
||||
textView.setLinksClickable(true);
|
||||
textView.setLinkTextColor(Color.YELLOW);
|
||||
Linkify.addLinks(textView, Linkify.WEB_URLS);
|
||||
return textView;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.text.util.Linkify
|
||||
import android.widget.CheckBox
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.floor
|
||||
|
||||
abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRes objective: Int, @StringRes gate: Int) {
|
||||
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
|
||||
private val spName: String
|
||||
@StringRes val objective: Int
|
||||
@StringRes val gate: Int
|
||||
var startedOn: Long = 0
|
||||
set(value) {
|
||||
field = value
|
||||
sp.putLong("Objectives_" + spName + "_started", startedOn)
|
||||
}
|
||||
var accomplishedOn: Long = 0
|
||||
set(value) {
|
||||
field = value
|
||||
sp.putLong("Objectives_" + spName + "_accomplished", value)
|
||||
}
|
||||
|
||||
var tasks: MutableList<Task> = ArrayList()
|
||||
|
||||
var hasSpecialInput = false
|
||||
|
||||
val isCompleted: Boolean
|
||||
get() {
|
||||
for (task in tasks) {
|
||||
if (!task.shouldBeIgnored() && !task.isCompleted()) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
this.spName = spName
|
||||
this.objective = objective
|
||||
this.gate = gate
|
||||
startedOn = sp.getLong("Objectives_" + spName + "_started", 0L)
|
||||
accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 0L)
|
||||
if (accomplishedOn - DateUtil.now() > T.hours(3).msecs() || startedOn - DateUtil.now() > T.hours(3).msecs()) { // more than 3 hours in the future
|
||||
startedOn = 0
|
||||
accomplishedOn = 0
|
||||
}
|
||||
}
|
||||
|
||||
fun isCompleted(trueTime: Long): Boolean {
|
||||
for (task in tasks) {
|
||||
if (!task.shouldBeIgnored() && !task.isCompleted(trueTime)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val isAccomplished: Boolean
|
||||
get() = accomplishedOn != 0L && accomplishedOn < DateUtil.now()
|
||||
val isStarted: Boolean
|
||||
get() = startedOn != 0L
|
||||
|
||||
open fun specialActionEnabled(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
open fun specialAction(activity: FragmentActivity, input: String) {}
|
||||
|
||||
abstract inner class Task(var objective: Objective, @StringRes val task: Int) {
|
||||
|
||||
var hints = ArrayList<Hint>()
|
||||
|
||||
abstract fun isCompleted(): Boolean
|
||||
|
||||
open fun isCompleted(trueTime: Long): Boolean = isCompleted
|
||||
|
||||
open val progress: String
|
||||
get() = resourceHelper.gs(if (isCompleted) R.string.completed_well_done else R.string.not_completed_yet)
|
||||
|
||||
fun hint(hint: Hint): Task {
|
||||
hints.add(hint)
|
||||
return this
|
||||
}
|
||||
|
||||
open fun shouldBeIgnored(): Boolean = false
|
||||
}
|
||||
|
||||
inner class MinimumDurationTask internal constructor(objective: Objective, private val minimumDuration: Long) : Task(objective, R.string.time_elapsed) {
|
||||
|
||||
override fun isCompleted(): Boolean =
|
||||
objective.isStarted && System.currentTimeMillis() - objective.startedOn >= minimumDuration
|
||||
|
||||
override fun isCompleted(trueTime: Long): Boolean {
|
||||
return objective.isStarted && trueTime - objective.startedOn >= minimumDuration
|
||||
}
|
||||
|
||||
override val progress: String
|
||||
get() = (getDurationText(System.currentTimeMillis() - objective.startedOn)
|
||||
+ " / " + getDurationText(minimumDuration))
|
||||
|
||||
private fun getDurationText(duration: Long): String {
|
||||
val days = floor(duration.toDouble() / T.days(1).msecs()).toInt()
|
||||
val hours = floor(duration.toDouble() / T.hours(1).msecs()).toInt()
|
||||
val minutes = floor(duration.toDouble() / T.mins(1).msecs()).toInt()
|
||||
return when {
|
||||
days > 0 -> resourceHelper.gq(R.plurals.days, days, days)
|
||||
hours > 0 -> resourceHelper.gq(R.plurals.hours, hours, hours)
|
||||
else -> resourceHelper.gq(R.plurals.minutes, minutes, minutes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ExamTask internal constructor(objective: Objective, @StringRes task: Int, @StringRes val question: Int, private val spIdentifier: String) : Task(objective, task) {
|
||||
|
||||
var options = ArrayList<Option>()
|
||||
var answered: Boolean = false
|
||||
set(value) {
|
||||
field = value
|
||||
sp.putBoolean("ExamTask_$spIdentifier", value)
|
||||
}
|
||||
var disabledTo: Long = 0
|
||||
set(value) {
|
||||
field = value
|
||||
sp.putLong("DisabledTo_$spIdentifier", value)
|
||||
}
|
||||
|
||||
init {
|
||||
answered = sp.getBoolean("ExamTask_$spIdentifier", false)
|
||||
disabledTo = sp.getLong("DisabledTo_$spIdentifier", 0L)
|
||||
}
|
||||
|
||||
override fun isCompleted(): Boolean = answered
|
||||
|
||||
fun isEnabledAnswer(): Boolean = disabledTo < DateUtil.now()
|
||||
|
||||
fun option(option: Option): ExamTask {
|
||||
options.add(option)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
inner class Option internal constructor(@StringRes var option: Int, var isCorrect: Boolean) {
|
||||
|
||||
var cb: CheckBox? = null // TODO: change it, this will block releasing memory
|
||||
|
||||
fun generate(context: Context): CheckBox {
|
||||
cb = CheckBox(context)
|
||||
cb?.setText(option)
|
||||
return cb!!
|
||||
}
|
||||
|
||||
fun evaluate(): Boolean {
|
||||
val selection = cb!!.isChecked
|
||||
return if (selection && isCorrect) true else !selection && !isCorrect
|
||||
}
|
||||
}
|
||||
|
||||
inner class Hint internal constructor(@StringRes var hint: Int) {
|
||||
|
||||
fun generate(context: Context): TextView {
|
||||
val textView = TextView(context)
|
||||
textView.setText(hint)
|
||||
textView.autoLinkMask = Linkify.WEB_URLS
|
||||
textView.linksClickable = true
|
||||
textView.setLinkTextColor(Color.YELLOW)
|
||||
Linkify.addLinks(textView, Linkify.WEB_URLS)
|
||||
return textView
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
public class Objective0 extends Objective {
|
||||
@Inject SP sp;
|
||||
@Inject ActivePluginProvider activePlugin;
|
||||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
||||
@Inject LoopPlugin loopPlugin;
|
||||
@Inject NSClientPlugin nsClientPlugin;
|
||||
@Inject IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||
|
||||
public Objective0(HasAndroidInjector injector) {
|
||||
super(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new Task(R.string.objectives_bgavailableinns) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false);
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.nsclienthaswritepermission) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return nsClientPlugin.hasWritePermission();
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.virtualpump_uploadstatus_title) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_virtualpump_uploadstatus, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBeIgnored() {
|
||||
return !virtualPumpPlugin.isEnabled(PluginType.PUMP);
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.objectives_pumpstatusavailableinns) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false);
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.hasbgdata) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return iobCobCalculatorPlugin.lastBg() != null;
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.loopenabled) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return loopPlugin.isEnabled(PluginType.LOOP);
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.apsselected) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
APSInterface usedAPS = activePlugin.getActiveAPS();
|
||||
return ((PluginBase) usedAPS).isEnabled(PluginType.APS);
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.activate_profile) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate) {
|
||||
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var loopPlugin: LoopPlugin
|
||||
@Inject lateinit var nsClientPlugin: NSClientPlugin
|
||||
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||
|
||||
init {
|
||||
tasks.add(object : Task(this, R.string.objectives_bgavailableinns) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false)
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.nsclienthaswritepermission) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return nsClientPlugin.hasWritePermission()
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.virtualpump_uploadstatus_title) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_virtualpump_uploadstatus, false)
|
||||
}
|
||||
|
||||
override fun shouldBeIgnored(): Boolean {
|
||||
return !virtualPumpPlugin.isEnabled(PluginType.PUMP)
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.objectives_pumpstatusavailableinns) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false)
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.hasbgdata) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return iobCobCalculatorPlugin.lastBg() != null
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.loopenabled) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return loopPlugin.isEnabled(PluginType.LOOP)
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.apsselected) {
|
||||
override fun isCompleted(): Boolean {
|
||||
val usedAPS = activePlugin.activeAPS
|
||||
return (usedAPS as PluginBase).isEnabled(PluginType.APS)
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.activate_profile) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
public class Objective1 extends Objective {
|
||||
@Inject SP sp;
|
||||
@Inject ActionsPlugin actionsPlugin;
|
||||
|
||||
@Inject
|
||||
public Objective1(HasAndroidInjector injector) {
|
||||
super(injector, "usage", R.string.objectives_usage_objective, R.string.objectives_usage_gate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new Task(R.string.objectives_useprofileswitch) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_objectiveuseprofileswitch, false);
|
||||
}
|
||||
});
|
||||
tasks.add(new Task(R.string.objectives_usedisconnectpump) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_objectiveusedisconnect, false);
|
||||
}
|
||||
}.hint(new Hint(R.string.disconnectpump_hint)));
|
||||
tasks.add(new Task(R.string.objectives_usereconnectpump) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_objectiveusereconnect, false);
|
||||
}
|
||||
}.hint(new Hint(R.string.disconnectpump_hint)));
|
||||
tasks.add(new Task(R.string.objectives_usetemptarget) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_objectiveusetemptarget, false);
|
||||
}
|
||||
}.hint(new Hint(R.string.usetemptarget_hint)));
|
||||
tasks.add(new Task(R.string.objectives_useactions) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_objectiveuseactions, false) && actionsPlugin.isEnabled(PluginType.GENERAL) && actionsPlugin.isFragmentVisible();
|
||||
}
|
||||
}.hint(new Hint(R.string.useaction_hint)));
|
||||
tasks.add(new Task(R.string.objectives_useloop) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_objectiveuseloop, false);
|
||||
}
|
||||
}.hint(new Hint(R.string.useaction_hint)));
|
||||
tasks.add(new Task(R.string.objectives_usescale) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getBoolean(R.string.key_objectiveusescale, false);
|
||||
}
|
||||
}.hint(new Hint(R.string.usescale_hint)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
|
||||
import javax.inject.Inject
|
||||
|
||||
class Objective1 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "usage", R.string.objectives_usage_objective, R.string.objectives_usage_gate) {
|
||||
|
||||
@Inject lateinit var actionsPlugin: ActionsPlugin
|
||||
|
||||
init {
|
||||
tasks.add(object : Task(this, R.string.objectives_useprofileswitch) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_objectiveuseprofileswitch, false)
|
||||
}
|
||||
})
|
||||
tasks.add(object : Task(this, R.string.objectives_usedisconnectpump) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_objectiveusedisconnect, false)
|
||||
}
|
||||
}.hint(Hint(R.string.disconnectpump_hint)))
|
||||
tasks.add(object : Task(this, R.string.objectives_usereconnectpump) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_objectiveusereconnect, false)
|
||||
}
|
||||
}.hint(Hint(R.string.disconnectpump_hint)))
|
||||
tasks.add(object : Task(this, R.string.objectives_usetemptarget) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_objectiveusetemptarget, false)
|
||||
}
|
||||
}.hint(Hint(R.string.usetemptarget_hint)))
|
||||
tasks.add(object : Task(this, R.string.objectives_useactions) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_objectiveuseactions, false) && actionsPlugin.isEnabled(PluginType.GENERAL) && actionsPlugin.isFragmentVisible()
|
||||
}
|
||||
}.hint(Hint(R.string.useaction_hint)))
|
||||
tasks.add(object : Task(this, R.string.objectives_useloop) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_objectiveuseloop, false)
|
||||
}
|
||||
}.hint(Hint(R.string.useaction_hint)))
|
||||
tasks.add(object : Task(this, R.string.objectives_usescale) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getBoolean(R.string.key_objectiveusescale, false)
|
||||
}
|
||||
}.hint(Hint(R.string.usescale_hint)))
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class Objective10 extends Objective {
|
||||
|
||||
public Objective10(HasAndroidInjector injector) {
|
||||
super(injector, "auto", R.string.objectives_auto_objective, R.string.objectives_auto_gate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
||||
class Objective10(injector: HasAndroidInjector) : Objective(injector, "auto", R.string.objectives_auto_objective, R.string.objectives_auto_gate) {
|
||||
|
||||
init {
|
||||
tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
|
||||
}
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
|
||||
public class Objective2 extends Objective {
|
||||
|
||||
|
||||
public Objective2(HasAndroidInjector injector) {
|
||||
super(injector, "exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate);
|
||||
for (Task task : tasks) {
|
||||
if (!task.isCompleted()) setAccomplishedOn(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new ExamTask(R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
|
||||
.option(new Option(R.string.prerequisites_nightscout, true))
|
||||
.option(new Option(R.string.prerequisites_computer, true))
|
||||
.option(new Option(R.string.prerequisites_pump, true))
|
||||
.option(new Option(R.string.prerequisites_beanandroiddeveloper, false))
|
||||
.hint(new Hint(R.string.prerequisites_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.prerequisites2_label, R.string.prerequisites2_what, "prerequisites2")
|
||||
.option(new Option(R.string.prerequisites2_profile, true))
|
||||
.option(new Option(R.string.prerequisites2_device, true))
|
||||
.option(new Option(R.string.prerequisites2_internet, false))
|
||||
.option(new Option(R.string.prerequisites2_supportedcgm, true))
|
||||
.hint(new Hint(R.string.prerequisites2_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.basaltest_label, R.string.basaltest_when,"basaltest")
|
||||
.option(new Option(R.string.basaltest_fixed, false))
|
||||
.option(new Option(R.string.basaltest_havingregularhighlow, true))
|
||||
.option(new Option(R.string.basaltest_weekly, false))
|
||||
.option(new Option(R.string.basaltest_beforeloop, true))
|
||||
.hint(new Hint(R.string.basaltest_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.dia_label_exam, R.string.dia_whatmeansdia,"dia")
|
||||
.option(new Option(R.string.dia_profile, true))
|
||||
.option(new Option(R.string.dia_minimumis5h, true))
|
||||
.option(new Option(R.string.dia_meaningisequaltodiapump, false))
|
||||
.option(new Option(R.string.dia_valuemustbedetermined, true))
|
||||
.hint(new Hint(R.string.dia_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.isf_label_exam, R.string.blank,"isf")
|
||||
.option(new Option(R.string.isf_decreasingvalue, true))
|
||||
.option(new Option(R.string.isf_preferences, false))
|
||||
.option(new Option(R.string.isf_increasingvalue, false))
|
||||
.option(new Option(R.string.isf_noeffect, false))
|
||||
.hint(new Hint(R.string.isf_hint1))
|
||||
.hint(new Hint(R.string.isf_hint2))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.ic_label_exam, R.string.blank,"ic")
|
||||
.option(new Option(R.string.ic_increasingvalue, true))
|
||||
.option(new Option(R.string.ic_decreasingvalue, false))
|
||||
.option(new Option(R.string.ic_multiple, true))
|
||||
.option(new Option(R.string.ic_isf, false))
|
||||
.hint(new Hint(R.string.ic_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.hypott_label, R.string.hypott_whenhypott,"hypott")
|
||||
.option(new Option(R.string.hypott_preventoversmb, true))
|
||||
.option(new Option(R.string.hypott_exercise, false))
|
||||
.option(new Option(R.string.hypott_wrongbasal, false))
|
||||
.option(new Option(R.string.hypott_0basal, false))
|
||||
.hint(new Hint(R.string.hypott_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitch_pctwillchange,"profileswitch")
|
||||
.option(new Option(R.string.profileswitch_basallower, true))
|
||||
.option(new Option(R.string.profileswitch_isfhigher, true))
|
||||
.option(new Option(R.string.profileswitch_iclower, false))
|
||||
.option(new Option(R.string.profileswitch_unchanged, false))
|
||||
.hint(new Hint(R.string.profileswitch_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.profileswitch2_label, R.string.profileswitch2_pctwillchange,"profileswitch2")
|
||||
.option(new Option(R.string.profileswitch2_bghigher, false))
|
||||
.option(new Option(R.string.profileswitch2_basalhigher, true))
|
||||
.option(new Option(R.string.profileswitch2_bgunchanged, true))
|
||||
.option(new Option(R.string.profileswitch2_isfhigher, false))
|
||||
.hint(new Hint(R.string.profileswitch_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.profileswitchtime_label, R.string.profileswitchtime_iwant,"profileswitchtime")
|
||||
.option(new Option(R.string.profileswitchtime_2, false))
|
||||
.option(new Option(R.string.profileswitchtime__2, true))
|
||||
.option(new Option(R.string.profileswitchtime_tt, false))
|
||||
.option(new Option(R.string.profileswitchtime_100, false))
|
||||
.hint(new Hint(R.string.profileswitchtime_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.profileswitch4_label, R.string.blank,"profileswitch4")
|
||||
.option(new Option(R.string.profileswitch4_rates, true))
|
||||
.option(new Option(R.string.profileswitch4_internet, true))
|
||||
.option(new Option(R.string.profileswitch4_sufficient, false))
|
||||
.option(new Option(R.string.profileswitch4_multi, true))
|
||||
.hint(new Hint(R.string.profileswitch_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.exerciseprofile_label, R.string.exerciseprofile_whattodo,"exercise")
|
||||
.option(new Option(R.string.exerciseprofile_switchprofileabove100, false))
|
||||
.option(new Option(R.string.exerciseprofile_switchprofilebelow100, true))
|
||||
.option(new Option(R.string.exerciseprofile_suspendloop, false))
|
||||
.option(new Option(R.string.exerciseprofile_leaveat100, false))
|
||||
.hint(new Hint(R.string.exerciseprofile_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.exercise_label, R.string.exercise_whattodo,"exercise2")
|
||||
.option(new Option(R.string.exercise_settt, true))
|
||||
.option(new Option(R.string.exercise_setfinished, false))
|
||||
.option(new Option(R.string.exercise_setunchanged, false))
|
||||
.option(new Option(R.string.exercise_15g, false))
|
||||
.hint(new Hint(R.string.exercise_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.noisycgm_label, R.string.noisycgm_whattodo,"noisycgm")
|
||||
.option(new Option(R.string.noisycgm_nothing, false))
|
||||
.option(new Option(R.string.noisycgm_pause, true))
|
||||
.option(new Option(R.string.noisycgm_replacesensor, true))
|
||||
.option(new Option(R.string.noisycgm_checksmoothing, true))
|
||||
.hint(new Hint(R.string.noisycgm_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.pumpdisconnect_label, R.string.blank,"pumpdisconnect")
|
||||
.option(new Option(R.string.pumpdisconnect_unnecessary, false))
|
||||
.option(new Option(R.string.pumpdisconnect_missinginsulin, true))
|
||||
.option(new Option(R.string.pumpdisconnect_notstop, false))
|
||||
.option(new Option(R.string.pumpdisconnect_openloop, false))
|
||||
.hint(new Hint(R.string.pumpdisconnect_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.insulin_label, R.string.insulin_ultrarapid,"insulin")
|
||||
.option(new Option(R.string.insulin_novorapid, false))
|
||||
.option(new Option(R.string.insulin_humalog, false))
|
||||
.option(new Option(R.string.insulin_actrapid, false))
|
||||
.option(new Option(R.string.insulin_fiasp, true))
|
||||
.hint(new Hint(R.string.insulin_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.sensitivity_label, R.string.blank,"sensitivity")
|
||||
.option(new Option(R.string.sensitivity_adjust, true))
|
||||
.option(new Option(R.string.sensitivity_edit, false))
|
||||
.option(new Option(R.string.sensitivity_cannula, true))
|
||||
.option(new Option(R.string.sensitivity_time, true))
|
||||
.hint(new Hint(R.string.sensitivity_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.objectives_label, R.string.objectives_howtosave,"objectives")
|
||||
.option(new Option(R.string.objectives_notesettings, false))
|
||||
.option(new Option(R.string.objectives_afterobjective, true))
|
||||
.option(new Option(R.string.objectives_afterchange, true))
|
||||
.option(new Option(R.string.objectives_afterinitialsetup, true))
|
||||
.hint(new Hint(R.string.objectives_hint1))
|
||||
.hint(new Hint(R.string.objectives_hint2))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.objectives2_label, R.string.objectives_howtosave,"objectives2")
|
||||
.option(new Option(R.string.objectives2_maintenance, true))
|
||||
.option(new Option(R.string.objectives2_internalstorage, true))
|
||||
.option(new Option(R.string.objectives2_cloud, true))
|
||||
.option(new Option(R.string.objectives2_easyrestore, false))
|
||||
.hint(new Hint(R.string.objectives_hint1))
|
||||
.hint(new Hint(R.string.objectives_hint2))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.update_label, R.string.blank,"update")
|
||||
.option(new Option(R.string.update_git, true))
|
||||
.option(new Option(R.string.update_askfriend, false))
|
||||
.option(new Option(R.string.update_keys, true))
|
||||
.option(new Option(R.string.update_asap, true))
|
||||
.hint(new Hint(R.string.update_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.troubleshooting_label, R.string.troubleshooting_wheretoask,"troubleshooting")
|
||||
.option(new Option(R.string.troubleshooting_fb, true))
|
||||
.option(new Option(R.string.troubleshooting_wiki, true))
|
||||
.option(new Option(R.string.troubleshooting_gitter, true))
|
||||
.option(new Option(R.string.troubleshooting_yourendo, false))
|
||||
.hint(new Hint(R.string.troubleshooting_hint1))
|
||||
.hint(new Hint(R.string.troubleshooting_hint2))
|
||||
.hint(new Hint(R.string.troubleshooting_hint3))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo,"wrongcarbs")
|
||||
.option(new Option(R.string.wrongcarbs_addinsulin, false))
|
||||
.option(new Option(R.string.wrongcarbs_treatmentstab, true))
|
||||
.option(new Option(R.string.wrongcarbs_donothing, false))
|
||||
.option(new Option(R.string.wrongcarbs_bolus, false))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.wronginsulin_label, R.string.wronginsulin_whattodo,"wronginsulin")
|
||||
.option(new Option(R.string.wronginsulin_careportal, false))
|
||||
.option(new Option(R.string.wronginsulin_compare, true))
|
||||
.option(new Option(R.string.wronginsulin_prime, true))
|
||||
.option(new Option(R.string.wrongcarbs_donothing, false))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.iob_label, R.string.blank,"iob")
|
||||
.option(new Option(R.string.iob_value, true))
|
||||
.option(new Option(R.string.iob_hightemp, false))
|
||||
.option(new Option(R.string.iob_negiob, true))
|
||||
.option(new Option(R.string.iob_posiob, true))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.breadgrams_label, R.string.blank,"breadgrams")
|
||||
.option(new Option(R.string.breadgrams_grams, true))
|
||||
.option(new Option(R.string.breadgrams_exchange, false))
|
||||
.option(new Option(R.string.breadgrams_decay, true))
|
||||
.option(new Option(R.string.breadgrams_calc, true))
|
||||
.hint(new Hint(R.string.breadgrams_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.extendedcarbs_label, R.string.extendedcarbs_handling,"extendedcarbs")
|
||||
.option(new Option(R.string.extendedcarbs_future, true))
|
||||
.option(new Option(R.string.extendedcarbs_free, false))
|
||||
.option(new Option(R.string.extendedcarbs_fat, true))
|
||||
.option(new Option(R.string.extendedcarbs_rescue, false))
|
||||
.hint(new Hint(R.string.extendedcarbs_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.nsclient_label, R.string.nsclient_howcanyou,"nsclient")
|
||||
.option(new Option(R.string.nsclient_nightscout, true))
|
||||
.option(new Option(R.string.nsclient_dexcomfollow, true))
|
||||
.option(new Option(R.string.nsclient_data, true))
|
||||
.option(new Option(R.string.nsclient_fullcontrol, false))
|
||||
.hint(new Hint(R.string.nsclient_hint1))
|
||||
);
|
||||
tasks.add(new ExamTask(R.string.other_medication_label, R.string.other_medication_text,"otherMedicationWarning")
|
||||
.option(new Option(R.string.yes, true))
|
||||
.option(new Option(R.string.no, false))
|
||||
);
|
||||
|
||||
for (Task task : tasks)
|
||||
Collections.shuffle(((ExamTask)task).options);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
class Objective2(injector: HasAndroidInjector) : Objective(injector, "exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate) {
|
||||
|
||||
init {
|
||||
tasks.add(ExamTask(this, R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
|
||||
.option(Option(R.string.prerequisites_nightscout, true))
|
||||
.option(Option(R.string.prerequisites_computer, true))
|
||||
.option(Option(R.string.prerequisites_pump, true))
|
||||
.option(Option(R.string.prerequisites_beanandroiddeveloper, false))
|
||||
.hint(Hint(R.string.prerequisites_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.prerequisites2_label, R.string.prerequisites2_what, "prerequisites2")
|
||||
.option(Option(R.string.prerequisites2_profile, true))
|
||||
.option(Option(R.string.prerequisites2_device, true))
|
||||
.option(Option(R.string.prerequisites2_internet, false))
|
||||
.option(Option(R.string.prerequisites2_supportedcgm, true))
|
||||
.hint(Hint(R.string.prerequisites2_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.basaltest_label, R.string.basaltest_when, "basaltest")
|
||||
.option(Option(R.string.basaltest_fixed, false))
|
||||
.option(Option(R.string.basaltest_havingregularhighlow, true))
|
||||
.option(Option(R.string.basaltest_weekly, false))
|
||||
.option(Option(R.string.basaltest_beforeloop, true))
|
||||
.hint(Hint(R.string.basaltest_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.dia_label_exam, R.string.dia_whatmeansdia, "dia")
|
||||
.option(Option(R.string.dia_profile, true))
|
||||
.option(Option(R.string.dia_minimumis5h, true))
|
||||
.option(Option(R.string.dia_meaningisequaltodiapump, false))
|
||||
.option(Option(R.string.dia_valuemustbedetermined, true))
|
||||
.hint(Hint(R.string.dia_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.isf_label_exam, R.string.blank, "isf")
|
||||
.option(Option(R.string.isf_decreasingvalue, true))
|
||||
.option(Option(R.string.isf_preferences, false))
|
||||
.option(Option(R.string.isf_increasingvalue, false))
|
||||
.option(Option(R.string.isf_noeffect, false))
|
||||
.hint(Hint(R.string.isf_hint1))
|
||||
.hint(Hint(R.string.isf_hint2))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.ic_label_exam, R.string.blank, "ic")
|
||||
.option(Option(R.string.ic_increasingvalue, true))
|
||||
.option(Option(R.string.ic_decreasingvalue, false))
|
||||
.option(Option(R.string.ic_multiple, true))
|
||||
.option(Option(R.string.ic_isf, false))
|
||||
.hint(Hint(R.string.ic_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.hypott_label, R.string.hypott_whenhypott, "hypott")
|
||||
.option(Option(R.string.hypott_preventoversmb, true))
|
||||
.option(Option(R.string.hypott_exercise, false))
|
||||
.option(Option(R.string.hypott_wrongbasal, false))
|
||||
.option(Option(R.string.hypott_0basal, false))
|
||||
.hint(Hint(R.string.hypott_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.profileswitch_label, R.string.profileswitch_pctwillchange, "profileswitch")
|
||||
.option(Option(R.string.profileswitch_basallower, true))
|
||||
.option(Option(R.string.profileswitch_isfhigher, true))
|
||||
.option(Option(R.string.profileswitch_iclower, false))
|
||||
.option(Option(R.string.profileswitch_unchanged, false))
|
||||
.hint(Hint(R.string.profileswitch_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.profileswitch2_label, R.string.profileswitch2_pctwillchange, "profileswitch2")
|
||||
.option(Option(R.string.profileswitch2_bghigher, false))
|
||||
.option(Option(R.string.profileswitch2_basalhigher, true))
|
||||
.option(Option(R.string.profileswitch2_bgunchanged, true))
|
||||
.option(Option(R.string.profileswitch2_isfhigher, false))
|
||||
.hint(Hint(R.string.profileswitch_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.profileswitchtime_label, R.string.profileswitchtime_iwant, "profileswitchtime")
|
||||
.option(Option(R.string.profileswitchtime_2, false))
|
||||
.option(Option(R.string.profileswitchtime__2, true))
|
||||
.option(Option(R.string.profileswitchtime_tt, false))
|
||||
.option(Option(R.string.profileswitchtime_100, false))
|
||||
.hint(Hint(R.string.profileswitchtime_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.profileswitch4_label, R.string.blank, "profileswitch4")
|
||||
.option(Option(R.string.profileswitch4_rates, true))
|
||||
.option(Option(R.string.profileswitch4_internet, true))
|
||||
.option(Option(R.string.profileswitch4_sufficient, false))
|
||||
.option(Option(R.string.profileswitch4_multi, true))
|
||||
.hint(Hint(R.string.profileswitch_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.exerciseprofile_label, R.string.exerciseprofile_whattodo, "exercise")
|
||||
.option(Option(R.string.exerciseprofile_switchprofileabove100, false))
|
||||
.option(Option(R.string.exerciseprofile_switchprofilebelow100, true))
|
||||
.option(Option(R.string.exerciseprofile_suspendloop, false))
|
||||
.option(Option(R.string.exerciseprofile_leaveat100, false))
|
||||
.hint(Hint(R.string.exerciseprofile_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.exercise_label, R.string.exercise_whattodo, "exercise2")
|
||||
.option(Option(R.string.exercise_settt, true))
|
||||
.option(Option(R.string.exercise_setfinished, false))
|
||||
.option(Option(R.string.exercise_setunchanged, false))
|
||||
.option(Option(R.string.exercise_15g, false))
|
||||
.hint(Hint(R.string.exercise_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.noisycgm_label, R.string.noisycgm_whattodo, "noisycgm")
|
||||
.option(Option(R.string.noisycgm_nothing, false))
|
||||
.option(Option(R.string.noisycgm_pause, true))
|
||||
.option(Option(R.string.noisycgm_replacesensor, true))
|
||||
.option(Option(R.string.noisycgm_checksmoothing, true))
|
||||
.hint(Hint(R.string.noisycgm_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.pumpdisconnect_label, R.string.blank, "pumpdisconnect")
|
||||
.option(Option(R.string.pumpdisconnect_unnecessary, false))
|
||||
.option(Option(R.string.pumpdisconnect_missinginsulin, true))
|
||||
.option(Option(R.string.pumpdisconnect_notstop, false))
|
||||
.option(Option(R.string.pumpdisconnect_openloop, false))
|
||||
.hint(Hint(R.string.pumpdisconnect_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.insulin_label, R.string.insulin_ultrarapid, "insulin")
|
||||
.option(Option(R.string.insulin_novorapid, false))
|
||||
.option(Option(R.string.insulin_humalog, false))
|
||||
.option(Option(R.string.insulin_actrapid, false))
|
||||
.option(Option(R.string.insulin_fiasp, true))
|
||||
.hint(Hint(R.string.insulin_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.sensitivity_label, R.string.blank, "sensitivity")
|
||||
.option(Option(R.string.sensitivity_adjust, true))
|
||||
.option(Option(R.string.sensitivity_edit, false))
|
||||
.option(Option(R.string.sensitivity_cannula, true))
|
||||
.option(Option(R.string.sensitivity_time, true))
|
||||
.hint(Hint(R.string.sensitivity_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.objectives_label, R.string.objectives_howtosave, "objectives")
|
||||
.option(Option(R.string.objectives_notesettings, false))
|
||||
.option(Option(R.string.objectives_afterobjective, true))
|
||||
.option(Option(R.string.objectives_afterchange, true))
|
||||
.option(Option(R.string.objectives_afterinitialsetup, true))
|
||||
.hint(Hint(R.string.objectives_hint1))
|
||||
.hint(Hint(R.string.objectives_hint2))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.objectives2_label, R.string.objectives_howtosave, "objectives2")
|
||||
.option(Option(R.string.objectives2_maintenance, true))
|
||||
.option(Option(R.string.objectives2_internalstorage, true))
|
||||
.option(Option(R.string.objectives2_cloud, true))
|
||||
.option(Option(R.string.objectives2_easyrestore, false))
|
||||
.hint(Hint(R.string.objectives_hint1))
|
||||
.hint(Hint(R.string.objectives_hint2))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.update_label, R.string.blank, "update")
|
||||
.option(Option(R.string.update_git, true))
|
||||
.option(Option(R.string.update_askfriend, false))
|
||||
.option(Option(R.string.update_keys, true))
|
||||
.option(Option(R.string.update_asap, true))
|
||||
.hint(Hint(R.string.update_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.troubleshooting_label, R.string.troubleshooting_wheretoask, "troubleshooting")
|
||||
.option(Option(R.string.troubleshooting_fb, true))
|
||||
.option(Option(R.string.troubleshooting_wiki, true))
|
||||
.option(Option(R.string.troubleshooting_gitter, true))
|
||||
.option(Option(R.string.troubleshooting_yourendo, false))
|
||||
.hint(Hint(R.string.troubleshooting_hint1))
|
||||
.hint(Hint(R.string.troubleshooting_hint2))
|
||||
.hint(Hint(R.string.troubleshooting_hint3))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo, "wrongcarbs")
|
||||
.option(Option(R.string.wrongcarbs_addinsulin, false))
|
||||
.option(Option(R.string.wrongcarbs_treatmentstab, true))
|
||||
.option(Option(R.string.wrongcarbs_donothing, false))
|
||||
.option(Option(R.string.wrongcarbs_bolus, false))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.wronginsulin_label, R.string.wronginsulin_whattodo, "wronginsulin")
|
||||
.option(Option(R.string.wronginsulin_careportal, false))
|
||||
.option(Option(R.string.wronginsulin_compare, true))
|
||||
.option(Option(R.string.wronginsulin_prime, true))
|
||||
.option(Option(R.string.wrongcarbs_donothing, false))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.iob_label, R.string.blank, "iob")
|
||||
.option(Option(R.string.iob_value, true))
|
||||
.option(Option(R.string.iob_hightemp, false))
|
||||
.option(Option(R.string.iob_negiob, true))
|
||||
.option(Option(R.string.iob_posiob, true))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.breadgrams_label, R.string.blank, "breadgrams")
|
||||
.option(Option(R.string.breadgrams_grams, true))
|
||||
.option(Option(R.string.breadgrams_exchange, false))
|
||||
.option(Option(R.string.breadgrams_decay, true))
|
||||
.option(Option(R.string.breadgrams_calc, true))
|
||||
.hint(Hint(R.string.breadgrams_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.extendedcarbs_label, R.string.extendedcarbs_handling, "extendedcarbs")
|
||||
.option(Option(R.string.extendedcarbs_future, true))
|
||||
.option(Option(R.string.extendedcarbs_free, false))
|
||||
.option(Option(R.string.extendedcarbs_fat, true))
|
||||
.option(Option(R.string.extendedcarbs_rescue, false))
|
||||
.hint(Hint(R.string.extendedcarbs_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.nsclient_label, R.string.nsclient_howcanyou, "nsclient")
|
||||
.option(Option(R.string.nsclient_nightscout, true))
|
||||
.option(Option(R.string.nsclient_dexcomfollow, true))
|
||||
.option(Option(R.string.nsclient_data, true))
|
||||
.option(Option(R.string.nsclient_fullcontrol, false))
|
||||
.hint(Hint(R.string.nsclient_hint1))
|
||||
)
|
||||
tasks.add(ExamTask(this, R.string.other_medication_label, R.string.other_medication_text, "otherMedicationWarning")
|
||||
.option(Option(R.string.yes, true))
|
||||
.option(Option(R.string.no, false))
|
||||
)
|
||||
for (task in tasks) (task as ExamTask).options.shuffle()
|
||||
|
||||
for (task in tasks) {
|
||||
if (!task.isCompleted()) accomplishedOn = 0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
public class Objective3 extends Objective {
|
||||
@Inject SP sp;
|
||||
@Inject ObjectivesPlugin objectivesPlugin;
|
||||
@Inject ResourceHelper resourceHelper;
|
||||
@Inject NSClientPlugin nsClientPlugin;
|
||||
|
||||
private final int MANUAL_ENACTS_NEEDED = 20;
|
||||
|
||||
@Inject
|
||||
public Objective3(HasAndroidInjector injector) {
|
||||
super(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate);
|
||||
// disable option for skipping objectives for now
|
||||
// hasSpecialInput = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
|
||||
tasks.add(new Task(R.string.objectives_manualenacts) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProgress() {
|
||||
if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED)
|
||||
return resourceHelper.gs(R.string.completed_well_done);
|
||||
else
|
||||
return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) + " / " + MANUAL_ENACTS_NEEDED;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specialActionEnabled() {
|
||||
return NSClientService.isConnected && NSClientService.hasWriteAuth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void specialAction(FragmentActivity activity, String input) {
|
||||
objectivesPlugin.completeObjectives(activity, input);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate) {
|
||||
|
||||
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
|
||||
@Inject lateinit var nsClientPlugin: NSClientPlugin
|
||||
|
||||
init {
|
||||
tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
|
||||
tasks.add(object : Task(this, R.string.objectives_manualenacts) {
|
||||
override fun isCompleted(): Boolean {
|
||||
return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED
|
||||
}
|
||||
|
||||
override val progress: String
|
||||
get() = if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED) resourceHelper.gs(R.string.completed_well_done) else sp.getInt(R.string.key_ObjectivesmanualEnacts, 0).toString() + " / " + MANUAL_ENACTS_NEEDED
|
||||
})
|
||||
}
|
||||
|
||||
override fun specialActionEnabled(): Boolean =
|
||||
NSClientService.isConnected && NSClientService.hasWriteAuth
|
||||
|
||||
override fun specialAction(activity: FragmentActivity, input: String) {
|
||||
objectivesPlugin.completeObjectives(activity, input)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val MANUAL_ENACTS_NEEDED = 20
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
|
||||
public class Objective4 extends Objective {
|
||||
|
||||
public Objective4(HasAndroidInjector injector) {
|
||||
super(injector, "maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
class Objective4(injector: HasAndroidInjector) : Objective(injector, "maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate)
|
|
@ -1,32 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class Objective5 extends Objective {
|
||||
@Inject SafetyPlugin safetyPlugin;
|
||||
|
||||
public Objective5(HasAndroidInjector injector) {
|
||||
super(injector, "maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new MinimumDurationTask(T.days(5).msecs()));
|
||||
tasks.add(new Task(R.string.closedmodeenabled) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
|
||||
safetyPlugin.isClosedLoopAllowed(closedLoopEnabled);
|
||||
return closedLoopEnabled.value();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
class Objective5(injector: HasAndroidInjector) : Objective(injector, "maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate) {
|
||||
|
||||
@Inject lateinit var safetyPlugin: SafetyPlugin
|
||||
|
||||
init {
|
||||
tasks.add(MinimumDurationTask(this, T.days(5).msecs()))
|
||||
tasks.add(object : Task(this, R.string.closedmodeenabled) {
|
||||
override fun isCompleted(): Boolean {
|
||||
val closedLoopEnabled = Constraint(true)
|
||||
safetyPlugin.isClosedLoopAllowed(closedLoopEnabled)
|
||||
return closedLoopEnabled.value()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class Objective6 extends Objective {
|
||||
@Inject ConstraintChecker constraintChecker;
|
||||
|
||||
public Objective6(HasAndroidInjector injector) {
|
||||
super(injector, "maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new MinimumDurationTask(T.days(1).msecs()));
|
||||
tasks.add(new Task(R.string.maxiobset) {
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
double maxIOB = constraintChecker.getMaxIOBAllowed().value();
|
||||
return maxIOB > 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
class Objective6(injector: HasAndroidInjector) : Objective(injector, "maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate) {
|
||||
|
||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
|
||||
init {
|
||||
tasks.add(MinimumDurationTask(this, T.days(1).msecs()))
|
||||
tasks.add(object : Task(this, R.string.maxiobset) {
|
||||
override fun isCompleted(): Boolean {
|
||||
val maxIOB = constraintChecker.getMaxIOBAllowed().value()
|
||||
return maxIOB > 0
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class Objective7 extends Objective {
|
||||
|
||||
public Objective7(HasAndroidInjector injector) {
|
||||
super(injector, "autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
||||
class Objective7(injector: HasAndroidInjector) : Objective(injector, "autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate) {
|
||||
|
||||
init {
|
||||
tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class Objective8 extends Objective {
|
||||
|
||||
public Objective8(HasAndroidInjector injector) {
|
||||
super(injector, "ama", R.string.objectives_ama_objective, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
||||
class Objective8(injector: HasAndroidInjector) : Objective(injector, "ama", R.string.objectives_ama_objective, 0) {
|
||||
|
||||
init {
|
||||
tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class Objective9 extends Objective {
|
||||
|
||||
public Objective9(HasAndroidInjector injector) {
|
||||
super(injector, "smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTasks(List<Task> tasks) {
|
||||
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
||||
class Objective9(injector: HasAndroidInjector) : Objective(injector, "smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate) {
|
||||
|
||||
init {
|
||||
tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
|
||||
}
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.safety;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.BgSourceInterface;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.PumpDescription;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter;
|
||||
import info.nightscout.androidaps.utils.HardLimits;
|
||||
import info.nightscout.androidaps.utils.Round;
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
@Singleton
|
||||
public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
||||
|
||||
private final SP sp;
|
||||
private final RxBusWrapper rxBus;
|
||||
private final ConstraintChecker constraintChecker;
|
||||
private final OpenAPSAMAPlugin openAPSAMAPlugin;
|
||||
private final OpenAPSSMBPlugin openAPSSMBPlugin;
|
||||
private final SensitivityOref1Plugin sensitivityOref1Plugin;
|
||||
private final ActivePluginProvider activePlugin;
|
||||
private final HardLimits hardLimits;
|
||||
private final BuildHelper buildHelper;
|
||||
private final TreatmentsPlugin treatmentsPlugin;
|
||||
private final Config config;
|
||||
|
||||
@Inject
|
||||
public SafetyPlugin(
|
||||
HasAndroidInjector injector,
|
||||
AAPSLogger aapsLogger,
|
||||
ResourceHelper resourceHelper,
|
||||
SP sp,
|
||||
RxBusWrapper rxBus,
|
||||
ConstraintChecker constraintChecker,
|
||||
OpenAPSAMAPlugin openAPSAMAPlugin,
|
||||
OpenAPSSMBPlugin openAPSSMBPlugin,
|
||||
SensitivityOref1Plugin sensitivityOref1Plugin,
|
||||
ActivePluginProvider activePlugin,
|
||||
HardLimits hardLimits,
|
||||
BuildHelper buildHelper,
|
||||
TreatmentsPlugin treatmentsPlugin,
|
||||
Config config
|
||||
) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.CONSTRAINTS)
|
||||
.neverVisible(true)
|
||||
.alwaysEnabled(true)
|
||||
.showInList(false)
|
||||
.pluginName(R.string.safety)
|
||||
.preferencesId(R.xml.pref_safety),
|
||||
aapsLogger, resourceHelper, injector
|
||||
);
|
||||
this.sp = sp;
|
||||
this.rxBus = rxBus;
|
||||
this.constraintChecker = constraintChecker;
|
||||
this.openAPSAMAPlugin = openAPSAMAPlugin;
|
||||
this.openAPSSMBPlugin = openAPSSMBPlugin;
|
||||
this.sensitivityOref1Plugin = sensitivityOref1Plugin;
|
||||
this.activePlugin = activePlugin;
|
||||
this.hardLimits = hardLimits;
|
||||
this.buildHelper = buildHelper;
|
||||
this.treatmentsPlugin = treatmentsPlugin;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constraints interface
|
||||
**/
|
||||
@NonNull @Override
|
||||
public Constraint<Boolean> isLoopInvocationAllowed(@NonNull Constraint<Boolean> value) {
|
||||
if (!activePlugin.getActivePump().getPumpDescription().isTempBasalCapable)
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.pumpisnottempbasalcapable), this);
|
||||
return value;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Boolean> isClosedLoopAllowed(@NonNull Constraint<Boolean> value) {
|
||||
String mode = sp.getString(R.string.key_aps_mode, "open");
|
||||
if ((mode.equals("open")))
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closedmodedisabledinpreferences), this);
|
||||
|
||||
if (!buildHelper.isEngineeringModeOrRelease()) {
|
||||
if (value.value()) {
|
||||
Notification n = new Notification(Notification.TOAST_ALARM, getResourceHelper().gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL);
|
||||
rxBus.send(new EventNewNotification(n));
|
||||
}
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closed_loop_disabled_on_dev_branch), this);
|
||||
}
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
if (!pump.isFakingTempsByExtendedBoluses() && treatmentsPlugin.isInHistoryExtendedBoluslInProgress()) {
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closed_loop_disabled_with_eb), this);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Boolean> isAutosensModeEnabled(@NonNull Constraint<Boolean> value) {
|
||||
boolean enabled = sp.getBoolean(R.string.key_openapsama_useautosens, false);
|
||||
if (!enabled)
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.autosensdisabledinpreferences), this);
|
||||
return value;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Boolean> isSMBModeEnabled(@NonNull Constraint<Boolean> value) {
|
||||
boolean enabled = sp.getBoolean(R.string.key_use_smb, false);
|
||||
if (!enabled)
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbdisabledinpreferences), this);
|
||||
Constraint<Boolean> closedLoop = constraintChecker.isClosedLoopAllowed();
|
||||
if (!closedLoop.value())
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbnotallowedinopenloopmode), this);
|
||||
return value;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Boolean> isUAMEnabled(@NonNull Constraint<Boolean> value) {
|
||||
boolean enabled = sp.getBoolean(R.string.key_use_uam, false);
|
||||
if (!enabled)
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.uamdisabledinpreferences), this);
|
||||
boolean oref1Enabled = sensitivityOref1Plugin.isEnabled(PluginType.SENSITIVITY);
|
||||
if (!oref1Enabled)
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.uamdisabledoref1notselected), this);
|
||||
return value;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Boolean> isAdvancedFilteringEnabled(@NonNull Constraint<Boolean> value) {
|
||||
BgSourceInterface bgSource = activePlugin.getActiveBgSource();
|
||||
|
||||
if (!bgSource.advancedFilteringSupported())
|
||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbalwaysdisabled), this);
|
||||
return value;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, @NonNull Profile profile) {
|
||||
|
||||
absoluteRate.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingbasalratio), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
||||
|
||||
if (config.getAPS()) {
|
||||
double maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1d);
|
||||
if (maxBasal < profile.getMaxDailyBasal()) {
|
||||
maxBasal = profile.getMaxDailyBasal();
|
||||
absoluteRate.addReason(getResourceHelper().gs(R.string.increasingmaxbasal), this);
|
||||
}
|
||||
absoluteRate.setIfSmaller(getAapsLogger(), maxBasal, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxBasal, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
||||
|
||||
// Check percentRate but absolute rate too, because we know real current basal in pump
|
||||
double maxBasalMult = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
|
||||
double maxFromBasalMult = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
|
||||
absoluteRate.setIfSmaller(getAapsLogger(), maxFromBasalMult, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxFromBasalMult, getResourceHelper().gs(R.string.maxbasalmultiplier)), this);
|
||||
|
||||
double maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d);
|
||||
double maxFromDaily = Math.floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100;
|
||||
absoluteRate.setIfSmaller(getAapsLogger(), maxFromDaily, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxFromDaily, getResourceHelper().gs(R.string.maxdailybasalmultiplier)), this);
|
||||
}
|
||||
|
||||
absoluteRate.setIfSmaller(getAapsLogger(), hardLimits.maxBasal(), String.format(getResourceHelper().gs(R.string.limitingbasalratio), hardLimits.maxBasal(), getResourceHelper().gs(R.string.hardlimit)), this);
|
||||
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
// check for pump max
|
||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
|
||||
absoluteRate.setIfSmaller(getAapsLogger(), pumpLimit, String.format(getResourceHelper().gs(R.string.limitingbasalratio), pumpLimit, getResourceHelper().gs(R.string.pumplimit)), this);
|
||||
}
|
||||
|
||||
// do rounding
|
||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
absoluteRate.set(getAapsLogger(), Round.roundTo(absoluteRate.value(), pump.getPumpDescription().tempAbsoluteStep));
|
||||
}
|
||||
return absoluteRate;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
|
||||
|
||||
Double currentBasal = profile.getBasal();
|
||||
double absoluteRate = currentBasal * ((double) percentRate.originalValue() / 100);
|
||||
|
||||
percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this);
|
||||
|
||||
Constraint<Double> absoluteConstraint = new Constraint<>(absoluteRate);
|
||||
applyBasalConstraints(absoluteConstraint, profile);
|
||||
percentRate.copyReasons(absoluteConstraint);
|
||||
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
|
||||
int percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue();
|
||||
if (percentRateAfterConst < 100)
|
||||
percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
|
||||
else
|
||||
percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
|
||||
|
||||
percentRate.set(getAapsLogger(), percentRateAfterConst, String.format(getResourceHelper().gs(R.string.limitingpercentrate), percentRateAfterConst, getResourceHelper().gs(R.string.pumplimit)), this);
|
||||
|
||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT) {
|
||||
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
|
||||
percentRate.setIfSmaller(getAapsLogger(), (int) pumpLimit, String.format(getResourceHelper().gs(R.string.limitingbasalratio), pumpLimit, getResourceHelper().gs(R.string.pumplimit)), this);
|
||||
}
|
||||
|
||||
return percentRate;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
|
||||
insulin.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingbolus), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
||||
|
||||
Double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
|
||||
insulin.setIfSmaller(getAapsLogger(), maxBolus, String.format(getResourceHelper().gs(R.string.limitingbolus), maxBolus, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
||||
|
||||
insulin.setIfSmaller(getAapsLogger(), hardLimits.maxBolus(), String.format(getResourceHelper().gs(R.string.limitingbolus), hardLimits.maxBolus(), getResourceHelper().gs(R.string.hardlimit)), this);
|
||||
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
double rounded = pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value());
|
||||
insulin.setIfDifferent(getAapsLogger(), rounded, getResourceHelper().gs(R.string.pumplimit), this);
|
||||
return insulin;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) {
|
||||
insulin.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingextendedbolus), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
||||
|
||||
Double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
|
||||
insulin.setIfSmaller(getAapsLogger(), maxBolus, String.format(getResourceHelper().gs(R.string.limitingextendedbolus), maxBolus, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
||||
|
||||
insulin.setIfSmaller(getAapsLogger(), hardLimits.maxBolus(), String.format(getResourceHelper().gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), getResourceHelper().gs(R.string.hardlimit)), this);
|
||||
|
||||
PumpInterface pump = activePlugin.getActivePump();
|
||||
double rounded = pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value());
|
||||
insulin.setIfDifferent(getAapsLogger(), rounded, getResourceHelper().gs(R.string.pumplimit), this);
|
||||
return insulin;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
|
||||
carbs.setIfGreater(getAapsLogger(), 0, String.format(getResourceHelper().gs(R.string.limitingcarbs), 0, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
||||
|
||||
Integer maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
|
||||
carbs.setIfSmaller(getAapsLogger(), maxCarbs, String.format(getResourceHelper().gs(R.string.limitingcarbs), maxCarbs, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
||||
|
||||
return carbs;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) {
|
||||
double maxIobPref;
|
||||
String apsmode = sp.getString(R.string.key_aps_mode, "open");
|
||||
if (openAPSSMBPlugin.isEnabled(PluginType.APS))
|
||||
maxIobPref = sp.getDouble(R.string.key_openapssmb_max_iob, 3d);
|
||||
else
|
||||
maxIobPref = sp.getDouble(R.string.key_openapsma_max_iob, 1.5d);
|
||||
maxIob.setIfSmaller(getAapsLogger(), maxIobPref, String.format(getResourceHelper().gs(R.string.limitingiob), maxIobPref, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
||||
|
||||
if (openAPSAMAPlugin.isEnabled(PluginType.APS))
|
||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this);
|
||||
if (openAPSSMBPlugin.isEnabled(PluginType.APS))
|
||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobSMB(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobSMB(), getResourceHelper().gs(R.string.hardlimit)), this);
|
||||
if ((apsmode.equals("lgs")))
|
||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.getMAXIOB_LGS(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.getMAXIOB_LGS(), getResourceHelper().gs(R.string.lowglucosesuspend)), this);
|
||||
|
||||
return maxIob;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.safety
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.Round
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.floor
|
||||
|
||||
@Singleton
|
||||
class SafetyPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val constraintChecker: ConstraintChecker,
|
||||
private val openAPSAMAPlugin: OpenAPSAMAPlugin,
|
||||
private val openAPSSMBPlugin: OpenAPSSMBPlugin,
|
||||
private val sensitivityOref1Plugin: SensitivityOref1Plugin,
|
||||
private val activePlugin: ActivePluginProvider,
|
||||
private val hardLimits: HardLimits,
|
||||
private val buildHelper: BuildHelper,
|
||||
private val treatmentsPlugin: TreatmentsInterface,
|
||||
private val config: Config
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.CONSTRAINTS)
|
||||
.neverVisible(true)
|
||||
.alwaysEnabled(true)
|
||||
.showInList(false)
|
||||
.pluginName(R.string.safety)
|
||||
.preferencesId(R.xml.pref_safety),
|
||||
aapsLogger, resourceHelper, injector
|
||||
), ConstraintsInterface {
|
||||
|
||||
/**
|
||||
* Constraints interface
|
||||
*/
|
||||
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
if (!activePlugin.activePump.pumpDescription.isTempBasalCapable) value[aapsLogger, false, resourceHelper.gs(R.string.pumpisnottempbasalcapable)] = this
|
||||
return value
|
||||
}
|
||||
|
||||
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
val mode = sp.getString(R.string.key_aps_mode, "open")
|
||||
if (mode == "open") value[aapsLogger, false, resourceHelper.gs(R.string.closedmodedisabledinpreferences)] = this
|
||||
if (!buildHelper.isEngineeringModeOrRelease()) {
|
||||
if (value.value()) {
|
||||
val n = Notification(Notification.TOAST_ALARM, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL)
|
||||
rxBus.send(EventNewNotification(n))
|
||||
}
|
||||
value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)] = this
|
||||
}
|
||||
val pump = activePlugin.activePump
|
||||
if (!pump.isFakingTempsByExtendedBoluses && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
|
||||
value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_with_eb)] = this
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
val enabled = sp.getBoolean(R.string.key_openapsama_useautosens, false)
|
||||
if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.autosensdisabledinpreferences)] = this
|
||||
return value
|
||||
}
|
||||
|
||||
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
val enabled = sp.getBoolean(R.string.key_use_smb, false)
|
||||
if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.smbdisabledinpreferences)] = this
|
||||
val closedLoop = constraintChecker.isClosedLoopAllowed()
|
||||
if (!closedLoop.value()) value[aapsLogger, false, resourceHelper.gs(R.string.smbnotallowedinopenloopmode)] = this
|
||||
return value
|
||||
}
|
||||
|
||||
override fun isUAMEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
val enabled = sp.getBoolean(R.string.key_use_uam, false)
|
||||
if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.uamdisabledinpreferences)] = this
|
||||
val oref1Enabled = sensitivityOref1Plugin.isEnabled(PluginType.SENSITIVITY)
|
||||
if (!oref1Enabled) value[aapsLogger, false, resourceHelper.gs(R.string.uamdisabledoref1notselected)] = this
|
||||
return value
|
||||
}
|
||||
|
||||
override fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||
val bgSource = activePlugin.activeBgSource
|
||||
if (!bgSource.advancedFilteringSupported()) value[aapsLogger, false, resourceHelper.gs(R.string.smbalwaysdisabled)] = this
|
||||
return value
|
||||
}
|
||||
|
||||
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> {
|
||||
absoluteRate.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingbasalratio), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||
if (config.APS) {
|
||||
var maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1.0)
|
||||
if (maxBasal < profile.maxDailyBasal) {
|
||||
maxBasal = profile.maxDailyBasal
|
||||
absoluteRate.addReason(resourceHelper.gs(R.string.increasingmaxbasal), this)
|
||||
}
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxBasal, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxBasal, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||
|
||||
// Check percentRate but absolute rate too, because we know real current basal in pump
|
||||
val maxBasalMultiplier = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)
|
||||
val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.basal * 100) / 100
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxFromBasalMultiplier, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxFromBasalMultiplier, resourceHelper.gs(R.string.maxbasalmultiplier)), this)
|
||||
val maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)
|
||||
val maxFromDaily = floor(profile.maxDailyBasal * maxBasalFromDaily * 100) / 100
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxFromDaily, resourceHelper.gs(R.string.maxdailybasalmultiplier)), this)
|
||||
}
|
||||
absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(), String.format(resourceHelper.gs(R.string.limitingbasalratio), hardLimits.maxBasal(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||
val pump = activePlugin.activePump
|
||||
// check for pump max
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
|
||||
absoluteRate.setIfSmaller(aapsLogger, pumpLimit, String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this)
|
||||
}
|
||||
|
||||
// do rounding
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
absoluteRate[aapsLogger] = Round.roundTo(absoluteRate.value(), pump.pumpDescription.tempAbsoluteStep)
|
||||
}
|
||||
return absoluteRate
|
||||
}
|
||||
|
||||
override fun applyBasalPercentConstraints(percentRate: Constraint<Int>, profile: Profile): Constraint<Int> {
|
||||
val currentBasal = profile.basal
|
||||
val absoluteRate = currentBasal * (percentRate.originalValue().toDouble() / 100)
|
||||
percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this)
|
||||
val absoluteConstraint = Constraint(absoluteRate)
|
||||
applyBasalConstraints(absoluteConstraint, profile)
|
||||
percentRate.copyReasons(absoluteConstraint)
|
||||
val pump = activePlugin.activePump
|
||||
var percentRateAfterConst = java.lang.Double.valueOf(absoluteConstraint.value() / currentBasal * 100).toInt()
|
||||
percentRateAfterConst = if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt()
|
||||
percentRate[aapsLogger, percentRateAfterConst, String.format(resourceHelper.gs(R.string.limitingpercentrate), percentRateAfterConst, resourceHelper.gs(R.string.pumplimit))] = this
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
|
||||
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
|
||||
percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this)
|
||||
}
|
||||
return percentRate
|
||||
}
|
||||
|
||||
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
|
||||
insulin.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingbolus), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
|
||||
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(resourceHelper.gs(R.string.limitingbolus), maxBolus, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(resourceHelper.gs(R.string.limitingbolus), hardLimits.maxBolus(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||
val pump = activePlugin.activePump
|
||||
val rounded = pump.pumpDescription.pumpType.determineCorrectBolusSize(insulin.value())
|
||||
insulin.setIfDifferent(aapsLogger, rounded, resourceHelper.gs(R.string.pumplimit), this)
|
||||
return insulin
|
||||
}
|
||||
|
||||
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
|
||||
insulin.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingextendedbolus), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
|
||||
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(resourceHelper.gs(R.string.limitingextendedbolus), maxBolus, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(resourceHelper.gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||
val pump = activePlugin.activePump
|
||||
val rounded = pump.pumpDescription.pumpType.determineCorrectExtendedBolusSize(insulin.value())
|
||||
insulin.setIfDifferent(aapsLogger, rounded, resourceHelper.gs(R.string.pumplimit), this)
|
||||
return insulin
|
||||
}
|
||||
|
||||
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> {
|
||||
carbs.setIfGreater(aapsLogger, 0, String.format(resourceHelper.gs(R.string.limitingcarbs), 0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||
val maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48)
|
||||
carbs.setIfSmaller(aapsLogger, maxCarbs, String.format(resourceHelper.gs(R.string.limitingcarbs), maxCarbs, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||
return carbs
|
||||
}
|
||||
|
||||
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
|
||||
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||
val maxIobPref: Double = if (openAPSSMBPlugin.isEnabled(PluginType.APS)) sp.getDouble(R.string.key_openapssmb_max_iob, 3.0) else sp.getDouble(R.string.key_openapsma_max_iob, 1.5)
|
||||
maxIob.setIfSmaller(aapsLogger, maxIobPref, String.format(resourceHelper.gs(R.string.limitingiob), maxIobPref, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||
if (openAPSAMAPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobAMA(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||
if (openAPSSMBPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobSMB(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, hardLimits.MAXIOB_LGS, String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.MAXIOB_LGS, resourceHelper.gs(R.string.lowglucosesuspend)), this)
|
||||
return maxIob
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
|||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||
import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler
|
||||
|
@ -32,7 +33,6 @@ import info.nightscout.androidaps.skins.SkinProvider
|
|||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
@ -41,6 +41,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
|||
import info.nightscout.androidaps.utils.ui.SingleClickButton
|
||||
import info.nightscout.androidaps.utils.ui.UIRunnable
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -61,6 +62,7 @@ class ActionsFragment : DaggerFragment() {
|
|||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
@Inject lateinit var skinProvider: SkinProvider
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
|
@ -152,16 +154,11 @@ class ActionsFragment : DaggerFragment() {
|
|||
}
|
||||
extendedBolusCancel?.setOnClickListener {
|
||||
if (activePlugin.activeTreatments.isInHistoryExtendedBoluslInProgress) {
|
||||
aapsLogger.debug("USER ENTRY: CANCEL EXTENDED BOLUS")
|
||||
uel.log("CANCEL EXTENDED BOLUS")
|
||||
commandQueue.cancelExtended(object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -172,16 +169,11 @@ class ActionsFragment : DaggerFragment() {
|
|||
}
|
||||
cancelTempBasal?.setOnClickListener {
|
||||
if (activePlugin.activeTreatments.isTempBasalInProgress) {
|
||||
aapsLogger.debug("USER ENTRY: CANCEL TEMP BASAL")
|
||||
uel.log("CANCEL TEMP BASAL")
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.boluserror)
|
||||
i.putExtra("status", result.comment)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(i)
|
||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -264,10 +256,10 @@ class ActionsFragment : DaggerFragment() {
|
|||
profileSwitch?.visibility = (
|
||||
activePlugin.activeProfileInterface.profile != null &&
|
||||
pump.pumpDescription.isSetBasalProfileCapable &&
|
||||
pump.isInitialized &&
|
||||
!pump.isSuspended).toVisibility()
|
||||
pump.isInitialized() &&
|
||||
!pump.isSuspended()).toVisibility()
|
||||
|
||||
if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized || pump.isSuspended || pump.isFakingTempsByExtendedBoluses) {
|
||||
if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses) {
|
||||
extendedBolus?.visibility = View.GONE
|
||||
extendedBolusCancel?.visibility = View.GONE
|
||||
} else {
|
||||
|
@ -283,7 +275,7 @@ class ActionsFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized || pump.isSuspended) {
|
||||
if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized() || pump.isSuspended()) {
|
||||
setTempBasal?.visibility = View.GONE
|
||||
cancelTempBasal?.visibility = View.GONE
|
||||
} else {
|
||||
|
@ -300,7 +292,7 @@ class ActionsFragment : DaggerFragment() {
|
|||
}
|
||||
val activeBgSource = activePlugin.activeBgSource
|
||||
historyBrowser?.visibility = (profile != null).toVisibility()
|
||||
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized && !pump.isSuspended).toVisibility()
|
||||
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility()
|
||||
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
|
||||
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
|
||||
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
|
||||
|
@ -320,7 +312,7 @@ class ActionsFragment : DaggerFragment() {
|
|||
|
||||
private fun checkPumpCustomActions() {
|
||||
val activePump = activePlugin.activePump
|
||||
val customActions = activePump.customActions ?: return
|
||||
val customActions = activePump.getCustomActions() ?: return
|
||||
val currentContext = context ?: return
|
||||
removePumpCustomActions()
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class AutomationEvent(private val injector: HasAndroidInjector) {
|
|||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
|
||||
var title: String? = null
|
||||
var title: String = ""
|
||||
var isEnabled = true
|
||||
var systemAction: Boolean = false // true = generated by AAPS, false = entered by user
|
||||
var readOnly: Boolean = false // removing, editing disabled
|
||||
|
|
|
@ -20,6 +20,7 @@ import dagger.android.support.DaggerFragment
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.databinding.AutomationEventItemBinding
|
||||
import info.nightscout.androidaps.databinding.AutomationFragmentBinding
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter
|
||||
|
@ -31,8 +32,8 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventAutomat
|
|||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
|
@ -48,6 +49,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var automationPlugin: AutomationPlugin
|
||||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private lateinit var eventListAdapter: EventListAdapter
|
||||
|
@ -212,11 +214,12 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
}
|
||||
// remove event
|
||||
holder.binding.iconTrash.setOnClickListener {
|
||||
showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
|
||||
Runnable {
|
||||
OKDialog.showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
|
||||
{
|
||||
uel.log("AUTOM REMOVED", automationPlugin.at(position).title)
|
||||
automationPlugin.removeAt(position)
|
||||
notifyItemRemoved(position)
|
||||
}, Runnable {
|
||||
}, {
|
||||
rxBus.send(EventAutomationUpdateGui())
|
||||
})
|
||||
}
|
||||
|
@ -234,8 +237,9 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
|
||||
override fun onItemDismiss(position: Int) {
|
||||
activity?.let { activity ->
|
||||
showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
|
||||
Runnable {
|
||||
uel.log("AUTOM REMOVED", automationPlugin.at(position).title)
|
||||
automationPlugin.removeAt(position)
|
||||
notifyItemRemoved(position)
|
||||
rxBus.send(EventAutomationDataChanged())
|
||||
|
|
|
@ -30,7 +30,7 @@ import info.nightscout.androidaps.services.LocationServiceHelper
|
|||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.DrawableRes
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.activities.PreferencesActivity
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationUserMessage
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.JsonHelper
|
||||
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.TimerUtil
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
|
@ -28,28 +23,24 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
|
|||
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var nsUpload: NSUpload
|
||||
@Inject lateinit var context: Context
|
||||
@Inject lateinit var timerUtil: TimerUtil
|
||||
|
||||
var text = InputString(injector)
|
||||
|
||||
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
|
||||
this.text = InputString(injector, text)
|
||||
}
|
||||
|
||||
override fun friendlyName(): Int = R.string.alarm
|
||||
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
|
||||
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
|
||||
|
||||
override fun isValid(): Boolean = text.value.isNotEmpty()
|
||||
override fun isValid(): Boolean = true // empty alarm will show app name
|
||||
|
||||
override fun doAction(callback: Callback) {
|
||||
val i = Intent(context, ErrorHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.modern_alarm)
|
||||
i.putExtra("status", text.value)
|
||||
i.putExtra("title", resourceHelper.gs(R.string.alarm))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(i)
|
||||
|
||||
timerUtil.scheduleReminder(DateUtil.now() + T.secs(10L).msecs(), text.value.takeIf { it.isNotBlank() }
|
||||
?: resourceHelper.gs(R.string.app_name))
|
||||
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventAutomat
|
|||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
|
|
@ -16,7 +16,7 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
|
|||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import org.json.JSONObject
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.StringRes
|
||||
import com.dpro.widgets.WeekdaysPicker
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.utils.ui.WeekdayPicker
|
||||
import java.util.*
|
||||
|
||||
class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
||||
|
@ -56,7 +54,7 @@ class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
|||
for (day in DayOfWeek.values()) set(day, false)
|
||||
}
|
||||
|
||||
fun setAll(value:Boolean) {
|
||||
fun setAll(value: Boolean) {
|
||||
for (day in DayOfWeek.values()) set(day, value)
|
||||
}
|
||||
|
||||
|
@ -78,13 +76,10 @@ class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
|||
}
|
||||
|
||||
override fun addToLayout(root: LinearLayout) {
|
||||
val weekdaysPicker = WeekdaysPicker(root.context)
|
||||
weekdaysPicker.setEditable(true)
|
||||
weekdaysPicker.selectedDays = getSelectedDays()
|
||||
weekdaysPicker.setOnWeekdaysChangeListener { _: View?, i: Int, list: List<Int?> -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)) }
|
||||
weekdaysPicker.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
weekdaysPicker.sundayFirstDay = Calendar.getInstance().firstDayOfWeek == Calendar.SUNDAY
|
||||
weekdaysPicker.redrawDays()
|
||||
root.addView(weekdaysPicker)
|
||||
WeekdayPicker(root.context).apply {
|
||||
setSelectedDays(getSelectedDays())
|
||||
setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) }
|
||||
root.addView(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,15 +11,15 @@ import com.google.common.base.Optional
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerChanged
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerClone
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerRemove
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.services.LastLocationDataContainer
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -29,13 +29,14 @@ import javax.inject.Inject
|
|||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
abstract class Trigger(val injector: HasAndroidInjector) {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var locationDataContainer: LastLocationDataContainer
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var treatmentsInterface: TreatmentsInterface
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||
|
||||
|
@ -53,12 +54,13 @@ abstract class Trigger(val injector: HasAndroidInjector) {
|
|||
abstract fun duplicate(): Trigger
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun scanForActivity(cont: Context?): AppCompatActivity? {
|
||||
when (cont) {
|
||||
null -> return null
|
||||
null -> return null
|
||||
is AppCompatActivity -> return cont
|
||||
is ContextWrapper -> return scanForActivity(cont.baseContext)
|
||||
is ContextWrapper -> return scanForActivity(cont.baseContext)
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) {
|
|||
}
|
||||
|
||||
override fun shouldRun(): Boolean {
|
||||
val lastBolusTime = treatmentsPlugin.getLastBolusTime(true)
|
||||
val lastBolusTime = treatmentsInterface.getLastBolusTime(true)
|
||||
if (lastBolusTime == 0L)
|
||||
return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
|
||||
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
||||
|
|
|
@ -73,8 +73,8 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) {
|
|||
false
|
||||
}
|
||||
val calculatedDelta = when (delta.deltaType) {
|
||||
DeltaType.SHORT_AVERAGE -> glucoseStatus.short_avgdelta
|
||||
DeltaType.LONG_AVERAGE -> glucoseStatus.long_avgdelta
|
||||
DeltaType.SHORT_AVERAGE -> glucoseStatus.shortAvgDelta
|
||||
DeltaType.LONG_AVERAGE -> glucoseStatus.longAvgDelta
|
||||
else -> glucoseStatus.delta
|
||||
}
|
||||
if (comparator.value.check(calculatedDelta, Profile.toMgdl(delta.value, units))) {
|
||||
|
|
|
@ -28,7 +28,7 @@ class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) {
|
|||
}
|
||||
|
||||
override fun shouldRun(): Boolean {
|
||||
val tt = treatmentsPlugin.tempTargetFromHistory
|
||||
val tt = treatmentsInterface.tempTargetFromHistory
|
||||
if (tt == null && comparator.value == ComparatorExists.Compare.NOT_EXISTS) {
|
||||
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
||||
return true
|
||||
|
|
|
@ -130,7 +130,7 @@ class DataBroadcastPlugin @Inject constructor(
|
|||
bundle.putString("units", profileFunction.getUnits()) // units used in AAPS "mg/dl" or "mmol"
|
||||
bundle.putString("slopeArrow", lastBG.trendArrow.text) // direction arrow as string
|
||||
bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl
|
||||
bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgdelta) // average bg delta
|
||||
bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgDelta) // average bg delta
|
||||
bundle.putDouble("high", defaultValueHelper.determineHighLine()) // predefined top value of in range (green area)
|
||||
bundle.putDouble("low", defaultValueHelper.determineLowLine()) // predefined bottom value of in range
|
||||
}
|
||||
|
|
|
@ -18,11 +18,12 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.databinding.FoodFragmentBinding
|
||||
import info.nightscout.androidaps.databinding.FoodItemBinding
|
||||
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
@ -38,6 +39,7 @@ class FoodFragment : DaggerFragment() {
|
|||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var foodPlugin: FoodPlugin
|
||||
@Inject lateinit var nsUpload: NSUpload
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private lateinit var unfiltered: List<Food>
|
||||
|
@ -213,7 +215,8 @@ class FoodFragment : DaggerFragment() {
|
|||
binding.remove.setOnClickListener { v: View ->
|
||||
val food = v.tag as Food
|
||||
activity?.let { activity ->
|
||||
showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int ->
|
||||
uel.log("FOOD REMOVED", food.name)
|
||||
if (food._id != null && food._id != "") {
|
||||
nsUpload.removeFoodFromNS(food._id)
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@ import info.nightscout.androidaps.interfaces.ConfigInterface
|
|||
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
|
||||
import info.nightscout.androidaps.utils.AndroidPermission
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
|
||||
import info.nightscout.androidaps.utils.alertDialogs.PrefImportSummaryDialog
|
||||
import info.nightscout.androidaps.utils.alertDialogs.TwoMessagesAlertDialog
|
||||
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
|
||||
|
@ -58,7 +58,8 @@ class ImportExportPrefs @Inject constructor(
|
|||
private val androidPermission: AndroidPermission,
|
||||
private val classicPrefsFormat: ClassicPrefsFormat,
|
||||
private val encryptedPrefsFormat: EncryptedPrefsFormat,
|
||||
private val prefFileList: PrefFileListProvider
|
||||
private val prefFileList: PrefFileListProvider,
|
||||
private val uel: UserEntryLogger
|
||||
) : ImportExportPrefsInterface {
|
||||
|
||||
override fun prefsFileExists(): Boolean {
|
||||
|
@ -342,7 +343,8 @@ class ImportExportPrefs @Inject constructor(
|
|||
|
||||
private fun restartAppAfterImport(context: Context) {
|
||||
sp.putBoolean(R.string.key_setupwizard_processed, true)
|
||||
show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
|
||||
OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
|
||||
uel.log("IMPORT")
|
||||
log.debug(LTag.CORE, "Exiting")
|
||||
rxBus.send(EventAppExit())
|
||||
if (context is AppCompatActivity) {
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.maintenance;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
|
||||
/**
|
||||
* This class provides serveral methods for log-handling (eg. sending logs as emails).
|
||||
*/
|
||||
public class LoggerUtils {
|
||||
|
||||
public static String SUFFIX = ".log.zip";
|
||||
|
||||
/**
|
||||
* Returns the directory, in which the logs are stored on the system. This is configured in the
|
||||
* logback.xml file.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getLogDirectory() {
|
||||
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
return lc.getProperty("EXT_FILES_DIR");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package info.nightscout.androidaps.plugins.general.maintenance
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext
|
||||
import org.slf4j.LoggerFactory
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* This class provides several methods for log-handling (eg. sending logs as emails).
|
||||
*/
|
||||
@Singleton
|
||||
class LoggerUtils @Inject constructor() {
|
||||
|
||||
var suffix = ".log.zip"
|
||||
|
||||
/**
|
||||
* Returns the directory, in which the logs are stored on the system. This is configured in the
|
||||
* logback.xml file.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
val logDirectory: String
|
||||
get() {
|
||||
val lc = LoggerFactory.getILoggerFactory() as LoggerContext
|
||||
return lc.getProperty("EXT_FILES_DIR")
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
|
|||
import info.nightscout.androidaps.events.EventNewBG
|
||||
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
||||
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
||||
|
@ -36,6 +37,7 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
|
@ -54,13 +56,13 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
|
||||
binding.logDelete.setOnClickListener {
|
||||
aapsLogger.debug("USER ENTRY: DELETE LOGS")
|
||||
uel.log("DELETE LOGS")
|
||||
maintenancePlugin.deleteLogs()
|
||||
}
|
||||
binding.navResetdb.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
|
||||
aapsLogger.debug("USER ENTRY: RESET DATABASES")
|
||||
uel.log("RESET DATABASES")
|
||||
compositeDisposable.add(
|
||||
fromAction {
|
||||
MainApp.getDbHelper().resetDatabases()
|
||||
|
@ -81,14 +83,14 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
binding.navExport.setOnClickListener {
|
||||
aapsLogger.debug("USER ENTRY: EXPORT SETTINGS")
|
||||
uel.log("EXPORT SETTINGS")
|
||||
// start activity for checking permissions...
|
||||
importExportPrefs.verifyStoragePermissions(this) {
|
||||
importExportPrefs.exportSharedPreferences(this)
|
||||
}
|
||||
}
|
||||
binding.navImport.setOnClickListener {
|
||||
aapsLogger.debug("USER ENTRY: IMPORT SETTINGS")
|
||||
uel.log("IMPORT SETTINGS")
|
||||
// start activity for checking permissions...
|
||||
importExportPrefs.verifyStoragePermissions(this) {
|
||||
importExportPrefs.importSharedPreferences(this)
|
||||
|
|
|
@ -34,7 +34,8 @@ class MaintenancePlugin @Inject constructor(
|
|||
private val nsSettingsStatus: NSSettingsStatus,
|
||||
aapsLogger: AAPSLogger,
|
||||
private val buildHelper: BuildHelper,
|
||||
private val config: Config
|
||||
private val config: Config,
|
||||
private val loggerUtils: LoggerUtils
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(MaintenanceFragment::class.java.name)
|
||||
|
@ -51,8 +52,7 @@ class MaintenancePlugin @Inject constructor(
|
|||
fun sendLogs() {
|
||||
val recipient = sp.getString(R.string.key_maintenance_logs_email, "logs@androidaps.org")
|
||||
val amount = sp.getInt(R.string.key_maintenance_logs_amount, 2)
|
||||
val logDirectory = LoggerUtils.getLogDirectory()
|
||||
val logs = getLogFiles(logDirectory, amount)
|
||||
val logs = getLogFiles(amount)
|
||||
val zipDir = context.getExternalFilesDir("exports")
|
||||
val zipFile = File(zipDir, constructName())
|
||||
aapsLogger.debug("zipFile: ${zipFile.absolutePath}")
|
||||
|
@ -66,29 +66,27 @@ class MaintenancePlugin @Inject constructor(
|
|||
//todo replace this with a call on startup of the application, specifically to remove
|
||||
// unnecessary garbage from the log exports
|
||||
fun deleteLogs() {
|
||||
LoggerUtils.getLogDirectory()?.let { logDirectory ->
|
||||
val logDir = File(logDirectory)
|
||||
val files = logDir.listFiles { _: File?, name: String ->
|
||||
(name.startsWith("AndroidAPS") && name.endsWith(".zip"))
|
||||
val logDir = File(loggerUtils.logDirectory)
|
||||
val files = logDir.listFiles { _: File?, name: String ->
|
||||
(name.startsWith("AndroidAPS") && name.endsWith(".zip"))
|
||||
}
|
||||
Arrays.sort(files) { f1: File, f2: File -> f1.name.compareTo(f2.name) }
|
||||
var delFiles = listOf(*files)
|
||||
val amount = sp.getInt(R.string.key_logshipper_amount, 2)
|
||||
val keepIndex = amount - 1
|
||||
if (keepIndex < delFiles.size) {
|
||||
delFiles = delFiles.subList(keepIndex, delFiles.size)
|
||||
for (file in delFiles) {
|
||||
file.delete()
|
||||
}
|
||||
Arrays.sort(files) { f1: File, f2: File -> f1.name.compareTo(f2.name) }
|
||||
var delFiles = listOf(*files)
|
||||
val amount = sp.getInt(R.string.key_logshipper_amount, 2)
|
||||
val keepIndex = amount - 1
|
||||
if (keepIndex < delFiles.size) {
|
||||
delFiles = delFiles.subList(keepIndex, delFiles.size)
|
||||
for (file in delFiles) {
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
val exportDir = File(logDirectory, "exports")
|
||||
if (exportDir.exists()) {
|
||||
val expFiles = exportDir.listFiles()
|
||||
for (file in expFiles) {
|
||||
file.delete()
|
||||
}
|
||||
exportDir.delete()
|
||||
}
|
||||
val exportDir = File(loggerUtils.logDirectory, "exports")
|
||||
if (exportDir.exists()) {
|
||||
val expFiles = exportDir.listFiles()
|
||||
for (file in expFiles) {
|
||||
file.delete()
|
||||
}
|
||||
exportDir.delete()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,17 +96,16 @@ class MaintenancePlugin @Inject constructor(
|
|||
*
|
||||
* The log files are sorted by the name descending.
|
||||
*
|
||||
* @param directory
|
||||
* @param amount
|
||||
* @return
|
||||
*/
|
||||
fun getLogFiles(directory: String, amount: Int): List<File> {
|
||||
aapsLogger.debug("getting $amount logs from directory $directory")
|
||||
val logDir = File(directory)
|
||||
fun getLogFiles(amount: Int): List<File> {
|
||||
aapsLogger.debug("getting $amount logs from directory ${loggerUtils.logDirectory}")
|
||||
val logDir = File(loggerUtils.logDirectory)
|
||||
val files = logDir.listFiles { _: File?, name: String ->
|
||||
(name.startsWith("AndroidAPS")
|
||||
&& (name.endsWith(".log")
|
||||
|| name.endsWith(".zip") && !name.endsWith(LoggerUtils.SUFFIX)))
|
||||
|| name.endsWith(".zip") && !name.endsWith(loggerUtils.suffix)))
|
||||
}
|
||||
Arrays.sort(files) { f1: File, f2: File -> f2.name.compareTo(f1.name) }
|
||||
val result = listOf(*files)
|
||||
|
@ -139,7 +136,7 @@ class MaintenancePlugin @Inject constructor(
|
|||
* @return
|
||||
*/
|
||||
private fun constructName(): String {
|
||||
return "AndroidAPS_LOG_" + Date().time + LoggerUtils.SUFFIX
|
||||
return "AndroidAPS_LOG_" + Date().time + loggerUtils.suffix
|
||||
}
|
||||
|
||||
private fun zip(zipFile: File?, files: List<File>) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import javax.inject.Inject;
|
|||
|
||||
import dagger.android.support.DaggerFragment;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
|
||||
|
@ -36,6 +37,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
|
|||
@Inject UploadQueue uploadQueue;
|
||||
@Inject FabricPrivacy fabricPrivacy;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject UserEntryLogger uel;
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
|
@ -121,6 +123,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
|
|||
break;
|
||||
case R.id.nsclientinternal_clearqueue:
|
||||
OKDialog.showConfirmation(getContext(), resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), () -> {
|
||||
uel.log("NS QUEUE CLEARED", "", 0.0, 0.0, 0, 0);
|
||||
uploadQueue.clearQueue();
|
||||
updateGui();
|
||||
fabricPrivacy.logCustom("NSClientClearQueue");
|
||||
|
@ -136,6 +139,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
|
|||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
switch (buttonView.getId()) {
|
||||
case R.id.nsclientinternal_paused:
|
||||
uel.log("NS PAUSED", "", 0.0, 0.0, isChecked ? 1 : 0, 0);
|
||||
nsClientPlugin.pause(isChecked);
|
||||
updateGui();
|
||||
fabricPrivacy.logCustom("NSClientPause");
|
||||
|
|
|
@ -5,6 +5,7 @@ import info.nightscout.androidaps.Config
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
|
@ -116,7 +117,8 @@ class NSSettingsStatus @Inject constructor(
|
|||
private val rxBus: RxBusWrapper,
|
||||
private val defaultValueHelper: DefaultValueHelper,
|
||||
private val sp: SP,
|
||||
private val config: Config
|
||||
private val config: Config,
|
||||
private val uel: UserEntryLogger
|
||||
) {
|
||||
|
||||
var nightscoutVersionName = ""
|
||||
|
@ -127,7 +129,7 @@ class NSSettingsStatus @Inject constructor(
|
|||
fun handleNewData(nightscoutVersionName: String, nightscoutVersionCode: Int, status: JSONObject) {
|
||||
this.nightscoutVersionName = nightscoutVersionName
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: $nightscoutVersionName")
|
||||
if (nightscoutVersionCode < config.SUPPORTEDNSVERSION) {
|
||||
if (nightscoutVersionCode != 0 && nightscoutVersionCode < config.SUPPORTEDNSVERSION) {
|
||||
val notification = Notification(Notification.OLD_NS, resourceHelper.gs(R.string.unsupportednsversion), Notification.NORMAL)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
} else {
|
||||
|
@ -233,6 +235,7 @@ class NSSettingsStatus @Inject constructor(
|
|||
getExtendedWarnValue("sage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_sage_critical, it) }
|
||||
getExtendedWarnValue("bage", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) }
|
||||
getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, it) }
|
||||
uel.log("NS SETTINGS COPIED")
|
||||
}
|
||||
|
||||
if (context != null) OKDialog.showConfirmation(context, resourceHelper.gs(R.string.statuslights), resourceHelper.gs(R.string.copyexistingvalues), action)
|
||||
|
|
|
@ -16,7 +16,7 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.BackpressureStrategy
|
||||
|
|
|
@ -27,7 +27,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
|||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -363,7 +363,7 @@ class OpenHumansUploader @Inject constructor(
|
|||
copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
|
||||
.andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows + treatmentsPlugin.service.count()) })
|
||||
.doOnSuccess { maxProgress = it }
|
||||
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } }
|
||||
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } }
|
||||
.map { enqueueTreatment(it); increaseCounter() }
|
||||
.ignoreElements()
|
||||
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
|
||||
|
|
|
@ -33,6 +33,7 @@ import info.nightscout.androidaps.dialogs.*
|
|||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
|
@ -42,7 +43,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
|||
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||
|
@ -98,7 +99,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
||||
@Inject lateinit var xdripPlugin: XdripPlugin
|
||||
@Inject lateinit var notificationStore: NotificationStore
|
||||
@Inject lateinit var actionStringHandler: ActionStringHandler
|
||||
@Inject lateinit var quickWizard: QuickWizard
|
||||
@Inject lateinit var buildHelper: BuildHelper
|
||||
@Inject lateinit var commandQueue: CommandQueue
|
||||
|
@ -109,6 +109,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
|
@ -341,10 +342,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
|
||||
?: "".toSpanned(), {
|
||||
aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL")
|
||||
uel.log("ACCEPT TEMP BASAL")
|
||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
||||
actionStringHandler.handleInitiate("cancelChangeRequest")
|
||||
rxBus.send(EventWearDoAction("cancelChangeRequest"))
|
||||
loopPlugin.acceptChangeRequest()
|
||||
})
|
||||
})
|
||||
|
@ -445,7 +446,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
// QuickWizard button
|
||||
val quickWizardEntry = quickWizard.getActive()
|
||||
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized && !pump.isSuspended) {
|
||||
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized() && !pump.isSuspended()) {
|
||||
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
|
||||
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false)
|
||||
binding.buttonsLayout.quickWizardButton.text = quickWizardEntry.buttonText() + "\n" + resourceHelper.gs(R.string.format_carbs, quickWizardEntry.carbs()) +
|
||||
|
@ -462,7 +463,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
(lastRun.lastOpenModeAccept == 0L || lastRun.lastOpenModeAccept < lastRun.lastAPSRun) &&// never accepted or before last result
|
||||
lastRun.constraintsProcessed?.isChangeRequested == true // change is requested
|
||||
|
||||
if (showAcceptButton && pump.isInitialized && !pump.isSuspended && loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
if (showAcceptButton && pump.isInitialized() && !pump.isSuspended() && loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
binding.buttonsLayout.acceptTempButton.visibility = View.VISIBLE
|
||||
binding.buttonsLayout.acceptTempButton.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
|
||||
} else {
|
||||
|
@ -470,10 +471,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
|
||||
// **** Various treatment buttons ****
|
||||
binding.buttonsLayout.carbsButton.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized && !pump.isSuspended) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
|
||||
binding.buttonsLayout.treatmentButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
|
||||
binding.buttonsLayout.wizardButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
|
||||
binding.buttonsLayout.insulinButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
|
||||
binding.buttonsLayout.carbsButton.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized() && !pump.isSuspended()) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
|
||||
binding.buttonsLayout.treatmentButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
|
||||
binding.buttonsLayout.wizardButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
|
||||
binding.buttonsLayout.insulinButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
|
||||
|
||||
// **** Calibration & CGM buttons ****
|
||||
val xDripIsBgSource = xdripPlugin.isEnabled(PluginType.BGSOURCE)
|
||||
|
@ -587,8 +588,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
binding.infoLayout.deltaLarge.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.deltaLarge.setTextColor(color)
|
||||
binding.infoLayout.delta.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||
} else {
|
||||
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
||||
binding.infoLayout.avgDelta.text = ""
|
||||
|
@ -632,7 +633,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
binding.infoLayout.apsModeText.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
pump.isSuspended -> {
|
||||
pump.isSuspended() -> {
|
||||
binding.infoLayout.apsMode.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Omnipod_Eros) {
|
||||
// For Omnipod, indicate the pump as disconnected when it's suspended.
|
||||
// The only way to 'reconnect' it, is through the Omnipod tab
|
||||
|
@ -860,7 +861,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
graphData.addTreatments(fromTime, endTime)
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
graphData.setNumVerticalLables()
|
||||
graphData.setNumVerticalLabels()
|
||||
graphData.formatAxis(fromTime, endTime)
|
||||
|
||||
|
||||
|
@ -887,23 +888,25 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
var useDevForScale = false
|
||||
var useRatioForScale = false
|
||||
var useDSForScale = false
|
||||
var useIAForScale = false
|
||||
var useBGIForScale = false
|
||||
when {
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
|
||||
}
|
||||
val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
|
||||
val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
|
||||
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, now, useABSForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal])
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0, alignDevBgiScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, endTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
|
@ -924,7 +927,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] ||
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] ||
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
|
||||
).toVisibility()
|
||||
secondaryGraphsData[g].performUpdate()
|
||||
|
|
|
@ -40,7 +40,8 @@ class OverviewMenus @Inject constructor(
|
|||
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true,shortnameId = R.string.cob),
|
||||
DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true,shortnameId = R.string.deviation_shortname),
|
||||
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true,shortnameId = R.string.sensitivity_shortname),
|
||||
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = true,shortnameId = R.string.activity_shortname),
|
||||
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = false,shortnameId = R.string.activity_shortname),
|
||||
BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.bgi_shortname),
|
||||
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true,shortnameId = R.string.devslope_shortname)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
|
|
@ -17,7 +17,7 @@ import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWiza
|
|||
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
|
|
@ -66,7 +66,7 @@ class GraphData(
|
|||
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
||||
if (bgReadingsArray?.isEmpty() != false) {
|
||||
aapsLogger.debug("No BG data.")
|
||||
maxY = 10.0
|
||||
maxY = if (units == Constants.MGDL) 180.0 else 10.0
|
||||
minY = 0.0
|
||||
return
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class GraphData(
|
|||
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
|
||||
}
|
||||
|
||||
internal fun setNumVerticalLables() {
|
||||
internal fun setNumVerticalLabels() {
|
||||
graph.gridLabelRenderer.numVerticalLabels = if (units == Constants.MGDL) (maxY / 40 + 1).toInt() else (maxY / 2 + 1).toInt()
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ class GraphData(
|
|||
|
||||
fun addActivity(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||
val actArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val actArrayPred: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val actArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val now = System.currentTimeMillis().toDouble()
|
||||
val actScale = Scale()
|
||||
var total: IobTotal
|
||||
|
@ -305,7 +305,7 @@ class GraphData(
|
|||
}
|
||||
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
|
||||
val act: Double = total.activity
|
||||
if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPred.add(ScaledDataPoint(time, act, actScale))
|
||||
if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPrediction.add(ScaledDataPoint(time, act, actScale))
|
||||
maxIAValue = max(maxIAValue, abs(act))
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ class GraphData(
|
|||
it.color = resourceHelper.gc(R.color.activity)
|
||||
it.thickness = 3
|
||||
})
|
||||
addSeries(FixedLineGraphSeries(Array(actArrayPred.size) { i -> actArrayPred[i] }).also {
|
||||
addSeries(FixedLineGraphSeries(Array(actArrayPrediction.size) { i -> actArrayPrediction[i] }).also {
|
||||
it.setCustomPaint(Paint().also { paint ->
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = 3f
|
||||
|
@ -329,8 +329,51 @@ class GraphData(
|
|||
actScale.setMultiplier(maxY * scale / maxIAValue)
|
||||
}
|
||||
|
||||
//Function below show -BGI to be able to compare curves with deviations
|
||||
fun addMinusBGI(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
|
||||
val bgiArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val bgiArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val now = System.currentTimeMillis().toDouble()
|
||||
val bgiScale = Scale()
|
||||
var total: IobTotal
|
||||
var maxBGIValue = 0.0
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 5 * 60 * 1000L
|
||||
continue
|
||||
}
|
||||
val deviation = if (devBgiScale) iobCobCalculatorPlugin.getAutosensData(time)?.deviation ?:0.0 else 0.0
|
||||
|
||||
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
|
||||
val bgi: Double = total.activity * profile.getIsfMgdl(time) * 5.0
|
||||
if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale)) else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, bgiScale))
|
||||
maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation))
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
addSeries(FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also {
|
||||
it.isDrawBackground = false
|
||||
it.color = resourceHelper.gc(R.color.bgi)
|
||||
it.thickness = 3
|
||||
})
|
||||
addSeries(FixedLineGraphSeries(Array(bgiArrayPrediction.size) { i -> bgiArrayPrediction[i] }).also {
|
||||
it.setCustomPaint(Paint().also { paint ->
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = 3f
|
||||
paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
|
||||
paint.color = resourceHelper.gc(R.color.bgi)
|
||||
})
|
||||
})
|
||||
if (useForScale) {
|
||||
maxY = maxBGIValue
|
||||
minY = -maxBGIValue
|
||||
}
|
||||
bgiScale.setMultiplier(maxY * scale / maxBGIValue)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean) {
|
||||
fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean, absScale: Boolean) {
|
||||
val iobSeries: FixedLineGraphSeries<ScaledDataPoint?>
|
||||
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||
var maxIobValueFound = Double.MIN_VALUE
|
||||
|
@ -340,11 +383,15 @@ class GraphData(
|
|||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
var iob = 0.0
|
||||
if (profile != null) iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
|
||||
var absIob = 0.0
|
||||
if (profile != null) {
|
||||
iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
|
||||
if (absScale) absIob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob
|
||||
}
|
||||
if (abs(lastIob - iob) > 0.02) {
|
||||
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||
iobArray.add(ScaledDataPoint(time, iob, iobScale))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(iob))
|
||||
maxIobValueFound = if (absScale) max(maxIobValueFound, abs(absIob)) else max(maxIobValueFound, abs(iob))
|
||||
lastIob = iob
|
||||
}
|
||||
time += 5 * 60 * 1000L
|
||||
|
@ -359,22 +406,22 @@ class GraphData(
|
|||
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData")
|
||||
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
|
||||
val isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null
|
||||
val iobPred: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||
val iobPredArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||
for (i in iobPredArray) {
|
||||
iobPred.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
|
||||
val iobPrediction: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||
val iobPredictionArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||
for (i in iobPredictionArray) {
|
||||
iobPrediction.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||
}
|
||||
addSeries(PointsWithLabelGraphSeries(Array(iobPred.size) { i -> iobPred[i] }))
|
||||
val iobPred2: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||
val iobPredArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||
for (i in iobPredArray2) {
|
||||
iobPred2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
|
||||
addSeries(PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }))
|
||||
val iobPrediction2: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||
val iobPredictionArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||
for (i in iobPredictionArray2) {
|
||||
iobPrediction2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||
}
|
||||
addSeries(PointsWithLabelGraphSeries(Array(iobPred2.size) { i -> iobPred2[i] }))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray2))
|
||||
addSeries(PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] }))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray2))
|
||||
}
|
||||
if (useForScale) {
|
||||
maxY = maxIobValueFound
|
||||
|
@ -395,7 +442,7 @@ class GraphData(
|
|||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
var iob = 0.0
|
||||
if (profile != null) iob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time, profile).iob
|
||||
if (profile != null) iob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob
|
||||
if (abs(lastIob - iob) > 0.02) {
|
||||
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||
iobArray.add(ScaledDataPoint(time, iob, iobScale))
|
||||
|
@ -460,14 +507,23 @@ class GraphData(
|
|||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||
fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
|
||||
class DeviationDataPoint(x: Double, y: Double, var color: Int, scale: Scale) : ScaledDataPoint(x, y, scale)
|
||||
|
||||
val devArray: MutableList<DeviationDataPoint> = ArrayList()
|
||||
var maxDevValueFound = 0.0
|
||||
val devScale = Scale()
|
||||
var time = fromTime
|
||||
var total: IobTotal
|
||||
|
||||
while (time <= toTime) {
|
||||
// if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0
|
||||
val bgi: Double = if (devBgiScale) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
|
||||
total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0
|
||||
} else 0.0
|
||||
|
||||
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
|
||||
var color = resourceHelper.gc(R.color.deviationblack) // "="
|
||||
if (autosensData.type == "" || autosensData.type == "non-meal") {
|
||||
|
@ -480,7 +536,7 @@ class GraphData(
|
|||
color = resourceHelper.gc(R.color.deviationgrey)
|
||||
}
|
||||
devArray.add(DeviationDataPoint(time.toDouble(), autosensData.deviation, color, devScale))
|
||||
maxDevValueFound = max(maxDevValueFound, abs(autosensData.deviation))
|
||||
maxDevValueFound = max(maxDevValueFound, max(abs(autosensData.deviation), abs(bgi)))
|
||||
}
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ class PersistentNotificationPlugin @Inject constructor(
|
|||
line1 = line1aa
|
||||
if (glucoseStatus != null) {
|
||||
line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||
+ " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units))
|
||||
+ " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgDelta, glucoseStatus.avgDelta * Constants.MGDL_TO_MMOLL, units))
|
||||
line1aa += " " + lastBG.trendArrow.symbol
|
||||
} else {
|
||||
line1 += " " +
|
||||
|
@ -207,7 +207,7 @@ class PersistentNotificationPlugin @Inject constructor(
|
|||
builder.setCategory(NotificationCompat.CATEGORY_STATUS)
|
||||
builder.setSmallIcon(iconsProvider.getNotificationIcon())
|
||||
builder.setLargeIcon(resourceHelper.decodeResource(iconsProvider.getIcon()))
|
||||
if (line1 != null) builder.setContentTitle(line1)
|
||||
builder.setContentTitle(line1)
|
||||
if (line2 != null) builder.setContentText(line2)
|
||||
if (line3 != null) builder.setSubText(line3)
|
||||
/// Android Auto
|
||||
|
|
|
@ -11,7 +11,7 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSm
|
|||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import java.util.*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue