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
|
.gradle
|
||||||
/local.properties
|
/local.properties
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
*/jacoco.exec
|
||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
*.apk
|
*.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: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
//apply plugin: 'jacoco-android'
|
|
||||||
apply plugin: 'com.hiya.jacoco-android'
|
apply plugin: 'com.hiya.jacoco-android'
|
||||||
apply plugin: 'com.google.firebase.crashlytics'
|
apply plugin: 'com.google.firebase.crashlytics'
|
||||||
|
|
||||||
|
apply from: "${project.rootDir}/gradle/android_dependencies.gradle"
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
toolVersion = "0.8.3"
|
toolVersion = "0.8.6"
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
jacoco.includeNoLocationClasses = true
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -109,51 +104,20 @@ tasks.matching { it instanceof Test }.all {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
|
||||||
ndkVersion "21.1.6352462"
|
ndkVersion "21.1.6352462"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 26
|
|
||||||
targetSdkVersion 28
|
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
versionCode 1500
|
versionCode 1500
|
||||||
version "2.8.2.1-dev"
|
version "2.8.2.1-dev-b"
|
||||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||||
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
|
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
|
||||||
buildConfigField "String", "COMMITTED", '"' + allCommitted() + '"'
|
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"
|
flavorDimensions "standard"
|
||||||
productFlavors {
|
productFlavors {
|
||||||
full {
|
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"
|
useLibrary "org.apache.http.legacy"
|
||||||
|
|
||||||
configurations.all {
|
|
||||||
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
@ -245,32 +189,9 @@ dependencies {
|
||||||
|
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
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
|
/* Dagger2 - We are going to use dagger.android which includes
|
||||||
* support for Activity and fragment injection so we need to include
|
* support for Activity and fragment injection so we need to include
|
||||||
* the following dependencies */
|
* the following dependencies */
|
||||||
|
|
||||||
|
|
||||||
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
||||||
|
@ -279,10 +200,11 @@ dependencies {
|
||||||
|
|
||||||
/* Dagger2 - default dependency */
|
/* Dagger2 - default dependency */
|
||||||
kapt "com.google.dagger:dagger-compiler:$dagger_version"
|
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
|
// Run 'adb' shell command to clear application data of main app for 'debug' variant
|
||||||
task clearMainAppData(type: Exec) {
|
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="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="com.dexcom.cgm.EXTERNAL_PERMISSION" />
|
<uses-permission android:name="com.dexcom.cgm.EXTERNAL_PERMISSION" />
|
||||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
<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" />
|
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
|
|
||||||
|
@ -74,8 +75,12 @@
|
||||||
<activity android:name=".activities.StatsActivity" />
|
<activity android:name=".activities.StatsActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name="com.google.firebase.auth.internal.FederatedSignInActivity"
|
android:name="com.google.firebase.auth.internal.FederatedSignInActivity"
|
||||||
tools:replace="android:launchMode"
|
android:excludeFromRecents="true"
|
||||||
android:launchMode="standard" />
|
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 -->
|
<!-- Receive new BG readings from other local apps -->
|
||||||
<receiver
|
<receiver
|
||||||
|
|
|
@ -131,6 +131,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
// Default profile
|
// Default profile
|
||||||
binding.copytolocalprofile.setOnClickListener {
|
binding.copytolocalprofile.setOnClickListener {
|
||||||
|
storeValues()
|
||||||
val age = ageUsed[tabSelected]
|
val age = ageUsed[tabSelected]
|
||||||
val weight = weightUsed[tabSelected]
|
val weight = weightUsed[tabSelected]
|
||||||
val tdd = tddUsed[tabSelected]
|
val tdd = tddUsed[tabSelected]
|
||||||
|
@ -289,7 +290,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setBackgroundColorOnSelected(tab: Int) {
|
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))
|
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 android.os.Bundle
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.databinding.ActivityStatsBinding
|
import info.nightscout.androidaps.databinding.ActivityStatsBinding
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.stats.TddCalculator
|
import info.nightscout.androidaps.utils.stats.TddCalculator
|
||||||
|
@ -14,6 +15,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
|
||||||
@Inject lateinit var tddCalculator: TddCalculator
|
@Inject lateinit var tddCalculator: TddCalculator
|
||||||
@Inject lateinit var tirCalculator: TirCalculator
|
@Inject lateinit var tirCalculator: TirCalculator
|
||||||
@Inject lateinit var activityMonitor: ActivityMonitor
|
@Inject lateinit var activityMonitor: ActivityMonitor
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private lateinit var binding: ActivityStatsBinding
|
private lateinit var binding: ActivityStatsBinding
|
||||||
|
|
||||||
|
@ -29,6 +31,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
|
||||||
binding.ok.setOnClickListener { finish() }
|
binding.ok.setOnClickListener { finish() }
|
||||||
binding.reset.setOnClickListener {
|
binding.reset.setOnClickListener {
|
||||||
OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats)) {
|
OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats)) {
|
||||||
|
uel.log("STATS RESET")
|
||||||
activityMonitor.reset()
|
activityMonitor.reset()
|
||||||
recreate()
|
recreate()
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,18 +77,13 @@ abstract class FragmentsModule {
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusFragment
|
||||||
abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment
|
||||||
abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsExtendedBolusesFragment(): TreatmentsExtendedBolusesFragment
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesTreatmentsCareportalFragment(): TreatmentsCareportalFragment
|
||||||
abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsProfileSwitchFragment(): TreatmentsProfileSwitchFragment
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesTreatmentsUserEntryFragment(): TreatmentsUserEntryFragment
|
||||||
abstract fun contributesTreatmentsExtendedBolusesFragment(): TreatmentsExtendedBolusesFragment
|
|
||||||
@ContributesAndroidInjector
|
|
||||||
abstract fun contributesTreatmentsCareportalFragment(): TreatmentsCareportalFragment
|
|
||||||
@ContributesAndroidInjector
|
|
||||||
abstract fun contributesTreatmentsProfileSwitchFragment(): TreatmentsProfileSwitchFragment
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesVirtualPumpFragment(): VirtualPumpFragment
|
@ContributesAndroidInjector abstract fun contributesVirtualPumpFragment(): VirtualPumpFragment
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,13 @@ abstract class WizardModule {
|
||||||
@ContributesAndroidInjector abstract fun swBreakInjector(): SWBreak
|
@ContributesAndroidInjector abstract fun swBreakInjector(): SWBreak
|
||||||
@ContributesAndroidInjector abstract fun swButtonInjector(): SWButton
|
@ContributesAndroidInjector abstract fun swButtonInjector(): SWButton
|
||||||
@ContributesAndroidInjector abstract fun swEditNumberWithUnitsInjector(): SWEditNumberWithUnits
|
@ContributesAndroidInjector abstract fun swEditNumberWithUnitsInjector(): SWEditNumberWithUnits
|
||||||
|
@ContributesAndroidInjector abstract fun swEditNumberInjector(): SWEditNumber
|
||||||
@ContributesAndroidInjector abstract fun swEditStringInjector(): SWEditString
|
@ContributesAndroidInjector abstract fun swEditStringInjector(): SWEditString
|
||||||
@ContributesAndroidInjector abstract fun swEditEncryptedPasswordInjector(): SWEditEncryptedPassword
|
@ContributesAndroidInjector abstract fun swEditEncryptedPasswordInjector(): SWEditEncryptedPassword
|
||||||
@ContributesAndroidInjector abstract fun swEditUrlInjector(): SWEditUrl
|
@ContributesAndroidInjector abstract fun swEditUrlInjector(): SWEditUrl
|
||||||
@ContributesAndroidInjector abstract fun swFragmentInjector(): SWFragment
|
@ContributesAndroidInjector abstract fun swFragmentInjector(): SWFragment
|
||||||
@ContributesAndroidInjector abstract fun swHtmlLinkInjector(): SWHtmlLink
|
@ContributesAndroidInjector abstract fun swHtmlLinkInjector(): SWHtmlLink
|
||||||
@ContributesAndroidInjector abstract fun swInfotextInjector(): SWInfotext
|
@ContributesAndroidInjector abstract fun swInfotextInjector(): SWInfoText
|
||||||
@ContributesAndroidInjector abstract fun swItemInjector(): SWItem
|
@ContributesAndroidInjector abstract fun swItemInjector(): SWItem
|
||||||
@ContributesAndroidInjector abstract fun swPluginInjector(): SWPlugin
|
@ContributesAndroidInjector abstract fun swPluginInjector(): SWPlugin
|
||||||
@ContributesAndroidInjector abstract fun swRadioButtonInjector(): SWRadioButton
|
@ContributesAndroidInjector abstract fun swRadioButtonInjector(): SWRadioButton
|
||||||
|
|
|
@ -11,6 +11,7 @@ import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.Profile
|
import info.nightscout.androidaps.data.Profile
|
||||||
import info.nightscout.androidaps.databinding.DialogCalibrationBinding
|
import info.nightscout.androidaps.databinding.DialogCalibrationBinding
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
import info.nightscout.androidaps.utils.XdripCalibrations
|
import info.nightscout.androidaps.utils.XdripCalibrations
|
||||||
|
@ -26,6 +27,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var xdripCalibrations: XdripCalibrations
|
@Inject lateinit var xdripCalibrations: XdripCalibrations
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var _binding: DialogCalibrationBinding? = null
|
private var _binding: DialogCalibrationBinding? = null
|
||||||
|
|
||||||
|
@ -75,7 +77,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
||||||
if (bg > 0) {
|
if (bg > 0) {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
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)
|
xdripCalibrations.sendIntent(bg)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,16 +17,13 @@ import info.nightscout.androidaps.db.Source
|
||||||
import info.nightscout.androidaps.db.TempTarget
|
import info.nightscout.androidaps.db.TempTarget
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
|
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.*
|
||||||
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.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.extensions.formatColor
|
import info.nightscout.androidaps.utils.extensions.formatColor
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -46,6 +43,8 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||||
@Inject lateinit var nsUpload: NSUpload
|
@Inject lateinit var nsUpload: NSUpload
|
||||||
@Inject lateinit var carbsGenerator: CarbsGenerator
|
@Inject lateinit var carbsGenerator: CarbsGenerator
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
@Inject lateinit var carbTimer: CarbTimer
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
@ -174,6 +173,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
val hypoTT = defaultValueHelper.determineHypoTT()
|
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||||
val actions: LinkedList<String?> = LinkedList()
|
val actions: LinkedList<String?> = LinkedList()
|
||||||
val unitLabel = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl)
|
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
|
val activitySelected = binding.activityTt.isChecked
|
||||||
if (activitySelected)
|
if (activitySelected)
|
||||||
|
@ -190,6 +190,8 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
val time = eventTime + timeOffset * 1000 * 60
|
val time = eventTime + timeOffset * 1000 * 60
|
||||||
if (timeOffset != 0)
|
if (timeOffset != 0)
|
||||||
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time))
|
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()
|
val duration = binding.duration.value.toInt()
|
||||||
if (duration > 0)
|
if (duration > 0)
|
||||||
actions.add(resourceHelper.gs(R.string.duration) + ": " + duration + resourceHelper.gs(R.string.shorthour))
|
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)), {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||||
when {
|
when {
|
||||||
activitySelected -> {
|
activitySelected -> {
|
||||||
aapsLogger.debug("USER ENTRY: TEMPTARGET ACTIVITY $activityTT duration: $activityTTDuration")
|
uel.log("TT ACTIVITY", d1 = activityTT, i1 = activityTTDuration)
|
||||||
val tempTarget = TempTarget()
|
val tempTarget = TempTarget()
|
||||||
.date(System.currentTimeMillis())
|
.date(System.currentTimeMillis())
|
||||||
.duration(activityTTDuration)
|
.duration(activityTTDuration)
|
||||||
|
@ -222,7 +224,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
eatingSoonSelected -> {
|
eatingSoonSelected -> {
|
||||||
aapsLogger.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
|
uel.log("TT EATING SOON", d1 = eatingSoonTT, i1 = eatingSoonTTDuration)
|
||||||
val tempTarget = TempTarget()
|
val tempTarget = TempTarget()
|
||||||
.date(System.currentTimeMillis())
|
.date(System.currentTimeMillis())
|
||||||
.duration(eatingSoonTTDuration)
|
.duration(eatingSoonTTDuration)
|
||||||
|
@ -234,7 +236,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
hypoSelected -> {
|
hypoSelected -> {
|
||||||
aapsLogger.debug("USER ENTRY: TEMPTARGET HYPO $hypoTT duration: $hypoTTDuration")
|
uel.log("TT HYPO", d1 = hypoTT, i1 = hypoTTDuration)
|
||||||
val tempTarget = TempTarget()
|
val tempTarget = TempTarget()
|
||||||
.date(System.currentTimeMillis())
|
.date(System.currentTimeMillis())
|
||||||
.duration(hypoTTDuration)
|
.duration(hypoTTDuration)
|
||||||
|
@ -247,14 +249,17 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
}
|
}
|
||||||
if (carbsAfterConstraints > 0) {
|
if (carbsAfterConstraints > 0) {
|
||||||
if (duration == 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)
|
carbsGenerator.createCarb(carbsAfterConstraints, time, CareportalEvent.CARBCORRECTION, notes)
|
||||||
} else {
|
} 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)
|
carbsGenerator.generateCarbs(carbsAfterConstraints, time, duration, notes)
|
||||||
nsUpload.uploadEvent(CareportalEvent.NOTE, DateUtil.now() - 2000, resourceHelper.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset))
|
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)
|
}, null)
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -17,6 +17,7 @@ import info.nightscout.androidaps.databinding.DialogCareBinding
|
||||||
import info.nightscout.androidaps.db.CareportalEvent
|
import info.nightscout.androidaps.db.CareportalEvent
|
||||||
import info.nightscout.androidaps.db.Source
|
import info.nightscout.androidaps.db.Source
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
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.general.nsclient.NSUpload
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
@ -37,6 +38,7 @@ class CareDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var nsUpload: NSUpload
|
@Inject lateinit var nsUpload: NSUpload
|
||||||
@Inject lateinit var translator: Translator
|
@Inject lateinit var translator: Translator
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
enum class EventType {
|
enum class EventType {
|
||||||
BGCHECK,
|
BGCHECK,
|
||||||
|
@ -220,7 +222,7 @@ class CareDialog : DialogFragmentWithDate() {
|
||||||
EventType.ANNOUNCEMENT -> CareportalEvent.ANNOUNCEMENT
|
EventType.ANNOUNCEMENT -> CareportalEvent.ANNOUNCEMENT
|
||||||
}
|
}
|
||||||
careportalEvent.json = json.toString()
|
careportalEvent.json = json.toString()
|
||||||
aapsLogger.debug("USER ENTRY: CAREPORTAL ${careportalEvent.eventType} json: ${careportalEvent.json}")
|
uel.log("CAREPORTAL", careportalEvent.eventType)
|
||||||
MainApp.getDbHelper().createOrUpdate(careportalEvent)
|
MainApp.getDbHelper().createOrUpdate(careportalEvent)
|
||||||
nsUpload.uploadCareportalEntryToNS(json)
|
nsUpload.uploadCareportalEntryToNS(json)
|
||||||
}, null)
|
}, null)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
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.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
|
@ -32,6 +32,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var _binding: DialogExtendedbolusBinding? = null
|
private var _binding: DialogExtendedbolusBinding? = null
|
||||||
|
|
||||||
|
@ -86,16 +87,11 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
||||||
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
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() {
|
commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
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.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -37,6 +37,7 @@ class FillDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var nsUpload: NSUpload
|
@Inject lateinit var nsUpload: NSUpload
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var _binding: DialogFillBinding? = null
|
private var _binding: DialogFillBinding? = null
|
||||||
|
|
||||||
|
@ -126,16 +127,16 @@ class FillDialog : DialogFragmentWithDate() {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||||
if (insulinAfterConstraints > 0) {
|
if (insulinAfterConstraints > 0) {
|
||||||
aapsLogger.debug("USER ENTRY: PRIME BOLUS $insulinAfterConstraints")
|
uel.log("PRIME BOLUS", d1 = insulinAfterConstraints)
|
||||||
requestPrimeBolus(insulinAfterConstraints, notes)
|
requestPrimeBolus(insulinAfterConstraints, notes)
|
||||||
}
|
}
|
||||||
if (siteChange) {
|
if (siteChange) {
|
||||||
aapsLogger.debug("USER ENTRY: SITE CHANGE")
|
uel.log("SITE CHANGE")
|
||||||
nsUpload.generateCareportalEvent(CareportalEvent.SITECHANGE, eventTime, notes)
|
nsUpload.generateCareportalEvent(CareportalEvent.SITECHANGE, eventTime, notes)
|
||||||
}
|
}
|
||||||
if (insulinChange) {
|
if (insulinChange) {
|
||||||
// add a second for case of both checked
|
// 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)
|
nsUpload.generateCareportalEvent(CareportalEvent.INSULINCHANGE, eventTime + 1000, notes)
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
|
@ -159,12 +160,7 @@ class FillDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
|
@ -15,6 +14,7 @@ import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
import info.nightscout.androidaps.data.Profile
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.databinding.DialogInsulinBinding
|
import info.nightscout.androidaps.databinding.DialogInsulinBinding
|
||||||
import info.nightscout.androidaps.db.CareportalEvent
|
import info.nightscout.androidaps.db.CareportalEvent
|
||||||
import info.nightscout.androidaps.db.Source
|
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.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.*
|
||||||
|
@ -46,7 +47,9 @@ class InsulinDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
@Inject lateinit var ctx: Context
|
@Inject lateinit var ctx: Context
|
||||||
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
@ -175,7 +178,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||||
if (eatingSoonChecked) {
|
if (eatingSoonChecked) {
|
||||||
aapsLogger.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
|
uel.log("TT EATING SOON", d1 = eatingSoonTT, i1 = eatingSoonTTDuration)
|
||||||
val tempTarget = TempTarget()
|
val tempTarget = TempTarget()
|
||||||
.date(System.currentTimeMillis())
|
.date(System.currentTimeMillis())
|
||||||
.duration(eatingSoonTTDuration)
|
.duration(eatingSoonTTDuration)
|
||||||
|
@ -193,21 +196,16 @@ class InsulinDialog : DialogFragmentWithDate() {
|
||||||
detailedBolusInfo.source = Source.USER
|
detailedBolusInfo.source = Source.USER
|
||||||
detailedBolusInfo.notes = notes
|
detailedBolusInfo.notes = notes
|
||||||
if (recordOnlyChecked) {
|
if (recordOnlyChecked) {
|
||||||
aapsLogger.debug("USER ENTRY: BOLUS RECORD ONLY $insulinAfterConstraints")
|
uel.log("BOLUS RECORD", d1 = insulinAfterConstraints, i1 = timeOffset)
|
||||||
detailedBolusInfo.date = time
|
detailedBolusInfo.date = time
|
||||||
activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false)
|
activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false)
|
||||||
} else {
|
} else {
|
||||||
aapsLogger.debug("USER ENTRY: BOLUS $insulinAfterConstraints")
|
uel.log("BOLUS", d1 = insulinAfterConstraints)
|
||||||
detailedBolusInfo.date = DateUtil.now()
|
detailedBolusInfo.date = DateUtil.now()
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -14,14 +13,15 @@ import dagger.android.support.DaggerDialogFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||||
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
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.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
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.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
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.queue.Callback
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.ToastUtils
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
|
@ -41,16 +41,17 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var loopPlugin: LoopPlugin
|
@Inject lateinit var loopPlugin: LoopPlugin
|
||||||
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
|
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
|
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var showOkCancel: Boolean = true
|
private var showOkCancel: Boolean = true
|
||||||
private var _binding: DialogLoopBinding? = null
|
private var _binding: DialogLoopBinding? = null
|
||||||
private var loopHandler = Handler()
|
private var loopHandler = Handler()
|
||||||
private var refreshDialog: Runnable? = null
|
private var refreshDialog: Runnable? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// This property is only valid between onCreateView and
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
@ -104,7 +105,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
binding.cancel.setOnClickListener { dismiss() }
|
binding.cancel.setOnClickListener { dismiss() }
|
||||||
|
|
||||||
refreshDialog = Runnable {
|
refreshDialog = Runnable {
|
||||||
scheduleUpdateGUI("refreshDialog")
|
scheduleUpdateGUI()
|
||||||
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
|
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
|
||||||
}
|
}
|
||||||
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
|
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
|
||||||
|
@ -119,11 +120,11 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
|
|
||||||
var task: Runnable? = null
|
var task: Runnable? = null
|
||||||
|
|
||||||
private fun scheduleUpdateGUI(from: String) {
|
private fun scheduleUpdateGUI() {
|
||||||
class UpdateRunnable : Runnable {
|
class UpdateRunnable : Runnable {
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
updateGUI(from)
|
updateGUI("refreshDialog")
|
||||||
task = null
|
task = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,8 +138,8 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
if (_binding == null) return
|
if (_binding == null) return
|
||||||
aapsLogger.debug("UpdateGUI from $from")
|
aapsLogger.debug("UpdateGUI from $from")
|
||||||
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
|
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
|
||||||
val closedLoopAllowed = objectivesPlugin.isClosedLoopAllowed(Constraint(true))
|
val closedLoopAllowed = constraintChecker.isClosedLoopAllowed(Constraint(true))
|
||||||
val lgsEnabled = objectivesPlugin.isLgsAllowed(Constraint(true))
|
val lgsEnabled = constraintChecker.isLgsAllowed(Constraint(true))
|
||||||
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||||
if (profileFunction.isProfileValid("LoopDialogUpdateGUI")) {
|
if (profileFunction.isProfileValid("LoopDialogUpdateGUI")) {
|
||||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||||
|
@ -237,28 +238,28 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
val profile = profileFunction.getProfile() ?: return true
|
val profile = profileFunction.getProfile() ?: return true
|
||||||
when (v.id) {
|
when (v.id) {
|
||||||
R.id.overview_closeloop -> {
|
R.id.overview_closeloop -> {
|
||||||
aapsLogger.debug("USER ENTRY: CLOSED LOOP MODE")
|
uel.log("CLOSED LOOP MODE")
|
||||||
sp.putString(R.string.key_aps_mode, "closed")
|
sp.putString(R.string.key_aps_mode, "closed")
|
||||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop)))
|
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop)))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_lgsloop -> {
|
R.id.overview_lgsloop -> {
|
||||||
aapsLogger.debug("USER ENTRY: LGS LOOP MODE")
|
uel.log("LGS LOOP MODE")
|
||||||
sp.putString(R.string.key_aps_mode, "lgs")
|
sp.putString(R.string.key_aps_mode, "lgs")
|
||||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_openloop -> {
|
R.id.overview_openloop -> {
|
||||||
aapsLogger.debug("USER ENTRY: OPEN LOOP MODE")
|
uel.log("OPEN LOOP MODE")
|
||||||
sp.putString(R.string.key_aps_mode, "open")
|
sp.putString(R.string.key_aps_mode, "open")
|
||||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disable -> {
|
R.id.overview_disable -> {
|
||||||
aapsLogger.debug("USER ENTRY: LOOP DISABLED")
|
uel.log("LOOP DISABLED")
|
||||||
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
||||||
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
|
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
|
||||||
configBuilderPlugin.storeSettings("DisablingLoop")
|
configBuilderPlugin.storeSettings("DisablingLoop")
|
||||||
|
@ -275,7 +276,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_enable -> {
|
R.id.overview_enable -> {
|
||||||
aapsLogger.debug("USER ENTRY: LOOP ENABLED")
|
uel.log("LOOP ENABLED")
|
||||||
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
||||||
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
||||||
configBuilderPlugin.storeSettings("EnablingLoop")
|
configBuilderPlugin.storeSettings("EnablingLoop")
|
||||||
|
@ -285,18 +286,13 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_resume, R.id.overview_reconnect -> {
|
R.id.overview_resume, R.id.overview_reconnect -> {
|
||||||
aapsLogger.debug("USER ENTRY: RESUME")
|
uel.log("RESUME")
|
||||||
loopPlugin.suspendTo(0L)
|
loopPlugin.suspendTo(0L)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -306,49 +302,49 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_1h -> {
|
R.id.overview_suspend_1h -> {
|
||||||
aapsLogger.debug("USER ENTRY: SUSPEND 1h")
|
uel.log("SUSPEND 1h")
|
||||||
loopPlugin.suspendLoop(60)
|
loopPlugin.suspendLoop(60)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_2h -> {
|
R.id.overview_suspend_2h -> {
|
||||||
aapsLogger.debug("USER ENTRY: SUSPEND 2h")
|
uel.log("SUSPEND 2h")
|
||||||
loopPlugin.suspendLoop(120)
|
loopPlugin.suspendLoop(120)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_3h -> {
|
R.id.overview_suspend_3h -> {
|
||||||
aapsLogger.debug("USER ENTRY: SUSPEND 3h")
|
uel.log("SUSPEND 3h")
|
||||||
loopPlugin.suspendLoop(180)
|
loopPlugin.suspendLoop(180)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_10h -> {
|
R.id.overview_suspend_10h -> {
|
||||||
aapsLogger.debug("USER ENTRY: SUSPEND 10h")
|
uel.log("SUSPEND 10h")
|
||||||
loopPlugin.suspendLoop(600)
|
loopPlugin.suspendLoop(600)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_15m -> {
|
R.id.overview_disconnect_15m -> {
|
||||||
aapsLogger.debug("USER ENTRY: DISCONNECT 15m")
|
uel.log("DISCONNECT 15m")
|
||||||
loopPlugin.disconnectPump(15, profile)
|
loopPlugin.disconnectPump(15, profile)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_30m -> {
|
R.id.overview_disconnect_30m -> {
|
||||||
aapsLogger.debug("USER ENTRY: DISCONNECT 30m")
|
uel.log("DISCONNECT 30m")
|
||||||
loopPlugin.disconnectPump(30, profile)
|
loopPlugin.disconnectPump(30, profile)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_1h -> {
|
R.id.overview_disconnect_1h -> {
|
||||||
aapsLogger.debug("USER ENTRY: DISCONNECT 1h")
|
uel.log("DISCONNECT 1h")
|
||||||
loopPlugin.disconnectPump(60, profile)
|
loopPlugin.disconnectPump(60, profile)
|
||||||
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
@ -356,14 +352,14 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_2h -> {
|
R.id.overview_disconnect_2h -> {
|
||||||
aapsLogger.debug("USER ENTRY: DISCONNECT 2h")
|
uel.log("DISCONNECT 2h")
|
||||||
loopPlugin.disconnectPump(120, profile)
|
loopPlugin.disconnectPump(120, profile)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_3h -> {
|
R.id.overview_disconnect_3h -> {
|
||||||
aapsLogger.debug("USER ENTRY: DISCONNECT 3h")
|
uel.log("DISCONNECT 3h")
|
||||||
loopPlugin.disconnectPump(180, profile)
|
loopPlugin.disconnectPump(180, profile)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -11,6 +11,7 @@ import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
|
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
|
@ -26,6 +27,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var profileIndex: Int? = null
|
private var profileIndex: Int? = null
|
||||||
|
|
||||||
|
@ -122,7 +124,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
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)
|
treatmentsPlugin.doProfileSwitch(profileStore, profile, duration, percent, timeShift, eventTime)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
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.Constraint
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.interfaces.PumpDescription
|
import info.nightscout.androidaps.interfaces.PumpDescription
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
|
@ -35,6 +35,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var ctx: Context
|
@Inject lateinit var ctx: Context
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var isPercentPump = true
|
private var isPercentPump = true
|
||||||
|
|
||||||
|
@ -119,20 +120,15 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
||||||
val callback: Callback = object : Callback() {
|
val callback: Callback = object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPercentPump) {
|
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)
|
commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, callback)
|
||||||
} else {
|
} 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)
|
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.db.TempTarget
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||||
|
@ -33,8 +34,9 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@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
|
private var _binding: DialogTemptargetBinding? = null
|
||||||
|
|
||||||
|
@ -162,7 +164,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
||||||
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
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) {
|
if (target == 0.0 || duration == 0) {
|
||||||
val tempTarget = TempTarget()
|
val tempTarget = TempTarget()
|
||||||
.date(eventTime)
|
.date(eventTime)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
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.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||||
|
@ -41,6 +41,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var ctx: Context
|
@Inject lateinit var ctx: Context
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private val textWatcher: TextWatcher = object : TextWatcher {
|
private val textWatcher: TextWatcher = object : TextWatcher {
|
||||||
override fun afterTextChanged(s: Editable) {}
|
override fun afterTextChanged(s: Editable) {}
|
||||||
|
@ -128,7 +129,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
||||||
if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
|
if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
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()
|
val detailedBolusInfo = DetailedBolusInfo()
|
||||||
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION
|
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION
|
||||||
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
|
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
|
||||||
|
@ -140,12 +141,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -270,7 +270,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
||||||
val end = start + T.hours(rangeToDisplay.toLong()).msecs()
|
val end = start + T.hours(rangeToDisplay.toLong()).msecs()
|
||||||
iobCobCalculatorPluginHistory.stopCalculation(from)
|
iobCobCalculatorPluginHistory.stopCalculation(from)
|
||||||
iobCobCalculatorPluginHistory.clearCache()
|
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 useDevForScale = false
|
||||||
var useRatioForScale = false
|
var useRatioForScale = false
|
||||||
var useDSForScale = false
|
var useDSForScale = false
|
||||||
var useIAForScale = false
|
var useBGIForScale = false
|
||||||
var useABSForScale = false
|
var useABSForScale = false
|
||||||
when {
|
when {
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = 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.ABS.ordinal] -> useABSForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = 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])
|
val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
|
||||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
|
||||||
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)
|
|
||||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, toTime, useABSForScale, 1.0)
|
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)
|
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
|
// set manual x bounds to have nice steps
|
||||||
|
@ -362,7 +365,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set manual x bounds to have nice steps
|
// set manual x bounds to have nice steps
|
||||||
graphData.setNumVerticalLables()
|
graphData.setNumVerticalLabels()
|
||||||
graphData.formatAxis(fromTime, toTime)
|
graphData.formatAxis(fromTime, toTime)
|
||||||
}
|
}
|
||||||
// finally enforce drawing of graphs in UI thread
|
// 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.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LoopFragment : DaggerFragment() {
|
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.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.JSONFormatter
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -114,7 +114,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
||||||
if (openAPSAMAPlugin.lastAPSRun != 0L) {
|
if (openAPSAMAPlugin.lastAPSRun != 0L) {
|
||||||
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun)
|
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun)
|
||||||
}
|
}
|
||||||
openAPSAMAPlugin.lastAutosensResult?.let {
|
openAPSAMAPlugin.lastAutosensResult.let {
|
||||||
binding.autosensdata.text = JSONFormatter.format(it.json())
|
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.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.JSONFormatter
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -117,7 +117,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
if (openAPSSMBPlugin.lastAPSRun != 0L) {
|
if (openAPSSMBPlugin.lastAPSRun != 0L) {
|
||||||
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun)
|
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun)
|
||||||
}
|
}
|
||||||
openAPSSMBPlugin.lastAutosensResult?.let {
|
openAPSSMBPlugin.lastAutosensResult.let {
|
||||||
binding.autosensdata.text = JSONFormatter.format(it.json())
|
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.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
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.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
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.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -25,7 +26,8 @@ class ConfigBuilderPlugin @Inject constructor(
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val rxBus: RxBusWrapper,
|
private val rxBus: RxBusWrapper,
|
||||||
private val activePlugin: ActivePluginProvider
|
private val activePlugin: ActivePluginProvider,
|
||||||
|
private val uel: UserEntryLogger
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(PluginDescription()
|
||||||
.mainType(PluginType.GENERAL)
|
.mainType(PluginType.GENERAL)
|
||||||
.fragmentClass(ConfigBuilderFragment::class.java.name)
|
.fragmentClass(ConfigBuilderFragment::class.java.name)
|
||||||
|
@ -137,9 +139,10 @@ class ConfigBuilderPlugin @Inject constructor(
|
||||||
if (allowHardwarePump || activity == null) {
|
if (allowHardwarePump || activity == null) {
|
||||||
performPluginSwitch(changedPlugin, newState, type)
|
performPluginSwitch(changedPlugin, newState, type)
|
||||||
} else {
|
} 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)
|
performPluginSwitch(changedPlugin, newState, type)
|
||||||
sp.putBoolean("allow_hardware_pump", true)
|
sp.putBoolean("allow_hardware_pump", true)
|
||||||
|
uel.log("HW PUMP ALLOWED")
|
||||||
aapsLogger.debug(LTag.PUMP, "First time HW pump allowed!")
|
aapsLogger.debug(LTag.PUMP, "First time HW pump allowed!")
|
||||||
}, Runnable {
|
}, Runnable {
|
||||||
rxBus.send(EventConfigBuilderUpdateGui())
|
rxBus.send(EventConfigBuilderUpdateGui())
|
||||||
|
|
|
@ -22,6 +22,7 @@ import info.nightscout.androidaps.databinding.ObjectivesItemBinding
|
||||||
import info.nightscout.androidaps.dialogs.NtpProgressDialog
|
import info.nightscout.androidaps.dialogs.NtpProgressDialog
|
||||||
import info.nightscout.androidaps.events.EventNtpStatus
|
import info.nightscout.androidaps.events.EventNtpStatus
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
|
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
|
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.HtmlHelper
|
||||||
import info.nightscout.androidaps.utils.SntpClient
|
import info.nightscout.androidaps.utils.SntpClient
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -52,6 +53,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var sntpClient: SntpClient
|
@Inject lateinit var sntpClient: SntpClient
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private val objectivesAdapter = ObjectivesAdapter()
|
private val objectivesAdapter = ObjectivesAdapter()
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
@ -194,19 +196,19 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
if (task.shouldBeIgnored()) continue
|
if (task.shouldBeIgnored()) continue
|
||||||
// name
|
// name
|
||||||
val name = TextView(holder.binding.progress.context)
|
val name = TextView(holder.binding.progress.context)
|
||||||
name.text = resourceHelper.gs(task.task) + ":"
|
name.text = "${resourceHelper.gs(task.task)}:"
|
||||||
name.setTextColor(-0x1)
|
name.setTextColor(-0x1)
|
||||||
holder.binding.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
holder.binding.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||||
// hint
|
// hint
|
||||||
task.hints.forEach { h ->
|
task.hints.forEach { h ->
|
||||||
if (!task.isCompleted)
|
if (!task.isCompleted())
|
||||||
holder.binding.progress.addView(h.generate(context))
|
context?.let { holder.binding.progress.addView(h.generate(it)) }
|
||||||
}
|
}
|
||||||
// state
|
// state
|
||||||
val state = TextView(holder.binding.progress.context)
|
val state = TextView(holder.binding.progress.context)
|
||||||
state.setTextColor(-0x1)
|
state.setTextColor(-0x1)
|
||||||
val basicHTML = "<font color=\"%1\$s\"><b>%2\$s</b></font>"
|
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.text = HtmlHelper.fromHtml(formattedHTML)
|
||||||
state.gravity = Gravity.END
|
state.gravity = Gravity.END
|
||||||
holder.binding.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
holder.binding.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||||
|
@ -305,6 +307,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
holder.binding.unstart.setOnClickListener {
|
holder.binding.unstart.setOnClickListener {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable {
|
||||||
|
uel.log("OBJECTIVE UNSTARTED", i1 = position + 1)
|
||||||
objective.startedOn = 0
|
objective.startedOn = 0
|
||||||
scrollToCurrentObjective()
|
scrollToCurrentObjective()
|
||||||
rxBus.send(EventObjectivesUpdateGui())
|
rxBus.send(EventObjectivesUpdateGui())
|
||||||
|
@ -329,7 +332,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
holder.binding.inputhint.visibility = View.VISIBLE
|
holder.binding.inputhint.visibility = View.VISIBLE
|
||||||
holder.binding.enterbutton.setOnClickListener {
|
holder.binding.enterbutton.setOnClickListener {
|
||||||
val input = holder.binding.input.text.toString()
|
val input = holder.binding.input.text.toString()
|
||||||
objective.specialAction(activity, input)
|
activity?.let { activity -> objective.specialAction(activity, input) }
|
||||||
rxBus.send(EventObjectivesUpdateGui())
|
rxBus.send(EventObjectivesUpdateGui())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
|
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
|
@ -25,8 +26,8 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
private val activePlugin: ActivePluginProvider,
|
private val activePlugin: ActivePluginProvider,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val config: Config
|
config: Config,
|
||||||
|
private val uel: UserEntryLogger
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(PluginDescription()
|
||||||
.mainType(PluginType.CONSTRAINTS)
|
.mainType(PluginType.CONSTRAINTS)
|
||||||
.fragmentClass(ObjectivesFragment::class.qualifiedName)
|
.fragmentClass(ObjectivesFragment::class.qualifiedName)
|
||||||
|
@ -141,6 +142,7 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
sp.putLong("Objectives_" + "auto" + "_accomplished", DateUtil.now())
|
sp.putLong("Objectives_" + "auto" + "_accomplished", DateUtil.now())
|
||||||
setupObjectives()
|
setupObjectives()
|
||||||
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeaccepted))
|
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeaccepted))
|
||||||
|
uel.log("OBJECTIVES SKIPPED")
|
||||||
} else {
|
} else {
|
||||||
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeinvalid))
|
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeinvalid))
|
||||||
}
|
}
|
||||||
|
@ -163,7 +165,7 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
|
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXBASAL_OBJECTIVE + 1), this)
|
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXBASAL_OBJECTIVE + 1), this)
|
||||||
return value
|
return value
|
||||||
|
|
|
@ -80,28 +80,30 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
||||||
// Options
|
// Options
|
||||||
binding.examOptions.removeAllViews()
|
binding.examOptions.removeAllViews()
|
||||||
task.options.forEach {
|
task.options.forEach {
|
||||||
val cb = it.generate(context)
|
context?.let { context ->
|
||||||
if (task.answered) {
|
val cb = it.generate(context)
|
||||||
cb.isEnabled = false
|
if (task.answered) {
|
||||||
if (it.isCorrect)
|
cb.isEnabled = false
|
||||||
cb.isChecked = true
|
if (it.isCorrect)
|
||||||
|
cb.isChecked = true
|
||||||
|
}
|
||||||
|
binding.examOptions.addView(cb)
|
||||||
}
|
}
|
||||||
binding.examOptions.addView(cb)
|
|
||||||
}
|
}
|
||||||
// Hints
|
// Hints
|
||||||
binding.examHints.removeAllViews()
|
binding.examHints.removeAllViews()
|
||||||
for (h in task.hints) {
|
for (h in task.hints) {
|
||||||
binding.examHints.addView(h.generate(context))
|
context?.let { binding.examHints.addView(h.generate(it)) }
|
||||||
}
|
}
|
||||||
// Disabled to
|
// Disabled to
|
||||||
binding.examDisabledto.text = resourceHelper.gs(R.string.answerdisabledto, dateUtil.timeString(task.disabledTo))
|
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
|
// Buttons
|
||||||
binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer
|
binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer()
|
||||||
binding.examVerify.setOnClickListener {
|
binding.examVerify.setOnClickListener {
|
||||||
var result = true
|
var result = true
|
||||||
for (o in task.options) {
|
for (o in task.options) {
|
||||||
val option: Option = o as Option
|
val option: Option = o
|
||||||
result = result && option.evaluate()
|
result = result && option.evaluate()
|
||||||
}
|
}
|
||||||
task.answered = result
|
task.answered = result
|
||||||
|
@ -133,14 +135,14 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
||||||
binding.nextUnansweredButton.isEnabled = !objective.isCompleted
|
binding.nextUnansweredButton.isEnabled = !objective.isCompleted
|
||||||
binding.nextUnansweredButton.setOnClickListener {
|
binding.nextUnansweredButton.setOnClickListener {
|
||||||
for (i in (currentTask + 1) until objective.tasks.size) {
|
for (i in (currentTask + 1) until objective.tasks.size) {
|
||||||
if (!objective.tasks[i].isCompleted) {
|
if (!objective.tasks[i].isCompleted()) {
|
||||||
currentTask = i
|
currentTask = i
|
||||||
updateGui()
|
updateGui()
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i in 0..currentTask) {
|
for (i in 0..currentTask) {
|
||||||
if (!objective.tasks[i].isCompleted) {
|
if (!objective.tasks[i].isCompleted()) {
|
||||||
currentTask = i
|
currentTask = i
|
||||||
updateGui()
|
updateGui()
|
||||||
return@setOnClickListener
|
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.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||||
import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler
|
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.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
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.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
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.SingleClickButton
|
||||||
import info.nightscout.androidaps.utils.ui.UIRunnable
|
import info.nightscout.androidaps.utils.ui.UIRunnable
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ class ActionsFragment : DaggerFragment() {
|
||||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||||
@Inject lateinit var skinProvider: SkinProvider
|
@Inject lateinit var skinProvider: SkinProvider
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -152,16 +154,11 @@ class ActionsFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
extendedBolusCancel?.setOnClickListener {
|
extendedBolusCancel?.setOnClickListener {
|
||||||
if (activePlugin.activeTreatments.isInHistoryExtendedBoluslInProgress) {
|
if (activePlugin.activeTreatments.isInHistoryExtendedBoluslInProgress) {
|
||||||
aapsLogger.debug("USER ENTRY: CANCEL EXTENDED BOLUS")
|
uel.log("CANCEL EXTENDED BOLUS")
|
||||||
commandQueue.cancelExtended(object : Callback() {
|
commandQueue.cancelExtended(object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -172,16 +169,11 @@ class ActionsFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
cancelTempBasal?.setOnClickListener {
|
cancelTempBasal?.setOnClickListener {
|
||||||
if (activePlugin.activeTreatments.isTempBasalInProgress) {
|
if (activePlugin.activeTreatments.isTempBasalInProgress) {
|
||||||
aapsLogger.debug("USER ENTRY: CANCEL TEMP BASAL")
|
uel.log("CANCEL TEMP BASAL")
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -264,10 +256,10 @@ class ActionsFragment : DaggerFragment() {
|
||||||
profileSwitch?.visibility = (
|
profileSwitch?.visibility = (
|
||||||
activePlugin.activeProfileInterface.profile != null &&
|
activePlugin.activeProfileInterface.profile != null &&
|
||||||
pump.pumpDescription.isSetBasalProfileCapable &&
|
pump.pumpDescription.isSetBasalProfileCapable &&
|
||||||
pump.isInitialized &&
|
pump.isInitialized() &&
|
||||||
!pump.isSuspended).toVisibility()
|
!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
|
extendedBolus?.visibility = View.GONE
|
||||||
extendedBolusCancel?.visibility = View.GONE
|
extendedBolusCancel?.visibility = View.GONE
|
||||||
} else {
|
} 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
|
setTempBasal?.visibility = View.GONE
|
||||||
cancelTempBasal?.visibility = View.GONE
|
cancelTempBasal?.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
|
@ -300,7 +292,7 @@ class ActionsFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
val activeBgSource = activePlugin.activeBgSource
|
val activeBgSource = activePlugin.activeBgSource
|
||||||
historyBrowser?.visibility = (profile != null).toVisibility()
|
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()
|
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
|
||||||
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
|
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
|
||||||
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
|
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
|
||||||
|
@ -320,7 +312,7 @@ class ActionsFragment : DaggerFragment() {
|
||||||
|
|
||||||
private fun checkPumpCustomActions() {
|
private fun checkPumpCustomActions() {
|
||||||
val activePump = activePlugin.activePump
|
val activePump = activePlugin.activePump
|
||||||
val customActions = activePump.customActions ?: return
|
val customActions = activePump.getCustomActions() ?: return
|
||||||
val currentContext = context ?: return
|
val currentContext = context ?: return
|
||||||
removePumpCustomActions()
|
removePumpCustomActions()
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ class AutomationEvent(private val injector: HasAndroidInjector) {
|
||||||
|
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
|
||||||
var title: String? = null
|
var title: String = ""
|
||||||
var isEnabled = true
|
var isEnabled = true
|
||||||
var systemAction: Boolean = false // true = generated by AAPS, false = entered by user
|
var systemAction: Boolean = false // true = generated by AAPS, false = entered by user
|
||||||
var readOnly: Boolean = false // removing, editing disabled
|
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.R
|
||||||
import info.nightscout.androidaps.databinding.AutomationEventItemBinding
|
import info.nightscout.androidaps.databinding.AutomationEventItemBinding
|
||||||
import info.nightscout.androidaps.databinding.AutomationFragmentBinding
|
import info.nightscout.androidaps.databinding.AutomationFragmentBinding
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
||||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter
|
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.plugins.general.automation.triggers.TriggerConnector
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import info.nightscout.androidaps.utils.extensions.toVisibility
|
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
@ -48,6 +49,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var automationPlugin: AutomationPlugin
|
@Inject lateinit var automationPlugin: AutomationPlugin
|
||||||
@Inject lateinit var injector: HasAndroidInjector
|
@Inject lateinit var injector: HasAndroidInjector
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
private lateinit var eventListAdapter: EventListAdapter
|
private lateinit var eventListAdapter: EventListAdapter
|
||||||
|
@ -212,11 +214,12 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
}
|
}
|
||||||
// remove event
|
// remove event
|
||||||
holder.binding.iconTrash.setOnClickListener {
|
holder.binding.iconTrash.setOnClickListener {
|
||||||
showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
|
OKDialog.showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
|
||||||
Runnable {
|
{
|
||||||
|
uel.log("AUTOM REMOVED", automationPlugin.at(position).title)
|
||||||
automationPlugin.removeAt(position)
|
automationPlugin.removeAt(position)
|
||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
}, Runnable {
|
}, {
|
||||||
rxBus.send(EventAutomationUpdateGui())
|
rxBus.send(EventAutomationUpdateGui())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -234,8 +237,9 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
|
|
||||||
override fun onItemDismiss(position: Int) {
|
override fun onItemDismiss(position: Int) {
|
||||||
activity?.let { activity ->
|
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 {
|
Runnable {
|
||||||
|
uel.log("AUTOM REMOVED", automationPlugin.at(position).title)
|
||||||
automationPlugin.removeAt(position)
|
automationPlugin.removeAt(position)
|
||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
rxBus.send(EventAutomationDataChanged())
|
rxBus.send(EventAutomationDataChanged())
|
||||||
|
|
|
@ -30,7 +30,7 @@ import info.nightscout.androidaps.services.LocationServiceHelper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
|
|
@ -1,25 +1,20 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.actions
|
package info.nightscout.androidaps.plugins.general.automation.actions
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
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.data.PumpEnactResult
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
|
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.LabelWithElement
|
||||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
|
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.queue.Callback
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.JsonHelper
|
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 info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -28,28 +23,24 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
|
||||||
|
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
@Inject lateinit var nsUpload: NSUpload
|
|
||||||
@Inject lateinit var context: Context
|
@Inject lateinit var context: Context
|
||||||
|
@Inject lateinit var timerUtil: TimerUtil
|
||||||
|
|
||||||
var text = InputString(injector)
|
var text = InputString(injector)
|
||||||
|
|
||||||
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
|
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
|
||||||
this.text = InputString(injector, text)
|
this.text = InputString(injector, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun friendlyName(): Int = R.string.alarm
|
override fun friendlyName(): Int = R.string.alarm
|
||||||
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
|
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
|
||||||
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
|
@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) {
|
override fun doAction(callback: Callback) {
|
||||||
val i = Intent(context, ErrorHelperActivity::class.java)
|
timerUtil.scheduleReminder(DateUtil.now() + T.secs(10L).msecs(), text.value.takeIf { it.isNotBlank() }
|
||||||
i.putExtra("soundid", R.raw.modern_alarm)
|
?: resourceHelper.gs(R.string.app_name))
|
||||||
i.putExtra("status", text.value)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.alarm))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
context.startActivity(i)
|
|
||||||
|
|
||||||
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
|
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.plugins.general.automation.triggers.TriggerConnector
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.ToastUtils
|
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.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
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.TriggerConnector
|
||||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy
|
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
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.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.elements
|
package info.nightscout.androidaps.plugins.general.automation.elements
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import com.dpro.widgets.WeekdaysPicker
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.ui.WeekdayPicker
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
||||||
|
@ -56,7 +54,7 @@ class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
||||||
for (day in DayOfWeek.values()) set(day, false)
|
for (day in DayOfWeek.values()) set(day, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setAll(value:Boolean) {
|
fun setAll(value: Boolean) {
|
||||||
for (day in DayOfWeek.values()) set(day, value)
|
for (day in DayOfWeek.values()) set(day, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,13 +76,10 @@ class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addToLayout(root: LinearLayout) {
|
override fun addToLayout(root: LinearLayout) {
|
||||||
val weekdaysPicker = WeekdaysPicker(root.context)
|
WeekdayPicker(root.context).apply {
|
||||||
weekdaysPicker.setEditable(true)
|
setSelectedDays(getSelectedDays())
|
||||||
weekdaysPicker.selectedDays = getSelectedDays()
|
setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) }
|
||||||
weekdaysPicker.setOnWeekdaysChangeListener { _: View?, i: Int, list: List<Int?> -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)) }
|
root.addView(this)
|
||||||
weekdaysPicker.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
}
|
||||||
weekdaysPicker.sundayFirstDay = Calendar.getInstance().firstDayOfWeek == Calendar.SUNDAY
|
|
||||||
weekdaysPicker.redrawDays()
|
|
||||||
root.addView(weekdaysPicker)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,15 @@ import com.google.common.base.Optional
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
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.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
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.dialogs.ChooseTriggerDialog
|
||||||
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerChanged
|
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.EventTriggerClone
|
||||||
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerRemove
|
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerRemove
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
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.services.LastLocationDataContainer
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -29,13 +29,14 @@ import javax.inject.Inject
|
||||||
import kotlin.reflect.full.primaryConstructor
|
import kotlin.reflect.full.primaryConstructor
|
||||||
|
|
||||||
abstract class Trigger(val injector: HasAndroidInjector) {
|
abstract class Trigger(val injector: HasAndroidInjector) {
|
||||||
|
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var sp: SP
|
@Inject lateinit var sp: SP
|
||||||
@Inject lateinit var locationDataContainer: LastLocationDataContainer
|
@Inject lateinit var locationDataContainer: LastLocationDataContainer
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
@Inject lateinit var treatmentsInterface: TreatmentsInterface
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||||
|
|
||||||
|
@ -53,12 +54,13 @@ abstract class Trigger(val injector: HasAndroidInjector) {
|
||||||
abstract fun duplicate(): Trigger
|
abstract fun duplicate(): Trigger
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun scanForActivity(cont: Context?): AppCompatActivity? {
|
fun scanForActivity(cont: Context?): AppCompatActivity? {
|
||||||
when (cont) {
|
when (cont) {
|
||||||
null -> return null
|
null -> return null
|
||||||
is AppCompatActivity -> return cont
|
is AppCompatActivity -> return cont
|
||||||
is ContextWrapper -> return scanForActivity(cont.baseContext)
|
is ContextWrapper -> return scanForActivity(cont.baseContext)
|
||||||
else -> return null
|
else -> return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shouldRun(): Boolean {
|
override fun shouldRun(): Boolean {
|
||||||
val lastBolusTime = treatmentsPlugin.getLastBolusTime(true)
|
val lastBolusTime = treatmentsInterface.getLastBolusTime(true)
|
||||||
if (lastBolusTime == 0L)
|
if (lastBolusTime == 0L)
|
||||||
return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
|
return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
|
||||||
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
||||||
|
|
|
@ -73,8 +73,8 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
val calculatedDelta = when (delta.deltaType) {
|
val calculatedDelta = when (delta.deltaType) {
|
||||||
DeltaType.SHORT_AVERAGE -> glucoseStatus.short_avgdelta
|
DeltaType.SHORT_AVERAGE -> glucoseStatus.shortAvgDelta
|
||||||
DeltaType.LONG_AVERAGE -> glucoseStatus.long_avgdelta
|
DeltaType.LONG_AVERAGE -> glucoseStatus.longAvgDelta
|
||||||
else -> glucoseStatus.delta
|
else -> glucoseStatus.delta
|
||||||
}
|
}
|
||||||
if (comparator.value.check(calculatedDelta, Profile.toMgdl(delta.value, units))) {
|
if (comparator.value.check(calculatedDelta, Profile.toMgdl(delta.value, units))) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shouldRun(): Boolean {
|
override fun shouldRun(): Boolean {
|
||||||
val tt = treatmentsPlugin.tempTargetFromHistory
|
val tt = treatmentsInterface.tempTargetFromHistory
|
||||||
if (tt == null && comparator.value == ComparatorExists.Compare.NOT_EXISTS) {
|
if (tt == null && comparator.value == ComparatorExists.Compare.NOT_EXISTS) {
|
||||||
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
||||||
return true
|
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("units", profileFunction.getUnits()) // units used in AAPS "mg/dl" or "mmol"
|
||||||
bundle.putString("slopeArrow", lastBG.trendArrow.text) // direction arrow as string
|
bundle.putString("slopeArrow", lastBG.trendArrow.text) // direction arrow as string
|
||||||
bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl
|
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("high", defaultValueHelper.determineHighLine()) // predefined top value of in range (green area)
|
||||||
bundle.putDouble("low", defaultValueHelper.determineLowLine()) // predefined bottom value of in range
|
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.FoodFragmentBinding
|
||||||
import info.nightscout.androidaps.databinding.FoodItemBinding
|
import info.nightscout.androidaps.databinding.FoodItemBinding
|
||||||
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
|
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder
|
import info.nightscout.androidaps.plugins.general.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
@ -38,6 +39,7 @@ class FoodFragment : DaggerFragment() {
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var foodPlugin: FoodPlugin
|
@Inject lateinit var foodPlugin: FoodPlugin
|
||||||
@Inject lateinit var nsUpload: NSUpload
|
@Inject lateinit var nsUpload: NSUpload
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
private lateinit var unfiltered: List<Food>
|
private lateinit var unfiltered: List<Food>
|
||||||
|
@ -213,7 +215,8 @@ class FoodFragment : DaggerFragment() {
|
||||||
binding.remove.setOnClickListener { v: View ->
|
binding.remove.setOnClickListener { v: View ->
|
||||||
val food = v.tag as Food
|
val food = v.tag as Food
|
||||||
activity?.let { activity ->
|
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 != "") {
|
if (food._id != null && food._id != "") {
|
||||||
nsUpload.removeFoodFromNS(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.interfaces.ImportExportPrefsInterface
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
|
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
|
||||||
import info.nightscout.androidaps.utils.AndroidPermission
|
import info.nightscout.androidaps.utils.AndroidPermission
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.ToastUtils
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
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.PrefImportSummaryDialog
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.TwoMessagesAlertDialog
|
import info.nightscout.androidaps.utils.alertDialogs.TwoMessagesAlertDialog
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
|
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
|
||||||
|
@ -58,7 +58,8 @@ class ImportExportPrefs @Inject constructor(
|
||||||
private val androidPermission: AndroidPermission,
|
private val androidPermission: AndroidPermission,
|
||||||
private val classicPrefsFormat: ClassicPrefsFormat,
|
private val classicPrefsFormat: ClassicPrefsFormat,
|
||||||
private val encryptedPrefsFormat: EncryptedPrefsFormat,
|
private val encryptedPrefsFormat: EncryptedPrefsFormat,
|
||||||
private val prefFileList: PrefFileListProvider
|
private val prefFileList: PrefFileListProvider,
|
||||||
|
private val uel: UserEntryLogger
|
||||||
) : ImportExportPrefsInterface {
|
) : ImportExportPrefsInterface {
|
||||||
|
|
||||||
override fun prefsFileExists(): Boolean {
|
override fun prefsFileExists(): Boolean {
|
||||||
|
@ -342,7 +343,8 @@ class ImportExportPrefs @Inject constructor(
|
||||||
|
|
||||||
private fun restartAppAfterImport(context: Context) {
|
private fun restartAppAfterImport(context: Context) {
|
||||||
sp.putBoolean(R.string.key_setupwizard_processed, true)
|
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")
|
log.debug(LTag.CORE, "Exiting")
|
||||||
rxBus.send(EventAppExit())
|
rxBus.send(EventAppExit())
|
||||||
if (context is AppCompatActivity) {
|
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.events.EventNewBG
|
||||||
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
|
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
||||||
|
@ -36,6 +37,7 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
|
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private val compositeDisposable = CompositeDisposable()
|
private val compositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -54,13 +56,13 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
|
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
|
||||||
binding.logDelete.setOnClickListener {
|
binding.logDelete.setOnClickListener {
|
||||||
aapsLogger.debug("USER ENTRY: DELETE LOGS")
|
uel.log("DELETE LOGS")
|
||||||
maintenancePlugin.deleteLogs()
|
maintenancePlugin.deleteLogs()
|
||||||
}
|
}
|
||||||
binding.navResetdb.setOnClickListener {
|
binding.navResetdb.setOnClickListener {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
|
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(
|
compositeDisposable.add(
|
||||||
fromAction {
|
fromAction {
|
||||||
MainApp.getDbHelper().resetDatabases()
|
MainApp.getDbHelper().resetDatabases()
|
||||||
|
@ -81,14 +83,14 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.navExport.setOnClickListener {
|
binding.navExport.setOnClickListener {
|
||||||
aapsLogger.debug("USER ENTRY: EXPORT SETTINGS")
|
uel.log("EXPORT SETTINGS")
|
||||||
// start activity for checking permissions...
|
// start activity for checking permissions...
|
||||||
importExportPrefs.verifyStoragePermissions(this) {
|
importExportPrefs.verifyStoragePermissions(this) {
|
||||||
importExportPrefs.exportSharedPreferences(this)
|
importExportPrefs.exportSharedPreferences(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.navImport.setOnClickListener {
|
binding.navImport.setOnClickListener {
|
||||||
aapsLogger.debug("USER ENTRY: IMPORT SETTINGS")
|
uel.log("IMPORT SETTINGS")
|
||||||
// start activity for checking permissions...
|
// start activity for checking permissions...
|
||||||
importExportPrefs.verifyStoragePermissions(this) {
|
importExportPrefs.verifyStoragePermissions(this) {
|
||||||
importExportPrefs.importSharedPreferences(this)
|
importExportPrefs.importSharedPreferences(this)
|
||||||
|
|
|
@ -34,7 +34,8 @@ class MaintenancePlugin @Inject constructor(
|
||||||
private val nsSettingsStatus: NSSettingsStatus,
|
private val nsSettingsStatus: NSSettingsStatus,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private val buildHelper: BuildHelper,
|
private val buildHelper: BuildHelper,
|
||||||
private val config: Config
|
private val config: Config,
|
||||||
|
private val loggerUtils: LoggerUtils
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(PluginDescription()
|
||||||
.mainType(PluginType.GENERAL)
|
.mainType(PluginType.GENERAL)
|
||||||
.fragmentClass(MaintenanceFragment::class.java.name)
|
.fragmentClass(MaintenanceFragment::class.java.name)
|
||||||
|
@ -51,8 +52,7 @@ class MaintenancePlugin @Inject constructor(
|
||||||
fun sendLogs() {
|
fun sendLogs() {
|
||||||
val recipient = sp.getString(R.string.key_maintenance_logs_email, "logs@androidaps.org")
|
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 amount = sp.getInt(R.string.key_maintenance_logs_amount, 2)
|
||||||
val logDirectory = LoggerUtils.getLogDirectory()
|
val logs = getLogFiles(amount)
|
||||||
val logs = getLogFiles(logDirectory, amount)
|
|
||||||
val zipDir = context.getExternalFilesDir("exports")
|
val zipDir = context.getExternalFilesDir("exports")
|
||||||
val zipFile = File(zipDir, constructName())
|
val zipFile = File(zipDir, constructName())
|
||||||
aapsLogger.debug("zipFile: ${zipFile.absolutePath}")
|
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
|
//todo replace this with a call on startup of the application, specifically to remove
|
||||||
// unnecessary garbage from the log exports
|
// unnecessary garbage from the log exports
|
||||||
fun deleteLogs() {
|
fun deleteLogs() {
|
||||||
LoggerUtils.getLogDirectory()?.let { logDirectory ->
|
val logDir = File(loggerUtils.logDirectory)
|
||||||
val logDir = File(logDirectory)
|
val files = logDir.listFiles { _: File?, name: String ->
|
||||||
val files = logDir.listFiles { _: File?, name: String ->
|
(name.startsWith("AndroidAPS") && name.endsWith(".zip"))
|
||||||
(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 exportDir = File(loggerUtils.logDirectory, "exports")
|
||||||
val amount = sp.getInt(R.string.key_logshipper_amount, 2)
|
if (exportDir.exists()) {
|
||||||
val keepIndex = amount - 1
|
val expFiles = exportDir.listFiles()
|
||||||
if (keepIndex < delFiles.size) {
|
for (file in expFiles) {
|
||||||
delFiles = delFiles.subList(keepIndex, delFiles.size)
|
file.delete()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
exportDir.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,17 +96,16 @@ class MaintenancePlugin @Inject constructor(
|
||||||
*
|
*
|
||||||
* The log files are sorted by the name descending.
|
* The log files are sorted by the name descending.
|
||||||
*
|
*
|
||||||
* @param directory
|
|
||||||
* @param amount
|
* @param amount
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun getLogFiles(directory: String, amount: Int): List<File> {
|
fun getLogFiles(amount: Int): List<File> {
|
||||||
aapsLogger.debug("getting $amount logs from directory $directory")
|
aapsLogger.debug("getting $amount logs from directory ${loggerUtils.logDirectory}")
|
||||||
val logDir = File(directory)
|
val logDir = File(loggerUtils.logDirectory)
|
||||||
val files = logDir.listFiles { _: File?, name: String ->
|
val files = logDir.listFiles { _: File?, name: String ->
|
||||||
(name.startsWith("AndroidAPS")
|
(name.startsWith("AndroidAPS")
|
||||||
&& (name.endsWith(".log")
|
&& (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) }
|
Arrays.sort(files) { f1: File, f2: File -> f2.name.compareTo(f1.name) }
|
||||||
val result = listOf(*files)
|
val result = listOf(*files)
|
||||||
|
@ -139,7 +136,7 @@ class MaintenancePlugin @Inject constructor(
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private fun constructName(): String {
|
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>) {
|
private fun zip(zipFile: File?, files: List<File>) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
import dagger.android.support.DaggerFragment;
|
import dagger.android.support.DaggerFragment;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
|
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 UploadQueue uploadQueue;
|
||||||
@Inject FabricPrivacy fabricPrivacy;
|
@Inject FabricPrivacy fabricPrivacy;
|
||||||
@Inject AapsSchedulers aapsSchedulers;
|
@Inject AapsSchedulers aapsSchedulers;
|
||||||
|
@Inject UserEntryLogger uel;
|
||||||
|
|
||||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||||
|
|
||||||
|
@ -121,6 +123,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
|
||||||
break;
|
break;
|
||||||
case R.id.nsclientinternal_clearqueue:
|
case R.id.nsclientinternal_clearqueue:
|
||||||
OKDialog.showConfirmation(getContext(), resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), () -> {
|
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();
|
uploadQueue.clearQueue();
|
||||||
updateGui();
|
updateGui();
|
||||||
fabricPrivacy.logCustom("NSClientClearQueue");
|
fabricPrivacy.logCustom("NSClientClearQueue");
|
||||||
|
@ -136,6 +139,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
|
||||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
switch (buttonView.getId()) {
|
switch (buttonView.getId()) {
|
||||||
case R.id.nsclientinternal_paused:
|
case R.id.nsclientinternal_paused:
|
||||||
|
uel.log("NS PAUSED", "", 0.0, 0.0, isChecked ? 1 : 0, 0);
|
||||||
nsClientPlugin.pause(isChecked);
|
nsClientPlugin.pause(isChecked);
|
||||||
updateGui();
|
updateGui();
|
||||||
fabricPrivacy.logCustom("NSClientPause");
|
fabricPrivacy.logCustom("NSClientPause");
|
||||||
|
|
|
@ -5,6 +5,7 @@ import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
|
@ -116,7 +117,8 @@ class NSSettingsStatus @Inject constructor(
|
||||||
private val rxBus: RxBusWrapper,
|
private val rxBus: RxBusWrapper,
|
||||||
private val defaultValueHelper: DefaultValueHelper,
|
private val defaultValueHelper: DefaultValueHelper,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val config: Config
|
private val config: Config,
|
||||||
|
private val uel: UserEntryLogger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var nightscoutVersionName = ""
|
var nightscoutVersionName = ""
|
||||||
|
@ -127,7 +129,7 @@ class NSSettingsStatus @Inject constructor(
|
||||||
fun handleNewData(nightscoutVersionName: String, nightscoutVersionCode: Int, status: JSONObject) {
|
fun handleNewData(nightscoutVersionName: String, nightscoutVersionCode: Int, status: JSONObject) {
|
||||||
this.nightscoutVersionName = nightscoutVersionName
|
this.nightscoutVersionName = nightscoutVersionName
|
||||||
aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: $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)
|
val notification = Notification(Notification.OLD_NS, resourceHelper.gs(R.string.unsupportednsversion), Notification.NORMAL)
|
||||||
rxBus.send(EventNewNotification(notification))
|
rxBus.send(EventNewNotification(notification))
|
||||||
} else {
|
} else {
|
||||||
|
@ -233,6 +235,7 @@ class NSSettingsStatus @Inject constructor(
|
||||||
getExtendedWarnValue("sage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_sage_critical, it) }
|
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", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) }
|
||||||
getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, 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)
|
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.events.Event
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.BackpressureStrategy
|
import io.reactivex.BackpressureStrategy
|
||||||
|
|
|
@ -27,7 +27,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -363,7 +363,7 @@ class OpenHumansUploader @Inject constructor(
|
||||||
copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
|
copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
|
||||||
.andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows + treatmentsPlugin.service.count()) })
|
.andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows + treatmentsPlugin.service.count()) })
|
||||||
.doOnSuccess { maxProgress = it }
|
.doOnSuccess { maxProgress = it }
|
||||||
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } }
|
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } }
|
||||||
.map { enqueueTreatment(it); increaseCounter() }
|
.map { enqueueTreatment(it); increaseCounter() }
|
||||||
.ignoreElements()
|
.ignoreElements()
|
||||||
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
|
.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.events.*
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
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.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
@ -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.activities.QuickWizardListActivity
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
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.GlucoseStatus
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
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 dexcomMediator: DexcomPlugin.DexcomMediator
|
||||||
@Inject lateinit var xdripPlugin: XdripPlugin
|
@Inject lateinit var xdripPlugin: XdripPlugin
|
||||||
@Inject lateinit var notificationStore: NotificationStore
|
@Inject lateinit var notificationStore: NotificationStore
|
||||||
@Inject lateinit var actionStringHandler: ActionStringHandler
|
|
||||||
@Inject lateinit var quickWizard: QuickWizard
|
@Inject lateinit var quickWizard: QuickWizard
|
||||||
@Inject lateinit var buildHelper: BuildHelper
|
@Inject lateinit var buildHelper: BuildHelper
|
||||||
@Inject lateinit var commandQueue: CommandQueue
|
@Inject lateinit var commandQueue: CommandQueue
|
||||||
|
@ -109,6 +109,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
||||||
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -341,10 +342,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
|
||||||
?: "".toSpanned(), {
|
?: "".toSpanned(), {
|
||||||
aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL")
|
uel.log("ACCEPT TEMP BASAL")
|
||||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
||||||
actionStringHandler.handleInitiate("cancelChangeRequest")
|
rxBus.send(EventWearDoAction("cancelChangeRequest"))
|
||||||
loopPlugin.acceptChangeRequest()
|
loopPlugin.acceptChangeRequest()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -445,7 +446,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
|
|
||||||
// QuickWizard button
|
// QuickWizard button
|
||||||
val quickWizardEntry = quickWizard.getActive()
|
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
|
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
|
||||||
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false)
|
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false)
|
||||||
binding.buttonsLayout.quickWizardButton.text = quickWizardEntry.buttonText() + "\n" + resourceHelper.gs(R.string.format_carbs, quickWizardEntry.carbs()) +
|
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.lastOpenModeAccept == 0L || lastRun.lastOpenModeAccept < lastRun.lastAPSRun) &&// never accepted or before last result
|
||||||
lastRun.constraintsProcessed?.isChangeRequested == true // change is requested
|
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.visibility = View.VISIBLE
|
||||||
binding.buttonsLayout.acceptTempButton.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
|
binding.buttonsLayout.acceptTempButton.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
|
||||||
} else {
|
} else {
|
||||||
|
@ -470,10 +471,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
}
|
}
|
||||||
|
|
||||||
// **** Various treatment buttons ****
|
// **** 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.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.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.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.insulinButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
|
||||||
|
|
||||||
// **** Calibration & CGM buttons ****
|
// **** Calibration & CGM buttons ****
|
||||||
val xDripIsBgSource = xdripPlugin.isEnabled(PluginType.BGSOURCE)
|
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.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||||
binding.infoLayout.deltaLarge.setTextColor(color)
|
binding.infoLayout.deltaLarge.setTextColor(color)
|
||||||
binding.infoLayout.delta.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
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.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||||
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)
|
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||||
} else {
|
} else {
|
||||||
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
||||||
binding.infoLayout.avgDelta.text = ""
|
binding.infoLayout.avgDelta.text = ""
|
||||||
|
@ -632,7 +633,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
binding.infoLayout.apsModeText.visibility = View.VISIBLE
|
binding.infoLayout.apsModeText.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
pump.isSuspended -> {
|
pump.isSuspended() -> {
|
||||||
binding.infoLayout.apsMode.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Omnipod_Eros) {
|
binding.infoLayout.apsMode.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Omnipod_Eros) {
|
||||||
// For Omnipod, indicate the pump as disconnected when it's suspended.
|
// For Omnipod, indicate the pump as disconnected when it's suspended.
|
||||||
// The only way to 'reconnect' it, is through the Omnipod tab
|
// 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)
|
graphData.addTreatments(fromTime, endTime)
|
||||||
|
|
||||||
// set manual x bounds to have nice steps
|
// set manual x bounds to have nice steps
|
||||||
graphData.setNumVerticalLables()
|
graphData.setNumVerticalLabels()
|
||||||
graphData.formatAxis(fromTime, endTime)
|
graphData.formatAxis(fromTime, endTime)
|
||||||
|
|
||||||
|
|
||||||
|
@ -887,23 +888,25 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
var useDevForScale = false
|
var useDevForScale = false
|
||||||
var useRatioForScale = false
|
var useRatioForScale = false
|
||||||
var useDSForScale = false
|
var useDSForScale = false
|
||||||
var useIAForScale = false
|
var useBGIForScale = false
|
||||||
when {
|
when {
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = 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
|
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.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.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.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)
|
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
|
// 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.COB.ordinal] ||
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
|
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.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]
|
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
|
||||||
).toVisibility()
|
).toVisibility()
|
||||||
secondaryGraphsData[g].performUpdate()
|
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),
|
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),
|
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),
|
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)
|
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.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
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.plugins.general.overview.events.EventQuickWizardChange
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
|
|
@ -66,7 +66,7 @@ class GraphData(
|
||||||
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
||||||
if (bgReadingsArray?.isEmpty() != false) {
|
if (bgReadingsArray?.isEmpty() != false) {
|
||||||
aapsLogger.debug("No BG data.")
|
aapsLogger.debug("No BG data.")
|
||||||
maxY = 10.0
|
maxY = if (units == Constants.MGDL) 180.0 else 10.0
|
||||||
minY = 0.0
|
minY = 0.0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class GraphData(
|
||||||
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
|
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()
|
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) {
|
fun addActivity(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||||
val actArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
val actArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
val actArrayPred: MutableList<ScaledDataPoint> = ArrayList()
|
val actArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
val now = System.currentTimeMillis().toDouble()
|
val now = System.currentTimeMillis().toDouble()
|
||||||
val actScale = Scale()
|
val actScale = Scale()
|
||||||
var total: IobTotal
|
var total: IobTotal
|
||||||
|
@ -305,7 +305,7 @@ class GraphData(
|
||||||
}
|
}
|
||||||
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
|
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
|
||||||
val act: Double = total.activity
|
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))
|
maxIAValue = max(maxIAValue, abs(act))
|
||||||
time += 5 * 60 * 1000L
|
time += 5 * 60 * 1000L
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@ class GraphData(
|
||||||
it.color = resourceHelper.gc(R.color.activity)
|
it.color = resourceHelper.gc(R.color.activity)
|
||||||
it.thickness = 3
|
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 ->
|
it.setCustomPaint(Paint().also { paint ->
|
||||||
paint.style = Paint.Style.STROKE
|
paint.style = Paint.Style.STROKE
|
||||||
paint.strokeWidth = 3f
|
paint.strokeWidth = 3f
|
||||||
|
@ -329,8 +329,51 @@ class GraphData(
|
||||||
actScale.setMultiplier(maxY * scale / maxIAValue)
|
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)
|
// 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 iobSeries: FixedLineGraphSeries<ScaledDataPoint?>
|
||||||
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
|
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
var maxIobValueFound = Double.MIN_VALUE
|
var maxIobValueFound = Double.MIN_VALUE
|
||||||
|
@ -340,11 +383,15 @@ class GraphData(
|
||||||
while (time <= toTime) {
|
while (time <= toTime) {
|
||||||
val profile = profileFunction.getProfile(time)
|
val profile = profileFunction.getProfile(time)
|
||||||
var iob = 0.0
|
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.02) {
|
||||||
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||||
iobArray.add(ScaledDataPoint(time, iob, 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
|
lastIob = iob
|
||||||
}
|
}
|
||||||
time += 5 * 60 * 1000L
|
time += 5 * 60 * 1000L
|
||||||
|
@ -359,22 +406,22 @@ class GraphData(
|
||||||
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData")
|
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData")
|
||||||
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
|
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
|
||||||
val isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null
|
val isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null
|
||||||
val iobPred: MutableList<DataPointWithLabelInterface> = ArrayList()
|
val iobPrediction: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||||
val iobPredArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
val iobPredictionArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||||
for (i in iobPredArray) {
|
for (i in iobPredictionArray) {
|
||||||
iobPred.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
|
iobPrediction.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
|
||||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||||
}
|
}
|
||||||
addSeries(PointsWithLabelGraphSeries(Array(iobPred.size) { i -> iobPred[i] }))
|
addSeries(PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }))
|
||||||
val iobPred2: MutableList<DataPointWithLabelInterface> = ArrayList()
|
val iobPrediction2: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||||
val iobPredArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
val iobPredictionArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||||
for (i in iobPredArray2) {
|
for (i in iobPredictionArray2) {
|
||||||
iobPred2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
|
iobPrediction2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
|
||||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||||
}
|
}
|
||||||
addSeries(PointsWithLabelGraphSeries(Array(iobPred2.size) { i -> iobPred2[i] }))
|
addSeries(PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] }))
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray))
|
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray))
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray2))
|
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray2))
|
||||||
}
|
}
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = maxIobValueFound
|
maxY = maxIobValueFound
|
||||||
|
@ -395,7 +442,7 @@ class GraphData(
|
||||||
while (time <= toTime) {
|
while (time <= toTime) {
|
||||||
val profile = profileFunction.getProfile(time)
|
val profile = profileFunction.getProfile(time)
|
||||||
var iob = 0.0
|
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.02) {
|
||||||
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||||
iobArray.add(ScaledDataPoint(time, iob, iobScale))
|
iobArray.add(ScaledDataPoint(time, iob, iobScale))
|
||||||
|
@ -460,14 +507,23 @@ class GraphData(
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
// 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)
|
class DeviationDataPoint(x: Double, y: Double, var color: Int, scale: Scale) : ScaledDataPoint(x, y, scale)
|
||||||
|
|
||||||
val devArray: MutableList<DeviationDataPoint> = ArrayList()
|
val devArray: MutableList<DeviationDataPoint> = ArrayList()
|
||||||
var maxDevValueFound = 0.0
|
var maxDevValueFound = 0.0
|
||||||
val devScale = Scale()
|
val devScale = Scale()
|
||||||
var time = fromTime
|
var time = fromTime
|
||||||
|
var total: IobTotal
|
||||||
|
|
||||||
while (time <= toTime) {
|
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 ->
|
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
|
||||||
var color = resourceHelper.gc(R.color.deviationblack) // "="
|
var color = resourceHelper.gc(R.color.deviationblack) // "="
|
||||||
if (autosensData.type == "" || autosensData.type == "non-meal") {
|
if (autosensData.type == "" || autosensData.type == "non-meal") {
|
||||||
|
@ -480,7 +536,7 @@ class GraphData(
|
||||||
color = resourceHelper.gc(R.color.deviationgrey)
|
color = resourceHelper.gc(R.color.deviationgrey)
|
||||||
}
|
}
|
||||||
devArray.add(DeviationDataPoint(time.toDouble(), autosensData.deviation, color, devScale))
|
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
|
time += 5 * 60 * 1000L
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ class PersistentNotificationPlugin @Inject constructor(
|
||||||
line1 = line1aa
|
line1 = line1aa
|
||||||
if (glucoseStatus != null) {
|
if (glucoseStatus != null) {
|
||||||
line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
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
|
line1aa += " " + lastBG.trendArrow.symbol
|
||||||
} else {
|
} else {
|
||||||
line1 += " " +
|
line1 += " " +
|
||||||
|
@ -207,7 +207,7 @@ class PersistentNotificationPlugin @Inject constructor(
|
||||||
builder.setCategory(NotificationCompat.CATEGORY_STATUS)
|
builder.setCategory(NotificationCompat.CATEGORY_STATUS)
|
||||||
builder.setSmallIcon(iconsProvider.getNotificationIcon())
|
builder.setSmallIcon(iconsProvider.getNotificationIcon())
|
||||||
builder.setLargeIcon(resourceHelper.decodeResource(iconsProvider.getIcon()))
|
builder.setLargeIcon(resourceHelper.decodeResource(iconsProvider.getIcon()))
|
||||||
if (line1 != null) builder.setContentTitle(line1)
|
builder.setContentTitle(line1)
|
||||||
if (line2 != null) builder.setContentText(line2)
|
if (line2 != null) builder.setContentText(line2)
|
||||||
if (line3 != null) builder.setSubText(line3)
|
if (line3 != null) builder.setSubText(line3)
|
||||||
/// Android Auto
|
/// 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.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
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 info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import java.util.*
|
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