Merge branch 'dev' into virtual_pump_Bug863

This commit is contained in:
Andy Rozman 2018-05-04 10:06:18 +01:00
commit f2df13dbfb
523 changed files with 30337 additions and 11723 deletions

4
.gitignore vendored
View file

@ -7,3 +7,7 @@
*.apk *.apk
build/ build/
.idea/ .idea/
app/src/main/jniLibs
full/
debug/
release/

View file

@ -2,7 +2,7 @@ language: android
jdk: oraclejdk8 jdk: oraclejdk8
env: env:
matrix: matrix:
- ANDROID_TARGET=android-23 ANDROID_ABI=x86 - ANDROID_TARGET=android-23 ANDROID_ABI=x86 org.gradle.jvmargs=-XX:-OmitStackTraceInFastThrow
android: android:
components: components:
- platform-tools - platform-tools
@ -18,7 +18,17 @@ before_install:
script: script:
# Unit Test # Unit Test
- ./gradlew test jacocoTestReport - ./gradlew -Pcoverage testFullDebugUnitTest jacocoTestFullDebugUnitTestReport
after_success: after_success:
- bash <(curl -s https://codecov.io/bash) - bash <(curl -s https://codecov.io/bash)
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.android/build-cache

1
app/.gitignore vendored
View file

@ -1 +0,0 @@
/build

View file

@ -15,15 +15,17 @@ apply plugin: "jacoco-android"
apply plugin: 'com.jakewharton.butterknife' apply plugin: 'com.jakewharton.butterknife'
ext { ext {
supportLibraryVersion = "27.0.2" supportLibraryVersion = "27.1.0"
ormLiteVersion = "4.46" ormLiteVersion = "4.46"
powermockVersion = "1.7.3" powermockVersion = "1.7.3"
dexmakerVersion = "1.2" dexmakerVersion = "1.2"
butterknifeVersion = "8.8.1"
} }
repositories { repositories {
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
jcenter { url "https://jcenter.bintray.com/" }
} }
def generateGitBuild = { -> def generateGitBuild = { ->
@ -47,19 +49,24 @@ def generateGitBuild = { ->
return stringBuilder.toString() return stringBuilder.toString()
} }
tasks.matching {it instanceof Test}.all {
testLogging.events = ["failed", "skipped", "started"]
testLogging.exceptionFormat = "full"
}
android { android {
compileSdkVersion 27 compileSdkVersion 27
buildToolsVersion "${supportLibraryVersion}"
defaultConfig { defaultConfig {
applicationId "info.nightscout.androidaps" applicationId "info.nightscout.androidaps"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 23 targetSdkVersion 25
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "1.58" version "1.60e-dev"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", generateGitBuild() buildConfigField "String", "BUILDVERSION", generateGitBuild()
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk { ndk {
moduleName "BleCommandUtil" moduleName "BleCommandUtil"
@ -69,7 +76,7 @@ android {
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0 // TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0
// has been upgraded (requiring significant code changes), which currently fails release // has been upgraded (requiring significant code changes), which currently fails release
// build with a deprecation warning // build with a deprecation warning
//abortOnError false abortOnError false
// (disabled entirely to avoid reports on the error, which would still be displayed // (disabled entirely to avoid reports on the error, which would still be displayed
// and it's easy to overlook that it's ignored) // and it's easy to overlook that it's ignored)
checkReleaseBuilds false checkReleaseBuilds false
@ -82,7 +89,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
debug { debug {
testCoverageEnabled true testCoverageEnabled (project.hasProperty('coverage') ? true : false)
} }
} }
productFlavors { productFlavors {
@ -97,21 +104,6 @@ android {
buildConfigField "boolean", "APS", "true" buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true" buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false" buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "true"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
}
openloop {
dimension "standard"
resValue "string", "app_name", "AndroidAPS"
versionName version
manifestPlaceholders = [
appIcon: "@mipmap/blueowl"
]
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false" buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false" buildConfigField "boolean", "PUMPCONTROL", "false"
} }
@ -125,7 +117,6 @@ android {
buildConfigField "boolean", "APS", "false" buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "true" buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false" buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false" buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "true" buildConfigField "boolean", "PUMPCONTROL", "true"
} }
@ -139,7 +130,6 @@ android {
buildConfigField "boolean", "APS", "false" buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false" buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "NSCLIENTOLNY", "true" buildConfigField "boolean", "NSCLIENTOLNY", "true"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false" buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false" buildConfigField "boolean", "PUMPCONTROL", "false"
} }
@ -153,12 +143,20 @@ android {
buildConfigField "boolean", "APS", "false" buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false" buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "NSCLIENTOLNY", "false" buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "true" buildConfigField "boolean", "G5UPLOADER", "true"
buildConfigField "boolean", "PUMPCONTROL", "false" buildConfigField "boolean", "PUMPCONTROL", "false"
} }
} }
} compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
testOptions {
unitTests.returnDefaultValues = true
unitTests.includeAndroidResources = true
}
}
allprojects { allprojects {
repositories { repositories {
@ -169,62 +167,100 @@ allprojects {
} }
} }
configurations {
libs
}
dependencies { dependencies {
wearApp project(':wear') wearApp project(':wear')
compile fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
compile("com.crashlytics.sdk.android:crashlytics:2.6.7@aar") { implementation("com.crashlytics.sdk.android:crashlytics:2.6.7@aar") {
transitive = true; transitive = true;
} }
compile("com.crashlytics.sdk.android:answers:1.3.12@aar") { implementation("com.crashlytics.sdk.android:answers:1.3.12@aar") {
transitive = true; transitive = true;
} }
libs "MilosKozak:danars-support-lib:master@zip"
compile "com.android.support:appcompat-v7:${supportLibraryVersion}" implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
compile "com.android.support:support-v4:${supportLibraryVersion}" implementation "com.android.support:support-v4:${supportLibraryVersion}"
compile "com.android.support:cardview-v7:${supportLibraryVersion}" implementation "com.android.support:cardview-v7:${supportLibraryVersion}"
compile "com.android.support:recyclerview-v7:${supportLibraryVersion}" implementation "com.android.support:recyclerview-v7:${supportLibraryVersion}"
compile "com.android.support:gridlayout-v7:${supportLibraryVersion}" implementation "com.android.support:gridlayout-v7:${supportLibraryVersion}"
compile "com.android.support:design:${supportLibraryVersion}" implementation "com.android.support:design:${supportLibraryVersion}"
compile "com.android.support:percent:${supportLibraryVersion}" implementation "com.android.support:percent:${supportLibraryVersion}"
compile "com.wdullaer:materialdatetimepicker:2.3.0" implementation "com.wdullaer:materialdatetimepicker:2.3.0"
compile "com.squareup:otto:1.3.7" implementation 'com.android.support.constraint:constraint-layout:1.0.2'
compile "com.j256.ormlite:ormlite-core:${ormLiteVersion}" implementation "com.squareup:otto:1.3.7"
compile "com.j256.ormlite:ormlite-android:${ormLiteVersion}" implementation "com.j256.ormlite:ormlite-core:${ormLiteVersion}"
compile("com.github.tony19:logback-android-classic:1.1.1-6") { implementation "com.j256.ormlite:ormlite-android:${ormLiteVersion}"
implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
exclude group: "com.google.android", module: "android" exclude group: "com.google.android", module: "android"
} }
compile "org.apache.commons:commons-lang3:3.6" implementation "org.apache.commons:commons-lang3:3.6"
compile "org.slf4j:slf4j-api:1.7.12" implementation "org.slf4j:slf4j-api:1.7.12"
compile "com.jjoe64:graphview:4.0.1" implementation "com.jjoe64:graphview:4.0.1"
compile "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1" implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1"
compile "com.google.android.gms:play-services-wearable:7.5.0" implementation "com.google.android.gms:play-services-wearable:7.5.0"
compile(name: "android-edittext-validator-v1.3.4-mod", ext: "aar") implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
compile("com.google.android:flexbox:0.3.0") { implementation(name: "sightparser-release", ext: "aar")
implementation("com.google.android:flexbox:0.3.0") {
exclude group: "com.android.support" exclude group: "com.android.support"
} }
compile("io.socket:socket.io-client:0.8.3") { implementation("io.socket:socket.io-client:0.8.3") {
// excluding org.json which is provided by Android // excluding org.json which is provided by Android
exclude group: "org.json", module: "json" exclude group: "org.json", module: "json"
} }
compile "com.google.code.gson:gson:2.7" implementation "com.google.code.gson:gson:2.7"
compile "com.google.guava:guava:20.0" implementation "com.google.guava:guava:20.0"
compile "net.danlew:android.joda:2.9.9.1" implementation "net.danlew:android.joda:2.9.9.1"
implementation "uk.com.robust-it:cloning:1.9.9"
api "com.jakewharton:butterknife:8.8.1" implementation 'org.mozilla:rhino:1.7.7.2'
annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"
testCompile "junit:junit:4.12" implementation "com.jakewharton:butterknife:${butterknifeVersion}"
testCompile "org.json:json:20140107" annotationProcessor "com.jakewharton:butterknife-compiler:${butterknifeVersion}"
testCompile "org.mockito:mockito-core:2.7.22"
testCompile "org.powermock:powermock-api-mockito2:${powermockVersion}"
testCompile "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
testCompile "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
testCompile "org.powermock:powermock-module-junit4:${powermockVersion}"
testCompile "joda-time:joda-time:2.9.4.2"
androidTestCompile "org.mockito:mockito-core:2.7.22" testImplementation "junit:junit:4.12"
androidTestCompile "com.google.dexmaker:dexmaker:${dexmakerVersion}" testImplementation "org.json:json:20140107"
androidTestCompile "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}" testImplementation "org.mockito:mockito-core:2.7.22"
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:2.9.4.2"
testImplementation "com.google.truth:truth:0.39"
testImplementation 'org.robolectric:robolectric:3.8'
testImplementation "org.skyscreamer:jsonassert:1.5.0"
androidTestImplementation "org.mockito:mockito-core:2.7.22"
androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"
androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
} }
task unzip(type: Copy) {
def zipPath = configurations.libs.find {it.name.startsWith("danars") }
def zipFile = file(zipPath)
def outputDir = file("${buildDir}/unpacked/dist")
from zipTree(zipFile)
into outputDir
}
task copyLibs(dependsOn: unzip, type: Copy) {
def src = file("${buildDir}/unpacked/dist/danars-support-lib-master")
def target = file("src/main/jniLibs/")
from src
into target
}
task full_clean(type: Delete) {
delete file("src/main/jniLibs")
}
clean.dependsOn full_clean
preBuild.dependsOn copyLibs

Binary file not shown.

Binary file not shown.

View file

@ -15,9 +15,11 @@
<uses-permission android:name="android.permission.SEND_MMS" /> <uses-permission android:name="android.permission.SEND_MMS" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" /> <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="sugar.free.sightremote.HISTORY_BROADCASTS" />
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
@ -47,7 +49,7 @@
android:theme="@style/Theme.AppCompat.Translucent" /> android:theme="@style/Theme.AppCompat.Translucent" />
<activity android:name=".AgreementActivity" /> <activity android:name=".AgreementActivity" />
<activity android:name=".plugins.PumpDanaR.activities.DanaRHistoryActivity" /> <activity android:name=".plugins.PumpDanaR.activities.DanaRHistoryActivity" />
<activity android:name=".plugins.PumpDanaR.activities.DanaRStatsActivity" /> <activity android:name=".TDDStatsActivity" />
<activity android:name=".plugins.Overview.activities.QuickWizardListActivity"> <activity android:name=".plugins.Overview.activities.QuickWizardListActivity">
<intent-filter> <intent-filter>
<action android:name="info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity" /> <action android:name="info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity" />
@ -61,6 +63,7 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".plugins.PumpDanaRS.activities.PairingHelperActivity" /> <activity android:name=".plugins.PumpDanaRS.activities.PairingHelperActivity" />
<activity android:name=".HistoryBrowseActivity" />
<receiver <receiver
android:name=".receivers.DataReceiver" android:name=".receivers.DataReceiver"
@ -110,6 +113,14 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Network change local receiver -->
<receiver android:name=".receivers.NetworkChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
<!-- Service processing incomming data --> <!-- Service processing incomming data -->
<service <service
android:name=".Services.DataService" android:name=".Services.DataService"

View file

@ -0,0 +1,20 @@
// IRTHandler.aidl
package org.monkey.d.ruffy.ruffy.driver;
// Declare any non-default types here with import statements
import org.monkey.d.ruffy.ruffy.driver.display.Menu;
interface IRTHandler {
void log(String message);
void fail(String message);
void requestBluetooth();
void rtStopped();
void rtStarted();
void rtClearDisplay();
void rtUpdateDisplay(in byte[] quarter, int which);
void rtDisplayHandleMenu(in Menu menu);
void rtDisplayHandleNoMenu();
}

View file

@ -0,0 +1,23 @@
// IRuffyService.aidl
package org.monkey.d.ruffy.ruffy.driver;
// Declare any non-default types here with import statements
import org.monkey.d.ruffy.ruffy.driver.IRTHandler;
interface IRuffyService {
void setHandler(IRTHandler handler);
/** Connect to the pump
*
* @return 0 if successful, -1 otherwise
*/
int doRTConnect();
/** Disconnect from the pump */
void doRTDisconnect();
void rtSendKey(byte keyCode, boolean changed);
void resetPairing();
boolean isConnected();
}

View file

@ -0,0 +1,3 @@
package org.monkey.d.ruffy.ruffy.driver.display;
parcelable Menu;

View file

@ -0,0 +1 @@
//b916a900c0899ef58ad58c7427d1c30d3c8731f4

View file

@ -0,0 +1,61 @@
'use strict';
function reason(rT, msg) {
rT.reason = (rT.reason ? rT.reason + '. ' : '') + msg;
console.error(msg);
}
var tempBasalFunctions = {};
tempBasalFunctions.getMaxSafeBasal = function getMaxSafeBasal(profile) {
var max_daily_safety_multiplier = (isNaN(profile.max_daily_safety_multiplier) || profile.max_daily_safety_multiplier == null) ? 3 : profile.max_daily_safety_multiplier;
var current_basal_safety_multiplier = (isNaN(profile.current_basal_safety_multiplier) || profile.current_basal_safety_multiplier == null) ? 4 : profile.current_basal_safety_multiplier;
return Math.min(profile.max_basal, max_daily_safety_multiplier * profile.max_daily_basal, current_basal_safety_multiplier * profile.current_basal);
};
tempBasalFunctions.setTempBasal = function setTempBasal(rate, duration, profile, rT, currenttemp) {
//var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal);
var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
var round_basal = require('./round-basal');
if (rate < 0) {
rate = 0;
} // if >30m @ 0 required, zero temp will be extended to 30m instead
else if (rate > maxSafeBasal) {
rate = maxSafeBasal;
}
var suggestedRate = round_basal(rate, profile);
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && typeof(currenttemp.rate) !== 'undefined' && currenttemp.duration > (duration-10) && currenttemp.duration <= 120 && suggestedRate <= currenttemp.rate * 1.2 && suggestedRate >= currenttemp.rate * 0.8) {
rT.reason += " "+currenttemp.duration+"m left and " + currenttemp.rate + " ~ req " + suggestedRate + "U/hr: no temp required";
return rT;
}
if (suggestedRate === profile.current_basal) {
if (profile.skip_neutral_temps) {
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && currenttemp.duration > 0) {
reason(rT, 'Suggested rate is same as profile rate, a temp basal is active, canceling current temp');
rT.duration = 0;
rT.rate = 0;
return rT;
} else {
reason(rT, 'Suggested rate is same as profile rate, no temp basal is active, doing nothing');
return rT;
}
} else {
reason(rT, 'Setting neutral temp basal of ' + profile.current_basal + 'U/hr');
rT.duration = duration;
rT.rate = suggestedRate;
return rT;
}
} else {
rT.duration = duration;
rT.rate = suggestedRate;
return rT;
}
};
module.exports = tempBasalFunctions;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
<configuration> <configuration>
<!-- Create a file appender for a log in the application's data directory --> <!-- Create a file appender for a log in the application's data directory -->
<property name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/> <property scope="context" name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${EXT_FILES_DIR}/AndroidAPS.log</file> <file>${EXT_FILES_DIR}/AndroidAPS.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

View file

@ -13,10 +13,9 @@ public class Config {
public static final boolean G5UPLOADER = BuildConfig.G5UPLOADER; public static final boolean G5UPLOADER = BuildConfig.G5UPLOADER;
public static final boolean PUMPCONTROL = BuildConfig.PUMPCONTROL; public static final boolean PUMPCONTROL = BuildConfig.PUMPCONTROL;
public static final boolean DANAR = BuildConfig.PUMPDRIVERS; public static final boolean HWPUMPS = BuildConfig.PUMPDRIVERS;
public static final boolean ACTION = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean ACTION = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean VIRTUALPUMP = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean MDI = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean MDI = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean OTHERPROFILES = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean OTHERPROFILES = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean SAFETY = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean SAFETY = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
@ -31,12 +30,12 @@ public class Config {
public static final boolean logPumpComm = true; public static final boolean logPumpComm = true;
public static final boolean logPrefsChange = true; public static final boolean logPrefsChange = true;
public static final boolean logConfigBuilder = true; public static final boolean logConfigBuilder = true;
public static final boolean logConstraintsChanges = true;
public static final boolean logNSUpload = true; public static final boolean logNSUpload = true;
public static final boolean logPumpActions = true; public static final boolean logPumpActions = true;
public static final boolean logCongigBuilderActions = true; public static final boolean logCongigBuilderActions = true;
public static final boolean logAutosensData = false; public static final boolean logAutosensData = false;
public static final boolean logEvents = false; public static final boolean logEvents = false;
public static final boolean logProfile = false;
// DanaR specific // DanaR specific
public static final boolean logDanaBTComm = true; public static final boolean logDanaBTComm = true;

View file

@ -1,6 +1,6 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import com.j256.ormlite.stmt.query.In; import info.nightscout.utils.T;
/** /**
* Created by mike on 07.06.2016. * Created by mike on 07.06.2016.
@ -14,10 +14,11 @@ public class Constants {
public static final double defaultDIA = 3d; public static final double defaultDIA = 3d;
public static final double basalAbsoluteOnlyForCheckLimit = 10101010d; public static final Double REALLYHIGHBASALRATE = 1111111d;
public static final Integer basalPercentOnlyForCheckLimit = 10101010; public static final Integer REALLYHIGHPERCENTBASALRATE = 1111111;
public static final double bolusOnlyForCheckLimit = 10101010d; public static final double REALLYHIGHBOLUS = 1111111d;
public static final Integer carbsOnlyForCheckLimit = 10101010; public static final Integer REALLYHIGHCARBS = 1111111;
public static final double REALLYHIGHIOB = 1111111d;
public static final Integer notificationID = 556677; public static final Integer notificationID = 556677;
@ -35,20 +36,20 @@ public class Constants {
public static final int CPP_MIN_TIMESHIFT = -6; public static final int CPP_MIN_TIMESHIFT = -6;
public static final int CPP_MAX_TIMESHIFT = 23; public static final int CPP_MAX_TIMESHIFT = 23;
// Very Hard Limits Ranges
// First value is the Lowest and second value is the Highest a Limit can define
public static final int[] VERY_HARD_LIMIT_MIN_BG = {72,180};
public static final int[] VERY_HARD_LIMIT_MAX_BG = {90,270};
public static final int[] VERY_HARD_LIMIT_TARGET_BG = {80,200};
// Very Hard Limits Ranges for Temp Targets
public static final int[] VERY_HARD_LIMIT_TEMP_MIN_BG = {72,180};
public static final int[] VERY_HARD_LIMIT_TEMP_MAX_BG = {72,270};
public static final int[] VERY_HARD_LIMIT_TEMP_TARGET_BG = {72,200};
//DanaR //DanaR
public static final double dailyLimitWarning = 0.95d; public static final double dailyLimitWarning = 0.95d;
// Temp targets
public static final int defaultActivityTTDuration = 90; // min
public static final double defaultActivityTTmgdl = 140d;
public static final double defaultActivityTTmmol = 8d;
public static final int defaultEatingSoonTTDuration = 45; // min
public static final double defaultEatingSoonTTmgdl = 90d;
public static final double defaultEatingSoonTTmmol = 5d;
public static final int defaultHypoTTDuration = 30; // min
public static final double defaultHypoTTmgdl = 120d;
public static final double defaultHypoTTmmol = 6.5d;
//NSClientInternal //NSClientInternal
public static final int MAX_LOG_LINES = 100; public static final int MAX_LOG_LINES = 100;
@ -58,8 +59,12 @@ public class Constants {
//Autosens //Autosens
public static final double DEVIATION_TO_BE_EQUAL = 2.0; public static final double DEVIATION_TO_BE_EQUAL = 2.0;
public static final double DEFAULT_MAX_ABSORPTION_TIME = 6.0;
// Pump // Pump
public static final int PUMP_MAX_CONNECTION_TIME_IN_SECONDS = 120 - 1; public static final int PUMP_MAX_CONNECTION_TIME_IN_SECONDS = 120 - 1;
public static final int MIN_WATCHDOG_INTERVAL_IN_SECONDS = 12 * 60; public static final int MIN_WATCHDOG_INTERVAL_IN_SECONDS = 12 * 60;
//SMS Communicator
public static final long SMS_CONFIRM_TIMEOUT = T.mins(5).msecs();
} }

View file

@ -0,0 +1,404 @@
package info.nightscout.androidaps;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import com.jjoe64.graphview.GraphView;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnLongClick;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCustomCalculationFinished;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.graphData.GraphData;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
public class HistoryBrowseActivity extends AppCompatActivity {
private static Logger log = LoggerFactory.getLogger(HistoryBrowseActivity.class);
ImageButton chartButton;
boolean showBasal = true;
boolean showIob, showCob, showDev, showRat, showDevslope;
@BindView(R.id.historybrowse_date)
Button buttonDate;
@BindView(R.id.historybrowse_zoom)
Button buttonZoom;
@BindView(R.id.historyybrowse_bggraph)
GraphView bgGraph;
@BindView(R.id.historybrowse_iobgraph)
GraphView iobGraph;
@BindView(R.id.historybrowse_seekBar)
SeekBar seekBar;
@BindView(R.id.historybrowse_noprofile)
TextView noProfile;
private int rangeToDisplay = 24; // for graph
private long start;
IobCobCalculatorPlugin iobCobCalculatorPlugin;
EventCustomCalculationFinished eventCustomCalculationFinished = new EventCustomCalculationFinished();
public HistoryBrowseActivity() {
iobCobCalculatorPlugin = new IobCobCalculatorPlugin();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_historybrowse);
ButterKnife.bind(this);
bgGraph.getGridLabelRenderer().setGridColor(MainApp.sResources.getColor(R.color.graphgrid));
bgGraph.getGridLabelRenderer().reloadStyles();
iobGraph.getGridLabelRenderer().setGridColor(MainApp.sResources.getColor(R.color.graphgrid));
iobGraph.getGridLabelRenderer().reloadStyles();
iobGraph.getGridLabelRenderer().setHorizontalLabelsVisible(false);
bgGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
iobGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
iobGraph.getGridLabelRenderer().setNumVerticalLabels(5);
setupChartMenu();
// set start of current day
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.HOUR_OF_DAY, 0);
start = calendar.getTimeInMillis();
}
@Override
protected void onResume() {
super.onResume();
updateGUI("onResume");
}
@OnClick(R.id.historybrowse_start)
void onClickStart() {
}
@OnClick(R.id.historybrowse_left)
void onClickLeft() {
start -= rangeToDisplay * 60 * 60 * 1000L;
updateGUI("left");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onClickLeft", start, true, eventCustomCalculationFinished);
}
@OnClick(R.id.historybrowse_right)
void onClickRight() {
start += rangeToDisplay * 60 * 60 * 1000L;
updateGUI("right");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onClickRight", start, true, eventCustomCalculationFinished);
}
@OnClick(R.id.historybrowse_end)
void onClickEnd() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.HOUR_OF_DAY, 0);
start = calendar.getTimeInMillis();
updateGUI("resetToMidnight");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onClickEnd", start, true, eventCustomCalculationFinished);
}
@OnClick(R.id.historybrowse_zoom)
void onClickZoom() {
rangeToDisplay += 6;
rangeToDisplay = rangeToDisplay > 24 ? 6 : rangeToDisplay;
updateGUI("rangeChange");
}
@OnLongClick(R.id.historybrowse_zoom)
boolean onLongClickZoom() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(start);
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.HOUR_OF_DAY, 0);
start = calendar.getTimeInMillis();
updateGUI("resetToMidnight");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onLongClickZoom", start, true, eventCustomCalculationFinished);
return true;
}
@OnClick(R.id.historybrowse_date)
void onClickDate() {
}
@Subscribe
public void onStatusEvent(final EventAutosensCalculationFinished e) {
Activity activity = this;
if (activity != null && e.cause == eventCustomCalculationFinished) {
log.debug("EventAutosensCalculationFinished");
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
updateGUI("EventAutosensCalculationFinished");
}
});
}
}
void updateGUI(String from) {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
final Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) {
noProfile.setVisibility(View.VISIBLE);
return;
} else {
noProfile.setVisibility(View.GONE);
}
final String units = profile.getUnits();
double lowLineSetting = SP.getDouble("low_mark", Profile.fromMgdlToUnits(OverviewPlugin.bgTargetLow, units));
double highLineSetting = SP.getDouble("high_mark", Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units));
if (lowLineSetting < 1)
lowLineSetting = Profile.fromMgdlToUnits(76d, units);
if (highLineSetting < 1)
highLineSetting = Profile.fromMgdlToUnits(180d, units);
final double lowLine = lowLineSetting;
final double highLine = highLineSetting;
final boolean showPrediction = false;
int hoursToFetch;
final long toTime;
final long fromTime;
//if (showPrediction) {
//int predHours = (int) (Math.ceil(((DetermineBasalResultAMA) finalLastRun.constraintsProcessed).getLatestPredictionsTime() - System.currentTimeMillis()) / (60 * 60 * 1000));
//predHours = Math.min(2, predHours);
//predHours = Math.max(0, predHours);
//hoursToFetch = rangeToDisplay - predHours;
//toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding - Graphview specific
//fromTime = toTime - hoursToFetch * 60 * 60 * 1000L;
//endTime = toTime + predHours * 60 * 60 * 1000L;
//} else {
fromTime = start + 100000;
toTime = start + rangeToDisplay * 60 * 60 * 1000L;
//}
buttonDate.setText(DateUtil.dateAndTimeString(start));
buttonZoom.setText(String.valueOf(rangeToDisplay));
log.debug("Period: " + DateUtil.dateAndTimeString(fromTime) + " - " + DateUtil.dateAndTimeString(toTime));
final long pointer = System.currentTimeMillis();
// ------------------ 1st graph
final GraphData graphData = new GraphData(bgGraph, IobCobCalculatorPlugin.getPlugin());
// **** In range Area ****
graphData.addInRangeArea(fromTime, toTime, lowLine, highLine);
// **** BG ****
if (showPrediction)
//graphData.addBgReadings(fromTime, toTime, lowLine, highLine, (DetermineBasalResultAMA) finalLastRun.constraintsProcessed);
;
else
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null);
// set manual x bounds to have nice steps
graphData.formatAxis(fromTime, toTime);
// Treatments
graphData.addTreatments(fromTime, toTime);
// add basal data
if (pump.getPumpDescription().isTempBasalCapable && showBasal) {
graphData.addBasals(fromTime, toTime, lowLine / graphData.maxY / 1.2d);
}
// **** NOW line ****
graphData.addNowLine(pointer);
// ------------------ 2nd graph
final GraphData secondGraphData = new GraphData(iobGraph, iobCobCalculatorPlugin);
boolean useIobForScale = false;
boolean useCobForScale = false;
boolean useDevForScale = false;
boolean useRatioForScale = false;
boolean useDevSlopeForScale = false;
if (showIob) {
useIobForScale = true;
} else if (showCob) {
useCobForScale = true;
} else if (showDev) {
useDevForScale = true;
} else if (showRat) {
useRatioForScale = true;
} else if (showDevslope) {
useDevSlopeForScale = true;
}
if (showIob)
secondGraphData.addIob(fromTime, toTime, useIobForScale, 1d);
if (showCob)
secondGraphData.addCob(fromTime, toTime, useCobForScale, useCobForScale ? 1d : 0.5d);
if (showDev)
secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1d);
if (showRat)
secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1d);
if (showDevslope)
secondGraphData.addDeviationSlope(fromTime, toTime, useDevSlopeForScale, 1d);
// **** NOW line ****
// set manual x bounds to have nice steps
secondGraphData.formatAxis(fromTime, toTime);
secondGraphData.addNowLine(pointer);
// do GUI update
if (showIob || showCob || showDev || showRat || showDevslope) {
iobGraph.setVisibility(View.VISIBLE);
} else {
iobGraph.setVisibility(View.GONE);
}
// finally enforce drawing of graphs
graphData.performUpdate();
secondGraphData.performUpdate();
}
private void setupChartMenu() {
chartButton = (ImageButton) findViewById(R.id.overview_chartMenuButton);
chartButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MenuItem item;
CharSequence title;
SpannableString s;
PopupMenu popup = new PopupMenu(v.getContext(), v);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.BAS.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_basals));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.basal, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showBasal);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.IOB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_iob));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showIob);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.COB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_cob));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showCob);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEV.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_deviations));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showDev);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.SEN.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_sensitivity));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.ratio, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showRat);
if (MainApp.devBranch) {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope");
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showDevslope);
}
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) {
showBasal = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.IOB.ordinal()) {
showIob = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.COB.ordinal()) {
showCob = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.DEV.ordinal()) {
showDev = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) {
showRat = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) {
showDevslope = !item.isChecked();
}
updateGUI("onGraphCheckboxesCheckedChanged");
return true;
}
});
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
@Override
public void onDismiss(PopupMenu menu) {
chartButton.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp);
}
});
popup.show();
}
});
}
}

View file

@ -19,6 +19,9 @@ import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu; import android.support.v7.widget.PopupMenu;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -27,6 +30,7 @@ import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.TextView;
import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule; import com.joanzapata.iconify.fonts.FontAwesomeModule;
@ -35,14 +39,16 @@ import com.squareup.otto.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Services.AlarmSoundService;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventFeatureRunning;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Food.FoodPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock; import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.tabs.SlidingTabLayout; import info.nightscout.androidaps.tabs.SlidingTabLayout;
import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.utils.ImportExportPrefs; import info.nightscout.utils.ImportExportPrefs;
@ -112,9 +118,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if(ev.recreate) { if (ev.recreate) {
recreate(); recreate();
}else { } else {
try { // activity may be destroyed try { // activity may be destroyed
setUpTabs(true); setUpTabs(true);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
@ -171,7 +177,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
// Added in 1.57 at 21.01.2018 // Added in 1.57 at 21.01.2018
Integer unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30); Integer unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30);
SP.remove(R.string.key_pump_unreachable_threshold); SP.remove(R.string.key_pump_unreachable_threshold);
if(unreachable_threshold < 30) unreachable_threshold = 30; if (unreachable_threshold < 30) unreachable_threshold = 30;
SP.putString(R.string.key_pump_unreachable_threshold, unreachable_threshold.toString()); SP.putString(R.string.key_pump_unreachable_threshold, unreachable_threshold.toString());
} }
@ -222,6 +228,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
super.onResume(); super.onResume();
askForSMSPermissions(); askForSMSPermissions();
askForLocationPermissions(); askForLocationPermissions();
MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN));
} }
@Override @Override
@ -358,6 +365,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
}, null); }, null);
break; break;
case R.id.nav_historybrowser:
startActivity(new Intent(v.getContext(), HistoryBrowseActivity.class));
break;
case R.id.nav_resetdb: case R.id.nav_resetdb:
new AlertDialog.Builder(v.getContext()) new AlertDialog.Builder(v.getContext())
.setTitle(R.string.nav_resetdb) .setTitle(R.string.nav_resetdb)
@ -367,6 +377,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
MainApp.getDbHelper().resetDatabases(); MainApp.getDbHelper().resetDatabases();
// should be handled by Plugin-Interface and
// additional service interface and plugin registry
FoodPlugin.getPlugin().getService().resetFood();
TreatmentsPlugin.getPlugin().getService().resetTreatments();
} }
}) })
.create() .create()
@ -386,16 +400,23 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
case R.id.nav_about: case R.id.nav_about:
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
builder.setTitle(getString(R.string.app_name) + " " + BuildConfig.VERSION); builder.setTitle(getString(R.string.app_name) + " " + BuildConfig.VERSION);
if (Config.NSCLIENT|| Config.G5UPLOADER) if (Config.NSCLIENT || Config.G5UPLOADER)
builder.setIcon(R.mipmap.yellowowl); builder.setIcon(R.mipmap.yellowowl);
else else
builder.setIcon(R.mipmap.blueowl); builder.setIcon(R.mipmap.blueowl);
String message = "Build: " + BuildConfig.BUILDVERSION + "\n"; String message = "Build: " + BuildConfig.BUILDVERSION + "\n";
message += MainApp.sResources.getString(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n";
builder.setMessage(message); message += getString(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName;
if (MainApp.engineeringMode)
message += "\n" + MainApp.gs(R.string.engineering_mode_enabled);
message += getString(R.string.about_link_urls);
final SpannableString messageSpanned = new SpannableString(message);
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS);
builder.setMessage(messageSpanned);
builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null);
AlertDialog alertDialog = builder.create(); AlertDialog alertDialog = builder.create();
alertDialog.show(); alertDialog.show();
((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
break; break;
case R.id.nav_exit: case R.id.nav_exit:
log.debug("Exiting"); log.debug("Exiting");

View file

@ -20,57 +20,63 @@ import net.danlew.android.joda.JodaTimeAndroid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import ch.qos.logback.classic.LoggerContext;
import info.nightscout.androidaps.Services.Intents; import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.Actions.ActionsFragment; import info.nightscout.androidaps.plugins.Actions.ActionsFragment;
import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin; import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.Food.FoodPlugin; import info.nightscout.androidaps.plugins.Food.FoodPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinFastactingPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinFastactingProlongedPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefUltraRapidActingPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefUltraRapidActingPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver; import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin; import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPercentageProfileFragment;
import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin; import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileSimple.SimpleProfilePlugin; import info.nightscout.androidaps.plugins.ProfileSimple.SimpleProfilePlugin;
import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin;
import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin; import info.nightscout.androidaps.plugins.Source.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin; import info.nightscout.androidaps.plugins.Source.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; import info.nightscout.androidaps.plugins.Source.SourceXdripPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin;
import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin; import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin;
import info.nightscout.androidaps.receivers.DataReceiver; import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.androidaps.receivers.KeepAliveReceiver; import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.androidaps.receivers.NSAlarmReceiver; import info.nightscout.androidaps.receivers.NSAlarmReceiver;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import io.fabric.sdk.android.Fabric; import io.fabric.sdk.android.Fabric;
@ -85,6 +91,7 @@ public class MainApp extends Application {
private static DatabaseHelper sDatabaseHelper = null; private static DatabaseHelper sDatabaseHelper = null;
private static ConfigBuilderPlugin sConfigBuilder = null; private static ConfigBuilderPlugin sConfigBuilder = null;
private static ConstraintChecker sConstraintsChecker = null;
private static ArrayList<PluginBase> pluginsList = null; private static ArrayList<PluginBase> pluginsList = null;
@ -93,20 +100,39 @@ public class MainApp extends Application {
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver(); private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
private LocalBroadcastManager lbm; private LocalBroadcastManager lbm;
public static boolean devBranch;
public static boolean engineeringMode;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
Fabric.with(this, new Crashlytics()); sInstance = this;
Fabric.with(this, new Answers()); sResources = getResources();
sConstraintsChecker = new ConstraintChecker(this);
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
try {
if (FabricPrivacy.fabricEnabled()) {
Fabric.with(this, new Crashlytics());
Fabric.with(this, new Answers());
Crashlytics.setString("BUILDVERSION", BuildConfig.BUILDVERSION);
}
} catch (Exception e) {
android.util.Log.e("ANDROIDAPS", "Error with Fabric init! " + e);
}
JodaTimeAndroid.init(this); JodaTimeAndroid.init(this);
Crashlytics.setString("BUILDVERSION", BuildConfig.BUILDVERSION);
log.info("Version: " + BuildConfig.VERSION_NAME); log.info("Version: " + BuildConfig.VERSION_NAME);
log.info("BuildVersion: " + BuildConfig.BUILDVERSION); log.info("BuildVersion: " + BuildConfig.BUILDVERSION);
sBus = Config.logEvents ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY); String extFilesDir = this.getLogDirectory();
File engineeringModeSemaphore = new File(extFilesDir, "engineering_mode");
sInstance = this; engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile();
sResources = getResources(); devBranch = BuildConfig.VERSION.contains("dev");
sBus = Config.logEvents ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY);
registerLocalBroadcastReceiver(); registerLocalBroadcastReceiver();
@ -116,29 +142,29 @@ public class MainApp extends Application {
pluginsList.add(OverviewPlugin.getPlugin()); pluginsList.add(OverviewPlugin.getPlugin());
pluginsList.add(IobCobCalculatorPlugin.getPlugin()); pluginsList.add(IobCobCalculatorPlugin.getPlugin());
if (Config.ACTION) pluginsList.add(ActionsFragment.getPlugin()); if (Config.ACTION) pluginsList.add(ActionsFragment.getPlugin());
pluginsList.add(InsulinFastactingPlugin.getPlugin());
pluginsList.add(InsulinFastactingProlongedPlugin.getPlugin());
pluginsList.add(InsulinOrefRapidActingPlugin.getPlugin()); pluginsList.add(InsulinOrefRapidActingPlugin.getPlugin());
pluginsList.add(InsulinOrefUltraRapidActingPlugin.getPlugin()); pluginsList.add(InsulinOrefUltraRapidActingPlugin.getPlugin());
pluginsList.add(InsulinOrefFreePeakPlugin.getPlugin()); pluginsList.add(InsulinOrefFreePeakPlugin.getPlugin());
pluginsList.add(SensitivityOref0Plugin.getPlugin()); pluginsList.add(SensitivityOref0Plugin.getPlugin());
pluginsList.add(SensitivityAAPSPlugin.getPlugin()); pluginsList.add(SensitivityAAPSPlugin.getPlugin());
pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin()); pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRKoreanPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRv2Plugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRSPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRSPlugin.getPlugin());
pluginsList.add(CareportalPlugin.getPlugin()); pluginsList.add(CareportalPlugin.getPlugin());
if (Config.HWPUMPS && engineeringMode)
pluginsList.add(InsightPlugin.getPlugin()); // <-- Enable Insight plugin here
if (Config.HWPUMPS) pluginsList.add(ComboPlugin.getPlugin());
if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin());
if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getPlugin()); pluginsList.add(VirtualPumpPlugin.getPlugin());
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin()); if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin()); if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin()); if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSSMBPlugin.getPlugin());
pluginsList.add(NSProfilePlugin.getPlugin()); pluginsList.add(NSProfilePlugin.getPlugin());
if (Config.OTHERPROFILES) pluginsList.add(SimpleProfilePlugin.getPlugin()); if (Config.OTHERPROFILES) pluginsList.add(SimpleProfilePlugin.getPlugin());
if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin()); if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin());
if (Config.OTHERPROFILES)
pluginsList.add(CircadianPercentageProfileFragment.getPlugin());
pluginsList.add(TreatmentsPlugin.getPlugin()); pluginsList.add(TreatmentsPlugin.getPlugin());
if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin()); if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin());
if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin()); if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin());
@ -158,33 +184,33 @@ public class MainApp extends Application {
pluginsList.add(WearPlugin.initPlugin(this)); pluginsList.add(WearPlugin.initPlugin(this));
pluginsList.add(StatuslinePlugin.initPlugin(this)); pluginsList.add(StatuslinePlugin.initPlugin(this));
pluginsList.add(new PersistentNotificationPlugin(this)); pluginsList.add(new PersistentNotificationPlugin(this));
pluginsList.add(NSClientInternalPlugin.getPlugin()); pluginsList.add(NSClientPlugin.getPlugin());
pluginsList.add(sConfigBuilder = ConfigBuilderFragment.getPlugin()); pluginsList.add(sConfigBuilder = ConfigBuilderPlugin.getPlugin());
MainApp.getConfigBuilder().initialize(); MainApp.getConfigBuilder().initialize();
} }
NSUpload.uploadAppStart(); NSUpload.uploadAppStart();
if (Config.NSCLIENT)
Answers.getInstance().logCustom(new CustomEvent("AppStart-NSClient"));
else if (Config.G5UPLOADER)
Answers.getInstance().logCustom(new CustomEvent("AppStart-G5Uploader"));
else if (Config.PUMPCONTROL)
Answers.getInstance().logCustom(new CustomEvent("AppStart-PumpControl"));
else if (MainApp.getConfigBuilder().isClosedModeEnabled())
Answers.getInstance().logCustom(new CustomEvent("AppStart-ClosedLoop"));
else
Answers.getInstance().logCustom(new CustomEvent("AppStart-OpenLoop"));
new Thread(new Runnable() { if (Config.NSCLIENT)
@Override FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-NSClient"));
public void run() { else if (Config.G5UPLOADER)
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-G5Uploader"));
else if (Config.PUMPCONTROL)
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-PumpControl"));
else if (MainApp.getConstraintChecker().isClosedLoopAllowed().value())
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-ClosedLoop"));
else
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-OpenLoop"));
final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (pump != null) {
new Thread(() -> {
SystemClock.sleep(5000); SystemClock.sleep(5000);
ConfigBuilderPlugin.getCommandQueue().readStatus("Initialization", null); ConfigBuilderPlugin.getCommandQueue().readStatus("Initialization", null);
startKeepAliveService(); startKeepAliveService();
} }).start();
}).start(); }
} }
private void registerLocalBroadcastReceiver() { private void registerLocalBroadcastReceiver() {
@ -237,14 +263,15 @@ public class MainApp extends Application {
return sResources.getString(id, args); return sResources.getString(id, args);
} }
public static int gc(int id) {
return sResources.getColor(id);
}
public static MainApp instance() { public static MainApp instance() {
return sInstance; return sInstance;
} }
public static DatabaseHelper getDbHelper() { public static DatabaseHelper getDbHelper() {
if (sDatabaseHelper == null) {
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
}
return sDatabaseHelper; return sDatabaseHelper;
} }
@ -259,11 +286,15 @@ public class MainApp extends Application {
return sConfigBuilder; return sConfigBuilder;
} }
public static ConstraintChecker getConstraintChecker() {
return sConstraintsChecker;
}
public static ArrayList<PluginBase> getPluginsList() { public static ArrayList<PluginBase> getPluginsList() {
return pluginsList; return pluginsList;
} }
public static ArrayList<PluginBase> getSpecificPluginsList(int type) { public static ArrayList<PluginBase> getSpecificPluginsList(PluginType type) {
ArrayList<PluginBase> newList = new ArrayList<>(); ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) { if (pluginsList != null) {
@ -277,20 +308,7 @@ public class MainApp extends Application {
return newList; return newList;
} }
@Nullable public static ArrayList<PluginBase> getSpecificPluginsVisibleInList(PluginType type) {
public static InsulinInterface getInsulinIterfaceById(int id) {
if (pluginsList != null) {
for (PluginBase p : pluginsList) {
if (p.getType() == PluginBase.INSULIN && ((InsulinInterface) p).getId() == id)
return (InsulinInterface) p;
}
} else {
log.error("InsulinInterface not found");
}
return null;
}
public static ArrayList<PluginBase> getSpecificPluginsVisibleInList(int type) {
ArrayList<PluginBase> newList = new ArrayList<>(); ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) { if (pluginsList != null) {
@ -319,7 +337,7 @@ public class MainApp extends Application {
return newList; return newList;
} }
public static ArrayList<PluginBase> getSpecificPluginsVisibleInListByInterface(Class interfaceClass, int type) { public static ArrayList<PluginBase> getSpecificPluginsVisibleInListByInterface(Class interfaceClass, PluginType type) {
ArrayList<PluginBase> newList = new ArrayList<>(); ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) { if (pluginsList != null) {
@ -347,9 +365,23 @@ public class MainApp extends Application {
return null; return null;
} }
public static boolean isEngineeringModeOrRelease() {
if (!BuildConfig.APS)
return true;
return engineeringMode || !devBranch;
}
public String getLogDirectory() {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
return lc.getProperty("EXT_FILES_DIR");
}
@Override @Override
public void onTerminate() { public void onTerminate() {
super.onTerminate(); super.onTerminate();
sDatabaseHelper.close(); if (sDatabaseHelper != null) {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
} }
} }

View file

@ -1,11 +1,9 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.MultiSelectListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
@ -16,23 +14,27 @@ import android.text.TextUtils;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin; import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin;
import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin; import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin;
import info.nightscout.utils.LocaleHelper; import info.nightscout.utils.LocaleHelper;
@ -66,8 +68,8 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
if (key.equals("short_tabtitles")) { if (key.equals("short_tabtitles")) {
MainApp.bus().post(new EventRefreshGui()); MainApp.bus().post(new EventRefreshGui());
} }
if (key.equals("openapsama_useautosens") && SP.getBoolean("openapsama_useautosens", false)) { if (key.equals(MainApp.gs(R.string.key_openapsama_useautosens)) && SP.getBoolean(R.string.key_openapsama_useautosens, false)) {
OKDialog.show(this, MainApp.sResources.getString(R.string.configbuilder_sensitivity), MainApp.sResources.getString(R.string.sensitivity_warning), null); OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning), null);
} }
updatePrefSummary(myPreferenceFragment.getPreference(key)); updatePrefSummary(myPreferenceFragment.getPreference(key));
} }
@ -81,13 +83,13 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
EditTextPreference editTextPref = (EditTextPreference) pref; EditTextPreference editTextPref = (EditTextPreference) pref;
if (pref.getKey().contains("password") || pref.getKey().contains("secret")) { if (pref.getKey().contains("password") || pref.getKey().contains("secret")) {
pref.setSummary("******"); pref.setSummary("******");
} else if (pref.getKey().equals(MainApp.sResources.getString(R.string.key_danars_name))) { } else if (pref.getKey().equals(MainApp.gs(R.string.key_danars_name))) {
pref.setSummary(SP.getString(R.string.key_danars_name, "")); pref.setSummary(SP.getString(R.string.key_danars_name, ""));
} else if (editTextPref.getText() != null && !editTextPref.getText().equals("")) { } else if (editTextPref.getText() != null && !editTextPref.getText().equals("")) {
((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage()); ((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage());
pref.setSummary(editTextPref.getText()); pref.setSummary(editTextPref.getText());
} else if (pref.getKey().contains("smscommunicator_allowednumbers") && TextUtils.isEmpty(editTextPref.getText().trim())) { } else if (pref.getKey().contains("smscommunicator_allowednumbers") && TextUtils.isEmpty(editTextPref.getText().trim())) {
pref.setSummary(MainApp.sResources.getString(R.string.smscommunicator_allowednumbers_summary)); pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary));
} }
} }
} }
@ -112,7 +114,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
id = args.getInt("id"); id = args.getInt("id");
} }
void addPreferencesFromResourceIfEnabled(PluginBase p, int type) { void addPreferencesFromResourceIfEnabled(PluginBase p, PluginType type) {
if (p.isEnabled(type) && p.getPreferencesId() != -1) if (p.isEnabled(type) && p.getPreferencesId() != -1)
addPreferencesFromResource(p.getPreferencesId()); addPreferencesFromResource(p.getPreferencesId());
} }
@ -127,60 +129,62 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
if (id != -1) { if (id != -1) {
addPreferencesFromResource(id); addPreferencesFromResource(id);
addPreferencesFromResource(R.xml.pref_advanced);
} else { } else {
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT && !Config.G5UPLOADER) {
addPreferencesFromResource(R.xml.pref_password); addPreferencesFromResource(R.xml.pref_password);
} }
addPreferencesFromResource(R.xml.pref_age); addPreferencesFromResource(R.xml.pref_age);
addPreferencesFromResource(R.xml.pref_language); addPreferencesFromResource(R.xml.pref_language);
if (!Config.NSCLIENT && !Config.G5UPLOADER) { addPreferencesFromResource(R.xml.pref_overview);
addPreferencesFromResource(R.xml.pref_quickwizard);
} addPreferencesFromResourceIfEnabled(SourceDexcomG5Plugin.getPlugin(), PluginType.BGSOURCE);
addPreferencesFromResourceIfEnabled(SourceDexcomG5Plugin.getPlugin(), PluginBase.BGSOURCE); addPreferencesFromResourceIfEnabled(CareportalPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(CareportalPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(SafetyPlugin.getPlugin(), PluginType.CONSTRAINTS);
addPreferencesFromResourceIfEnabled(SafetyPlugin.getPlugin(), PluginBase.CONSTRAINTS);
if (Config.APS) { if (Config.APS) {
addPreferencesFromResourceIfEnabled(LoopPlugin.getPlugin(), PluginBase.LOOP); addPreferencesFromResourceIfEnabled(LoopPlugin.getPlugin(), PluginType.LOOP);
addPreferencesFromResourceIfEnabled(OpenAPSMAPlugin.getPlugin(), PluginBase.APS); addPreferencesFromResourceIfEnabled(OpenAPSMAPlugin.getPlugin(), PluginType.APS);
addPreferencesFromResourceIfEnabled(OpenAPSAMAPlugin.getPlugin(), PluginBase.APS); addPreferencesFromResourceIfEnabled(OpenAPSAMAPlugin.getPlugin(), PluginType.APS);
addPreferencesFromResourceIfEnabled(OpenAPSSMBPlugin.getPlugin(), PluginType.APS);
} }
addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginBase.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginBase.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginBase.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY);
if (Config.DANAR) { if (Config.HWPUMPS) {
addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginBase.PUMP); addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(DanaRKoreanPlugin.getPlugin(), PluginBase.PUMP); addPreferencesFromResourceIfEnabled(DanaRKoreanPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(DanaRv2Plugin.getPlugin(), PluginBase.PUMP); addPreferencesFromResourceIfEnabled(DanaRv2Plugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(DanaRSPlugin.getPlugin(), PluginBase.PUMP); addPreferencesFromResourceIfEnabled(DanaRSPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(InsightPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(ComboPlugin.getPlugin(), PluginType.PUMP);
if (DanaRPlugin.getPlugin().isEnabled(PluginBase.PROFILE) if (DanaRPlugin.getPlugin().isEnabled(PluginType.PROFILE)
|| DanaRKoreanPlugin.getPlugin().isEnabled(PluginBase.PROFILE) || DanaRKoreanPlugin.getPlugin().isEnabled(PluginType.PROFILE)
|| DanaRv2Plugin.getPlugin().isEnabled(PluginBase.PROFILE) || DanaRv2Plugin.getPlugin().isEnabled(PluginType.PROFILE)
|| DanaRSPlugin.getPlugin().isEnabled(PluginBase.PROFILE)) { || DanaRSPlugin.getPlugin().isEnabled(PluginType.PROFILE)) {
addPreferencesFromResource(R.xml.pref_danarprofile); addPreferencesFromResource(R.xml.pref_danarprofile);
} }
} }
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT && !Config.G5UPLOADER) {
addPreferencesFromResourceIfEnabled(VirtualPumpPlugin.getPlugin(), PluginBase.PUMP); addPreferencesFromResourceIfEnabled(VirtualPumpPlugin.getPlugin(), PluginType.PUMP);
} }
addPreferencesFromResourceIfEnabled(InsulinOrefFreePeakPlugin.getPlugin(), PluginBase.INSULIN); addPreferencesFromResourceIfEnabled(InsulinOrefFreePeakPlugin.getPlugin(), PluginType.INSULIN);
addPreferencesFromResourceIfEnabled(NSClientInternalPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL);
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT && !Config.G5UPLOADER) {
addPreferencesFromResource(R.xml.pref_others); addPreferencesFromResource(R.xml.pref_others);
} }
addPreferencesFromResource(R.xml.pref_advanced); addPreferencesFromResource(R.xml.pref_datachoices);
addPreferencesFromResourceIfEnabled(WearPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(WearPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginType.GENERAL);
} }
initSummary(getPreferenceScreen()); initSummary(getPreferenceScreen());

View file

@ -1,8 +1,10 @@
package info.nightscout.androidaps.Services; package info.nightscout.androidaps.Services;
import android.app.Service; import android.app.Service;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.AssetFileDescriptor; import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.os.IBinder; import android.os.IBinder;
@ -53,7 +55,10 @@ public class AlarmSoundService extends Service {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
player.setLooping(true); // Set looping player.setLooping(true); // Set looping
player.setVolume(100, 100); AudioManager manager = (AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
if (manager == null || !manager.isMusicActive()) {
player.setVolume(100, 100);
}
try { try {
player.prepare(); player.prepare();

View file

@ -18,7 +18,8 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventNsFood;
import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
@ -33,13 +34,14 @@ import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.events.EventNSProfileUpdateGUI; import info.nightscout.androidaps.plugins.ProfileNS.events.EventNSProfileUpdateGUI;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync; import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS; import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin;
import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin; import info.nightscout.androidaps.plugins.Source.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin; import info.nightscout.androidaps.plugins.Source.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; import info.nightscout.androidaps.plugins.Source.SourceXdripPlugin;
import info.nightscout.androidaps.receivers.DataReceiver; import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.utils.BundleLogger; import info.nightscout.utils.BundleLogger;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -62,32 +64,37 @@ public class DataService extends IntentService {
protected void onHandleIntent(final Intent intent) { protected void onHandleIntent(final Intent intent) {
if (Config.logFunctionCalls) if (Config.logFunctionCalls)
log.debug("onHandleIntent " + BundleLogger.log(intent.getExtras())); log.debug("onHandleIntent " + BundleLogger.log(intent.getExtras()));
if (ConfigBuilderPlugin.getPlugin().getActiveBgSource() == null) {
if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceXdripPlugin.class)) {
xDripEnabled = true; xDripEnabled = true;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = false; mm640gEnabled = false;
glimpEnabled = false; glimpEnabled = false;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceNSClientPlugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceXdripPlugin.class)) {
xDripEnabled = true;
nsClientEnabled = false;
mm640gEnabled = false;
glimpEnabled = false;
dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceNSClientPlugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = true; nsClientEnabled = true;
mm640gEnabled = false; mm640gEnabled = false;
glimpEnabled = false; glimpEnabled = false;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceMM640gPlugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceMM640gPlugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = true; mm640gEnabled = true;
glimpEnabled = false; glimpEnabled = false;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceGlimpPlugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceGlimpPlugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = false; mm640gEnabled = false;
glimpEnabled = true; glimpEnabled = true;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceDexcomG5Plugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceDexcomG5Plugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = false; mm640gEnabled = false;
@ -95,7 +102,7 @@ public class DataService extends IntentService {
dexcomG5Enabled = true; dexcomG5Enabled = true;
} }
boolean isNSProfile = ConfigBuilderPlugin.getActiveProfileInterface().getClass().equals(NSProfilePlugin.class); boolean isNSProfile = MainApp.getConfigBuilder().getActiveProfileInterface() != null && MainApp.getConfigBuilder().getActiveProfileInterface().getClass().equals(NSProfilePlugin.class);
boolean acceptNSData = !SP.getBoolean(R.string.key_ns_upload_only, false); boolean acceptNSData = !SP.getBoolean(R.string.key_ns_upload_only, false);
Bundle bundles = intent.getExtras(); Bundle bundles = intent.getExtras();
@ -123,8 +130,8 @@ public class DataService extends IntentService {
handleNewDataFromDexcomG5(intent); handleNewDataFromDexcomG5(intent);
} }
} else if (Intents.ACTION_NEW_SGV.equals(action)) { } else if (Intents.ACTION_NEW_SGV.equals(action)) {
// always backfill SGV from NS if (nsClientEnabled || SP.getBoolean(R.string.key_ns_autobackfill, true))
handleNewDataFromNSClient(intent); handleNewDataFromNSClient(intent);
// Objectives 0 // Objectives 0
ObjectivesPlugin.bgIsAvailableInNS = true; ObjectivesPlugin.bgIsAvailableInNS = true;
ObjectivesPlugin.saveProgress(); ObjectivesPlugin.saveProgress();
@ -190,7 +197,8 @@ public class DataService extends IntentService {
bgReading.direction = bundle.getString(Intents.EXTRA_BG_SLOPE_NAME); bgReading.direction = bundle.getString(Intents.EXTRA_BG_SLOPE_NAME);
bgReading.date = bundle.getLong(Intents.EXTRA_TIMESTAMP); bgReading.date = bundle.getLong(Intents.EXTRA_TIMESTAMP);
bgReading.raw = bundle.getDouble(Intents.EXTRA_RAW); bgReading.raw = bundle.getDouble(Intents.EXTRA_RAW);
String source = bundle.getString(Intents.XDRIP_DATA_SOURCE_DESCRIPTION, "no Source specified");
SourceXdripPlugin.getPlugin().setSource(source);
MainApp.getDbHelper().createIfNotExists(bgReading, "XDRIP"); MainApp.getDbHelper().createIfNotExists(bgReading, "XDRIP");
} }
@ -222,7 +230,7 @@ public class DataService extends IntentService {
try { try {
JSONArray jsonArray = new JSONArray(data); JSONArray jsonArray = new JSONArray(data);
log.debug("Received Dexcom Data size:" + jsonArray.length()); log.debug("Received Dexcom Data size:" + jsonArray.length());
for(int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i); JSONObject json = jsonArray.getJSONObject(i);
bgReading.value = json.getInt("m_value"); bgReading.value = json.getInt("m_value");
bgReading.direction = json.getString("m_trend"); bgReading.direction = json.getString("m_trend");
@ -365,11 +373,8 @@ public class DataService extends IntentService {
String activeProfile = bundles.getString("activeprofile"); String activeProfile = bundles.getString("activeprofile");
String profile = bundles.getString("profile"); String profile = bundles.getString("profile");
ProfileStore profileStore = new ProfileStore(new JSONObject(profile)); ProfileStore profileStore = new ProfileStore(new JSONObject(profile));
NSProfilePlugin.storeNewProfile(profileStore); NSProfilePlugin.getPlugin().storeNewProfile(profileStore);
MainApp.bus().post(new EventNSProfileUpdateGUI()); MainApp.bus().post(new EventNSProfileUpdateGUI());
// if there are no profile switches this should lead to profile update
if (MainApp.getConfigBuilder().getProfileSwitchesFromHistory().size() == 0)
MainApp.bus().post(new EventNewBasalProfile());
if (Config.logIncommingData) if (Config.logIncommingData)
log.debug("Received profileStore: " + activeProfile + " " + profile); log.debug("Received profileStore: " + activeProfile + " " + profile);
} catch (JSONException e) { } catch (JSONException e) {
@ -380,19 +385,18 @@ public class DataService extends IntentService {
if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT) || intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) { if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT) || intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) {
try { try {
if (bundles.containsKey("treatment")) { if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment"); JSONObject json = new JSONObject(bundles.getString("treatment"));
handleAddChangeDataFromNS(trstring); handleTreatmentFromNS(json, intent);
} }
if (bundles.containsKey("treatments")) { if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments"); String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring); JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i); JSONObject json = jsonArray.getJSONObject(i);
String trstr = trJson.toString(); handleTreatmentFromNS(json, intent);
handleAddChangeDataFromNS(trstr);
} }
} }
} catch (Exception e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
} }
@ -401,21 +405,19 @@ public class DataService extends IntentService {
try { try {
if (bundles.containsKey("treatment")) { if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment"); String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring); JSONObject json = new JSONObject(trstring);
String _id = trJson.getString("_id"); handleTreatmentFromNS(json);
handleRemovedRecordFromNS(_id);
} }
if (bundles.containsKey("treatments")) { if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments"); String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring); JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i); JSONObject json = jsonArray.getJSONObject(i);
String _id = trJson.getString("_id"); handleTreatmentFromNS(json);
handleRemovedRecordFromNS(_id);
} }
} }
} catch (Exception e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
} }
@ -474,59 +476,25 @@ public class DataService extends IntentService {
} }
} }
if (intent.getAction().equals(Intents.ACTION_NEW_FOOD) || intent.getAction().equals(Intents.ACTION_CHANGED_FOOD)) { if (intent.getAction().equals(Intents.ACTION_NEW_FOOD)
try { || intent.getAction().equals(Intents.ACTION_CHANGED_FOOD)) {
if (bundles.containsKey("food")) { int mode = Intents.ACTION_NEW_FOOD.equals(intent.getAction()) ? EventNsFood.ADD : EventNsFood.UPDATE;
String trstring = bundles.getString("food"); EventNsFood evt = new EventNsFood(mode, bundles);
handleAddChangeFoodRecord(new JSONObject(trstring)); MainApp.bus().post(evt);
}
if (bundles.containsKey("foods")) {
String trstring = bundles.getString("foods");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
handleAddChangeFoodRecord(trJson);
}
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
} }
if (intent.getAction().equals(Intents.ACTION_REMOVED_FOOD)) { if (intent.getAction().equals(Intents.ACTION_REMOVED_FOOD)) {
try { EventNsFood evt = new EventNsFood(EventNsFood.REMOVE, bundles);
if (bundles.containsKey("food")) { MainApp.bus().post(evt);
String trstring = bundles.getString("food");
JSONObject trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
handleRemovedFoodRecord(_id);
}
if (bundles.containsKey("foods")) {
String trstring = bundles.getString("foods");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
String _id = trJson.getString("_id");
handleRemovedFoodRecord(_id);
}
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
} }
} }
private void handleRemovedFoodRecord(String _id) { private void handleTreatmentFromNS(JSONObject json) {
MainApp.getDbHelper().foodHelper.deleteFoodById(_id); // new DB model
} EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.REMOVE, json);
MainApp.bus().post(evtTreatment);
public void handleAddChangeFoodRecord(JSONObject trJson) throws JSONException { // old DB model
MainApp.getDbHelper().foodHelper.createFoodFromJsonIfNotExists(trJson); String _id = JsonHelper.safeGetString(json, "_id");
}
private void handleRemovedRecordFromNS(String _id) {
MainApp.getDbHelper().deleteTreatmentById(_id);
MainApp.getDbHelper().deleteTempTargetById(_id); MainApp.getDbHelper().deleteTempTargetById(_id);
MainApp.getDbHelper().deleteTempBasalById(_id); MainApp.getDbHelper().deleteTempBasalById(_id);
MainApp.getDbHelper().deleteExtendedBolusById(_id); MainApp.getDbHelper().deleteExtendedBolusById(_id);
@ -534,85 +502,53 @@ public class DataService extends IntentService {
MainApp.getDbHelper().deleteProfileSwitchById(_id); MainApp.getDbHelper().deleteProfileSwitchById(_id);
} }
private void handleAddChangeDataFromNS(String trstring) throws JSONException { private void handleTreatmentFromNS(JSONObject json, Intent intent) throws JSONException {
JSONObject trJson = new JSONObject(trstring); // new DB model
handleDanaRHistoryRecords(trJson); // update record _id in history int mode = Intents.ACTION_NEW_TREATMENT.equals(intent.getAction()) ? EventNsTreatment.ADD : EventNsTreatment.UPDATE;
handleAddChangeTempTargetRecord(trJson); double insulin = JsonHelper.safeGetDouble(json, "insulin");
handleAddChangeTempBasalRecord(trJson); double carbs = JsonHelper.safeGetDouble(json, "carbs");
handleAddChangeExtendedBolusRecord(trJson); String eventType = JsonHelper.safeGetString(json, "eventType");
handleAddChangeCareportalEventRecord(trJson); if (insulin > 0 || carbs > 0) {
handleAddChangeTreatmentRecord(trJson); EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
handleAddChangeProfileSwitchRecord(trJson); MainApp.bus().post(evtTreatment);
} } else if (json.has(DanaRNSHistorySync.DANARSIGNATURE)) {
// old DB model
public void handleDanaRHistoryRecords(JSONObject trJson) { MainApp.getDbHelper().updateDanaRHistoryRecordId(json);
if (trJson.has(DanaRNSHistorySync.DANARSIGNATURE)) { } else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) {
MainApp.getDbHelper().updateDanaRHistoryRecordId(trJson); MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(json);
} } else if (eventType.equals(CareportalEvent.TEMPBASAL)) {
} MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.COMBOBOLUS)) {
public void handleAddChangeTreatmentRecord(JSONObject trJson) throws JSONException { MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
if (trJson.has("insulin") || trJson.has("carbs")) { } else if (eventType.equals(CareportalEvent.PROFILESWITCH)) {
MainApp.getDbHelper().createTreatmentFromJsonIfNotExists(trJson); MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(json);
return; } else if (eventType.equals(CareportalEvent.SITECHANGE) ||
} eventType.equals(CareportalEvent.INSULINCHANGE) ||
} eventType.equals(CareportalEvent.SENSORCHANGE) ||
eventType.equals(CareportalEvent.BGCHECK) ||
public void handleAddChangeTempTargetRecord(JSONObject trJson) throws JSONException { eventType.equals(CareportalEvent.NOTE) ||
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.TEMPORARYTARGET)) { eventType.equals(CareportalEvent.NONE) ||
MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(trJson); eventType.equals(CareportalEvent.ANNOUNCEMENT) ||
} eventType.equals(CareportalEvent.QUESTION) ||
} eventType.equals(CareportalEvent.EXERCISE) ||
eventType.equals(CareportalEvent.OPENAPSOFFLINE) ||
public void handleAddChangeTempBasalRecord(JSONObject trJson) throws JSONException { eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.TEMPBASAL)) { MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(trJson);
}
}
public void handleAddChangeExtendedBolusRecord(JSONObject trJson) throws JSONException {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.COMBOBOLUS)) {
MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(trJson);
}
}
public void handleAddChangeCareportalEventRecord(JSONObject trJson) throws JSONException {
if (trJson.has("insulin") && trJson.getDouble("insulin") > 0)
return;
if (trJson.has("carbs") && trJson.getDouble("carbs") > 0)
return;
if (trJson.has("eventType") && (
trJson.getString("eventType").equals(CareportalEvent.SITECHANGE) ||
trJson.getString("eventType").equals(CareportalEvent.INSULINCHANGE) ||
trJson.getString("eventType").equals(CareportalEvent.SENSORCHANGE) ||
trJson.getString("eventType").equals(CareportalEvent.BGCHECK) ||
trJson.getString("eventType").equals(CareportalEvent.NOTE) ||
trJson.getString("eventType").equals(CareportalEvent.NONE) ||
trJson.getString("eventType").equals(CareportalEvent.ANNOUNCEMENT) ||
trJson.getString("eventType").equals(CareportalEvent.QUESTION) ||
trJson.getString("eventType").equals(CareportalEvent.EXERCISE) ||
trJson.getString("eventType").equals(CareportalEvent.OPENAPSOFFLINE) ||
trJson.getString("eventType").equals(CareportalEvent.PUMPBATTERYCHANGE)
)) {
MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(trJson);
} }
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.ANNOUNCEMENT)) { if (eventType.equals(CareportalEvent.ANNOUNCEMENT)) {
long date = trJson.getLong("mills"); long date = JsonHelper.safeGetLong(json,"mills");
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (date > now - 15 * 60 * 1000L && trJson.has("notes")) { String enteredBy = JsonHelper.safeGetString(json, "enteredBy", "");
Notification announcement = new Notification(Notification.NSANNOUNCEMENT, trJson.getString("notes"), Notification.ANNOUNCEMENT, 60); String notes = JsonHelper.safeGetString(json, "notes", "");
if (date > now - 15 * 60 * 1000L && !notes.isEmpty()
&& !enteredBy.equals(SP.getString("careportal_enteredby", "AndroidAPS"))) {
Notification announcement = new Notification(Notification.NSANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60);
MainApp.bus().post(new EventNewNotification(announcement)); MainApp.bus().post(new EventNewNotification(announcement));
} }
} }
} }
public void handleAddChangeProfileSwitchRecord(JSONObject trJson) throws JSONException {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.PROFILESWITCH)) {
MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(trJson);
}
}
private void handleNewSMS(Intent intent) { private void handleNewSMS(Intent intent) {
Bundle bundle = intent.getExtras(); Bundle bundle = intent.getExtras();
if (bundle == null) return; if (bundle == null) return;

View file

@ -37,6 +37,8 @@ public interface Intents {
String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery"; String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time"; String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw"; String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw";
String XDRIP_DATA_SOURCE_DESCRIPTION = "com.eveningoutpost.dexdrip.Extras.SourceDesc";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData"; String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";

View file

@ -1,11 +1,9 @@
package info.nightscout.androidaps.plugins.PumpDanaR.activities; package info.nightscout.androidaps;
import android.app.Activity; import android.app.Activity;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -35,21 +33,26 @@ import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.DanaRHistoryRecord; import info.nightscout.androidaps.db.DanaRHistoryRecord;
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.events.EventPumpStatusChanged; import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus; import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
public class DanaRStatsActivity extends Activity { public class TDDStatsActivity extends Activity {
private static Logger log = LoggerFactory.getLogger(DanaRStatsActivity.class); private static Logger log = LoggerFactory.getLogger(TDDStatsActivity.class);
TextView statusView, statsMessage, totalBaseBasal2; TextView statusView, statsMessage, totalBaseBasal2;
EditText totalBaseBasal; EditText totalBaseBasal;
@ -60,10 +63,10 @@ public class DanaRStatsActivity extends Activity {
double magicNumber; double magicNumber;
DecimalFormat decimalFormat; DecimalFormat decimalFormat;
List<DanaRHistoryRecord> historyList = new ArrayList<>(); List<TDD> historyList = new ArrayList<>();
List<DanaRHistoryRecord> dummies; List<TDD> dummies;
public DanaRStatsActivity() { public TDDStatsActivity() {
super(); super();
} }
@ -126,6 +129,9 @@ public class DanaRStatsActivity extends Activity {
} }
totalBaseBasal.setText(TBB); totalBaseBasal.setText(TBB);
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().needsManualTDDLoad)
reloadButton.setVisibility(View.GONE);
// stats table // stats table
tl = (TableLayout) findViewById(R.id.main_table); tl = (TableLayout) findViewById(R.id.main_table);
TableRow tr_head = new TableRow(this); TableRow tr_head = new TableRow(this);
@ -232,10 +238,10 @@ public class DanaRStatsActivity extends Activity {
statsMessage.setText(getString(R.string.danar_stats_warning_Message)); statsMessage.setText(getString(R.string.danar_stats_warning_Message));
} }
}); });
ConfigBuilderPlugin.getCommandQueue().loadHistory(RecordTypes.RECORD_TYPE_DAILY, new Callback() { ConfigBuilderPlugin.getCommandQueue().loadTDDs( new Callback() {
@Override @Override
public void run() { public void run() {
loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); loadDataFromDB();
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -268,18 +274,18 @@ public class DanaRStatsActivity extends Activity {
} else { } else {
SP.putString("TBB", totalBaseBasal.getText().toString()); SP.putString("TBB", totalBaseBasal.getText().toString());
TBB = SP.getString("TBB", ""); TBB = SP.getString("TBB", "");
loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); loadDataFromDB();
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(totalBaseBasal.getWindowToken(), 0); imm.hideSoftInputFromWindow(totalBaseBasal.getWindowToken(), 0);
} }
} }
}); });
loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); loadDataFromDB();
} }
private void loadDataFromDB(byte type) { private void loadDataFromDB() {
historyList = MainApp.getDbHelper().getDanaRHistoryRecordsByType(type); historyList = MainApp.getDbHelper().getTDDs();
//only use newest 10 //only use newest 10
historyList = historyList.subList(0, Math.min(10, historyList.size())); historyList = historyList.subList(0, Math.min(10, historyList.size()));
@ -288,24 +294,24 @@ public class DanaRStatsActivity extends Activity {
dummies = new LinkedList(); dummies = new LinkedList();
DateFormat df = new SimpleDateFormat("dd.MM."); DateFormat df = new SimpleDateFormat("dd.MM.");
for (int i = 0; i < historyList.size() - 1; i++) { for (int i = 0; i < historyList.size() - 1; i++) {
DanaRHistoryRecord elem1 = historyList.get(i); TDD elem1 = historyList.get(i);
DanaRHistoryRecord elem2 = historyList.get(i + 1); TDD elem2 = historyList.get(i + 1);
if (!df.format(new Date(elem1.recordDate)).equals(df.format(new Date(elem2.recordDate + 25 * 60 * 60 * 1000)))) { if (!df.format(new Date(elem1.date)).equals(df.format(new Date(elem2.date + 25 * 60 * 60 * 1000)))) {
DanaRHistoryRecord dummy = new DanaRHistoryRecord(); TDD dummy = new TDD();
dummy.recordDate = elem1.recordDate - 24 * 60 * 60 * 1000; dummy.date = elem1.date - 24 * 60 * 60 * 1000;
dummy.recordDailyBasal = elem1.recordDailyBasal / 2; dummy.basal = elem1.basal / 2;
dummy.recordDailyBolus = elem1.recordDailyBolus / 2; dummy.bolus = elem1.bolus / 2;
dummies.add(dummy); dummies.add(dummy);
elem1.recordDailyBasal /= 2; elem1.basal /= 2;
elem1.recordDailyBolus /= 2; elem1.bolus /= 2;
} }
} }
historyList.addAll(dummies); historyList.addAll(dummies);
Collections.sort(historyList, new Comparator<DanaRHistoryRecord>() { Collections.sort(historyList, new Comparator<TDD>() {
@Override @Override
public int compare(DanaRHistoryRecord lhs, DanaRHistoryRecord rhs) { public int compare(TDD lhs, TDD rhs) {
return (int) (rhs.recordDate - lhs.recordDate); return (int) (rhs.date - lhs.date);
} }
}); });
@ -333,11 +339,13 @@ public class DanaRStatsActivity extends Activity {
double weighted05 = 0d; double weighted05 = 0d;
double weighted07 = 0d; double weighted07 = 0d;
for (DanaRHistoryRecord record : historyList) {
double tdd = record.recordDailyBolus + record.recordDailyBasal; //TDD table
for (TDD record : historyList) {
double tdd = record.getTotal();
// Create the table row // Create the table row
TableRow tr = new TableRow(DanaRStatsActivity.this); TableRow tr = new TableRow(TDDStatsActivity.this);
if (i % 2 != 0) tr.setBackgroundColor(Color.DKGRAY); if (i % 2 != 0) tr.setBackgroundColor(Color.DKGRAY);
if (dummies.contains(record)) { if (dummies.contains(record)) {
tr.setBackgroundColor(Color.argb(125, 255, 0, 0)); tr.setBackgroundColor(Color.argb(125, 255, 0, 0));
@ -348,31 +356,31 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
// Here create the TextView dynamically // Here create the TextView dynamically
TextView labelDATE = new TextView(DanaRStatsActivity.this); TextView labelDATE = new TextView(TDDStatsActivity.this);
labelDATE.setId(200 + i); labelDATE.setId(200 + i);
labelDATE.setText(df.format(new Date(record.recordDate))); labelDATE.setText(df.format(new Date(record.date)));
labelDATE.setTextColor(Color.WHITE); labelDATE.setTextColor(Color.WHITE);
tr.addView(labelDATE); tr.addView(labelDATE);
TextView labelBASAL = new TextView(DanaRStatsActivity.this); TextView labelBASAL = new TextView(TDDStatsActivity.this);
labelBASAL.setId(300 + i); labelBASAL.setId(300 + i);
labelBASAL.setText(DecimalFormatter.to2Decimal(record.recordDailyBasal) + " U"); labelBASAL.setText(DecimalFormatter.to2Decimal(record.basal) + " U");
labelBASAL.setTextColor(Color.WHITE); labelBASAL.setTextColor(Color.WHITE);
tr.addView(labelBASAL); tr.addView(labelBASAL);
TextView labelBOLUS = new TextView(DanaRStatsActivity.this); TextView labelBOLUS = new TextView(TDDStatsActivity.this);
labelBOLUS.setId(400 + i); labelBOLUS.setId(400 + i);
labelBOLUS.setText(DecimalFormatter.to2Decimal(record.recordDailyBolus) + " U"); labelBOLUS.setText(DecimalFormatter.to2Decimal(record.bolus) + " U");
labelBOLUS.setTextColor(Color.WHITE); labelBOLUS.setTextColor(Color.WHITE);
tr.addView(labelBOLUS); tr.addView(labelBOLUS);
TextView labelTDD = new TextView(DanaRStatsActivity.this); TextView labelTDD = new TextView(TDDStatsActivity.this);
labelTDD.setId(500 + i); labelTDD.setId(500 + i);
labelTDD.setText(DecimalFormatter.to2Decimal(tdd) + " U"); labelTDD.setText(DecimalFormatter.to2Decimal(tdd) + " U");
labelTDD.setTextColor(Color.WHITE); labelTDD.setTextColor(Color.WHITE);
tr.addView(labelTDD); tr.addView(labelTDD);
TextView labelRATIO = new TextView(DanaRStatsActivity.this); TextView labelRATIO = new TextView(TDDStatsActivity.this);
labelRATIO.setId(600 + i); labelRATIO.setId(600 + i);
labelRATIO.setText(Math.round(100 * tdd / magicNumber) + " %"); labelRATIO.setText(Math.round(100 * tdd / magicNumber) + " %");
labelRATIO.setTextColor(Color.WHITE); labelRATIO.setTextColor(Color.WHITE);
@ -383,11 +391,23 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.MATCH_PARENT,
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
sum = sum + tdd; i++;
}
i = 0;
//cumulative TDDs
for (TDD record : historyList) {
if(!historyList.isEmpty() && df.format(new Date(record.date)).equals(df.format(new Date()))) {
//Today should not be included
continue;
}
i++; i++;
sum = sum + record.getTotal();
// Create the cumtable row // Create the cumtable row
TableRow ctr = new TableRow(DanaRStatsActivity.this); TableRow ctr = new TableRow(TDDStatsActivity.this);
if (i % 2 == 0) ctr.setBackgroundColor(Color.DKGRAY); if (i % 2 == 0) ctr.setBackgroundColor(Color.DKGRAY);
ctr.setId(700 + i); ctr.setId(700 + i);
ctr.setLayoutParams(new TableLayout.LayoutParams( ctr.setLayoutParams(new TableLayout.LayoutParams(
@ -395,19 +415,19 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
// Here create the TextView dynamically // Here create the TextView dynamically
TextView labelDAYS = new TextView(DanaRStatsActivity.this); TextView labelDAYS = new TextView(TDDStatsActivity.this);
labelDAYS.setId(800 + i); labelDAYS.setId(800 + i);
labelDAYS.setText("" + i); labelDAYS.setText("" + i);
labelDAYS.setTextColor(Color.WHITE); labelDAYS.setTextColor(Color.WHITE);
ctr.addView(labelDAYS); ctr.addView(labelDAYS);
TextView labelCUMTDD = new TextView(DanaRStatsActivity.this); TextView labelCUMTDD = new TextView(TDDStatsActivity.this);
labelCUMTDD.setId(900 + i); labelCUMTDD.setId(900 + i);
labelCUMTDD.setText(DecimalFormatter.to2Decimal(sum / i) + " U"); labelCUMTDD.setText(DecimalFormatter.to2Decimal(sum / i) + " U");
labelCUMTDD.setTextColor(Color.WHITE); labelCUMTDD.setTextColor(Color.WHITE);
ctr.addView(labelCUMTDD); ctr.addView(labelCUMTDD);
TextView labelCUMRATIO = new TextView(DanaRStatsActivity.this); TextView labelCUMRATIO = new TextView(TDDStatsActivity.this);
labelCUMRATIO.setId(1000 + i); labelCUMRATIO.setId(1000 + i);
labelCUMRATIO.setText(Math.round(100 * sum / i / magicNumber) + " %"); labelCUMRATIO.setText(Math.round(100 * sum / i / magicNumber) + " %");
labelCUMRATIO.setTextColor(Color.WHITE); labelCUMRATIO.setTextColor(Color.WHITE);
@ -419,7 +439,7 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
} }
if (historyList.size() < 3 || !(df.format(new Date(historyList.get(0).recordDate)).equals(df.format(new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24))))) { if (isOldData(historyList) && ConfigBuilderPlugin.getActivePump().getPumpDescription().needsManualTDDLoad) {
statsMessage.setVisibility(View.VISIBLE); statsMessage.setVisibility(View.VISIBLE);
statsMessage.setText(getString(R.string.danar_stats_olddata_Message)); statsMessage.setText(getString(R.string.danar_stats_olddata_Message));
@ -427,12 +447,17 @@ public class DanaRStatsActivity extends Activity {
tl.setBackgroundColor(Color.TRANSPARENT); tl.setBackgroundColor(Color.TRANSPARENT);
} }
if(!historyList.isEmpty() && df.format(new Date(historyList.get(0).date)).equals(df.format(new Date()))) {
//Today should not be included
historyList.remove(0);
}
Collections.reverse(historyList); Collections.reverse(historyList);
i = 0; i = 0;
for (DanaRHistoryRecord record : historyList) { for (TDD record : historyList) {
double tdd = record.recordDailyBolus + record.recordDailyBasal; double tdd = record.getTotal();
if (i == 0) { if (i == 0) {
weighted03 = tdd; weighted03 = tdd;
weighted05 = tdd; weighted05 = tdd;
@ -447,7 +472,7 @@ public class DanaRStatsActivity extends Activity {
} }
// Create the exptable row // Create the exptable row
TableRow etr = new TableRow(DanaRStatsActivity.this); TableRow etr = new TableRow(TDDStatsActivity.this);
if (i % 2 != 0) etr.setBackgroundColor(Color.DKGRAY); if (i % 2 != 0) etr.setBackgroundColor(Color.DKGRAY);
etr.setId(1100 + i); etr.setId(1100 + i);
etr.setLayoutParams(new TableLayout.LayoutParams( etr.setLayoutParams(new TableLayout.LayoutParams(
@ -455,13 +480,13 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
// Here create the TextView dynamically // Here create the TextView dynamically
TextView labelWEIGHT = new TextView(DanaRStatsActivity.this); TextView labelWEIGHT = new TextView(TDDStatsActivity.this);
labelWEIGHT.setId(1200 + i); labelWEIGHT.setId(1200 + i);
labelWEIGHT.setText("0.3\n" + "0.5\n" + "0.7"); labelWEIGHT.setText("0.3\n" + "0.5\n" + "0.7");
labelWEIGHT.setTextColor(Color.WHITE); labelWEIGHT.setTextColor(Color.WHITE);
etr.addView(labelWEIGHT); etr.addView(labelWEIGHT);
TextView labelEXPTDD = new TextView(DanaRStatsActivity.this); TextView labelEXPTDD = new TextView(TDDStatsActivity.this);
labelEXPTDD.setId(1300 + i); labelEXPTDD.setId(1300 + i);
labelEXPTDD.setText(DecimalFormatter.to2Decimal(weighted03) labelEXPTDD.setText(DecimalFormatter.to2Decimal(weighted03)
+ " U\n" + DecimalFormatter.to2Decimal(weighted05) + " U\n" + DecimalFormatter.to2Decimal(weighted05)
@ -469,7 +494,7 @@ public class DanaRStatsActivity extends Activity {
labelEXPTDD.setTextColor(Color.WHITE); labelEXPTDD.setTextColor(Color.WHITE);
etr.addView(labelEXPTDD); etr.addView(labelEXPTDD);
TextView labelEXPRATIO = new TextView(DanaRStatsActivity.this); TextView labelEXPRATIO = new TextView(TDDStatsActivity.this);
labelEXPRATIO.setId(1400 + i); labelEXPRATIO.setId(1400 + i);
labelEXPRATIO.setText(Math.round(100 * weighted03 / magicNumber) + " %\n" labelEXPRATIO.setText(Math.round(100 * weighted03 / magicNumber) + " %\n"
+ Math.round(100 * weighted05 / magicNumber) + " %\n" + Math.round(100 * weighted05 / magicNumber) + " %\n"
@ -516,4 +541,19 @@ public class DanaRStatsActivity extends Activity {
} }
); );
} }
public static boolean isOldData(List<TDD> historyList) {
Object activePump = MainApp.getConfigBuilder().getActivePump();
PumpInterface dana = MainApp.getSpecificPlugin(DanaRPlugin.class);
PumpInterface danaRS = MainApp.getSpecificPlugin(DanaRSPlugin.class);
PumpInterface danaV2 = MainApp.getSpecificPlugin(DanaRv2Plugin.class);
PumpInterface danaKorean = MainApp.getSpecificPlugin(DanaRKoreanPlugin.class);
PumpInterface insight = MainApp.getSpecificPlugin(InsightPlugin.class);
boolean startsYesterday = activePump == dana || activePump == danaRS || activePump == danaV2 || activePump == danaKorean || activePump == insight;
DateFormat df = new SimpleDateFormat("dd.MM.");
return (historyList.size() < 3 || !(df.format(new Date(historyList.get(0).date)).equals(df.format(new Date(System.currentTimeMillis() - (startsYesterday?1000 * 60 * 60 * 24:0))))));
}
} }

View file

@ -0,0 +1,198 @@
package info.nightscout.androidaps.data;
import java.util.ArrayList;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
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.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
/**
* Created by mike on 19.03.2018.
*/
public class ConstraintChecker implements ConstraintsInterface {
private MainApp mainApp;
public ConstraintChecker(MainApp mainApp) {
this.mainApp = mainApp;
}
public Constraint<Boolean> isLoopInvokationAllowed() {
return isLoopInvokationAllowed(new Constraint<>(true));
}
public Constraint<Boolean> isClosedLoopAllowed() {
return isClosedLoopAllowed(new Constraint<>(true));
}
public Constraint<Boolean> isAutosensModeEnabled() {
return isAutosensModeEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isAMAModeEnabled() {
return isAMAModeEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isSMBModeEnabled() {
return isSMBModeEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isAdvancedFilteringEnabled() {
return isAdvancedFilteringEnabled(new Constraint<>(true));
}
public Constraint<Double> getMaxBasalAllowed(Profile profile) {
return applyBasalConstraints(new Constraint<>(Constants.REALLYHIGHBASALRATE), profile);
}
public Constraint<Integer> getMaxBasalPercentAllowed(Profile profile) {
return applyBasalPercentConstraints(new Constraint<>(Constants.REALLYHIGHPERCENTBASALRATE), profile);
}
public Constraint<Double> getMaxBolusAllowed() {
return applyBolusConstraints(new Constraint<>(Constants.REALLYHIGHBOLUS));
}
public Constraint<Integer> getMaxCarbsAllowed() {
return applyCarbsConstraints(new Constraint<>(Constants.REALLYHIGHCARBS));
}
public Constraint<Double> getMaxIOBAllowed() {
return applyMaxIOBConstraints(new Constraint<>(Constants.REALLYHIGHIOB));
}
@Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isLoopInvokationAllowed(value);
}
return value;
}
@Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isClosedLoopAllowed(value);
}
return value;
}
@Override
public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isAutosensModeEnabled(value);
}
return value;
}
@Override
public Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.isAMAModeEnabled(value);
}
return value;
}
@Override
public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isSMBModeEnabled(value);
}
return value;
}
@Override
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isAdvancedFilteringEnabled(value);
}
return value;
}
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.applyBasalConstraints(absoluteRate, profile);
}
return absoluteRate;
}
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyBasalPercentConstraints(percentRate, profile);
}
return percentRate;
}
@Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyBolusConstraints(insulin);
}
return insulin;
}
@Override
public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyCarbsConstraints(carbs);
}
return carbs;
}
@Override
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyMaxIOBConstraints(maxIob);
}
return maxIob;
}
}

View file

@ -2,14 +2,14 @@ package info.nightscout.androidaps.data;
import android.content.Context; import android.content.Context;
import com.rits.cloning.Cloner;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.MainApp;
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.InsulinInterface;
/** /**
* Created by mike on 29.05.2017. * Created by mike on 29.05.2017.
@ -29,6 +29,28 @@ public class DetailedBolusInfo {
public Context context = null; // context for progress dialog public Context context = null; // context for progress dialog
public long pumpId = 0; // id of record if comming from pump history (not a newly created treatment) public long pumpId = 0; // id of record if comming from pump history (not a newly created treatment)
public boolean isSMB = false; // is a Super-MicroBolus public boolean isSMB = false; // is a Super-MicroBolus
public long deliverAt = 0; // SMB should be delivered within 1 min from this time
public String notes = null;
public DetailedBolusInfo copy() {
DetailedBolusInfo n = new DetailedBolusInfo();
n.date = date;
n.eventType = eventType;
n.insulin = insulin;
n.carbs = carbs;
n.source = source;
n.isValid = isValid;
n.glucose = glucose;
n.glucoseType = glucoseType;
n.carbTime = carbTime;
n.boluscalc = boluscalc;
n.context = context;
n.pumpId = pumpId;
n.isSMB = isSMB;
n.deliverAt = deliverAt;
n.notes = notes;
return n;
}
@Override @Override
public String toString() { public String toString() {
@ -37,6 +59,7 @@ public class DetailedBolusInfo {
" carbs: " + carbs + " carbs: " + carbs +
" isValid: " + isValid + " isValid: " + isValid +
" carbTime: " + carbTime + " carbTime: " + carbTime +
" isSMB: " + isSMB; " isSMB: " + isSMB +
" deliverAt: " + new Date(deliverAt).toLocaleString();
} }
} }

View file

@ -21,6 +21,7 @@ import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
@ -35,21 +36,15 @@ public class GlucoseStatus {
public double avgdelta = 0d; public double avgdelta = 0d;
public double short_avgdelta = 0d; public double short_avgdelta = 0d;
public double long_avgdelta = 0d; public double long_avgdelta = 0d;
public long date = 0L;
@Override @Override
public String toString() { public String toString() {
return MainApp.sResources.getString(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" + return MainApp.gs(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" +
MainApp.sResources.getString(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" + MainApp.gs(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" +
MainApp.sResources.getString(R.string.short_avgdelta) + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl\n" + MainApp.gs(R.string.short_avgdelta) + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl\n" +
MainApp.sResources.getString(R.string.long_avgdelta) + " " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl"; MainApp.gs(R.string.long_avgdelta) + " " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
}
public Spanned toSpanned() {
return Html.fromHtml("<b>" + MainApp.sResources.getString(R.string.glucose) + "</b>: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.delta) + "</b>: " + DecimalFormatter.to0Decimal(delta) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.short_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.long_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl");
} }
public GlucoseStatus() { public GlucoseStatus() {
@ -74,11 +69,15 @@ public class GlucoseStatus {
@Nullable @Nullable
public static GlucoseStatus getGlucoseStatusData(boolean allowOldData) { public static GlucoseStatus getGlucoseStatusData(boolean allowOldData) {
// load 45min // load 45min
long fromtime = (long) (System.currentTimeMillis() - 60 * 1000L * 45); long fromtime = DateUtil.now() - 60 * 1000L * 45;
List<BgReading> data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false); List<BgReading> data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false);
int sizeRecords = data.size(); int sizeRecords = data.size();
if (sizeRecords < 1 || (data.get(0).date < System.currentTimeMillis() - 7 * 60 * 1000L && !allowOldData)) { if (sizeRecords == 0) {
return null;
}
if (data.get(0).date < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
return null; return null;
} }
@ -86,13 +85,14 @@ public class GlucoseStatus {
long now_date = now.date; long now_date = now.date;
double change; double change;
if (sizeRecords < 2) { if (sizeRecords == 1) {
GlucoseStatus status = new GlucoseStatus(); GlucoseStatus status = new GlucoseStatus();
status.glucose = now.value; status.glucose = now.value;
status.short_avgdelta = 0d; status.short_avgdelta = 0d;
status.delta = 0d; status.delta = 0d;
status.long_avgdelta = 0d; status.long_avgdelta = 0d;
status.avgdelta = 0d; // for OpenAPS MA status.avgdelta = 0d; // for OpenAPS MA
status.date = now_date;
return status.round(); return status.round();
} }
@ -133,6 +133,7 @@ public class GlucoseStatus {
GlucoseStatus status = new GlucoseStatus(); GlucoseStatus status = new GlucoseStatus();
status.glucose = now.value; status.glucose = now.value;
status.date = now_date;
status.short_avgdelta = average(short_deltas); status.short_avgdelta = average(short_deltas);

View file

@ -16,7 +16,11 @@ import info.nightscout.androidaps.interfaces.Interval;
public abstract class Intervals<T extends Interval> { public abstract class Intervals<T extends Interval> {
LongSparseArray<T> rawData = new LongSparseArray<T>(); // oldest at index 0 LongSparseArray<T> rawData; // oldest at index 0
public Intervals() {
rawData = new LongSparseArray<T>();
}
public synchronized Intervals reset() { public synchronized Intervals reset() {
rawData = new LongSparseArray<T>(); rawData = new LongSparseArray<T>();
@ -27,8 +31,7 @@ public abstract class Intervals<T extends Interval> {
/** /**
* The List must be sorted by `T.start()` in ascending order * The List must be sorted by `T.start()` in ascending order
* */
* */
public synchronized void add(List<T> list) { public synchronized void add(List<T> list) {
for (T interval : list) { for (T interval : list) {
rawData.put(interval.start(), interval); rawData.put(interval.start(), interval);
@ -36,6 +39,10 @@ public abstract class Intervals<T extends Interval> {
merge(); merge();
} }
public synchronized void add(T interval) {
rawData.put(interval.start(), interval);
merge();
}
public synchronized List<T> getList() { public synchronized List<T> getList() {
@ -47,7 +54,7 @@ public abstract class Intervals<T extends Interval> {
public synchronized List<T> getReversedList() { public synchronized List<T> getReversedList() {
List<T> list = new ArrayList<>(); List<T> list = new ArrayList<>();
for (int i = rawData.size() -1; i>=0; i--) for (int i = rawData.size() - 1; i >= 0; i--)
list.add(rawData.valueAt(i)); list.add(rawData.valueAt(i));
return list; return list;
} }
@ -86,5 +93,4 @@ public abstract class Intervals<T extends Interval> {
} }
} }

View file

@ -7,6 +7,16 @@ public class Iob {
public double iobContrib = 0d; public double iobContrib = 0d;
public double activityContrib = 0d; public double activityContrib = 0d;
public Iob iobContrib(double iobContrib) {
this.iobContrib = iobContrib;
return this;
}
public Iob activityContrib(double activityContrib) {
this.activityContrib = activityContrib;
return this;
}
public Iob plus(Iob iob) { public Iob plus(Iob iob) {
iobContrib += iob.iobContrib; iobContrib += iob.iobContrib;
activityContrib += iob.activityContrib; activityContrib += iob.activityContrib;

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.data; package info.nightscout.androidaps.data;
import com.rits.cloning.Cloner;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -21,8 +23,8 @@ public class IobTotal {
public double hightempinsulin; public double hightempinsulin;
// oref1 // oref1
public double microBolusInsulin; public long lastBolusTime;
public double microBolusIOB; public IobTotal iobWithZeroTemp;
public double netInsulin = 0d; // for calculations from temp basals only public double netInsulin = 0d; // for calculations from temp basals only
public double netRatio = 0d; // net ratio at start of temp basal public double netRatio = 0d; // net ratio at start of temp basal
@ -31,6 +33,12 @@ public class IobTotal {
long time; long time;
public IobTotal copy() {
Cloner cloner = new Cloner();
return cloner.deepClone(this);
}
public IobTotal(long time) { public IobTotal(long time) {
this.iob = 0d; this.iob = 0d;
this.activity = 0d; this.activity = 0d;
@ -38,8 +46,7 @@ public class IobTotal {
this.basaliob = 0d; this.basaliob = 0d;
this.netbasalinsulin = 0d; this.netbasalinsulin = 0d;
this.hightempinsulin = 0d; this.hightempinsulin = 0d;
this.microBolusInsulin = 0d; this.lastBolusTime = 0;
this.microBolusIOB = 0d;
this.time = time; this.time = time;
} }
@ -52,8 +59,6 @@ public class IobTotal {
hightempinsulin += other.hightempinsulin; hightempinsulin += other.hightempinsulin;
netInsulin += other.netInsulin; netInsulin += other.netInsulin;
extendedBolusInsulin += other.extendedBolusInsulin; extendedBolusInsulin += other.extendedBolusInsulin;
microBolusInsulin += other.microBolusInsulin;
microBolusIOB += other.microBolusIOB;
return this; return this;
} }
@ -62,11 +67,13 @@ public class IobTotal {
result.iob = bolusIOB.iob + basalIob.basaliob; result.iob = bolusIOB.iob + basalIob.basaliob;
result.activity = bolusIOB.activity + basalIob.activity; result.activity = bolusIOB.activity + basalIob.activity;
result.bolussnooze = bolusIOB.bolussnooze; result.bolussnooze = bolusIOB.bolussnooze;
result.basaliob = basalIob.basaliob; result.basaliob = bolusIOB.basaliob + basalIob.basaliob;
result.netbasalinsulin = basalIob.netbasalinsulin; result.netbasalinsulin = bolusIOB.netbasalinsulin + basalIob.netbasalinsulin;
result.hightempinsulin = basalIob.hightempinsulin; result.hightempinsulin = basalIob.hightempinsulin + bolusIOB.hightempinsulin;
result.microBolusInsulin = bolusIOB.microBolusInsulin + basalIob.microBolusInsulin; result.netInsulin = basalIob.netInsulin + bolusIOB.netInsulin;
result.microBolusIOB = bolusIOB.microBolusIOB + basalIob.microBolusIOB; result.extendedBolusInsulin = basalIob.extendedBolusInsulin + bolusIOB.extendedBolusInsulin;
result.lastBolusTime = bolusIOB.lastBolusTime;
result.iobWithZeroTemp = basalIob.iobWithZeroTemp;
return result; return result;
} }
@ -77,8 +84,8 @@ public class IobTotal {
this.basaliob = Round.roundTo(this.basaliob, 0.001); this.basaliob = Round.roundTo(this.basaliob, 0.001);
this.netbasalinsulin = Round.roundTo(this.netbasalinsulin, 0.001); this.netbasalinsulin = Round.roundTo(this.netbasalinsulin, 0.001);
this.hightempinsulin = Round.roundTo(this.hightempinsulin, 0.001); this.hightempinsulin = Round.roundTo(this.hightempinsulin, 0.001);
this.microBolusInsulin = Round.roundTo(this.microBolusInsulin, 0.001); this.netInsulin = Round.roundTo(this.netInsulin, 0.001);
this.microBolusIOB = Round.roundTo(this.microBolusIOB, 0.001); this.extendedBolusInsulin = Round.roundTo(this.extendedBolusInsulin, 0.001);
return this; return this;
} }
@ -102,7 +109,24 @@ public class IobTotal {
json.put("basaliob", basaliob); json.put("basaliob", basaliob);
json.put("bolussnooze", bolussnooze); json.put("bolussnooze", bolussnooze);
json.put("activity", activity); json.put("activity", activity);
json.put("lastBolusTime", lastBolusTime);
json.put("time", DateUtil.toISOString(new Date(time))); json.put("time", DateUtil.toISOString(new Date(time)));
/*
This is requested by SMB determine_basal but by based on Scott's info
it's MDT specific safety check only
It's causing rounding issues in determine_basal
JSONObject lastTemp = new JSONObject();
lastTemp.put("date", lastTempDate);
lastTemp.put("rate", lastTempRate);
lastTemp.put("duration", lastTempDuration);
json.put("lastTemp", lastTemp);
*/
if (iobWithZeroTemp != null) {
JSONObject iwzt = iobWithZeroTemp.determineBasalJson();
json.put("iobWithZeroTemp", iwzt);
}
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }

View file

@ -7,4 +7,9 @@ public class MealData {
public double boluses = 0d; public double boluses = 0d;
public double carbs = 0d; public double carbs = 0d;
public double mealCOB = 0.0d; public double mealCOB = 0.0d;
public double slopeFromMaxDeviation = 0;
public double slopeFromMinDeviation = 999;
public long lastBolusTime;
public long lastCarbTime = 0L;
public double usedMinCarbsImpact = 0d;
} }

View file

@ -2,7 +2,9 @@ package info.nightscout.androidaps.data;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
/** /**
@ -11,6 +13,14 @@ import info.nightscout.androidaps.interfaces.Interval;
public class NonOverlappingIntervals<T extends Interval> extends Intervals<T> { public class NonOverlappingIntervals<T extends Interval> extends Intervals<T> {
public NonOverlappingIntervals() {
super();
}
public NonOverlappingIntervals (Intervals<T> other) {
rawData = other.rawData.clone();
}
protected synchronized void merge() { protected synchronized void merge() {
for (int index = 0; index < rawData.size() - 1; index++) { for (int index = 0; index < rawData.size() - 1; index++) {
Interval i = rawData.valueAt(index); Interval i = rawData.valueAt(index);
@ -27,4 +37,5 @@ public class NonOverlappingIntervals<T extends Interval> extends Intervals<T> {
if (index >= 0) return rawData.valueAt(index); if (index >= 0) return rawData.valueAt(index);
return null; return null;
} }
} }

View file

@ -11,18 +11,26 @@ import info.nightscout.androidaps.interfaces.Interval;
public class OverlappingIntervals<T extends Interval> extends Intervals<T> { public class OverlappingIntervals<T extends Interval> extends Intervals<T> {
public OverlappingIntervals() {
super();
}
public OverlappingIntervals(Intervals<T> other) {
rawData = other.rawData.clone();
}
protected synchronized void merge() { protected synchronized void merge() {
boolean needToCut = false; boolean needToCut = false;
long cutTime = 0; long cutTime = 0;
for (int index = rawData.size()-1; index >= 0; index--) { //begin with newest for (int index = rawData.size() - 1; index >= 0; index--) { //begin with newest
Interval cur = rawData.valueAt(index); Interval cur = rawData.valueAt(index);
if (cur.isEndingEvent()){ if (cur.isEndingEvent()) {
needToCut = true; needToCut = true;
cutTime = cur.start(); cutTime = cur.start();
} else { } else {
//event that is no EndingEvent might need to be stopped by an ending event //event that is no EndingEvent might need to be stopped by an ending event
if(needToCut&&cur.end() > cutTime){ if (needToCut && cur.end() > cutTime) {
cur.cutEndTo(cutTime); cur.cutEndTo(cutTime);
} }
} }
@ -31,9 +39,9 @@ public class OverlappingIntervals<T extends Interval> extends Intervals<T> {
@Nullable @Nullable
public synchronized T getValueByInterval(long time) { public synchronized T getValueByInterval(long time) {
for (int index = rawData.size()-1; index >= 0; index--) { //begin with newest for (int index = rawData.size() - 1; index >= 0; index--) { //begin with newest
T cur = rawData.valueAt(index); T cur = rawData.valueAt(index);
if (cur.match(time)){ if (cur.match(time)) {
return cur; return cur;
} }
} }

View file

@ -2,8 +2,6 @@ package info.nightscout.androidaps.data;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import com.crashlytics.android.Crashlytics;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -14,56 +12,76 @@ import java.text.DecimalFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.TimeZone; import java.util.TimeZone;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.ToastUtils; import info.nightscout.utils.FabricPrivacy;
public class Profile { public class Profile {
private static Logger log = LoggerFactory.getLogger(Profile.class); private static Logger log = LoggerFactory.getLogger(Profile.class);
private JSONObject json; private JSONObject json;
private String units = null; private String units;
private double dia = Constants.defaultDIA; private double dia;
private TimeZone timeZone = TimeZone.getDefault(); private TimeZone timeZone;
private JSONArray isf; private JSONArray isf;
private LongSparseArray<Double> isf_v = null; // oldest at index 0 private LongSparseArray<Double> isf_v; // oldest at index 0
private JSONArray ic; private JSONArray ic;
private LongSparseArray<Double> ic_v = null; // oldest at index 0 private LongSparseArray<Double> ic_v; // oldest at index 0
private JSONArray basal; private JSONArray basal;
private LongSparseArray<Double> basal_v = null; // oldest at index 0 private LongSparseArray<Double> basal_v; // oldest at index 0
private JSONArray targetLow; private JSONArray targetLow;
private LongSparseArray<Double> targetLow_v = null; // oldest at index 0 private LongSparseArray<Double> targetLow_v; // oldest at index 0
private JSONArray targetHigh; private JSONArray targetHigh;
private LongSparseArray<Double> targetHigh_v = null; // oldest at index 0 private LongSparseArray<Double> targetHigh_v; // oldest at index 0
private int percentage = 100; private int percentage;
private int timeshift = 0; private int timeshift;
private boolean isValid = true; protected boolean isValid;
private boolean isValidated = false; protected boolean isValidated;
// Default constructor for tests
protected Profile() {
}
// Constructor from profileStore JSON
public Profile(JSONObject json, String units) { public Profile(JSONObject json, String units) {
this(json, 100, 0); init(json, 100, 0);
if (this.units == null) { if (this.units == null) {
if (units != null) if (units != null)
this.units = units; this.units = units;
else { else {
Crashlytics.log("Profile failover failed too"); FabricPrivacy.log("Profile failover failed too");
this.units = Constants.MGDL; this.units = Constants.MGDL;
} }
} }
} }
public Profile(JSONObject json, int percentage, int timeshift) { public Profile(JSONObject json, int percentage, int timeshift) {
init(json, percentage, timeshift);
}
protected void init(JSONObject json, int percentage, int timeshift) {
units = null;
dia = Constants.defaultDIA;
timeZone = TimeZone.getDefault();
isf_v = null;
ic_v = null;
basal_v = null;
targetLow_v = null;
targetHigh_v = null;
isValid = true;
isValidated = false;
this.percentage = percentage; this.percentage = percentage;
this.timeshift = timeshift; this.timeshift = timeshift;
this.json = json; this.json = json;
@ -77,53 +95,12 @@ public class Profile {
if (json.has("timezone")) if (json.has("timezone"))
timeZone = TimeZone.getTimeZone(json.getString("timezone")); timeZone = TimeZone.getTimeZone(json.getString("timezone"));
isf = json.getJSONArray("sens"); isf = json.getJSONArray("sens");
if (getIsf(0) == null) {
int defaultISF = units.equals(Constants.MGDL) ? 400 : 20;
isf = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultISF + "\",\"timeAsSeconds\":\"0\"}]");
Notification noisf = new Notification(Notification.ISF_MISSING, MainApp.sResources.getString(R.string.isfmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(noisf));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.ISF_MISSING));
}
ic = json.getJSONArray("carbratio"); ic = json.getJSONArray("carbratio");
if (getIc(0) == null) {
int defaultIC = 25;
ic = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultIC + "\",\"timeAsSeconds\":\"0\"}]");
Notification noic = new Notification(Notification.IC_MISSING, MainApp.sResources.getString(R.string.icmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(noic));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.IC_MISSING));
}
basal = json.getJSONArray("basal"); basal = json.getJSONArray("basal");
if (getBasal(0) == null) {
double defaultBasal = 0.1d;
basal = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultBasal + "\",\"timeAsSeconds\":\"0\"}]");
Notification nobasal = new Notification(Notification.BASAL_MISSING, MainApp.sResources.getString(R.string.basalmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(nobasal));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.BASAL_MISSING));
}
targetLow = json.getJSONArray("target_low"); targetLow = json.getJSONArray("target_low");
if (getTargetLow(0) == null) {
double defaultLow = units.equals(Constants.MGDL) ? 120 : 6;
targetLow = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultLow + "\",\"timeAsSeconds\":\"0\"}]");
Notification notarget = new Notification(Notification.TARGET_MISSING, MainApp.sResources.getString(R.string.targetmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notarget));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.TARGET_MISSING));
}
targetHigh = json.getJSONArray("target_high"); targetHigh = json.getJSONArray("target_high");
if (getTargetHigh(0) == null) {
double defaultHigh = units.equals(Constants.MGDL) ? 160 : 8;
targetHigh = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultHigh + "\",\"timeAsSeconds\":\"0\"}]");
Notification notarget = new Notification(Notification.TARGET_MISSING, MainApp.sResources.getString(R.string.targetmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notarget));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.TARGET_MISSING));
}
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.invalidprofile));
isValid = false; isValid = false;
isValidated = true; isValidated = true;
} }
@ -132,7 +109,7 @@ public class Profile {
public String log() { public String log() {
String ret = "\n"; String ret = "\n";
for (Integer hour = 0; hour < 24; hour++) { for (Integer hour = 0; hour < 24; hour++) {
double value = getBasal((Integer) (hour * 60 * 60)); double value = getBasalTimeFromMidnight((Integer) (hour * 60 * 60));
ret += "NS basal value for " + hour + ":00 is " + value + "\n"; ret += "NS basal value for " + hour + ":00 is " + value + "\n";
} }
ret += "NS units: " + getUnits(); ret += "NS units: " + getUnits();
@ -154,6 +131,10 @@ public class Profile {
} }
// mmol or mg/dl // mmol or mg/dl
public void setUnits(String units) {
this.units = units;
}
public String getUnits() { public String getUnits() {
return units; return units;
} }
@ -163,6 +144,11 @@ public class Profile {
} }
private LongSparseArray<Double> convertToSparseArray(JSONArray array) { private LongSparseArray<Double> convertToSparseArray(JSONArray array) {
if (array == null) {
isValid = false;
return new LongSparseArray<>();
}
double multiplier = getMultiplier(array); double multiplier = getMultiplier(array);
LongSparseArray<Double> sparse = new LongSparseArray<>(); LongSparseArray<Double> sparse = new LongSparseArray<>();
@ -217,22 +203,24 @@ public class Profile {
if (isValid) { if (isValid) {
// Check for hours alignment // Check for hours alignment
for (int index = 0; index < basal_v.size(); index++) { PumpInterface pump = MainApp.getConfigBuilder().getActivePump();
long secondsFromMidnight = basal_v.keyAt(index); if (pump != null && !pump.getPumpDescription().is30minBasalRatesCapable) {
if (secondsFromMidnight % 3600 != 0) { for (int index = 0; index < basal_v.size(); index++) {
Notification notification = new Notification(Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS, String.format(MainApp.gs(R.string.basalprofilenotaligned), from), Notification.NORMAL); long secondsFromMidnight = basal_v.keyAt(index);
MainApp.bus().post(new EventNewNotification(notification)); if (secondsFromMidnight % 3600 != 0) {
Notification notification = new Notification(Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS, String.format(MainApp.gs(R.string.basalprofilenotaligned), from), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
}
} }
} }
// Check for minimal basal value // Check for minimal basal value
PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (pump != null) { if (pump != null) {
PumpDescription description = pump.getPumpDescription(); PumpDescription description = pump.getPumpDescription();
for (int i = 0; i < basal_v.size(); i++) { for (int i = 0; i < basal_v.size(); i++) {
if (basal_v.valueAt(i) < description.basalMinimumRate) { if (basal_v.valueAt(i) < description.basalMinimumRate) {
basal_v.setValueAt(i, description.basalMinimumRate); basal_v.setValueAt(i, description.basalMinimumRate);
MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL))); sendBelowMinimumNotification(from);
} }
} }
} else { } else {
@ -246,6 +234,10 @@ public class Profile {
return isValid; return isValid;
} }
protected void sendBelowMinimumNotification(String from) {
MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL)));
}
private void validate(LongSparseArray array) { private void validate(LongSparseArray array) {
if (array.size() == 0) { if (array.size() == 0) {
isValid = false; isValid = false;
@ -259,6 +251,7 @@ public class Profile {
} }
} }
/*
private Double getValueToTime(JSONArray array, Integer timeAsSeconds) { private Double getValueToTime(JSONArray array, Integer timeAsSeconds) {
Double lastValue = null; Double lastValue = null;
@ -278,11 +271,12 @@ public class Profile {
} }
return lastValue; return lastValue;
} }
*/
Integer getShitfTimeSecs(Integer originalTime) { Integer getShitfTimeSecs(Integer originalTime) {
Integer shiftedTime = originalTime + timeshift * 60 * 60; Integer shiftedTime = originalTime + timeshift * 60 * 60;
shiftedTime = (shiftedTime + 24 * 60 * 60) % (24 * 60 * 60); shiftedTime = (shiftedTime + 24 * 60 * 60) % (24 * 60 * 60);
if (timeshift != 0) if (timeshift != 0 && Config.logProfile)
log.debug("(Sec) Original time: " + originalTime + " ShiftedTime: " + shiftedTime); log.debug("(Sec) Original time: " + originalTime + " ShiftedTime: " + shiftedTime);
return shiftedTime; return shiftedTime;
} }
@ -319,7 +313,7 @@ public class Profile {
return multiplier; return multiplier;
} }
private Double getValueToTime(LongSparseArray<Double> array, Integer timeAsSeconds) { private double getValueToTime(LongSparseArray<Double> array, Integer timeAsSeconds) {
Double lastValue = null; Double lastValue = null;
for (Integer index = 0; index < array.size(); index++) { for (Integer index = 0; index < array.size(); index++) {
@ -334,7 +328,7 @@ public class Profile {
return lastValue; return lastValue;
} }
private String format_HH_MM(Integer timeAsSeconds) { protected String format_HH_MM(Integer timeAsSeconds) {
String time; String time;
int hour = timeAsSeconds / 60 / 60; int hour = timeAsSeconds / 60 / 60;
int minutes = (timeAsSeconds - hour * 60 * 60) / 60; int minutes = (timeAsSeconds - hour * 60 * 60) / 60;
@ -361,51 +355,55 @@ public class Profile {
return retValue; return retValue;
} }
public Double getIsf() { public double getIsf() {
return getIsf(secondsFromMidnight(System.currentTimeMillis())); return getIsfTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getIsf(long time) { public double getIsf(long time) {
return getIsf(secondsFromMidnight(time)); return getIsfTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getIsf(Integer timeAsSeconds) { double getIsfTimeFromMidnight(int timeAsSeconds) {
if (isf_v == null) if (isf_v == null)
isf_v = convertToSparseArray(isf); isf_v = convertToSparseArray(isf);
return getValueToTime(isf_v, timeAsSeconds); return getValueToTime(isf_v, timeAsSeconds);
} }
public String getIsfList() { public String getIsfList() {
if (isf_v == null)
isf_v = convertToSparseArray(isf);
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U"); return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U");
} }
public Double getIc() { public double getIc() {
return getIc(secondsFromMidnight(System.currentTimeMillis())); return getIcTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getIc(long time) { public double getIc(long time) {
return getIc(secondsFromMidnight(time)); return getIcTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getIc(Integer timeAsSeconds) { public double getIcTimeFromMidnight(int timeAsSeconds) {
if (ic_v == null) if (ic_v == null)
ic_v = convertToSparseArray(ic); ic_v = convertToSparseArray(ic);
return getValueToTime(ic_v, timeAsSeconds); return getValueToTime(ic_v, timeAsSeconds);
} }
public String getIcList() { public String getIcList() {
return getValuesList(ic_v, null, new DecimalFormat("0.0"), " g/U"); if (ic_v == null)
ic_v = convertToSparseArray(ic);
return getValuesList(ic_v, null, new DecimalFormat("0.0"), "g/U");
} }
public Double getBasal() { public double getBasal() {
return getBasal(secondsFromMidnight(System.currentTimeMillis())); return getBasalTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getBasal(long time) { public double getBasal(long time) {
return getBasal(secondsFromMidnight(time)); return getBasalTimeFromMidnight(secondsFromMidnight(time));
} }
public synchronized Double getBasal(Integer timeAsSeconds) { public synchronized double getBasalTimeFromMidnight(int timeAsSeconds) {
if (basal_v == null) { if (basal_v == null) {
basal_v = convertToSparseArray(basal); basal_v = convertToSparseArray(basal);
} }
@ -413,17 +411,19 @@ public class Profile {
} }
public String getBasalList() { public String getBasalList() {
return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U"); if (basal_v == null)
basal_v = convertToSparseArray(basal);
return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U/h");
} }
public class BasalValue { public class BasalValue {
public BasalValue(Integer timeAsSeconds, Double value) { public BasalValue(int timeAsSeconds, double value) {
this.timeAsSeconds = timeAsSeconds; this.timeAsSeconds = timeAsSeconds;
this.value = value; this.value = value;
} }
public Integer timeAsSeconds; public int timeAsSeconds;
public Double value; public double value;
} }
public synchronized BasalValue[] getBasalValues() { public synchronized BasalValue[] getBasalValues() {
@ -433,54 +433,66 @@ public class Profile {
for (Integer index = 0; index < basal_v.size(); index++) { for (Integer index = 0; index < basal_v.size(); index++) {
Integer tas = (int) basal_v.keyAt(index); Integer tas = (int) basal_v.keyAt(index);
Double value = basal_v.valueAt(index); double value = basal_v.valueAt(index);
ret[index] = new BasalValue(tas, value); ret[index] = new BasalValue(tas, value);
} }
return ret; return ret;
} }
public Double getTargetLow() { public double getTarget(){
return getTargetLow(secondsFromMidnight(System.currentTimeMillis())); return getTarget(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getTargetLow(long time) { protected double getTarget(int timeAsSeconds) {
return getTargetLow(secondsFromMidnight(time)); return (getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds))/2;
} }
public Double getTargetLow(Integer timeAsSeconds) { public double getTargetLow() {
return getTargetLowTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
}
public double getTargetLow(long time) {
return getTargetLowTimeFromMidnight(secondsFromMidnight(time));
}
public double getTargetLowTimeFromMidnight(int timeAsSeconds) {
if (targetLow_v == null) if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow); targetLow_v = convertToSparseArray(targetLow);
return getValueToTime(targetLow_v, timeAsSeconds); return getValueToTime(targetLow_v, timeAsSeconds);
} }
public Double getTargetHigh() { public double getTargetHigh() {
return getTargetHigh(secondsFromMidnight(System.currentTimeMillis())); return getTargetHighTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getTargetHigh(long time) { public double getTargetHigh(long time) {
return getTargetHigh(secondsFromMidnight(time)); return getTargetHighTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getTargetHigh(Integer timeAsSeconds) { public double getTargetHighTimeFromMidnight(int timeAsSeconds) {
if (targetHigh_v == null) if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh); targetHigh_v = convertToSparseArray(targetHigh);
return getValueToTime(targetHigh_v, timeAsSeconds); return getValueToTime(targetHigh_v, timeAsSeconds);
} }
public String getTargetList() { public String getTargetList() {
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
return getValuesList(targetLow_v, targetHigh_v, new DecimalFormat("0.0"), getUnits()); return getValuesList(targetLow_v, targetHigh_v, new DecimalFormat("0.0"), getUnits());
} }
public double getMaxDailyBasal() { public double getMaxDailyBasal() {
Double max = 0d; double max = 0d;
for (Integer hour = 0; hour < 24; hour++) { for (int hour = 0; hour < 24; hour++) {
double value = getBasal((Integer) (hour * 60 * 60)); double value = getBasalTimeFromMidnight((Integer) (hour * 60 * 60));
if (value > max) max = value; if (value > max) max = value;
} }
return max; return max;
} }
public static Integer secondsFromMidnight() { public static int secondsFromMidnight() {
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis(); long now = c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.HOUR_OF_DAY, 0);
@ -491,7 +503,7 @@ public class Profile {
return (int) (passed / 1000); return (int) (passed / 1000);
} }
public static Integer secondsFromMidnight(long date) { public static int secondsFromMidnight(long date) {
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
c.setTimeInMillis(date); c.setTimeInMillis(date);
c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.HOUR_OF_DAY, 0);
@ -502,22 +514,22 @@ public class Profile {
return (int) (passed / 1000); return (int) (passed / 1000);
} }
public static Double toMgdl(Double value, String units) { public static double toMgdl(double value, String units) {
if (units.equals(Constants.MGDL)) return value; if (units.equals(Constants.MGDL)) return value;
else return value * Constants.MMOLL_TO_MGDL; else return value * Constants.MMOLL_TO_MGDL;
} }
public static Double toMmol(Double value, String units) { public static double toMmol(double value, String units) {
if (units.equals(Constants.MGDL)) return value * Constants.MGDL_TO_MMOLL; if (units.equals(Constants.MGDL)) return value * Constants.MGDL_TO_MMOLL;
else return value; else return value;
} }
public static Double fromMgdlToUnits(Double value, String units) { public static double fromMgdlToUnits(double value, String units) {
if (units.equals(Constants.MGDL)) return value; if (units.equals(Constants.MGDL)) return value;
else return value * Constants.MGDL_TO_MMOLL; else return value * Constants.MGDL_TO_MMOLL;
} }
public static Double toUnits(Double valueInMgdl, Double valueInMmol, String units) { public static double toUnits(Double valueInMgdl, Double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) return valueInMgdl; if (units.equals(Constants.MGDL)) return valueInMgdl;
else return valueInMmol; else return valueInMmol;
} }
@ -543,7 +555,7 @@ public class Profile {
public double percentageBasalSum() { public double percentageBasalSum() {
double result = 0d; double result = 0d;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
result += getBasal((Integer) (i * 60 * 60)); result += getBasalTimeFromMidnight(i * 60 * 60);
} }
return result; return result;
} }
@ -552,7 +564,7 @@ public class Profile {
public double baseBasalSum() { public double baseBasalSum() {
double result = 0d; double result = 0d;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
result += getBasal((Integer) (i * 60 * 60)) / getMultiplier(basal_v); result += getBasalTimeFromMidnight(i * 60 * 60) / getMultiplier(basal_v);
} }
return result; return result;
} }

View file

@ -3,10 +3,14 @@ package info.nightscout.androidaps.data;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.utils.DateUtil;
/** /**
* Created by mike on 09.05.2017. * Created by mike on 09.05.2017.
@ -16,8 +20,17 @@ import info.nightscout.androidaps.interfaces.Interval;
// When no interval match the lastest record without duration is used // When no interval match the lastest record without duration is used
public class ProfileIntervals<T extends Interval> { public class ProfileIntervals<T extends Interval> {
private static Logger log = LoggerFactory.getLogger(ProfileIntervals.class);
private LongSparseArray<T> rawData = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<T> rawData; // oldest at index 0
public ProfileIntervals () {
rawData = new LongSparseArray<>();
}
public ProfileIntervals (ProfileIntervals<T> other) {
rawData = other.rawData.clone();
}
public synchronized ProfileIntervals reset() { public synchronized ProfileIntervals reset() {
rawData = new LongSparseArray<>(); rawData = new LongSparseArray<>();
@ -25,8 +38,10 @@ public class ProfileIntervals<T extends Interval> {
} }
public synchronized void add(T newInterval) { public synchronized void add(T newInterval) {
rawData.put(newInterval.start(), newInterval); if (newInterval.isValid()) {
merge(); rawData.put(newInterval.start(), newInterval);
merge();
}
} }
public synchronized void add(List<T> list) { public synchronized void add(List<T> list) {
@ -51,6 +66,13 @@ public class ProfileIntervals<T extends Interval> {
public synchronized Interval getValueToTime(long time) { public synchronized Interval getValueToTime(long time) {
int index = binarySearch(time); int index = binarySearch(time);
if (index >= 0) return rawData.valueAt(index); if (index >= 0) return rawData.valueAt(index);
// if we request data older than first record, use oldest with zero duration instead
for (index = 0; index < rawData.size(); index++) {
if (rawData.valueAt(index).durationInMsec() == 0) {
//log.debug("Requested profile for time: " + DateUtil.dateAndTimeString(time) + ". Providing oldest record: " + rawData.valueAt(0).toString());
return rawData.valueAt(index);
}
}
return null; return null;
} }
@ -107,4 +129,9 @@ public class ProfileIntervals<T extends Interval> {
public synchronized T getReversed(int index) { public synchronized T getReversed(int index) {
return rawData.valueAt(size() - 1 - index); return rawData.valueAt(size() - 1 - index);
} }
@Override
public String toString() {
return rawData.toString();
}
} }

View file

@ -13,7 +13,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
public class PumpEnactResult extends Object { public class PumpEnactResult {
private static Logger log = LoggerFactory.getLogger(PumpEnactResult.class); private static Logger log = LoggerFactory.getLogger(PumpEnactResult.class);
public boolean success = false; // request was processed successfully (but possible no change was needed) public boolean success = false; // request was processed successfully (but possible no change was needed)
@ -21,19 +21,19 @@ public class PumpEnactResult extends Object {
public String comment = ""; public String comment = "";
// Result of basal change // Result of basal change
public Integer duration = -1; // duration set [minutes] public int duration = -1; // duration set [minutes]
public Double absolute = -1d; // absolute rate [U/h] , isPercent = false public double absolute = -1d; // absolute rate [U/h] , isPercent = false
public Integer percent = -1; // percent of current basal [%] (100% = current basal), isPercent = true public int percent = -1; // percent of current basal [%] (100% = current basal), isPercent = true
public boolean isPercent = false; // if true percent is used, otherwise absolute public boolean isPercent = false; // if true percent is used, otherwise absolute
public boolean isTempCancel = false; // if true we are caceling temp basal public boolean isTempCancel = false; // if true we are caceling temp basal
// Result of treatment delivery // Result of treatment delivery
public Double bolusDelivered = 0d; // real value of delivered insulin public double bolusDelivered = 0d; // real value of delivered insulin
public Double carbsDelivered = 0d; // real value of delivered carbs public double carbsDelivered = 0d; // real value of delivered carbs
public boolean queued = false; public boolean queued = false;
public PumpEnactResult success(boolean success) { public PumpEnactResult success(boolean success) {
this.success = success; this.success = success;
return this; return this;
} }
@ -47,16 +47,21 @@ public class PumpEnactResult extends Object {
return this; return this;
} }
public PumpEnactResult duration(Integer duration) { public PumpEnactResult duration(int duration) {
this.duration = duration; this.duration = duration;
return this; return this;
} }
public PumpEnactResult absolute(Double absolute) { public PumpEnactResult absolute(double absolute) {
this.absolute = absolute; this.absolute = absolute;
return this; return this;
} }
public PumpEnactResult percent(int percent) {
this.percent = percent;
return this;
}
public PumpEnactResult isPercent(boolean isPercent) { public PumpEnactResult isPercent(boolean isPercent) {
this.isPercent = isPercent; this.isPercent = isPercent;
return this; return this;
@ -67,12 +72,12 @@ public class PumpEnactResult extends Object {
return this; return this;
} }
public PumpEnactResult bolusDelivered(Double bolusDelivered) { public PumpEnactResult bolusDelivered(double bolusDelivered) {
this.bolusDelivered = bolusDelivered; this.bolusDelivered = bolusDelivered;
return this; return this;
} }
public PumpEnactResult carbsDelivered(Double carbsDelivered) { public PumpEnactResult carbsDelivered(double carbsDelivered) {
this.carbsDelivered = carbsDelivered; this.carbsDelivered = carbsDelivered;
return this; return this;
} }
@ -82,72 +87,96 @@ public class PumpEnactResult extends Object {
return this; return this;
} }
public String log() { public String log() {
return "Success: " + success + " Enacted: " + enacted + " Comment: " + comment + " Duration: " + duration + " Absolute: " + absolute + " Percent: " + percent + " IsPercent: " + isPercent + " Queued: " + queued; return "Success: " + success +
" Enacted: " + enacted +
" Comment: " + comment +
" Duration: " + duration +
" Absolute: " + absolute +
" Percent: " + percent +
" IsPercent: " + isPercent +
" IsTempCancel: " + isTempCancel +
" bolusDelivered: " + bolusDelivered +
" carbsDelivered: " + carbsDelivered +
" Queued: " + queued;
} }
public String toString() { public String toString() {
String ret = MainApp.sResources.getString(R.string.success) + ": " + success; String ret = MainApp.gs(R.string.success) + ": " + success;
if (enacted) { if (enacted) {
if (isTempCancel) { if (bolusDelivered > 0) {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment + "\n" + ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
MainApp.sResources.getString(R.string.canceltemp); ret += "\n" + MainApp.gs(R.string.smb_shortname)
+ ": " + bolusDelivered + " " + MainApp.gs(R.string.insulin_unit_shortname);
} else if (isTempCancel) {
ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
if (!comment.isEmpty())
ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.gs(R.string.canceltemp);
} else if (isPercent) { } else if (isPercent) {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment; if (!comment.isEmpty())
ret += "\n" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min"; ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.sResources.getString(R.string.percent) + ": " + percent + "%"; ret += "\n" + MainApp.gs(R.string.duration) + ": " + duration + " min";
ret += "\n" + MainApp.gs(R.string.percent) + ": " + percent + "%";
} else { } else {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment; if (!comment.isEmpty())
ret += "\n" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min"; ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.sResources.getString(R.string.absolute) + ": " + absolute + " U/h"; ret += "\n" + MainApp.gs(R.string.duration) + ": " + duration + " min";
ret += "\n" + MainApp.gs(R.string.absolute) + ": " + absolute + " U/h";
} }
} else { } else {
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment; ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
} }
return ret; return ret;
} }
public Spanned toSpanned() { public String toHtml() {
String ret = MainApp.sResources.getString(R.string.success) + ": " + success; String ret = "<b>" + MainApp.gs(R.string.success) + "</b>: " + success;
if (queued) { if (queued) {
ret = MainApp.sResources.getString(R.string.waitingforpumpresult); ret = MainApp.gs(R.string.waitingforpumpresult);
} else if (enacted) { } else if (enacted) {
if (isTempCancel) { if (bolusDelivered > 0) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted; ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment + if (!comment.isEmpty())
"<br>" + MainApp.sResources.getString(R.string.canceltemp); ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
} else if (isPercent) { ret += "<br><b>" + MainApp.gs(R.string.smb_shortname) + "</b>: " + bolusDelivered + " " + MainApp.gs(R.string.insulin_unit_shortname);
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted; } else if (isTempCancel) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment; ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + duration + " min"; ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment +
ret += "<br><b>" + MainApp.sResources.getString(R.string.percent) + "</b>: " + percent + "%"; "<br>" + MainApp.gs(R.string.canceltemp);
} else { } else if (isPercent && percent != -1) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted; ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment; if (!comment.isEmpty())
ret += "<br><b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + duration + " min"; ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
ret += "<br><b>" + MainApp.sResources.getString(R.string.absolute) + "</b>: " + DecimalFormatter.to2Decimal(absolute) + " U/h"; ret += "<br><b>" + MainApp.gs(R.string.duration) + "</b>: " + duration + " min";
ret += "<br><b>" + MainApp.gs(R.string.percent) + "</b>: " + percent + "%";
} else if (absolute != -1) {
ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
if (!comment.isEmpty())
ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
ret += "<br><b>" + MainApp.gs(R.string.duration) + "</b>: " + duration + " min";
ret += "<br><b>" + MainApp.gs(R.string.absolute) + "</b>: " + DecimalFormatter.to2Decimal(absolute) + " U/h";
} }
} else { } else {
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment; ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
} }
return Html.fromHtml(ret); return ret;
} }
public PumpEnactResult() { public JSONObject json(Profile profile) {
}
public JSONObject json() {
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
try { try {
if (isTempCancel) { if (bolusDelivered > 0) {
result.put("smb", bolusDelivered);
} else if (isTempCancel) {
result.put("rate", 0); result.put("rate", 0);
result.put("duration", 0); result.put("duration", 0);
} else if (isPercent) { } else if (isPercent) {
// Nightscout is expecting absolute value // Nightscout is expecting absolute value
Double abs = Round.roundTo(MainApp.getConfigBuilder().getProfile().getBasal() * percent / 100, 0.01); Double abs = Round.roundTo(profile.getBasal() * percent / 100, 0.01);
result.put("rate", abs); result.put("rate", abs);
result.put("duration", duration); result.put("duration", duration);
} else { } else {

View file

@ -10,6 +10,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.utils.SP;
/** /**
* Created by mike on 12.10.2016. * Created by mike on 12.10.2016.
@ -25,10 +26,7 @@ public class QuickWizard {
} }
public void save() { public void save() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); SP.putString("QuickWizard", storage.toString());
SharedPreferences.Editor editor = preferences.edit();
editor.putString("QuickWizard", storage.toString());
editor.apply();
} }
public int size() { public int size() {

View file

@ -7,15 +7,14 @@ import org.slf4j.LoggerFactory;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.CobInfo;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.BolusWizard; import info.nightscout.utils.BolusWizard;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -80,14 +79,10 @@ public class QuickWizardEntry {
// COB // COB
double cob = 0d; double cob = 0d;
AutosensData autosensData; if (useCOB() == YES) {
if (_synchronized) CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(_synchronized, "QuickWizard COB");
autosensData = IobCobCalculatorPlugin.getLastAutosensDataSynchronized("QuickWizard COB"); if (cobInfo.displayCob != null)
else cob = cobInfo.displayCob;
autosensData = IobCobCalculatorPlugin.getLastAutosensData("QuickWizard COB");
if (autosensData != null && useCOB() == YES) {
cob = autosensData.cob;
} }
// Temp target // Temp target
@ -102,7 +97,7 @@ public class QuickWizardEntry {
} }
// Basal IOB // Basal IOB
TreatmentsInterface treatments = MainApp.getConfigBuilder(); TreatmentsInterface treatments = TreatmentsPlugin.getPlugin();
treatments.updateTotalIOBTempBasals(); treatments.updateTotalIOBTempBasals();
IobTotal basalIob = treatments.getLastCalculationTempBasals().round(); IobTotal basalIob = treatments.getLastCalculationTempBasals().round();
boolean basalIOB = false; boolean basalIOB = false;
@ -119,8 +114,8 @@ public class QuickWizardEntry {
if (useSuperBolus() == YES && SP.getBoolean(R.string.key_usesuperbolus, false)) { if (useSuperBolus() == YES && SP.getBoolean(R.string.key_usesuperbolus, false)) {
superBolus = true; superBolus = true;
} }
final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop(); final LoopPlugin loopPlugin = LoopPlugin.getPlugin();
if (activeloop != null && activeloop.isEnabled(activeloop.getType()) && activeloop.isSuperBolus()) if (loopPlugin.isEnabled(loopPlugin.getType()) && loopPlugin.isSuperBolus())
superBolus = false; superBolus = false;
// Trend // Trend

View file

@ -17,7 +17,6 @@ import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -43,7 +42,11 @@ public class BgReading implements DataPointWithLabelInterface {
@DatabaseField @DatabaseField
public String _id = null; // NS _id public String _id = null; // NS _id
public boolean isPrediction = false; // true when drawing predictions as bg points public boolean isCOBPrediction = false; // true when drawing predictions as bg points (COB)
public boolean isaCOBPrediction = false; // true when drawing predictions as bg points (aCOB)
public boolean isIOBPrediction = false; // true when drawing predictions as bg points (IOB)
public boolean isUAMPrediction = false; // true when drawing predictions as bg points (UAM)
public boolean isZTPrediction = false; // true when drawing predictions as bg points (ZT)
public BgReading() { public BgReading() {
} }
@ -184,13 +187,15 @@ public class BgReading implements DataPointWithLabelInterface {
@Override @Override
public PointsWithLabelGraphSeries.Shape getShape() { public PointsWithLabelGraphSeries.Shape getShape() {
return PointsWithLabelGraphSeries.Shape.POINT; if (isPrediction())
return PointsWithLabelGraphSeries.Shape.PREDICTION;
else
return PointsWithLabelGraphSeries.Shape.BG;
} }
@Override @Override
public float getSize() { public float getSize() {
boolean isTablet = MainApp.sResources.getBoolean(R.bool.isTablet); return 1;
return isTablet ? 8 : 5;
} }
@Override @Override
@ -205,7 +210,7 @@ public class BgReading implements DataPointWithLabelInterface {
highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units); highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units);
} }
int color = MainApp.sResources.getColor(R.color.inrange); int color = MainApp.sResources.getColor(R.color.inrange);
if (isPrediction) if (isPrediction())
color = MainApp.sResources.getColor(R.color.prediction); color = MainApp.sResources.getColor(R.color.prediction);
else if (valueToUnits(units) < lowLine) else if (valueToUnits(units) < lowLine)
color = MainApp.sResources.getColor(R.color.low); color = MainApp.sResources.getColor(R.color.low);
@ -214,4 +219,23 @@ public class BgReading implements DataPointWithLabelInterface {
return color; return color;
} }
@Override
public int getSecondColor() {
if (isIOBPrediction)
return MainApp.sResources.getColor(R.color.iob);
if (isCOBPrediction)
return MainApp.sResources.getColor(R.color.cob);
if (isaCOBPrediction)
return 0x80FFFFFF & MainApp.sResources.getColor(R.color.cob);
if (isUAMPrediction)
return MainApp.sResources.getColor(R.color.uam);
if (isZTPrediction)
return MainApp.sResources.getColor(R.color.zt);
return R.color.mdtp_white;
}
private boolean isPrediction() {
return isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction;
}
} }

View file

@ -5,6 +5,7 @@ import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -97,6 +98,14 @@ public class CareportalEvent implements DataPointWithLabelInterface {
return diff.get(TimeUnit.DAYS) + " " + MainApp.sResources.getString(R.string.days) + " " + diff.get(TimeUnit.HOURS) + " " + MainApp.sResources.getString(R.string.hours); return diff.get(TimeUnit.DAYS) + " " + MainApp.sResources.getString(R.string.days) + " " + diff.get(TimeUnit.HOURS) + " " + MainApp.sResources.getString(R.string.hours);
} }
public boolean isOlderThan(double hours) {
Map<TimeUnit, Long> diff = computeDiff(date, System.currentTimeMillis());
if(diff.get(TimeUnit.DAYS)*24 + diff.get(TimeUnit.HOURS) > hours)
return true;
else
return false;
}
public String log() { public String log() {
return "CareportalEvent{" + return "CareportalEvent{" +
"date= " + date + "date= " + date +
@ -184,7 +193,7 @@ public class CareportalEvent implements DataPointWithLabelInterface {
try { try {
JSONObject object = new JSONObject(json); JSONObject object = new JSONObject(json);
if (object.has("notes")) if (object.has("notes"))
return object.getString("notes"); return StringUtils.abbreviate(object.getString("notes"), 40);
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
@ -253,4 +262,10 @@ public class CareportalEvent implements DataPointWithLabelInterface {
return Color.GRAY; return Color.GRAY;
return Color.GRAY; return Color.GRAY;
} }
@Override
public int getSecondColor() {
return 0;
}
} }

View file

@ -30,12 +30,10 @@ import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventProfileSwitchChange; import info.nightscout.androidaps.events.EventProfileSwitchChange;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
@ -44,17 +42,23 @@ import info.nightscout.androidaps.events.EventReloadTempBasalData;
import info.nightscout.androidaps.events.EventReloadTreatmentData; import info.nightscout.androidaps.events.EventReloadTreatmentData;
import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.events.EventTempTargetChange; import info.nightscout.androidaps.events.EventTempTargetChange;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync; import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.PercentageSplitter; import info.nightscout.utils.PercentageSplitter;
import info.nightscout.utils.ToastUtils;
/**
* This Helper contains all resource to provide a central DB management functionality. Only methods handling
* data-structure (and not the DB content) should be contained in here (meaning DDL and not SQL).
* <p>
* This class can safely be called from Services, but should not call Services to avoid circular dependencies.
* One major issue with this (right now) are the scheduled events, which are put into the service. Therefor all
* direct calls to the corresponding methods (eg. resetDatabases) should be done by a central service.
*/
public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class); private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class);
@ -63,23 +67,19 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals"; public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals";
public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses"; public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses";
public static final String DATABASE_TEMPTARGETS = "TempTargets"; public static final String DATABASE_TEMPTARGETS = "TempTargets";
public static final String DATABASE_TREATMENTS = "Treatments";
public static final String DATABASE_DANARHISTORY = "DanaRHistory"; public static final String DATABASE_DANARHISTORY = "DanaRHistory";
public static final String DATABASE_DBREQUESTS = "DBRequests"; public static final String DATABASE_DBREQUESTS = "DBRequests";
public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents"; public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents";
public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches"; public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches";
public static final String DATABASE_FOODS = "Foods"; public static final String DATABASE_TDDS = "TDDs";
private static final int DATABASE_VERSION = 8; private static final int DATABASE_VERSION = 8;
private static Long earliestDataChange = null; public static Long earliestDataChange = null;
private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledBgPost = null; private static ScheduledFuture<?> scheduledBgPost = null;
private static final ScheduledExecutorService treatmentsWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTratmentPost = null;
private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTemBasalsPost = null; private static ScheduledFuture<?> scheduledTemBasalsPost = null;
@ -95,7 +95,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null; private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null;
public FoodHelper foodHelper = new FoodHelper(this); private int oldVersion = 0;
private int newVersion = 0;
public DatabaseHelper(Context context) { public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);
@ -108,7 +109,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try { try {
log.info("onCreate"); log.info("onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class); TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class); TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
@ -116,7 +116,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class); TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class); TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, Food.class); TableUtils.createTableIfNotExists(connectionSource, TDD.class);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Can't create database", e); log.error("Can't create database", e);
throw new RuntimeException(e); throw new RuntimeException(e);
@ -126,14 +126,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@Override @Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
try { try {
this.oldVersion = oldVersion;
this.newVersion = newVersion;
if (oldVersion == 7 && newVersion == 8) { if (oldVersion == 7 && newVersion == 8) {
log.debug("Upgrading database from v7 to v8"); log.debug("Upgrading database from v7 to v8");
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
} else { } else {
log.info(DatabaseHelper.class.getName(), "onUpgrade"); log.info(DatabaseHelper.class.getName(), "onUpgrade");
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true); TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
@ -141,7 +141,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true); TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, Food.class, true);
onCreate(database, connectionSource); onCreate(database, connectionSource);
} }
} catch (SQLException e) { } catch (SQLException e) {
@ -150,6 +149,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
public int getOldVersion() {
return oldVersion;
}
public int getNewVersion() {
return newVersion;
}
/** /**
* Close the database connections and clear any cached DAOs. * Close the database connections and clear any cached DAOs.
*/ */
@ -158,40 +165,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
super.close(); super.close();
} }
public void cleanUpDatabases() {
// TODO: call it somewhere
log.debug("Before BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
getWritableDatabase().delete(DATABASE_BGREADINGS, "date" + " < '" + (System.currentTimeMillis() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
log.debug("Before TempTargets size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPTARGETS));
getWritableDatabase().delete(DATABASE_TEMPTARGETS, "date" + " < '" + (System.currentTimeMillis() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After TempTargets size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPTARGETS));
log.debug("Before Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
getWritableDatabase().delete(DATABASE_TREATMENTS, "date" + " < '" + (System.currentTimeMillis() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
log.debug("Before History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_DANARHISTORY));
getWritableDatabase().delete(DATABASE_DANARHISTORY, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_DANARHISTORY));
log.debug("Before TemporaryBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPORARYBASALS));
getWritableDatabase().delete(DATABASE_TEMPORARYBASALS, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After TemporaryBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPORARYBASALS));
log.debug("Before ExtendedBoluses size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_EXTENDEDBOLUSES));
getWritableDatabase().delete(DATABASE_EXTENDEDBOLUSES, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After ExtendedBoluses size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_EXTENDEDBOLUSES));
log.debug("Before CareportalEvent size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_CAREPORTALEVENTS));
getWritableDatabase().delete(DATABASE_CAREPORTALEVENTS, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After CareportalEvent size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_CAREPORTALEVENTS));
log.debug("Before ProfileSwitch size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_PROFILESWITCHES));
getWritableDatabase().delete(DATABASE_PROFILESWITCHES, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After ProfileSwitch size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_PROFILESWITCHES));
}
public long size(String database) { public long size(String database) {
return DatabaseUtils.queryNumEntries(getReadableDatabase(), database); return DatabaseUtils.queryNumEntries(getReadableDatabase(), database);
@ -202,7 +175,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void resetDatabases() { public void resetDatabases() {
try { try {
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true); TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
@ -210,8 +182,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true); TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class); TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class); TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
@ -219,20 +191,18 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class); TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class); TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
foodHelper.resetFood(); TableUtils.createTableIfNotExists(connectionSource, TDD.class);
updateEarliestDataChange(0); updateEarliestDataChange(0);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
VirtualPumpPlugin.setFakingStatus(true); VirtualPumpPlugin.setFakingStatus(true);
scheduleBgChange(); // trigger refresh scheduleBgChange(null); // trigger refresh
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
scheduleTreatmentChange();
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();
scheduleCareportalEventChange(); scheduleCareportalEventChange();
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
foodHelper.scheduleFoodChange();
new java.util.Timer().schedule( new java.util.Timer().schedule(
new java.util.TimerTask() { new java.util.TimerTask() {
@Override @Override
@ -244,17 +214,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
); );
} }
public void resetTreatments() {
try {
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
updateEarliestDataChange(0);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleTreatmentChange();
}
public void resetTempTargets() { public void resetTempTargets() {
try { try {
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
@ -308,16 +267,21 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
} }
public void resetTDDs() {
try {
TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.createTableIfNotExists(connectionSource, TDD.class);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
// ------------------ getDao ------------------------------------------- // ------------------ getDao -------------------------------------------
private Dao<TempTarget, Long> getDaoTempTargets() throws SQLException { private Dao<TempTarget, Long> getDaoTempTargets() throws SQLException {
return getDao(TempTarget.class); return getDao(TempTarget.class);
} }
private Dao<Treatment, Long> getDaoTreatments() throws SQLException {
return getDao(Treatment.class);
}
private Dao<BgReading, Long> getDaoBgReadings() throws SQLException { private Dao<BgReading, Long> getDaoBgReadings() throws SQLException {
return getDao(BgReading.class); return getDao(BgReading.class);
} }
@ -326,6 +290,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(DanaRHistoryRecord.class); return getDao(DanaRHistoryRecord.class);
} }
private Dao<TDD, String> getDaoTDD() throws SQLException {
return getDao(TDD.class);
}
private Dao<DbRequest, String> getDaoDbRequest() throws SQLException { private Dao<DbRequest, String> getDaoDbRequest() throws SQLException {
return getDao(DbRequest.class); return getDao(DbRequest.class);
} }
@ -346,7 +314,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(ProfileSwitch.class); return getDao(ProfileSwitch.class);
} }
public long roundDateToSec(long date) { public static long roundDateToSec(long date) {
return date - date % 1000; return date - date % 1000;
} }
// ------------------- BgReading handling ----------------------- // ------------------- BgReading handling -----------------------
@ -358,7 +326,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (old == null) { if (old == null) {
getDaoBgReadings().create(bgReading); getDaoBgReadings().create(bgReading);
log.debug("BG: New record from: " + from + " " + bgReading.toString()); log.debug("BG: New record from: " + from + " " + bgReading.toString());
scheduleBgChange(); scheduleBgChange(bgReading);
return true; return true;
} }
if (!old.isEqual(bgReading)) { if (!old.isEqual(bgReading)) {
@ -366,7 +334,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(bgReading); old.copyFrom(bgReading);
getDaoBgReadings().update(old); getDaoBgReadings().update(old);
log.debug("BG: Updating record from: " + from + " New data: " + old.toString()); log.debug("BG: Updating record from: " + from + " New data: " + old.toString());
scheduleBgChange(); scheduleBgChange(bgReading);
return false; return false;
} }
} catch (SQLException e) { } catch (SQLException e) {
@ -380,15 +348,15 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try { try {
getDaoBgReadings().update(bgReading); getDaoBgReadings().update(bgReading);
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); log.error("Unhandled exception", e);
} }
} }
private static void scheduleBgChange() { private static void scheduleBgChange(@Nullable final BgReading bgReading) {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
log.debug("Firing EventNewBg"); log.debug("Firing EventNewBg");
MainApp.bus().post(new EventNewBG()); MainApp.bus().post(new EventNewBG(bgReading));
scheduledBgPost = null; scheduledBgPost = null;
} }
} }
@ -403,8 +371,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
/* /*
* Return last BgReading from database or null if db is empty * Return last BgReading from database or null if db is empty
*/ */
@Nullable @Nullable
public static BgReading lastBg() { public static BgReading lastBg() {
List<BgReading> bgList = null; List<BgReading> bgList = null;
@ -428,9 +396,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
/* /*
* Return bg reading if not old ( <9 min ) * Return bg reading if not old ( <9 min )
* or null if older * or null if older
*/ */
@Nullable @Nullable
public static BgReading actualBg() { public static BgReading actualBg() {
BgReading lastBg = lastBg(); BgReading lastBg = lastBg();
@ -479,6 +447,33 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<BgReading>(); return new ArrayList<BgReading>();
} }
// ------------------- TDD handling -----------------------
public void createOrUpdateTDD(TDD tdd) {
try {
Dao<TDD, String> dao = getDaoTDD();
dao.createOrUpdate(tdd);
} catch (SQLException e) {
ToastUtils.showToastInUiThread(MainApp.instance(), "createOrUpdate-Exception");
log.error("Unhandled exception", e);
}
}
public List<TDD> getTDDs() {
List<TDD> tddList;
try {
QueryBuilder<TDD, String> queryBuilder = getDaoTDD().queryBuilder();
queryBuilder.orderBy("date", false);
queryBuilder.limit(10L);
PreparedQuery<TDD> preparedQuery = queryBuilder.prepare();
tddList = getDaoTDD().query(preparedQuery);
} catch (SQLException e) {
log.error("Unhandled exception", e);
tddList = new ArrayList<>();
}
return tddList;
}
// ------------- DbRequests handling ------------------- // ------------- DbRequests handling -------------------
public void create(DbRequest dbr) { public void create(DbRequest dbr) {
@ -515,7 +510,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
queryBuilder.limit(10L); queryBuilder.limit(10L);
PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare(); PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare();
List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery); List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery);
log.error("deleteDbRequestbyMongoId query size: " + dbList.size());
for (DbRequest r : dbList) { for (DbRequest r : dbList) {
delete(r); delete(r);
} }
@ -543,146 +537,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// -------------------- TREATMENT HANDLING ------------------- // -------------------- TREATMENT HANDLING -------------------
// return true if new record is created public static void updateEarliestDataChange(long newDate) {
public boolean createOrUpdate(Treatment treatment) {
try {
Treatment old;
treatment.date = roundDateToSec(treatment.date);
if (treatment.source == Source.PUMP) {
// check for changed from pump change in NS
QueryBuilder<Treatment, Long> queryBuilder = getDaoTreatments().queryBuilder();
Where where = queryBuilder.where();
where.eq("pumpId", treatment.pumpId);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = getDaoTreatments().query(preparedQuery);
if (trList.size() > 0) {
// do nothing, pump history record cannot be changed
return false;
}
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
if (treatment.source == Source.NIGHTSCOUT) {
old = getDaoTreatments().queryForId(treatment.date);
if (old != null) {
if (!old.isEqual(treatment)) {
boolean historyChange = old.isDataChanging(treatment);
long oldDate = old.date;
getDaoTreatments().delete(old); // need to delete/create because date may change too
old.copyFrom(treatment);
getDaoTreatments().create(old);
log.debug("TREATMENT: Updating record by date from: " + Source.getString(treatment.source) + " " + old.toString());
if (historyChange) {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
}
scheduleTreatmentChange();
return true;
}
return false;
}
// find by NS _id
if (treatment._id != null) {
QueryBuilder<Treatment, Long> queryBuilder = getDaoTreatments().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", treatment._id);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = getDaoTreatments().query(preparedQuery);
if (trList.size() > 0) {
old = trList.get(0);
if (!old.isEqual(treatment)) {
boolean historyChange = old.isDataChanging(treatment);
long oldDate = old.date;
getDaoTreatments().delete(old); // need to delete/create because date may change too
old.copyFrom(treatment);
getDaoTreatments().create(old);
log.debug("TREATMENT: Updating record by _id from: " + Source.getString(treatment.source) + " " + old.toString());
if (historyChange) {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
}
scheduleTreatmentChange();
return true;
}
}
}
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
if (treatment.source == Source.USER) {
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return false;
}
public void delete(Treatment treatment) {
try {
getDaoTreatments().delete(treatment);
updateEarliestDataChange(treatment.date);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleTreatmentChange();
}
public void update(Treatment treatment) {
try {
getDaoTreatments().update(treatment);
updateEarliestDataChange(treatment.date);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleTreatmentChange();
}
public void deleteTreatmentById(String _id) {
Treatment stored = findTreatmentById(_id);
if (stored != null) {
log.debug("TREATMENT: Removing Treatment record from database: " + stored.toString());
delete(stored);
updateEarliestDataChange(stored.date);
scheduleTreatmentChange();
}
}
@Nullable
public Treatment findTreatmentById(String _id) {
try {
Dao<Treatment, Long> daoTreatments = getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
queryBuilder.limit(10L);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
//log.debug("Treatment findTreatmentById query size: " + trList.size());
return null;
} else {
//log.debug("Treatment findTreatmentById found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
private void updateEarliestDataChange(long newDate) {
if (earliestDataChange == null) { if (earliestDataChange == null) {
earliestDataChange = newDate; earliestDataChange = newDate;
return; return;
@ -692,73 +547,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
private static void scheduleTreatmentChange() {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventTreatmentChange");
MainApp.bus().post(new EventReloadTreatmentData(new EventTreatmentChange()));
if (earliestDataChange != null)
MainApp.bus().post(new EventNewHistoryData(earliestDataChange));
earliestDataChange = null;
scheduledTratmentPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledTratmentPost != null)
scheduledTratmentPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledTratmentPost = treatmentsWorker.schedule(task, sec, TimeUnit.SECONDS);
}
public List<Treatment> getTreatmentDataFromTime(long mills, boolean ascending) {
try {
Dao<Treatment, Long> daoTreatments = getDaoTreatments();
List<Treatment> treatments;
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
treatments = daoTreatments.query(preparedQuery);
return treatments;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<Treatment>();
}
public void createTreatmentFromJsonIfNotExists(JSONObject trJson) {
try {
Treatment treatment = new Treatment();
treatment.source = Source.NIGHTSCOUT;
treatment.date = roundDateToSec(trJson.getLong("mills"));
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
treatment.pumpId = trJson.has("pumpId") ? trJson.getLong("pumpId") : 0;
treatment._id = trJson.getString("_id");
if (trJson.has("isSMB"))
treatment.isSMB = trJson.getBoolean("isSMB");
if (trJson.has("eventType")) {
treatment.mealBolus = !trJson.get("eventType").equals("Correction Bolus");
double carbs = treatment.carbs;
if (trJson.has("boluscalc")) {
JSONObject boluscalc = trJson.getJSONObject("boluscalc");
if (boluscalc.has("carbs")) {
carbs = Math.max(boluscalc.getDouble("carbs"), carbs);
}
}
if (carbs <= 0)
treatment.mealBolus = false;
}
createOrUpdate(treatment);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
// ---------------- TempTargets handling --------------- // ---------------- TempTargets handling ---------------
public List<TempTarget> getTemptargetsDataFromTime(long mills, boolean ascending) { public List<TempTarget> getTemptargetsDataFromTime(long mills, boolean ascending) {
@ -876,15 +664,15 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createTemptargetFromJsonIfNotExists(JSONObject trJson) { public void createTemptargetFromJsonIfNotExists(JSONObject trJson) {
try { try {
String units = MainApp.getConfigBuilder().getProfileUnits(); String units = JsonHelper.safeGetString(trJson, "units", MainApp.getConfigBuilder().getProfileUnits());
TempTarget tempTarget = new TempTarget(); TempTarget tempTarget = new TempTarget()
tempTarget.date = trJson.getLong("mills"); .date(trJson.getLong("mills"))
tempTarget.durationInMinutes = trJson.getInt("duration"); .duration(trJson.getInt("duration"))
tempTarget.low = Profile.toMgdl(trJson.getDouble("targetBottom"), units); .low(Profile.toMgdl(trJson.getDouble("targetBottom"), units))
tempTarget.high = Profile.toMgdl(trJson.getDouble("targetTop"), units); .high(Profile.toMgdl(trJson.getDouble("targetTop"), units))
tempTarget.reason = trJson.getString("reason"); .reason(trJson.getString("reason"))
tempTarget._id = trJson.getString("_id"); ._id(trJson.getString("_id"))
tempTarget.source = Source.NIGHTSCOUT; .source(Source.NIGHTSCOUT);
createOrUpdate(tempTarget); createOrUpdate(tempTarget);
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -924,6 +712,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createOrUpdate(DanaRHistoryRecord record) { public void createOrUpdate(DanaRHistoryRecord record) {
try { try {
getDaoDanaRHistory().createOrUpdate(record); getDaoDanaRHistory().createOrUpdate(record);
//If it is a TDD, store it for stats also.
if (record.recordCode == RecordTypes.RECORD_TYPE_DAILY) {
createOrUpdateTDD(new TDD(record.recordDate, record.recordDailyBolus, record.recordDailyBasal, 0));
}
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
@ -1153,10 +947,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
createOrUpdate(extendedBolus); createOrUpdate(extendedBolus);
} else { } else {
TemporaryBasal tempBasal = new TemporaryBasal(); TemporaryBasal tempBasal = new TemporaryBasal()
tempBasal.date = trJson.getLong("mills"); .date(trJson.getLong("mills"))
tempBasal.source = Source.NIGHTSCOUT; .source(Source.NIGHTSCOUT)
tempBasal.pumpId = trJson.has("pumpId") ? trJson.getLong("pumpId") : 0; .pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0);
if (trJson.has("duration")) { if (trJson.has("duration")) {
tempBasal.durationInMinutes = trJson.getInt("duration"); tempBasal.durationInMinutes = trJson.getInt("duration");
} }
@ -1360,37 +1154,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
*/ */
public void createExtendedBolusFromJsonIfNotExists(JSONObject trJson) { public void createExtendedBolusFromJsonIfNotExists(JSONObject json) {
try { ExtendedBolus extendedBolus = ExtendedBolus.createFromJson(json);
QueryBuilder<ExtendedBolus, Long> queryBuilder = null; if (extendedBolus != null)
queryBuilder = getDaoExtendedBolus().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills"));
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
List<ExtendedBolus> list = getDaoExtendedBolus().query(preparedQuery);
ExtendedBolus extendedBolus;
if (list.size() == 0) {
extendedBolus = new ExtendedBolus();
extendedBolus.source = Source.NIGHTSCOUT;
if (Config.logIncommingData)
log.debug("Adding ExtendedBolus record to database: " + trJson.toString());
// Record does not exists. add
} else if (list.size() == 1) {
extendedBolus = list.get(0);
if (Config.logIncommingData)
log.debug("Updating ExtendedBolus record in database: " + trJson.toString());
} else {
log.error("Something went wrong");
return;
}
extendedBolus.date = trJson.getLong("mills");
extendedBolus.durationInMinutes = trJson.has("duration") ? trJson.getInt("duration") : 0;
extendedBolus.insulin = trJson.getDouble("relative");
extendedBolus._id = trJson.getString("_id");
createOrUpdate(extendedBolus); createOrUpdate(extendedBolus);
} catch (SQLException | JSONException e) {
log.error("Unhandled exception", e);
}
} }
private static void scheduleExtendedBolusChange() { private static void scheduleExtendedBolusChange() {
@ -1436,6 +1203,15 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
scheduleCareportalEventChange(); scheduleCareportalEventChange();
} }
public CareportalEvent getCareportalEventFromTimestamp(long timestamp) {
try {
return getDaoCareportalEvents().queryForId(timestamp);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
@Nullable @Nullable
public CareportalEvent getLastCareportalEvent(String event) { public CareportalEvent getLastCareportalEvent(String event) {
try { try {
@ -1489,7 +1265,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void deleteCareportalEventById(String _id) { public void deleteCareportalEventById(String _id) {
try { try {
QueryBuilder<CareportalEvent, Long> queryBuilder = null; QueryBuilder<CareportalEvent, Long> queryBuilder;
queryBuilder = getDaoCareportalEvents().queryBuilder(); queryBuilder = getDaoCareportalEvents().queryBuilder();
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.eq("_id", _id); where.eq("_id", _id);
@ -1512,7 +1288,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createCareportalEventFromJsonIfNotExists(JSONObject trJson) { public void createCareportalEventFromJsonIfNotExists(JSONObject trJson) {
try { try {
QueryBuilder<CareportalEvent, Long> queryBuilder = null; QueryBuilder<CareportalEvent, Long> queryBuilder;
queryBuilder = getDaoCareportalEvents().queryBuilder(); queryBuilder = getDaoCareportalEvents().queryBuilder();
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills")); where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills"));
@ -1569,14 +1345,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
List<ProfileSwitch> profileSwitches; List<ProfileSwitch> profileSwitches;
QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder(); QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
queryBuilder.limit(20L); queryBuilder.limit(100L);
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare(); PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
profileSwitches = daoProfileSwitch.query(preparedQuery); profileSwitches = daoProfileSwitch.query(preparedQuery);
return profileSwitches; return profileSwitches;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
return new ArrayList<ProfileSwitch>(); return new ArrayList<>();
} }
public boolean createOrUpdate(ProfileSwitch profileSwitch) { public boolean createOrUpdate(ProfileSwitch profileSwitch) {
@ -1693,7 +1469,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (trJson.has("profileJson")) if (trJson.has("profileJson"))
profileSwitch.profileJson = trJson.getString("profileJson"); profileSwitch.profileJson = trJson.getString("profileJson");
else { else {
ProfileStore store = ConfigBuilderPlugin.getActiveProfileInterface().getProfile(); ProfileStore store = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile();
Profile profile = store.getSpecificProfile(profileSwitch.profileName); Profile profile = store.getSpecificProfile(profileSwitch.profileName);
if (profile != null) { if (profile != null) {
profileSwitch.profileJson = profile.getData().toString(); profileSwitch.profileJson = profile.getData().toString();
@ -1742,4 +1518,4 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
// ---------------- Food handling --------------- // ---------------- Food handling ---------------
} }

View file

@ -9,24 +9,25 @@ import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects; import java.util.Objects;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
/** /**
@ -91,6 +92,16 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
pumpId = t.pumpId; pumpId = t.pumpId;
} }
public static ExtendedBolus createFromJson(JSONObject json) {
ExtendedBolus extendedBolus = new ExtendedBolus();
extendedBolus.source = Source.NIGHTSCOUT;
extendedBolus.date = JsonHelper.safeGetLong(json, "mills");
extendedBolus.durationInMinutes = JsonHelper.safeGetInt(json, "duration");
extendedBolus.insulin = JsonHelper.safeGetDouble(json, "relative") / 60 * extendedBolus.durationInMinutes;
extendedBolus._id = JsonHelper.safeGetString(json, "_id");
extendedBolus.pumpId = JsonHelper.safeGetLong(json, "pumpId");
return extendedBolus;
}
// -------- Interval interface --------- // -------- Interval interface ---------
Long cuttedEnd = null; Long cuttedEnd = null;
@ -285,4 +296,9 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
public int getColor() { public int getColor() {
return Color.CYAN; return Color.CYAN;
} }
@Override
public int getSecondColor() {
return 0;
}
} }

View file

@ -1,208 +0,0 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.android.AndroidConnectionSource;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.j256.ormlite.table.TableUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
/**
* Created by mike on 24.09.2017.
*/
public class FoodHelper {
private static Logger log = LoggerFactory.getLogger(FoodHelper.class);
DatabaseHelper databaseHelper;
private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledFoodEventPost = null;
public FoodHelper(DatabaseHelper databaseHelper) {
this.databaseHelper = databaseHelper;
}
private Dao<Food, Long> getDaoFood() throws SQLException {
return databaseHelper.getDao(Food.class);
}
public void resetFood() {
try {
TableUtils.dropTable(databaseHelper.getConnectionSource(), Food.class, true);
TableUtils.createTableIfNotExists(databaseHelper.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleFoodChange();
}
public List<Food> getFoodData() {
try {
Dao<Food, Long> daoFood = getDaoFood();
List<Food> foods;
QueryBuilder<Food, Long> queryBuilder = daoFood.queryBuilder();
PreparedQuery<Food> preparedQuery = queryBuilder.prepare();
foods = daoFood.query(preparedQuery);
return foods;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public boolean createOrUpdate(Food food) {
try {
// find by NS _id
if (food._id != null && !food._id.equals("")) {
Food old;
QueryBuilder<Food, Long> queryBuilder = getDaoFood().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", food._id);
PreparedQuery<Food> preparedQuery = queryBuilder.prepare();
List<Food> found = getDaoFood().query(preparedQuery);
if (found.size() > 0) {
old = found.get(0);
if (!old.isEqual(food)) {
getDaoFood().delete(old); // need to delete/create because date may change too
old.copyFrom(food);
getDaoFood().create(old);
log.debug("FOOD: Updating record by _id: " + old.toString());
scheduleFoodChange();
return true;
} else {
return false;
}
} else {
getDaoFood().createOrUpdate(food);
log.debug("FOOD: New record: " + food.toString());
scheduleFoodChange();
return true;
}
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return false;
}
public void delete(Food food) {
try {
getDaoFood().delete(food);
scheduleFoodChange();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
public static void scheduleFoodChange() {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventFoodChange");
MainApp.bus().post(new EventFoodDatabaseChanged());
scheduledFoodEventPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledFoodEventPost != null)
scheduledFoodEventPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledFoodEventPost = foodEventWorker.schedule(task, sec, TimeUnit.SECONDS);
}
/*
{
"_id": "551ee3ad368e06e80856e6a9",
"type": "food",
"category": "Zakladni",
"subcategory": "Napoje",
"name": "Mleko",
"portion": 250,
"carbs": 12,
"gi": 1,
"created_at": "2015-04-14T06:59:16.500Z",
"unit": "ml"
}
*/
public void createFoodFromJsonIfNotExists(JSONObject trJson) {
try {
Food food = new Food();
if (trJson.has("type") && trJson.getString("type").equals("food")) {
if (trJson.has("_id"))
food._id = trJson.getString("_id");
if (trJson.has("category"))
food.category = trJson.getString("category");
if (trJson.has("subcategory"))
food.subcategory = trJson.getString("subcategory");
if (trJson.has("name"))
food.name = trJson.getString("name");
if (trJson.has("unit"))
food.units = trJson.getString("unit");
if (trJson.has("portion"))
food.portion = trJson.getDouble("portion");
if (trJson.has("carbs"))
food.carbs = trJson.getInt("carbs");
if (trJson.has("gi"))
food.gi = trJson.getInt("gi");
if (trJson.has("energy"))
food.energy = trJson.getInt("energy");
if (trJson.has("protein"))
food.protein = trJson.getInt("protein");
if (trJson.has("fat"))
food.fat = trJson.getInt("fat");
}
createOrUpdate(food);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
public void deleteFoodById(String _id) {
Food stored = findFoodById(_id);
if (stored != null) {
log.debug("FOOD: Removing Food record from database: " + stored.toString());
delete(stored);
scheduleFoodChange();
}
}
public Food findFoodById(String _id) {
try {
QueryBuilder<Food, Long> queryBuilder = getDaoFood().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
PreparedQuery<Food> preparedQuery = queryBuilder.prepare();
List<Food> list = getDaoFood().query(preparedQuery);
if (list.size() == 1) {
return list.get(0);
} else {
return null;
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.db;
import java.util.concurrent.ScheduledFuture;
/**
* Created by triplem on 05.01.18.
*/
public interface ICallback {
void setPost(ScheduledFuture<?> post);
ScheduledFuture<?> getPost();
}

View file

@ -61,6 +61,31 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
private Profile profile = null; private Profile profile = null;
public ProfileSwitch date(long date) {
this.date = date;
return this;
}
public ProfileSwitch profileName(String profileName) {
this.profileName = profileName;
return this;
}
public ProfileSwitch profile(Profile profile) {
this.profile = profile;
return this;
}
public ProfileSwitch source(int source) {
this.source = source;
return this;
}
public ProfileSwitch duration(int duration) {
this.durationInMinutes = duration;
return this;
}
@Nullable @Nullable
public Profile getProfileObject() { public Profile getProfileObject() {
if (profile == null) if (profile == null)
@ -238,6 +263,11 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
return Color.CYAN; return Color.CYAN;
} }
@Override
public int getSecondColor() {
return 0;
}
public String toString() { public String toString() {
return "ProfileSwitch{" + return "ProfileSwitch{" +
"date=" + date + "date=" + date +

View file

@ -0,0 +1,46 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
/**
* Created by mike on 20.09.2017.
*/
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TDDS)
public class TDD {
private static Logger log = LoggerFactory.getLogger(TDD.class);
@DatabaseField(id = true)
public long date;
@DatabaseField
public double bolus;
@DatabaseField
public double basal;
@DatabaseField
public double total;
public double getTotal(){
return (total > 0d) ? total:(bolus+basal);
}
public TDD() { }
public TDD(long date, double bolus, double basal, double total){
this.date = date;
this.bolus = bolus;
this.basal = basal;
this.total = total;
}
}

View file

@ -41,6 +41,10 @@ public class TempTarget implements Interval {
@DatabaseField @DatabaseField
public int durationInMinutes; public int durationInMinutes;
public double target() {
return (low + high) / 2;
}
public boolean isEqual(TempTarget other) { public boolean isEqual(TempTarget other) {
if (date != other.date) { if (date != other.date) {
return false; return false;
@ -67,6 +71,41 @@ public class TempTarget implements Interval {
reason = t.reason; reason = t.reason;
} }
public TempTarget date(long date) {
this.date = date;
return this;
}
public TempTarget low(double low) {
this.low = low;
return this;
}
public TempTarget high(double high) {
this.high = high;
return this;
}
public TempTarget duration(int duration) {
this.durationInMinutes = duration;
return this;
}
public TempTarget reason(String reason) {
this.reason = reason;
return this;
}
public TempTarget _id(String _id) {
this._id = _id;
return this;
}
public TempTarget source(int source) {
this.source = source;
return this;
}
// -------- Interval interface --------- // -------- Interval interface ---------
Long cuttedEnd = null; Long cuttedEnd = null;

View file

@ -6,7 +6,6 @@ import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects; import java.util.Objects;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -17,6 +16,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -60,8 +60,36 @@ public class TemporaryBasal implements Interval {
public TemporaryBasal() { public TemporaryBasal() {
} }
public TemporaryBasal(long date) { public TemporaryBasal date(long date) {
this.date = date; this.date = date;
return this;
}
public TemporaryBasal duration(int durationInMinutes) {
this.durationInMinutes = durationInMinutes;
return this;
}
public TemporaryBasal absolute(double absoluteRate) {
this.absoluteRate = absoluteRate;
this.isAbsolute = true;
return this;
}
public TemporaryBasal percent(int percentRate) {
this.percentRate = percentRate;
this.isAbsolute = false;
return this;
}
public TemporaryBasal source(int source) {
this.source = source;
return this;
}
public TemporaryBasal pumpId(long pumpId) {
this.pumpId = pumpId;
return this;
} }
public TemporaryBasal(ExtendedBolus extendedBolus) { public TemporaryBasal(ExtendedBolus extendedBolus) {
@ -189,7 +217,7 @@ public class TemporaryBasal implements Interval {
// -------- Interval interface end --------- // -------- Interval interface end ---------
public IobTotal iobCalc(long time) { public IobTotal iobCalc(long time, Profile profile) {
if(isFakeExtended){ if(isFakeExtended){
log.error("iobCalc should only be called on Extended boluses separately"); log.error("iobCalc should only be called on Extended boluses separately");
@ -197,7 +225,6 @@ public class TemporaryBasal implements Interval {
} }
IobTotal result = new IobTotal(time); IobTotal result = new IobTotal(time);
Profile profile = MainApp.getConfigBuilder().getProfile(time);
InsulinInterface insulinInterface = ConfigBuilderPlugin.getActiveInsulin(); InsulinInterface insulinInterface = ConfigBuilderPlugin.getActiveInsulin();
int realDuration = getDurationToTime(time); int realDuration = getDurationToTime(time);
@ -262,13 +289,13 @@ public class TemporaryBasal implements Interval {
return (remainingMin < 0) ? 0 : Math.round(remainingMin); return (remainingMin < 0) ? 0 : Math.round(remainingMin);
} }
public double tempBasalConvertedToAbsolute(long time) { public double tempBasalConvertedToAbsolute(long time, Profile profile) {
if(isFakeExtended){ if(isFakeExtended){
return MainApp.getConfigBuilder().getProfile(time).getBasal(time) + netExtendedRate; return profile.getBasal(time) + netExtendedRate;
} else if (isAbsolute) { } else if (isAbsolute) {
return absoluteRate; return absoluteRate;
} else { } else {
return MainApp.getConfigBuilder().getProfile(time).getBasal(time) * percentRate / 100; return profile.getBasal(time) * percentRate / 100;
} }
} }
@ -325,13 +352,13 @@ public class TemporaryBasal implements Interval {
if(profile != null) { if(profile != null) {
double basal = profile.getBasal(); double basal = profile.getBasal();
if(basal != 0){ if(basal != 0){
return Math.round(rate*100d/basal) + "% "; return Math.round(rate*100d/basal) + "%";
} }
} }
} }
return DecimalFormatter.to2Decimal(rate) + "U/h "; return DecimalFormatter.to2Decimal(rate) + "U/h";
} else { // percent } else { // percent
return percentRate + "% "; return percentRate + "%";
} }
} }

View file

@ -0,0 +1,8 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 13.02.2018.
*/
public class EventCustomCalculationFinished extends Event {
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.events;
/**
* Created by jamorham on 07/02/2018.
*
* Event to indicate that an app feature is being used, for example bolus wizard being opened
*
* The purpose this has been created for is to enable opportunistic connection to the pump
* so that it is already connected before the user wishes to enact a pump function
*
*/
public class EventFeatureRunning extends Event {
private Feature feature = Feature.UNKNOWN;
public EventFeatureRunning() {
}
public EventFeatureRunning(Feature feature) {
this.feature = feature;
}
public Feature getFeature() {
return feature;
}
public enum Feature {
UNKNOWN,
MAIN,
WIZARD,
JUST_ADD_MORE_HERE
}
}

View file

@ -0,0 +1,10 @@
package info.nightscout.androidaps.events;
public class EventNetworkChange extends Event {
public boolean mobileConnected = false;
public boolean wifiConnected = false;
public String ssid;
public boolean roaming = false;
}

View file

@ -1,7 +1,17 @@
package info.nightscout.androidaps.events; package info.nightscout.androidaps.events;
import android.support.annotation.Nullable;
import info.nightscout.androidaps.db.BgReading;
/** /**
* Created by mike on 05.06.2016. * Created by mike on 05.06.2016.
*/ */
public class EventNewBG extends EventLoop { public class EventNewBG extends EventLoop {
@Nullable
public final BgReading bgReading;
public EventNewBG(BgReading bgReading) {
this.bgReading = bgReading;
}
} }

View file

@ -0,0 +1,35 @@
package info.nightscout.androidaps.events;
import android.os.Bundle;
/**
* Event which is published with data fetched from NightScout specific for the
* Food-class.
*
* Payload is the from NS retrieved JSON-String which should be handled by all
* subscriber.
*/
public class EventNsFood extends Event {
public static final int ADD = 0;
public static final int UPDATE = 1;
public static final int REMOVE = 2;
private final int mode;
private final Bundle payload;
public EventNsFood(int mode, Bundle payload) {
this.mode = mode;
this.payload = payload;
}
public int getMode() {
return mode;
}
public Bundle getPayload() {
return payload;
}
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.events;
import org.json.JSONObject;
/**
* Event which is published with data fetched from NightScout specific for the
* Treatment-class.
* <p>
* Payload is the from NS retrieved JSON-String which should be handled by all
* subscriber.
*/
public class EventNsTreatment extends Event {
public static final int ADD = 0;
public static final int UPDATE = 1;
public static final int REMOVE = 2;
private final int mode;
private final JSONObject payload;
public EventNsTreatment(int mode, JSONObject payload) {
this.mode = mode;
this.payload = payload;
}
public int getMode() {
return mode;
}
public JSONObject getPayload() {
return payload;
}
}

View file

@ -1,7 +1,17 @@
package info.nightscout.androidaps.events; package info.nightscout.androidaps.events;
import android.support.annotation.Nullable;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
/** /**
* Created by mike on 04.06.2016. * Created by mike on 04.06.2016.
*/ */
public class EventTreatmentChange extends EventLoop { public class EventTreatmentChange extends EventLoop {
@Nullable
public final Treatment treatment;
public EventTreatmentChange(Treatment treatment) {
this.treatment = treatment;
}
} }

View file

@ -11,5 +11,5 @@ public interface APSInterface {
public APSResult getLastAPSResult(); public APSResult getLastAPSResult();
public Date getLastAPSRun(); public Date getLastAPSRun();
public void invoke(String initiator); public void invoke(String initiator, boolean tempBasalFallback);
} }

View file

@ -4,4 +4,5 @@ package info.nightscout.androidaps.interfaces;
* Created by mike on 20.06.2016. * Created by mike on 20.06.2016.
*/ */
public interface BgSourceInterface { public interface BgSourceInterface {
boolean advancedFilteringSupported();
} }

View file

@ -0,0 +1,117 @@
package info.nightscout.androidaps.interfaces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Created by mike on 19.03.2018.
*/
public class Constraint<T extends Comparable> {
private static Logger log = LoggerFactory.getLogger(Constraint.class);
T value;
T originalValue;
List<String> reasons = new ArrayList<>();
List<String> mostLimiting = new ArrayList<>();
public Constraint(T value) {
this.value = value;
this.originalValue = value;
}
public T value() {
return value;
}
public T originalValue() {
return originalValue;
}
public Constraint<T> set(T value) {
this.value = value;
this.originalValue = value;
return this;
}
public Constraint<T> set(T value, String reason, Object from) {
this.value = value;
addReason(reason, from);
addMostLimingReason(reason, from);
return this;
}
public Constraint<T> setIfSmaller(T value, String reason, Object from) {
if (value.compareTo(this.value) < 0) {
this.value = value;
mostLimiting.clear();
addMostLimingReason(reason, from);
}
if (value.compareTo(this.originalValue) < 0) {
addReason(reason, from);
}
return this;
}
public Constraint<T> setIfGreater(T value, String reason, Object from) {
if (value.compareTo(this.value) > 0) {
this.value = value;
mostLimiting.clear();
addMostLimingReason(reason, from);
}
if (value.compareTo(this.originalValue) > 0) {
addReason(reason, from);
}
return this;
}
public Constraint addReason(String reason, Object from) {
reasons.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason);
return this;
}
public Constraint addMostLimingReason(String reason, Object from) {
mostLimiting.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason);
return this;
}
public String getReasons() {
StringBuilder sb = new StringBuilder();
int count = 0;
for (String r : reasons) {
if (count++ != 0) sb.append("\n");
sb.append(r);
}
log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString());
return sb.toString();
}
public List<String> getReasonList() {
return reasons;
}
public String getMostLimitedReasons() {
StringBuilder sb = new StringBuilder();
int count = 0;
for (String r : mostLimiting) {
if (count++ != 0) sb.append("\n");
sb.append(r);
}
log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString());
return sb.toString();
}
public List<String> getMostLimitedReasonList() {
return mostLimiting;
}
public void copyReasons(Constraint<?> another) {
for (String s: another.getReasonList()) {
reasons.add(s);
}
}
}

View file

@ -1,30 +1,54 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.data.Profile;
/** /**
* Created by mike on 15.06.2016. * Created by mike on 15.06.2016.
*/ */
public interface ConstraintsInterface { public interface ConstraintsInterface {
boolean isLoopEnabled(); default Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
return value;
}
boolean isClosedModeEnabled(); default Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
return value;
}
boolean isAutosensModeEnabled(); default Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
return value;
}
boolean isAMAModeEnabled(); default Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
return value;
}
boolean isSMBModeEnabled(); default Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
return value;
}
Double applyBasalConstraints(Double absoluteRate); default Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
return value;
}
Integer applyBasalConstraints(Integer percentRate); default Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
return absoluteRate;
}
Double applyBolusConstraints(Double insulin); default Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
return percentRate;
}
Integer applyCarbsConstraints(Integer carbs); default Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
return insulin;
}
Double applyMaxIOBConstraints(Double maxIob); default Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
return carbs;
}
default Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
return maxIob;
};
} }

View file

@ -1,25 +1,23 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import java.util.Date;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
/** /**
* Created by mike on 17.04.2017. * Created by mike on 17.04.2017.
*/ */
public interface InsulinInterface { public interface InsulinInterface {
final int FASTACTINGINSULIN = 0; int FASTACTINGINSULIN = 0;
final int FASTACTINGINSULINPROLONGED = 1; int FASTACTINGINSULINPROLONGED = 1;
final int OREF_RAPID_ACTING = 2; int OREF_RAPID_ACTING = 2;
final int OREF_ULTRA_RAPID_ACTING = 3; int OREF_ULTRA_RAPID_ACTING = 3;
final int OREF_FREE_PEAK = 4; int OREF_FREE_PEAK = 4;
int getId(); int getId();
String getFriendlyName(); String getFriendlyName();
String getComment(); String getComment();
double getDia(); double getDia();
public Iob iobCalcForTreatment(Treatment treatment, long time, double dia); Iob iobCalcForTreatment(Treatment treatment, long time, double dia);
} }

View file

@ -1,34 +1,165 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import java.util.Date; import android.os.SystemClock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
/** /**
* Created by mike on 09.06.2016. * Created by mike on 09.06.2016.
*/ */
public interface PluginBase { public abstract class PluginBase {
int GENERAL = 1; private static Logger log = LoggerFactory.getLogger(PluginBase.class);
int TREATMENT = 2;
int SENSITIVITY = 3;
int PROFILE = 4;
int APS = 5;
int PUMP = 6;
int CONSTRAINTS = 7;
int LOOP = 8;
int BGSOURCE = 9;
int INSULIN = 10;
int LAST = 11; // keep always highest number
int getType(); public enum State {
String getFragmentClass(); NOT_INITIALIZED,
ENABLED,
DISABLED
}
String getName(); private State state = State.NOT_INITIALIZED;
String getNameShort(); private boolean isFragmentVisible = false;
boolean isEnabled(int type); public PluginDescription pluginDescription;
boolean isVisibleInTabs(int type);
boolean canBeHidden(int type);
boolean hasFragment(); // Specific plugin with more Interfaces
boolean showInList(int type); protected boolean isProfileInterfaceEnabled = false;
void setFragmentEnabled(int type, boolean fragmentEnabled);
void setFragmentVisible(int type, boolean fragmentVisible); public PluginBase(PluginDescription pluginDescription) {
int getPreferencesId(); this.pluginDescription = pluginDescription;
}
// public PluginType getType() {
// return mainType;
// }
// public String getFragmentClass() {
// return fragmentClass;
// }
public String getName() {
if (pluginDescription.pluginName == -1)
return "UKNOWN";
else
return MainApp.gs(pluginDescription.pluginName);
}
public String getNameShort() {
if (pluginDescription.shortName == -1)
return getName();
String name = MainApp.gs(pluginDescription.shortName);
if (!name.trim().isEmpty()) //only if translation exists
return name;
// use long name as fallback
return getName();
}
public PluginType getType() {
return pluginDescription.mainType;
}
public int getPreferencesId() {
return pluginDescription.preferencesId;
}
public int getAdvancedPreferencesId() {
return pluginDescription.advancedPreferencesId;
}
public boolean isEnabled(PluginType type) {
if (pluginDescription.alwaysEnabled && type == pluginDescription.mainType)
return true;
if (pluginDescription.mainType == PluginType.CONSTRAINTS && type == PluginType.CONSTRAINTS)
return true;
if (type == pluginDescription.mainType)
return state == State.ENABLED && specialEnableCondition();
if (type == PluginType.CONSTRAINTS && pluginDescription.mainType == PluginType.PUMP && isEnabled(PluginType.PUMP))
return true;
if (type == PluginType.PROFILE && pluginDescription.mainType == PluginType.PUMP)
return isProfileInterfaceEnabled;
return false;
}
public boolean hasFragment() {
return pluginDescription.fragmentClass != null;
}
/**
* So far plugin can have it's main type + ConstraintInterface + ProfileInterface
* ConstraintInterface is enabled if main plugin is enabled
* ProfileInterface can be enabled only if main iterface is enable
*/
public void setPluginEnabled(PluginType type, boolean newState) {
if (type == pluginDescription.mainType) {
if (newState == true) { // enabling plugin
if (state != State.ENABLED) {
onStateChange(type, state, State.ENABLED);
state = State.ENABLED;
log.debug("Starting: " + getName());
onStart();
}
} else { // disabling plugin
if (state == State.ENABLED) {
onStateChange(type, state, State.ENABLED);
state = State.DISABLED;
onStop();
log.debug("Stopping: " + getName());
}
}
} else if (type == PluginType.PROFILE) {
isProfileInterfaceEnabled = newState;
}
}
public void setFragmentVisible(PluginType type, boolean fragmentVisible) {
if (type == pluginDescription.mainType) {
isFragmentVisible = fragmentVisible && specialEnableCondition();
}
}
public boolean isFragmentVisible() {
if (pluginDescription.alwayVisible)
return true;
if (pluginDescription.neverVisible)
return false;
return isFragmentVisible;
}
public boolean showInList(PluginType type) {
if (pluginDescription.mainType == type)
return pluginDescription.showInList && specialShowInListCondition();
if (type == PluginType.PROFILE && pluginDescription.mainType == PluginType.PUMP)
return isEnabled(PluginType.PUMP);
return false;
}
public boolean specialEnableCondition() {
return true;
}
public boolean specialShowInListCondition() {
return true;
}
protected void onStart() {
if (getType() == PluginType.PUMP) {
new Thread(() -> {
SystemClock.sleep(3000);
ConfigBuilderPlugin.getCommandQueue().readStatus("Pump driver changed.", null);
}).start();
}
}
protected void onStop() {
}
protected void onStateChange(PluginType type, State oldState, State newState) {
}
} }

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.interfaces;
public class PluginDescription {
PluginType mainType = PluginType.GENERAL;
String fragmentClass = null;
public boolean alwayVisible = false;
public boolean neverVisible = false;
public boolean alwaysEnabled = false;
boolean showInList = true;
int pluginName = -1;
int shortName = -1;
int preferencesId = -1;
int advancedPreferencesId = -1;
public boolean enableByDefault = false;
public boolean visibleByDefault = false;
public PluginDescription mainType(PluginType mainType) {
this.mainType = mainType;
return this;
}
public PluginDescription fragmentClass(String fragmentClass) {
this.fragmentClass = fragmentClass;
return this;
}
public PluginDescription alwaysEnabled(boolean alwaysEnabled) {
this.alwaysEnabled = alwaysEnabled;
return this;
}
public PluginDescription alwayVisible(boolean alwayVisible) {
this.alwayVisible = alwayVisible;
return this;
}
public PluginDescription neverVisible(boolean neverVisible) {
this.neverVisible = neverVisible;
return this;
}
public PluginDescription showInList(boolean showInList) {
this.showInList = showInList;
return this;
}
public PluginDescription pluginName(int pluginName) {
this.pluginName = pluginName;
return this;
}
public PluginDescription shortName(int shortName) {
this.shortName = shortName;
return this;
}
public PluginDescription preferencesId(int preferencesId) {
this.preferencesId = preferencesId;
return this;
}
public PluginDescription advancedPreferencesId(int advancedPreferencesId) {
this.advancedPreferencesId = advancedPreferencesId;
return this;
}
public PluginDescription enableByDefault(boolean enableByDefault) {
this.enableByDefault = enableByDefault;
return this;
}
public PluginDescription visibleByDefault(boolean visibleByDefault) {
this.visibleByDefault = visibleByDefault;
return this;
}
public String getFragmentClass() {
return fragmentClass;
}
public PluginType getType() {
return mainType;
}
}

View file

@ -0,0 +1,14 @@
package info.nightscout.androidaps.interfaces;
public enum PluginType {
GENERAL,
TREATMENT,
SENSITIVITY,
PROFILE,
APS,
PUMP,
CONSTRAINTS,
LOOP,
BGSOURCE,
INSULIN
}

View file

@ -27,6 +27,8 @@ public class PumpDescription {
public double tempAbsoluteStep = 0.05d; public double tempAbsoluteStep = 0.05d;
public int tempDurationStep = 60; public int tempDurationStep = 60;
public boolean tempDurationStep15mAllowed = false;
public boolean tempDurationStep30mAllowed = false;
public int tempMaxDuration = 12 * 60; public int tempMaxDuration = 12 * 60;
@ -38,6 +40,11 @@ public class PumpDescription {
public boolean storesCarbInfo = true; public boolean storesCarbInfo = true;
public boolean is30minBasalRatesCapable = false;
public boolean supportsTDDs = false;
public boolean needsManualTDDLoad = true;
public void resetSettings() public void resetSettings()
{ {
@ -71,6 +78,4 @@ public class PumpDescription {
storesCarbInfo = true; storesCarbInfo = true;
} }
} }

View file

@ -5,8 +5,8 @@ import org.json.JSONObject;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
/** /**
* Created by mike on 04.06.2016. * Created by mike on 04.06.2016.
@ -35,8 +35,8 @@ public interface PumpInterface {
PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo); PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo);
void stopBolusDelivering(); void stopBolusDelivering();
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew); PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew);
PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew); PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew);
PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes); PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes);
//some pumps might set a very short temp close to 100% as cancelling a temp can be noisy //some pumps might set a very short temp close to 100% as cancelling a temp can be noisy
//when the cancel request is requested by the user (forced), the pump should always do a real cancel //when the cancel request is requested by the user (forced), the pump should always do a real cancel
@ -44,7 +44,7 @@ public interface PumpInterface {
PumpEnactResult cancelExtendedBolus(); PumpEnactResult cancelExtendedBolus();
// Status to be passed to NS // Status to be passed to NS
JSONObject getJSONStatus(); JSONObject getJSONStatus(Profile profile, String profileName);
String deviceID(); String deviceID();
// Pump capabilities // Pump capabilities
@ -54,4 +54,7 @@ public interface PumpInterface {
String shortStatus(boolean veryShort); String shortStatus(boolean veryShort);
boolean isFakingTempsByExtendedBoluses(); boolean isFakingTempsByExtendedBoluses();
PumpEnactResult loadTDDs();
} }

View file

@ -5,11 +5,12 @@ import java.util.List;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.data.Intervals; import info.nightscout.androidaps.data.Intervals;
import info.nightscout.androidaps.data.ProfileIntervals; import info.nightscout.androidaps.data.ProfileIntervals;
@ -24,12 +25,13 @@ public interface TreatmentsInterface {
IobTotal getLastCalculationTreatments(); IobTotal getLastCalculationTreatments();
IobTotal getCalculationToTimeTreatments(long time); IobTotal getCalculationToTimeTreatments(long time);
IobTotal getLastCalculationTempBasals(); IobTotal getLastCalculationTempBasals();
IobTotal getCalculationToTimeTempBasals(long time); IobTotal getCalculationToTimeTempBasals(long time, Profile profile);
MealData getMealData(); MealData getMealData();
List<Treatment> getTreatmentsFromHistory(); List<Treatment> getTreatmentsFromHistory();
List<Treatment> getTreatments5MinBackFromHistory(long time); List<Treatment> getTreatments5MinBackFromHistory(long time);
long getLastBolusTime();
// real basals (not faked by extended bolus) // real basals (not faked by extended bolus)
boolean isInHistoryRealTempBasalInProgress(); boolean isInHistoryRealTempBasalInProgress();
@ -40,8 +42,6 @@ public interface TreatmentsInterface {
// basal that can be faked by extended boluses // basal that can be faked by extended boluses
boolean isTempBasalInProgress(); boolean isTempBasalInProgress();
TemporaryBasal getTempBasalFromHistory(long time); TemporaryBasal getTempBasalFromHistory(long time);
double getTempBasalAbsoluteRateHistory();
double getTempBasalRemainingMinutesFromHistory();
Intervals<TemporaryBasal> getTemporaryBasalsFromHistory(); Intervals<TemporaryBasal> getTemporaryBasalsFromHistory();
boolean isInHistoryExtendedBoluslInProgress(); boolean isInHistoryExtendedBoluslInProgress();
@ -55,6 +55,7 @@ public interface TreatmentsInterface {
TempTarget getTempTargetFromHistory(); TempTarget getTempTargetFromHistory();
TempTarget getTempTargetFromHistory(long time); TempTarget getTempTargetFromHistory(long time);
Intervals<TempTarget> getTempTargetsFromHistory(); Intervals<TempTarget> getTempTargetsFromHistory();
void addToHistoryTempTarget(TempTarget tempTarget);
ProfileSwitch getProfileSwitchFromHistory(long time); ProfileSwitch getProfileSwitchFromHistory(long time);
ProfileIntervals<ProfileSwitch> getProfileSwitchesFromHistory(); ProfileIntervals<ProfileSwitch> getProfileSwitchesFromHistory();

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.Actions;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
@ -9,14 +10,14 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.HistoryBrowseActivity;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.TDDStatsActivity;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventExtendedBolusChange;
@ -32,6 +33,8 @@ import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialo
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.SingleClickButton; import info.nightscout.utils.SingleClickButton;
/** /**
@ -52,6 +55,8 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
SingleClickButton tempBasal; SingleClickButton tempBasal;
SingleClickButton tempBasalCancel; SingleClickButton tempBasalCancel;
SingleClickButton fill; SingleClickButton fill;
SingleClickButton tddStats;
SingleClickButton history;
public ActionsFragment() { public ActionsFragment() {
super(); super();
@ -71,6 +76,8 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempBasal = (SingleClickButton) view.findViewById(R.id.actions_settempbasal); tempBasal = (SingleClickButton) view.findViewById(R.id.actions_settempbasal);
tempBasalCancel = (SingleClickButton) view.findViewById(R.id.actions_canceltempbasal); tempBasalCancel = (SingleClickButton) view.findViewById(R.id.actions_canceltempbasal);
fill = (SingleClickButton) view.findViewById(R.id.actions_fill); fill = (SingleClickButton) view.findViewById(R.id.actions_fill);
tddStats = view.findViewById(R.id.actions_tddstats);
history = view.findViewById(R.id.actions_historybrowser);
profileSwitch.setOnClickListener(this); profileSwitch.setOnClickListener(this);
tempTarget.setOnClickListener(this); tempTarget.setOnClickListener(this);
@ -79,11 +86,13 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempBasal.setOnClickListener(this); tempBasal.setOnClickListener(this);
tempBasalCancel.setOnClickListener(this); tempBasalCancel.setOnClickListener(this);
fill.setOnClickListener(this); fill.setOnClickListener(this);
history.setOnClickListener(this);
tddStats.setOnClickListener(this);
updateGUI(); updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
@ -116,9 +125,14 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (MainApp.getConfigBuilder().getActiveProfileInterface().getProfile() == null) { if (MainApp.getConfigBuilder().getActiveProfileInterface().getProfile() != null) {
tempTarget.setVisibility(View.GONE); profileSwitch.setVisibility(View.VISIBLE);
} else {
profileSwitch.setVisibility(View.GONE); profileSwitch.setVisibility(View.GONE);
}
if (MainApp.getConfigBuilder().getProfile() == null) {
tempTarget.setVisibility(View.GONE);
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);
tempBasal.setVisibility(View.GONE); tempBasal.setVisibility(View.GONE);
@ -126,22 +140,25 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
fill.setVisibility(View.GONE); fill.setVisibility(View.GONE);
return; return;
} }
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (!pump.getPumpDescription().isSetBasalProfileCapable || !pump.isInitialized() || pump.isSuspended()) final boolean basalprofileEnabled = MainApp.isEngineeringModeOrRelease()
&& pump.getPumpDescription().isSetBasalProfileCapable;
if (!basalprofileEnabled || !pump.isInitialized() || pump.isSuspended())
profileSwitch.setVisibility(View.GONE); profileSwitch.setVisibility(View.GONE);
else else
profileSwitch.setVisibility(View.VISIBLE); profileSwitch.setVisibility(View.VISIBLE);
if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) { if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) {
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);
} else { } else {
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) { ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis());
if (activeExtendedBolus != null) {
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.VISIBLE); extendedBolusCancel.setVisibility(View.VISIBLE);
ExtendedBolus running = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()); extendedBolusCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + activeExtendedBolus.toString());
extendedBolusCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + running.toString());
} else { } else {
extendedBolus.setVisibility(View.VISIBLE); extendedBolus.setVisibility(View.VISIBLE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);
@ -153,10 +170,10 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempBasal.setVisibility(View.GONE); tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.GONE); tempBasalCancel.setVisibility(View.GONE);
} else { } else {
if (MainApp.getConfigBuilder().isTempBasalInProgress()) { final TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis());
if (activeTemp != null) {
tempBasal.setVisibility(View.GONE); tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.VISIBLE); tempBasalCancel.setVisibility(View.VISIBLE);
final TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
tempBasalCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + activeTemp.toStringShort()); tempBasalCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + activeTemp.toStringShort());
} else { } else {
tempBasal.setVisibility(View.VISIBLE); tempBasal.setVisibility(View.VISIBLE);
@ -173,6 +190,9 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempTarget.setVisibility(View.GONE); tempTarget.setVisibility(View.GONE);
else else
tempTarget.setVisibility(View.VISIBLE); tempTarget.setVisibility(View.VISIBLE);
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().supportsTDDs) tddStats.setVisibility(View.GONE);
else tddStats.setVisibility(View.VISIBLE);
} }
}); });
} }
@ -201,15 +221,15 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
newExtendedDialog.show(manager, "NewExtendedDialog"); newExtendedDialog.show(manager, "NewExtendedDialog");
break; break;
case R.id.actions_extendedbolus_cancel: case R.id.actions_extendedbolus_cancel:
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) { if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
ConfigBuilderPlugin.getCommandQueue().cancelExtended(null); ConfigBuilderPlugin.getCommandQueue().cancelExtended(null);
Answers.getInstance().logCustom(new CustomEvent("CancelExtended")); FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelExtended"));
} }
break; break;
case R.id.actions_canceltempbasal: case R.id.actions_canceltempbasal:
if (MainApp.getConfigBuilder().isTempBasalInProgress()) { if (TreatmentsPlugin.getPlugin().isTempBasalInProgress()) {
ConfigBuilderPlugin.getCommandQueue().cancelTempBasal(true, null); ConfigBuilderPlugin.getCommandQueue().cancelTempBasal(true, null);
Answers.getInstance().logCustom(new CustomEvent("CancelTemp")); FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelTemp"));
} }
break; break;
case R.id.actions_settempbasal: case R.id.actions_settempbasal:
@ -220,6 +240,12 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
FillDialog fillDialog = new FillDialog(); FillDialog fillDialog = new FillDialog();
fillDialog.show(manager, "FillDialog"); fillDialog.show(manager, "FillDialog");
break; break;
case R.id.actions_historybrowser:
startActivity(new Intent(getContext(), HistoryBrowseActivity.class));
break;
case R.id.actions_tddstats:
startActivity(new Intent(getContext(), TDDStatsActivity.class));
break;
} }
} }
} }

View file

@ -1,82 +1,22 @@
package info.nightscout.androidaps.plugins.Actions; package info.nightscout.androidaps.plugins.Actions;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
/** /**
* Created by mike on 05.11.2016. * Created by mike on 05.11.2016.
*/ */
public class ActionsPlugin implements PluginBase { public class ActionsPlugin extends PluginBase {
private boolean fragmentEnabled = true; public ActionsPlugin() {
private boolean fragmentVisible = true; super(new PluginDescription()
.mainType(PluginType.GENERAL)
@Override .fragmentClass(ActionsFragment.class.getName())
public int getType() { .pluginName(R.string.actions)
return PluginBase.GENERAL; .shortName(R.string.actions_shortname)
);
} }
@Override
public String getFragmentClass() {
return ActionsFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.actions);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.actions_shortname);
if (!name.trim().isEmpty()){
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == GENERAL && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
} }

View file

@ -1,11 +1,13 @@
package info.nightscout.androidaps.plugins.Actions.dialogs; package info.nightscout.androidaps.plugins.Actions.dialogs;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@ -13,40 +15,73 @@ import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.google.common.base.Joiner;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.text.DecimalFormat; import java.util.LinkedList;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
import info.nightscout.utils.ToastUtils;
import static info.nightscout.utils.DateUtil.now;
public class FillDialog extends DialogFragment implements OnClickListener { public class FillDialog extends DialogFragment implements OnClickListener {
private static Logger log = LoggerFactory.getLogger(FillDialog.class); private static Logger log = LoggerFactory.getLogger(FillDialog.class);
Button deliverButton; private CheckBox pumpSiteChangeCheckbox;
private CheckBox insulinCartridgeChangeCheckbox;
private NumberPicker editInsulin;
double amount1 = 0d; double amount1 = 0d;
double amount2 = 0d; double amount2 = 0d;
double amount3 = 0d; double amount3 = 0d;
NumberPicker editInsulin; private EditText notesEdit;
public FillDialog() { final private TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
validateInputs();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
private void validateInputs() {
int time = editInsulin.getValue().intValue();
if (Math.abs(time) > 12 * 60) {
editInsulin.setValue(0d);
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.constraintapllied));
}
} }
@Override @Override
@ -54,110 +89,122 @@ public class FillDialog extends DialogFragment implements OnClickListener {
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.actions_fill_dialog, null, false); View view = inflater.inflate(R.layout.actions_fill_dialog, null, false);
deliverButton = (Button) view.findViewById(R.id.treatments_newtreatment_deliverbutton); view.findViewById(R.id.ok).setOnClickListener(this);
view.findViewById(R.id.cancel).setOnClickListener(this);
deliverButton.setOnClickListener(this);
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); pumpSiteChangeCheckbox = view.findViewById(R.id.fill_catheter_change);
insulinCartridgeChangeCheckbox = view.findViewById(R.id.fill_cartridge_change);
Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
double bolusstep = ConfigBuilderPlugin.getActivePump().getPumpDescription().bolusStep; double bolusstep = ConfigBuilderPlugin.getActivePump().getPumpDescription().bolusStep;
editInsulin = (NumberPicker) view.findViewById(R.id.treatments_newtreatment_insulinamount); editInsulin = view.findViewById(R.id.fill_insulinamount);
editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, new DecimalFormat("0.00"), false); editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, textWatcher);
//setup preset buttons
Button button1 = (Button) view.findViewById(R.id.fill_preset_button1);
Button button2 = (Button) view.findViewById(R.id.fill_preset_button2);
Button button3 = (Button) view.findViewById(R.id.fill_preset_button3);
View divider = view.findViewById(R.id.fill_preset_divider);
Button preset1Button = view.findViewById(R.id.fill_preset_button1);
amount1 = SP.getDouble("fill_button1", 0.3); amount1 = SP.getDouble("fill_button1", 0.3);
amount2 = SP.getDouble("fill_button2", 0d);
amount3 = SP.getDouble("fill_button3", 0d);
if (amount1 > 0) { if (amount1 > 0) {
button1.setVisibility(View.VISIBLE); preset1Button.setVisibility(View.VISIBLE);
button1.setText(DecimalFormatter.to2Decimal(amount1) + "U"); preset1Button.setText(DecimalFormatter.toPumpSupportedBolus(amount1)); // + "U");
button1.setOnClickListener(this); preset1Button.setOnClickListener(this);
} else { } else {
button1.setVisibility(View.GONE); preset1Button.setVisibility(View.GONE);
} }
Button preset2Button = view.findViewById(R.id.fill_preset_button2);
amount2 = SP.getDouble("fill_button2", 0d);
if (amount2 > 0) { if (amount2 > 0) {
button2.setVisibility(View.VISIBLE); preset2Button.setVisibility(View.VISIBLE);
button2.setText(DecimalFormatter.to2Decimal(amount2) + "U"); preset2Button.setText(DecimalFormatter.toPumpSupportedBolus(amount2)); // + "U");
button2.setOnClickListener(this); preset2Button.setOnClickListener(this);
} else { } else {
button2.setVisibility(View.GONE); preset2Button.setVisibility(View.GONE);
} }
Button preset3Button = view.findViewById(R.id.fill_preset_button3);
amount3 = SP.getDouble("fill_button3", 0d);
if (amount3 > 0) { if (amount3 > 0) {
button3.setVisibility(View.VISIBLE); preset3Button.setVisibility(View.VISIBLE);
button3.setText(DecimalFormatter.to2Decimal(amount3) + "U"); preset3Button.setText(DecimalFormatter.toPumpSupportedBolus(amount3)); // + "U");
button3.setOnClickListener(this); preset3Button.setOnClickListener(this);
} else { } else {
button3.setVisibility(View.GONE); preset3Button.setVisibility(View.GONE);
} }
if (button1.getVisibility() == View.GONE && button2.getVisibility() == View.GONE && button3.getVisibility() == View.GONE) { LinearLayout notesLayout = view.findViewById(R.id.fill_notes_layout);
divider.setVisibility(View.GONE); notesLayout.setVisibility(SP.getBoolean(R.string.key_show_notes_entry_dialogs, false) ? View.VISIBLE : View.GONE);
} notesEdit = view.findViewById(R.id.fill_notes);
setCancelable(true); setCancelable(true);
getDialog().setCanceledOnTouchOutside(false); getDialog().setCanceledOnTouchOutside(false);
return view; return view;
} }
@Override
public void onResume() {
super.onResume();
if (getDialog() != null)
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override @Override
public void onClick(View view) { public void onClick(View view) {
switch (view.getId()) { switch (view.getId()) {
case R.id.treatments_newtreatment_deliverbutton: case R.id.ok:
Double insulin = SafeParse.stringToDouble(editInsulin.getText().toString()); confirmAndDeliver();
confirmAndDeliver(insulin); break;
case R.id.cancel:
dismiss();
break; break;
case R.id.fill_preset_button1: case R.id.fill_preset_button1:
confirmAndDeliver(amount1); editInsulin.setValue(amount1);
break; break;
case R.id.fill_preset_button2: case R.id.fill_preset_button2:
confirmAndDeliver(amount2); editInsulin.setValue(amount2);
break; break;
case R.id.fill_preset_button3: case R.id.fill_preset_button3:
confirmAndDeliver(amount3); editInsulin.setValue(amount3);
break; break;
} }
} }
private void confirmAndDeliver(Double insulin) { private void confirmAndDeliver() {
try { try {
Double insulin = SafeParse.stringToDouble(editInsulin.getText());
String confirmMessage = getString(R.string.fillwarning) + "\n"; List<String> confirmMessage = new LinkedList<>();
Double insulinAfterConstraints = MainApp.getConfigBuilder().applyBolusConstraints(insulin); Double insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(insulin)).value();
confirmMessage += getString(R.string.bolus) + ": " + insulinAfterConstraints + "U"; if (insulinAfterConstraints > 0) {
if (insulinAfterConstraints - insulin != 0) confirmMessage.add(MainApp.gs(R.string.fillwarning));
confirmMessage += "\n" + getString(R.string.constraintapllied); confirmMessage.add("");
confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorCarbsButton) + "'>" + insulinAfterConstraints + "U" + "</font>");
if (!insulinAfterConstraints.equals(insulin))
confirmMessage.add("<font color='" + MainApp.sResources.getColor(R.color.low) + "'>" + MainApp.gs(R.string.bolusconstraintapplied) + "</font>");
}
if (pumpSiteChangeCheckbox.isChecked())
confirmMessage.add("" + "<font color='" + MainApp.sResources.getColor(R.color.high) + "'>" + getString(R.string.record_pump_site_change) + "</font>");
if (insulinCartridgeChangeCheckbox.isChecked())
confirmMessage.add("" + "<font color='" + MainApp.sResources.getColor(R.color.high) + "'>" + getString(R.string.record_insulin_cartridge_change) + "</font>");
final String notes = notesEdit.getText().toString();
if (!notes.isEmpty()) {
confirmMessage.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes);
}
final Double finalInsulinAfterConstraints = insulinAfterConstraints; final Double finalInsulinAfterConstraints = insulinAfterConstraints;
final Context context = getContext(); final Context context = getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(this.getContext().getString(R.string.confirmation)); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(confirmMessage); if (insulinAfterConstraints > 0 || pumpSiteChangeCheckbox.isChecked() || insulinCartridgeChangeCheckbox.isChecked()) {
builder.setPositiveButton(getString(R.string.primefill), new DialogInterface.OnClickListener() { builder.setMessage(Html.fromHtml(Joiner.on("<br/>").join(confirmMessage)));
public void onClick(DialogInterface dialog, int id) { builder.setPositiveButton(getString(R.string.primefill), (dialog, id) -> {
if (finalInsulinAfterConstraints > 0) { if (finalInsulinAfterConstraints > 0) {
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.insulin = finalInsulinAfterConstraints; detailedBolusInfo.insulin = finalInsulinAfterConstraints;
detailedBolusInfo.context = context; detailedBolusInfo.context = context;
detailedBolusInfo.source = Source.USER; detailedBolusInfo.source = Source.USER;
detailedBolusInfo.isValid = false; // do not count it in IOB (for pump history) detailedBolusInfo.isValid = false; // do not count it in IOB (for pump history)
detailedBolusInfo.notes = notes;
ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() { ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override @Override
public void run() { public void run() {
@ -171,10 +218,16 @@ public class FillDialog extends DialogFragment implements OnClickListener {
} }
} }
}); });
Answers.getInstance().logCustom(new CustomEvent("Fill")); FabricPrivacy.getInstance().logCustom(new CustomEvent("Fill"));
} }
} if (pumpSiteChangeCheckbox.isChecked())
}); NSUpload.uploadEvent(CareportalEvent.SITECHANGE, now(), notes);
if (insulinCartridgeChangeCheckbox.isChecked())
NSUpload.uploadEvent(CareportalEvent.INSULINCHANGE, now() + 1000, notes);
});
} else {
builder.setMessage(MainApp.gs(R.string.no_action_selected));
}
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(getString(R.string.cancel), null);
builder.show(); builder.show();
dismiss(); dismiss();

View file

@ -10,7 +10,6 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -18,12 +17,13 @@ import org.slf4j.LoggerFactory;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
@ -43,7 +43,7 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
View view = inflater.inflate(R.layout.overview_newextendedbolus_dialog, container, false); View view = inflater.inflate(R.layout.overview_newextendedbolus_dialog, container, false);
Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin); editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin);
editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false); editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false);
@ -70,7 +70,7 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
String confirmMessage = getString(R.string.setextendedbolusquestion); String confirmMessage = getString(R.string.setextendedbolusquestion);
Double insulinAfterConstraint = MainApp.getConfigBuilder().applyBolusConstraints(insulin); Double insulinAfterConstraint = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(insulin)).value();
confirmMessage += " " + insulinAfterConstraint + " U "; confirmMessage += " " + insulinAfterConstraint + " U ";
confirmMessage += getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += getString(R.string.duration) + " " + durationInMinutes + "min ?";
if (insulinAfterConstraint - insulin != 0d) if (insulinAfterConstraint - insulin != 0d)
@ -99,7 +99,7 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
} }
} }
}); });
Answers.getInstance().logCustom(new CustomEvent("ExtendedBolus")); FabricPrivacy.getInstance().logCustom(new CustomEvent("ExtendedBolus"));
} }
}); });
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(getString(R.string.cancel), null);

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.Actions.dialogs; package info.nightscout.androidaps.plugins.Actions.dialogs;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@ -13,7 +12,6 @@ import android.widget.LinearLayout;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.RadioGroup; import android.widget.RadioGroup;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -24,10 +22,12 @@ import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
@ -118,17 +118,21 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
final boolean setAsPercent = percentRadio.isChecked(); final boolean setAsPercent = percentRadio.isChecked();
int durationInMinutes = SafeParse.stringToInt(duration.getText()); int durationInMinutes = SafeParse.stringToInt(duration.getText());
Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null)
return;
String confirmMessage = getString(R.string.setbasalquestion); String confirmMessage = getString(R.string.setbasalquestion);
if (setAsPercent) { if (setAsPercent) {
int basalPercentInput = SafeParse.stringToInt(basalPercent.getText()); int basalPercentInput = SafeParse.stringToInt(basalPercent.getText());
percent = MainApp.getConfigBuilder().applyBasalConstraints(basalPercentInput); percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(basalPercentInput), profile).value();
confirmMessage += "\n" + percent + "% "; confirmMessage += "\n" + percent + "% ";
confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?";
if (percent != basalPercentInput) if (percent != basalPercentInput)
confirmMessage += "\n" + getString(R.string.constraintapllied); confirmMessage += "\n" + getString(R.string.constraintapllied);
} else { } else {
Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText()); Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText());
absolute = MainApp.getConfigBuilder().applyBasalConstraints(basalAbsoluteInput); absolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(basalAbsoluteInput), profile).value();
confirmMessage += "\n" + absolute + " U/h "; confirmMessage += "\n" + absolute + " U/h ";
confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?";
if (absolute - basalAbsoluteInput != 0d) if (absolute - basalAbsoluteInput != 0d)
@ -158,11 +162,11 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
} }
}; };
if (setAsPercent) { if (setAsPercent) {
ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, callback); ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, profile, callback);
} else { } else {
ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, callback); ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, profile, callback);
} }
Answers.getInstance().logCustom(new CustomEvent("TempBasal")); FabricPrivacy.getInstance().logCustom(new CustomEvent("TempBasal"));
} }
}); });
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(getString(R.string.cancel), null);

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.Careportal;
import android.app.Activity; import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -10,10 +11,11 @@ import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.BuildConfig; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
@ -22,10 +24,12 @@ import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment; import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.utils.FabricPrivacy;
public class CareportalFragment extends SubscriberFragment implements View.OnClickListener { public class CareportalFragment extends SubscriberFragment implements View.OnClickListener {
private static Logger log = LoggerFactory.getLogger(CareportalFragment.class);
TextView iage; TextView iage;
TextView cage; TextView cage;
@ -96,7 +100,7 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
noProfileView = view.findViewById(R.id.profileview_noprofile); noProfileView = view.findViewById(R.id.profileview_noprofile);
butonsLayout = (LinearLayout) view.findViewById(R.id.careportal_buttons); butonsLayout = (LinearLayout) view.findViewById(R.id.careportal_buttons);
ProfileStore profileStore = ConfigBuilderPlugin.getActiveProfileInterface().getProfile(); ProfileStore profileStore = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile();
if (profileStore == null) { if (profileStore == null) {
noProfileView.setVisibility(View.VISIBLE); noProfileView.setVisibility(View.VISIBLE);
butonsLayout.setVisibility(View.GONE); butonsLayout.setVisibility(View.GONE);
@ -111,7 +115,7 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
updateGUI(); updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
@ -208,26 +212,54 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
public static void updateAge(Activity activity, final TextView sage, final TextView iage, final TextView cage, final TextView pbage) { public static void updateAge(Activity activity, final TextView sage, final TextView iage, final TextView cage, final TextView pbage) {
if (activity != null) { if (activity != null) {
activity.runOnUiThread( activity.runOnUiThread(
new Runnable() { () -> {
@Override CareportalEvent careportalEvent;
public void run() { NSSettingsStatus nsSettings = new NSSettingsStatus().getInstance();
CareportalEvent careportalEvent;
String notavailable = OverviewFragment.shorttextmode ? "-" : MainApp.sResources.getString(R.string.notavailable); double iageUrgent = nsSettings.getExtendedWarnValue("iage", "urgent", 96);
if (sage != null) { double iageWarn = nsSettings.getExtendedWarnValue("iage", "warn", 72);
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SENSORCHANGE); double cageUrgent = nsSettings.getExtendedWarnValue("cage", "urgent", 72);
sage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); double cageWarn = nsSettings.getExtendedWarnValue("cage", "warn", 48);
double sageUrgent = nsSettings.getExtendedWarnValue("sage", "urgent", 166);
double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164);
double pbageUrgent = nsSettings.getExtendedWarnValue("pgage", "urgent", 360);
double pbageWarn = nsSettings.getExtendedWarnValue("pgage", "warn", 240);
String notavailable = OverviewFragment.shorttextmode ? "-" : MainApp.sResources.getString(R.string.notavailable);
if (sage != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SENSORCHANGE);
if (careportalEvent != null) {
sage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, sageWarn, sageUrgent));
sage.setText(careportalEvent.age());
} else {
sage.setText(notavailable);
} }
if (iage != null) { }
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.INSULINCHANGE); if (iage != null) {
iage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.INSULINCHANGE);
if (careportalEvent != null) {
iage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, iageWarn, iageUrgent));
iage.setText(careportalEvent.age());
} else {
iage.setText(notavailable);
} }
if (cage != null) { }
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SITECHANGE); if (cage != null) {
cage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SITECHANGE);
if (careportalEvent != null) {
cage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, cageWarn, cageUrgent));
cage.setText(careportalEvent.age());
} else {
cage.setText(notavailable);
} }
if (pbage != null) { }
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.PUMPBATTERYCHANGE); if (pbage != null) {
pbage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.PUMPBATTERYCHANGE);
if (careportalEvent != null) {
pbage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, pbageWarn, pbageUrgent));
pbage.setText(careportalEvent.age());
} else {
pbage.setText(notavailable);
} }
} }
} }
@ -235,4 +267,15 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
} }
} }
public static int determineTextColor(CareportalEvent careportalEvent, double warnThreshold, double urgentThreshold) {
if (careportalEvent.isOlderThan(urgentThreshold)) {
return MainApp.sResources.getColor(R.color.low);
} else if (careportalEvent.isOlderThan(warnThreshold)) {
return MainApp.sResources.getColor(R.color.high);
} else {
return Color.WHITE;
}
}
} }

View file

@ -1,14 +1,12 @@
package info.nightscout.androidaps.plugins.Careportal; package info.nightscout.androidaps.plugins.Careportal;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
public class CareportalPlugin implements PluginBase { public class CareportalPlugin extends PluginBase {
private boolean fragmentEnabled = true;
private boolean fragmentVisible = true;
static CareportalPlugin careportalPlugin; static CareportalPlugin careportalPlugin;
@ -19,70 +17,13 @@ public class CareportalPlugin implements PluginBase {
return careportalPlugin; return careportalPlugin;
} }
@Override public CareportalPlugin() {
public int getType() { super(new PluginDescription()
return PluginBase.GENERAL; .mainType(PluginType.GENERAL)
} .fragmentClass(CareportalFragment.class.getName())
.pluginName(R.string.careportal)
@Override .shortName(R.string.careportal_shortname)
public String getFragmentClass() { );
return CareportalFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.careportal);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.careportal_shortname);
if (!name.trim().isEmpty()){
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == GENERAL && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return !Config.NSCLIENT && !Config.G5UPLOADER;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_careportal;
} }
} }

View file

@ -2,8 +2,6 @@ package info.nightscout.androidaps.plugins.Careportal.Dialogs;
import android.app.Activity; import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
@ -16,15 +14,14 @@ import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.google.common.collect.Lists;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout; import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
@ -38,6 +35,7 @@ import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -45,16 +43,18 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.GlucoseStatus;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DefaultValueHelper;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.HardLimits;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -70,8 +70,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
private static String event; private static String event;
Profile profile; Profile profile;
ProfileStore profileStore; public ProfileStore profileStore;
String units; String units = Constants.MGDL;
TextView eventTypeText; TextView eventTypeText;
LinearLayout layoutPercent; LinearLayout layoutPercent;
@ -105,13 +105,19 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
Date eventTime; Date eventTime;
private static Integer seconds = null;
public void setOptions(OptionsToShow options, int event) { public void setOptions(OptionsToShow options, int event) {
this.options = options; this.options = options;
this.event = MainApp.sResources.getString(event); this.event = MainApp.gs(event);
} }
public NewNSTreatmentDialog() { public NewNSTreatmentDialog() {
super(); super();
if (seconds == null) {
seconds = Double.valueOf(Math.random() * 59).intValue();
}
} }
@Override @Override
@ -130,7 +136,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
if (options == null) return null; if (options == null) return null;
getDialog().setTitle(getString(options.eventName)); getDialog().setTitle(MainApp.gs(options.eventName));
setStyle(DialogFragment.STYLE_NORMAL, getTheme()); setStyle(DialogFragment.STYLE_NORMAL, getTheme());
View view = inflater.inflate(R.layout.careportal_newnstreatment_dialog, container, false); View view = inflater.inflate(R.layout.careportal_newnstreatment_dialog, container, false);
@ -166,52 +172,61 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
// profile // profile
profile = MainApp.getConfigBuilder().getProfile(); profile = MainApp.getConfigBuilder().getProfile();
profileStore = ConfigBuilderPlugin.getActiveProfileInterface().getProfile(); profileStore = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile();
ArrayList<CharSequence> profileList; if (profileStore == null) {
units = profile != null ? profile.getUnits() : Constants.MGDL; if (options.eventType == R.id.careportal_profileswitch) {
profileList = profileStore.getProfileList(); log.error("Profile switch called but plugin doesn't contain valid profile");
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(), }
R.layout.spinner_centered, profileList); } else {
profileSpinner.setAdapter(adapter); ArrayList<CharSequence> profileList;
// set selected to actual profile units = profile != null ? profile.getUnits() : Constants.MGDL;
for (int p = 0; p < profileList.size(); p++) { profileList = profileStore.getProfileList();
if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName(false))) ArrayAdapter<CharSequence> adapter = new ArrayAdapter<>(getContext(),
profileSpinner.setSelection(p); R.layout.spinner_centered, profileList);
profileSpinner.setAdapter(adapter);
// set selected to actual profile
for (int p = 0; p < profileList.size(); p++) {
if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName(false)))
profileSpinner.setSelection(p);
}
} }
final Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, units);
final Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile != null ? profile.getUnits() : Constants.MGDL);
// temp target // temp target
final ArrayList<CharSequence> reasonList = new ArrayList<CharSequence>(); final List<String> reasonList = Lists.newArrayList(
reasonList.add(MainApp.sResources.getString(R.string.manual)); MainApp.gs(R.string.manual),
reasonList.add(MainApp.sResources.getString(R.string.eatingsoon)); MainApp.gs(R.string.eatingsoon),
reasonList.add(MainApp.sResources.getString(R.string.activity)); MainApp.gs(R.string.activity),
ArrayAdapter<CharSequence> adapterReason = new ArrayAdapter<CharSequence>(getContext(), MainApp.gs(R.string.hypo));
ArrayAdapter<String> adapterReason = new ArrayAdapter<>(getContext(),
R.layout.spinner_centered, reasonList); R.layout.spinner_centered, reasonList);
reasonSpinner.setAdapter(adapterReason); reasonSpinner.setAdapter(adapterReason);
reasonSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { reasonSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
double defaultDuration = 0; double defaultDuration;
double defaultTarget = 0; double defaultTarget = 0;
if (profile != null) { if (profile != null) {
defaultTarget = bg.doubleValue(); defaultTarget = bg;
} }
boolean erase = false; boolean erase = false;
if (MainApp.sResources.getString(R.string.eatingsoon).equals(reasonList.get(position))) { String units = MainApp.getConfigBuilder().getProfileUnits();
defaultDuration = SP.getDouble(R.string.key_eatingsoon_duration, 0d); DefaultValueHelper helper = new DefaultValueHelper();
defaultTarget = SP.getDouble(R.string.key_eatingsoon_target, 0d); if (MainApp.gs(R.string.eatingsoon).equals(reasonList.get(position))) {
; defaultDuration = helper.determineEatingSoonTTDuration();
} else if (MainApp.sResources.getString(R.string.activity).equals(reasonList.get(position))) { defaultTarget = helper.determineEatingSoonTT(units);
defaultDuration = SP.getDouble(R.string.key_activity_duration, 0d); } else if (MainApp.gs(R.string.activity).equals(reasonList.get(position))) {
; defaultDuration = helper.determineActivityTTDuration();
defaultTarget = SP.getDouble(R.string.key_activity_target, 0d); defaultTarget = helper.determineActivityTT(units);
; } else if (MainApp.gs(R.string.hypo).equals(reasonList.get(position))) {
defaultDuration = helper.determineHypoTTDuration();
defaultTarget = helper.determineHypoTT(units);
} else { } else {
defaultDuration = 0; defaultDuration = 0;
erase = true; erase = true;
} }
if (defaultTarget != 0 || erase) { if (defaultTarget != 0 || erase) {
editTemptarget.setValue(defaultTarget); editTemptarget.setValue(defaultTarget);
} }
@ -256,19 +271,16 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
editBg.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false, bgTextWatcher); editBg.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false, bgTextWatcher);
editTemptarget.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false); editTemptarget.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false);
} }
sensorRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { sensorRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
@Override Double bg1 = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile.getUnits());
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { editBg.setValue(bg1);
Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile.getUnits());
editBg.setValue(bg);
}
}); });
Integer maxCarbs = MainApp.getConfigBuilder().applyCarbsConstraints(Constants.carbsOnlyForCheckLimit); Integer maxCarbs = MainApp.getConstraintChecker().getMaxCarbsAllowed().value();
editCarbs = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_carbsinput); editCarbs = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_carbsinput);
editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false); editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false);
Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
editInsulin = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_insulininput); editInsulin = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_insulininput);
editInsulin.setParams(0d, 0d, maxInsulin, 0.05d, new DecimalFormat("0.00"), false); editInsulin.setParams(0d, 0d, maxInsulin, 0.05d, new DecimalFormat("0.00"), false);
@ -295,7 +307,9 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} }
}; };
Integer maxPercent = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalPercentOnlyForCheckLimit); Integer maxPercent = 200;
if (profile != null)
maxPercent = MainApp.getConstraintChecker().getMaxBasalPercentAllowed(profile).value();
editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput); editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput);
editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher); editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher);
@ -317,7 +331,9 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} }
}; };
Double maxAbsolute = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalAbsoluteOnlyForCheckLimit); Double maxAbsolute = HardLimits.maxBasal();
if (profile != null)
maxAbsolute = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value();
editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput); editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput);
editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true, absoluteTextWatcher); editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true, absoluteTextWatcher);
@ -330,19 +346,19 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
editTimeshift = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_timeshift); editTimeshift = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_timeshift);
editTimeshift.setParams(0d, (double) Constants.CPP_MIN_TIMESHIFT, (double) Constants.CPP_MAX_TIMESHIFT, 1d, new DecimalFormat("0"), false); editTimeshift.setParams(0d, (double) Constants.CPP_MIN_TIMESHIFT, (double) Constants.CPP_MAX_TIMESHIFT, 1d, new DecimalFormat("0"), false);
ProfileSwitch ps = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); ProfileSwitch ps = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now());
if (ps != null && ps.isCPP) { if (ps != null && ps.isCPP) {
final int percentage = ps.percentage; final int percentage = ps.percentage;
final int timeshift = ps.timeshift; final int timeshift = ps.timeshift;
reuseButton.setText(reuseButton.getText() + " " + percentage + "% " + timeshift + "h"); reuseButton.setText(reuseButton.getText() + " " + percentage + "% " + timeshift + "h");
reuseButton.setOnClickListener(new View.OnClickListener() { reuseButton.setOnClickListener(v -> {
@Override editPercentage.setValue((double) percentage);
public void onClick(View v) { editTimeshift.setValue((double) timeshift);
editPercentage.setValue((double) percentage);
editTimeshift.setValue((double) timeshift);
}
}); });
} }
if (ps == null) {
options.duration = false;
}
showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_eventtime_layout), options.date); showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_eventtime_layout), options.date);
showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_bg_layout), options.bg); showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_bg_layout), options.bg);
@ -393,7 +409,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
tpd.show(context.getFragmentManager(), "Timepickerdialog"); tpd.show(context.getFragmentManager(), "Timepickerdialog");
break; break;
case R.id.ok: case R.id.ok:
createNSTreatment(); confirmNSTreatmentCreation();
dismiss(); dismiss();
break; break;
case R.id.cancel: case R.id.cancel:
@ -407,20 +423,32 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
else layout.setVisibility(View.GONE); else layout.setVisibility(View.GONE);
} }
private void updateBGforDateTime() {
long millis = eventTime.getTime() - (150 * 1000L); // 2,5 * 60 * 1000
List<BgReading> data = MainApp.getDbHelper().getBgreadingsDataFromTime(millis, true);
if ((data.size() > 0) &&
(data.get(0).date > millis - 7 * 60 * 1000L) &&
(data.get(0).date < millis + 7 * 60 * 1000L)) {
editBg.setValue(Profile.fromMgdlToUnits(data.get(0).value, profile != null ? profile.getUnits() : Constants.MGDL));
}
}
@Override @Override
public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) { public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
eventTime.setYear(year - 1900); eventTime.setYear(year - 1900);
eventTime.setMonth(monthOfYear); eventTime.setMonth(monthOfYear);
eventTime.setDate(dayOfMonth); eventTime.setDate(dayOfMonth);
dateButton.setText(DateUtil.dateString(eventTime)); dateButton.setText(DateUtil.dateString(eventTime));
updateBGforDateTime();
} }
@Override @Override
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute, int second) { public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute, int second) {
eventTime.setHours(hourOfDay); eventTime.setHours(hourOfDay);
eventTime.setMinutes(minute); eventTime.setMinutes(minute);
eventTime.setSeconds(second); eventTime.setSeconds(this.seconds++); // randomize seconds to prevent creating record of the same time, if user choose time manually
timeButton.setText(DateUtil.timeString(eventTime)); timeButton.setText(DateUtil.timeString(eventTime));
updateBGforDateTime();
} }
@ -545,159 +573,151 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
String buildConfirmText(JSONObject data) { String buildConfirmText(JSONObject data) {
String ret = ""; String ret = "";
try { if (data.has("eventType")) {
if (data.has("eventType")) { ret += MainApp.gs(R.string.careportal_newnstreatment_eventtype);
ret += getString(R.string.careportal_newnstreatment_eventtype); ret += ": ";
ret += ": "; ret += Translator.translate(JsonHelper.safeGetString(data, "eventType", ""));
ret += Translator.translate(data.getString("eventType")); ret += "\n";
ret += "\n"; }
} if (data.has("glucose")) {
if (data.has("glucose")) { ret += MainApp.gs(R.string.treatments_wizard_bg_label);
ret += getString(R.string.treatments_wizard_bg_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "glucose", "");
ret += data.get("glucose"); ret += " " + units + "\n";
ret += " " + units + "\n"; }
} if (data.has("glucoseType")) {
if (data.has("glucoseType")) { ret += MainApp.gs(R.string.careportal_newnstreatment_glucosetype);
ret += getString(R.string.careportal_newnstreatment_glucosetype); ret += ": ";
ret += ": "; ret += Translator.translate(JsonHelper.safeGetString(data, "glucoseType", ""));
ret += Translator.translate(data.getString("glucoseType")); ret += "\n";
ret += "\n"; }
} if (data.has("carbs")) {
if (data.has("carbs")) { ret += MainApp.gs(R.string.careportal_newnstreatment_carbs_label);
ret += getString(R.string.careportal_newnstreatment_carbs_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "carbs", "");
ret += data.get("carbs"); ret += " g\n";
ret += " g\n"; }
} if (data.has("insulin")) {
if (data.has("insulin")) { ret += MainApp.gs(R.string.careportal_newnstreatment_insulin_label);
ret += getString(R.string.careportal_newnstreatment_insulin_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "insulin", "");
ret += data.get("insulin"); ret += " U\n";
ret += " U\n"; }
} if (data.has("duration")) {
if (data.has("duration")) { ret += MainApp.gs(R.string.careportal_newnstreatment_duration_label);
ret += getString(R.string.careportal_newnstreatment_duration_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "duration", "");
ret += data.get("duration"); ret += " min\n";
ret += " min\n"; }
} if (data.has("percent")) {
if (data.has("percent")) { ret += MainApp.gs(R.string.careportal_newnstreatment_percent_label);
ret += getString(R.string.careportal_newnstreatment_percent_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "percent", "");
ret += data.get("percent"); ret += " %\n";
ret += " %\n"; }
} if (data.has("absolute")) {
if (data.has("absolute")) { ret += MainApp.gs(R.string.careportal_newnstreatment_absolute_label);
ret += getString(R.string.careportal_newnstreatment_absolute_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "absolute", "");
ret += data.get("absolute"); ret += " U/h\n";
ret += " U/h\n"; }
} if (data.has("preBolus")) {
if (data.has("preBolus")) { ret += MainApp.gs(R.string.careportal_newnstreatment_carbtime_label);
ret += getString(R.string.careportal_newnstreatment_carbtime_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "preBolus", "");
ret += data.get("preBolus"); ret += " min\n";
ret += " min\n"; }
} if (data.has("notes")) {
if (data.has("notes")) { ret += MainApp.gs(R.string.careportal_newnstreatment_notes_label);
ret += getString(R.string.careportal_newnstreatment_notes_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "notes", "");
ret += data.get("notes"); ret += "\n";
ret += "\n"; }
} if (data.has("profile")) {
if (data.has("profile")) { ret += MainApp.gs(R.string.careportal_newnstreatment_profile_label);
ret += getString(R.string.careportal_newnstreatment_profile_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "profile", "");
ret += data.get("profile"); ret += "\n";
ret += "\n"; }
} if (data.has("percentage")) {
if (data.has("percentage")) { ret += MainApp.gs(R.string.careportal_newnstreatment_percentage_label);
ret += getString(R.string.careportal_newnstreatment_percentage_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "percentage", "");
ret += data.get("percentage"); ret += " %\n";
ret += " %\n"; }
} if (data.has("timeshift")) {
if (data.has("timeshift")) { ret += MainApp.gs(R.string.careportal_newnstreatment_timeshift_label);
ret += getString(R.string.careportal_newnstreatment_timeshift_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "timeshift", "");
ret += data.get("timeshift"); ret += " h\n";
ret += " h\n"; }
} if (data.has("targetBottom") && data.has("targetTop")) {
if (data.has("targetBottom") && data.has("targetTop")) { ret += MainApp.gs(R.string.target_range);
ret += getString(R.string.target_range); ret += " ";
ret += " "; ret += JsonHelper.safeGetObject(data, "targetBottom", "");
ret += data.get("targetBottom"); ret += " - ";
ret += " - "; ret += JsonHelper.safeGetObject(data, "targetTop", "");
ret += data.get("targetTop"); ret += "\n";
ret += "\n"; }
} if (data.has("created_at")) {
if (data.has("created_at")) { ret += MainApp.gs(R.string.careportal_newnstreatment_eventtime_label);
ret += getString(R.string.careportal_newnstreatment_eventtime_label); ret += ": ";
ret += ": "; ret += eventTime.toLocaleString();
ret += eventTime.toLocaleString(); ret += "\n";
ret += "\n"; }
} if (data.has("enteredBy")) {
if (data.has("enteredBy")) { ret += MainApp.gs(R.string.careportal_newnstreatment_enteredby_title);
ret += getString(R.string.careportal_newnstreatment_enteredby_title); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "enteredBy", "");
ret += data.get("enteredBy"); ret += "\n";
ret += "\n";
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
} }
return ret; return ret;
} }
void createNSTreatment() { void confirmNSTreatmentCreation() {
final JSONObject data = gatherData(); if (context != null) {
String confirmText = buildConfirmText(data); final JSONObject data = gatherData();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); final String confirmText = buildConfirmText(data);
builder.setTitle(getContext().getString(R.string.confirmation)); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(confirmText); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setPositiveButton(getContext().getString(R.string.ok), new DialogInterface.OnClickListener() { builder.setMessage(confirmText);
public void onClick(DialogInterface dialog, int id) { builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> createNSTreatment(data));
if (options.executeProfileSwitch) { builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
if (data.has("profile")) { builder.show();
try { }
doProfileSwitch(profileStore, data.getString("profile"), data.getInt("duration"), data.getInt("percentage"), data.getInt("timeshift")); }
} catch (JSONException e) {
log.error("Unhandled exception", e);
} public void createNSTreatment(JSONObject data) {
} if (options.executeProfileSwitch) {
} else if (options.executeTempTarget) { if (data.has("profile")) {
try { doProfileSwitch(profileStore, JsonHelper.safeGetString(data, "profile"), JsonHelper.safeGetInt(data, "duration"), JsonHelper.safeGetInt(data, "percentage"), JsonHelper.safeGetInt(data, "timeshift"));
if ((data.has("targetBottom") && data.has("targetTop")) || (data.has("duration") && data.getInt("duration") == 0)) {
TempTarget tempTarget = new TempTarget();
tempTarget.date = eventTime.getTime();
tempTarget.durationInMinutes = data.getInt("duration");
tempTarget.reason = data.getString("reason");
tempTarget.source = Source.USER;
if (tempTarget.durationInMinutes != 0) {
tempTarget.low = Profile.toMgdl(data.getDouble("targetBottom"), profile.getUnits());
tempTarget.high = Profile.toMgdl(data.getDouble("targetTop"), profile.getUnits());
} else {
tempTarget.low = 0;
tempTarget.high = 0;
}
log.debug("Creating new TempTarget db record: " + tempTarget.toString());
MainApp.getDbHelper().createOrUpdate(tempTarget);
NSUpload.uploadCareportalEntryToNS(data);
Answers.getInstance().logCustom(new CustomEvent("TempTarget"));
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
} else {
NSUpload.uploadCareportalEntryToNS(data);
Answers.getInstance().logCustom(new CustomEvent("NSTreatment"));
}
} }
}); } else if (options.executeTempTarget) {
builder.setNegativeButton(getContext().getString(R.string.cancel), null); final int duration = JsonHelper.safeGetInt(data, "duration");
builder.show(); final double targetBottom = JsonHelper.safeGetDouble(data, "targetBottom");
final double targetTop = JsonHelper.safeGetDouble(data, "targetTop");
final String reason = JsonHelper.safeGetString(data, "reason", "");
if ((targetBottom != 0d && targetTop != 0d) || duration == 0) {
TempTarget tempTarget = new TempTarget()
.date(eventTime.getTime())
.duration(duration)
.reason(reason)
.source(Source.USER);
if (tempTarget.durationInMinutes != 0) {
tempTarget.low(Profile.toMgdl(targetBottom, profile.getUnits()))
.high(Profile.toMgdl(targetTop, profile.getUnits()));
} else {
tempTarget.low(0).high(0);
}
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
FabricPrivacy.getInstance().logCustom(new CustomEvent("TempTarget"));
}
} else {
NSUpload.uploadCareportalEntryToNS(data);
FabricPrivacy.getInstance().logCustom(new CustomEvent("NSTreatment"));
}
} }
public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) { public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) {
@ -706,60 +726,30 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
profileSwitch.source = Source.USER; profileSwitch.source = Source.USER;
profileSwitch.profileName = profileName; profileSwitch.profileName = profileName;
profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString(); profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getActiveProfileInterface().getClass().getName(); profileSwitch.profilePlugin = MainApp.getConfigBuilder().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration; profileSwitch.durationInMinutes = duration;
profileSwitch.isCPP = percentage != 100 || timeshift != 0; profileSwitch.isCPP = percentage != 100 || timeshift != 0;
profileSwitch.timeshift = timeshift; profileSwitch.timeshift = timeshift;
profileSwitch.percentage = percentage; profileSwitch.percentage = percentage;
MainApp.getConfigBuilder().addToHistoryProfileSwitch(profileSwitch); TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
ConfigBuilderPlugin.getCommandQueue().setProfile(profileSwitch.getProfileObject(), new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.failedupdatebasalprofile));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
MainApp.bus().post(new EventNewBasalProfile());
}
});
Answers.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
} }
public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) { public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) {
ProfileSwitch profileSwitch = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); ProfileSwitch profileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis());
if (profileSwitch != null) { if (profileSwitch != null) {
profileSwitch = new ProfileSwitch(); profileSwitch = new ProfileSwitch();
profileSwitch.date = System.currentTimeMillis(); profileSwitch.date = System.currentTimeMillis();
profileSwitch.source = Source.USER; profileSwitch.source = Source.USER;
profileSwitch.profileName = MainApp.getConfigBuilder().getProfileName(System.currentTimeMillis(), false); profileSwitch.profileName = MainApp.getConfigBuilder().getProfileName(System.currentTimeMillis(), false);
profileSwitch.profileJson = MainApp.getConfigBuilder().getProfile().getData().toString(); profileSwitch.profileJson = MainApp.getConfigBuilder().getProfile().getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getActiveProfileInterface().getClass().getName(); profileSwitch.profilePlugin = MainApp.getConfigBuilder().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration; profileSwitch.durationInMinutes = duration;
profileSwitch.isCPP = percentage != 100 || timeshift != 0; profileSwitch.isCPP = percentage != 100 || timeshift != 0;
profileSwitch.timeshift = timeshift; profileSwitch.timeshift = timeshift;
profileSwitch.percentage = percentage; profileSwitch.percentage = percentage;
MainApp.getConfigBuilder().addToHistoryProfileSwitch(profileSwitch); TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
ConfigBuilderPlugin.getCommandQueue().setProfile(profileSwitch.getProfileObject(), new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.failedupdatebasalprofile));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
MainApp.bus().post(new EventNewBasalProfile());
}
});
Answers.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
} else { } else {
log.error("No profile switch existing"); log.error("No profile switch existing");
} }

View file

@ -4,7 +4,7 @@ package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.annotation.NonNull;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -17,12 +17,14 @@ import android.widget.ListAdapter;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import java.util.ArrayList; import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.PreferencesActivity; import info.nightscout.androidaps.PreferencesActivity;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
@ -33,43 +35,59 @@ import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.SensitivityInterface; import info.nightscout.androidaps.interfaces.SensitivityInterface;
import info.nightscout.androidaps.plugins.Insulin.InsulinFastactingPlugin; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.PasswordProtection;
public class ConfigBuilderFragment extends Fragment { public class ConfigBuilderFragment extends SubscriberFragment {
static ConfigBuilderPlugin configBuilderPlugin = new ConfigBuilderPlugin();
static public ConfigBuilderPlugin getPlugin() {
return configBuilderPlugin;
}
@BindView(R.id.configbuilder_insulinlistview)
ListView insulinListView; ListView insulinListView;
@BindView(R.id.configbuilder_sensitivitylistview)
ListView sensitivityListView; ListView sensitivityListView;
@BindView(R.id.configbuilder_bgsourcelistview)
ListView bgsourceListView; ListView bgsourceListView;
@BindView(R.id.configbuilder_bgsourcelabel)
TextView bgsourceLabel; TextView bgsourceLabel;
@BindView(R.id.configbuilder_pumplistview)
ListView pumpListView; ListView pumpListView;
@BindView(R.id.configbuilder_pumplabel)
TextView pumpLabel; TextView pumpLabel;
@BindView(R.id.configbuilder_looplistview)
ListView loopListView; ListView loopListView;
@BindView(R.id.configbuilder_looplabel)
TextView loopLabel; TextView loopLabel;
@BindView(R.id.configbuilder_treatmentslistview)
ListView treatmentsListView; ListView treatmentsListView;
@BindView(R.id.configbuilder_treatmentslabel)
TextView treatmentsLabel; TextView treatmentsLabel;
@BindView(R.id.configbuilder_profilelistview)
ListView profileListView; ListView profileListView;
@BindView(R.id.configbuilder_profilelabel)
TextView profileLabel; TextView profileLabel;
@BindView(R.id.configbuilder_apslistview)
ListView apsListView; ListView apsListView;
@BindView(R.id.configbuilder_apslabel)
TextView apsLabel; TextView apsLabel;
@BindView(R.id.configbuilder_constraintslistview)
ListView constraintsListView; ListView constraintsListView;
@BindView(R.id.configbuilder_constraintslabel)
TextView constraintsLabel; TextView constraintsLabel;
@BindView(R.id.configbuilder_generallistview)
ListView generalListView; ListView generalListView;
@BindView(R.id.configbuilder_mainlayout)
LinearLayout mainLayout; LinearLayout mainLayout;
@BindView(R.id.configbuilder_unlock)
Button unlock; Button unlock;
PluginCustomAdapter insulinDataAdapter = null; PluginCustomAdapter insulinDataAdapter = null;
@ -84,105 +102,83 @@ public class ConfigBuilderFragment extends Fragment {
PluginCustomAdapter generalDataAdapter = null; PluginCustomAdapter generalDataAdapter = null;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
try { try {
View view = inflater.inflate(R.layout.configbuilder_fragment, container, false); View view = inflater.inflate(R.layout.configbuilder_fragment, container, false);
insulinListView = (ListView) view.findViewById(R.id.configbuilder_insulinlistview); unbinder = ButterKnife.bind(this, view);
sensitivityListView = (ListView) view.findViewById(R.id.configbuilder_sensitivitylistview);
bgsourceListView = (ListView) view.findViewById(R.id.configbuilder_bgsourcelistview);
bgsourceLabel = (TextView) view.findViewById(R.id.configbuilder_bgsourcelabel);
pumpListView = (ListView) view.findViewById(R.id.configbuilder_pumplistview);
pumpLabel = (TextView) view.findViewById(R.id.configbuilder_pumplabel);
loopListView = (ListView) view.findViewById(R.id.configbuilder_looplistview);
loopLabel = (TextView) view.findViewById(R.id.configbuilder_looplabel);
treatmentsListView = (ListView) view.findViewById(R.id.configbuilder_treatmentslistview);
treatmentsLabel = (TextView) view.findViewById(R.id.configbuilder_treatmentslabel);
profileListView = (ListView) view.findViewById(R.id.configbuilder_profilelistview);
profileLabel = (TextView) view.findViewById(R.id.configbuilder_profilelabel);
apsListView = (ListView) view.findViewById(R.id.configbuilder_apslistview);
apsLabel = (TextView) view.findViewById(R.id.configbuilder_apslabel);
constraintsListView = (ListView) view.findViewById(R.id.configbuilder_constraintslistview);
constraintsLabel = (TextView) view.findViewById(R.id.configbuilder_constraintslabel);
generalListView = (ListView) view.findViewById(R.id.configbuilder_generallistview);
mainLayout = (LinearLayout) view.findViewById(R.id.configbuilder_mainlayout); if (PasswordProtection.isLocked("settings_password"))
unlock = (Button) view.findViewById(R.id.configbuilder_unlock);
setViews();
if (PasswordProtection.isLocked("settings_password")) {
mainLayout.setVisibility(View.GONE); mainLayout.setVisibility(View.GONE);
unlock.setOnClickListener(new View.OnClickListener() { else
@Override
public void onClick(View v) {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", new Runnable() {
@Override
public void run() {
mainLayout.setVisibility(View.VISIBLE);
unlock.setVisibility(View.GONE);
}
}, null);
}
});
} else {
unlock.setVisibility(View.GONE); unlock.setVisibility(View.GONE);
}
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
} }
void setViews() { @OnClick(R.id.configbuilder_unlock)
insulinDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginBase.INSULIN), PluginBase.INSULIN); public void onClickUnlock() {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
mainLayout.setVisibility(View.VISIBLE);
unlock.setVisibility(View.GONE);
}, null);
}
@Override
protected void updateGUI() {
insulinDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginType.INSULIN), PluginType.INSULIN);
insulinListView.setAdapter(insulinDataAdapter); insulinListView.setAdapter(insulinDataAdapter);
setListViewHeightBasedOnChildren(insulinListView); setListViewHeightBasedOnChildren(insulinListView);
bgsourceDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginBase.BGSOURCE), PluginBase.BGSOURCE); bgsourceDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginType.BGSOURCE), PluginType.BGSOURCE);
bgsourceListView.setAdapter(bgsourceDataAdapter); bgsourceListView.setAdapter(bgsourceDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.BGSOURCE).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.BGSOURCE).size() == 0)
bgsourceLabel.setVisibility(View.GONE); bgsourceLabel.setVisibility(View.GONE);
setListViewHeightBasedOnChildren(bgsourceListView); setListViewHeightBasedOnChildren(bgsourceListView);
pumpDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.PUMP), PluginBase.PUMP); pumpDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP), PluginType.PUMP);
pumpListView.setAdapter(pumpDataAdapter); pumpListView.setAdapter(pumpDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.PUMP).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP).size() == 0 || Config.NSCLIENT || Config.G5UPLOADER) {
pumpLabel.setVisibility(View.GONE); pumpLabel.setVisibility(View.GONE);
pumpListView.setVisibility(View.GONE);
}
setListViewHeightBasedOnChildren(pumpListView); setListViewHeightBasedOnChildren(pumpListView);
loopDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.LOOP), PluginBase.LOOP); loopDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP), PluginType.LOOP);
loopListView.setAdapter(loopDataAdapter); loopListView.setAdapter(loopDataAdapter);
setListViewHeightBasedOnChildren(loopListView); setListViewHeightBasedOnChildren(loopListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.LOOP).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP).size() == 0)
loopLabel.setVisibility(View.GONE); loopLabel.setVisibility(View.GONE);
treatmentDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.TREATMENT), PluginBase.TREATMENT); treatmentDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT), PluginType.TREATMENT);
treatmentsListView.setAdapter(treatmentDataAdapter); treatmentsListView.setAdapter(treatmentDataAdapter);
setListViewHeightBasedOnChildren(treatmentsListView); setListViewHeightBasedOnChildren(treatmentsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.TREATMENT).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT).size() == 0)
treatmentsLabel.setVisibility(View.GONE); treatmentsLabel.setVisibility(View.GONE);
profileDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginBase.PROFILE), PluginBase.PROFILE); profileDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginType.PROFILE), PluginType.PROFILE);
profileListView.setAdapter(profileDataAdapter); profileListView.setAdapter(profileDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.PROFILE).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.PROFILE).size() == 0)
profileLabel.setVisibility(View.GONE); profileLabel.setVisibility(View.GONE);
setListViewHeightBasedOnChildren(profileListView); setListViewHeightBasedOnChildren(profileListView);
apsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.APS), PluginBase.APS); apsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.APS), PluginType.APS);
apsListView.setAdapter(apsDataAdapter); apsListView.setAdapter(apsDataAdapter);
setListViewHeightBasedOnChildren(apsListView); setListViewHeightBasedOnChildren(apsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.APS).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.APS).size() == 0)
apsLabel.setVisibility(View.GONE); apsLabel.setVisibility(View.GONE);
sensivityDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginBase.SENSITIVITY), PluginBase.SENSITIVITY); sensivityDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginType.SENSITIVITY), PluginType.SENSITIVITY);
sensitivityListView.setAdapter(sensivityDataAdapter); sensitivityListView.setAdapter(sensivityDataAdapter);
setListViewHeightBasedOnChildren(sensitivityListView); setListViewHeightBasedOnChildren(sensitivityListView);
constraintsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginBase.CONSTRAINTS), PluginBase.CONSTRAINTS); constraintsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginType.CONSTRAINTS), PluginType.CONSTRAINTS);
constraintsListView.setAdapter(constraintsDataAdapter); constraintsListView.setAdapter(constraintsDataAdapter);
setListViewHeightBasedOnChildren(constraintsListView); setListViewHeightBasedOnChildren(constraintsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.CONSTRAINTS).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS).size() == 0)
constraintsLabel.setVisibility(View.GONE); constraintsLabel.setVisibility(View.GONE);
generalDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.GENERAL), PluginBase.GENERAL); generalDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL), PluginType.GENERAL);
generalListView.setAdapter(generalDataAdapter); generalListView.setAdapter(generalDataAdapter);
setListViewHeightBasedOnChildren(generalListView); setListViewHeightBasedOnChildren(generalListView);
} }
/* /*
@ -192,10 +188,10 @@ public class ConfigBuilderFragment extends Fragment {
private class PluginCustomAdapter extends ArrayAdapter<PluginBase> { private class PluginCustomAdapter extends ArrayAdapter<PluginBase> {
private ArrayList<PluginBase> pluginList; private ArrayList<PluginBase> pluginList;
final private int type; final private PluginType type;
public PluginCustomAdapter(Context context, int textViewResourceId, PluginCustomAdapter(Context context, int textViewResourceId,
ArrayList<PluginBase> pluginList, int type) { ArrayList<PluginBase> pluginList, PluginType type) {
super(context, textViewResourceId, pluginList); super(context, textViewResourceId, pluginList);
this.pluginList = new ArrayList<>(); this.pluginList = new ArrayList<>();
this.pluginList.addAll(pluginList); this.pluginList.addAll(pluginList);
@ -209,10 +205,11 @@ public class ConfigBuilderFragment extends Fragment {
ImageView settings; ImageView settings;
} }
@NonNull
@Override @Override
public View getView(int position, View view, ViewGroup parent) { public View getView(int position, View view, @NonNull ViewGroup parent) {
PluginViewHolder holder = null; PluginViewHolder holder;
PluginBase plugin = pluginList.get(position); PluginBase plugin = pluginList.get(position);
if (view == null) { if (view == null) {
@ -231,60 +228,45 @@ public class ConfigBuilderFragment extends Fragment {
view.setTag(holder); view.setTag(holder);
holder.checkboxEnabled.setOnClickListener(new View.OnClickListener() { holder.checkboxEnabled.setOnClickListener(v -> {
public void onClick(View v) { CheckBox cb = (CheckBox) v;
CheckBox cb = (CheckBox) v; PluginBase plugin1 = (PluginBase) cb.getTag();
PluginBase plugin = (PluginBase) cb.getTag(); plugin1.setPluginEnabled(type, cb.isChecked());
plugin.setFragmentEnabled(type, cb.isChecked()); plugin1.setFragmentVisible(type, cb.isChecked());
plugin.setFragmentVisible(type, cb.isChecked()); onEnabledCategoryChanged(plugin1, type);
onEnabledCategoryChanged(plugin, type); ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
configBuilderPlugin.storeSettings(); MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventRefreshGui()); MainApp.bus().post(new EventConfigBuilderChange());
MainApp.bus().post(new EventConfigBuilderChange()); ConfigBuilderPlugin.getPlugin().logPluginStatus();
getPlugin().logPluginStatus(); FabricPrivacy.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
Answers.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
}
}); });
holder.checkboxVisible.setOnClickListener(new View.OnClickListener() { holder.checkboxVisible.setOnClickListener(v -> {
public void onClick(View v) { CheckBox cb = (CheckBox) v;
CheckBox cb = (CheckBox) v; PluginBase plugin12 = (PluginBase) cb.getTag();
PluginBase plugin = (PluginBase) cb.getTag(); plugin12.setFragmentVisible(type, cb.isChecked());
plugin.setFragmentVisible(type, cb.isChecked()); ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible");
configBuilderPlugin.storeSettings(); MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventRefreshGui()); ConfigBuilderPlugin.getPlugin().logPluginStatus();
getPlugin().logPluginStatus();
}
}); });
holder.settings.setOnClickListener(new View.OnClickListener() { holder.settings.setOnClickListener(v -> {
public void onClick(View v) { final PluginBase plugin13 = (PluginBase) v.getTag();
final PluginBase plugin = (PluginBase) v.getTag(); PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", new Runnable() { Intent i = new Intent(getContext(), PreferencesActivity.class);
@Override i.putExtra("id", plugin13.getPreferencesId());
public void run() { startActivity(i);
Intent i = new Intent(getContext(), PreferencesActivity.class); }, null);
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}
}, null);
}
}); });
holder.name.setOnLongClickListener(new View.OnLongClickListener() { holder.name.setOnLongClickListener(v -> {
@Override final PluginBase plugin14 = (PluginBase) v.getTag();
public boolean onLongClick(View v) { PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
final PluginBase plugin = (PluginBase) v.getTag(); Intent i = new Intent(getContext(), PreferencesActivity.class);
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", new Runnable() { i.putExtra("id", plugin14.getPreferencesId());
@Override startActivity(i);
public void run() { }, null);
Intent i = new Intent(getContext(), PreferencesActivity.class); return false;
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}
}, null);
return false;
}
}); });
} else { } else {
@ -293,15 +275,18 @@ public class ConfigBuilderFragment extends Fragment {
holder.name.setText(plugin.getName()); holder.name.setText(plugin.getName());
holder.checkboxEnabled.setChecked(plugin.isEnabled(type)); holder.checkboxEnabled.setChecked(plugin.isEnabled(type));
holder.checkboxVisible.setChecked(plugin.isVisibleInTabs(type)); holder.checkboxVisible.setChecked(plugin.isFragmentVisible());
holder.name.setTag(plugin); holder.name.setTag(plugin);
holder.checkboxEnabled.setTag(plugin); holder.checkboxEnabled.setTag(plugin);
holder.checkboxVisible.setTag(plugin); holder.checkboxVisible.setTag(plugin);
holder.settings.setTag(plugin); holder.settings.setTag(plugin);
if (!plugin.canBeHidden(type)) { if (plugin.pluginDescription.alwaysEnabled) {
holder.checkboxEnabled.setEnabled(false);
}
if (plugin.pluginDescription.alwayVisible) {
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
holder.checkboxVisible.setEnabled(false);
} }
if (!plugin.isEnabled(type)) { if (!plugin.isEnabled(type)) {
@ -313,19 +298,19 @@ public class ConfigBuilderFragment extends Fragment {
} }
// Hide enabled control and force enabled plugin if there is only one plugin available // Hide enabled control and force enabled plugin if there is only one plugin available
if (type == PluginBase.INSULIN || type == PluginBase.PUMP || type == PluginBase.TREATMENT || type == PluginBase.PROFILE || type == PluginBase.SENSITIVITY) if (type == PluginType.INSULIN || type == PluginType.PUMP || type == PluginType.SENSITIVITY)
if (pluginList.size() < 2) { if (pluginList.size() < 2) {
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
plugin.setFragmentEnabled(type, true); plugin.setPluginEnabled(type, true);
getPlugin().storeSettings(); ConfigBuilderPlugin.getPlugin().storeSettings("ForceEnable");
} }
// Constraints cannot be disabled // Constraints cannot be disabled
if (type == PluginBase.CONSTRAINTS) if (type == PluginType.CONSTRAINTS)
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
// Hide disabled profiles by default // Hide disabled profiles by default
if (type == PluginBase.PROFILE) { if (type == PluginType.PROFILE) {
if (!plugin.isEnabled(type)) { if (!plugin.isEnabled(type)) {
holder.checkboxVisible.setEnabled(false); holder.checkboxVisible.setEnabled(false);
holder.checkboxVisible.setChecked(false); holder.checkboxVisible.setChecked(false);
@ -335,9 +320,9 @@ public class ConfigBuilderFragment extends Fragment {
} }
// Disable profile control for pump profiles if pump is not enabled // Disable profile control for pump profiles if pump is not enabled
if (type == PluginBase.PROFILE) { if (type == PluginType.PROFILE) {
if (PumpInterface.class.isAssignableFrom(plugin.getClass())) { if (PumpInterface.class.isAssignableFrom(plugin.getClass())) {
if (!plugin.isEnabled(PluginBase.PUMP)) { if (!plugin.isEnabled(PluginType.PUMP)) {
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
holder.checkboxEnabled.setChecked(false); holder.checkboxEnabled.setChecked(false);
} }
@ -354,32 +339,32 @@ public class ConfigBuilderFragment extends Fragment {
} }
void onEnabledCategoryChanged(PluginBase changedPlugin, int type) { void onEnabledCategoryChanged(PluginBase changedPlugin, PluginType type) {
ArrayList<PluginBase> pluginsInCategory = null; ArrayList<PluginBase> pluginsInCategory = null;
switch (type) { switch (type) {
// Multiple selection allowed // Multiple selection allowed
case PluginBase.GENERAL: case GENERAL:
case PluginBase.CONSTRAINTS: case CONSTRAINTS:
case PluginBase.LOOP: case LOOP:
break; break;
// Single selection allowed // Single selection allowed
case PluginBase.INSULIN: case INSULIN:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class);
break; break;
case PluginBase.SENSITIVITY: case SENSITIVITY:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class);
break; break;
case PluginBase.APS: case APS:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
break; break;
case PluginBase.PROFILE: case PROFILE:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
break; break;
case PluginBase.BGSOURCE: case BGSOURCE:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
break; break;
case PluginBase.TREATMENT: case TREATMENT:
case PluginBase.PUMP: case PUMP:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(PumpInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(PumpInterface.class);
break; break;
} }
@ -390,23 +375,23 @@ public class ConfigBuilderFragment extends Fragment {
if (p.getName().equals(changedPlugin.getName())) { if (p.getName().equals(changedPlugin.getName())) {
// this is new selected // this is new selected
} else { } else {
p.setFragmentEnabled(type, false); p.setPluginEnabled(type, false);
p.setFragmentVisible(type, false); p.setFragmentVisible(type, false);
} }
} }
} else { // enable first plugin in list } else { // enable first plugin in list
if (type == PluginBase.PUMP) if (type == PluginType.PUMP)
MainApp.getSpecificPlugin(VirtualPumpPlugin.class).setFragmentEnabled(type, true); VirtualPumpPlugin.getPlugin().setPluginEnabled(type, true);
else if (type == PluginBase.INSULIN) else if (type == PluginType.INSULIN)
MainApp.getSpecificPlugin(InsulinFastactingPlugin.class).setFragmentEnabled(type, true); InsulinOrefRapidActingPlugin.getPlugin().setPluginEnabled(type, true);
else if (type == PluginBase.SENSITIVITY) else if (type == PluginType.SENSITIVITY)
MainApp.getSpecificPlugin(SensitivityOref0Plugin.class).setFragmentEnabled(type, true); SensitivityOref0Plugin.getPlugin().setPluginEnabled(type, true);
else if (type == PluginBase.PROFILE) else if (type == PluginType.PROFILE)
MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentEnabled(type, true); NSProfilePlugin.getPlugin().setPluginEnabled(type, true);
else else
pluginsInCategory.get(0).setFragmentEnabled(type, true); pluginsInCategory.get(0).setPluginEnabled(type, true);
} }
setViews(); updateGUI();
} }
} }

View file

@ -15,7 +15,6 @@ import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -25,8 +24,10 @@ import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.utils.FabricPrivacy;
public class ObjectivesFragment extends Fragment { public class ObjectivesFragment extends SubscriberFragment {
private static Logger log = LoggerFactory.getLogger(ObjectivesFragment.class); private static Logger log = LoggerFactory.getLogger(ObjectivesFragment.class);
RecyclerView recyclerView; RecyclerView recyclerView;
@ -84,37 +85,52 @@ public class ObjectivesFragment extends Fragment {
} }
}); });
Long now = System.currentTimeMillis(); long prevObjectiveAccomplishedTime = position > 0 ?
if (position > 0 && objectives.get(position - 1).accomplished.getTime() == 0) { objectives.get(position - 1).accomplished.getTime() : -1;
// Phase 0: previous not completed
holder.startedLayout.setVisibility(View.GONE); int phase = modifyVisibility(position, prevObjectiveAccomplishedTime,
holder.durationLayout.setVisibility(View.GONE); o.started.getTime(), o.durationInDays,
holder.progressLayout.setVisibility(View.GONE); o.accomplished.getTime(), requirementsMet.done, enableFake.isChecked());
holder.verifyLayout.setVisibility(View.GONE);
} else if (o.started.getTime() == 0) { switch (phase) {
// Phase 1: not started case 0:
holder.durationLayout.setVisibility(View.GONE); // Phase 0: previous not completed
holder.progressLayout.setVisibility(View.GONE); holder.startedLayout.setVisibility(View.GONE);
holder.verifyLayout.setVisibility(View.GONE); holder.durationLayout.setVisibility(View.GONE);
holder.started.setVisibility(View.GONE); holder.progressLayout.setVisibility(View.GONE);
} else if (o.started.getTime() > 0 && !enableFake.isChecked() && o.accomplished.getTime() == 0 && !(o.started.getTime() + o.durationInDays * 24 * 60 * 60 * 1000 < now && requirementsMet.done)) { holder.verifyLayout.setVisibility(View.GONE);
// Phase 2: started, waiting for duration and met requirements break;
holder.startButton.setEnabled(false); case 1:
holder.verifyLayout.setVisibility(View.GONE); // Phase 1: not started
} else if (o.accomplished.getTime() == 0) { holder.durationLayout.setVisibility(View.GONE);
// Phase 3: started, after duration, requirements met holder.progressLayout.setVisibility(View.GONE);
holder.startButton.setEnabled(false); holder.verifyLayout.setVisibility(View.GONE);
holder.accomplished.setVisibility(View.INVISIBLE); holder.started.setVisibility(View.GONE);
} else { break;
// Phase 4: verified case 2:
holder.gateLayout.setVisibility(View.GONE); // Phase 2: started, waiting for duration and met requirements
holder.startedLayout.setVisibility(View.GONE); holder.startButton.setEnabled(false);
holder.durationLayout.setVisibility(View.GONE); holder.verifyLayout.setVisibility(View.GONE);
holder.progressLayout.setVisibility(View.GONE); break;
holder.verifyButton.setVisibility(View.INVISIBLE); case 3:
// Phase 3: started, after duration, requirements met
holder.startButton.setEnabled(false);
holder.accomplished.setVisibility(View.INVISIBLE);
break;
case 4:
// Phase 4: verified
holder.gateLayout.setVisibility(View.GONE);
holder.startedLayout.setVisibility(View.GONE);
holder.durationLayout.setVisibility(View.GONE);
holder.progressLayout.setVisibility(View.GONE);
holder.verifyButton.setVisibility(View.INVISIBLE);
break;
default:
// should not happen
} }
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return objectives.size(); return objectives.size();
@ -163,6 +179,40 @@ public class ObjectivesFragment extends Fragment {
} }
} }
/**
* returns an int, which represents the phase the current objective is at.
*
* this is mainly used for unit-testing the conditions
*
* @param currentPosition
* @param prevObjectiveAccomplishedTime
* @param objectiveStartedTime
* @param durationInDays
* @param objectiveAccomplishedTime
* @param requirementsMet
* @return
*/
public int modifyVisibility(int currentPosition,
long prevObjectiveAccomplishedTime,
long objectiveStartedTime, int durationInDays,
long objectiveAccomplishedTime, boolean requirementsMet,
boolean enableFakeValue) {
Long now = System.currentTimeMillis();
if (currentPosition > 0 && prevObjectiveAccomplishedTime == 0) {
return 0;
} else if (objectiveStartedTime == 0) {
return 1;
} else if (objectiveStartedTime > 0 && !enableFakeValue
&& objectiveAccomplishedTime == 0
&& !(objectiveStartedTime + durationInDays * 24 * 60 * 60 * 1000 >= now && requirementsMet)) {
return 2;
} else if (objectiveAccomplishedTime == 0) {
return 3;
} else {
return 4;
}
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
@ -204,26 +254,25 @@ public class ObjectivesFragment extends Fragment {
ObjectivesPlugin.objectives.get(3).gate = MainApp.sResources.getString(R.string.objectives_3_gate); ObjectivesPlugin.objectives.get(3).gate = MainApp.sResources.getString(R.string.objectives_3_gate);
ObjectivesPlugin.objectives.get(4).gate = MainApp.sResources.getString(R.string.objectives_4_gate); ObjectivesPlugin.objectives.get(4).gate = MainApp.sResources.getString(R.string.objectives_4_gate);
ObjectivesPlugin.objectives.get(5).gate = MainApp.sResources.getString(R.string.objectives_5_gate); ObjectivesPlugin.objectives.get(5).gate = MainApp.sResources.getString(R.string.objectives_5_gate);
updateGUI(); updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
} }
void updateGUI() { @Override
public void updateGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(() -> {
@Override RecyclerViewAdapter adapter = new RecyclerViewAdapter(ObjectivesPlugin.objectives);
public void run() { recyclerView.setAdapter(adapter);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(ObjectivesPlugin.objectives);
recyclerView.setAdapter(adapter);
}
}); });
} }
} }

View file

@ -10,25 +10,30 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class ObjectivesPlugin implements PluginBase, ConstraintsInterface { public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface {
private static Logger log = LoggerFactory.getLogger(ObjectivesPlugin.class); private static Logger log = LoggerFactory.getLogger(ObjectivesPlugin.class);
private static ObjectivesPlugin objectivesPlugin; private static ObjectivesPlugin objectivesPlugin;
@ -42,80 +47,26 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
public static List<Objective> objectives; public static List<Objective> objectives;
private boolean fragmentVisible = true;
private ObjectivesPlugin() { private ObjectivesPlugin() {
super(new PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.fragmentClass(ObjectivesFragment.class.getName())
.alwaysEnabled(!Config.NSCLIENT && !Config.G5UPLOADER)
.showInList(!Config.NSCLIENT && !Config.G5UPLOADER)
.pluginName(R.string.objectives)
.shortName(R.string.objectives_shortname)
);
initializeData(); initializeData();
loadProgress(); loadProgress();
MainApp.bus().register(this);
} }
@Override @Override
public String getFragmentClass() { public boolean specialEnableCondition() {
return ObjectivesFragment.class.getName(); PumpInterface pump = ConfigBuilderPlugin.getActivePump();
return pump == null || pump.getPumpDescription().isTempBasalCapable;
} }
@Override public class Objective {
public int getType() {
return PluginBase.CONSTRAINTS;
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.objectives);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.objectives_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == CONSTRAINTS && ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == CONSTRAINTS && fragmentVisible && !Config.NSCLIENT && !Config.G5UPLOADER;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == CONSTRAINTS) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
class Objective {
Integer num; Integer num;
String objective; String objective;
String gate; String gate;
@ -131,6 +82,18 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
this.durationInDays = durationInDays; this.durationInDays = durationInDays;
this.accomplished = accomplished; this.accomplished = accomplished;
} }
public void setStarted(Date started) {
this.started = started;
}
boolean isStarted() {
return started.getTime() > 0;
}
boolean isFinished() {
return accomplished.getTime() != 0;
}
} }
// Objective 0 // Objective 0
@ -158,37 +121,41 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
RequirementResult requirementsMet(Integer objNum) { RequirementResult requirementsMet(Integer objNum) {
switch (objNum) { switch (objNum) {
case 0: case 0:
boolean isVirtualPump = VirtualPumpPlugin.getPlugin().isEnabled(PluginBase.PUMP); boolean isVirtualPump = VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
boolean vpUploadEnabled = SP.getBoolean("virtualpump_uploadstatus", false); boolean vpUploadEnabled = SP.getBoolean("virtualpump_uploadstatus", false);
boolean vpUploadNeeded = !isVirtualPump || vpUploadEnabled; boolean vpUploadNeeded = !isVirtualPump || vpUploadEnabled;
boolean hasBGData = DatabaseHelper.lastBg() != null; boolean hasBGData = DatabaseHelper.lastBg() != null;
boolean apsEnabled = false; boolean apsEnabled = false;
APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS(); APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS();
if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginBase.APS)) if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS))
apsEnabled = true; apsEnabled = true;
return new RequirementResult(hasBGData && bgIsAvailableInNS && pumpStatusIsAvailableInNS && NSClientInternalPlugin.getPlugin().hasWritePermission() && LoopPlugin.getPlugin().isEnabled(PluginBase.LOOP) && apsEnabled && vpUploadNeeded, boolean profileSwitchExists = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now()) != null;
MainApp.sResources.getString(R.string.objectives_bgavailableinns) + ": " + yesOrNo(bgIsAvailableInNS)
+ "\n" + MainApp.sResources.getString(R.string.nsclienthaswritepermission) + ": " + yesOrNo(NSClientInternalPlugin.getPlugin().hasWritePermission()) return new RequirementResult(hasBGData && bgIsAvailableInNS && pumpStatusIsAvailableInNS && NSClientPlugin.getPlugin().hasWritePermission() && LoopPlugin.getPlugin().isEnabled(PluginType.LOOP) && apsEnabled && vpUploadNeeded && profileSwitchExists,
+ (isVirtualPump ? "\n" + MainApp.sResources.getString(R.string.virtualpump_uploadstatus_title) + ": " + yesOrNo(vpUploadEnabled) : "") MainApp.gs(R.string.objectives_bgavailableinns) + ": " + yesOrNo(bgIsAvailableInNS)
+ "\n" + MainApp.sResources.getString(R.string.objectives_pumpstatusavailableinns) + ": " + yesOrNo(pumpStatusIsAvailableInNS) + "\n" + MainApp.gs(R.string.nsclienthaswritepermission) + ": " + yesOrNo(NSClientPlugin.getPlugin().hasWritePermission())
+ "\n" + MainApp.sResources.getString(R.string.hasbgdata) + ": " + yesOrNo(hasBGData) + (isVirtualPump ? "\n" + MainApp.gs(R.string.virtualpump_uploadstatus_title) + ": " + yesOrNo(vpUploadEnabled) : "")
+ "\n" + MainApp.sResources.getString(R.string.loopenabled) + ": " + yesOrNo(LoopPlugin.getPlugin().isEnabled(PluginBase.LOOP)) + "\n" + MainApp.gs(R.string.objectives_pumpstatusavailableinns) + ": " + yesOrNo(pumpStatusIsAvailableInNS)
+ "\n" + MainApp.sResources.getString(R.string.apsselected) + ": " + yesOrNo(apsEnabled) + "\n" + MainApp.gs(R.string.hasbgdata) + ": " + yesOrNo(hasBGData)
+ "\n" + MainApp.gs(R.string.loopenabled) + ": " + yesOrNo(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
+ "\n" + MainApp.gs(R.string.apsselected) + ": " + yesOrNo(apsEnabled)
+ "\n" + MainApp.gs(R.string.activate_profile) + ": " + yesOrNo(profileSwitchExists)
); );
case 1: case 1:
return new RequirementResult(manualEnacts >= manualEnactsNeeded, return new RequirementResult(manualEnacts >= manualEnactsNeeded,
MainApp.sResources.getString(R.string.objectives_manualenacts) + ": " + manualEnacts + "/" + manualEnactsNeeded); MainApp.gs(R.string.objectives_manualenacts) + ": " + manualEnacts + "/" + manualEnactsNeeded);
case 2: case 2:
return new RequirementResult(true, ""); return new RequirementResult(true, "");
case 3: case 3:
boolean closedModeEnabled = SafetyPlugin.getPlugin().isClosedModeEnabled(); Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
return new RequirementResult(closedModeEnabled, MainApp.sResources.getString(R.string.closedmodeenabled) + ": " + yesOrNo(closedModeEnabled)); SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return new RequirementResult(closedLoopEnabled.value(), MainApp.gs(R.string.closedmodeenabled) + ": " + yesOrNo(closedLoopEnabled.value()));
case 4: case 4:
double maxIOB = MainApp.getConfigBuilder().applyMaxIOBConstraints(1000d); double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
boolean maxIobSet = maxIOB > 0; boolean maxIobSet = maxIOB > 0;
return new RequirementResult(maxIobSet, MainApp.sResources.getString(R.string.maxiobset) + ": " + yesOrNo(maxIobSet)); return new RequirementResult(maxIobSet, MainApp.gs(R.string.maxiobset) + ": " + yesOrNo(maxIobSet));
default: default:
return new RequirementResult(true, ""); return new RequirementResult(true, "");
} }
@ -202,49 +169,49 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
objectives = new ArrayList<>(); objectives = new ArrayList<>();
objectives.add(new Objective(0, objectives.add(new Objective(0,
MainApp.sResources.getString(R.string.objectives_0_objective), MainApp.gs(R.string.objectives_0_objective),
MainApp.sResources.getString(R.string.objectives_0_gate), MainApp.gs(R.string.objectives_0_gate),
new Date(0), new Date(0),
0, // 0 day 0, // 0 day
new Date(0))); new Date(0)));
objectives.add(new Objective(1, objectives.add(new Objective(1,
MainApp.sResources.getString(R.string.objectives_1_objective), MainApp.gs(R.string.objectives_1_objective),
MainApp.sResources.getString(R.string.objectives_1_gate), MainApp.gs(R.string.objectives_1_gate),
new Date(0), new Date(0),
7, // 7 days 7, // 7 days
new Date(0))); new Date(0)));
objectives.add(new Objective(2, objectives.add(new Objective(2,
MainApp.sResources.getString(R.string.objectives_2_objective), MainApp.gs(R.string.objectives_2_objective),
MainApp.sResources.getString(R.string.objectives_2_gate), MainApp.gs(R.string.objectives_2_gate),
new Date(0), new Date(0),
0, // 0 days 0, // 0 days
new Date(0))); new Date(0)));
objectives.add(new Objective(3, objectives.add(new Objective(3,
MainApp.sResources.getString(R.string.objectives_3_objective), MainApp.gs(R.string.objectives_3_objective),
MainApp.sResources.getString(R.string.objectives_3_gate), MainApp.gs(R.string.objectives_3_gate),
new Date(0), new Date(0),
5, // 5 days 5, // 5 days
new Date(0))); new Date(0)));
objectives.add(new Objective(4, objectives.add(new Objective(4,
MainApp.sResources.getString(R.string.objectives_4_objective), MainApp.gs(R.string.objectives_4_objective),
MainApp.sResources.getString(R.string.objectives_4_gate), MainApp.gs(R.string.objectives_4_gate),
new Date(0), new Date(0),
1, 1,
new Date(0))); new Date(0)));
objectives.add(new Objective(5, objectives.add(new Objective(5,
MainApp.sResources.getString(R.string.objectives_5_objective), MainApp.gs(R.string.objectives_5_objective),
MainApp.sResources.getString(R.string.objectives_5_gate), MainApp.gs(R.string.objectives_5_gate),
new Date(0), new Date(0),
7, 7,
new Date(0))); new Date(0)));
objectives.add(new Objective(6, objectives.add(new Objective(6,
MainApp.sResources.getString(R.string.objectives_6_objective), MainApp.gs(R.string.objectives_6_objective),
"", "",
new Date(0), new Date(0),
28, 28,
new Date(0))); new Date(0)));
objectives.add(new Objective(7, objectives.add(new Objective(7,
MainApp.sResources.getString(R.string.objectives_7_objective), MainApp.gs(R.string.objectives_7_objective),
"", "",
new Date(0), new Date(0),
28, 28,
@ -294,60 +261,45 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public boolean isLoopEnabled() { public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
return objectives.get(0).started.getTime() > 0; if (!objectives.get(0).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this);
return value;
} }
@Override @Override
public boolean isClosedModeEnabled() { public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
return objectives.get(3).started.getTime() > 0; if (!objectives.get(3).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 4), this);
return value;
} }
@Override @Override
public boolean isAutosensModeEnabled() { public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
return objectives.get(5).started.getTime() > 0; if (!objectives.get(5).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 6), this);
return value;
} }
@Override @Override
public boolean isAMAModeEnabled() { public Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
return objectives.get(6).started.getTime() > 0; if (!objectives.get(6).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 7), this);
return value;
} }
@Override @Override
public boolean isSMBModeEnabled() { public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
return objectives.get(7).started.getTime() > 0; if (!objectives.get(7).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 8), this);
return value;
} }
@Override @Override
public Double applyMaxIOBConstraints(Double maxIob) { public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
if (objectives.get(3).started.getTime() > 0 && objectives.get(3).accomplished.getTime() == 0) { if (objectives.get(3).isStarted() && !objectives.get(3).isFinished())
if (Config.logConstraintsChanges) maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this);
log.debug("Limiting maxIOB " + maxIob + " to " + 0 + "U"); return maxIob;
return 0d;
} else {
return maxIob;
}
} }
@Override
public Double applyBasalConstraints(Double absoluteRate) {
return absoluteRate;
}
@Override
public Integer applyBasalConstraints(Integer percentRate) {
return percentRate;
}
@Override
public Double applyBolusConstraints(Double insulin) {
return insulin;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
return carbs;
}
} }

View file

@ -1,19 +1,22 @@
package info.nightscout.androidaps.plugins.ConstraintsSafety; package info.nightscout.androidaps.plugins.ConstraintsSafety;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.HardLimits; import info.nightscout.utils.HardLimits;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -21,8 +24,7 @@ import info.nightscout.utils.SP;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class SafetyPlugin implements PluginBase, ConstraintsInterface { public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
private static Logger log = LoggerFactory.getLogger(SafetyPlugin.class);
static SafetyPlugin plugin = null; static SafetyPlugin plugin = null;
@ -32,201 +34,154 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
return plugin; return plugin;
} }
@Override public SafetyPlugin() {
public String getFragmentClass() { super(new PluginDescription()
return null; .mainType(PluginType.CONSTRAINTS)
} .neverVisible(true)
.alwaysEnabled(true)
@Override .showInList(false)
public int getType() { .pluginName(R.string.safety)
return PluginBase.CONSTRAINTS; .preferencesId(R.xml.pref_safety)
} );
@Override
public String getName() {
return MainApp.instance().getString(R.string.safety);
}
@Override
public String getNameShort() {
// use long name as fallback (no tabs)
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == CONSTRAINTS;
}
@Override
public boolean isVisibleInTabs(int type) {
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return false;
}
@Override
public boolean showInList(int type) {
return false;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
}
@Override
public int getPreferencesId() {
return R.xml.pref_safety;
}
@Override
public boolean isLoopEnabled() {
return ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
} }
/** /**
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public boolean isClosedModeEnabled() { public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable)
value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable), this);
return value;
}
@Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
String mode = SP.getString("aps_mode", "open"); String mode = SP.getString("aps_mode", "open");
return mode.equals("closed") && BuildConfig.CLOSEDLOOP; if (!mode.equals("closed"))
value.set(false, MainApp.gs(R.string.closedmodedisabledinpreferences), this);
if (!MainApp.isEngineeringModeOrRelease()) {
if (value.value()) {
Notification n = new Notification(Notification.TOAST_ALARM, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(n));
}
value.set(false, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), this);
}
return value;
} }
@Override @Override
public boolean isAutosensModeEnabled() { public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
return true; boolean enabled = SP.getBoolean(R.string.key_openapsama_useautosens, false);
if (!enabled)
value.set(false, MainApp.gs(R.string.autosensdisabledinpreferences), this);
return value;
} }
@Override @Override
public boolean isAMAModeEnabled() { public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
return true; boolean enabled = SP.getBoolean(R.string.key_use_smb, false);
if (!enabled)
value.set(false, MainApp.gs(R.string.smbdisabledinpreferences), this);
ConstraintChecker constraintChecker = MainApp.getConstraintChecker();
Constraint<Boolean> closedLoop = constraintChecker.isClosedLoopAllowed();
if (!closedLoop.value())
value.set(false, MainApp.gs(R.string.smbnotallowedinopenloopmode), this);
return value;
} }
@Override @Override
public boolean isSMBModeEnabled() { public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
return true; BgSourceInterface bgSource = MainApp.getConfigBuilder().getActiveBgSource();
if (bgSource != null) {
if (!bgSource.advancedFilteringSupported())
value.set(false, MainApp.gs(R.string.smbalwaysdisabled), this);
}
return value;
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
Double origAbsoluteRate = absoluteRate;
Double maxBasal = SP.getDouble("openapsma_max_basal", 1d);
Profile profile = MainApp.getConfigBuilder().getProfile(); absoluteRate.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingbasalratio), 0d, MainApp.gs(R.string.itmustbepositivevalue)), this);
if (profile == null) return absoluteRate;
if (absoluteRate < 0) absoluteRate = 0d; double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
absoluteRate.setIfSmaller(maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), maxBasal, MainApp.gs(R.string.maxvalueinpreferences)), this);
Integer maxBasalMult = SP.getInt("openapsama_current_basal_safety_multiplier", 4);
Integer maxBasalFromDaily = SP.getInt("openapsama_max_daily_safety_multiplier", 3);
// Check percentRate but absolute rate too, because we know real current basal in pump // Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate; Double maxBasalMult = SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
if (absoluteRate > maxBasal) { double maxFromBasalMult = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
absoluteRate = maxBasal; absoluteRate.setIfSmaller(maxFromBasalMult, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromBasalMult, MainApp.gs(R.string.maxbasalmultiplier)), this);
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origRate + " by maxBasal preference to " + absoluteRate + "U/h"); Double maxBasalFromDaily = SP.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d);
} double maxFromDaily = Math.floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100;
if (absoluteRate > maxBasalMult * profile.getBasal()) { absoluteRate.setIfSmaller(maxFromDaily, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromDaily, MainApp.gs(R.string.maxdailybasalmultiplier)), this);
absoluteRate = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit) absoluteRate.setIfSmaller(HardLimits.maxBasal(), String.format(MainApp.gs(R.string.limitingbasalratio), HardLimits.maxBasal(), MainApp.gs(R.string.hardlimit)), this);
log.debug("Limiting rate " + origRate + " by maxBasalMult to " + absoluteRate + "U/h");
}
if (absoluteRate > profile.getMaxDailyBasal() * maxBasalFromDaily) {
absoluteRate = profile.getMaxDailyBasal() * maxBasalFromDaily;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origRate + " by 3 * maxDailyBasal to " + absoluteRate + "U/h");
}
return absoluteRate; return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
Integer origPercentRate = percentRate;
Double maxBasal = SP.getDouble("openapsma_max_basal", 1d);
Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) return percentRate;
Double currentBasal = profile.getBasal(); Double currentBasal = profile.getBasal();
Double absoluteRate = currentBasal * ((double) percentRate.originalValue() / 100);
Double absoluteRate = currentBasal * ((double) percentRate / 100); percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this);
if (Config.logConstraintsChanges) Constraint<Double> absoluteConstraint = new Constraint<>(absoluteRate);
log.debug("Percent rate " + percentRate + "% recalculated to " + absoluteRate + "U/h with current basal " + currentBasal + "U/h"); applyBasalConstraints(absoluteConstraint, profile);
percentRate.copyReasons(absoluteConstraint);
if (absoluteRate < 0) absoluteRate = 0d; Integer percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue();
Integer maxBasalMult = SP.getInt("openapsama_current_basal_safety_multiplier", 4);
Integer maxBasalFromDaily = SP.getInt("openapsama_max_daily_safety_multiplier", 3);
// Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate;
if (absoluteRate > maxBasal) {
absoluteRate = maxBasal;
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting rate " + origRate + " by maxBasal preference to " + absoluteRate + "U/h");
}
if (absoluteRate > maxBasalMult * profile.getBasal()) {
absoluteRate = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting rate " + origRate + " by maxBasalMult to " + absoluteRate + "U/h");
}
if (absoluteRate > profile.getMaxDailyBasal() * maxBasalFromDaily) {
absoluteRate = profile.getMaxDailyBasal() * maxBasalFromDaily;
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting rate " + origRate + " by 3 * maxDailyBasal to " + absoluteRate + "U/h");
}
Integer percentRateAfterConst = new Double(absoluteRate / currentBasal * 100).intValue();
if (percentRateAfterConst < 100) if (percentRateAfterConst < 100)
percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, 10d).intValue(); percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, 10d).intValue();
else percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, 10d).intValue(); else percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, 10d).intValue();
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit)) percentRate.set(percentRateAfterConst, String.format(MainApp.gs(R.string.limitingpercentrate), percentRateAfterConst, MainApp.gs(R.string.pumplimit)), this);
log.debug("Recalculated percent rate " + percentRate + "% to " + percentRateAfterConst + "%");
return percentRateAfterConst; return percentRate;
} }
@Override @Override
public Double applyBolusConstraints(Double insulin) { public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
try { insulin.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingbolus), 0d, MainApp.gs(R.string.itmustbepositivevalue)), this);
Double maxBolus = SP.getDouble("treatmentssafety_maxbolus", 3d);
if (insulin < 0) insulin = 0d; Double maxBolus = SP.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
if (insulin > maxBolus) insulin = maxBolus; insulin.setIfSmaller(maxBolus, String.format(MainApp.gs(R.string.limitingbolus), maxBolus, MainApp.gs(R.string.maxvalueinpreferences)), this);
} catch (Exception e) {
insulin = 0d; insulin.setIfSmaller(HardLimits.maxBolus(), String.format(MainApp.gs(R.string.limitingbolus), HardLimits.maxBolus(), MainApp.gs(R.string.hardlimit)), this);
}
if (insulin > HardLimits.maxBolus()) insulin = HardLimits.maxBolus();
return insulin; return insulin;
} }
@Override @Override
public Integer applyCarbsConstraints(Integer carbs) { public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
try { carbs.setIfGreater(0, String.format(MainApp.gs(R.string.limitingcarbs), 0, MainApp.gs(R.string.itmustbepositivevalue)), this);
Integer maxCarbs = SP.getInt("treatmentssafety_maxcarbs", 48);
Integer maxCarbs = SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
carbs.setIfSmaller(maxCarbs, String.format(MainApp.gs(R.string.limitingcarbs), maxCarbs, MainApp.gs(R.string.maxvalueinpreferences)), this);
if (carbs < 0) carbs = 0;
if (carbs > maxCarbs) carbs = maxCarbs;
} catch (Exception e) {
carbs = 0;
}
return carbs; return carbs;
} }
@Override @Override
public Double applyMaxIOBConstraints(Double maxIob) { public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
double maxIobPref;
if (OpenAPSSMBPlugin.getPlugin().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(maxIobPref, String.format(MainApp.gs(R.string.limitingiob), maxIobPref, MainApp.gs(R.string.maxvalueinpreferences)), this);
if (OpenAPSMAPlugin.getPlugin().isEnabled(PluginType.APS))
maxIob.setIfSmaller(HardLimits.maxIobAMA(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobAMA(), MainApp.gs(R.string.hardlimit)), this);
if (OpenAPSAMAPlugin.getPlugin().isEnabled(PluginType.APS))
maxIob.setIfSmaller(HardLimits.maxIobAMA(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobAMA(), MainApp.gs(R.string.hardlimit)), this);
if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS))
maxIob.setIfSmaller(HardLimits.maxIobSMB(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobSMB(), MainApp.gs(R.string.hardlimit)), this);
return maxIob; return maxIob;
} }

View file

@ -1,21 +1,22 @@
package info.nightscout.androidaps.db; package info.nightscout.androidaps.plugins.Food;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger; import org.json.JSONException;
import org.slf4j.LoggerFactory; import org.json.JSONObject;
import java.util.Objects; import java.util.Objects;
import info.nightscout.utils.JsonHelper;
/** /**
* Created by mike on 20.09.2017. * Created by mike on 20.09.2017.
*/ */
@DatabaseTable(tableName = Food.TABLE_FOODS)
@DatabaseTable(tableName = DatabaseHelper.DATABASE_FOODS)
public class Food { public class Food {
private static Logger log = LoggerFactory.getLogger(Food.class); static final String TABLE_FOODS = "Foods";
@DatabaseField(id = true) @DatabaseField(id = true)
public long key; public long key;
@ -60,10 +61,29 @@ public class Food {
@DatabaseField @DatabaseField
public int gi; // not used yet public int gi; // not used yet
public Food() { private Food() {
key = System.currentTimeMillis(); key = System.currentTimeMillis();
} }
public static Food createFromJson(JSONObject json) throws JSONException {
Food food = new Food();
if ("food".equals(JsonHelper.safeGetString(json, "type"))) {
food._id = JsonHelper.safeGetString(json, "_id");
food.category = JsonHelper.safeGetString(json, "category");
food.subcategory = JsonHelper.safeGetString(json, "subcategory");
food.name = JsonHelper.safeGetString(json, "name");
food.units = JsonHelper.safeGetString(json, "unit");
food.portion = JsonHelper.safeGetDouble(json, "portion");
food.carbs = JsonHelper.safeGetInt(json, "carbs");
food.gi = JsonHelper.safeGetInt(json, "gi");
food.energy = JsonHelper.safeGetInt(json, "energy");
food.protein = JsonHelper.safeGetInt(json, "protein");
food.fat = JsonHelper.safeGetInt(json, "fat");
}
return food;
}
public boolean isEqual(Food other) { public boolean isEqual(Food other) {
if (portion != other.portion) if (portion != other.portion)
return false; return false;
@ -104,4 +124,22 @@ public class Food {
units = other.units; units = other.units;
gi = other.gi; gi = other.gi;
} }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("_id=" + _id + ";");
sb.append("isValid=" + isValid + ";");
sb.append("name=" + name + ";");
sb.append("category=" + category + ";");
sb.append("subcategory=" + subcategory + ";");
sb.append("portion=" + portion + ";");
sb.append("carbs=" + carbs + ";");
sb.append("protein=" + protein + ";");
sb.append("energy=" + energy + ";");
sb.append("units=" + units + ";");
sb.append("gi=" + gi + ";");
return sb.toString();
}
} }

View file

@ -18,7 +18,6 @@ import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -27,12 +26,13 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.Food;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged; import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SpinnerHelper; import info.nightscout.utils.SpinnerHelper;
@ -121,7 +121,8 @@ public class FoodFragment extends SubscriberFragment {
} }
}); });
RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().foodHelper.getFoodData()); RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp
.getSpecificPlugin(FoodPlugin.class).getService().getFoodData());
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
loadData(); loadData();
@ -130,7 +131,7 @@ public class FoodFragment extends SubscriberFragment {
filterData(); filterData();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
@ -144,20 +145,19 @@ public class FoodFragment extends SubscriberFragment {
} }
void loadData() { void loadData() {
unfiltered = MainApp.getDbHelper().foodHelper.getFoodData(); unfiltered = MainApp.getSpecificPlugin(FoodPlugin.class).getService().getFoodData();
} }
void fillCategories() { void fillCategories() {
categories = new ArrayList<>(); Set<CharSequence> catSet = new HashSet<>();
for (Food f : unfiltered) { for (Food f : unfiltered) {
if (f.category != null && !f.category.equals("")) if (f.category != null && !f.category.equals(""))
categories.add(f.category); catSet.add(f.category);
} }
// make it unique // make it unique
categories = new ArrayList<>(new HashSet<>(categories)); categories = new ArrayList<>(catSet);
categories.add(0, MainApp.sResources.getString(R.string.none)); categories.add(0, MainApp.sResources.getString(R.string.none));
ArrayAdapter<CharSequence> adapterCategories = new ArrayAdapter<>(getContext(), ArrayAdapter<CharSequence> adapterCategories = new ArrayAdapter<>(getContext(),
@ -167,19 +167,19 @@ public class FoodFragment extends SubscriberFragment {
void fillSubcategories() { void fillSubcategories() {
String categoryFilter = category.getSelectedItem().toString(); String categoryFilter = category.getSelectedItem().toString();
subcategories = new ArrayList<>();
Set<CharSequence> subCatSet = new HashSet<>();
if (!categoryFilter.equals(EMPTY)) { if (!categoryFilter.equals(EMPTY)) {
for (Food f : unfiltered) { for (Food f : unfiltered) {
if (f.category != null && f.category.equals(categoryFilter)) if (f.category != null && f.category.equals(categoryFilter))
if (f.subcategory != null && !f.subcategory.equals("")) if (f.subcategory != null && !f.subcategory.equals(""))
subcategories.add(f.subcategory); subCatSet.add(f.subcategory);
} }
} }
// make it unique // make it unique
subcategories = new ArrayList<>(new HashSet<>(subcategories)); subcategories = new ArrayList<>(subCatSet);
subcategories.add(0, MainApp.sResources.getString(R.string.none)); subcategories.add(0, MainApp.sResources.getString(R.string.none));
ArrayAdapter<CharSequence> adapterSubcategories = new ArrayAdapter<>(getContext(), ArrayAdapter<CharSequence> adapterSubcategories = new ArrayAdapter<>(getContext(),
@ -299,7 +299,7 @@ public class FoodFragment extends SubscriberFragment {
if (_id != null && !_id.equals("")) { if (_id != null && !_id.equals("")) {
NSUpload.removeFoodFromNS(_id); NSUpload.removeFoodFromNS(_id);
} }
MainApp.getDbHelper().foodHelper.delete(food); MainApp.getSpecificPlugin(FoodPlugin.class).getService().delete(food);
} }
}); });
builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null); builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null);

View file

@ -1,15 +1,14 @@
package info.nightscout.androidaps.plugins.Food; package info.nightscout.androidaps.plugins.Food;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class FoodPlugin implements PluginBase { public class FoodPlugin extends PluginBase {
private boolean fragmentEnabled = true;
private boolean fragmentVisible = false;
private static FoodPlugin plugin = null; private static FoodPlugin plugin = null;
@ -19,67 +18,20 @@ public class FoodPlugin implements PluginBase {
return plugin; return plugin;
} }
@Override private FoodService service;
public String getFragmentClass() {
return FoodFragment.class.getName(); private FoodPlugin() {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(FoodFragment.class.getName())
.pluginName(R.string.food)
.shortName(R.string.food_short)
);
this.service = new FoodService();
} }
@Override public FoodService getService() {
public int getType() { return this.service;
return PluginBase.GENERAL;
} }
@Override
public String getName() {
return MainApp.instance().getString(R.string.food);
}
@Override
public String getNameShort() {
// use long name as fallback (not visible in tabs)
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == GENERAL && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
} }

View file

@ -0,0 +1,369 @@
package info.nightscout.androidaps.plugins.Food;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.j256.ormlite.android.apptools.OrmLiteBaseService;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import com.squareup.otto.Subscribe;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.ICallback;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.events.EventNsFood;
/**
* Created by mike on 24.09.2017.
*/
public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
private static Logger log = LoggerFactory.getLogger(FoodService.class);
private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledFoodEventPost = null;
public FoodService() {
onCreate();
dbInitialize();
MainApp.bus().register(this);
}
/**
* This method is a simple re-implementation of the database create and up/downgrade functionality
* in SQLiteOpenHelper#getDatabaseLocked method.
* <p>
* It is implemented to be able to late initialize separate plugins of the application.
*/
protected void dbInitialize() {
DatabaseHelper helper = OpenHelperManager.getHelper(this, DatabaseHelper.class);
int newVersion = helper.getNewVersion();
int oldVersion = helper.getOldVersion();
if (oldVersion > newVersion) {
onDowngrade(this.getConnectionSource(), oldVersion, newVersion);
} else {
onUpgrade(this.getConnectionSource(), oldVersion, newVersion);
}
}
public Dao<Food, Long> getDao() {
try {
return DaoManager.createDao(this.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Cannot create Dao for Food.class");
}
return null;
}
@Subscribe
public void handleNsEvent(EventNsFood event) {
int mode = event.getMode();
Bundle payload = event.getPayload();
try {
if (payload.containsKey("food")) {
JSONObject json = new JSONObject(payload.getString("food"));
if (mode == EventNsFood.ADD || mode == EventNsFood.UPDATE) {
this.createFoodFromJsonIfNotExists(json);
} else {
this.deleteNS(json);
}
}
if (payload.containsKey("foods")) {
JSONArray array = new JSONArray(payload.getString("foods"));
if (mode == EventNsFood.ADD || mode == EventNsFood.UPDATE) {
this.createFoodFromJsonIfNotExists(array);
} else {
this.deleteNS(array);
}
}
} catch (JSONException e) {
log.error("Unhandled Exception", e);
}
}
@Override
public void onCreate() {
super.onCreate();
try {
log.info("onCreate");
TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Can't create database", e);
throw new RuntimeException(e);
}
}
public void onUpgrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
if (oldVersion == 7 && newVersion == 8) {
log.debug("Upgrading database from v7 to v8");
} else {
log.info("onUpgrade");
// this.resetFood();
}
}
public void onDowngrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
// this method is not supported right now
}
public void resetFood() {
try {
TableUtils.dropTable(this.getConnectionSource(), Food.class, true);
TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleFoodChange();
}
/**
* A place to centrally register events to be posted, if any data changed.
* This should be implemented in an abstract service-class.
* <p>
* We do need to make sure, that ICallback is extended to be able to handle multiple
* events, or handle a list of events.
* <p>
* on some methods the earliestDataChange event is handled separatly, in that it is checked if it is
* set to null by another event already (eg. scheduleExtendedBolusChange).
*
* @param event
* @param eventWorker
* @param callback
*/
private void scheduleEvent(final Event event, ScheduledExecutorService eventWorker,
final ICallback callback) {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventFoodChange");
MainApp.bus().post(event);
callback.setPost(null);
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (callback.getPost() != null)
callback.getPost().cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
callback.setPost(eventWorker.schedule(task, sec, TimeUnit.SECONDS));
}
/**
* Schedule a foodChange Event.
*/
public void scheduleFoodChange() {
this.scheduleEvent(new EventFoodDatabaseChanged(), foodEventWorker, new ICallback() {
@Override
public void setPost(ScheduledFuture<?> post) {
scheduledFoodEventPost = post;
}
@Override
public ScheduledFuture<?> getPost() {
return scheduledFoodEventPost;
}
});
}
public List<Food> getFoodData() {
try {
return this.getDao().queryForAll();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
/*
{
"_id": "551ee3ad368e06e80856e6a9",
"type": "food",
"category": "Zakladni",
"subcategory": "Napoje",
"name": "Mleko",
"portion": 250,
"carbs": 12,
"gi": 1,
"created_at": "2015-04-14T06:59:16.500Z",
"unit": "ml"
}
*/
public void createFoodFromJsonIfNotExists(JSONObject json) {
try {
Food food = Food.createFromJson(json);
this.createFoodFromJsonIfNotExists(food);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
public void createFoodFromJsonIfNotExists(JSONArray array) {
try {
for (int n = 0; n < array.length(); n++) {
JSONObject json = array.getJSONObject(n);
Food food = Food.createFromJson(json);
this.createFoodFromJsonIfNotExists(food);
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
public void createFoodFromJsonIfNotExists(Food food) {
this.createOrUpdateByNS(food);
}
public void deleteNS(JSONObject json) {
try {
String _id = json.getString("_id");
this.deleteByNSId(_id);
} catch (JSONException | SQLException e) {
log.error("Unhandled exception", e);
}
}
public void deleteNS(JSONArray array) {
try {
for (int n = 0; n < array.length(); n++) {
JSONObject json = array.getJSONObject(n);
this.deleteNS(json);
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
/**
* deletes an entry by its NS Id.
* <p>
* Basically a convenience method for findByNSId and delete.
*
* @param _id
*/
public void deleteByNSId(String _id) throws SQLException {
Food stored = this.findByNSId(_id);
if (stored != null) {
log.debug("FOOD: Removing Food record from database: " + stored.toString());
this.delete(stored);
}
}
/**
* deletes the food and sends the foodChange Event
* <p>
* should be moved ot a Service
*
* @param food
*/
public void delete(Food food) {
try {
this.getDao().delete(food);
this.scheduleFoodChange();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
/**
* Create of update a food record by the NS (Nightscout) Id.
*
* @param food
* @return
*/
public boolean createOrUpdateByNS(Food food) {
// find by NS _id
if (food._id != null && !food._id.equals("")) {
Food old = this.findByNSId(food._id);
if (old != null) {
if (!old.isEqual(food)) {
this.delete(old); // need to delete/create because date may change too
old.copyFrom(food);
this.create(old);
return true;
} else {
return false;
}
} else {
this.createOrUpdate(food);
return true;
}
}
return false;
}
public void createOrUpdate(Food food) {
try {
this.getDao().createOrUpdate(food);
log.debug("FOOD: Created or Updated: " + food.toString());
} catch (SQLException e) {
log.error("Unable to createOrUpdate Food", e);
}
this.scheduleFoodChange();
}
public void create(Food food) {
try {
this.getDao().create(food);
log.debug("FOOD: New record: " + food.toString());
} catch (SQLException e) {
log.error("Unable to create Food", e);
}
this.scheduleFoodChange();
}
/**
* finds food by its NS Id.
*
* @param _id
* @return
*/
@Nullable
public Food findByNSId(String _id) {
try {
List<Food> list = this.getDao().queryForEq("_id", _id);
if (list.size() == 1) { // really? if there are more then one result, then we do not return anything...
return list.get(0);
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

View file

@ -12,7 +12,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
/** /**

View file

@ -1,136 +0,0 @@
package info.nightscout.androidaps.plugins.Insulin;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
/**
* Created by mike on 17.04.2017.
*/
public class InsulinFastactingPlugin implements PluginBase, InsulinInterface {
private boolean fragmentEnabled = true;
private boolean fragmentVisible = false;
private static InsulinFastactingPlugin plugin = null;
public static InsulinFastactingPlugin getPlugin() {
if (plugin == null)
plugin = new InsulinFastactingPlugin();
return plugin;
}
@Override
public int getType() {
return INSULIN;
}
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.fastactinginsulin);
}
@Override
public String getNameShort() {
return MainApp.sResources.getString(R.string.insulin_shortname);
}
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
// Insulin interface
@Override
public int getId() {
return FASTACTINGINSULIN;
}
@Override
public String getFriendlyName() {
return MainApp.sResources.getString(R.string.fastactinginsulin);
}
@Override
public String getComment() {
return MainApp.sResources.getString(R.string.fastactinginsulincomment);
}
@Override
public double getDia() {
return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : Constants.defaultDIA;
}
@Override
public Iob iobCalcForTreatment(Treatment treatment, long time, double dia) {
Iob result = new Iob();
double scaleFactor = 3.0 / dia;
double peak = 75d;
double end = 180d;
if (treatment.insulin != 0d) {
long bolusTime = treatment.date;
double minAgo = scaleFactor * (time - bolusTime) / 1000d / 60d;
if (minAgo < peak) {
double x1 = minAgo / 5d + 1;
result.iobContrib = treatment.insulin * (1 - 0.001852 * x1 * x1 + 0.001852 * x1);
// units: BG (mg/dL) = (BG/U) * U insulin * scalar
result.activityContrib = treatment.insulin * (2 / dia / 60 / peak) * minAgo;
} else if (minAgo < end) {
double x2 = (minAgo - 75) / 5;
result.iobContrib = treatment.insulin * (0.001323 * x2 * x2 - 0.054233 * x2 + 0.55556);
result.activityContrib = treatment.insulin * (2 / dia / 60 - (minAgo - peak) * 2 / dia / 60 / (60 * 3 - peak));
}
}
return result;
}
}

View file

@ -1,141 +0,0 @@
package info.nightscout.androidaps.plugins.Insulin;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
/**
* Created by mike on 17.04.2017.
*/
public class InsulinFastactingProlongedPlugin implements PluginBase, InsulinInterface {
private boolean fragmentEnabled = false;
private boolean fragmentVisible = false;
private static InsulinFastactingProlongedPlugin plugin = null;
public static InsulinFastactingProlongedPlugin getPlugin() {
if (plugin == null)
plugin = new InsulinFastactingProlongedPlugin();
return plugin;
}
@Override
public int getType() {
return INSULIN;
}
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.fastactinginsulinprolonged);
}
@Override
public String getNameShort() {
return MainApp.sResources.getString(R.string.insulin_shortname);
}
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
// Insulin interface
@Override
public int getId() {
return FASTACTINGINSULINPROLONGED;
}
@Override
public String getFriendlyName() {
return MainApp.sResources.getString(R.string.fastactinginsulinprolonged);
}
@Override
public String getComment() {
return MainApp.sResources.getString(R.string.fastactinginsulincomment);
}
@Override
public double getDia() {
return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : Constants.defaultDIA;
}
@Override
public Iob iobCalcForTreatment(Treatment treatment, long time, double dia) {
Iob result = new Iob();
//Double scaleFactor = 3.0 / dia;
double peak = 75d * dia / 6.0;
double tail = 180d * dia / 6.0;
double end = 360d * dia / 6.0;
double Total = 2 * peak + (tail - peak) * 5 / 2 + (end - tail) / 2;
if (treatment.insulin != 0d) {
long bolusTime = treatment.date;
double minAgo = (time - bolusTime) / 1000d / 60d;
if (minAgo < peak) {
double x1 = 6 / dia * minAgo / 5d + 1;
result.iobContrib = treatment.insulin * (1 - 0.0012595 * x1 * x1 + 0.0012595 * x1);
// units: BG (mg/dL) = (BG/U) * U insulin * scalar
result.activityContrib = treatment.insulin * ((2 * peak / Total) * 2 / peak / peak * minAgo);
} else if (minAgo < tail) {
double x2 = (6 / dia * (minAgo - peak)) / 5;
result.iobContrib = treatment.insulin * (0.00074 * x2 * x2 - 0.0403 * x2 + 0.69772);
result.activityContrib = treatment.insulin * (-((2 * peak / Total) * 2 / peak * 3 / 4) / (tail - peak) * (minAgo - peak) + (2 * peak / Total) * 2 / peak);
} else if (minAgo < end) {
double x3 = (6 / dia * (minAgo - tail)) / 5;
result.iobContrib = treatment.insulin * (0.0001323 * x3 * x3 - 0.0097 * x3 + 0.17776);
result.activityContrib = treatment.insulin * (-((2 * peak / Total) * 2 / peak * 1 / 4) / (end - tail) * (minAgo - tail) + (2 * peak / Total) * 2 / peak / 4);
}
}
return result;
}
}

View file

@ -7,11 +7,11 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.utils.FabricPrivacy;
/** /**
* Created by mike on 17.04.2017. * Created by mike on 17.04.2017.
@ -37,7 +37,7 @@ public class InsulinFragment extends Fragment {
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;

View file

@ -5,45 +5,31 @@ import com.squareup.otto.Bus;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
/** /**
* Created by adrian on 13.08.2017. * Created by adrian on 13.08.2017.
*/ */
public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterface { public abstract class InsulinOrefBasePlugin extends PluginBase implements InsulinInterface {
public static double MIN_DIA = 5; public static double MIN_DIA = 5;
long lastWarned = 0; long lastWarned = 0;
@Override public InsulinOrefBasePlugin() {
public int getType() { super(new PluginDescription()
return INSULIN; .mainType(PluginType.INSULIN)
} .fragmentClass(InsulinFragment.class.getName())
.pluginName(R.string.fastactinginsulin)
@Override .shortName(R.string.insulin_shortname)
public String getNameShort() { );
return MainApp.sResources.getString(R.string.insulin_shortname);
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
} }
public Bus getBus() { public Bus getBus() {
@ -53,7 +39,7 @@ public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterf
@Override @Override
public double getDia() { public double getDia() {
double dia = getUserDefinedDia(); double dia = getUserDefinedDia();
if(dia >= MIN_DIA){ if (dia >= MIN_DIA) {
return dia; return dia;
} else { } else {
sendShortDiaNotification(dia); sendShortDiaNotification(dia);
@ -62,7 +48,7 @@ public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterf
} }
void sendShortDiaNotification(double dia) { void sendShortDiaNotification(double dia) {
if((System.currentTimeMillis() - lastWarned) > 60*1000) { if ((System.currentTimeMillis() - lastWarned) > 60 * 1000) {
lastWarned = System.currentTimeMillis(); lastWarned = System.currentTimeMillis();
Notification notification = new Notification(Notification.SHORT_DIA, String.format(this.getNotificationPattern(), dia, MIN_DIA), Notification.URGENT); Notification notification = new Notification(Notification.SHORT_DIA, String.format(this.getNotificationPattern(), dia, MIN_DIA), Notification.URGENT);
this.getBus().post(new EventNewNotification(notification)); this.getBus().post(new EventNewNotification(notification));
@ -92,7 +78,7 @@ public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterf
long bolusTime = treatment.date; long bolusTime = treatment.date;
double t = (time - bolusTime) / 1000d / 60d; double t = (time - bolusTime) / 1000d / 60d;
double td = getDia()*60; //getDIA() always >= MIN_DIA double td = getDia() * 60; //getDIA() always >= MIN_DIA
double tp = peak; double tp = peak;
// force the IOB to 0 if over DIA hours have passed // force the IOB to 0 if over DIA hours have passed
@ -109,9 +95,9 @@ public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterf
@Override @Override
public String getComment() { public String getComment() {
String comment = commentStandardText(); String comment = commentStandardText();
double userDia = getUserDefinedDia(); double userDia = getUserDefinedDia();
if(userDia < MIN_DIA){ if (userDia < MIN_DIA) {
comment += "\n" + String.format(MainApp.sResources.getString(R.string.dia_too_short), userDia, MIN_DIA); comment += "\n" + String.format(MainApp.sResources.getString(R.string.dia_too_short), userDia, MIN_DIA);
} }
return comment; return comment;

View file

@ -10,9 +10,6 @@ import info.nightscout.utils.SP;
public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin { public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin {
private boolean fragmentEnabled = false;
private boolean fragmentVisible = false;
private static InsulinOrefFreePeakPlugin plugin = null; private static InsulinOrefFreePeakPlugin plugin = null;
public static InsulinOrefFreePeakPlugin getPlugin() { public static InsulinOrefFreePeakPlugin getPlugin() {
@ -21,24 +18,20 @@ public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin {
return plugin; return plugin;
} }
public static final int DEFAULT_PEAK = 75; private static final int DEFAULT_PEAK = 75;
private InsulinOrefFreePeakPlugin() {
super();
pluginDescription
.pluginName(R.string.free_peak_oref)
.preferencesId(R.xml.pref_insulinoreffreepeak);
}
@Override @Override
public int getId() { public int getId() {
return OREF_FREE_PEAK; return OREF_FREE_PEAK;
} }
@Override
public String getName() {
return MainApp.sResources.getString(R.string.free_peak_oref);
}
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override
public String getFriendlyName() { public String getFriendlyName() {
return MainApp.sResources.getString(R.string.free_peak_oref); return MainApp.sResources.getString(R.string.free_peak_oref);
} }
@ -48,31 +41,6 @@ public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin {
return MainApp.sResources.getString(R.string.insulin_peak_time) + ": " + getPeak(); return MainApp.sResources.getString(R.string.insulin_peak_time) + ": " + getPeak();
} }
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_insulinoreffreepeak;
}
@Override @Override
int getPeak() { int getPeak() {
return SP.getInt(R.string.key_insulin_oref_peak, DEFAULT_PEAK); return SP.getInt(R.string.key_insulin_oref_peak, DEFAULT_PEAK);

View file

@ -9,9 +9,6 @@ import info.nightscout.androidaps.R;
public class InsulinOrefRapidActingPlugin extends InsulinOrefBasePlugin { public class InsulinOrefRapidActingPlugin extends InsulinOrefBasePlugin {
private boolean fragmentEnabled = false;
private boolean fragmentVisible = false;
private static InsulinOrefRapidActingPlugin plugin = null; private static InsulinOrefRapidActingPlugin plugin = null;
public static InsulinOrefRapidActingPlugin getPlugin() { public static InsulinOrefRapidActingPlugin getPlugin() {
@ -20,23 +17,19 @@ public class InsulinOrefRapidActingPlugin extends InsulinOrefBasePlugin {
return plugin; return plugin;
} }
public static final int PEAK = 75; private static final int PEAK = 75;
private InsulinOrefRapidActingPlugin() {
super();
pluginDescription
.pluginName(R.string.rapid_acting_oref);
}
@Override @Override
public int getId() { public int getId() {
return OREF_RAPID_ACTING; return OREF_RAPID_ACTING;
} }
@Override
public String getName() {
return MainApp.sResources.getString(R.string.rapid_acting_oref);
}
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override @Override
public String getFriendlyName() { public String getFriendlyName() {
return MainApp.sResources.getString(R.string.rapid_acting_oref); return MainApp.sResources.getString(R.string.rapid_acting_oref);
@ -47,31 +40,6 @@ public class InsulinOrefRapidActingPlugin extends InsulinOrefBasePlugin {
return MainApp.sResources.getString(R.string.fastactinginsulincomment); return MainApp.sResources.getString(R.string.fastactinginsulincomment);
} }
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
@Override @Override
int getPeak() { int getPeak() {
return PEAK; return PEAK;

View file

@ -9,9 +9,6 @@ import info.nightscout.androidaps.R;
public class InsulinOrefUltraRapidActingPlugin extends InsulinOrefBasePlugin { public class InsulinOrefUltraRapidActingPlugin extends InsulinOrefBasePlugin {
private boolean fragmentEnabled = false;
private boolean fragmentVisible = false;
private static InsulinOrefUltraRapidActingPlugin plugin = null; private static InsulinOrefUltraRapidActingPlugin plugin = null;
public static InsulinOrefUltraRapidActingPlugin getPlugin() { public static InsulinOrefUltraRapidActingPlugin getPlugin() {
@ -20,7 +17,13 @@ public class InsulinOrefUltraRapidActingPlugin extends InsulinOrefBasePlugin {
return plugin; return plugin;
} }
public static final int PEAK = 55; private static final int PEAK = 55;
private InsulinOrefUltraRapidActingPlugin() {
super();
pluginDescription
.pluginName(R.string.ultrarapid_oref);
}
@Override @Override
public int getId() { public int getId() {
@ -32,11 +35,6 @@ public class InsulinOrefUltraRapidActingPlugin extends InsulinOrefBasePlugin {
return MainApp.sResources.getString(R.string.ultrarapid_oref); return MainApp.sResources.getString(R.string.ultrarapid_oref);
} }
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override @Override
public String getFriendlyName() { public String getFriendlyName() {
return MainApp.sResources.getString(R.string.ultrarapid_oref); return MainApp.sResources.getString(R.string.ultrarapid_oref);
@ -47,31 +45,6 @@ public class InsulinOrefUltraRapidActingPlugin extends InsulinOrefBasePlugin {
return MainApp.sResources.getString(R.string.ultrafastactinginsulincomment); return MainApp.sResources.getString(R.string.ultrafastactinginsulincomment);
} }
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
@Override @Override
int getPeak() { int getPeak() {
return PEAK; return PEAK;

View file

@ -7,22 +7,31 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.Scale;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
/** /**
* Created by mike on 25.04.2017. * Created by mike on 25.04.2017.
*/ */
public class AutosensData { public class AutosensData implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(AutosensData.class); private static Logger log = LoggerFactory.getLogger(AutosensData.class);
public void setChartTime(long chartTime) {
this.chartTime = chartTime;
}
static class CarbsInPast { static class CarbsInPast {
long time = 0L; long time = 0L;
double carbs = 0d; double carbs = 0d;
@ -33,20 +42,21 @@ public class AutosensData {
time = t.date; time = t.date;
carbs = t.carbs; carbs = t.carbs;
remaining = t.carbs; remaining = t.carbs;
if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginBase.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginBase.SENSITIVITY)) { if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
double maxAbsorptionHours = SP.getDouble(R.string.key_absorption_maxtime, 4d); double maxAbsorptionHours = SP.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME);
Profile profile = MainApp.getConfigBuilder().getProfile(t.date); Profile profile = MainApp.getConfigBuilder().getProfile(t.date);
double sens = Profile.toMgdl(profile.getIsf(t.date), profile.getUnits()); double sens = Profile.toMgdl(profile.getIsf(t.date), profile.getUnits());
double ic = profile.getIc(t.date); double ic = profile.getIc(t.date);
min5minCarbImpact = t.carbs / (maxAbsorptionHours * 60 / 5) * sens / ic; min5minCarbImpact = t.carbs / (maxAbsorptionHours * 60 / 5) * sens / ic;
log.debug("Min 5m carbs impact for " + carbs + "g @" + new Date(t.date).toLocaleString() + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic); log.debug("Min 5m carbs impact for " + carbs + "g @" + new Date(t.date).toLocaleString() + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic);
} else { } else {
min5minCarbImpact = SP.getDouble("openapsama_min_5m_carbimpact", 3.0); min5minCarbImpact = SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
} }
} }
} }
public long time = 0L; public long time = 0L;
long chartTime;
public String pastSensitivity = ""; public String pastSensitivity = "";
public double deviation = 0d; public double deviation = 0d;
boolean nonCarbsDeviation = false; boolean nonCarbsDeviation = false;
@ -57,26 +67,39 @@ public class AutosensData {
public double cob = 0; public double cob = 0;
public double bgi = 0d; public double bgi = 0d;
public double delta = 0d; public double delta = 0d;
public double avgDelta = 0d;
public double avgDeviation = 0d;
public double autosensRatio = 1d; public double autosensRatio = 1d;
public double slopeFromMaxDeviation = 0;
public double slopeFromMinDeviation = 999;
public double usedMinCarbsImpact = 0d;
public boolean failoverToMinAbsorbtionRate = false;
public String log(long time) { @Override
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " Bgi=" + bgi + " Deviation=" + deviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio; public String toString() {
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " avgDelta=" + avgDelta + " Bgi=" + bgi + " Deviation=" + deviation + " avgDeviation=" + avgDeviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation =" + slopeFromMinDeviation;
} }
public int minOld() { public int minOld() {
return (int) ((System.currentTimeMillis() - time) / 1000 / 60); return (int) ((System.currentTimeMillis() - time) / 1000 / 60);
} }
// remove carbs older than 4h // remove carbs older than timeframe
public void removeOldCarbs(long toTime) { public void removeOldCarbs(long toTime) {
double maxAbsorptionHours = Constants.DEFAULT_MAX_ABSORPTION_TIME;
if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
maxAbsorptionHours = SP.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME);
} else {
maxAbsorptionHours = SP.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME);
}
for (int i = 0; i < activeCarbsList.size(); i++) { for (int i = 0; i < activeCarbsList.size(); i++) {
CarbsInPast c = activeCarbsList.get(i); CarbsInPast c = activeCarbsList.get(i);
if (c.time + 4 * 60 * 60 * 1000L < toTime) { if (c.time + maxAbsorptionHours * 60 * 60 * 1000L < toTime) {
activeCarbsList.remove(i--); activeCarbsList.remove(i--);
if (c.remaining > 0) if (c.remaining > 0)
cob -= c.remaining; cob -= c.remaining;
log.debug("Removing carbs at "+ new Date(toTime).toLocaleString() + " + after 4h :" + new Date(c.time).toLocaleString()); log.debug("Removing carbs at " + new Date(toTime).toLocaleString() + " + after " + maxAbsorptionHours + "h :" + new Date(c.time).toLocaleString());
} }
} }
} }
@ -93,4 +116,57 @@ public class AutosensData {
} }
} }
// ------- DataPointWithLabelInterface ------
private Scale scale;
public void setScale(Scale scale) {
this.scale = scale;
}
@Override
public double getX() {
return chartTime;
}
@Override
public double getY() {
return scale.transform(cob);
}
@Override
public void setY(double y) {
}
@Override
public String getLabel() {
return null;
}
@Override
public long getDuration() {
return 0;
}
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
return PointsWithLabelGraphSeries.Shape.COBFAILOVER;
}
@Override
public float getSize() {
return 0.5f;
}
@Override
public int getColor() {
return MainApp.gc(R.color.cob);
}
@Override
public int getSecondColor() {
return 0;
}
} }

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.plugins.IobCobCalculator;
import android.support.annotation.Nullable;
public class CobInfo {
/** All COB up to now, including carbs not yet processed by IobCob calculation. */
@Nullable
public final Double displayCob;
public final double futureCarbs;
public CobInfo(@Nullable Double displayCob, double futureCarbs) {
this.displayCob = displayCob;
this.futureCarbs = futureCarbs;
}
}

View file

@ -22,36 +22,30 @@ import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventAppInitialized; import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventConfigBuilderChange;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import static info.nightscout.utils.DateUtil.now;
/** /**
* Created by mike on 24.04.2017. * Created by mike on 24.04.2017.
*/ */
public class IobCobCalculatorPlugin implements PluginBase { public class IobCobCalculatorPlugin extends PluginBase {
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class); private Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
private static LongSparseArray<IobTotal> iobTable = new LongSparseArray<>(); // oldest at index 0
private static LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
private static LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0
private static volatile List<BgReading> bgReadings = null; // newest at index 0
private static volatile List<BgReading> bucketed_data = null;
private static double dia = Constants.defaultDIA;
static final Object dataLock = new Object();
boolean stopCalculationTrigger = false;
IobCobThread thread = null;
private static IobCobCalculatorPlugin plugin = null; private static IobCobCalculatorPlugin plugin = null;
@ -61,80 +55,52 @@ public class IobCobCalculatorPlugin implements PluginBase {
return plugin; return plugin;
} }
public static LongSparseArray<AutosensData> getAutosensDataTable() { private LongSparseArray<IobTotal> iobTable = new LongSparseArray<>(); // oldest at index 0
private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0
private volatile List<BgReading> bgReadings = null; // newest at index 0
private volatile List<BgReading> bucketed_data = null;
private double dia = Constants.defaultDIA;
final Object dataLock = new Object();
boolean stopCalculationTrigger = false;
private IobCobThread thread = null;
public IobCobCalculatorPlugin() {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
.pluginName(R.string.iobcobcalculator)
.showInList(false)
.neverVisible(true)
.alwaysEnabled(true)
);
}
@Override
protected void onStart() {
MainApp.bus().register(this);
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
MainApp.bus().unregister(this);
}
public LongSparseArray<AutosensData> getAutosensDataTable() {
return autosensDataTable; return autosensDataTable;
} }
public static List<BgReading> getBucketedData() { public List<BgReading> getBucketedData() {
return bucketed_data; return bucketed_data;
} }
@Override
public int getType() {
return GENERAL;
}
@Override
public String getFragmentClass() {
return null;
}
@Override
public String getName() {
return "IOB COB Calculator";
}
@Override
public String getNameShort() {
return "IOC";
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL;
}
@Override
public boolean isVisibleInTabs(int type) {
return false;
}
@Override
public boolean canBeHidden(int type) {
return false;
}
@Override
public boolean hasFragment() {
return false;
}
@Override
public boolean showInList(int type) {
return false;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
}
@Override
public int getPreferencesId() {
return -1;
}
IobCobCalculatorPlugin() {
MainApp.bus().register(this);
}
@Nullable @Nullable
public static List<BgReading> getBucketedData(long fromTime) { public List<BgReading> getBucketedData(long fromTime) {
//log.debug("Locking getBucketedData"); //log.debug("Locking getBucketedData");
synchronized (dataLock) { synchronized (dataLock) {
if (bucketed_data == null) { if (bucketed_data == null) {
@ -152,7 +118,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
return null; return null;
} }
private static int indexNewerThan(long time) { private int indexNewerThan(long time) {
for (int index = 0; index < bucketed_data.size(); index++) { for (int index = 0; index < bucketed_data.size(); index++) {
if (bucketed_data.get(index).date < time) if (bucketed_data.get(index).date < time)
return index - 1; return index - 1;
@ -167,9 +133,9 @@ public class IobCobCalculatorPlugin implements PluginBase {
return rouded; return rouded;
} }
void loadBgData() { void loadBgData(long start) {
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)), false); bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (start - 60 * 60 * 1000L * (24 + dia)), false);
log.debug("BG data loaded. Size: " + bgReadings.size()); log.debug("BG data loaded. Size: " + bgReadings.size() + " Start date: " + DateUtil.dateAndTimeString(start));
} }
private boolean isAbout5minData() { private boolean isAbout5minData() {
@ -259,7 +225,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
public void createBucketedData5min() { private void createBucketedData5min() {
if (bgReadings == null || bgReadings.size() < 3) { if (bgReadings == null || bgReadings.size() < 3) {
bucketed_data = null; bucketed_data = null;
return; return;
@ -321,22 +287,22 @@ public class IobCobCalculatorPlugin implements PluginBase {
log.debug("Bucketed data created. Size: " + bucketed_data.size()); log.debug("Bucketed data created. Size: " + bucketed_data.size());
} }
public static long oldestDataAvailable() { public long oldestDataAvailable() {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long oldestDataAvailable = MainApp.getConfigBuilder().oldestDataAvailable(); long oldestDataAvailable = TreatmentsPlugin.getPlugin().oldestDataAvailable();
long getBGDataFrom = Math.max(oldestDataAvailable, (long) (now - 60 * 60 * 1000L * (24 + MainApp.getConfigBuilder().getProfile().getDia()))); long getBGDataFrom = Math.max(oldestDataAvailable, (long) (now - 60 * 60 * 1000L * (24 + MainApp.getConfigBuilder().getProfile().getDia())));
log.debug("Limiting data to oldest available temps: " + new Date(oldestDataAvailable).toString()); log.debug("Limiting data to oldest available temps: " + new Date(oldestDataAvailable).toString());
return getBGDataFrom; return getBGDataFrom;
} }
public static IobTotal calculateFromTreatmentsAndTempsSynchronized(long time) { public IobTotal calculateFromTreatmentsAndTempsSynchronized(long time, Profile profile) {
synchronized (dataLock) { synchronized (dataLock) {
return calculateFromTreatmentsAndTemps(time); return calculateFromTreatmentsAndTemps(time, profile);
} }
} }
public static IobTotal calculateFromTreatmentsAndTemps(long time) { public IobTotal calculateFromTreatmentsAndTemps(long time, Profile profile) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
time = roundUpTime(time); time = roundUpTime(time);
if (time < now && iobTable.get(time) != null) { if (time < now && iobTable.get(time) != null) {
@ -345,8 +311,22 @@ public class IobCobCalculatorPlugin implements PluginBase {
} else { } else {
//log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString()); //log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
} }
IobTotal bolusIob = MainApp.getConfigBuilder().getCalculationToTimeTreatments(time).round(); IobTotal bolusIob = TreatmentsPlugin.getPlugin().getCalculationToTimeTreatments(time).round();
IobTotal basalIob = MainApp.getConfigBuilder().getCalculationToTimeTempBasals(time).round(); IobTotal basalIob = TreatmentsPlugin.getPlugin().getCalculationToTimeTempBasals(time, profile, true, now).round();
if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS)) {
// Add expected zero temp basal for next 240 mins
IobTotal basalIobWithZeroTemp = basalIob.copy();
TemporaryBasal t = new TemporaryBasal()
.date(now + 60 * 1000L)
.duration(240)
.absolute(0);
if (t.date < time) {
IobTotal calc = t.iobCalc(time, profile);
basalIobWithZeroTemp.plus(calc);
}
basalIob.iobWithZeroTemp = basalIobWithZeroTemp;
}
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round(); IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
if (time < System.currentTimeMillis()) { if (time < System.currentTimeMillis()) {
@ -356,7 +336,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
@Nullable @Nullable
private static Long findPreviousTimeFromBucketedData(long time) { private Long findPreviousTimeFromBucketedData(long time) {
if (bucketed_data == null) if (bucketed_data == null)
return null; return null;
for (int index = 0; index < bucketed_data.size(); index++) { for (int index = 0; index < bucketed_data.size(); index++) {
@ -366,17 +346,18 @@ public class IobCobCalculatorPlugin implements PluginBase {
return null; return null;
} }
public static BasalData getBasalData(long time) { public BasalData getBasalData(long time) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
time = roundUpTime(time); time = roundUpTime(time);
BasalData retval = basalDataTable.get(time); BasalData retval = basalDataTable.get(time);
if (retval == null) { if (retval == null) {
retval = new BasalData(); retval = new BasalData();
TemporaryBasal tb = MainApp.getConfigBuilder().getTempBasalFromHistory(time); Profile profile = MainApp.getConfigBuilder().getProfile(time);
retval.basal = MainApp.getConfigBuilder().getProfile(time).getBasal(time); TemporaryBasal tb = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(time);
retval.basal = profile.getBasal(time);
if (tb != null) { if (tb != null) {
retval.isTempBasalRunning = true; retval.isTempBasalRunning = true;
retval.tempBasalAbsolute = tb.tempBasalConvertedToAbsolute(time); retval.tempBasalAbsolute = tb.tempBasalConvertedToAbsolute(time, profile);
} else { } else {
retval.isTempBasalRunning = false; retval.isTempBasalRunning = false;
retval.tempBasalAbsolute = retval.basal; retval.tempBasalAbsolute = retval.basal;
@ -392,7 +373,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
@Nullable @Nullable
public static AutosensData getAutosensData(long time) { public AutosensData getAutosensData(long time) {
synchronized (dataLock) { synchronized (dataLock) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (time > now) if (time > now)
@ -417,20 +398,43 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
@Nullable @Nullable
public static AutosensData getLastAutosensDataSynchronized(String reason) { public AutosensData getLastAutosensDataSynchronized(String reason) {
synchronized (dataLock) { synchronized (dataLock) {
return getLastAutosensData(reason); return getLastAutosensData(reason);
} }
} }
public CobInfo getCobInfo(boolean _synchronized, String reason) {
AutosensData autosensData = _synchronized ? getLastAutosensDataSynchronized(reason) : getLastAutosensData(reason);
Double displayCob = null;
double futureCarbs = 0;
long now = now();
List<Treatment> treatments = TreatmentsPlugin.getPlugin().getTreatmentsFromHistory();
if (autosensData != null) {
displayCob = autosensData.cob;
for (Treatment treatment : treatments) {
if (IobCobCalculatorPlugin.roundUpTime(treatment.date) > IobCobCalculatorPlugin.roundUpTime(autosensData.time)
&& treatment.date <= now && treatment.carbs > 0) {
displayCob += treatment.carbs;
}
}
}
for (Treatment treatment : treatments) {
if (treatment.date > now && treatment.carbs > 0) {
futureCarbs += treatment.carbs;
}
}
return new CobInfo(displayCob, futureCarbs);
}
@Nullable @Nullable
public static AutosensData getLastAutosensData(String reason) { public AutosensData getLastAutosensData(String reason) {
if (autosensDataTable.size() < 1) { if (autosensDataTable.size() < 1) {
log.debug("AUTOSENSDATA null: autosensDataTable empty (" + reason + ")"); log.debug("AUTOSENSDATA null: autosensDataTable empty (" + reason + ")");
return null; return null;
} }
AutosensData data = null; AutosensData data;
try { try {
data = autosensDataTable.valueAt(autosensDataTable.size() - 1); data = autosensDataTable.valueAt(autosensDataTable.size() - 1);
} catch (Exception e) { } catch (Exception e) {
@ -444,14 +448,11 @@ public class IobCobCalculatorPlugin implements PluginBase {
log.debug("AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + DateUtil.dateAndTimeString(data.time)); log.debug("AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + DateUtil.dateAndTimeString(data.time));
return null; return null;
} else { } else {
if (data == null)
log.debug("AUTOSENSDATA null: data == null (" + " " + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + DateUtil.dateAndTimeString(data.time));
return data; return data;
} }
} }
public static IobTotal[] calculateIobArrayInDia() { public IobTotal[] calculateIobArrayInDia(Profile profile) {
Profile profile = MainApp.getConfigBuilder().getProfile();
// predict IOB out to DIA plus 30m // predict IOB out to DIA plus 30m
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
time = roundUpTime(time); time = roundUpTime(time);
@ -460,14 +461,30 @@ public class IobCobCalculatorPlugin implements PluginBase {
int pos = 0; int pos = 0;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
long t = time + i * 5 * 60000; long t = time + i * 5 * 60000;
IobTotal iob = calculateFromTreatmentsAndTempsSynchronized(t); IobTotal iob = calculateFromTreatmentsAndTempsSynchronized(t, profile);
array[pos] = iob; array[pos] = iob;
pos++; pos++;
} }
return array; return array;
} }
public static AutosensResult detectSensitivityWithLock(long fromTime, long toTime) { public IobTotal[] calculateIobArrayForSMB(Profile profile) {
// predict IOB out to DIA plus 30m
long time = System.currentTimeMillis();
time = roundUpTime(time);
int len = (4 * 60) / 5;
IobTotal[] array = new IobTotal[len];
int pos = 0;
for (int i = 0; i < len; i++) {
long t = time + i * 5 * 60000;
IobTotal iob = calculateFromTreatmentsAndTempsSynchronized(t, profile);
array[pos] = iob;
pos++;
}
return array;
}
public AutosensResult detectSensitivityWithLock(long fromTime, long toTime) {
synchronized (dataLock) { synchronized (dataLock) {
return detectSensitivity(fromTime, toTime); return detectSensitivity(fromTime, toTime);
} }
@ -486,14 +503,24 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
@Subscribe @Subscribe
@SuppressWarnings("unused")
public void onEventAppInitialized(EventAppInitialized ev) { public void onEventAppInitialized(EventAppInitialized ev) {
runCalculation("onEventAppInitialized", true); if (this != getPlugin()) {
log.debug("Ignoring event for non default instance");
return;
}
runCalculation("onEventAppInitialized", System.currentTimeMillis(), true, ev);
} }
@Subscribe @Subscribe
@SuppressWarnings("unused")
public void onEventNewBG(EventNewBG ev) { public void onEventNewBG(EventNewBG ev) {
if (this != getPlugin()) {
log.debug("Ignoring event for non default instance");
return;
}
stopCalculation("onEventNewBG"); stopCalculation("onEventNewBG");
runCalculation("onEventNewBG", true); runCalculation("onEventNewBG", System.currentTimeMillis(), true, ev);
} }
private void stopCalculation(String from) { private void stopCalculation(String from) {
@ -507,16 +534,20 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
} }
private void runCalculation(String from, boolean bgDataReload) { public void runCalculation(String from, long start, boolean bgDataReload, Event cause) {
log.debug("Starting calculation thread: " + from); log.debug("Starting calculation thread: " + from);
if (thread == null || thread.getState() == Thread.State.TERMINATED) { if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new IobCobThread(this, from, bgDataReload); thread = new IobCobThread(this, from, start, bgDataReload, cause);
thread.start(); thread.start();
} }
} }
@Subscribe @Subscribe
public void onNewProfile(EventNewBasalProfile ev) { public void onNewProfile(EventNewBasalProfile ev) {
if (this != getPlugin()) {
log.debug("Ignoring event for non default instance");
return;
}
if (MainApp.getConfigBuilder() == null) if (MainApp.getConfigBuilder() == null)
return; // app still initializing return; // app still initializing
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = MainApp.getConfigBuilder().getProfile();
@ -532,14 +563,20 @@ public class IobCobCalculatorPlugin implements PluginBase {
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
runCalculation("onNewProfile", false); runCalculation("onNewProfile", System.currentTimeMillis(), false, ev);
} }
@Subscribe @Subscribe
public void onEventPreferenceChange(EventPreferenceChange ev) { public void onEventPreferenceChange(EventPreferenceChange ev) {
if (this != getPlugin()) {
log.debug("Ignoring event for non default instance");
return;
}
if (ev.isChanged(R.string.key_openapsama_autosens_period) || if (ev.isChanged(R.string.key_openapsama_autosens_period) ||
ev.isChanged(R.string.key_age) || ev.isChanged(R.string.key_age) ||
ev.isChanged(R.string.key_absorption_maxtime) ev.isChanged(R.string.key_absorption_maxtime) ||
ev.isChanged(R.string.key_openapsama_min_5m_carbimpact) ||
ev.isChanged(R.string.key_absorption_cutoff)
) { ) {
stopCalculation("onEventPreferenceChange"); stopCalculation("onEventPreferenceChange");
synchronized (dataLock) { synchronized (dataLock) {
@ -547,24 +584,32 @@ public class IobCobCalculatorPlugin implements PluginBase {
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
runCalculation("onEventPreferenceChange", false); runCalculation("onEventPreferenceChange", System.currentTimeMillis(), false, ev);
} }
} }
@Subscribe @Subscribe
public void onEventConfigBuilderChange(EventConfigBuilderChange ev) { public void onEventConfigBuilderChange(EventConfigBuilderChange ev) {
if (this != getPlugin()) {
log.debug("Ignoring event for non default instance");
return;
}
stopCalculation("onEventConfigBuilderChange"); stopCalculation("onEventConfigBuilderChange");
synchronized (dataLock) { synchronized (dataLock) {
log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
runCalculation("onEventConfigBuilderChange", false); runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, ev);
} }
// When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated // When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
@Subscribe @Subscribe
public void onEventNewHistoryData(EventNewHistoryData ev) { public void onEventNewHistoryData(EventNewHistoryData ev) {
if (this != getPlugin()) {
log.debug("Ignoring event for non default instance");
return;
}
//log.debug("Locking onNewHistoryData"); //log.debug("Locking onNewHistoryData");
stopCalculation("onEventNewHistoryData"); stopCalculation("onEventNewHistoryData");
synchronized (dataLock) { synchronized (dataLock) {
@ -599,10 +644,18 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
} }
} }
runCalculation("onEventNewHistoryData", false); runCalculation("onEventNewHistoryData", System.currentTimeMillis(), false, ev);
//log.debug("Releasing onNewHistoryData"); //log.debug("Releasing onNewHistoryData");
} }
public void clearCache() {
synchronized (dataLock) {
log.debug("Clearing cached data.");
iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>();
}
}
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2 // From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
// Returns the value at a given percentile in a sorted numeric array. // Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method // "Linear interpolation between closest ranks" method

View file

@ -4,6 +4,8 @@ import android.content.Context;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import com.crashlytics.android.answers.CustomEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -11,39 +13,52 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.queue.QueueThread; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.SP;
import static info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin.getBucketedData; import static info.nightscout.utils.DateUtil.now;
import static info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin.oldestDataAvailable;
import static info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin.roundUpTime;
/** /**
* Created by mike on 23.01.2018. * Created by mike on 23.01.2018.
*/ */
public class IobCobThread extends Thread { public class IobCobThread extends Thread {
private static Logger log = LoggerFactory.getLogger(QueueThread.class); private static Logger log = LoggerFactory.getLogger(IobCobThread.class);
private final Event cause;
private IobCobCalculatorPlugin iobCobCalculatorPlugin; private IobCobCalculatorPlugin iobCobCalculatorPlugin;
private boolean bgDataReload; private boolean bgDataReload;
private String from; private String from;
private long start;
private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mWakeLock;
public IobCobThread(IobCobCalculatorPlugin plugin, String from, boolean bgDataReload) { public IobCobThread(IobCobCalculatorPlugin plugin, String from, long start, boolean bgDataReload, Event cause) {
super(); super();
this.iobCobCalculatorPlugin = plugin; this.iobCobCalculatorPlugin = plugin;
this.bgDataReload = bgDataReload; this.bgDataReload = bgDataReload;
this.from = from; this.from = from;
this.cause = cause;
this.start = start;
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE); PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread"); mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread");
@ -57,34 +72,34 @@ public class IobCobThread extends Thread {
log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from); log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from);
return; // app still initializing return; // app still initializing
} }
if (MainApp.getConfigBuilder().getProfile() == null) { if (!MainApp.getConfigBuilder().isProfileValid("IobCobThread")) {
log.debug("Aborting calculation thread (No profile): " + from); log.debug("Aborting calculation thread (No profile): " + from);
return; // app still initializing return; // app still initializing
} }
//log.debug("Locking calculateSensitivityData"); //log.debug("Locking calculateSensitivityData");
Object dataLock = iobCobCalculatorPlugin.dataLock; long oldestTimeWithData = iobCobCalculatorPlugin.oldestDataAvailable();
long oldestTimeWithData = oldestDataAvailable(); synchronized (iobCobCalculatorPlugin.dataLock) {
synchronized (dataLock) {
if (bgDataReload) { if (bgDataReload) {
iobCobCalculatorPlugin.loadBgData(); iobCobCalculatorPlugin.loadBgData(start);
iobCobCalculatorPlugin.createBucketedData(); iobCobCalculatorPlugin.createBucketedData();
} }
List<BgReading> bucketed_data = getBucketedData(); List<BgReading> bucketed_data = iobCobCalculatorPlugin.getBucketedData();
LongSparseArray<AutosensData> autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable(); LongSparseArray<AutosensData> autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
if (bucketed_data == null || bucketed_data.size() < 3) { if (bucketed_data == null || bucketed_data.size() < 3) {
log.debug("Aborting calculation thread (No bucketed data available): " + from); log.debug("Aborting calculation thread (No bucketed data available): " + from);
return; return;
} }
long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date); long prevDataTime = IobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString()); log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
AutosensData previous = autosensDataTable.get(prevDataTime); AutosensData previous = autosensDataTable.get(prevDataTime);
// start from oldest to be able sub cob // start from oldest to be able sub cob
for (int i = bucketed_data.size() - 4; i >= 0; i--) { for (int i = bucketed_data.size() - 4; i >= 0; i--) {
MainApp.bus().post(new EventIobCalculationProgress(i + "/" + bucketed_data.size()));
if (iobCobCalculatorPlugin.stopCalculationTrigger) { if (iobCobCalculatorPlugin.stopCalculationTrigger) {
iobCobCalculatorPlugin.stopCalculationTrigger = false; iobCobCalculatorPlugin.stopCalculationTrigger = false;
log.debug("Aborting calculation thread (trigger): " + from); log.debug("Aborting calculation thread (trigger): " + from);
@ -92,10 +107,9 @@ public class IobCobThread extends Thread {
} }
// check if data already exists // check if data already exists
long bgTime = bucketed_data.get(i).date; long bgTime = bucketed_data.get(i).date;
bgTime = roundUpTime(bgTime); bgTime = IobCobCalculatorPlugin.roundUpTime(bgTime);
if (bgTime > System.currentTimeMillis()) if (bgTime > IobCobCalculatorPlugin.roundUpTime(now()))
continue; continue;
Profile profile = MainApp.getConfigBuilder().getProfile(bgTime);
AutosensData existing; AutosensData existing;
if ((existing = autosensDataTable.get(bgTime)) != null) { if ((existing = autosensDataTable.get(bgTime)) != null) {
@ -103,16 +117,12 @@ public class IobCobThread extends Thread {
continue; continue;
} }
Profile profile = MainApp.getConfigBuilder().getProfile(bgTime);
if (profile == null) { if (profile == null) {
log.debug("Aborting calculation thread (no profile): " + from); log.debug("Aborting calculation thread (no profile): " + from);
return; // profile not set yet return; // profile not set yet
} }
if (profile.getIsf(bgTime) == null) {
log.debug("Aborting calculation thread (no ISF): " + from);
return; // profile not set yet
}
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")"); log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
@ -135,13 +145,59 @@ public class IobCobThread extends Thread {
continue; continue;
} }
delta = (bg - bucketed_data.get(i + 1).value); delta = (bg - bucketed_data.get(i + 1).value);
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime); IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile);
double bgi = -iob.activity * sens * 5; double bgi = -iob.activity * sens * 5;
double deviation = delta - bgi; double deviation = delta - bgi;
double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000;
List<Treatment> recentTreatments = MainApp.getConfigBuilder().getTreatments5MinBackFromHistory(bgTime); double slopeFromMaxDeviation = 0;
double slopeFromMinDeviation = 999;
double maxDeviation = 0;
double minDeviation = 999;
// https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
if (i < bucketed_data.size() - 16) { // we need 1h of data to calculate minDeviationSlope
long hourago = bgTime + 10 * 1000 - 60 * 60 * 1000L;
AutosensData hourAgoData = IobCobCalculatorPlugin.getPlugin().getAutosensData(hourago);
if (hourAgoData != null) {
int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time);
if (Config.logAutosensData)
log.debug(">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + "hourAgoData=" + hourAgoData.toString());
int past = 1;
try {
for (; past < 12; past++) {
AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
if (ad.avgDeviation > maxDeviation) {
slopeFromMaxDeviation = Math.min(0, deviationSlope);
maxDeviation = ad.avgDeviation;
}
if (ad.avgDeviation < minDeviation) {
slopeFromMinDeviation = Math.max(0, deviationSlope);
minDeviation = ad.avgDeviation;
}
//if (Config.logAutosensData)
// log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation);
}
} catch (Exception e) {
log.error("Unhandled exception", e);
FabricPrivacy.logException(e);
FabricPrivacy.getInstance().logCustom(new CustomEvent("CatchedError")
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
.putCustomAttribute("version", BuildConfig.VERSION)
.putCustomAttribute("autosensDataTable", iobCobCalculatorPlugin.getAutosensDataTable().toString())
.putCustomAttribute("for_data", ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + "hourAgoData=" + hourAgoData.toString())
.putCustomAttribute("past", past)
);
}
}
}
List<Treatment> recentTreatments = TreatmentsPlugin.getPlugin().getTreatments5MinBackFromHistory(bgTime);
for (int ir = 0; ir < recentTreatments.size(); ir++) { for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs; autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir))); autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
@ -152,24 +208,38 @@ public class IobCobThread extends Thread {
if (previous != null && previous.cob > 0) { if (previous != null && previous.cob > 0) {
// calculate sum of min carb impact from all active treatments // calculate sum of min carb impact from all active treatments
double totalMinCarbsImpact = 0d; double totalMinCarbsImpact = 0d;
for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) { if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii); //when the impact depends on a max time, sum them up as smaller carb sizes make them smaller
totalMinCarbsImpact += c.min5minCarbImpact; for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
totalMinCarbsImpact += c.min5minCarbImpact;
}
} else {
//Oref sensitivity
totalMinCarbsImpact = SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
} }
// figure out how many carbs that represents // figure out how many carbs that represents
// but always assume at least 3mg/dL/5m (default) absorption per active treatment // but always assume at least 3mg/dL/5m (default) absorption per active treatment
double ci = Math.max(deviation, totalMinCarbsImpact); double ci = Math.max(deviation, totalMinCarbsImpact);
if (ci != deviation)
autosensData.failoverToMinAbsorbtionRate = true;
autosensData.absorbed = ci * profile.getIc(bgTime) / sens; autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
// and add that to the running total carbsAbsorbed // and add that to the running total carbsAbsorbed
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d); autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
autosensData.substractAbosorbedCarbs(); autosensData.substractAbosorbedCarbs();
autosensData.usedMinCarbsImpact = totalMinCarbsImpact;
} }
autosensData.removeOldCarbs(bgTime); autosensData.removeOldCarbs(bgTime);
autosensData.cob += autosensData.carbsFromBolus; autosensData.cob += autosensData.carbsFromBolus;
autosensData.deviation = deviation; autosensData.deviation = deviation;
autosensData.bgi = bgi; autosensData.bgi = bgi;
autosensData.delta = delta; autosensData.delta = delta;
autosensData.avgDelta = avgDelta;
autosensData.avgDeviation = avgDeviation;
autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation;
autosensData.slopeFromMinDeviation = slopeFromMinDeviation;
// calculate autosens only without COB // calculate autosens only without COB
if (autosensData.cob <= 0) { if (autosensData.cob <= 0) {
@ -191,15 +261,18 @@ public class IobCobThread extends Thread {
previous = autosensData; previous = autosensData;
autosensDataTable.put(bgTime, autosensData); autosensDataTable.put(bgTime, autosensData);
if (Config.logAutosensData)
log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime));
autosensData.autosensRatio = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime).ratio; autosensData.autosensRatio = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime).ratio;
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug(autosensData.log(bgTime)); log.debug(autosensData.toString());
} }
} }
MainApp.bus().post(new EventAutosensCalculationFinished()); MainApp.bus().post(new EventAutosensCalculationFinished(cause));
log.debug("Finishing calculation thread: " + from); log.debug("Finishing calculation thread: " + from);
} finally { } finally {
mWakeLock.release(); mWakeLock.release();
MainApp.bus().post(new EventIobCalculationProgress(""));
} }
} }

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.IobCobCalculator.events; package info.nightscout.androidaps.plugins.IobCobCalculator.events;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventLoop; import info.nightscout.androidaps.events.EventLoop;
/** /**
@ -7,4 +8,9 @@ import info.nightscout.androidaps.events.EventLoop;
*/ */
public class EventAutosensCalculationFinished extends EventLoop { public class EventAutosensCalculationFinished extends EventLoop {
public Event cause;
public EventAutosensCalculationFinished(Event cause) {
this.cause = cause;
}
} }

View file

@ -0,0 +1,11 @@
package info.nightscout.androidaps.plugins.IobCobCalculator.events;
import info.nightscout.androidaps.events.Event;
public class EventIobCalculationProgress extends Event {
public String progress;
public EventIobCalculationProgress(String progress) {
this.progress = progress;
}
}

View file

@ -1,17 +1,23 @@
package info.nightscout.androidaps.plugins.Loop; package info.nightscout.androidaps.plugins.Loop;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.Html; import android.text.Html;
import android.text.Spanned; import android.text.Spanned;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
@ -22,36 +28,69 @@ import info.nightscout.utils.DecimalFormatter;
public class APSResult { public class APSResult {
private static Logger log = LoggerFactory.getLogger(APSResult.class); private static Logger log = LoggerFactory.getLogger(APSResult.class);
public Date date;
public String reason; public String reason;
public double rate; public double rate;
public int duration; public int duration;
public boolean changeRequested = false; public boolean tempBasalRequested = false;
public boolean bolusRequested = false;
public IobTotal iob;
public JSONObject json = new JSONObject();
public boolean hasPredictions = false;
public double smb = 0d; // super micro bolus in units
public long deliverAt = 0;
public Constraint<Double> inputConstraints;
public Constraint<Double> rateConstraint;
public Constraint<Double> smbConstraint;
@Override @Override
public String toString() { public String toString() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (changeRequested) { if (isChangeRequested()) {
String ret;
// rate
if (rate == 0 && duration == 0) if (rate == 0 && duration == 0)
return MainApp.sResources.getString(R.string.canceltemp); ret = MainApp.sResources.getString(R.string.canceltemp) + "\n";
else if (rate == -1)
ret = MainApp.sResources.getString(R.string.let_temp_basal_run) + "\n";
else else
return MainApp.sResources.getString(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " + ret = MainApp.sResources.getString(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%)\n" + "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) \n" +
MainApp.sResources.getString(R.string.duration) + ": " + DecimalFormatter.to0Decimal(duration) + " min\n" + MainApp.sResources.getString(R.string.duration) + ": " + DecimalFormatter.to2Decimal(duration) + " min\n";
MainApp.sResources.getString(R.string.reason) + ": " + reason;
// smb
if (smb != 0)
ret += ("SMB: " + DecimalFormatter.toPumpSupportedBolus(smb) + " U\n");
// reason
ret += MainApp.sResources.getString(R.string.reason) + ": " + reason;
return ret;
} else } else
return MainApp.sResources.getString(R.string.nochangerequested); return MainApp.sResources.getString(R.string.nochangerequested);
} }
public Spanned toSpanned() { public Spanned toSpanned() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (changeRequested) { if (isChangeRequested()) {
String ret = ""; String ret;
if (rate == 0 && duration == 0) ret = MainApp.sResources.getString(R.string.canceltemp); // rate
if (rate == 0 && duration == 0)
ret = MainApp.sResources.getString(R.string.canceltemp) + "<br>";
else if (rate == -1)
ret = MainApp.sResources.getString(R.string.let_temp_basal_run) + "<br>";
else else
ret = "<b>" + MainApp.sResources.getString(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " + ret = "<b>" + MainApp.sResources.getString(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) <br>" + "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) <br>" +
"<b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>" + "<b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>";
"<b>" + MainApp.sResources.getString(R.string.reason) + "</b>: " + reason.replace("<", "&lt;").replace(">", "&gt;");
// smb
if (smb != 0)
ret += ("<b>" + "SMB" + "</b>: " + DecimalFormatter.toPumpSupportedBolus(smb) + " U<br>");
// reason
ret += "<b>" + MainApp.sResources.getString(R.string.reason) + "</b>: " + reason.replace("<", "&lt;").replace(">", "&gt;");
return Html.fromHtml(ret); return Html.fromHtml(ret);
} else } else
return Html.fromHtml(MainApp.sResources.getString(R.string.nochangerequested)); return Html.fromHtml(MainApp.sResources.getString(R.string.nochangerequested));
@ -62,17 +101,25 @@ public class APSResult {
public APSResult clone() { public APSResult clone() {
APSResult newResult = new APSResult(); APSResult newResult = new APSResult();
newResult.reason = new String(reason); newResult.reason = reason;
newResult.rate = rate; newResult.rate = rate;
newResult.duration = duration; newResult.duration = duration;
newResult.changeRequested = changeRequested; newResult.tempBasalRequested = tempBasalRequested;
newResult.bolusRequested = bolusRequested;
newResult.iob = iob;
newResult.json = json;
newResult.hasPredictions = hasPredictions;
newResult.smb = smb;
newResult.deliverAt = deliverAt;
newResult.rateConstraint = rateConstraint;
newResult.smbConstraint = smbConstraint;
return newResult; return newResult;
} }
public JSONObject json() { public JSONObject json() {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
try { try {
if (changeRequested) { if (isChangeRequested()) {
json.put("rate", rate); json.put("rate", rate);
json.put("duration", duration); json.put("duration", duration);
json.put("reason", reason); json.put("reason", reason);
@ -82,4 +129,105 @@ public class APSResult {
} }
return json; return json;
} }
public List<BgReading> getPredictions() {
List<BgReading> array = new ArrayList<>();
try {
long startTime = date.getTime();
if (json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isIOBPrediction = true;
array.add(bg);
}
}
if (predBGs.has("aCOB")) {
JSONArray iob = predBGs.getJSONArray("aCOB");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isaCOBPrediction = true;
array.add(bg);
}
}
if (predBGs.has("COB")) {
JSONArray iob = predBGs.getJSONArray("COB");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isCOBPrediction = true;
array.add(bg);
}
}
if (predBGs.has("UAM")) {
JSONArray iob = predBGs.getJSONArray("UAM");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isUAMPrediction = true;
array.add(bg);
}
}
if (predBGs.has("ZT")) {
JSONArray iob = predBGs.getJSONArray("ZT");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isZTPrediction = true;
array.add(bg);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return array;
}
public long getLatestPredictionsTime() {
long latest = 0;
try {
long startTime = date != null ? date.getTime() : 0;
if (json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("aCOB")) {
JSONArray iob = predBGs.getJSONArray("aCOB");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("COB")) {
JSONArray iob = predBGs.getJSONArray("COB");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("UAM")) {
JSONArray iob = predBGs.getJSONArray("UAM");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("ZT")) {
JSONArray iob = predBGs.getJSONArray("ZT");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return latest;
}
public boolean isChangeRequested() {
return tempBasalRequested || bolusRequested;
}
} }

View file

@ -3,36 +3,51 @@ package info.nightscout.androidaps.plugins.Loop;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui;
import info.nightscout.utils.FabricPrivacy;
public class LoopFragment extends SubscriberFragment implements View.OnClickListener { public class LoopFragment extends SubscriberFragment {
private static Logger log = LoggerFactory.getLogger(LoopFragment.class); private static Logger log = LoggerFactory.getLogger(LoopFragment.class);
@BindView(R.id.loop_run)
Button runNowButton; Button runNowButton;
@BindView(R.id.loop_lastrun)
TextView lastRunView; TextView lastRunView;
@BindView(R.id.loop_lastenact)
TextView lastEnactView; TextView lastEnactView;
@BindView(R.id.loop_source)
TextView sourceView; TextView sourceView;
@BindView(R.id.loop_request)
TextView requestView; TextView requestView;
@BindView(R.id.loop_constraintsprocessed)
TextView constraintsProcessedView; TextView constraintsProcessedView;
TextView setByPumpView; @BindView(R.id.loop_constraints)
TextView constraintsView;
@BindView(R.id.loop_tbrsetbypump)
TextView tbrSetByPumpView;
@BindView(R.id.loop_smbsetbypump)
TextView smbSetByPumpView;
@Override @Override
@ -40,41 +55,19 @@ public class LoopFragment extends SubscriberFragment implements View.OnClickList
Bundle savedInstanceState) { Bundle savedInstanceState) {
try { try {
View view = inflater.inflate(R.layout.loop_fragment, container, false); View view = inflater.inflate(R.layout.loop_fragment, container, false);
unbinder = ButterKnife.bind(this, view);
lastRunView = (TextView) view.findViewById(R.id.loop_lastrun);
lastEnactView = (TextView) view.findViewById(R.id.loop_lastenact);
sourceView = (TextView) view.findViewById(R.id.loop_source);
requestView = (TextView) view.findViewById(R.id.loop_request);
constraintsProcessedView = (TextView) view.findViewById(R.id.loop_constraintsprocessed);
setByPumpView = (TextView) view.findViewById(R.id.loop_setbypump);
runNowButton = (Button) view.findViewById(R.id.loop_run);
runNowButton.setOnClickListener(this);
updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
} }
@Override @OnClick(R.id.loop_run)
public void onClick(View view) { void onRunClick() {
switch (view.getId()) { lastRunView.setText(MainApp.sResources.getString(R.string.executing));
case R.id.loop_run: new Thread(() -> LoopPlugin.getPlugin().invoke("Loop button", true)).start();
lastRunView.setText(MainApp.sResources.getString(R.string.executing)); FabricPrivacy.getInstance().logCustom(new CustomEvent("Loop_Run"));
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
LoopPlugin.getPlugin().invoke("Loop button", true);
}
});
thread.start();
Answers.getInstance().logCustom(new CustomEvent("Loop_Run"));
break;
}
} }
@Subscribe @Subscribe
@ -87,12 +80,7 @@ public class LoopFragment extends SubscriberFragment implements View.OnClickList
clearGUI(); clearGUI();
final Activity activity = getActivity(); final Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(() -> lastRunView.setText(ev.text));
@Override
public void run() {
lastRunView.setText(ev.text);
}
});
} }
@ -100,17 +88,27 @@ public class LoopFragment extends SubscriberFragment implements View.OnClickList
protected void updateGUI() { protected void updateGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(() -> {
@Override LoopPlugin.LastRun lastRun = LoopPlugin.lastRun;
public void run() { if (lastRun != null) {
if (LoopPlugin.lastRun != null) { requestView.setText(lastRun.request != null ? lastRun.request.toSpanned() : "");
requestView.setText(LoopPlugin.lastRun.request != null ? LoopPlugin.lastRun.request.toSpanned() : ""); constraintsProcessedView.setText(lastRun.constraintsProcessed != null ? lastRun.constraintsProcessed.toSpanned() : "");
constraintsProcessedView.setText(LoopPlugin.lastRun.constraintsProcessed != null ? LoopPlugin.lastRun.constraintsProcessed.toSpanned() : ""); sourceView.setText(lastRun.source != null ? lastRun.source : "");
setByPumpView.setText(LoopPlugin.lastRun.setByPump != null ? LoopPlugin.lastRun.setByPump.toSpanned() : ""); lastRunView.setText(lastRun.lastAPSRun != null && lastRun.lastAPSRun.getTime() != 0 ? lastRun.lastAPSRun.toLocaleString() : "");
sourceView.setText(LoopPlugin.lastRun.source != null ? LoopPlugin.lastRun.source : ""); lastEnactView.setText(lastRun.lastEnact != null && lastRun.lastEnact.getTime() != 0 ? lastRun.lastEnact.toLocaleString() : "");
lastRunView.setText(LoopPlugin.lastRun.lastAPSRun != null && LoopPlugin.lastRun.lastAPSRun.getTime() != 0 ? LoopPlugin.lastRun.lastAPSRun.toLocaleString() : ""); tbrSetByPumpView.setText(lastRun.tbrSetByPump != null ? Html.fromHtml(lastRun.tbrSetByPump.toHtml()) : "");
lastEnactView.setText(LoopPlugin.lastRun.lastEnact != null && LoopPlugin.lastRun.lastEnact.getTime() != 0 ? LoopPlugin.lastRun.lastEnact.toLocaleString() : ""); smbSetByPumpView.setText(lastRun.smbSetByPump != null ? Html.fromHtml(lastRun.smbSetByPump.toHtml()) : "");
String constraints = "";
if (lastRun.constraintsProcessed != null) {
Constraint<Double> allConstraints = new Constraint<>(0d);
if (lastRun.constraintsProcessed.rateConstraint != null)
allConstraints.copyReasons(lastRun.constraintsProcessed.rateConstraint);
if (lastRun.constraintsProcessed.smbConstraint != null)
allConstraints.copyReasons(lastRun.constraintsProcessed.smbConstraint);
constraints = allConstraints.getMostLimitedReasons();
} }
constraintsView.setText(constraints);
} }
}); });
} }
@ -118,16 +116,14 @@ public class LoopFragment extends SubscriberFragment implements View.OnClickList
void clearGUI() { void clearGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(() -> {
@Override requestView.setText("");
public void run() { constraintsProcessedView.setText("");
requestView.setText(""); sourceView.setText("");
constraintsProcessedView.setText(""); lastRunView.setText("");
setByPumpView.setText(""); lastEnactView.setText("");
sourceView.setText(""); tbrSetByPumpView.setText("");
lastRunView.setText(""); smbSetByPumpView.setText("");
lastEnactView.setText("");
}
}); });
} }
} }

View file

@ -1,14 +1,18 @@
package info.nightscout.androidaps.plugins.Loop; package info.nightscout.androidaps.plugins.Loop;
import android.annotation.SuppressLint;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.TaskStackBuilder; import android.app.TaskStackBuilder;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Build;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -22,29 +26,43 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification; import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class LoopPlugin implements PluginBase { public class LoopPlugin extends PluginBase {
private static Logger log = LoggerFactory.getLogger(LoopPlugin.class); private static Logger log = LoggerFactory.getLogger(LoopPlugin.class);
private static LoopPlugin loopPlugin; public static final String CHANNEL_ID = "AndroidAPS-Openloop";
long lastBgTriggeredRun = 0;
protected static LoopPlugin loopPlugin;
@NonNull
public static LoopPlugin getPlugin() { public static LoopPlugin getPlugin() {
if (loopPlugin == null) { if (loopPlugin == null) {
loopPlugin = new LoopPlugin(); loopPlugin = new LoopPlugin();
@ -52,9 +70,6 @@ public class LoopPlugin implements PluginBase {
return loopPlugin; return loopPlugin;
} }
private boolean fragmentEnabled = false;
private boolean fragmentVisible = false;
private long loopSuspendedTill = 0L; // end of manual loop suspend private long loopSuspendedTill = 0L; // end of manual loop suspend
private boolean isSuperBolus = false; private boolean isSuperBolus = false;
private boolean isDisconnected = false; private boolean isDisconnected = false;
@ -62,7 +77,8 @@ public class LoopPlugin implements PluginBase {
public class LastRun { public class LastRun {
public APSResult request = null; public APSResult request = null;
public APSResult constraintsProcessed = null; public APSResult constraintsProcessed = null;
public PumpEnactResult setByPump = null; public PumpEnactResult tbrSetByPump = null;
public PumpEnactResult smbSetByPump = null;
public String source = null; public String source = null;
public Date lastAPSRun = null; public Date lastAPSRun = null;
public Date lastEnact = null; public Date lastEnact = null;
@ -72,88 +88,76 @@ public class LoopPlugin implements PluginBase {
static public LastRun lastRun = null; static public LastRun lastRun = null;
public LoopPlugin() { public LoopPlugin() {
MainApp.bus().register(this); super(new PluginDescription()
.mainType(PluginType.LOOP)
.fragmentClass(LoopFragment.class.getName())
.pluginName(R.string.loop)
.shortName(R.string.loop_shortname)
.preferencesId(R.xml.pref_closedmode)
);
loopSuspendedTill = SP.getLong("loopSuspendedTill", 0L); loopSuspendedTill = SP.getLong("loopSuspendedTill", 0L);
isSuperBolus = SP.getBoolean("isSuperBolus", false); isSuperBolus = SP.getBoolean("isSuperBolus", false);
isDisconnected = SP.getBoolean("isDisconnected", false); isDisconnected = SP.getBoolean("isDisconnected", false);
} }
@Override @Override
public String getFragmentClass() { protected void onStart() {
return LoopFragment.class.getName(); MainApp.bus().register(this);
createNotificationChannel();
super.onStart();
} }
@Override private void createNotificationChannel() {
public int getType() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return PluginBase.LOOP;
}
@Override NotificationManager mNotificationManager =
public String getName() { (NotificationManager) MainApp.instance().getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
return MainApp.instance().getString(R.string.loop); @SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
} CHANNEL_ID,
NotificationManager.IMPORTANCE_HIGH);
@Override mNotificationManager.createNotificationChannel(channel);
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.loop_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
} }
// use long name as fallback
return getName();
} }
@Override @Override
public boolean isEnabled(int type) { protected void onStop() {
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable; super.onStop();
return type == LOOP && fragmentEnabled && pumpCapable; MainApp.bus().unregister(this);
} }
@Override @Override
public boolean isVisibleInTabs(int type) { public boolean specialEnableCondition() {
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable; PumpInterface pump = ConfigBuilderPlugin.getActivePump();
return type == LOOP && fragmentVisible && pumpCapable; return pump == null || pump.getPumpDescription().isTempBasalCapable;
} }
@Override /**
public boolean canBeHidden(int type) { * This method is triggered once autosens calculation has completed, so the LoopPlugin
return true; * 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.
@Override *
public boolean hasFragment() { * Callers of {@link info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin#runCalculation(String, long, boolean, Event)}
return true; * are sources triggering a calculation which triggers this method upon completion.
} */
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == LOOP) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == LOOP) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_closedmode;
}
@Subscribe @Subscribe
public void onStatusEvent(final EventTreatmentChange ev) { public void onStatusEvent(final EventAutosensCalculationFinished ev) {
invoke("EventTreatmentChange", true); if (!(ev.cause instanceof EventNewBG)) {
} // Autosens calculation not triggered by a new BG
return;
}
BgReading bgReading = DatabaseHelper.actualBg();
if (bgReading == null) {
// BG outdated
return;
}
if (bgReading.date <= lastBgTriggeredRun) {
// already looped with that value
return;
}
@Subscribe lastBgTriggeredRun = bgReading.date;
public void onStatusEvent(final EventNewBG ev) { invoke("AutosenseCalculation for " + bgReading, true);
invoke("EventNewBG", true);
} }
public long suspendedTo() { public long suspendedTo() {
@ -243,23 +247,31 @@ public class LoopPlugin implements PluginBase {
return isDisconnected; return isDisconnected;
} }
public void invoke(String initiator, boolean allowNotification) { public synchronized void invoke(String initiator, boolean allowNotification){
invoke(initiator, allowNotification, false);
}
public synchronized void invoke(String initiator, boolean allowNotification, boolean tempBasalFallback) {
try { try {
if (Config.logFunctionCalls) if (Config.logFunctionCalls)
log.debug("invoke from " + initiator); log.debug("invoke from " + initiator);
ConstraintsInterface constraintsInterface = MainApp.getConfigBuilder(); Constraint<Boolean> loopEnabled = MainApp.getConstraintChecker().isLoopInvokationAllowed();
if (!constraintsInterface.isLoopEnabled()) {
log.debug(MainApp.sResources.getString(R.string.loopdisabled)); if (!loopEnabled.value()) {
MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.loopdisabled))); String message = MainApp.sResources.getString(R.string.loopdisabled) + "\n" + loopEnabled.getReasons();
log.debug(message);
MainApp.bus().post(new EventLoopSetLastRunGui(message));
return; return;
} }
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
APSResult result = null; APSResult result = null;
if (!isEnabled(PluginBase.LOOP)) if (!isEnabled(PluginType.LOOP))
return; return;
if (MainApp.getConfigBuilder().getProfile() == null) { Profile profile = MainApp.getConfigBuilder().getProfile();
if (!MainApp.getConfigBuilder().isProfileValid("Loop")) {
log.debug(MainApp.sResources.getString(R.string.noprofileselected)); log.debug(MainApp.sResources.getString(R.string.noprofileselected));
MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.noprofileselected))); MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.noprofileselected)));
return; return;
@ -269,8 +281,8 @@ public class LoopPlugin implements PluginBase {
if (pump.getBaseBasalRate() < 0.01d) return; if (pump.getBaseBasalRate() < 0.01d) return;
APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS(); APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS();
if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginBase.APS)) { if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS)) {
usedAPS.invoke(initiator); usedAPS.invoke(initiator, tempBasalFallback);
result = usedAPS.getLastAPSResult(); result = usedAPS.getLastAPSResult();
} }
@ -282,14 +294,25 @@ public class LoopPlugin implements PluginBase {
// check rate for constrais // check rate for constrais
final APSResult resultAfterConstraints = result.clone(); final APSResult resultAfterConstraints = result.clone();
resultAfterConstraints.rate = constraintsInterface.applyBasalConstraints(resultAfterConstraints.rate); resultAfterConstraints.rateConstraint = new Constraint<>(resultAfterConstraints.rate);
resultAfterConstraints.rate = MainApp.getConstraintChecker().applyBasalConstraints(resultAfterConstraints.rateConstraint, profile).value();
resultAfterConstraints.smbConstraint = new Constraint<>(resultAfterConstraints.smb);
resultAfterConstraints.smb = MainApp.getConstraintChecker().applyBolusConstraints(resultAfterConstraints.smbConstraint).value();
// safety check for multiple SMBs
long lastBolusTime = TreatmentsPlugin.getPlugin().getLastBolusTime();
if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
log.debug("SMB requsted but still in 3 min interval");
resultAfterConstraints.smb = 0;
}
if (lastRun == null) lastRun = new LastRun(); if (lastRun == null) lastRun = new LastRun();
lastRun.request = result; lastRun.request = result;
lastRun.constraintsProcessed = resultAfterConstraints; lastRun.constraintsProcessed = resultAfterConstraints;
lastRun.lastAPSRun = new Date(); lastRun.lastAPSRun = new Date();
lastRun.source = ((PluginBase) usedAPS).getName(); lastRun.source = ((PluginBase) usedAPS).getName();
lastRun.setByPump = null; lastRun.tbrSetByPump = null;
lastRun.smbSetByPump = null;
NSUpload.uploadDeviceStatus(); NSUpload.uploadDeviceStatus();
@ -305,34 +328,53 @@ public class LoopPlugin implements PluginBase {
return; return;
} }
if (constraintsInterface.isClosedModeEnabled()) { Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed();
if (result.changeRequested) {
if (closedLoopEnabled.value()) {
if (result.isChangeRequested()) {
final PumpEnactResult waiting = new PumpEnactResult(); final PumpEnactResult waiting = new PumpEnactResult();
final PumpEnactResult previousResult = lastRun.setByPump;
waiting.queued = true; waiting.queued = true;
lastRun.setByPump = waiting; if (resultAfterConstraints.tempBasalRequested)
lastRun.tbrSetByPump = waiting;
if (resultAfterConstraints.bolusRequested)
lastRun.smbSetByPump = waiting;
MainApp.bus().post(new EventLoopUpdateGui()); MainApp.bus().post(new EventLoopUpdateGui());
MainApp.getConfigBuilder().applyAPSRequest(resultAfterConstraints, new Callback() { FabricPrivacy.getInstance().logCustom(new CustomEvent("APSRequest"));
MainApp.getConfigBuilder().applyTBRRequest(resultAfterConstraints, profile, new Callback() {
@Override @Override
public void run() { public void run() {
Answers.getInstance().logCustom(new CustomEvent("APSRequest"));
if (result.enacted || result.success) { if (result.enacted || result.success) {
lastRun.setByPump = result; lastRun.tbrSetByPump = result;
lastRun.lastEnact = lastRun.lastAPSRun; lastRun.lastEnact = lastRun.lastAPSRun;
} else { MainApp.getConfigBuilder().applySMBRequest(resultAfterConstraints, new Callback() {
lastRun.setByPump = previousResult; @Override
public void run() {
//Callback is only called if a bolus was acutally requested
if (result.enacted || result.success) {
lastRun.smbSetByPump = result;
lastRun.lastEnact = lastRun.lastAPSRun;
} else {
new Thread(() -> {
SystemClock.sleep(1000);
LoopPlugin.getPlugin().invoke("tempBasalFallback", allowNotification, true);
}).start();
FabricPrivacy.getInstance().logCustom(new CustomEvent("Loop_Run_TempBasalFallback"));
}
MainApp.bus().post(new EventLoopUpdateGui());
}
});
} }
MainApp.bus().post(new EventLoopUpdateGui()); MainApp.bus().post(new EventLoopUpdateGui());
} }
}); });
} else { } else {
lastRun.setByPump = null; lastRun.tbrSetByPump = null;
lastRun.source = null; lastRun.smbSetByPump = null;
} }
} else { } else {
if (result.changeRequested && allowNotification) { if (result.isChangeRequested() && allowNotification) {
NotificationCompat.Builder builder = NotificationCompat.Builder builder =
new NotificationCompat.Builder(MainApp.instance().getApplicationContext()); new NotificationCompat.Builder(MainApp.instance().getApplicationContext(), CHANNEL_ID);
builder.setSmallIcon(R.drawable.notif_icon) builder.setSmallIcon(R.drawable.notif_icon)
.setContentTitle(MainApp.sResources.getString(R.string.openloop_newsuggestion)) .setContentTitle(MainApp.sResources.getString(R.string.openloop_newsuggestion))
.setContentText(resultAfterConstraints.toString()) .setContentText(resultAfterConstraints.toString())

Some files were not shown because too many files have changed in this diff Show more