diff --git a/.gitignore b/.gitignore
index 79927b784d..1cd8d2622a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
*.apk
build/
.idea/
+app/src/main/jniLibs
diff --git a/.travis.yml b/.travis.yml
index 52552b3ceb..73fe4b80d0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,12 +7,15 @@ android:
components:
- platform-tools
- tools
- - build-tools-26.0.2
+ - build-tools-27.0.2
- android-23
- extra-google-m2repository
- extra-android-m2repository
- extra-google-google_play_services
+before_install:
+- yes | sdkmanager "platforms;android-27"
+
script:
# Unit Test
- ./gradlew test jacocoTestReport
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000..db66ffec38
--- /dev/null
+++ b/ISSUE_TEMPLATE.md
@@ -0,0 +1,10 @@
+Reporting bugs
+--------------
+- Note the precise time the problem occurred and describe the circumstances and steps that caused
+ the problem
+- Note the Build version (found in the About dialog in the app, when pressing the three dots in the
+ upper-right corner).
+- Obtain the app's log files, which can be found on the phone in
+ _/storage/emulated/0/Android/data/info.nightscout.androidaps/_
+ See https://github.com/MilosKozak/AndroidAPS/wiki/Accessing-logfiles
+- Open an issue at https://github.com/MilosKozak/AndroidAPS/issues/new
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 3289276b59..51afdc54c6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -12,9 +12,10 @@ buildscript {
apply plugin: "com.android.application"
apply plugin: "io.fabric"
apply plugin: "jacoco-android"
+apply plugin: 'com.jakewharton.butterknife'
ext {
- supportLibraryVersion = "23.4.0"
+ supportLibraryVersion = "27.0.2"
ormLiteVersion = "4.46"
powermockVersion = "1.7.3"
dexmakerVersion = "1.2"
@@ -47,8 +48,8 @@ def generateGitBuild = { ->
}
android {
- compileSdkVersion 23
- buildToolsVersion "26.0.2"
+ compileSdkVersion 27
+ buildToolsVersion "${supportLibraryVersion}"
defaultConfig {
applicationId "info.nightscout.androidaps"
@@ -56,7 +57,7 @@ android {
targetSdkVersion 23
multiDexEnabled true
versionCode 1500
- version "1.57-dev"
+ version "1.59-dev"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", generateGitBuild()
@@ -65,6 +66,13 @@ android {
}
}
lintOptions {
+ // 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
+ // build with a deprecation warning
+ //abortOnError false
+ // (disabled entirely to avoid reports on the error, which would still be displayed
+ // and it's easy to overlook that it's ignored)
+ checkReleaseBuilds false
disable 'MissingTranslation'
disable 'ExtraTranslation'
}
@@ -171,6 +179,7 @@ dependencies {
compile("com.crashlytics.sdk.android:answers:1.3.12@aar") {
transitive = true;
}
+ compile 'MilosKozak:danars-support-lib:master@zip'
compile "com.android.support:appcompat-v7:${supportLibraryVersion}"
compile "com.android.support:support-v4:${supportLibraryVersion}"
@@ -180,6 +189,7 @@ dependencies {
compile "com.android.support:design:${supportLibraryVersion}"
compile "com.android.support:percent:${supportLibraryVersion}"
compile "com.wdullaer:materialdatetimepicker:2.3.0"
+ compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile "com.squareup:otto:1.3.7"
compile "com.j256.ormlite:ormlite-core:${ormLiteVersion}"
compile "com.j256.ormlite:ormlite-android:${ormLiteVersion}"
@@ -206,6 +216,11 @@ dependencies {
compile "net.danlew:android.joda:2.9.9.1"
+ compile 'org.mozilla:rhino:1.7.7.2'
+
+ api "com.jakewharton:butterknife:8.8.1"
+ annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"
+
testCompile "junit:junit:4.12"
testCompile "org.json:json:20140107"
testCompile "org.mockito:mockito-core:2.7.22"
@@ -220,3 +235,27 @@ dependencies {
androidTestCompile "com.google.dexmaker:dexmaker:${dexmakerVersion}"
androidTestCompile "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
}
+
+task unzip(type: Copy) {
+ def zipPath = configurations.compile.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
\ No newline at end of file
diff --git a/app/libs/rhino-1.7.7.2.jar b/app/libs/rhino-1.7.7.2.jar
deleted file mode 100644
index 4a18d33609..0000000000
Binary files a/app/libs/rhino-1.7.7.2.jar and /dev/null differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8290c46004..a36bdee3aa 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -61,6 +61,7 @@
+
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;
\ No newline at end of file
diff --git a/app/src/main/assets/OpenAPSSMB/determine-basal.js b/app/src/main/assets/OpenAPSSMB/determine-basal.js
new file mode 100644
index 0000000000..84bd684cf6
--- /dev/null
+++ b/app/src/main/assets/OpenAPSSMB/determine-basal.js
@@ -0,0 +1,1146 @@
+/*
+ Determine Basal
+
+ Released under MIT license. See the accompanying LICENSE.txt file for
+ full terms and conditions
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+var round_basal = require('../round-basal')
+
+// Rounds value to 'digits' decimal places
+function round(value, digits)
+{
+ if (! digits) { digits = 0; }
+ var scale = Math.pow(10, digits);
+ return Math.round(value * scale) / scale;
+}
+
+// we expect BG to rise or fall at the rate of BGI,
+// adjusted by the rate at which BG would need to rise /
+// fall to get eventualBG to target over 2 hours
+function calculate_expected_delta(target_bg, eventual_bg, bgi) {
+ // (hours * mins_per_hour) / 5 = how many 5 minute periods in 2h = 24
+ var five_min_blocks = (2 * 60) / 5;
+ var target_delta = target_bg - eventual_bg;
+ var expectedDelta = round(bgi + (target_delta / five_min_blocks), 1);
+ return expectedDelta;
+}
+
+
+function convert_bg(value, profile)
+{
+ if (profile.out_units == "mmol/L")
+ {
+ return round(value / 18, 1).toFixed(1);
+ }
+ else
+ {
+ return Math.round(value);
+ }
+}
+
+var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data) {
+ var rT = {}; //short for requestedTemp
+
+ var deliverAt = new Date();
+
+ if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
+ rT.error ='Error: could not get current basal rate';
+ return rT;
+ }
+ var profile_current_basal = round_basal(profile.current_basal, profile);
+ var basal = profile_current_basal;
+
+ var systemTime = new Date();
+ var bgTime = new Date(glucose_status.date);
+ var minAgo = round( (systemTime - bgTime) / 60 / 1000 ,1);
+
+ var bg = glucose_status.glucose;
+ if (bg < 39) { //Dexcom is in ??? mode or calibrating
+ rT.reason = "CGM is calibrating or in ??? state";
+ }
+ if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future
+ rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime;
+ }
+ if (bg < 39 || minAgo > 12 || minAgo < -5) {
+ if (currenttemp.rate >= basal) { // high temp is running
+ rT.reason += ". Canceling high temp basal of "+currenttemp.rate;
+ rT.deliverAt = deliverAt;
+ rT.temp = 'absolute';
+ rT.duration = 0;
+ rT.rate = 0;
+ return rT;
+ //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ } else if ( currenttemp.rate == 0 && currenttemp.duration > 30 ) { //shorten long zero temps to 30m
+ rT.reason += ". Shortening " + currenttemp.duration + "m long zero temp to 30m. ";
+ rT.deliverAt = deliverAt;
+ rT.temp = 'absolute';
+ rT.duration = 30;
+ rT.rate = 0;
+ return rT;
+ //return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp);
+ } else { //do nothing.
+ rT.reason += ". Temp " + currenttemp.rate + " <= current basal " + basal + "U/hr; doing nothing. ";
+ return rT;
+ }
+ }
+
+ var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver
+
+ // if min and max are set, then set target to their average
+ var target_bg;
+ var min_bg;
+ var max_bg;
+ if (typeof profile.min_bg !== 'undefined') {
+ min_bg = profile.min_bg;
+ }
+ if (typeof profile.max_bg !== 'undefined') {
+ max_bg = profile.max_bg;
+ }
+ if (typeof profile.min_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') {
+ target_bg = (profile.min_bg + profile.max_bg) / 2;
+ } else {
+ rT.error ='Error: could not determine target_bg. ';
+ return rT;
+ }
+
+ var sensitivityRatio;
+ var high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity;
+ var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled basal (which might change)
+ if ( profile.half_basal_exercise_target ) {
+ var halfBasalTarget = profile.half_basal_exercise_target;
+ } else {
+ var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%)
+ // 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default)
+ }
+ if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget + 10
+ || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
+ // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
+ // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
+ //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40);
+ var c = halfBasalTarget - normalTarget;
+ sensitivityRatio = c/(c+target_bg-normalTarget);
+ // limit sensitivityRatio to profile.autosens_max (1.2x by default)
+ sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
+ sensitivityRatio = round(sensitivityRatio,2);
+ console.error("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
+ } else if (typeof autosens_data !== 'undefined' ) {
+ sensitivityRatio = autosens_data.ratio;
+ console.error("Autosens ratio: "+sensitivityRatio+"; ");
+ }
+ if (sensitivityRatio) {
+ basal = profile.current_basal * sensitivityRatio;
+ basal = round_basal(basal, profile);
+ if (basal != profile_current_basal) {
+ console.error("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
+ } else {
+ console.error("Basal unchanged: "+basal+"; ");
+ }
+ }
+
+ // adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120
+ if (profile.temptargetSet) {
+ //console.error("Temp Target set, not adjusting with autosens; ");
+ } else if (typeof autosens_data !== 'undefined' ) {
+ if ( profile.sensitivity_raises_target && autosens_data.ratio < 1 || profile.resistance_lowers_target && autosens_data.ratio > 1 ) {
+ // with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range
+ min_bg = round((min_bg - 60) / autosens_data.ratio) + 60;
+ max_bg = round((max_bg - 60) / autosens_data.ratio) + 60;
+ new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60;
+ // don't allow target_bg below 80
+ new_target_bg = Math.max(80, new_target_bg);
+ if (target_bg == new_target_bg) {
+ console.error("target_bg unchanged: "+new_target_bg+"; ");
+ } else {
+ console.error("target_bg from "+target_bg+" to "+new_target_bg+"; ");
+ }
+ target_bg = new_target_bg;
+ }
+ }
+
+ if (typeof iob_data === 'undefined' ) {
+ rT.error ='Error: iob_data undefined. ';
+ return rT;
+ }
+
+ var iobArray = iob_data;
+ if (typeof(iob_data.length) && iob_data.length > 1) {
+ iob_data = iobArray[0];
+ //console.error(JSON.stringify(iob_data[0]));
+ }
+
+ if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' ) {
+ rT.error ='Error: iob_data missing some property. ';
+ return rT;
+ }
+
+ var tick;
+
+ if (glucose_status.delta > -0.5) {
+ tick = "+" + round(glucose_status.delta,0);
+ } else {
+ tick = round(glucose_status.delta,0);
+ }
+ //var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
+ var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta);
+ var minAvgDelta = Math.min(glucose_status.short_avgdelta, glucose_status.long_avgdelta);
+ var maxDelta = Math.max(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
+
+ var profile_sens = round(profile.sens,1)
+ var sens = profile.sens;
+ if (typeof autosens_data !== 'undefined' ) {
+ sens = profile.sens / sensitivityRatio;
+ sens = round(sens, 1);
+ if (sens != profile_sens) {
+ console.error("ISF from "+profile_sens+" to "+sens);
+ } else {
+ console.error("ISF unchanged: "+sens);
+ }
+ //console.error(" (autosens ratio "+sensitivityRatio+")");
+ }
+ console.error("; CR:",profile.carb_ratio);
+
+ // compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
+ var lastTempAge;
+ if (typeof iob_data.lastTemp !== 'undefined' ) {
+ lastTempAge = round(( new Date().getTime() - iob_data.lastTemp.date ) / 60000); // in minutes
+ // } ---- added to not produce errors
+ } else {
+ lastTempAge = 0;
+ }
+ //console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m");
+ tempModulus = (lastTempAge + currenttemp.duration) % 30;
+ console.error("currenttemp:",currenttemp,"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m");
+ rT.temp = 'absolute';
+ rT.deliverAt = deliverAt;
+ if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate != iob_data.lastTemp.rate ) {
+ rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; setting neutral temp of "+basal+".";
+ return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ }
+ if ( currenttemp && iob_data.lastTemp && currenttemp.duration > 0 ) {
+ // TODO: fix this (lastTemp.duration is how long it has run; currenttemp.duration is time left
+ //if ( currenttemp.duration < iob_data.lastTemp.duration - 2) {
+ //rT.reason = "Warning: currenttemp duration "+currenttemp.duration+" << lastTemp duration "+round(iob_data.lastTemp.duration,1)+" from pumphistory; setting neutral temp of "+basal+".";
+ //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ //}
+ //console.error(lastTempAge, round(iob_data.lastTemp.duration,1), round(lastTempAge - iob_data.lastTemp.duration,1));
+ var lastTempEnded = lastTempAge - iob_data.lastTemp.duration
+ if ( lastTempEnded > 5 ) {
+ rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; setting neutral temp of "+basal+".";
+ //console.error(currenttemp, round(iob_data.lastTemp,1), round(lastTempAge,1));
+ return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ }
+ // TODO: figure out a way to do this check that doesn't fail across basal schedule boundaries
+ //if ( tempModulus < 25 && tempModulus > 5 ) {
+ //rT.reason = "Warning: currenttemp duration "+currenttemp.duration+" + lastTempAge "+lastTempAge+" isn't a multiple of 30m; setting neutral temp of "+basal+".";
+ //console.error(rT.reason);
+ //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ //}
+ }
+
+ //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone
+ var bgi = round(( -iob_data.activity * sens * 5 ), 2);
+ // project deviations for 30 minutes
+ var deviation = round( 30 / 5 * ( minDelta - bgi ) );
+ // don't overreact to a big negative delta: use minAvgDelta if deviation is negative
+ if (deviation < 0) {
+ deviation = round( (30 / 5) * ( minAvgDelta - bgi ) );
+ // and if deviation is still negative, use long_avgdelta
+ if (deviation < 0) {
+ deviation = round( (30 / 5) * ( glucose_status.long_avgdelta - bgi ) );
+ }
+ }
+
+ // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity
+ if (iob_data.iob > 0) {
+ var naive_eventualBG = round( bg - (iob_data.iob * sens) );
+ } else { // if IOB is negative, be more conservative and use the lower of sens, profile.sens
+ var naive_eventualBG = round( bg - (iob_data.iob * Math.min(sens, profile.sens) ) );
+ }
+ // and adjust it for the deviation above
+ var eventualBG = naive_eventualBG + deviation;
+ // calculate what portion of that is due to bolussnooze
+ //var bolusContrib = iob_data.bolussnooze * sens;
+ // and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime
+ //var naive_snoozeBG = round( naive_eventualBG + 1.5 * bolusContrib );
+ // adjust that for deviation like we did eventualBG
+ //var snoozeBG = naive_snoozeBG + deviation;
+
+ // adjust target BG range if needed to safely bring down high BG faster without causing lows
+ if ( bg > max_bg && profile.adv_target_adjustments && ! profile.temptargetSet ) {
+ // with target=100, as BG rises from 100 to 160, adjustedTarget drops from 100 to 80
+ var adjustedMinBG = round(Math.max(80, min_bg - (bg - min_bg)/3 ),0);
+ var adjustedTargetBG =round( Math.max(80, target_bg - (bg - target_bg)/3 ),0);
+ var adjustedMaxBG = round(Math.max(80, max_bg - (bg - max_bg)/3 ),0);
+ // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedMinBG, don’t use it
+ //console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG);
+ if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) {
+ console.error("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
+ min_bg = adjustedMinBG;
+ } else {
+ console.error("min_bg unchanged: "+min_bg+"; ");
+ }
+ // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedTargetBG, don’t use it
+ if (eventualBG > adjustedTargetBG && naive_eventualBG > adjustedTargetBG && target_bg > adjustedTargetBG) {
+ console.error("target_bg from "+target_bg+" to "+adjustedTargetBG+"; ");
+ target_bg = adjustedTargetBG;
+ } else {
+ console.error("target_bg unchanged: "+target_bg+"; ");
+ }
+ // if eventualBG, naive_eventualBG, and max_bg aren't all above adjustedMaxBG, don’t use it
+ if (eventualBG > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) {
+ console.error("max_bg from "+max_bg+" to "+adjustedMaxBG);
+ max_bg = adjustedMaxBG;
+ } else {
+ console.error("max_bg unchanged: "+max_bg);
+ }
+ }
+
+ var expectedDelta = calculate_expected_delta(target_bg, eventualBG, bgi);
+ if (typeof eventualBG === 'undefined' || isNaN(eventualBG)) {
+ rT.error ='Error: could not calculate eventualBG. ';
+ return rT;
+ }
+
+ // min_bg of 90 -> threshold of 65, 100 -> 70 110 -> 75, and 130 -> 85
+ var threshold = min_bg - 0.5*(min_bg-40);
+
+ //console.error(reservoir_data);
+
+ rT = {
+ 'temp': 'absolute'
+ , 'bg': bg
+ , 'tick': tick
+ , 'eventualBG': eventualBG
+ //, 'snoozeBG': snoozeBG
+ , 'insulinReq': 0
+ , 'reservoir' : reservoir_data // The expected reservoir volume at which to deliver the microbolus (the reservoir volume from right before the last pumphistory run)
+ , 'deliverAt' : deliverAt // The time at which the microbolus should be delivered
+ , 'sensitivityRatio' : sensitivityRatio // autosens ratio (fraction of normal basal)
+ };
+
+ // generate predicted future BGs based on IOB, COB, and current absorption rate
+
+ var COBpredBGs = [];
+ var aCOBpredBGs = [];
+ var IOBpredBGs = [];
+ var UAMpredBGs = [];
+ var ZTpredBGs = [];
+ COBpredBGs.push(bg);
+ aCOBpredBGs.push(bg);
+ IOBpredBGs.push(bg);
+ ZTpredBGs.push(bg);
+ UAMpredBGs.push(bg);
+
+ // enable SMB whenever we have COB or UAM is enabled
+ // SMB is disabled by default, unless explicitly enabled in preferences.json
+ var enableSMB=false;
+ // disable SMB when a high temptarget is set
+ if (! microBolusAllowed) {
+ console.error("SMB disabled (!microBolusAllowed)")
+ } else if (! profile.allowSMB_with_high_temptarget && profile.temptargetSet && target_bg > 100) {
+ console.error("SMB disabled due to high temptarget of",target_bg);
+ enableSMB=false;
+ // enable SMB/UAM (if enabled in preferences) while we have COB
+ } else if (profile.enableSMB_with_COB === true && meal_data.mealCOB) {
+ if (meal_data.bwCarbs) {
+ if (profile.A52_risk_enable) {
+ console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard")
+ enableSMB=true;
+ } else {
+ console.error("SMB not enabled for Bolus Wizard COB");
+ }
+ } else {
+ console.error("SMB enabled for COB of",meal_data.mealCOB);
+ enableSMB=true;
+ }
+ // enable SMB/UAM (if enabled in preferences) for a full 6 hours after any carb entry
+ // (6 hours is defined in carbWindow in lib/meal/total.js)
+ } else if (profile.enableSMB_after_carbs === true && meal_data.carbs ) {
+ if (meal_data.bwCarbs) {
+ if (profile.A52_risk_enable) {
+ console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard")
+ enableSMB=true;
+ } else {
+ console.error("SMB not enabled for Bolus Wizard carbs");
+ }
+ } else {
+ console.error("SMB enabled for 6h after carb entry");
+ enableSMB=true;
+ }
+ // enable SMB/UAM (if enabled in preferences) if a low temptarget is set
+ } else if (profile.enableSMB_with_temptarget === true && (profile.temptargetSet && target_bg < 100)) {
+ if (meal_data.bwFound) {
+ if (profile.A52_risk_enable) {
+ console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard")
+ enableSMB=true;
+ } else {
+ console.error("enableSMB_with_temptarget not supported within 6h of using Bolus Wizard");
+ }
+ } else {
+ console.error("SMB enabled for temptarget of",convert_bg(target_bg, profile));
+ enableSMB=true;
+ }
+ // enable SMB/UAM if always-on (unless previously disabled for high temptarget)
+ } else if (profile.enableSMB_always === true) {
+ if (meal_data.bwFound) {
+ if (profile.A52_risk_enable === true) {
+ console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard")
+ enableSMB=true;
+ } else {
+ console.error("enableSMB_always not supported within 6h of using Bolus Wizard");
+ }
+ } else {
+ console.error("SMB enabled due to enableSMB_always");
+ enableSMB=true;
+ }
+ } else {
+ console.error("SMB disabled (no enableSMB preferences active)");
+ }
+ // enable UAM (if enabled in preferences) if SMB is enabled
+ var enableUAM=(profile.enableUAM && enableSMB);
+
+
+ //console.error(meal_data);
+ // carb impact and duration are 0 unless changed below
+ var ci = 0;
+ var cid = 0;
+ // calculate current carb absorption rate, and how long to absorb all carbs
+ // CI = current carb impact on BG in mg/dL/5m
+ ci = round((minDelta - bgi),1);
+ uci = round((minDelta - bgi),1);
+ // ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g)
+ if (profile.temptargetSet) {
+ // if temptargetSet, use unadjusted profile.sens to allow activity mode sensitivityRatio to adjust CR
+ var csf = profile.sens / profile.carb_ratio;
+ } else {
+ // otherwise, use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments
+ // so that autotuned CR is still in effect even when basals and ISF are being adjusted by autosens
+ var csf = sens / profile.carb_ratio;
+ }
+ var maxCarbAbsorptionRate = 30; // g/h; maximum rate to assume carbs will absorb if no CI observed
+ // limit Carb Impact to maxCarbAbsorptionRate * csf in mg/dL per 5m
+ maxCI = round(maxCarbAbsorptionRate*csf*5/60,1)
+ if (ci > maxCI) {
+ console.error("Limiting carb impact from",ci,"to",maxCI,"mg/dL/5m (",maxCarbAbsorptionRate,"g/h )");
+ ci = maxCI;
+ }
+ // set meal_carbimpact high enough to absorb all meal carbs over 6 hours
+ // total_impact (mg/dL) = CSF (mg/dL/g) * carbs (g)
+ //console.error(csf * meal_data.carbs);
+ // meal_carbimpact (mg/dL/5m) = CSF (mg/dL/g) * carbs (g) / 6 (h) * (1h/60m) * 5 (m/5m) * 2 (for linear decay)
+ //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1)
+ var remainingCATimeMin = 3; // h; before carb absorption starts
+ // adjust remainingCATime (instead of CR) for autosens
+ remainingCATimeMin = remainingCATimeMin / sensitivityRatio;
+ // 20 g/h means that anything <= 60g will get a remainingCATimeMin, 80g will get 4h, and 120g 6h
+ // when actual absorption ramps up it will take over from remainingCATime
+ var assumedCarbAbsorptionRate = 20; // g/h; maximum rate to assume carbs will absorb if no CI observed
+ var remainingCATime = remainingCATimeMin; // added by mike https://github.com/openaps/oref0/issues/884
+ if (meal_data.carbs) {
+ // if carbs * assumedCarbAbsorptionRate > remainingCATimeMin, raise it
+ // so <= 90g is assumed to take 3h, and 120g=4h
+ remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.mealCOB/assumedCarbAbsorptionRate);
+ var lastCarbAge = round(( new Date().getTime() - meal_data.lastCarbTime ) / 60000);
+ //console.error(meal_data.lastCarbTime, lastCarbAge);
+
+ fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs;
+ remainingCATime = remainingCATimeMin + 1.5 * lastCarbAge/60;
+ remainingCATime = round(remainingCATime,1);
+ //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime)
+ console.error("Last carbs",lastCarbAge,"minutes ago; remainingCATime:",remainingCATime,"hours;",round(fractionCOBAbsorbed*100)+"% carbs absorbed");
+ }
+
+ // calculate the number of carbs absorbed over remainingCATime hours at current CI
+ // CI (mg/dL/5m) * (5m)/5 (m) * 60 (min/hr) * 4 (h) / 2 (linear decay factor) = total carb impact (mg/dL)
+ var totalCI = Math.max(0, ci / 5 * 60 * remainingCATime / 2);
+ // totalCI (mg/dL) / CSF (mg/dL/g) = total carbs absorbed (g)
+ var totalCA = totalCI / csf;
+ var remainingCarbsCap = 90; // default to 90
+ var remainingCarbsFraction = 1;
+ if (profile.remainingCarbsCap) { remainingCarbsCap = Math.min(90,profile.remainingCarbsCap); }
+ if (profile.remainingCarbsFraction) { remainingCarbsFraction = Math.min(1,profile.remainingCarbsFraction); }
+ var remainingCarbsIgnore = 1 - remainingCarbsFraction;
+ var remainingCarbs = Math.max(0, meal_data.mealCOB - totalCA - meal_data.carbs*remainingCarbsIgnore);
+ remainingCarbs = Math.min(remainingCarbsCap,remainingCarbs);
+ // assume remainingCarbs will absorb in a /\ shaped bilinear curve
+ // peaking at remainingCATime / 2 and ending at remainingCATime hours
+ // area of the /\ triangle is the same as a remainingCIpeak-height rectangle out to remainingCATime/2
+ // remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / (remainingCATime/2) (h)
+ var remainingCIpeak = remainingCarbs * csf * 5 / 60 / (remainingCATime/2);
+ //console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI,remainingCATime);
+ //if (meal_data.mealCOB * 3 > meal_data.carbs) { }
+
+ // calculate peak deviation in last hour, and slope from that to current deviation
+ var slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation,2);
+ // calculate lowest deviation in last hour, and slope from that to current deviation
+ var slopeFromMinDeviation = round(meal_data.slopeFromMinDeviation,2);
+ // assume deviations will drop back down at least at 1/3 the rate they ramped up
+ var slopeFromDeviations = Math.min(slopeFromMaxDeviation,-slopeFromMinDeviation/3);
+ //console.error(slopeFromMaxDeviation);
+
+ aci = 10;
+ //5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m)
+ // duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m)
+ // limit cid to remainingCATime hours: the reset goes to remainingCI
+ if (ci == 0) {
+ // avoid divide by zero
+ cid = 0;
+ } else {
+ cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci ));
+ }
+ acid = Math.max(0, meal_data.mealCOB * csf / aci );
+ // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay)
+ console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (~2h peak):",round(remainingCIpeak,1),"mg/dL per 5m");
+ //console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours");
+ var minIOBPredBG = 999;
+ var minCOBPredBG = 999;
+ var minUAMPredBG = 999;
+ var minGuardBG = bg;
+ var minCOBGuardBG = 999;
+ var minUAMGuardBG = 999;
+ var minIOBGuardBG = 999;
+ var minZTGuardBG = 999;
+ var minPredBG;
+ var avgPredBG;
+ var IOBpredBG = eventualBG;
+ var maxIOBPredBG = bg;
+ var maxCOBPredBG = bg;
+ var maxUAMPredBG = bg;
+ //var maxPredBG = bg;
+ var eventualPredBG = bg;
+ var lastIOBpredBG;
+ var lastCOBpredBG;
+ var lastUAMpredBG;
+ var lastZTpredBG;
+ var UAMduration = 0;
+ var remainingCItotal = 0;
+ var remainingCIs = [];
+ var predCIs = [];
+ try {
+ iobArray.forEach(function(iobTick) {
+ //console.error(iobTick);
+ predBGI = round(( -iobTick.activity * sens * 5 ), 2);
+ predZTBGI = round(( -iobTick.iobWithZeroTemp.activity * sens * 5 ), 2);
+ // for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero
+ // over 60 minutes (data points every 5m)
+ predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) );
+ IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev;
+ // calculate predBGs with long zero temp without deviations
+ ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI;
+ // for COBpredBGs, predicted carb impact drops linearly from current carb impact down to zero
+ // eventually accounting for all carbs (if they can be absorbed over DIA)
+ predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) );
+ predACI = Math.max(0, Math.max(0,aci) * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) );
+ // if any carbs aren't absorbed after remainingCATime hours, assume they'll absorb in a /\ shaped
+ // bilinear curve peaking at remainingCIpeak at remainingCATime/2 hours (remainingCATime/2*12 * 5m)
+ // and ending at remainingCATime h (remainingCATime*12 * 5m intervals)
+ var intervals = Math.min( COBpredBGs.length, (remainingCATime*12)-COBpredBGs.length );
+ var remainingCI = Math.max(0, intervals / (remainingCATime/2*12) * remainingCIpeak );
+ remainingCItotal += predCI+remainingCI;
+ remainingCIs.push(round(remainingCI,0));
+ predCIs.push(round(predCI,0));
+ //console.error(round(predCI,1)+"+"+round(remainingCI,1)+" ");
+ COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI;
+ aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI;
+ // for UAMpredBGs, predicted carb impact drops at slopeFromDeviations
+ // calculate predicted CI from UAM based on slopeFromDeviations
+ predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*slopeFromDeviations ) );
+ // if slopeFromDeviations is too flat, predicted deviation impact drops linearly from
+ // current deviation down to zero over 3h (data points every 5m)
+ predUCImax = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(3*60/5,1) ) );
+ //console.error(predUCIslope, predUCImax);
+ // predicted CI from UAM is the lesser of CI based on deviationSlope or DIA
+ predUCI = Math.min(predUCIslope, predUCImax);
+ if(predUCI>0) {
+ //console.error(UAMpredBGs.length,slopeFromDeviations, predUCI);
+ UAMduration=round((UAMpredBGs.length+1)*5/60,1);
+ }
+ UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + predBGI + Math.min(0, predDev) + predUCI;
+ //console.error(predBGI, predCI, predUCI);
+ // truncate all BG predictions at 4 hours
+ if ( IOBpredBGs.length < 48) { IOBpredBGs.push(IOBpredBG); }
+ if ( COBpredBGs.length < 48) { COBpredBGs.push(COBpredBG); }
+ if ( aCOBpredBGs.length < 48) { aCOBpredBGs.push(aCOBpredBG); }
+ if ( UAMpredBGs.length < 48) { UAMpredBGs.push(UAMpredBG); }
+ if ( ZTpredBGs.length < 48) { ZTpredBGs.push(ZTpredBG); }
+ // calculate minGuardBGs without a wait from COB, UAM, IOB predBGs
+ if ( COBpredBG < minCOBGuardBG ) { minCOBGuardBG = round(COBpredBG); }
+ if ( UAMpredBG < minUAMGuardBG ) { minUAMGuardBG = round(UAMpredBG); }
+ if ( IOBpredBG < minIOBGuardBG ) { minIOBGuardBG = round(IOBpredBG); }
+ if ( ZTpredBG < minZTGuardBG ) { minZTGuardBG = round(ZTpredBG); }
+
+ // set minPredBGs starting when currently-dosed insulin activity will peak
+ // look ahead 60m (regardless of insulin type) so as to be less aggressive on slower insulins
+ var insulinPeakTime = 60;
+ // add 30m to allow for insluin delivery (SMBs or temps)
+ insulinPeakTime = 90;
+ var insulinPeak5m = (insulinPeakTime/60)*12;
+ //console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve);
+
+ // wait 90m before setting minIOBPredBG
+ if ( IOBpredBGs.length > insulinPeak5m && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); }
+ if ( IOBpredBG > maxIOBPredBG ) { maxIOBPredBG = IOBpredBG; }
+ // wait 85-105m before setting COB and 60m for UAM minPredBGs
+ if ( (cid || remainingCIpeak > 0) && COBpredBGs.length > insulinPeak5m && (COBpredBG < minCOBPredBG) ) { minCOBPredBG = round(COBpredBG); }
+ if ( (cid || remainingCIpeak > 0) && COBpredBG > maxIOBPredBG ) { maxCOBPredBG = COBpredBG; }
+ if ( enableUAM && UAMpredBGs.length > 12 && (UAMpredBG < minUAMPredBG) ) { minUAMPredBG = round(UAMpredBG); }
+ if ( enableUAM && UAMpredBG > maxIOBPredBG ) { maxUAMPredBG = UAMpredBG; }
+ });
+ // set eventualBG to include effect of carbs
+ //console.error("PredBGs:",JSON.stringify(predBGs));
+ } catch (e) {
+ console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled:",e);
+ }
+ if (meal_data.mealCOB) {
+ console.error("predCIs (mg/dL/5m):",predCIs.join(" "));
+ console.error("remainingCIs: ",remainingCIs.join(" "));
+ }
+ //,"totalCA:",round(totalCA,2),"remainingCItotal/csf+totalCA:",round(remainingCItotal/csf+totalCA,2));
+ rT.predBGs = {};
+ IOBpredBGs.forEach(function(p, i, theArray) {
+ theArray[i] = round(Math.min(401,Math.max(39,p)));
+ });
+ for (var i=IOBpredBGs.length-1; i > 12; i--) {
+ if (IOBpredBGs[i-1] != IOBpredBGs[i]) { break; }
+ else { IOBpredBGs.pop(); }
+ }
+ rT.predBGs.IOB = IOBpredBGs;
+ lastIOBpredBG=round(IOBpredBGs[IOBpredBGs.length-1]);
+ ZTpredBGs.forEach(function(p, i, theArray) {
+ theArray[i] = round(Math.min(401,Math.max(39,p)));
+ });
+ for (var i=ZTpredBGs.length-1; i > 6; i--) {
+ //if (ZTpredBGs[i-1] != ZTpredBGs[i]) { break; }
+ // stop displaying ZTpredBGs once they're rising and above target
+ if (ZTpredBGs[i-1] >= ZTpredBGs[i] || ZTpredBGs[i] < target_bg) { break; }
+ else { ZTpredBGs.pop(); }
+ }
+ rT.predBGs.ZT = ZTpredBGs;
+ lastZTpredBG=round(ZTpredBGs[ZTpredBGs.length-1]);
+ if (meal_data.mealCOB > 0) {
+ aCOBpredBGs.forEach(function(p, i, theArray) {
+ theArray[i] = round(Math.min(401,Math.max(39,p)));
+ });
+ for (var i=aCOBpredBGs.length-1; i > 12; i--) {
+ if (aCOBpredBGs[i-1] != aCOBpredBGs[i]) { break; }
+ else { aCOBpredBGs.pop(); }
+ }
+ // disable for now. may want to add a preference to re-enable
+ //rT.predBGs.aCOB = aCOBpredBGs;
+ }
+ if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
+ COBpredBGs.forEach(function(p, i, theArray) {
+ theArray[i] = round(Math.min(401,Math.max(39,p)));
+ });
+ for (var i=COBpredBGs.length-1; i > 12; i--) {
+ if (COBpredBGs[i-1] != COBpredBGs[i]) { break; }
+ else { COBpredBGs.pop(); }
+ }
+ rT.predBGs.COB = COBpredBGs;
+ lastCOBpredBG=round(COBpredBGs[COBpredBGs.length-1]);
+ eventualBG = Math.max(eventualBG, round(COBpredBGs[COBpredBGs.length-1]) );
+ }
+ if (ci > 0 || remainingCIpeak > 0) {
+ if (enableUAM) {
+ UAMpredBGs.forEach(function(p, i, theArray) {
+ theArray[i] = round(Math.min(401,Math.max(39,p)));
+ });
+ for (var i=UAMpredBGs.length-1; i > 12; i--) {
+ if (UAMpredBGs[i-1] != UAMpredBGs[i]) { break; }
+ else { UAMpredBGs.pop(); }
+ }
+ rT.predBGs.UAM = UAMpredBGs;
+ lastUAMpredBG=round(UAMpredBGs[UAMpredBGs.length-1]);
+ if (UAMpredBGs[UAMpredBGs.length-1]) {
+ eventualBG = Math.max(eventualBG, round(UAMpredBGs[UAMpredBGs.length-1]) );
+ }
+ }
+
+ // set eventualBG and snoozeBG based on COB or UAM predBGs
+ rT.eventualBG = eventualBG;
+ }
+
+ console.error("UAM Impact:",uci,"mg/dL per 5m; UAM Duration:",UAMduration,"hours");
+
+
+ minIOBPredBG = Math.max(39,minIOBPredBG);
+ minCOBPredBG = Math.max(39,minCOBPredBG);
+ minUAMPredBG = Math.max(39,minUAMPredBG);
+ minPredBG = round(minIOBPredBG);
+
+ var fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs;
+ // if we have COB and UAM is enabled, average both
+ if ( minUAMPredBG < 999 && minCOBPredBG < 999 ) {
+ // weight COBpredBG vs. UAMpredBG based on how many carbs remain as COB
+ avgPredBG = round( (1-fractionCarbsLeft)*UAMpredBG + fractionCarbsLeft*COBpredBG );
+ // if UAM is disabled, average IOB and COB
+ } else if ( minCOBPredBG < 999 ) {
+ avgPredBG = round( (IOBpredBG + COBpredBG)/2 );
+ // if we have UAM but no COB, average IOB and UAM
+ } else if ( minUAMPredBG < 999 ) {
+ avgPredBG = round( (IOBpredBG + UAMpredBG)/2 );
+ } else {
+ avgPredBG = round( IOBpredBG );
+ }
+ // if avgPredBG is below minZTGuardBG, bring it up to that level
+ if ( minZTGuardBG > avgPredBG ) {
+ avgPredBG = minZTGuardBG;
+ }
+
+ // if we have both minCOBGuardBG and minUAMGuardBG, blend according to fractionCarbsLeft
+ if ( (cid || remainingCIpeak > 0) ) {
+ if ( enableUAM ) {
+ minGuardBG = fractionCarbsLeft*minCOBGuardBG + (1-fractionCarbsLeft)*minUAMGuardBG;
+ } else {
+ minGuardBG = minCOBGuardBG;
+ }
+ } else if ( enableUAM ) {
+ minGuardBG = minUAMGuardBG;
+ } else {
+ minGuardBG = minIOBGuardBG;
+ }
+ minGuardBG = round(minGuardBG);
+ //console.error(minCOBGuardBG, minUAMGuardBG, minIOBGuardBG, minGuardBG);
+
+ var minZTUAMPredBG = minUAMPredBG;
+ // if minZTGuardBG is below threshold, bring down any super-high minUAMPredBG by averaging
+ // this helps prevent UAM from giving too much insulin in case absorption falls off suddenly
+ if ( minZTGuardBG < threshold ) {
+ minZTUAMPredBG = (minUAMPredBG + minZTGuardBG) / 2;
+ // if minZTGuardBG is between threshold and target, blend in the averaging
+ } else if ( minZTGuardBG < target_bg ) {
+ // target 100, threshold 70, minZTGuardBG 85 gives 50%: (85-70) / (100-70)
+ var blendPct = (minZTGuardBG-threshold) / (target_bg-threshold);
+ var blendedMinZTGuardBG = minUAMPredBG*blendPct + minZTGuardBG*(1-blendPct);
+ minZTUAMPredBG = (minUAMPredBG + blendedMinZTGuardBG) / 2;
+ //minZTUAMPredBG = minUAMPredBG - target_bg + minZTGuardBG;
+ // if minUAMPredBG is below minZTGuardBG, bring minUAMPredBG up by averaging
+ // this allows more insulin if lastUAMPredBG is below target, but minZTGuardBG is still high
+ } else if ( minZTGuardBG > minUAMPredBG ) {
+ minZTUAMPredBG = (minUAMPredBG + minZTGuardBG) / 2;
+ }
+ minZTUAMPredBG = round(minZTUAMPredBG);
+ //console.error("minUAMPredBG:",minUAMPredBG,"minZTGuardBG:",minZTGuardBG,"minZTUAMPredBG:",minZTUAMPredBG);
+ // if any carbs have been entered recently
+ if (meal_data.carbs) {
+ // average the minIOBPredBG and minUAMPredBG if available
+ /*
+ if ( minUAMPredBG < 999 ) {
+ avgMinPredBG = round( (minIOBPredBG+minUAMPredBG)/2 );
+ } else {
+ avgMinPredBG = minIOBPredBG;
+ }
+ */
+
+ // if UAM is disabled, use max of minIOBPredBG, minCOBPredBG
+ if ( ! enableUAM && minCOBPredBG < 999 ) {
+ minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG));
+ // if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher
+ } else if ( minCOBPredBG < 999 ) {
+ // calculate blendedMinPredBG based on how many carbs remain as COB
+ //blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minUAMPredBG;
+ blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG;
+ // if blendedMinPredBG > minCOBPredBG, use that instead
+ minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG));
+ // if carbs have been entered, but have expired, use minUAMPredBG
+ } else {
+ //minPredBG = minUAMPredBG;
+ minPredBG = minZTUAMPredBG;
+ }
+ // in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG
+ } else if ( enableUAM ) {
+ //minPredBG = round(Math.max(minIOBPredBG,minUAMPredBG));
+ minPredBG = round(Math.max(minIOBPredBG,minZTUAMPredBG));
+ }
+
+ // make sure minPredBG isn't higher than avgPredBG
+ minPredBG = Math.min( minPredBG, avgPredBG );
+
+ console.error("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG);
+ if (minCOBPredBG < 999) {
+ console.error(" minCOBPredBG: "+minCOBPredBG);
+ }
+ if (minUAMPredBG < 999) {
+ console.error(" minUAMPredBG: "+minUAMPredBG);
+ }
+ console.error(" avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"/",meal_data.carbs);
+ // But if the COB line falls off a cliff, don't trust UAM too much:
+ // use maxCOBPredBG if it's been set and lower than minPredBG
+ if ( maxCOBPredBG > bg ) {
+ minPredBG = Math.min(minPredBG, maxCOBPredBG);
+ }
+
+ rT.COB=meal_data.mealCOB;
+ rT.IOB=iob_data.iob;
+ rT.reason="COB: " + meal_data.mealCOB + ", Dev: " + convert_bg(deviation, profile) + ", BGI: " + convert_bg(bgi, profile) + ", ISF: " + convert_bg(sens, profile) + ", CR: " + round(profile.carb_ratio, 2) + ", Target: " + convert_bg(target_bg, profile) + ", minPredBG " + convert_bg(minPredBG, profile) + ", minGuardBG " + convert_bg(minGuardBG, profile) + ", IOBpredBG " + convert_bg(lastIOBpredBG, profile);
+ if (lastCOBpredBG > 0) {
+ rT.reason += ", COBpredBG " + convert_bg(lastCOBpredBG, profile);
+ }
+ if (lastUAMpredBG > 0) {
+ rT.reason += ", UAMpredBG " + convert_bg(lastUAMpredBG, profile)
+ }
+ rT.reason += "; ";
+ //var bgUndershoot = threshold - Math.min(minGuardBG, Math.max( naive_eventualBG, eventualBG ));
+ // use naive_eventualBG if above 40, but switch to minGuardBG if both eventualBGs hit floor of 39
+ //var carbsReqBG = Math.max( naive_eventualBG, eventualBG );
+ var carbsReqBG = naive_eventualBG;
+ if ( carbsReqBG < 40 ) {
+ carbsReqBG = Math.min( minGuardBG, carbsReqBG );
+ }
+ var bgUndershoot = threshold - carbsReqBG;
+ // calculate how long until COB (or IOB) predBGs drop below min_bg
+ var minutesAboveMinBG = 240;
+ var minutesAboveThreshold = 240;
+ if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
+ for (var i=0; i 0.20 * bg ) {
+ console.error("maxDelta",convert_bg(maxDelta, profile),"> 20% of BG",convert_bg(bg, profile),"- disabling SMB");
+ rT.reason += "maxDelta "+convert_bg(maxDelta, profile)+" > 20% of BG "+convert_bg(bg, profile)+": SMB disabled; ";
+ enableSMB = false;
+ }
+
+ console.error("BG projected to remain above",convert_bg(min_bg, profile),"for",minutesAboveMinBG,"minutes");
+ if ( minutesAboveThreshold < 240 || minutesAboveMinBG < 60 ) {
+ console.error("BG projected to remain above",convert_bg(threshold,profile),"for",minutesAboveThreshold,"minutes");
+ }
+ // include at least minutesAboveMinBG worth of zero temps in calculating carbsReq
+ // always include at least 30m worth of zero temp (carbs to 80, low temp up to target)
+ //var zeroTempDuration = Math.max(30,minutesAboveMinBG);
+ var zeroTempDuration = minutesAboveThreshold;
+ // BG undershoot, minus effect of zero temps until hitting min_bg, converted to grams, minus COB
+ var zeroTempEffect = profile.current_basal*sens*zeroTempDuration/60;
+ // don't count the last 25% of COB against carbsReq
+ var COBforCarbsReq = Math.max(0, meal_data.mealCOB - 0.25*meal_data.carbs);
+ var carbsReq = (bgUndershoot - zeroTempEffect) / csf - COBforCarbsReq;
+ zeroTempEffect = round(zeroTempEffect);
+ carbsReq = round(carbsReq);
+ console.error("naive_eventualBG:",naive_eventualBG,"bgUndershoot:",bgUndershoot,"zeroTempDuration:",zeroTempDuration,"zeroTempEffect:",zeroTempEffect,"carbsReq:",carbsReq);
+ if ( carbsReq >= profile.carbsReqThreshold && minutesAboveThreshold <= 45 ) {
+ rT.carbsReq = carbsReq;
+ rT.reason += carbsReq + " add'l carbs req w/in " + minutesAboveThreshold + "m; ";
+ }
+ // don't low glucose suspend if IOB is already super negative and BG is rising faster than predicted
+ if (bg < threshold && iob_data.iob < -profile.current_basal*20/60 && minDelta > 0 && minDelta > expectedDelta) {
+ rT.reason += "IOB "+iob_data.iob+" < " + round(-profile.current_basal*20/60,2);
+ rT.reason += " and minDelta " + convert_bg(minDelta, profile) + " > " + "expectedDelta " + convert_bg(expectedDelta, profile) + "; ";
+ // predictive low glucose suspend mode: BG is / is projected to be < threshold
+ } else if ( bg < threshold || minGuardBG < threshold ) {
+ rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile);
+ var bgUndershoot = target_bg - minGuardBG;
+ var worstCaseInsulinReq = bgUndershoot / sens;
+ var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
+ durationReq = round(durationReq/30)*30;
+ // always set a 30-120m zero temp (oref0-pump-loop will let any longer SMB zero temp run)
+ durationReq = Math.min(120,Math.max(30,durationReq));
+ return tempBasalFunctions.setTempBasal(0, durationReq, profile, rT, currenttemp);
+ }
+
+ if (eventualBG < min_bg) { // if eventual BG is below target:
+ rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " < " + convert_bg(min_bg, profile);
+ // if 5m or 30m avg BG is rising faster than expected delta
+ if ( minDelta > expectedDelta && minDelta > 0 && !carbsReq ) {
+ // if naive_eventualBG < 40, set a 30m zero temp (oref0-pump-loop will let any longer SMB zero temp run)
+ if (naive_eventualBG < 40) {
+ rT.reason += ", naive_eventualBG < 40. ";
+ return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp);
+ }
+ if (glucose_status.delta > minDelta) {
+ rT.reason += ", but Delta " + convert_bg(tick, profile) + " > expectedDelta " + convert_bg(expectedDelta, profile);
+ } else {
+ rT.reason += ", but Min. Delta " + minDelta.toFixed(2) + " > Exp. Delta " + convert_bg(expectedDelta, profile);
+ }
+ if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
+ rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
+ return rT;
+ } else {
+ rT.reason += "; setting current basal of " + basal + " as temp. ";
+ return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ }
+ }
+
+ // calculate 30m low-temp required to get projected BG up to target
+ // use snoozeBG to more gradually ramp in any counteraction of the user's boluses
+ // multiply by 2 to low-temp faster for increased hypo safety
+ //var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / sens);
+ var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / sens);
+ insulinReq = round( insulinReq , 2);
+ // calculate naiveInsulinReq based on naive_eventualBG
+ var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens);
+ naiveInsulinReq = round( naiveInsulinReq , 2);
+ if (minDelta < 0 && minDelta > expectedDelta) {
+ // if we're barely falling, newinsulinReq should be barely negative
+ //rT.reason += ", Snooze BG " + convert_bg(snoozeBG, profile);
+ var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2);
+ //console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
+ insulinReq = newinsulinReq;
+ }
+ // rate required to deliver insulinReq less insulin over 30m:
+ var rate = basal + (2 * insulinReq);
+ rate = round_basal(rate, profile);
+ // if required temp < existing temp basal
+ var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
+ // if current temp would deliver a lot (30% of basal) less than the required insulin,
+ // by both normal and naive calculations, then raise the rate
+ var minInsulinReq = Math.min(insulinReq,naiveInsulinReq);
+ if (insulinScheduled < minInsulinReq - basal*0.3) {
+ rT.reason += ", "+currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " is a lot less than needed. ";
+ return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
+ }
+ if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate >= currenttemp.rate * 0.8)) {
+ rT.reason += ", temp " + currenttemp.rate + " ~< req " + rate + "U/hr. ";
+ return rT;
+ } else {
+ // calculate a long enough zero temp to eventually correct back up to target
+ if ( rate <=0 ) {
+ var bgUndershoot = target_bg - naive_eventualBG;
+ var worstCaseInsulinReq = bgUndershoot / sens;
+ var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
+ if (durationReq < 0) {
+ durationReq = 0;
+ // don't set a temp longer than 120 minutes
+ } else {
+ durationReq = round(durationReq/30)*30;
+ durationReq = Math.min(120,Math.max(0,durationReq));
+ }
+ //console.error(durationReq);
+ //rT.reason += "insulinReq " + insulinReq + "; "
+ if (durationReq > 0) {
+ rT.reason += ", setting " + durationReq + "m zero temp. ";
+ return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp);
+ }
+ } else {
+ rT.reason += ", setting " + rate + "U/hr. ";
+ }
+ return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
+ }
+ }
+
+ // if eventual BG is above min but BG is falling faster than expected Delta
+ if (minDelta < expectedDelta) {
+ // if in SMB mode, don't cancel SMB zero temp
+ if (! (microBolusAllowed && enableSMB)) {
+ if (glucose_status.delta < minDelta) {
+ rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Delta " + convert_bg(tick, profile) + " < Exp. Delta " + convert_bg(expectedDelta, profile);
+ } else {
+ rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Min. Delta " + minDelta.toFixed(2) + " < Exp. Delta " + convert_bg(expectedDelta, profile);
+ }
+ if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
+ rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
+ return rT;
+ } else {
+ rT.reason += "; setting current basal of " + basal + " as temp. ";
+ return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ }
+ }
+ }
+ // eventualBG or minPredBG is below max_bg
+ if (Math.min(eventualBG,minPredBG) < max_bg) {
+ // if in SMB mode, don't cancel SMB zero temp
+ if (! (microBolusAllowed && enableSMB )) {
+ rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(minPredBG, profile)+" in range: no temp required";
+ if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
+ rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
+ return rT;
+ } else {
+ rT.reason += "; setting current basal of " + basal + " as temp. ";
+ return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ }
+ }
+ }
+
+ // eventual BG is at/above target
+ // if iob is over max, just cancel any temps
+ // if we're not here because of SMB, eventual BG is at/above target
+ if (! (microBolusAllowed && rT.COB)) {
+ rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " >= " + convert_bg(max_bg, profile) + ", ";
+ }
+ if (iob_data.iob > max_iob) {
+ rT.reason += "IOB " + round(iob_data.iob,2) + " > max_iob " + max_iob;
+ if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
+ rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
+ return rT;
+ } else {
+ rT.reason += "; setting current basal of " + basal + " as temp. ";
+ return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ }
+ } else { // otherwise, calculate 30m high-temp required to get projected BG down to target
+
+ // insulinReq is the additional insulin required to get minPredBG down to target_bg
+ //console.error(minPredBG,eventualBG);
+ //var insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
+ var insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
+ // when dropping, but not as fast as expected, reduce insulinReq proportionally
+ // to the what fraction of expectedDelta we're dropping at
+ //if (minDelta < 0 && minDelta > expectedDelta) {
+ //var newinsulinReq = round(( insulinReq * (1 - (minDelta / expectedDelta)) ), 2);
+ //console.error("Reducing insulinReq from " + insulinReq + " to " + newinsulinReq + " for minDelta " + minDelta + " vs. expectedDelta " + expectedDelta);
+ //insulinReq = newinsulinReq;
+ //}
+ // if that would put us over max_iob, then reduce accordingly
+ if (insulinReq > max_iob-iob_data.iob) {
+ rT.reason += "max_iob " + max_iob + ", ";
+ insulinReq = max_iob-iob_data.iob;
+ }
+
+ // rate required to deliver insulinReq more insulin over 30m:
+ var rate = basal + (2 * insulinReq);
+ rate = round_basal(rate, profile);
+ insulinReq = round(insulinReq,3);
+ rT.insulinReq = insulinReq;
+ //console.error(iob_data.lastBolusTime);
+ // minutes since last bolus
+ var lastBolusAge = round(( new Date().getTime() - iob_data.lastBolusTime ) / 60000,1);
+ //console.error(lastBolusAge);
+ //console.error(profile.temptargetSet, target_bg, rT.COB);
+ // only allow microboluses with COB or low temp targets, or within DIA hours of a bolus
+ if (microBolusAllowed && enableSMB && bg > threshold) {
+ // never bolus more than maxSMBBasalMinutes worth of basal
+ mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3);
+ if (typeof profile.maxSMBBasalMinutes == 'undefined' ) {
+ maxBolus = round( profile.current_basal * 30 / 60 ,1);
+ console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m");
+ // if IOB covers more than COB, limit maxBolus to 30m of basal
+ } else if ( iob_data.iob > mealInsulinReq && iob_data.iob > 0 ) {
+ console.error("IOB",iob_data.iob,"> COB",meal_data.mealCOB+"; mealInsulinReq =",mealInsulinReq);
+ maxBolus = round( profile.current_basal * 30 / 60 ,1);
+ } else {
+ console.error("profile.maxSMBBasalMinutes:",profile.maxSMBBasalMinutes,"profile.current_basal:",profile.current_basal);
+ maxBolus = round( profile.current_basal * profile.maxSMBBasalMinutes / 60 ,1);
+ }
+ // bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest 0.1U
+ microBolus = Math.floor(Math.min(insulinReq/2,maxBolus)*10)/10;
+ // calculate a long enough zero temp to eventually correct back up to target
+ var smbTarget = target_bg;
+ var worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens;
+ var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
+
+ // if insulinReq > 0 but not enough for a microBolus, don't set an SMB zero temp
+ if (insulinReq > 0 && microBolus < 0.1) {
+ durationReq = 0;
+ }
+
+ var smbLowTempReq = 0;
+ if (durationReq <= 0) {
+ durationReq = 0;
+ // don't set a temp longer than 120 minutes
+ } else if (durationReq >= 30) {
+ durationReq = round(durationReq/30)*30;
+ durationReq = Math.min(120,Math.max(0,durationReq));
+ } else {
+ // if SMB durationReq is less than 30m, set a nonzero low temp
+ smbLowTempReq = round( basal * durationReq/30 ,2);
+ durationReq = 30;
+ }
+ rT.reason += " insulinReq " + insulinReq;
+ if (microBolus >= maxBolus) {
+ rT.reason += "; maxBolus " + maxBolus;
+ }
+ if (durationReq > 0) {
+ rT.reason += "; setting " + durationReq + "m low temp of " + smbLowTempReq + "U/h";
+ }
+ rT.reason += ". ";
+
+ //allow SMBs every 3 minutes
+ var nextBolusMins = round(3-lastBolusAge,1);
+ //console.error(naive_eventualBG, insulinReq, worstCaseInsulinReq, durationReq);
+ console.error("naive_eventualBG",naive_eventualBG+",",durationReq+"m "+smbLowTempReq+"U/h temp needed; last bolus",lastBolusAge+"m ago; maxBolus: "+maxBolus);
+ if (lastBolusAge > 3) {
+ if (microBolus > 0) {
+ rT.units = microBolus;
+ rT.reason += "Microbolusing " + microBolus + "U. ";
+ }
+ } else {
+ rT.reason += "Waiting " + nextBolusMins + "m to microbolus again. ";
+ }
+ //rT.reason += ". ";
+
+ // if no zero temp is required, don't return yet; allow later code to set a high temp
+ if (durationReq > 0) {
+ rT.rate = smbLowTempReq;
+ rT.duration = durationReq;
+ return rT;
+ }
+
+ // if insulinReq is negative, snoozeBG > target_bg, and lastCOBpredBG > target_bg, set a neutral temp
+ //if (insulinReq < 0 && snoozeBG > target_bg && lastCOBpredBG > target_bg) {
+ //rT.reason += "; SMB bolus snooze: setting current basal of " + basal + " as temp. ";
+ //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
+ //}
+ }
+
+ var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
+
+ if (rate > maxSafeBasal) {
+ rT.reason += "adj. req. rate: "+rate+" to maxSafeBasal: "+maxSafeBasal+", ";
+ rate = round_basal(maxSafeBasal, profile);
+ }
+
+ var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
+ if (insulinScheduled >= insulinReq * 2) { // if current temp would deliver >2x more than the required insulin, lower the rate
+ rT.reason += currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " > 2 * insulinReq. Setting temp basal of " + rate + "U/hr. ";
+ return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
+ }
+
+ if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set
+ rT.reason += "no temp, setting " + rate + "U/hr. ";
+ return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
+ }
+
+ if (currenttemp.duration > 5 && (round_basal(rate, profile) <= round_basal(currenttemp.rate, profile))) { // if required temp <~ existing temp basal
+ rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr. ";
+ return rT;
+ }
+
+ // required temp > existing temp basal
+ rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr. ";
+ return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
+ }
+
+};
+
+module.exports = determine_basal;
diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java
index 3c8d6095ed..00c314787b 100644
--- a/app/src/main/java/info/nightscout/androidaps/Config.java
+++ b/app/src/main/java/info/nightscout/androidaps/Config.java
@@ -24,6 +24,8 @@ public class Config {
public static final boolean SMSCOMMUNICATORENABLED = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
+ public static final boolean displayDeviationSlope = false;
+
public static final boolean detailedLog = true;
public static final boolean logFunctionCalls = true;
public static final boolean logIncommingData = true;
diff --git a/app/src/main/java/info/nightscout/androidaps/Constants.java b/app/src/main/java/info/nightscout/androidaps/Constants.java
index 2d6ee910c8..e0549ab9bb 100644
--- a/app/src/main/java/info/nightscout/androidaps/Constants.java
+++ b/app/src/main/java/info/nightscout/androidaps/Constants.java
@@ -35,17 +35,6 @@ public class Constants {
public static final int CPP_MIN_TIMESHIFT = -6;
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
public static final double dailyLimitWarning = 0.95d;
diff --git a/app/src/main/java/info/nightscout/androidaps/HistoryBrowseActivity.java b/app/src/main/java/info/nightscout/androidaps/HistoryBrowseActivity.java
new file mode 100644
index 0000000000..b15aa42b84
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/HistoryBrowseActivity.java
@@ -0,0 +1,300 @@
+package info.nightscout.androidaps;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.SeekBar;
+
+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.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);
+
+ @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.overview_showprediction)
+ CheckBox showPredictionCheckbox;
+ @BindView(R.id.overview_showbasals)
+ CheckBox showBasalsCheckbox;
+ @BindView(R.id.overview_showiob)
+ CheckBox showIobCheckbox;
+ @BindView(R.id.overview_showcob)
+ CheckBox showCobCheckbox;
+ @BindView(R.id.overview_showdeviations)
+ CheckBox showDeviationsCheckbox;
+ @BindView(R.id.overview_showratios)
+ CheckBox showRatiosCheckbox;
+
+ 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);
+
+ // 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() {
+ }
+
+ @OnClick({R.id.overview_showbasals, R.id.overview_showprediction, R.id.overview_showiob, R.id.overview_showcob, R.id.overview_showdeviations, R.id.overview_showratios})
+ void onClickDate(View view) {
+ //((CheckBox) view).toggle();
+ updateGUI("checkboxToggle");
+ iobCobCalculatorPlugin.clearCache();
+ iobCobCalculatorPlugin.runCalculation("onClickDate", start, true, eventCustomCalculationFinished);
+ }
+
+
+ @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();
+ 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 && showBasalsCheckbox.isChecked()) {
+ 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;
+
+ if (showIobCheckbox.isChecked()) {
+ useIobForScale = true;
+ } else if (showCobCheckbox.isChecked()) {
+ useCobForScale = true;
+ } else if (showDeviationsCheckbox.isChecked()) {
+ useDevForScale = true;
+ } else if (showRatiosCheckbox.isChecked()) {
+ useRatioForScale = true;
+ }
+
+ if (showIobCheckbox.isChecked())
+ secondGraphData.addIob(fromTime, toTime, useIobForScale, 1d);
+ if (showCobCheckbox.isChecked())
+ secondGraphData.addCob(fromTime, toTime, useCobForScale, useCobForScale ? 1d : 0.5d);
+ if (showDeviationsCheckbox.isChecked())
+ secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1d);
+ if (showRatiosCheckbox.isChecked())
+ secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1d);
+
+ // **** NOW line ****
+ // set manual x bounds to have nice steps
+ secondGraphData.formatAxis(fromTime, toTime);
+ secondGraphData.addNowLine(pointer);
+
+ // do GUI update
+ if (showIobCheckbox.isChecked() || showCobCheckbox.isChecked() || showDeviationsCheckbox.isChecked() || showRatiosCheckbox.isChecked()) {
+ iobGraph.setVisibility(View.VISIBLE);
+ } else {
+ iobGraph.setVisibility(View.GONE);
+ }
+ // finally enforce drawing of graphs
+ graphData.performUpdate();
+ secondGraphData.performUpdate();
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
index fe6ab112ff..91446ada32 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
@@ -82,7 +82,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
Manifest.permission.WRITE_EXTERNAL_STORAGE}, CASE_STORAGE);
}
askForBatteryOptimizationPermission();
- checkUpgradeToProfileTarget();
+ doMigrations();
if (Config.logFunctionCalls)
log.debug("onCreate");
@@ -112,9 +112,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
runOnUiThread(new Runnable() {
@Override
public void run() {
- if(ev.recreate) {
+ if (ev.recreate) {
recreate();
- }else {
+ } else {
try { // activity may be destroyed
setUpTabs(true);
} catch (IllegalStateException e) {
@@ -163,6 +163,19 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
}
}
+ private void doMigrations() {
+
+ checkUpgradeToProfileTarget();
+
+ // guarantee that the unreachable threshold is at least 30 and of type String
+ // Added in 1.57 at 21.01.2018
+ Integer unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30);
+ SP.remove(R.string.key_pump_unreachable_threshold);
+ if (unreachable_threshold < 30) unreachable_threshold = 30;
+ SP.putString(R.string.key_pump_unreachable_threshold, unreachable_threshold.toString());
+ }
+
+
private void checkUpgradeToProfileTarget() { // TODO: can be removed in the future
boolean oldKeyExists = SP.contains("openapsma_min_bg");
if (oldKeyExists) {
@@ -346,6 +359,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
}
}, null);
break;
+ case R.id.nav_historybrowser:
+ startActivity(new Intent(v.getContext(), HistoryBrowseActivity.class));
+ break;
case R.id.nav_resetdb:
new AlertDialog.Builder(v.getContext())
.setTitle(R.string.nav_resetdb)
@@ -374,7 +390,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
case R.id.nav_about:
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
builder.setTitle(getString(R.string.app_name) + " " + BuildConfig.VERSION);
- if (Config.NSCLIENT|| Config.G5UPLOADER)
+ if (Config.NSCLIENT || Config.G5UPLOADER)
builder.setIcon(R.mipmap.yellowowl);
else
builder.setIcon(R.mipmap.blueowl);
diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java
index 44dbfa514e..ee3d437f97 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainApp.java
+++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java
@@ -44,9 +44,9 @@ import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugi
import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver;
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.OverviewPlugin;
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.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileSimple.SimpleProfilePlugin;
@@ -136,11 +136,10 @@ public class MainApp extends Application {
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin());
+ if (Config.APS) pluginsList.add(OpenAPSSMBPlugin.getPlugin());
pluginsList.add(NSProfilePlugin.getPlugin());
if (Config.OTHERPROFILES) pluginsList.add(SimpleProfilePlugin.getPlugin());
if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin());
- if (Config.OTHERPROFILES)
- pluginsList.add(CircadianPercentageProfileFragment.getPlugin());
pluginsList.add(TreatmentsPlugin.getPlugin());
if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin());
if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin());
@@ -235,6 +234,10 @@ public class MainApp extends Application {
return sResources.getString(id);
}
+ public static String gs(int id, Object... args) {
+ return sResources.getString(id, args);
+ }
+
public static MainApp instance() {
return sInstance;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java
index 5a0d84d1f7..ae3982ad68 100644
--- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java
@@ -16,6 +16,7 @@ import android.text.TextUtils;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin;
@@ -145,6 +146,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResourceIfEnabled(LoopPlugin.getPlugin(), PluginBase.LOOP);
addPreferencesFromResourceIfEnabled(OpenAPSMAPlugin.getPlugin(), PluginBase.APS);
addPreferencesFromResourceIfEnabled(OpenAPSAMAPlugin.getPlugin(), PluginBase.APS);
+ addPreferencesFromResourceIfEnabled(OpenAPSSMBPlugin.getPlugin(), PluginBase.APS);
}
addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginBase.SENSITIVITY);
diff --git a/app/src/main/java/info/nightscout/androidaps/Services/AlarmSoundService.java b/app/src/main/java/info/nightscout/androidaps/Services/AlarmSoundService.java
index 60dd92a2c1..f453b04d36 100644
--- a/app/src/main/java/info/nightscout/androidaps/Services/AlarmSoundService.java
+++ b/app/src/main/java/info/nightscout/androidaps/Services/AlarmSoundService.java
@@ -1,8 +1,10 @@
package info.nightscout.androidaps.Services;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
+import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.IBinder;
@@ -53,7 +55,10 @@ public class AlarmSoundService extends Service {
log.error("Unhandled exception", e);
}
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 {
player.prepare();
diff --git a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java
index e4d65eadc0..2bb7d8f9f0 100644
--- a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java
+++ b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java
@@ -15,20 +15,22 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
+import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg;
-import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
-import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
+import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
+import info.nightscout.androidaps.plugins.ProfileNS.events.EventNSProfileUpdateGUI;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin;
@@ -37,7 +39,6 @@ import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin;
import info.nightscout.androidaps.receivers.DataReceiver;
-import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
import info.nightscout.utils.BundleLogger;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
@@ -365,8 +366,10 @@ public class DataService extends IntentService {
String profile = bundles.getString("profile");
ProfileStore profileStore = new ProfileStore(new JSONObject(profile));
NSProfilePlugin.storeNewProfile(profileStore);
- MainApp.bus().post(new EventNewBasalProfile());
-
+ 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)
log.debug("Received profileStore: " + activeProfile + " " + profile);
} catch (JSONException e) {
@@ -597,7 +600,8 @@ public class DataService extends IntentService {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.ANNOUNCEMENT)) {
long date = trJson.getLong("mills");
long now = System.currentTimeMillis();
- if (date > now - 15 * 60 * 1000L && trJson.has("notes")) {
+ if (date > now - 15 * 60 * 1000L && trJson.has("notes")
+ && !(trJson.has("enteredBy") && trJson.getString("enteredBy").equals(SP.getString("careportal_enteredby", "AndroidAPS")))) {
Notification announcement = new Notification(Notification.NSANNOUNCEMENT, trJson.getString("notes"), Notification.ANNOUNCEMENT, 60);
MainApp.bus().post(new EventNewNotification(announcement));
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java b/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java
index 7720b03d3e..7d1dcac9ad 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java
@@ -29,6 +29,7 @@ public class DetailedBolusInfo {
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 boolean isSMB = false; // is a Super-MicroBolus
+ public long deliverAt = 0; // SMB should be delivered within 1 min from this time
@Override
public String toString() {
@@ -37,6 +38,7 @@ public class DetailedBolusInfo {
" carbs: " + carbs +
" isValid: " + isValid +
" carbTime: " + carbTime +
- " isSMB: " + isSMB;
+ " isSMB: " + isSMB +
+ " deliverAt: " + new Date(deliverAt).toLocaleString();
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java b/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java
index ad4f161799..1a5094253f 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java
@@ -35,6 +35,7 @@ public class GlucoseStatus {
public double avgdelta = 0d;
public double short_avgdelta = 0d;
public double long_avgdelta = 0d;
+ public long date = 0L;
@Override
@@ -133,6 +134,7 @@ public class GlucoseStatus {
GlucoseStatus status = new GlucoseStatus();
status.glucose = now.value;
+ status.date = now_date;
status.short_avgdelta = average(short_deltas);
diff --git a/app/src/main/java/info/nightscout/androidaps/data/Iob.java b/app/src/main/java/info/nightscout/androidaps/data/Iob.java
index ee70699604..762352782b 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/Iob.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/Iob.java
@@ -12,4 +12,26 @@ public class Iob {
activityContrib += iob.activityContrib;
return this;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Iob iob = (Iob) o;
+
+ if (Double.compare(iob.iobContrib, iobContrib) != 0) return false;
+ return Double.compare(iob.activityContrib, activityContrib) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ int result;
+ long temp;
+ temp = Double.doubleToLongBits(iobContrib);
+ result = (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(activityContrib);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java b/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
index 3240e79327..4bb55b0095 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
@@ -21,8 +21,11 @@ public class IobTotal {
public double hightempinsulin;
// oref1
- public double microBolusInsulin;
- public double microBolusIOB;
+ public long lastBolusTime;
+ public long lastTempDate;
+ public int lastTempDuration;
+ public double lastTempRate;
+ public IobTotal iobWithZeroTemp;
public double netInsulin = 0d; // for calculations from temp basals only
public double netRatio = 0d; // net ratio at start of temp basal
@@ -31,6 +34,23 @@ public class IobTotal {
long time;
+
+ public IobTotal clone() {
+ IobTotal copy = new IobTotal(time);
+ copy.iob = iob;
+ copy.activity = activity;
+ copy.bolussnooze = bolussnooze;
+ copy.basaliob = basaliob;
+ copy.netbasalinsulin = netbasalinsulin;
+ copy.hightempinsulin = hightempinsulin;
+ copy.lastBolusTime = lastBolusTime;
+ copy.lastTempDate = lastTempDate;
+ copy.lastTempDuration = lastTempDuration;
+ copy.lastTempRate = lastTempRate;
+ copy.iobWithZeroTemp = iobWithZeroTemp;
+ return copy;
+ }
+
public IobTotal(long time) {
this.iob = 0d;
this.activity = 0d;
@@ -38,8 +58,7 @@ public class IobTotal {
this.basaliob = 0d;
this.netbasalinsulin = 0d;
this.hightempinsulin = 0d;
- this.microBolusInsulin = 0d;
- this.microBolusIOB = 0d;
+ this.lastBolusTime = 0;
this.time = time;
}
@@ -52,8 +71,6 @@ public class IobTotal {
hightempinsulin += other.hightempinsulin;
netInsulin += other.netInsulin;
extendedBolusInsulin += other.extendedBolusInsulin;
- microBolusInsulin += other.microBolusInsulin;
- microBolusIOB += other.microBolusIOB;
return this;
}
@@ -62,11 +79,14 @@ public class IobTotal {
result.iob = bolusIOB.iob + basalIob.basaliob;
result.activity = bolusIOB.activity + basalIob.activity;
result.bolussnooze = bolusIOB.bolussnooze;
- result.basaliob = basalIob.basaliob;
- result.netbasalinsulin = basalIob.netbasalinsulin;
- result.hightempinsulin = basalIob.hightempinsulin;
- result.microBolusInsulin = bolusIOB.microBolusInsulin + basalIob.microBolusInsulin;
- result.microBolusIOB = bolusIOB.microBolusIOB + basalIob.microBolusIOB;
+ result.basaliob = bolusIOB.basaliob + basalIob.basaliob;
+ result.netbasalinsulin = bolusIOB.netbasalinsulin + basalIob.netbasalinsulin;
+ result.hightempinsulin = basalIob.hightempinsulin + bolusIOB.hightempinsulin;
+ result.lastBolusTime = bolusIOB.lastBolusTime;
+ result.lastTempDate = basalIob.lastTempDate;
+ result.lastTempRate = basalIob.lastTempRate;
+ result.lastTempDuration = basalIob.lastTempDuration;
+ result.iobWithZeroTemp = basalIob.iobWithZeroTemp;
return result;
}
@@ -77,8 +97,6 @@ public class IobTotal {
this.basaliob = Round.roundTo(this.basaliob, 0.001);
this.netbasalinsulin = Round.roundTo(this.netbasalinsulin, 0.001);
this.hightempinsulin = Round.roundTo(this.hightempinsulin, 0.001);
- this.microBolusInsulin = Round.roundTo(this.microBolusInsulin, 0.001);
- this.microBolusIOB = Round.roundTo(this.microBolusIOB, 0.001);
return this;
}
@@ -102,7 +120,24 @@ public class IobTotal {
json.put("basaliob", basaliob);
json.put("bolussnooze", bolussnooze);
json.put("activity", activity);
+ json.put("lastBolusTime", lastBolusTime);
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) {
log.error("Unhandled exception", e);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/MealData.java b/app/src/main/java/info/nightscout/androidaps/data/MealData.java
index 292d2272d5..054c76d602 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/MealData.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/MealData.java
@@ -7,4 +7,8 @@ public class MealData {
public double boluses = 0d;
public double carbs = 0d;
public double mealCOB = 0.0d;
+ public double slopeFromMaxDeviation = 0;
+ public double slopeFromMinDeviation = 999;
+ public long lastBolusTime;
+ public long lastCarbTime = 0L;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java
index 5235545362..849fcb97c0 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java
@@ -239,6 +239,7 @@ public class Profile {
// if pump not available (at start)
// do not store converted array
basal_v = null;
+ isValidated = false;
}
}
@@ -412,6 +413,8 @@ public class Profile {
}
public String getBasalList() {
+ if (basal_v == null)
+ basal_v = convertToSparseArray(basal);
return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U");
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java b/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java
index c50166d5a4..d19b3316ac 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java
@@ -57,6 +57,10 @@ public class PumpEnactResult extends Object {
return this;
}
+ public PumpEnactResult percent(Integer percent) {
+ this.percent = percent;
+ return this;
+ }
public PumpEnactResult isPercent(boolean isPercent) {
this.isPercent = isPercent;
return this;
@@ -111,7 +115,7 @@ public class PumpEnactResult extends Object {
}
public Spanned toSpanned() {
- String ret = MainApp.sResources.getString(R.string.success) + ": " + success;
+ String ret = "" + MainApp.sResources.getString(R.string.success) + ": " + success;
if (queued) {
ret = MainApp.sResources.getString(R.string.waitingforpumpresult);
} else if (enacted) {
@@ -119,17 +123,20 @@ public class PumpEnactResult extends Object {
ret += "
" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted;
ret += "
" + MainApp.sResources.getString(R.string.comment) + ": " + comment +
"
" + MainApp.sResources.getString(R.string.canceltemp);
- } else if (isPercent) {
+ } else if (isPercent && percent != -1) {
ret += "
" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted;
ret += "
" + MainApp.sResources.getString(R.string.comment) + ": " + comment;
ret += "
" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min";
ret += "
" + MainApp.sResources.getString(R.string.percent) + ": " + percent + "%";
- } else {
+ } else if (absolute != -1) {
ret += "
" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted;
ret += "
" + MainApp.sResources.getString(R.string.comment) + ": " + comment;
ret += "
" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min";
ret += "
" + MainApp.sResources.getString(R.string.absolute) + ": " + DecimalFormatter.to2Decimal(absolute) + " U/h";
}
+ if (bolusDelivered > 0) {
+ ret += "
" + MainApp.sResources.getString(R.string.bolus) + ": " + DecimalFormatter.to2Decimal(bolusDelivered) + " U";
+ }
} else {
ret += "
" + MainApp.sResources.getString(R.string.comment) + ": " + comment;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java b/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java
index 35a7265f2a..b08926f119 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java
@@ -82,9 +82,9 @@ public class QuickWizardEntry {
double cob = 0d;
AutosensData autosensData;
if (_synchronized)
- autosensData = IobCobCalculatorPlugin.getLastAutosensDataSynchronized("QuickWizard COB");
+ autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensDataSynchronized("QuickWizard COB");
else
- autosensData = IobCobCalculatorPlugin.getLastAutosensData("QuickWizard COB");
+ autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensData("QuickWizard COB");
if (autosensData != null && useCOB() == YES) {
cob = autosensData.cob;
diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
index c8d5295811..e842979ecb 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
@@ -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.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
-import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP;
@@ -43,7 +42,11 @@ public class BgReading implements DataPointWithLabelInterface {
@DatabaseField
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() {
}
@@ -184,7 +187,10 @@ public class BgReading implements DataPointWithLabelInterface {
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
- return PointsWithLabelGraphSeries.Shape.POINT;
+ if (isPrediction())
+ return PointsWithLabelGraphSeries.Shape.PREDICTION;
+ else
+ return PointsWithLabelGraphSeries.Shape.BG;
}
@Override
@@ -205,7 +211,7 @@ public class BgReading implements DataPointWithLabelInterface {
highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units);
}
int color = MainApp.sResources.getColor(R.color.inrange);
- if (isPrediction)
+ if (isPrediction())
color = MainApp.sResources.getColor(R.color.prediction);
else if (valueToUnits(units) < lowLine)
color = MainApp.sResources.getColor(R.color.low);
@@ -214,4 +220,23 @@ public class BgReading implements DataPointWithLabelInterface {
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;
+ }
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
index b80f4f932e..e2e4e6d639 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
@@ -5,6 +5,7 @@ import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
+import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
@@ -184,13 +185,24 @@ public class CareportalEvent implements DataPointWithLabelInterface {
try {
JSONObject object = new JSONObject(json);
if (object.has("notes"))
- return object.getString("notes");
+ return StringUtils.abbreviate(object.getString("notes"), 40);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return Translator.translate(eventType);
}
+ public String getNotes() {
+ try {
+ JSONObject object = new JSONObject(json);
+ if (object.has("notes"))
+ return object.getString("notes");
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ return "";
+ }
+
@Override
public long getDuration() {
try {
@@ -242,4 +254,9 @@ public class CareportalEvent implements DataPointWithLabelInterface {
return Color.GRAY;
return Color.GRAY;
}
+
+ @Override
+ public int getSecondColor() {
+ return 0;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
index 69bc542dae..fe59b49137 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
@@ -225,9 +225,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
log.error("Unhandled exception", e);
}
VirtualPumpPlugin.setFakingStatus(true);
- scheduleBgChange(); // trigger refresh
+ scheduleBgChange(null); // trigger refresh
scheduleTemporaryBasalChange();
- scheduleTreatmentChange();
+ scheduleTreatmentChange(null);
scheduleExtendedBolusChange();
scheduleTemporaryTargetChange();
scheduleCareportalEventChange();
@@ -252,7 +252,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
- scheduleTreatmentChange();
+ scheduleTreatmentChange(null);
}
public void resetTempTargets() {
@@ -358,7 +358,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (old == null) {
getDaoBgReadings().create(bgReading);
log.debug("BG: New record from: " + from + " " + bgReading.toString());
- scheduleBgChange();
+ scheduleBgChange(bgReading);
return true;
}
if (!old.isEqual(bgReading)) {
@@ -366,7 +366,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(bgReading);
getDaoBgReadings().update(old);
log.debug("BG: Updating record from: " + from + " New data: " + old.toString());
- scheduleBgChange();
+ scheduleBgChange(bgReading);
return false;
}
} catch (SQLException e) {
@@ -384,11 +384,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
- private static void scheduleBgChange() {
+ private static void scheduleBgChange(@Nullable final BgReading bgReading) {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventNewBg");
- MainApp.bus().post(new EventNewBG());
+ MainApp.bus().post(new EventNewBG(bgReading));
scheduledBgPost = null;
}
}
@@ -507,7 +507,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return 0;
}
- public int deleteDbRequestbyMongoId(String action, String id) {
+ public void deleteDbRequestbyMongoId(String action, String id) {
try {
QueryBuilder queryBuilder = getDaoDbRequest().queryBuilder();
Where where = queryBuilder.where();
@@ -515,16 +515,13 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
queryBuilder.limit(10L);
PreparedQuery preparedQuery = queryBuilder.prepare();
List dbList = getDaoDbRequest().query(preparedQuery);
- if (dbList.size() != 1) {
- log.error("deleteDbRequestbyMongoId query size: " + dbList.size());
- } else {
- //log.debug("Treatment findTreatmentById found: " + trList.get(0).log());
- return delete(dbList.get(0));
+ log.error("deleteDbRequestbyMongoId query size: " + dbList.size());
+ for (DbRequest r : dbList) {
+ delete(r);
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
- return 0;
}
public void deleteAllDbRequests() {
@@ -566,7 +563,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
- scheduleTreatmentChange();
+ scheduleTreatmentChange(treatment);
return true;
}
if (treatment.source == Source.NIGHTSCOUT) {
@@ -583,7 +580,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
}
- scheduleTreatmentChange();
+ scheduleTreatmentChange(treatment);
return true;
}
return false;
@@ -608,7 +605,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
}
- scheduleTreatmentChange();
+ scheduleTreatmentChange(treatment);
return true;
}
}
@@ -616,14 +613,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
- scheduleTreatmentChange();
+ scheduleTreatmentChange(treatment);
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();
+ scheduleTreatmentChange(treatment);
return true;
}
} catch (SQLException e) {
@@ -639,7 +636,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
- scheduleTreatmentChange();
+ scheduleTreatmentChange(treatment);
}
public void update(Treatment treatment) {
@@ -649,7 +646,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
- scheduleTreatmentChange();
+ scheduleTreatmentChange(treatment);
}
public void deleteTreatmentById(String _id) {
@@ -658,12 +655,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
log.debug("TREATMENT: Removing Treatment record from database: " + stored.toString());
delete(stored);
updateEarliestDataChange(stored.date);
- scheduleTreatmentChange();
+ scheduleTreatmentChange(null);
}
}
@Nullable
- public Treatment findTreatmentById(String _id) {
+ private Treatment findTreatmentById(String _id) {
try {
Dao daoTreatments = getDaoTreatments();
QueryBuilder queryBuilder = daoTreatments.queryBuilder();
@@ -695,11 +692,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
- private static void scheduleTreatmentChange() {
+ private static void scheduleTreatmentChange(@Nullable final Treatment treatment) {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventTreatmentChange");
- MainApp.bus().post(new EventReloadTreatmentData(new EventTreatmentChange()));
+ MainApp.bus().post(new EventReloadTreatmentData(new EventTreatmentChange(treatment)));
if (earliestDataChange != null)
MainApp.bus().post(new EventNewHistoryData(earliestDataChange));
earliestDataChange = null;
@@ -1473,7 +1470,21 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
- return new ArrayList();
+ return new ArrayList<>();
+ }
+
+ public List getCareportalEventsFromTime(boolean ascending) {
+ try {
+ List careportalEvents;
+ QueryBuilder queryBuilder = getDaoCareportalEvents().queryBuilder();
+ queryBuilder.orderBy("date", ascending);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ careportalEvents = getDaoCareportalEvents().query(preparedQuery);
+ return careportalEvents;
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return new ArrayList<>();
}
public void deleteCareportalEventById(String _id) {
@@ -1731,4 +1742,4 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
// ---------------- Food handling ---------------
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java b/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java
index 4232a2fc86..7bd60fe496 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java
@@ -285,4 +285,9 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
public int getColor() {
return Color.CYAN;
}
+
+ @Override
+ public int getSecondColor() {
+ return 0;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java b/app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java
index 992e328532..a933c2166e 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java
@@ -70,7 +70,7 @@ public class FoodHelper {
public boolean createOrUpdate(Food food) {
try {
// find by NS _id
- if (food._id != null) {
+ if (food._id != null && !food._id.equals("")) {
Food old;
QueryBuilder queryBuilder = getDaoFood().queryBuilder();
@@ -90,12 +90,13 @@ public class FoodHelper {
} else {
return false;
}
+ } else {
+ getDaoFood().createOrUpdate(food);
+ log.debug("FOOD: New record: " + food.toString());
+ scheduleFoodChange();
+ return true;
}
}
- getDaoFood().createOrUpdate(food);
- log.debug("FOOD: New record: " + food.toString());
- scheduleFoodChange();
- return true;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java b/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java
index dcce69639f..ba2f2758e2 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java
@@ -238,6 +238,11 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
return Color.CYAN;
}
+ @Override
+ public int getSecondColor() {
+ return 0;
+ }
+
public String toString() {
return "ProfileSwitch{" +
"date=" + date +
diff --git a/app/src/main/java/info/nightscout/androidaps/db/Treatment.java b/app/src/main/java/info/nightscout/androidaps/db/Treatment.java
index 9de76e6bf8..78e1fb6282 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/Treatment.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/Treatment.java
@@ -12,6 +12,7 @@ import java.util.Objects;
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.interfaces.InsulinInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
@@ -139,7 +140,10 @@ public class Treatment implements DataPointWithLabelInterface {
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
- return PointsWithLabelGraphSeries.Shape.BOLUS;
+ if (isSMB)
+ return PointsWithLabelGraphSeries.Shape.SMB;
+ else
+ return PointsWithLabelGraphSeries.Shape.BOLUS;
}
@Override
@@ -149,12 +153,19 @@ public class Treatment implements DataPointWithLabelInterface {
@Override
public int getColor() {
- if (isValid)
+ if (isSMB)
+ return MainApp.sResources.getColor(R.color.tempbasal);
+ else if (isValid)
return Color.CYAN;
else
return MainApp.instance().getResources().getColor(android.R.color.holo_red_light);
}
+ @Override
+ public int getSecondColor() {
+ return 0;
+ }
+
@Override
public void setY(double y) {
yValue = y;
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.java b/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.java
new file mode 100644
index 0000000000..17262cfb85
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.java
@@ -0,0 +1,8 @@
+package info.nightscout.androidaps.events;
+
+/**
+ * Created by mike on 23.01.2018.
+ */
+
+public class EventAppInitialized extends Event {
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.java b/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.java
new file mode 100644
index 0000000000..e52761dc58
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.java
@@ -0,0 +1,8 @@
+package info.nightscout.androidaps.events;
+
+/**
+ * Created by mike on 13.02.2018.
+ */
+
+public class EventCustomCalculationFinished extends Event {
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.java b/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.java
index 2fb9919b00..dc4d434e0a 100644
--- a/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.java
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.java
@@ -1,7 +1,17 @@
package info.nightscout.androidaps.events;
+import android.support.annotation.Nullable;
+
+import info.nightscout.androidaps.db.BgReading;
+
/**
* Created by mike on 05.06.2016.
*/
public class EventNewBG extends EventLoop {
+ @Nullable
+ public final BgReading bgReading;
+
+ public EventNewBG(BgReading bgReading) {
+ this.bgReading = bgReading;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.java
index 439d9a7124..2a3581f9bf 100644
--- a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.java
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.java
@@ -1,7 +1,17 @@
package info.nightscout.androidaps.events;
+import android.support.annotation.Nullable;
+
+import info.nightscout.androidaps.db.Treatment;
+
/**
* Created by mike on 04.06.2016.
*/
public class EventTreatmentChange extends EventLoop {
+ @Nullable
+ public final Treatment treatment;
+
+ public EventTreatmentChange(Treatment treatment) {
+ this.treatment = treatment;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.java
index 7ecc89ef66..a45ab083e7 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.java
@@ -4,4 +4,5 @@ package info.nightscout.androidaps.interfaces;
* Created by mike on 20.06.2016.
*/
public interface BgSourceInterface {
+ boolean advancedFilteringSupported();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java
index 48efa587d8..0114b8a48d 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java
@@ -10,16 +10,16 @@ import info.nightscout.androidaps.db.Treatment;
*/
public interface InsulinInterface {
- final int FASTACTINGINSULIN = 0;
- final int FASTACTINGINSULINPROLONGED = 1;
- final int OREF_RAPID_ACTING = 2;
- final int OREF_ULTRA_RAPID_ACTING = 3;
- final int OREF_FREE_PEAK = 4;
+ int FASTACTINGINSULIN = 0;
+ int FASTACTINGINSULINPROLONGED = 1;
+ int OREF_RAPID_ACTING = 2;
+ int OREF_ULTRA_RAPID_ACTING = 3;
+ int OREF_FREE_PEAK = 4;
int getId();
String getFriendlyName();
String getComment();
double getDia();
- public Iob iobCalcForTreatment(Treatment treatment, long time, double dia);
+ Iob iobCalcForTreatment(Treatment treatment, long time, double dia);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
index d37693d494..701b226031 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
@@ -35,4 +35,6 @@ public class PumpDescription {
public double basalMinimumRate = 0.04d;
public boolean isRefillingCapable = false;
+
+ public boolean storesCarbInfo = true;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java
index 044b259ac9..134b419240 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java
@@ -30,6 +30,7 @@ public interface TreatmentsInterface {
List getTreatmentsFromHistory();
List getTreatments5MinBackFromHistory(long time);
+ long getLastBolusTime();
// real basals (not faked by extended bolus)
boolean isInHistoryRealTempBasalInProgress();
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java
index d6f56e501b..c36dfe8b4f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java
@@ -137,11 +137,11 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE);
} else {
- if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
+ ExtendedBolus activeExtendedBolus = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (activeExtendedBolus != null) {
extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.VISIBLE);
- ExtendedBolus running = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- extendedBolusCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + running.toString());
+ extendedBolusCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + activeExtendedBolus.toString());
} else {
extendedBolus.setVisibility(View.VISIBLE);
extendedBolusCancel.setVisibility(View.GONE);
@@ -153,10 +153,10 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.GONE);
} else {
- if (MainApp.getConfigBuilder().isTempBasalInProgress()) {
+ final TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
+ if (activeTemp != null) {
tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.VISIBLE);
- final TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
tempBasalCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + activeTemp.toStringShort());
} else {
tempBasal.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java
index 58d0603301..b2d2769034 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java
@@ -38,6 +38,7 @@ import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
+import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
@@ -45,6 +46,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseStatus;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
+import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
@@ -407,12 +409,23 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
else layout.setVisibility(View.GONE);
}
+ private void updateBGforDateTime() {
+ long millis = eventTime.getTime() - (150 * 1000L); // 2,5 * 60 * 1000
+ List 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
public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
eventTime.setYear(year - 1900);
eventTime.setMonth(monthOfYear);
eventTime.setDate(dayOfMonth);
dateButton.setText(DateUtil.dateString(eventTime));
+ updateBGforDateTime();
}
@Override
@@ -421,6 +434,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
eventTime.setMinutes(minute);
eventTime.setSeconds(second);
timeButton.setText(DateUtil.timeString(eventTime));
+ updateBGforDateTime();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Common/SubscriberFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Common/SubscriberFragment.java
index 74abc837fe..5ca9232646 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Common/SubscriberFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Common/SubscriberFragment.java
@@ -2,9 +2,12 @@ package info.nightscout.androidaps.plugins.Common;
import android.support.v4.app.Fragment;
+import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp;
abstract public class SubscriberFragment extends Fragment {
+ protected Unbinder unbinder;
+
@Override
public void onPause() {
super.onPause();
@@ -18,5 +21,12 @@ abstract public class SubscriberFragment extends Fragment {
updateGUI();
}
+ @Override public void onDestroyView() {
+ super.onDestroyView();
+ if (unbinder != null)
+ unbinder.unbind();
+ }
+
+
protected abstract void updateGUI();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java
index 99ff546eac..8b8b794c64 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java
@@ -23,11 +23,14 @@ import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileIntervals;
import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
+import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
@@ -144,6 +147,7 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
public void initialize() {
pluginList = MainApp.getPluginsList();
loadSettings();
+ MainApp.bus().post(new EventAppInitialized());
}
public void storeSettings() {
@@ -240,96 +244,90 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
ArrayList pluginsInCategory;
// PluginBase.APS
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
- activeAPS = (APSInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.APS);
- if (activeAPS != null) {
- if (Config.logConfigBuilder)
- log.debug("Selected APS interface: " + ((PluginBase) activeAPS).getName());
- for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(((PluginBase) activeAPS).getName())) {
- p.setFragmentVisible(PluginBase.APS, false);
- }
- }
- }
+ activeAPS = this.determineActivePlugin(APSInterface.class, PluginBase.APS);
// PluginBase.INSULIN
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class);
- activeInsulin = (InsulinInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.INSULIN);
- if (Config.logConfigBuilder)
- log.debug("Selected insulin interface: " + ((PluginBase) activeInsulin).getName());
- for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(((PluginBase) activeInsulin).getName())) {
- p.setFragmentVisible(PluginBase.INSULIN, false);
- }
- }
+ activeInsulin = this.determineActivePlugin(InsulinInterface.class, PluginBase.INSULIN);
// PluginBase.SENSITIVITY
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class);
- activeSensitivity = (SensitivityInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.SENSITIVITY);
- if (Config.logConfigBuilder)
- log.debug("Selected sensitivity interface: " + ((PluginBase) activeSensitivity).getName());
- for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(((PluginBase) activeSensitivity).getName())) {
- p.setFragmentVisible(PluginBase.SENSITIVITY, false);
- }
- }
+ activeSensitivity = this.determineActivePlugin(SensitivityInterface.class, PluginBase.SENSITIVITY);
// PluginBase.PROFILE
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
- activeProfile = (ProfileInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.PROFILE);
- if (Config.logConfigBuilder)
- log.debug("Selected profile interface: " + ((PluginBase) activeProfile).getName());
- for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(((PluginBase) activeProfile).getName())) {
- p.setFragmentVisible(PluginBase.PROFILE, false);
- }
- }
+ activeProfile = this.determineActivePlugin(ProfileInterface.class, PluginBase.PROFILE);
// PluginBase.BGSOURCE
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
- activeBgSource = (BgSourceInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.BGSOURCE);
- if (Config.logConfigBuilder)
- log.debug("Selected bgSource interface: " + ((PluginBase) activeBgSource).getName());
- for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(((PluginBase) activeBgSource).getName())) {
- p.setFragmentVisible(PluginBase.BGSOURCE, false);
- }
- }
+ activeBgSource = this.determineActivePlugin(BgSourceInterface.class, PluginBase.BGSOURCE);
// PluginBase.PUMP
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.PUMP);
activePump = (PumpInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.PUMP);
if (activePump == null)
activePump = VirtualPumpPlugin.getPlugin(); // for NSClient build
- if (Config.logConfigBuilder)
- log.debug("Selected pump interface: " + ((PluginBase) activePump).getName());
- for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(((PluginBase) activePump).getName())) {
- p.setFragmentVisible(PluginBase.PUMP, false);
- }
- }
+ this.setFragmentVisiblities(((PluginBase)activePump).getName(), pluginsInCategory, PluginBase.PUMP);
// PluginBase.LOOP
- pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.LOOP);
- activeLoop = (LoopPlugin) getTheOneEnabledInArray(pluginsInCategory, PluginBase.LOOP);
- if (activeLoop != null) {
- if (Config.logConfigBuilder)
- log.debug("Selected loop interface: " + activeLoop.getName());
- for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(activeLoop.getName())) {
- p.setFragmentVisible(PluginBase.LOOP, false);
- }
- }
- }
+ activeLoop = this.determineActivePlugin(PluginBase.LOOP);
// PluginBase.TREATMENT
- pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.TREATMENT);
- activeTreatments = (TreatmentsInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.TREATMENT);
+ activeTreatments = this.determineActivePlugin(PluginBase.TREATMENT);
+ }
+
+ /**
+ * disables the visibility for all fragments of Plugins with the given PluginType
+ * which are not equally named to the Plugin implementing the given Plugin Interface.
+ *
+ * @param pluginInterface
+ * @param pluginType
+ * @param
+ * @return
+ */
+ private T determineActivePlugin(Class pluginInterface, int pluginType) {
+ ArrayList pluginsInCategory;
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(pluginInterface);
+
+ return this.determineActivePlugin(pluginsInCategory, pluginType);
+ }
+
+ private T determineActivePlugin(int pluginType) {
+ ArrayList pluginsInCategory;
+ pluginsInCategory = MainApp.getSpecificPluginsList(pluginType);
+
+ return this.determineActivePlugin(pluginsInCategory, pluginType);
+ }
+
+ /**
+ * disables the visibility for all fragments of Plugins in the given pluginsInCategory
+ * with the given PluginType which are not equally named to the Plugin implementing the
+ * given Plugin Interface.
+ *
+ * TODO we are casting an interface to PluginBase, which seems to be rather odd, since
+ * TODO the interface is not implementing PluginBase (this is just avoiding errors through
+ * TODO conventions.
+ *
+ * @param pluginsInCategory
+ * @param pluginType
+ * @param
+ * @return
+ */
+ private T determineActivePlugin(ArrayList pluginsInCategory,
+ int pluginType) {
+ T activePlugin = (T) getTheOneEnabledInArray(pluginsInCategory, pluginType);
+
+ if (activePlugin != null) {
+ this.setFragmentVisiblities(((PluginBase)activePlugin).getName(),
+ pluginsInCategory, pluginType);
+ }
+
+ return activePlugin;
+ }
+
+ private void setFragmentVisiblities(String activePluginName, ArrayList pluginsInCategory,
+ int pluginType) {
if (Config.logConfigBuilder)
- log.debug("Selected treatment interface: " + ((PluginBase) activeTreatments).getName());
+ log.debug("Selected interface: " + activePluginName);
for (PluginBase p : pluginsInCategory) {
- if (!p.getName().equals(((PluginBase) activeTreatments).getName())) {
- p.setFragmentVisible(PluginBase.TREATMENT, false);
+ if (!p.getName().equals(activePluginName)) {
+ p.setFragmentVisible(pluginType, false);
}
}
}
@@ -351,33 +349,19 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
return found;
}
- /*
- * Ex Pump interface
- *
- * Config builder return itself as a pump and check constraints before it passes command to pump driver
- */
-
-
/**
* expect absolute request and allow both absolute and percent response based on pump capabilities
- *
- * @param request
- * @return
- * true if command is going to be executed
- * false if error
*/
-
- public boolean applyAPSRequest(APSResult request, Callback callback) {
+ public void applyAPSRequest(APSResult request, Callback callback) {
PumpInterface pump = getActivePump();
request.rate = applyBasalConstraints(request.rate);
- PumpEnactResult result;
if (!pump.isInitialized()) {
log.debug("applyAPSRequest: " + MainApp.sResources.getString(R.string.pumpNotInitialized));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.sResources.getString(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
}
- return false;
+ return;
}
if (pump.isSuspended()) {
@@ -385,43 +369,56 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.sResources.getString(R.string.pumpsuspended)).enacted(false).success(false)).run();
}
- return false;
+ return;
}
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: " + request.toString());
- if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
- if (isTempBasalInProgress()) {
+
+ if (request.tempBasalReqested) {
+ if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
+ if (isTempBasalInProgress()) {
+ if (Config.logCongigBuilderActions)
+ log.debug("applyAPSRequest: cancelTempBasal()");
+ getCommandQueue().cancelTempBasal(false, callback);
+ } else {
+ if (Config.logCongigBuilderActions)
+ log.debug("applyAPSRequest: Basal set correctly");
+ if (callback != null) {
+ callback.result(new PumpEnactResult().absolute(request.rate).duration(0).enacted(false).success(true).comment("Basal set correctly")).run();
+ }
+ }
+ } else if (isTempBasalInProgress()
+ && getTempBasalRemainingMinutesFromHistory() > 5
+ && Math.abs(request.rate - getTempBasalAbsoluteRateHistory()) < pump.getPumpDescription().basalStep) {
if (Config.logCongigBuilderActions)
- log.debug("applyAPSRequest: cancelTempBasal()");
- getCommandQueue().cancelTempBasal(false, callback);
- return true;
+ log.debug("applyAPSRequest: Temp basal set correctly");
+ if (callback != null) {
+ callback.result(new PumpEnactResult().absolute(getTempBasalAbsoluteRateHistory()).duration(getTempBasalFromHistory(System.currentTimeMillis()).getPlannedRemainingMinutes()).enacted(false).success(true).comment("Temp basal set correctly")).run();
+ }
} else {
if (Config.logCongigBuilderActions)
- log.debug("applyAPSRequest: Basal set correctly");
- if (callback != null) {
- callback.result(new PumpEnactResult().absolute(request.rate).duration(0).enacted(false).success(true).comment("Basal set correctly")).run();
- }
- return false;
+ log.debug("applyAPSRequest: setTempBasalAbsolute()");
+ getCommandQueue().tempBasalAbsolute(request.rate, request.duration, false, callback);
}
- } else if (isTempBasalInProgress()
- && getTempBasalRemainingMinutesFromHistory() > 5
- && Math.abs(request.rate - getTempBasalAbsoluteRateHistory()) < pump.getPumpDescription().basalStep) {
- if (Config.logCongigBuilderActions)
- log.debug("applyAPSRequest: Temp basal set correctly");
- if (callback != null) {
- callback.result(new PumpEnactResult().absolute(getTempBasalAbsoluteRateHistory()).duration(getTempBasalFromHistory(System.currentTimeMillis()).getPlannedRemainingMinutes()).enacted(false).success(true).comment("Temp basal set correctly")).run();
+ }
+
+ if (request.bolusRequested) {
+ long lastBolusTime = getLastBolusTime();
+ if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
+ log.debug("SMB requsted but still in 3 min interval");
+ } else {
+ DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
+ detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
+ detailedBolusInfo.insulin = request.smb;
+ detailedBolusInfo.isSMB = true;
+ detailedBolusInfo.source = Source.USER;
+ detailedBolusInfo.deliverAt = request.deliverAt;
+ getCommandQueue().bolus(detailedBolusInfo, callback);
}
- return false;
- } else {
- if (Config.logCongigBuilderActions)
- log.debug("applyAPSRequest: setTempBasalAbsolute()");
- getCommandQueue().tempBasalAbsolute(request.rate, request.duration, false, callback);
- return true;
}
}
-
/**
* Constraints interface
**/
@@ -596,6 +593,11 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
return activeTreatments.getTreatments5MinBackFromHistory(time);
}
+ @Override
+ public long getLastBolusTime() {
+ return activeTreatments.getLastBolusTime();
+ }
+
@Override
public boolean isInHistoryRealTempBasalInProgress() {
return activeTreatments.isInHistoryRealTempBasalInProgress();
@@ -786,10 +788,10 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
return profile;
}
}
- // Unable to determine profile, failover to default
- if (activeProfile.getProfile() == null)
- return null; //app not initialized
}
+ // Unable to determine profile, failover to default
+ if (activeProfile.getProfile() == null)
+ return null; //app not initialized
Profile defaultProfile = activeProfile.getProfile().getDefaultProfile();
if (defaultProfile != null)
return defaultProfile;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java
index 558cf0d02f..a5c00aab7f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java
@@ -61,7 +61,6 @@ public class FoodFragment extends SubscriberFragment {
Bundle savedInstanceState) {
try {
View view = inflater.inflate(R.layout.food_fragment, container, false);
-
filter = (EditText) view.findViewById(R.id.food_filter);
clearFilter = (ImageView) view.findViewById(R.id.food_clearfilter);
category = new SpinnerHelper(view.findViewById(R.id.food_category));
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java
index cbe5f2ff64..b91eefdc9c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java
@@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.Insulin;
+import com.squareup.otto.Bus;
+
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
@@ -44,38 +46,53 @@ public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterf
return true;
}
+ public Bus getBus() {
+ return MainApp.bus();
+ }
+
@Override
public double getDia() {
double dia = getUserDefinedDia();
if(dia >= MIN_DIA){
return dia;
} else {
- if((System.currentTimeMillis() - lastWarned) > 60*1000) {
- lastWarned = System.currentTimeMillis();
- Notification notification = new Notification(Notification.SHORT_DIA, String.format(MainApp.sResources.getString(R.string.dia_too_short), dia, MIN_DIA), Notification.URGENT);
- MainApp.bus().post(new EventNewNotification(notification));
- }
+ sendShortDiaNotification(dia);
return MIN_DIA;
}
}
+ void sendShortDiaNotification(double dia) {
+ if((System.currentTimeMillis() - lastWarned) > 60*1000) {
+ lastWarned = System.currentTimeMillis();
+ Notification notification = new Notification(Notification.SHORT_DIA, String.format(this.getNotificationPattern(), dia, MIN_DIA), Notification.URGENT);
+ this.getBus().post(new EventNewNotification(notification));
+ }
+ }
+
+ public String getNotificationPattern() {
+ return MainApp.sResources.getString(R.string.dia_too_short);
+ }
+
public double getUserDefinedDia() {
return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : MIN_DIA;
}
+ public Iob iobCalcForTreatment(Treatment treatment, long time) {
+ return this.iobCalcForTreatment(treatment, time, 0d);
+ }
+
@Override
public Iob iobCalcForTreatment(Treatment treatment, long time, double dia) {
Iob result = new Iob();
int peak = getPeak();
-
if (treatment.insulin != 0d) {
long bolusTime = treatment.date;
double t = (time - bolusTime) / 1000d / 60d;
- double td = getDia()*60; //getDIA() always > 5
+ double td = getDia()*60; //getDIA() always >= MIN_DIA
double tp = peak;
// force the IOB to 0 if over DIA hours have passed
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java
index e6d58178f5..dddea570be 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java
@@ -57,11 +57,15 @@ public class AutosensData {
public double cob = 0;
public double bgi = 0d;
public double delta = 0d;
+ public double avgDelta = 0d;
+ public double avgDeviation = 0d;
public double autosensRatio = 1d;
+ public double slopeFromMaxDeviation = 0;
+ public double slopeFromMinDeviation = 999;
public String log(long time) {
- return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " Bgi=" + bgi + " Deviation=" + deviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio;
+ 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() {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java
index fbbbe43ccc..83f71c2430 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java
@@ -1,8 +1,6 @@
package info.nightscout.androidaps.plugins.IobCobCalculator;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
+import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
@@ -24,15 +22,17 @@ import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal;
-import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.events.Event;
+import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventConfigBuilderChange;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
+import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
+import info.nightscout.utils.DateUtil;
/**
* Created by mike on 24.04.2017.
@@ -41,19 +41,19 @@ import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistor
public class IobCobCalculatorPlugin implements PluginBase {
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
- private static LongSparseArray iobTable = new LongSparseArray<>(); // oldest at index 0
- private static LongSparseArray autosensDataTable = new LongSparseArray<>(); // oldest at index 0
- private static LongSparseArray basalDataTable = new LongSparseArray<>(); // oldest at index 0
+ private LongSparseArray iobTable = new LongSparseArray<>(); // oldest at index 0
+ private LongSparseArray autosensDataTable = new LongSparseArray<>(); // oldest at index 0
+ private LongSparseArray basalDataTable = new LongSparseArray<>(); // oldest at index 0
- private static volatile List bgReadings = null; // newest at index 0
- private static volatile List bucketed_data = null;
+ private volatile List bgReadings = null; // newest at index 0
+ private volatile List bucketed_data = null;
- private static double dia = Constants.defaultDIA;
+ private double dia = Constants.defaultDIA;
- private static Handler sHandler = null;
- private static HandlerThread sHandlerThread = null;
+ final Object dataLock = new Object();
- private static final Object dataLock = new Object();
+ boolean stopCalculationTrigger = false;
+ private IobCobThread thread = null;
private static IobCobCalculatorPlugin plugin = null;
@@ -63,11 +63,11 @@ public class IobCobCalculatorPlugin implements PluginBase {
return plugin;
}
- public static LongSparseArray getAutosensDataTable() {
+ public LongSparseArray getAutosensDataTable() {
return autosensDataTable;
}
- public static List getBucketedData() {
+ public List getBucketedData() {
return bucketed_data;
}
@@ -131,18 +131,12 @@ public class IobCobCalculatorPlugin implements PluginBase {
return -1;
}
- IobCobCalculatorPlugin() {
+ public IobCobCalculatorPlugin() {
MainApp.bus().register(this);
- if (sHandlerThread == null) {
- sHandlerThread = new HandlerThread(IobCobCalculatorPlugin.class.getSimpleName(), Process.THREAD_PRIORITY_LOWEST);
- sHandlerThread.start();
- sHandler = new Handler(sHandlerThread.getLooper());
- }
- onNewBg(new EventNewBG());
}
@Nullable
- public static List getBucketedData(long fromTime) {
+ public List getBucketedData(long fromTime) {
//log.debug("Locking getBucketedData");
synchronized (dataLock) {
if (bucketed_data == null) {
@@ -160,7 +154,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
return null;
}
- private static int indexNewerThan(long time) {
+ private int indexNewerThan(long time) {
for (int index = 0; index < bucketed_data.size(); index++) {
if (bucketed_data.get(index).date < time)
return index - 1;
@@ -175,14 +169,9 @@ public class IobCobCalculatorPlugin implements PluginBase {
return rouded;
}
- private void loadBgData() {
- //log.debug("Locking loadBgData");
- synchronized (dataLock) {
- onNewProfile(null);
- bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)), false);
- log.debug("BG data loaded. Size: " + bgReadings.size());
- }
- //log.debug("Releasing loadBgData");
+ void loadBgData(long start) {
+ bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (start - 60 * 60 * 1000L * (24 + dia)), false);
+ log.debug("BG data loaded. Size: " + bgReadings.size() + " Start date: " + DateUtil.dateAndTimeString(start));
}
private boolean isAbout5minData() {
@@ -209,7 +198,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
}
- private void createBucketedData() {
+ void createBucketedData() {
if (isAbout5minData())
createBucketedData5min();
else
@@ -241,223 +230,97 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
private void createBucketedDataRecalculated() {
- synchronized (dataLock) {
- if (bgReadings == null || bgReadings.size() < 3) {
- bucketed_data = null;
- return;
+ if (bgReadings == null || bgReadings.size() < 3) {
+ bucketed_data = null;
+ return;
+ }
+
+ bucketed_data = new ArrayList<>();
+ long currentTime = bgReadings.get(0).date + 5 * 60 * 1000 - bgReadings.get(0).date % (5 * 60 * 1000) - 5 * 60 * 1000L;
+ //log.debug("First reading: " + new Date(currentTime).toLocaleString());
+
+ while (true) {
+ // test if current value is older than current time
+ BgReading newer = findNewer(currentTime);
+ BgReading older = findOlder(currentTime);
+ if (newer == null || older == null)
+ break;
+
+ double bgDelta = newer.value - older.value;
+ long timeDiffToNew = newer.date - currentTime;
+
+ double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta;
+ BgReading newBgreading = new BgReading();
+ newBgreading.date = currentTime;
+ newBgreading.value = Math.round(currentBg);
+ bucketed_data.add(newBgreading);
+ //log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
+ currentTime -= 5 * 60 * 1000L;
+
+ }
+ }
+
+
+ private void createBucketedData5min() {
+ if (bgReadings == null || bgReadings.size() < 3) {
+ bucketed_data = null;
+ return;
+ }
+
+ bucketed_data = new ArrayList<>();
+ bucketed_data.add(bgReadings.get(0));
+ int j = 0;
+ for (int i = 1; i < bgReadings.size(); ++i) {
+ long bgTime = bgReadings.get(i).date;
+ long lastbgTime = bgReadings.get(i - 1).date;
+ //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
+ if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
+ continue;
}
- bucketed_data = new ArrayList<>();
- long currentTime = bgReadings.get(0).date + 5 * 60 * 1000 - bgReadings.get(0).date % (5 * 60 * 1000) - 5 * 60 * 1000L;
- //log.debug("First reading: " + new Date(currentTime).toLocaleString());
+ long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
+ if (Math.abs(elapsed_minutes) > 8) {
+ // interpolate missing data points
+ double lastbg = bgReadings.get(i - 1).value;
+ elapsed_minutes = Math.abs(elapsed_minutes);
+ //console.error(elapsed_minutes);
+ long nextbgTime;
+ while (elapsed_minutes > 5) {
+ nextbgTime = lastbgTime - 5 * 60 * 1000;
+ j++;
+ BgReading newBgreading = new BgReading();
+ newBgreading.date = nextbgTime;
+ double gapDelta = bgReadings.get(i).value - lastbg;
+ //console.error(gapDelta, lastbg, elapsed_minutes);
+ double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
+ newBgreading.value = Math.round(nextbg);
+ //console.error("Interpolated", bucketed_data[j]);
+ bucketed_data.add(newBgreading);
+ //log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
- while (true) {
- // test if current value is older than current time
- BgReading newer = findNewer(currentTime);
- BgReading older = findOlder(currentTime);
- if (newer == null || older == null)
- break;
-
- double bgDelta = newer.value - older.value;
- long timeDiffToNew = newer.date - currentTime;
-
- double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta;
+ elapsed_minutes = elapsed_minutes - 5;
+ lastbg = nextbg;
+ lastbgTime = nextbgTime;
+ }
+ j++;
BgReading newBgreading = new BgReading();
- newBgreading.date = currentTime;
- newBgreading.value = Math.round(currentBg);
+ newBgreading.value = bgReadings.get(i).value;
+ newBgreading.date = bgTime;
bucketed_data.add(newBgreading);
- //log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
- currentTime -= 5 * 60 * 1000L;
-
+ //log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
+ } else if (Math.abs(elapsed_minutes) > 2) {
+ j++;
+ BgReading newBgreading = new BgReading();
+ newBgreading.value = bgReadings.get(i).value;
+ newBgreading.date = bgTime;
+ bucketed_data.add(newBgreading);
+ //log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
+ } else {
+ bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2;
+ //log.error("***** Average");
}
}
- }
-
-
- public void createBucketedData5min() {
- //log.debug("Locking createBucketedData");
- synchronized (dataLock) {
- if (bgReadings == null || bgReadings.size() < 3) {
- bucketed_data = null;
- return;
- }
-
- bucketed_data = new ArrayList<>();
- bucketed_data.add(bgReadings.get(0));
- int j = 0;
- for (int i = 1; i < bgReadings.size(); ++i) {
- long bgTime = bgReadings.get(i).date;
- long lastbgTime = bgReadings.get(i - 1).date;
- //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
- if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
- continue;
- }
-
- long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
- if (Math.abs(elapsed_minutes) > 8) {
- // interpolate missing data points
- double lastbg = bgReadings.get(i - 1).value;
- elapsed_minutes = Math.abs(elapsed_minutes);
- //console.error(elapsed_minutes);
- long nextbgTime;
- while (elapsed_minutes > 5) {
- nextbgTime = lastbgTime - 5 * 60 * 1000;
- j++;
- BgReading newBgreading = new BgReading();
- newBgreading.date = nextbgTime;
- double gapDelta = bgReadings.get(i).value - lastbg;
- //console.error(gapDelta, lastbg, elapsed_minutes);
- double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
- newBgreading.value = Math.round(nextbg);
- //console.error("Interpolated", bucketed_data[j]);
- bucketed_data.add(newBgreading);
- //log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
-
- elapsed_minutes = elapsed_minutes - 5;
- lastbg = nextbg;
- lastbgTime = nextbgTime;
- }
- j++;
- BgReading newBgreading = new BgReading();
- newBgreading.value = bgReadings.get(i).value;
- newBgreading.date = bgTime;
- bucketed_data.add(newBgreading);
- //log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
- } else if (Math.abs(elapsed_minutes) > 2) {
- j++;
- BgReading newBgreading = new BgReading();
- newBgreading.value = bgReadings.get(i).value;
- newBgreading.date = bgTime;
- bucketed_data.add(newBgreading);
- //log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
- } else {
- bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2;
- //log.error("***** Average");
- }
- }
- log.debug("Bucketed data created. Size: " + bucketed_data.size());
- }
- //log.debug("Releasing createBucketedData");
- }
-
- private void calculateSensitivityData() {
- if (MainApp.getConfigBuilder() == null)
- return; // app still initializing
- if (MainApp.getConfigBuilder().getProfile() == null)
- return; // app still initializing
- //log.debug("Locking calculateSensitivityData");
- long oldestTimeWithData = oldestDataAvailable();
-
- synchronized (dataLock) {
-
- if (bucketed_data == null || bucketed_data.size() < 3) {
- log.debug("calculateSensitivityData: No bucketed data available");
- return;
- }
-
- long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
- log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
- AutosensData previous = autosensDataTable.get(prevDataTime);
- // start from oldest to be able sub cob
- for (int i = bucketed_data.size() - 4; i >= 0; i--) {
- // check if data already exists
- long bgTime = bucketed_data.get(i).date;
- bgTime = roundUpTime(bgTime);
- if (bgTime > System.currentTimeMillis())
- continue;
- Profile profile = MainApp.getConfigBuilder().getProfile(bgTime);
-
- AutosensData existing;
- if ((existing = autosensDataTable.get(bgTime)) != null) {
- previous = existing;
- continue;
- }
-
- if (profile.getIsf(bgTime) == null)
- return; // profile not set yet
-
- double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits());
-
- AutosensData autosensData = new AutosensData();
- autosensData.time = bgTime;
- if (previous != null)
- autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList);
- else
- autosensData.activeCarbsList = new ArrayList<>();
-
- //console.error(bgTime , bucketed_data[i].glucose);
- double bg;
- double avgDelta;
- double delta;
- bg = bucketed_data.get(i).value;
- if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
- log.error("! value < 39");
- continue;
- }
- delta = (bg - bucketed_data.get(i + 1).value);
-
- IobTotal iob = calculateFromTreatmentsAndTemps(bgTime);
-
- double bgi = -iob.activity * sens * 5;
- double deviation = delta - bgi;
-
- List recentTreatments = MainApp.getConfigBuilder().getTreatments5MinBackFromHistory(bgTime);
- for (int ir = 0; ir < recentTreatments.size(); ir++) {
- autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
- autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
- }
-
-
- // if we are absorbing carbs
- if (previous != null && previous.cob > 0) {
- // calculate sum of min carb impact from all active treatments
- double totalMinCarbsImpact = 0d;
- for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
- AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
- totalMinCarbsImpact += c.min5minCarbImpact;
- }
-
- // figure out how many carbs that represents
- // but always assume at least 3mg/dL/5m (default) absorption per active treatment
- double ci = Math.max(deviation, totalMinCarbsImpact);
- autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
- // and add that to the running total carbsAbsorbed
- autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
- autosensData.substractAbosorbedCarbs();
- }
- autosensData.removeOldCarbs(bgTime);
- autosensData.cob += autosensData.carbsFromBolus;
- autosensData.deviation = deviation;
- autosensData.bgi = bgi;
- autosensData.delta = delta;
-
- // calculate autosens only without COB
- if (autosensData.cob <= 0) {
- if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
- autosensData.pastSensitivity += "=";
- autosensData.nonEqualDeviation = true;
- } else if (deviation > 0) {
- autosensData.pastSensitivity += "+";
- autosensData.nonEqualDeviation = true;
- } else {
- autosensData.pastSensitivity += "-";
- autosensData.nonEqualDeviation = true;
- }
- autosensData.nonCarbsDeviation = true;
- } else {
- autosensData.pastSensitivity += "C";
- }
- //log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
-
- previous = autosensData;
- autosensDataTable.put(bgTime, autosensData);
- autosensData.autosensRatio = detectSensitivity(oldestTimeWithData, bgTime).ratio;
- if (Config.logAutosensData)
- log.debug(autosensData.log(bgTime));
- }
- }
- MainApp.bus().post(new EventAutosensCalculationFinished());
- //log.debug("Releasing calculateSensitivityData");
+ log.debug("Bucketed data created. Size: " + bucketed_data.size());
}
public static long oldestDataAvailable() {
@@ -469,13 +332,13 @@ public class IobCobCalculatorPlugin implements PluginBase {
return getBGDataFrom;
}
- public static IobTotal calculateFromTreatmentsAndTempsSynchronized(long time) {
+ public IobTotal calculateFromTreatmentsAndTempsSynchronized(long time) {
synchronized (dataLock) {
return calculateFromTreatmentsAndTemps(time);
}
}
- public static IobTotal calculateFromTreatmentsAndTemps(long time) {
+ public IobTotal calculateFromTreatmentsAndTemps(long time) {
long now = System.currentTimeMillis();
time = roundUpTime(time);
if (time < now && iobTable.get(time) != null) {
@@ -486,6 +349,21 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
IobTotal bolusIob = MainApp.getConfigBuilder().getCalculationToTimeTreatments(time).round();
IobTotal basalIob = MainApp.getConfigBuilder().getCalculationToTimeTempBasals(time).round();
+ if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginBase.APS)) {
+ // Add expected zere temp basal for next 240 mins
+ IobTotal basalIobWithZeroTemp = basalIob.clone();
+ TemporaryBasal t = new TemporaryBasal();
+ t.date = now + 60 * 1000L;
+ t.durationInMinutes = 240;
+ t.isAbsolute = true;
+ t.absoluteRate = 0;
+ if (t.date < time) {
+ IobTotal calc = t.iobCalc(time);
+ basalIobWithZeroTemp.plus(calc);
+ }
+
+ basalIob.iobWithZeroTemp = basalIobWithZeroTemp;
+ }
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
if (time < System.currentTimeMillis()) {
@@ -495,7 +373,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
@Nullable
- private static Long findPreviousTimeFromBucketedData(long time) {
+ private Long findPreviousTimeFromBucketedData(long time) {
if (bucketed_data == null)
return null;
for (int index = 0; index < bucketed_data.size(); index++) {
@@ -505,7 +383,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
return null;
}
- public static BasalData getBasalData(long time) {
+ public BasalData getBasalData(long time) {
long now = System.currentTimeMillis();
time = roundUpTime(time);
BasalData retval = basalDataTable.get(time);
@@ -531,7 +409,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
@Nullable
- public static AutosensData getAutosensData(long time) {
+ public AutosensData getAutosensData(long time) {
synchronized (dataLock) {
long now = System.currentTimeMillis();
if (time > now)
@@ -556,7 +434,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
@Nullable
- public static AutosensData getLastAutosensDataSynchronized(String reason) {
+ public AutosensData getLastAutosensDataSynchronized(String reason) {
synchronized (dataLock) {
return getLastAutosensData(reason);
}
@@ -564,7 +442,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
@Nullable
- public static AutosensData getLastAutosensData(String reason) {
+ public AutosensData getLastAutosensData(String reason) {
if (autosensDataTable.size() < 1) {
log.debug("AUTOSENSDATA null: autosensDataTable empty (" + reason + ")");
return null;
@@ -580,16 +458,16 @@ public class IobCobCalculatorPlugin implements PluginBase {
return null;
}
if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) {
- log.debug("AUTOSENSDATA null: data is old (" + reason + ")");
+ log.debug("AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + DateUtil.dateAndTimeString(data.time));
return null;
} else {
if (data == null)
- log.debug("AUTOSENSDATA null: data == null (" + " " + reason + ")");
+ log.debug("AUTOSENSDATA null: data == null (" + " " + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + DateUtil.dateAndTimeString(data.time));
return data;
}
}
- public static IobTotal[] calculateIobArrayInDia() {
+ public IobTotal[] calculateIobArrayInDia() {
Profile profile = MainApp.getConfigBuilder().getProfile();
// predict IOB out to DIA plus 30m
long time = System.currentTimeMillis();
@@ -606,13 +484,30 @@ public class IobCobCalculatorPlugin implements PluginBase {
return array;
}
- public static AutosensResult detectSensitivityWithLock(long fromTime, long toTime) {
+ public IobTotal[] calculateIobArrayForSMB() {
+ Profile profile = MainApp.getConfigBuilder().getProfile();
+ // 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);
+ array[pos] = iob;
+ pos++;
+ }
+ return array;
+ }
+
+ public AutosensResult detectSensitivityWithLock(long fromTime, long toTime) {
synchronized (dataLock) {
return detectSensitivity(fromTime, toTime);
}
}
- private static AutosensResult detectSensitivity(long fromTime, long toTime) {
+ static AutosensResult detectSensitivity(long fromTime, long toTime) {
return ConfigBuilderPlugin.getActiveSensitivity().detectSensitivity(fromTime, toTime);
}
@@ -625,19 +520,49 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
@Subscribe
- public void onNewBg(EventNewBG ev) {
- sHandler.post(new Runnable() {
- @Override
- public void run() {
- loadBgData();
- createBucketedData();
- calculateSensitivityData();
+ public void onEventAppInitialized(EventAppInitialized ev) {
+ if (this != getPlugin()) {
+ log.debug("Ignoring event for non default instance");
+ return;
+ }
+ runCalculation("onEventAppInitialized", System.currentTimeMillis(), true, ev);
+ }
+
+ @Subscribe
+ public void onEventNewBG(EventNewBG ev) {
+ if (this != getPlugin()) {
+ log.debug("Ignoring event for non default instance");
+ return;
+ }
+ stopCalculation("onEventNewBG");
+ runCalculation("onEventNewBG", System.currentTimeMillis(), true, ev);
+ }
+
+ private void stopCalculation(String from) {
+ if (thread != null && thread.getState() != Thread.State.TERMINATED) {
+ stopCalculationTrigger = true;
+ log.debug("Stopping calculation thread: " + from);
+ while (thread.getState() != Thread.State.TERMINATED) {
+ SystemClock.sleep(100);
}
- });
+ log.debug("Calculation thread stopped: " + from);
+ }
+ }
+
+ public void runCalculation(String from, long start, boolean bgDataReload, Event cause) {
+ log.debug("Starting calculation thread: " + from);
+ if (thread == null || thread.getState() == Thread.State.TERMINATED) {
+ thread = new IobCobThread(this, from, start, bgDataReload, cause);
+ thread.start();
+ }
}
@Subscribe
public void onNewProfile(EventNewBasalProfile ev) {
+ if (this != getPlugin()) {
+ log.debug("Ignoring event for non default instance");
+ return;
+ }
if (MainApp.getConfigBuilder() == null)
return; // app still initializing
Profile profile = MainApp.getConfigBuilder().getProfile();
@@ -647,66 +572,67 @@ public class IobCobCalculatorPlugin implements PluginBase {
if (ev == null) { // on init no need of reset
return;
}
+ stopCalculation("onNewProfile");
synchronized (dataLock) {
log.debug("Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>();
}
- sHandler.post(new Runnable() {
- @Override
- public void run() {
- calculateSensitivityData();
- }
- });
+ runCalculation("onNewProfile", System.currentTimeMillis(), false, ev);
}
@Subscribe
- public void onStatusEvent(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) ||
ev.isChanged(R.string.key_age) ||
ev.isChanged(R.string.key_absorption_maxtime)
) {
+ stopCalculation("onEventPreferenceChange");
synchronized (dataLock) {
log.debug("Invalidating cached data because of preference change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>();
}
- sHandler.post(new Runnable() {
- @Override
- public void run() {
- calculateSensitivityData();
- }
- });
+ runCalculation("onEventPreferenceChange", System.currentTimeMillis(), false, ev);
}
}
@Subscribe
- public void onStatusEvent(EventConfigBuilderChange ev) {
+ public void onEventConfigBuilderChange(EventConfigBuilderChange ev) {
+ if (this != getPlugin()) {
+ log.debug("Ignoring event for non default instance");
+ return;
+ }
+ stopCalculation("onEventConfigBuilderChange");
synchronized (dataLock) {
log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>();
}
- sHandler.post(new Runnable() {
- @Override
- public void run() {
- calculateSensitivityData();
- }
- });
+ runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, ev);
}
// When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
@Subscribe
- public void onNewHistoryData(EventNewHistoryData ev) {
+ public void onEventNewHistoryData(EventNewHistoryData ev) {
+ if (this != getPlugin()) {
+ log.debug("Ignoring event for non default instance");
+ return;
+ }
//log.debug("Locking onNewHistoryData");
+ stopCalculation("onEventNewHistoryData");
synchronized (dataLock) {
- long time = ev.time;
+ // clear up 5 min back for proper COB calculation
+ long time = ev.time - 5 * 60 * 1000L;
log.debug("Invalidating cached data to: " + new Date(time).toLocaleString());
for (int index = iobTable.size() - 1; index >= 0; index--) {
if (iobTable.keyAt(index) > time) {
if (Config.logAutosensData)
- if (Config.logAutosensData)
- log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
+ log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
iobTable.removeAt(index);
} else {
break;
@@ -731,15 +657,18 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
}
}
- sHandler.post(new Runnable() {
- @Override
- public void run() {
- calculateSensitivityData();
- }
- });
+ runCalculation("onEventNewHistoryData", System.currentTimeMillis(), false, ev);
//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
// Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobThread.java
new file mode 100644
index 0000000000..ba0475a26f
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobThread.java
@@ -0,0 +1,248 @@
+package info.nightscout.androidaps.plugins.IobCobCalculator;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.support.v4.util.LongSparseArray;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.Constants;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.data.IobTotal;
+import info.nightscout.androidaps.data.Profile;
+import info.nightscout.androidaps.db.BgReading;
+import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.events.Event;
+import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
+import info.nightscout.androidaps.queue.QueueThread;
+import info.nightscout.utils.DateUtil;
+
+/**
+ * Created by mike on 23.01.2018.
+ */
+
+public class IobCobThread extends Thread {
+ private static Logger log = LoggerFactory.getLogger(QueueThread.class);
+ private final Event cause;
+
+ private IobCobCalculatorPlugin iobCobCalculatorPlugin;
+ private boolean bgDataReload;
+ private String from;
+ private long start;
+
+ private PowerManager.WakeLock mWakeLock;
+
+ public IobCobThread(IobCobCalculatorPlugin plugin, String from, long start, boolean bgDataReload, Event cause) {
+ super();
+
+ this.iobCobCalculatorPlugin = plugin;
+ this.bgDataReload = bgDataReload;
+ this.from = from;
+ this.cause = cause;
+ this.start = start;
+
+ PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread");
+ }
+
+ @Override
+ public final void run() {
+ mWakeLock.acquire();
+ try {
+ if (MainApp.getConfigBuilder() == null) {
+ log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from);
+ return; // app still initializing
+ }
+ if (MainApp.getConfigBuilder().getProfile() == null) {
+ log.debug("Aborting calculation thread (No profile): " + from);
+ return; // app still initializing
+ }
+ //log.debug("Locking calculateSensitivityData");
+
+ Object dataLock = iobCobCalculatorPlugin.dataLock;
+
+ long oldestTimeWithData = iobCobCalculatorPlugin.oldestDataAvailable();
+
+ synchronized (dataLock) {
+ if (bgDataReload) {
+ iobCobCalculatorPlugin.loadBgData(start);
+ iobCobCalculatorPlugin.createBucketedData();
+ }
+ List bucketed_data = iobCobCalculatorPlugin.getBucketedData();
+ LongSparseArray autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
+
+ if (bucketed_data == null || bucketed_data.size() < 3) {
+ log.debug("Aborting calculation thread (No bucketed data available): " + from);
+ return;
+ }
+
+ long prevDataTime = iobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
+ log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
+ AutosensData previous = autosensDataTable.get(prevDataTime);
+ // start from oldest to be able sub cob
+ for (int i = bucketed_data.size() - 4; i >= 0; i--) {
+ if (iobCobCalculatorPlugin.stopCalculationTrigger) {
+ iobCobCalculatorPlugin.stopCalculationTrigger = false;
+ log.debug("Aborting calculation thread (trigger): " + from);
+ return;
+ }
+ // check if data already exists
+ long bgTime = bucketed_data.get(i).date;
+ bgTime = iobCobCalculatorPlugin.roundUpTime(bgTime);
+ if (bgTime > System.currentTimeMillis())
+ continue;
+ Profile profile = MainApp.getConfigBuilder().getProfile(bgTime);
+
+ AutosensData existing;
+ if ((existing = autosensDataTable.get(bgTime)) != null) {
+ previous = existing;
+ continue;
+ }
+
+ if (profile == null) {
+ log.debug("Aborting calculation thread (no profile): " + from);
+ 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)
+ log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
+
+ double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits());
+
+ AutosensData autosensData = new AutosensData();
+ autosensData.time = bgTime;
+ if (previous != null)
+ autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList);
+ else
+ autosensData.activeCarbsList = new ArrayList<>();
+
+ //console.error(bgTime , bucketed_data[i].glucose);
+ double bg;
+ double avgDelta;
+ double delta;
+ bg = bucketed_data.get(i).value;
+ if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
+ log.error("! value < 39");
+ continue;
+ }
+ delta = (bg - bucketed_data.get(i + 1).value);
+ avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
+
+ IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime);
+
+ double bgi = -iob.activity * sens * 5;
+ double deviation = delta - bgi;
+ double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000;
+
+ double currentDeviation;
+ 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.getAutosensData(hourago);
+ if (hourAgoData != null) {
+ currentDeviation = hourAgoData.avgDeviation;
+ int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time);
+
+ for (int past = 1; past < 12; past++) {
+ AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
+ double deviationSlope = (ad.avgDeviation - currentDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
+ if (ad.avgDeviation > maxDeviation) {
+ slopeFromMaxDeviation = Math.min(0, deviationSlope);
+ maxDeviation = ad.avgDeviation;
+ }
+ if (avgDeviation < minDeviation) {
+ slopeFromMinDeviation = Math.max(0, deviationSlope);
+ minDeviation = avgDeviation;
+ }
+
+ //if (Config.logAutosensData)
+ // log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation);
+ }
+ }
+ }
+
+ List recentTreatments = MainApp.getConfigBuilder().getTreatments5MinBackFromHistory(bgTime);
+ for (int ir = 0; ir < recentTreatments.size(); ir++) {
+ autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
+ autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
+ }
+
+
+ // if we are absorbing carbs
+ if (previous != null && previous.cob > 0) {
+ // calculate sum of min carb impact from all active treatments
+ double totalMinCarbsImpact = 0d;
+ for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
+ AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
+ totalMinCarbsImpact += c.min5minCarbImpact;
+ }
+
+ // figure out how many carbs that represents
+ // but always assume at least 3mg/dL/5m (default) absorption per active treatment
+ double ci = Math.max(deviation, totalMinCarbsImpact);
+ autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
+ // and add that to the running total carbsAbsorbed
+ autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
+ autosensData.substractAbosorbedCarbs();
+ }
+ autosensData.removeOldCarbs(bgTime);
+ autosensData.cob += autosensData.carbsFromBolus;
+ autosensData.deviation = deviation;
+ autosensData.bgi = bgi;
+ autosensData.delta = delta;
+ autosensData.avgDelta = avgDelta;
+ autosensData.avgDeviation = avgDeviation;
+ autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation;
+ autosensData.slopeFromMinDeviation = slopeFromMinDeviation;
+
+
+ // calculate autosens only without COB
+ if (autosensData.cob <= 0) {
+ if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
+ autosensData.pastSensitivity += "=";
+ autosensData.nonEqualDeviation = true;
+ } else if (deviation > 0) {
+ autosensData.pastSensitivity += "+";
+ autosensData.nonEqualDeviation = true;
+ } else {
+ autosensData.pastSensitivity += "-";
+ autosensData.nonEqualDeviation = true;
+ }
+ autosensData.nonCarbsDeviation = true;
+ } else {
+ autosensData.pastSensitivity += "C";
+ }
+ //log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
+
+ previous = autosensData;
+ autosensDataTable.put(bgTime, autosensData);
+ log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime));
+ autosensData.autosensRatio = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime).ratio;
+ if (Config.logAutosensData)
+ log.debug(autosensData.log(bgTime));
+ }
+ }
+ MainApp.bus().post(new EventAutosensCalculationFinished(cause));
+ log.debug("Finishing calculation thread: " + from);
+ } finally {
+ mWakeLock.release();
+ }
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/events/EventAutosensCalculationFinished.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/events/EventAutosensCalculationFinished.java
index ea73915436..2cb9b7ca4c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/events/EventAutosensCalculationFinished.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/events/EventAutosensCalculationFinished.java
@@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.IobCobCalculator.events;
+import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventLoop;
/**
@@ -7,4 +8,9 @@ import info.nightscout.androidaps.events.EventLoop;
*/
public class EventAutosensCalculationFinished extends EventLoop {
+ public Event cause;
+
+ public EventAutosensCalculationFinished(Event cause) {
+ this.cause = cause;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/APSResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/APSResult.java
index f8ca0ab8c4..8050aa7769 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/APSResult.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/APSResult.java
@@ -1,17 +1,22 @@
package info.nightscout.androidaps.plugins.Loop;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.text.Html;
import android.text.Spanned;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
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.R;
+import info.nightscout.androidaps.data.IobTotal;
+import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.utils.DecimalFormatter;
@@ -22,36 +27,64 @@ import info.nightscout.utils.DecimalFormatter;
public class APSResult {
private static Logger log = LoggerFactory.getLogger(APSResult.class);
+ public Date date;
public String reason;
public double rate;
public int duration;
- public boolean changeRequested = false;
+ public boolean tempBasalReqested = 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;
@Override
public String toString() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
- if (changeRequested) {
+ if (isChangeRequested()) {
+ String ret;
+ // rate
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
- return MainApp.sResources.getString(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " +
- "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%)\n" +
- MainApp.sResources.getString(R.string.duration) + ": " + DecimalFormatter.to0Decimal(duration) + " min\n" +
- MainApp.sResources.getString(R.string.reason) + ": " + reason;
+ ret = MainApp.sResources.getString(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " +
+ "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) \n" +
+ MainApp.sResources.getString(R.string.duration) + ": " + DecimalFormatter.to2Decimal(duration) + " min\n";
+
+ // smb
+ if (smb != 0)
+ ret += ("SMB: " + DecimalFormatter.to2Decimal(smb) + " U\n");
+
+ // reason
+ ret += MainApp.sResources.getString(R.string.reason) + ": " + reason;
+ return ret;
} else
return MainApp.sResources.getString(R.string.nochangerequested);
}
public Spanned toSpanned() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
- if (changeRequested) {
- String ret = "";
- if (rate == 0 && duration == 0) ret = MainApp.sResources.getString(R.string.canceltemp);
+ if (isChangeRequested()) {
+ String ret;
+ // rate
+ if (rate == 0 && duration == 0)
+ ret = MainApp.sResources.getString(R.string.canceltemp) + "
";
+ else if (rate == -1)
+ ret = MainApp.sResources.getString(R.string.let_temp_basal_run) + "
";
else
ret = "" + MainApp.sResources.getString(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " +
- "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%)
" +
- "" + MainApp.sResources.getString(R.string.duration) + ": " + DecimalFormatter.to2Decimal(duration) + " min
" +
- "" + MainApp.sResources.getString(R.string.reason) + ": " + reason.replace("<", "<").replace(">", ">");
+ "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%)
" +
+ "" + MainApp.sResources.getString(R.string.duration) + ": " + DecimalFormatter.to2Decimal(duration) + " min
";
+
+ // smb
+ if (smb != 0)
+ ret += ("" + "SMB" + ": " + DecimalFormatter.to2Decimal(smb) + " U
");
+
+ // reason
+ ret += "" + MainApp.sResources.getString(R.string.reason) + ": " + reason.replace("<", "<").replace(">", ">");
return Html.fromHtml(ret);
} else
return Html.fromHtml(MainApp.sResources.getString(R.string.nochangerequested));
@@ -62,17 +95,19 @@ public class APSResult {
public APSResult clone() {
APSResult newResult = new APSResult();
- newResult.reason = new String(reason);
+ newResult.reason = reason;
newResult.rate = rate;
newResult.duration = duration;
- newResult.changeRequested = changeRequested;
+ newResult.tempBasalReqested = tempBasalReqested;
+ newResult.bolusRequested = bolusRequested;
+ newResult.iob = iob;
return newResult;
}
public JSONObject json() {
JSONObject json = new JSONObject();
try {
- if (changeRequested) {
+ if (isChangeRequested()) {
json.put("rate", rate);
json.put("duration", duration);
json.put("reason", reason);
@@ -82,4 +117,105 @@ public class APSResult {
}
return json;
}
+
+ public List getPredictions() {
+ List 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 tempBasalReqested || bolusRequested;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java
index 539b9991a3..2debfa34c5 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java
@@ -6,7 +6,7 @@ import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
-import android.support.v7.app.NotificationCompat;
+import android.support.v4.app.NotificationCompat;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent;
@@ -30,9 +30,12 @@ import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
+import info.nightscout.androidaps.plugins.Loop.events.EventLoopResult;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
+import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
@@ -148,12 +151,16 @@ public class LoopPlugin implements PluginBase {
@Subscribe
public void onStatusEvent(final EventTreatmentChange ev) {
- invoke("EventTreatmentChange", true);
+ if (ev.treatment == null || !ev.treatment.isSMB){
+ invoke("EventTreatmentChange", true);
+ }
}
@Subscribe
- public void onStatusEvent(final EventNewBG ev) {
- invoke("EventNewBG", true);
+ public void onStatusEvent(final EventAutosensCalculationFinished ev) {
+ if (ev.cause instanceof EventNewBG) {
+ invoke(ev.getClass().getSimpleName() + "(" + ev.cause.getClass().getSimpleName() + ")", true);
+ }
}
public long suspendedTo() {
@@ -283,6 +290,14 @@ public class LoopPlugin implements PluginBase {
// check rate for constrais
final APSResult resultAfterConstraints = result.clone();
resultAfterConstraints.rate = constraintsInterface.applyBasalConstraints(resultAfterConstraints.rate);
+ resultAfterConstraints.smb = constraintsInterface.applyBolusConstraints(resultAfterConstraints.smb);
+
+ // 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();
lastRun.request = result;
@@ -305,8 +320,10 @@ public class LoopPlugin implements PluginBase {
return;
}
+ MainApp.bus().post(new EventLoopResult(resultAfterConstraints));
+
if (constraintsInterface.isClosedModeEnabled()) {
- if (result.changeRequested) {
+ if (result.isChangeRequested()) {
final PumpEnactResult waiting = new PumpEnactResult();
final PumpEnactResult previousResult = lastRun.setByPump;
waiting.queued = true;
@@ -330,7 +347,7 @@ public class LoopPlugin implements PluginBase {
lastRun.source = null;
}
} else {
- if (result.changeRequested && allowNotification) {
+ if (result.isChangeRequested() && allowNotification) {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(MainApp.instance().getApplicationContext());
builder.setSmallIcon(R.drawable.notif_icon)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/events/EventLoopResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/events/EventLoopResult.java
new file mode 100644
index 0000000000..5cbb24ea22
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/events/EventLoopResult.java
@@ -0,0 +1,12 @@
+package info.nightscout.androidaps.plugins.Loop.events;
+
+import info.nightscout.androidaps.plugins.Loop.APSResult;
+
+public class EventLoopResult {
+ public final APSResult apsResult;
+
+ public EventLoopResult(APSResult apsResult) {
+ this.apsResult = apsResult;
+ }
+}
+
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSDeviceStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSDeviceStatus.java
index 315e9724ce..d1755dd4c1 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSDeviceStatus.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSDeviceStatus.java
@@ -124,7 +124,7 @@ public class NSDeviceStatus {
static DeviceStatusPumpData deviceStatusPumpData = null;
public Spanned getExtendedPumpStatus() {
- if (deviceStatusPumpData.extended != null)
+ if (deviceStatusPumpData != null && deviceStatusPumpData.extended != null)
return deviceStatusPumpData.extended;
return Html.fromHtml("");
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java
index 466026e986..66d3ab2b96 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java
@@ -29,6 +29,7 @@ import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
import info.nightscout.androidaps.plugins.OpenAPSMA.LoggerCallback;
+import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
import info.nightscout.utils.SP;
public class DetermineBasalAdapterAMAJS {
@@ -189,8 +190,7 @@ public class DetermineBasalAdapterAMAJS {
GlucoseStatus glucoseStatus,
MealData mealData,
double autosensDataRatio,
- boolean tempTargetSet,
- double min_5m_carbimpact) throws JSONException {
+ boolean tempTargetSet) throws JSONException {
String units = profile.getUnits();
@@ -211,7 +211,7 @@ public class DetermineBasalAdapterAMAJS {
mProfile.put("current_basal", basalrate);
mProfile.put("temptargetSet", tempTargetSet);
mProfile.put("autosens_adjust_targets", SP.getBoolean("openapsama_autosens_adjusttargets", true));
- mProfile.put("min_5m_carbimpact", SP.getDouble("openapsama_min_5m_carbimpact", 3d));
+ mProfile.put("min_5m_carbimpact", SP.getInt("openapsama_min_5m_carbimpact", SMBDefaults.min_5m_carbimpact));
if (units.equals(Constants.MMOL)) {
mProfile.put("out_units", "mmol/L");
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java
index e4c23ae043..50dde42674 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java
@@ -1,35 +1,28 @@
package info.nightscout.androidaps.plugins.OpenAPSAMA;
-import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.javascript.NativeObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
import java.util.Date;
-import java.util.List;
-import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.plugins.Loop.APSResult;
-import info.nightscout.androidaps.data.IobTotal;
public class DetermineBasalResultAMA extends APSResult {
private static Logger log = LoggerFactory.getLogger(DetermineBasalResultAMA.class);
- public Date date;
- public JSONObject json = new JSONObject();
public double eventualBG;
public double snoozeBG;
- public IobTotal iob;
public DetermineBasalResultAMA(NativeObject result, JSONObject j) {
+ this();
date = new Date();
json = j;
if (result.containsKey("error")) {
reason = result.get("error").toString();
- changeRequested = false;
+ tempBasalReqested = false;
rate = -1;
duration = -1;
} else {
@@ -37,36 +30,37 @@ public class DetermineBasalResultAMA extends APSResult {
if (result.containsKey("eventualBG")) eventualBG = (Double) result.get("eventualBG");
if (result.containsKey("snoozeBG")) snoozeBG = (Double) result.get("snoozeBG");
if (result.containsKey("rate")) {
- rate = (Double) result.get("rate");
+ rate = (Double) result.get("rate");
if (rate < 0d) rate = 0d;
- changeRequested = true;
+ tempBasalReqested = true;
} else {
rate = -1;
- changeRequested = false;
+ tempBasalReqested = false;
}
if (result.containsKey("duration")) {
- duration = ((Double)result.get("duration")).intValue();
+ duration = ((Double) result.get("duration")).intValue();
//changeRequested as above
} else {
duration = -1;
- changeRequested = false;
+ tempBasalReqested = false;
}
}
+ bolusRequested = false;
}
public DetermineBasalResultAMA() {
+ hasPredictions = true;
}
@Override
public DetermineBasalResultAMA clone() {
DetermineBasalResultAMA newResult = new DetermineBasalResultAMA();
- newResult.reason = new String(reason);
+ newResult.reason = reason;
newResult.rate = rate;
newResult.duration = duration;
- newResult.changeRequested = changeRequested;
+ newResult.tempBasalReqested = tempBasalReqested;
newResult.rate = rate;
newResult.duration = duration;
- newResult.changeRequested = changeRequested;
try {
newResult.json = new JSONObject(json.toString());
@@ -90,72 +84,4 @@ public class DetermineBasalResultAMA extends APSResult {
return null;
}
- public List getPredictions() {
- List 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.isPrediction = 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.isPrediction = 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.isPrediction = true;
- array.add(bg);
- }
- }
- }
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return array;
- }
-
- public long getLatestPredictionsTime() {
- long latest = 0;
- try {
- long startTime = date.getTime();
- 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);
- }
- }
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
-
- return latest;
- }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java
index 4c14f33533..bfe4fedf1f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java
@@ -8,7 +8,6 @@ import java.io.IOException;
import java.util.Date;
import info.nightscout.androidaps.Config;
-import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseStatus;
@@ -18,6 +17,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
@@ -26,12 +26,10 @@ import info.nightscout.androidaps.plugins.Loop.ScriptReader;
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
import info.nightscout.utils.DateUtil;
-import info.nightscout.utils.NSUpload;
+import info.nightscout.utils.HardLimits;
import info.nightscout.utils.Profiler;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
-import info.nightscout.utils.SafeParse;
-import info.nightscout.utils.ToastUtils;
/**
* Created by mike on 05.08.2016.
@@ -149,6 +147,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
Profile profile = MainApp.getConfigBuilder().getProfile();
+ PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (profile == null) {
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.noprofileselected)));
@@ -184,7 +183,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
Date start = new Date();
Date startPart = new Date();
- IobTotal[] iobArray = IobCobCalculatorPlugin.calculateIobArrayInDia();
+ IobTotal[] iobArray = IobCobCalculatorPlugin.getPlugin().calculateIobArrayInDia();
Profiler.log(log, "calculateIobArrayInDia()", startPart);
startPart = new Date();
@@ -193,35 +192,37 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob);
- minBg = verifyHardLimits(minBg, "minBg", Constants.VERY_HARD_LIMIT_MIN_BG[0], Constants.VERY_HARD_LIMIT_MIN_BG[1]);
- maxBg = verifyHardLimits(maxBg, "maxBg", Constants.VERY_HARD_LIMIT_MAX_BG[0], Constants.VERY_HARD_LIMIT_MAX_BG[1]);
- targetBg = verifyHardLimits(targetBg, "targetBg", Constants.VERY_HARD_LIMIT_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TARGET_BG[1]);
+ minBg = HardLimits.verifyHardLimits(minBg, "minBg", HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1]);
+ maxBg = HardLimits.verifyHardLimits(maxBg, "maxBg", HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1]);
+ targetBg = HardLimits.verifyHardLimits(targetBg, "targetBg", HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TARGET_BG[1]);
boolean isTempTarget = false;
TempTarget tempTarget = MainApp.getConfigBuilder().getTempTargetFromHistory(System.currentTimeMillis());
if (tempTarget != null) {
isTempTarget = true;
- minBg = verifyHardLimits(tempTarget.low, "minBg", Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[1]);
- maxBg = verifyHardLimits(tempTarget.high, "maxBg", Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[1]);
- targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]);
+ minBg = HardLimits.verifyHardLimits(tempTarget.low, "minBg", HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]);
+ maxBg = HardLimits.verifyHardLimits(tempTarget.high, "maxBg", HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]);
+ targetBg = HardLimits.verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]);
}
- maxIob = verifyHardLimits(maxIob, "maxIob", 0, 7);
- maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, 10);
+ maxIob = HardLimits.verifyHardLimits(maxIob, "maxIob", 0, HardLimits.maxIobAMA());
+ maxBasal = HardLimits.verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
- if (!checkOnlyHardLimits(profile.getDia(), "dia", 2, 7)) return;
- if (!checkOnlyHardLimits(profile.getIc(Profile.secondsFromMidnight()), "carbratio", 2, 100))
+ if (!HardLimits.checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA))
return;
- if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", 2, 900))
+ if (!HardLimits.checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return;
- if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, 10)) return;
- if (!checkOnlyHardLimits(ConfigBuilderPlugin.getActivePump().getBaseBasalRate(), "current_basal", 0.01, 5))
+ if (!HardLimits.checkOnlyHardLimits(Profile.toMgdl(profile.getIsf().doubleValue(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
+ return;
+ if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, HardLimits.maxBasal()))
+ return;
+ if (!HardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;
startPart = new Date();
if (MainApp.getConfigBuilder().isAMAModeEnabled()) {
- lastAutosensResult = IobCobCalculatorPlugin.detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis());
+ lastAutosensResult = IobCobCalculatorPlugin.getPlugin().detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis());
} else {
lastAutosensResult = new AutosensResult();
}
@@ -233,8 +234,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
try {
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, ConfigBuilderPlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
lastAutosensResult.ratio, //autosensDataRatio
- isTempTarget,
- SafeParse.stringToDouble(SP.getString("openapsama_min_5m_carbimpact", "3.0"))//min_5m_carbimpact
+ isTempTarget
);
} catch (JSONException e) {
log.error("Unable to set data: " + e.toString());
@@ -245,15 +245,15 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
Profiler.log(log, "AMA calculation", start);
// Fix bug determine basal
if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
- determineBasalResultAMA.changeRequested = false;
+ determineBasalResultAMA.tempBasalReqested = false;
// limit requests on openloop mode
if (!MainApp.getConfigBuilder().isClosedModeEnabled()) {
if (MainApp.getConfigBuilder().isTempBasalInProgress() && determineBasalResultAMA.rate == 0 && determineBasalResultAMA.duration == 0) {
// going to cancel
} else if (MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultAMA.rate - MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()) < 0.1) {
- determineBasalResultAMA.changeRequested = false;
+ determineBasalResultAMA.tempBasalReqested = false;
} else if (!MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultAMA.rate - ConfigBuilderPlugin.getActivePump().getBaseBasalRate()) < 0.1)
- determineBasalResultAMA.changeRequested = false;
+ determineBasalResultAMA.tempBasalReqested = false;
}
determineBasalResultAMA.iob = iobArray[0];
@@ -274,24 +274,4 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
//deviceStatus.suggested = determineBasalResultAMA.json;
}
- // safety checks
- public static boolean checkOnlyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
- return value.equals(verifyHardLimits(value, valueName, lowLimit, highLimit));
- }
-
- public static Double verifyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
- Double newvalue = value;
- if (newvalue < lowLimit || newvalue > highLimit) {
- newvalue = Math.max(newvalue, lowLimit);
- newvalue = Math.min(newvalue, highLimit);
- String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), valueName);
- msg += ".\n";
- msg += String.format(MainApp.sResources.getString(R.string.openapsma_valuelimitedto), value, newvalue);
- log.error(msg);
- NSUpload.uploadError(msg);
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
- }
- return newvalue;
- }
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java
index e132c9f953..3f40c02980 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java
@@ -6,7 +6,6 @@ import org.mozilla.javascript.NativeObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.plugins.Loop.APSResult;
public class DetermineBasalResultMA extends APSResult {
@@ -16,13 +15,12 @@ public class DetermineBasalResultMA extends APSResult {
public double eventualBG;
public double snoozeBG;
public String mealAssist;
- public IobTotal iob;
public DetermineBasalResultMA(NativeObject result, JSONObject j) {
json = j;
if (result.containsKey("error")) {
reason = (String) result.get("error");
- changeRequested = false;
+ tempBasalReqested = false;
rate = -1;
duration = -1;
mealAssist = "";
@@ -33,17 +31,17 @@ public class DetermineBasalResultMA extends APSResult {
if (result.containsKey("rate")) {
rate = (Double) result.get("rate");
if (rate < 0d) rate = 0d;
- changeRequested = true;
+ tempBasalReqested = true;
} else {
rate = -1;
- changeRequested = false;
+ tempBasalReqested = false;
}
if (result.containsKey("duration")) {
duration = ((Double) result.get("duration")).intValue();
//changeRequested as above
} else {
duration = -1;
- changeRequested = false;
+ tempBasalReqested = false;
}
if (result.containsKey("mealAssist")) {
mealAssist = result.get("mealAssist").toString();
@@ -60,10 +58,10 @@ public class DetermineBasalResultMA extends APSResult {
newResult.reason = new String(reason);
newResult.rate = rate;
newResult.duration = duration;
- newResult.changeRequested = changeRequested;
+ newResult.tempBasalReqested = isChangeRequested();
newResult.rate = rate;
newResult.duration = duration;
- newResult.changeRequested = changeRequested;
+ newResult.tempBasalReqested = isChangeRequested();
try {
newResult.json = new JSONObject(json.toString());
@@ -72,7 +70,7 @@ public class DetermineBasalResultMA extends APSResult {
}
newResult.eventualBG = eventualBG;
newResult.snoozeBG = snoozeBG;
- newResult.mealAssist = new String(mealAssist);
+ newResult.mealAssist = mealAssist;
return newResult;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java
index d56dc44b89..adb18491a4 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java
@@ -8,7 +8,6 @@ import java.io.IOException;
import java.util.Date;
import info.nightscout.androidaps.Config;
-import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseStatus;
@@ -18,19 +17,21 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
import info.nightscout.utils.DateUtil;
+import info.nightscout.utils.HardLimits;
import info.nightscout.utils.Profiler;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse;
-import static info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin.checkOnlyHardLimits;
-import static info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin.verifyHardLimits;
+import static info.nightscout.utils.HardLimits.checkOnlyHardLimits;
+import static info.nightscout.utils.HardLimits.verifyHardLimits;
/**
* Created by mike on 05.08.2016.
@@ -147,6 +148,7 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
Profile profile = MainApp.getConfigBuilder().getProfile();
+ PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (profile == null) {
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.noprofileselected)));
@@ -195,26 +197,29 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob);
Profiler.log(log, "MA data gathering", start);
- minBg = verifyHardLimits(minBg, "minBg", Constants.VERY_HARD_LIMIT_MIN_BG[0], Constants.VERY_HARD_LIMIT_MIN_BG[1]);
- maxBg = verifyHardLimits(maxBg, "maxBg", Constants.VERY_HARD_LIMIT_MAX_BG[0], Constants.VERY_HARD_LIMIT_MAX_BG[1]);
- targetBg = verifyHardLimits(targetBg, "targetBg", Constants.VERY_HARD_LIMIT_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TARGET_BG[1]);
+ minBg = verifyHardLimits(minBg, "minBg", HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1]);
+ maxBg = verifyHardLimits(maxBg, "maxBg", HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1]);
+ targetBg = verifyHardLimits(targetBg, "targetBg", HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TARGET_BG[1]);
TempTarget tempTarget = MainApp.getConfigBuilder().getTempTargetFromHistory(System.currentTimeMillis());
if (tempTarget != null) {
- minBg = verifyHardLimits(tempTarget.low, "minBg", Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[1]);
- maxBg = verifyHardLimits(tempTarget.high, "maxBg", Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[1]);
- targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]);
+ minBg = verifyHardLimits(tempTarget.low, "minBg", HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]);
+ maxBg = verifyHardLimits(tempTarget.high, "maxBg", HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]);
+ targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]);
}
- maxIob = verifyHardLimits(maxIob, "maxIob", 0, 7);
- maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, 10);
+ maxIob = verifyHardLimits(maxIob, "maxIob", 0, HardLimits.maxIobAMA());
+ maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
- if (!checkOnlyHardLimits(profile.getDia(), "dia", 2, 7)) return;
- if (!checkOnlyHardLimits(profile.getIc(), "carbratio", 2, 100)) return;
- if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", 2, 900))
+ if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA))
return;
- if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, 10)) return;
- if (!checkOnlyHardLimits(ConfigBuilderPlugin.getActivePump().getBaseBasalRate(), "current_basal", 0.01, 5))
+ if (!checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
+ return;
+ if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf().doubleValue(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
+ return;
+ if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, HardLimits.maxBasal()))
+ return;
+ if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;
start = new Date();
@@ -229,15 +234,15 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
DetermineBasalResultMA determineBasalResultMA = determineBasalAdapterMAJS.invoke();
// Fix bug determinef basal
if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
- determineBasalResultMA.changeRequested = false;
+ determineBasalResultMA.tempBasalReqested = false;
// limit requests on openloop mode
if (!MainApp.getConfigBuilder().isClosedModeEnabled()) {
if (MainApp.getConfigBuilder().isTempBasalInProgress() && determineBasalResultMA.rate == 0 && determineBasalResultMA.duration == 0) {
// going to cancel
} else if (MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultMA.rate - MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()) < 0.1) {
- determineBasalResultMA.changeRequested = false;
+ determineBasalResultMA.tempBasalReqested = false;
} else if (!MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultMA.rate - ConfigBuilderPlugin.getActivePump().getBaseBasalRate()) < 0.1)
- determineBasalResultMA.changeRequested = false;
+ determineBasalResultMA.tempBasalReqested = false;
}
determineBasalResultMA.iob = iobTotal;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/DetermineBasalAdapterSMBJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/DetermineBasalAdapterSMBJS.java
new file mode 100644
index 0000000000..57c879a5cd
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/DetermineBasalAdapterSMBJS.java
@@ -0,0 +1,344 @@
+package info.nightscout.androidaps.plugins.OpenAPSSMB;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.javascript.Callable;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.NativeJSON;
+import org.mozilla.javascript.NativeObject;
+import org.mozilla.javascript.RhinoException;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Undefined;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.Constants;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.GlucoseStatus;
+import info.nightscout.androidaps.data.IobTotal;
+import info.nightscout.androidaps.data.MealData;
+import info.nightscout.androidaps.data.Profile;
+import info.nightscout.androidaps.db.TemporaryBasal;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
+import info.nightscout.androidaps.plugins.Loop.ScriptReader;
+import info.nightscout.androidaps.plugins.OpenAPSMA.LoggerCallback;
+import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin;
+import info.nightscout.utils.SP;
+import info.nightscout.utils.SafeParse;
+
+public class DetermineBasalAdapterSMBJS {
+ private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterSMBJS.class);
+
+
+ private ScriptReader mScriptReader = null;
+ private JSONObject mProfile;
+ private JSONObject mGlucoseStatus;
+ private JSONArray mIobData;
+ private JSONObject mMealData;
+ private JSONObject mCurrentTemp;
+ private JSONObject mAutosensData = null;
+ private boolean mMicrobolusAllowed;
+
+ private String storedCurrentTemp = null;
+ private String storedIobData = null;
+
+ private String storedGlucoseStatus = null;
+ private String storedProfile = null;
+ private String storedMeal_data = null;
+ private String storedAutosens_data = null;
+ private String storedMicroBolusAllowed = null;
+
+ private String scriptDebug = "";
+
+ /**
+ * Main code
+ */
+
+ public DetermineBasalAdapterSMBJS(ScriptReader scriptReader) throws IOException {
+ mScriptReader = scriptReader;
+ }
+
+
+ public DetermineBasalResultSMB invoke() {
+
+
+ log.debug(">>> Invoking detemine_basal <<<");
+ log.debug("Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString()));
+ log.debug("IOB data: " + (storedIobData = mIobData.toString()));
+ log.debug("Current temp: " + (storedCurrentTemp = mCurrentTemp.toString()));
+ log.debug("Profile: " + (storedProfile = mProfile.toString()));
+ log.debug("Meal data: " + (storedMeal_data = mMealData.toString()));
+ if (mAutosensData != null)
+ log.debug("Autosens data: " + (storedAutosens_data = mAutosensData.toString()));
+ else
+ log.debug("Autosens data: " + (storedAutosens_data = "undefined"));
+ log.debug("Reservoir data: " + "undefined");
+ log.debug("MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed));
+
+ DetermineBasalResultSMB determineBasalResultSMB = null;
+
+ Context rhino = Context.enter();
+ Scriptable scope = rhino.initStandardObjects();
+ // Turn off optimization to make Rhino Android compatible
+ rhino.setOptimizationLevel(-1);
+
+ try {
+
+ //register logger callback for console.log and console.error
+ ScriptableObject.defineClass(scope, LoggerCallback.class);
+ Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null);
+ scope.put("console2", scope, myLogger);
+ rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null);
+
+ //set module parent
+ rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null);
+ rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null);
+ rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null);
+
+ //generate functions "determine_basal" and "setTempBasal"
+ rhino.evaluateString(scope, readFile("OpenAPSSMB/determine-basal.js"), "JavaScript", 0, null);
+ rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null);
+ Object determineBasalObj = scope.get("determine_basal", scope);
+ Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope);
+
+ //call determine-basal
+ if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) {
+ Function determineBasalJS = (Function) determineBasalObj;
+
+ //prepare parameters
+ Object[] params = new Object[]{
+ makeParam(mGlucoseStatus, rhino, scope),
+ makeParam(mCurrentTemp, rhino, scope),
+ makeParamArray(mIobData, rhino, scope),
+ makeParam(mProfile, rhino, scope),
+ makeParam(mAutosensData, rhino, scope),
+ makeParam(mMealData, rhino, scope),
+ setTempBasalFunctionsObj,
+ new Boolean(mMicrobolusAllowed),
+ makeParam(null, rhino, scope) // reservoir data as undefined
+ };
+
+
+ NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params);
+ scriptDebug = LoggerCallback.getScriptDebug();
+
+ // Parse the jsResult object to a JSON-String
+ String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
+ if (Config.logAPSResult)
+ log.debug("Result: " + result);
+ try {
+ determineBasalResultSMB = new DetermineBasalResultSMB(new JSONObject(result));
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ } else {
+ log.debug("Problem loading JS Functions");
+ }
+ } catch (IOException e) {
+ log.debug("IOException");
+ } catch (RhinoException e) {
+ log.error("RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString());
+ } catch (IllegalAccessException e) {
+ log.error(e.toString());
+ } catch (InstantiationException e) {
+ log.error(e.toString());
+ } catch (InvocationTargetException e) {
+ log.error(e.toString());
+ } finally {
+ Context.exit();
+ }
+
+ storedGlucoseStatus = mGlucoseStatus.toString();
+ storedIobData = mIobData.toString();
+ storedCurrentTemp = mCurrentTemp.toString();
+ storedProfile = mProfile.toString();
+ storedMeal_data = mMealData.toString();
+
+ return determineBasalResultSMB;
+
+ }
+
+ String getGlucoseStatusParam() {
+ return storedGlucoseStatus;
+ }
+
+ String getCurrentTempParam() {
+ return storedCurrentTemp;
+ }
+
+ String getIobDataParam() {
+ return storedIobData;
+ }
+
+ String getProfileParam() {
+ return storedProfile;
+ }
+
+ String getMealDataParam() {
+ return storedMeal_data;
+ }
+
+ String getAutosensDataParam() {
+ return storedAutosens_data;
+ }
+
+ String getMicroBolusAllowedParam() {
+ return storedMicroBolusAllowed;
+ }
+
+ String getScriptDebug() {
+ return scriptDebug;
+ }
+
+ public void setData(Profile profile,
+ double maxIob,
+ double maxBasal,
+ double minBg,
+ double maxBg,
+ double targetBg,
+ double basalrate,
+ IobTotal[] iobArray,
+ GlucoseStatus glucoseStatus,
+ MealData mealData,
+ double autosensDataRatio,
+ boolean tempTargetSet,
+ boolean microBolusAllowed
+ ) throws JSONException {
+
+ String units = profile.getUnits();
+
+ mProfile = new JSONObject();
+
+ mProfile.put("max_iob", maxIob);
+ mProfile.put("dia", profile.getDia());
+ mProfile.put("type", "current");
+ mProfile.put("max_daily_basal", profile.getMaxDailyBasal());
+ mProfile.put("max_basal", maxBasal);
+ mProfile.put("min_bg", minBg);
+ mProfile.put("max_bg", maxBg);
+ mProfile.put("target_bg", targetBg);
+ mProfile.put("carb_ratio", profile.getIc());
+ mProfile.put("sens", Profile.toMgdl(profile.getIsf().doubleValue(), units));
+ mProfile.put("max_daily_safety_multiplier", SP.getInt("openapsama_max_daily_safety_multiplier", 3));
+ mProfile.put("current_basal_safety_multiplier", SP.getInt("openapsama_current_basal_safety_multiplier", 4));
+
+ mProfile.put("high_temptarget_raises_sensitivity", SMBDefaults.high_temptarget_raises_sensitivity);
+ mProfile.put("low_temptarget_lowers_sensitivity", SMBDefaults.low_temptarget_lowers_sensitivity);
+ mProfile.put("sensitivity_raises_target", SMBDefaults.sensitivity_raises_target);
+ mProfile.put("resistance_lowers_target", SMBDefaults.resistance_lowers_target);
+ mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments);
+ mProfile.put("exercise_mode", SMBDefaults.exercise_mode);
+ mProfile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target);
+ mProfile.put("maxCOB", SMBDefaults.maxCOB);
+ mProfile.put("skip_neutral_temps", SMBDefaults.skip_neutral_temps);
+ mProfile.put("min_5m_carbimpact", SP.getInt("openapsama_min_5m_carbimpact", SMBDefaults.min_5m_carbimpact));;
+ mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap);
+ mProfile.put("enableUAM", SP.getBoolean(R.string.key_use_uam, false));
+ mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
+ mProfile.put("enableSMB_with_COB", SP.getBoolean(R.string.key_use_smb, false) && SP.getBoolean(R.string.key_enableSMB_with_COB, false));
+ mProfile.put("enableSMB_with_temptarget", SP.getBoolean(R.string.key_use_smb, false) && SP.getBoolean(R.string.key_enableSMB_with_temptarget, false));
+ mProfile.put("allowSMB_with_high_temptarget", SP.getBoolean(R.string.key_use_smb, false) && SP.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
+ mProfile.put("enableSMB_always", SP.getBoolean(R.string.key_use_smb, false) && SP.getBoolean(R.string.key_enableSMB_always, false) && ConfigBuilderPlugin.getActiveBgSource().advancedFilteringSupported());
+ mProfile.put("enableSMB_after_carbs", SP.getBoolean(R.string.key_use_smb, false) && SP.getBoolean(R.string.key_enableSMB_after_carbs, false) && ConfigBuilderPlugin.getActiveBgSource().advancedFilteringSupported());
+ mProfile.put("maxSMBBasalMinutes", SP.getInt("key_smbmaxminutes", SMBDefaults.maxSMBBasalMinutes));
+ mProfile.put("carbsReqThreshold", SMBDefaults.carbsReqThreshold);
+
+ mProfile.put("current_basal", basalrate);
+ mProfile.put("temptargetSet", tempTargetSet);
+ mProfile.put("autosens_max", SafeParse.stringToDouble(SP.getString("openapsama_autosens_max", "1.2")));
+
+ if (units.equals(Constants.MMOL)) {
+ mProfile.put("out_units", "mmol/L");
+ }
+
+
+ mCurrentTemp = new JSONObject();
+ mCurrentTemp.put("temp", "absolute");
+ mCurrentTemp.put("duration", MainApp.getConfigBuilder().getTempBasalRemainingMinutesFromHistory());
+ mCurrentTemp.put("rate", MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory());
+
+ // as we have non default temps longer than 30 mintues
+ TemporaryBasal tempBasal = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
+ if (tempBasal != null) {
+ mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration());
+ }
+
+ mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray);
+
+ mGlucoseStatus = new JSONObject();
+ mGlucoseStatus.put("glucose", glucoseStatus.glucose);
+
+ if (SP.getBoolean("always_use_shortavg", false)) {
+ mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
+ } else {
+ mGlucoseStatus.put("delta", glucoseStatus.delta);
+ }
+ mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta);
+ mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta);
+ mGlucoseStatus.put("date", glucoseStatus.date);
+
+ mMealData = new JSONObject();
+ mMealData.put("carbs", mealData.carbs);
+ mMealData.put("boluses", mealData.boluses);
+ mMealData.put("mealCOB", mealData.mealCOB);
+ mMealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation);
+ mMealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation);
+ mMealData.put("lastBolusTime", mealData.lastBolusTime);
+ mMealData.put("lastCarbTime", mealData.lastCarbTime);
+
+
+ if (MainApp.getConfigBuilder().isAMAModeEnabled()) {
+ mAutosensData = new JSONObject();
+ mAutosensData.put("ratio", autosensDataRatio);
+ } else {
+ mAutosensData = new JSONObject();
+ mAutosensData.put("ratio", 1.0);
+ }
+ mMicrobolusAllowed = microBolusAllowed;
+
+ }
+
+ public Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
+
+ if (jsonObject == null) return Undefined.instance;
+
+ Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), new Callable() {
+ @Override
+ public Object call(Context context, Scriptable scriptable, Scriptable scriptable1, Object[] objects) {
+ return objects[1];
+ }
+ });
+ return param;
+ }
+
+ public Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
+ //Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
+ Object param = NativeJSON.parse(rhino, scope, jsonArray.toString(), new Callable() {
+ @Override
+ public Object call(Context context, Scriptable scriptable, Scriptable scriptable1, Object[] objects) {
+ return objects[1];
+ }
+ });
+ return param;
+ }
+
+ public String readFile(String filename) throws IOException {
+ byte[] bytes = mScriptReader.readFile(filename);
+ String string = new String(bytes, "UTF-8");
+ if (string.startsWith("#!/usr/bin/env node")) {
+ string = string.substring(20);
+ }
+ return string;
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/DetermineBasalResultSMB.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/DetermineBasalResultSMB.java
new file mode 100644
index 0000000000..0320b3633d
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/DetermineBasalResultSMB.java
@@ -0,0 +1,104 @@
+package info.nightscout.androidaps.plugins.OpenAPSSMB;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+import info.nightscout.androidaps.plugins.Loop.APSResult;
+import info.nightscout.utils.DateUtil;
+
+public class DetermineBasalResultSMB extends APSResult {
+ private static final Logger log = LoggerFactory.getLogger(DetermineBasalResultSMB.class);
+
+ public double eventualBG;
+ public double snoozeBG;
+ public double insulinReq;
+ public double carbsReq;
+
+ public DetermineBasalResultSMB(JSONObject result) {
+ this();
+ date = new Date();
+ json = result;
+ try {
+ if (result.has("error")) {
+ reason = result.getString("error");
+ return;
+ }
+
+ reason = result.getString("reason");
+ if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG");
+ if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG");
+ if (result.has("insulinReq")) insulinReq = result.getDouble("insulinReq");
+ if (result.has("carbsReq")) carbsReq = result.getDouble("carbsReq");
+
+ if (result.has("rate") && result.has("duration")) {
+ tempBasalReqested = true;
+ rate = result.getDouble("rate");
+ if (rate < 0d) rate = 0d;
+ duration = result.getInt("duration");
+ } else {
+ rate = -1;
+ duration = -1;
+ }
+
+ if (result.has("units")) {
+ bolusRequested = true;
+ smb = result.getDouble("units");
+ } else {
+ smb = 0d;
+ }
+
+ if (result.has("deliverAt")) {
+ String date = result.getString("deliverAt");
+ try {
+ deliverAt = DateUtil.fromISODateString(date).getTime();
+ } catch (Exception e) {
+ log.warn("Error parsing 'deliverAt' date: " + date, e);
+ }
+ }
+ } catch (JSONException e) {
+ log.error("Error parsing determine-basal result JSON", e);
+ }
+ }
+
+ public DetermineBasalResultSMB() {
+ hasPredictions = true;
+ }
+
+ @Override
+ public DetermineBasalResultSMB clone() {
+ DetermineBasalResultSMB newResult = new DetermineBasalResultSMB();
+ newResult.reason = reason;
+ newResult.rate = rate;
+ newResult.duration = duration;
+ newResult.tempBasalReqested = tempBasalReqested;
+ newResult.bolusRequested = bolusRequested;
+ newResult.rate = rate;
+ newResult.duration = duration;
+ newResult.smb = smb;
+ newResult.deliverAt = deliverAt;
+
+ try {
+ newResult.json = new JSONObject(json.toString());
+ } catch (JSONException e) {
+ log.error("Error clone parsing determine-basal result", e);
+ }
+ newResult.eventualBG = eventualBG;
+ newResult.snoozeBG = snoozeBG;
+ newResult.date = date;
+ return newResult;
+ }
+
+ @Override
+ public JSONObject json() {
+ try {
+ return new JSONObject(this.json.toString());
+ } catch (JSONException e) {
+ log.error("Error converting determine-basal result to JSON", e);
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/OpenAPSSMBFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/OpenAPSSMBFragment.java
new file mode 100644
index 0000000000..ef515c68f2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/OpenAPSSMBFragment.java
@@ -0,0 +1,142 @@
+package info.nightscout.androidaps.plugins.OpenAPSSMB;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.crashlytics.android.answers.Answers;
+import com.crashlytics.android.answers.CustomEvent;
+import com.squareup.otto.Subscribe;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
+import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
+import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
+import info.nightscout.utils.JSONFormatter;
+
+public class OpenAPSSMBFragment extends SubscriberFragment implements View.OnClickListener {
+ private static Logger log = LoggerFactory.getLogger(OpenAPSSMBFragment.class);
+
+ Button run;
+ TextView lastRunView;
+ TextView glucoseStatusView;
+ TextView currentTempView;
+ TextView iobDataView;
+ TextView profileView;
+ TextView mealDataView;
+ TextView autosensDataView;
+ TextView resultView;
+ TextView scriptdebugView;
+ TextView requestView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.openapsama_fragment, container, false);
+
+ run = (Button) view.findViewById(R.id.openapsma_run);
+ run.setOnClickListener(this);
+ lastRunView = (TextView) view.findViewById(R.id.openapsma_lastrun);
+ glucoseStatusView = (TextView) view.findViewById(R.id.openapsma_glucosestatus);
+ currentTempView = (TextView) view.findViewById(R.id.openapsma_currenttemp);
+ iobDataView = (TextView) view.findViewById(R.id.openapsma_iobdata);
+ profileView = (TextView) view.findViewById(R.id.openapsma_profile);
+ mealDataView = (TextView) view.findViewById(R.id.openapsma_mealdata);
+ autosensDataView = (TextView) view.findViewById(R.id.openapsma_autosensdata);
+ scriptdebugView = (TextView) view.findViewById(R.id.openapsma_scriptdebugdata);
+ resultView = (TextView) view.findViewById(R.id.openapsma_result);
+ requestView = (TextView) view.findViewById(R.id.openapsma_request);
+
+ updateGUI();
+ return view;
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.openapsma_run:
+ OpenAPSSMBPlugin.getPlugin().invoke("OpenAPSSMB button");
+ Answers.getInstance().logCustom(new CustomEvent("OpenAPS_SMB_Run"));
+ break;
+ }
+
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
+ updateGUI();
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventOpenAPSUpdateResultGui ev) {
+ updateResultGUI(ev.text);
+ }
+
+ @Override
+ protected void updateGUI() {
+ Activity activity = getActivity();
+ if (activity != null)
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ OpenAPSSMBPlugin plugin = OpenAPSSMBPlugin.getPlugin();
+ DetermineBasalResultSMB lastAPSResult = plugin.lastAPSResult;
+ if (lastAPSResult != null) {
+ resultView.setText(JSONFormatter.format(lastAPSResult.json));
+ requestView.setText(lastAPSResult.toSpanned());
+ }
+ DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS = plugin.lastDetermineBasalAdapterSMBJS;
+ if (determineBasalAdapterSMBJS != null) {
+ glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getGlucoseStatusParam()));
+ currentTempView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getCurrentTempParam()));
+ try {
+ JSONArray iobArray = new JSONArray(determineBasalAdapterSMBJS.getIobDataParam());
+ iobDataView.setText(String.format(MainApp.sResources.getString(R.string.array_of_elements), iobArray.length()) + "\n" + JSONFormatter.format(iobArray.getString(0)));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ iobDataView.setText("JSONException");
+ }
+ profileView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getProfileParam()));
+ mealDataView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getMealDataParam()));
+ scriptdebugView.setText(determineBasalAdapterSMBJS.getScriptDebug());
+ }
+ if (plugin.lastAPSRun != null) {
+ lastRunView.setText(plugin.lastAPSRun.toLocaleString());
+ }
+ if (plugin.lastAutosensResult != null) {
+ autosensDataView.setText(JSONFormatter.format(plugin.lastAutosensResult.json()));
+ }
+ }
+ });
+ }
+
+ void updateResultGUI(final String text) {
+ Activity activity = getActivity();
+ if (activity != null)
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ resultView.setText(text);
+ glucoseStatusView.setText("");
+ currentTempView.setText("");
+ iobDataView.setText("");
+ profileView.setText("");
+ mealDataView.setText("");
+ autosensDataView.setText("");
+ scriptdebugView.setText("");
+ requestView.setText("");
+ lastRunView.setText("");
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/OpenAPSSMBPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/OpenAPSSMBPlugin.java
new file mode 100644
index 0000000000..c992f0e739
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/OpenAPSSMBPlugin.java
@@ -0,0 +1,301 @@
+package info.nightscout.androidaps.plugins.OpenAPSSMB;
+
+import org.json.JSONException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Date;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.GlucoseStatus;
+import info.nightscout.androidaps.data.IobTotal;
+import info.nightscout.androidaps.data.MealData;
+import info.nightscout.androidaps.data.Profile;
+import info.nightscout.androidaps.db.TempTarget;
+import info.nightscout.androidaps.interfaces.APSInterface;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.PumpInterface;
+import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
+import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
+import info.nightscout.androidaps.plugins.Loop.APSResult;
+import info.nightscout.androidaps.plugins.Loop.ScriptReader;
+import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
+import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
+import info.nightscout.utils.DateUtil;
+import info.nightscout.utils.HardLimits;
+import info.nightscout.utils.NSUpload;
+import info.nightscout.utils.Profiler;
+import info.nightscout.utils.Round;
+import info.nightscout.utils.SP;
+import info.nightscout.utils.ToastUtils;
+
+/**
+ * Created by mike on 05.08.2016.
+ */
+public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
+ private static Logger log = LoggerFactory.getLogger(OpenAPSSMBPlugin.class);
+
+ // last values
+ DetermineBasalAdapterSMBJS lastDetermineBasalAdapterSMBJS = null;
+ Date lastAPSRun = null;
+ DetermineBasalResultSMB lastAPSResult = null;
+ AutosensResult lastAutosensResult = null;
+
+ boolean fragmentEnabled = false;
+ boolean fragmentVisible = true;
+
+ private static OpenAPSSMBPlugin openAPSSMBPlugin;
+
+ private OpenAPSSMBPlugin() {
+ }
+
+ public static OpenAPSSMBPlugin getPlugin() {
+ if (openAPSSMBPlugin == null) {
+ openAPSSMBPlugin = new OpenAPSSMBPlugin();
+ }
+ return openAPSSMBPlugin;
+ }
+
+ @Override
+ public String getName() {
+ return MainApp.instance().getString(R.string.openapssmb);
+ }
+
+ @Override
+ public String getNameShort() {
+ String name = MainApp.sResources.getString(R.string.smb_shortname);
+ if (!name.trim().isEmpty()) {
+ //only if translation exists
+ return name;
+ }
+ // use long name as fallback
+ return getName();
+ }
+
+ @Override
+ public boolean isEnabled(int type) {
+ boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
+ return type == APS && fragmentEnabled && pumpCapable;
+ }
+
+ @Override
+ public boolean isVisibleInTabs(int type) {
+ boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
+ return type == APS && fragmentVisible && pumpCapable;
+ }
+
+ @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 setFragmentVisible(int type, boolean fragmentVisible) {
+ if (type == APS) this.fragmentVisible = fragmentVisible;
+ }
+
+ @Override
+ public int getPreferencesId() {
+ return R.xml.pref_openapssmb;
+ }
+
+ @Override
+ public void setFragmentEnabled(int type, boolean fragmentEnabled) {
+ if (type == APS) this.fragmentEnabled = fragmentEnabled;
+ }
+
+ @Override
+ public int getType() {
+ return PluginBase.APS;
+ }
+
+ @Override
+ public String getFragmentClass() {
+ return OpenAPSSMBFragment.class.getName();
+ }
+
+ @Override
+ public APSResult getLastAPSResult() {
+ return lastAPSResult;
+ }
+
+ @Override
+ public Date getLastAPSRun() {
+ return lastAPSRun;
+ }
+
+ @Override
+ public void invoke(String initiator) {
+ log.debug("invoke from " + initiator);
+ lastAPSResult = null;
+ DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS = null;
+ try {
+ determineBasalAdapterSMBJS = new DetermineBasalAdapterSMBJS(new ScriptReader(MainApp.instance().getBaseContext()));
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ return;
+ }
+
+ GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
+ Profile profile = MainApp.getConfigBuilder().getProfile();
+ PumpInterface pump = ConfigBuilderPlugin.getActivePump();
+
+ if (profile == null) {
+ MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.noprofileselected)));
+ if (Config.logAPSResult)
+ log.debug(MainApp.instance().getString(R.string.noprofileselected));
+ return;
+ }
+
+ if (!isEnabled(PluginBase.APS)) {
+ MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_disabled)));
+ if (Config.logAPSResult)
+ log.debug(MainApp.instance().getString(R.string.openapsma_disabled));
+ return;
+ }
+
+ if (glucoseStatus == null) {
+ MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noglucosedata)));
+ if (Config.logAPSResult)
+ log.debug(MainApp.instance().getString(R.string.openapsma_noglucosedata));
+ return;
+ }
+
+ String units = profile.getUnits();
+
+ double maxIob = SP.getDouble("openapsma_max_iob", 1.5d);
+ double maxBasal = SP.getDouble("openapsma_max_basal", 1d);
+ double minBg = Profile.toMgdl(profile.getTargetLow(), units);
+ double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
+ double targetBg = (minBg + maxBg) / 2;
+
+ minBg = Round.roundTo(minBg, 0.1d);
+ maxBg = Round.roundTo(maxBg, 0.1d);
+
+ Date start = new Date();
+ Date startPart = new Date();
+ IobTotal[] iobArray = IobCobCalculatorPlugin.getPlugin().calculateIobArrayForSMB();
+ Profiler.log(log, "calculateIobArrayInDia()", startPart);
+
+ startPart = new Date();
+ MealData mealData = MainApp.getConfigBuilder().getMealData();
+ Profiler.log(log, "getMealData()", startPart);
+
+ maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob);
+
+ minBg = verifyHardLimits(minBg, "minBg", HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1]);
+ maxBg = verifyHardLimits(maxBg, "maxBg", HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1]);
+ targetBg = verifyHardLimits(targetBg, "targetBg", HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TARGET_BG[1]);
+
+ boolean isTempTarget = false;
+ TempTarget tempTarget = MainApp.getConfigBuilder().getTempTargetFromHistory(System.currentTimeMillis());
+ if (tempTarget != null) {
+ isTempTarget = true;
+ minBg = verifyHardLimits(tempTarget.low, "minBg", HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]);
+ maxBg = verifyHardLimits(tempTarget.high, "maxBg", HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]);
+ targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]);
+ }
+
+
+ maxIob = verifyHardLimits(maxIob, "maxIob", 0, HardLimits.maxIobSMB());
+ maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
+
+ if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA)) return;
+ if (!checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
+ return;
+ if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf().doubleValue(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
+ return;
+ if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, HardLimits.maxBasal())) return;
+ if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return;
+
+ startPart = new Date();
+ if (MainApp.getConfigBuilder().isAMAModeEnabled()) {
+ lastAutosensResult = IobCobCalculatorPlugin.getPlugin().detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis());
+ } else {
+ lastAutosensResult = new AutosensResult();
+ }
+ Profiler.log(log, "detectSensitivityandCarbAbsorption()", startPart);
+ Profiler.log(log, "SMB data gathering", start);
+
+ start = new Date();
+ try {
+ determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, ConfigBuilderPlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
+ lastAutosensResult.ratio, //autosensDataRatio
+ isTempTarget,
+ true //microBolusAllowed
+ );
+ } catch (JSONException e) {
+ log.error(e.getMessage());
+ return;
+ }
+
+
+ DetermineBasalResultSMB determineBasalResultSMB = determineBasalAdapterSMBJS.invoke();
+ Profiler.log(log, "SMB calculation", start);
+ // TODO still needed with oref1?
+ // Fix bug determine basal
+ if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
+ determineBasalResultSMB.tempBasalReqested = false;
+ // limit requests on openloop mode
+ if (!MainApp.getConfigBuilder().isClosedModeEnabled()) {
+ if (MainApp.getConfigBuilder().isTempBasalInProgress() && determineBasalResultSMB.rate == 0 && determineBasalResultSMB.duration == 0) {
+ // going to cancel
+ } else if (MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultSMB.rate - MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()) < 0.1) {
+ determineBasalResultSMB.tempBasalReqested = false;
+ } else if (!MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultSMB.rate - pump.getBaseBasalRate()) < 0.1) {
+ determineBasalResultSMB.tempBasalReqested = false;
+ }
+ }
+
+ determineBasalResultSMB.iob = iobArray[0];
+ Date now = new Date();
+
+ try {
+ determineBasalResultSMB.json.put("timestamp", DateUtil.toISOString(now));
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+
+ lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
+ lastAPSResult = determineBasalResultSMB;
+ lastAPSRun = now;
+ MainApp.bus().post(new EventOpenAPSUpdateGui());
+
+ //deviceStatus.suggested = determineBasalResultAMA.json;
+ }
+
+ // safety checks
+ private static boolean checkOnlyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
+ return value.equals(verifyHardLimits(value, valueName, lowLimit, highLimit));
+ }
+
+ private static Double verifyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
+ Double newvalue = value;
+ if (newvalue < lowLimit || newvalue > highLimit) {
+ newvalue = Math.max(newvalue, lowLimit);
+ newvalue = Math.min(newvalue, highLimit);
+ String msg = String.format(MainApp.sResources.getString(R.string.valueoutofrange), valueName);
+ msg += ".\n";
+ msg += String.format(MainApp.sResources.getString(R.string.valuelimitedto), value, newvalue);
+ log.error(msg);
+ NSUpload.uploadError(msg);
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
+ }
+ return newvalue;
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/SMBDefaults.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/SMBDefaults.java
new file mode 100644
index 0000000000..a7e690ce79
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSSMB/SMBDefaults.java
@@ -0,0 +1,64 @@
+package info.nightscout.androidaps.plugins.OpenAPSSMB;
+
+/**
+ * Created by mike on 10.12.2017.
+ */
+
+public class SMBDefaults {
+ // CALCULATED OR FROM PREFS
+
+ // max_iob: 0 // if max_iob is not provided, will default to zero
+ // max_daily_safety_multiplier:3
+ // current_basal_safety_multiplier:4
+ // autosens_max:1.2
+ // autosens_min:0.7
+
+ // USED IN AUTOSENS
+ public final static boolean rewind_resets_autosens = true; // reset autosensitivity to neutral for awhile after each pump rewind
+
+ // USED IN TARGETS
+ // by default the higher end of the target range is used only for avoiding bolus wizard overcorrections
+ // use wide_bg_target_range: true to force neutral temps over a wider range of eventualBGs
+ public final static boolean wide_bg_target_range = false; // by default use only the low end of the pump's BG target range as OpenAPS target
+
+ // USED IN AUTOTUNE
+ public final static double autotune_isf_adjustmentFraction = 1.0; // keep autotune ISF closer to pump ISF via a weighted average of fullNewISF and pumpISF. 1.0 allows full adjustment, 0 is no adjustment from pump ISF.
+ public final static double remainingCarbsFraction = 1.0; // fraction of carbs we'll assume will absorb over 4h if we don't yet see carb absorption
+
+ // USED IN DETERMINE_BASAL
+ public final static boolean low_temptarget_lowers_sensitivity = false; // lower sensitivity for temptargets <= 99.
+ public final static boolean high_temptarget_raises_sensitivity = false; // raise sensitivity for temptargets >= 111. synonym for exercise_mode
+ public final static boolean sensitivity_raises_target = true; // raise BG target when autosens detects sensitivity
+ public final static boolean resistance_lowers_target = false; // lower BG target when autosens detects resistance
+ public final static boolean adv_target_adjustments = false; // lower target automatically when BG and eventualBG are high
+ public final static boolean exercise_mode = false; // when true, > 105 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. This majorly changes the behavior of high temp targets from before. synonmym for high_temptarget_raises_sensitivity
+ public final static int half_basal_exercise_target = 160; // when temptarget is 160 mg/dL *and* exercise_mode=true, run 50% basal at this level (120 = 75%; 140 = 60%)
+ // create maxCOB and default it to 120 because that's the most a typical body can absorb over 4 hours.
+ // (If someone enters more carbs or stacks more; OpenAPS will just truncate dosing based on 120.
+ // Essentially, this just limits AMA/SMB as a safety cap against excessive COB entry)
+ public final static int maxCOB = 120;
+ public final static boolean skip_neutral_temps = true; // ***** default false in oref1 ***** if true, don't set neutral temps
+ // unsuspend_if_no_temp:false // if true, pump will un-suspend after a zero temp finishes
+ // bolussnooze_dia_divisor:2 // bolus snooze decays after 1/2 of DIA
+ public final static int min_5m_carbimpact = 8; // mg/dL per 5m (8 mg/dL/5m corresponds to 24g/hr at a CSF of 4 mg/dL/g (x/5*60/4))
+ public final static int remainingCarbsCap = 90; // max carbs we'll assume will absorb over 4h if we don't yet see carb absorption
+ // WARNING: use SMB with caution: it can and will automatically bolus up to max_iob worth of extra insulin
+ // enableUAM:true // enable detection of unannounced meal carb absorption
+ public final static boolean A52_risk_enable = false;
+ //public final static boolean enableSMB_with_COB = true; // ***** default false in oref1 ***** enable supermicrobolus while COB is positive
+ //public final static boolean enableSMB_with_temptarget = true; // ***** default false in oref1 ***** enable supermicrobolus for eating soon temp targets
+ // *** WARNING *** DO NOT USE enableSMB_always or enableSMB_after_carbs with xDrip+, Libre, or similar
+ // xDrip+, LimiTTer, etc. do not properly filter out high-noise SGVs
+ // Using SMB overnight with such data sources risks causing a dangerous overdose of insulin
+ // if the CGM sensor reads falsely high and doesn't come down as actual BG does
+ // public final static boolean enableSMB_always = false; // always enable supermicrobolus (unless disabled by high temptarget)
+ // *** WARNING *** DO NOT USE enableSMB_always or enableSMB_after_carbs with xDrip+, Libre, or similar
+ //public final static boolean enableSMB_after_carbs = false; // enable supermicrobolus for 6h after carbs, even with 0 COB
+ //public final static boolean allowSMB_with_high_temptarget = false; // allow supermicrobolus (if otherwise enabled) even with high temp targets
+ public final static int maxSMBBasalMinutes = 30; // maximum minutes of basal that can be delivered as a single SMB with uncovered COB
+ // curve:"rapid-acting" // Supported curves: "bilinear", "rapid-acting" (Novolog, Novorapid, Humalog, Apidra) and "ultra-rapid" (Fiasp)
+ // useCustomPeakTime:false // allows changing insulinPeakTime
+ // insulinPeakTime:75 // number of minutes after a bolus activity peaks. defaults to 55m for Fiasp if useCustomPeakTime: false
+ public final static int carbsReqThreshold = 1; // grams of carbsReq to trigger a pushover
+ // offline_hotspot:false // enabled an offline-only local wifi hotspot if no Internet available
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorDialog.java
index f11283c029..7d45c35792 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorDialog.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorDialog.java
@@ -19,6 +19,7 @@ import info.nightscout.androidaps.Services.AlarmSoundService;
public class ErrorDialog extends DialogFragment implements View.OnClickListener {
private static Logger log = LoggerFactory.getLogger(ErrorDialog.class);
+ Button muteButton;
Button okButton;
TextView statusView;
ErrorHelperActivity helperActivity;
@@ -52,14 +53,14 @@ public class ErrorDialog extends DialogFragment implements View.OnClickListener
Bundle savedInstanceState) {
getDialog().setTitle(title);
View view = inflater.inflate(R.layout.overview_error_dialog, container, false);
+ muteButton = (Button) view.findViewById(R.id.overview_error_mute);
okButton = (Button) view.findViewById(R.id.overview_error_ok);
statusView = (TextView) view.findViewById(R.id.overview_error_status);
+ muteButton.setOnClickListener(this);
okButton.setOnClickListener(this);
setCancelable(false);
- Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class);
- alarm.putExtra("soundid", soundId);
- MainApp.instance().startService(alarm);
+ startAlarm();
return view;
}
@@ -77,13 +78,16 @@ public class ErrorDialog extends DialogFragment implements View.OnClickListener
if (helperActivity != null) {
helperActivity.finish();
}
- Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class);
- MainApp.instance().stopService(alarm);
+ stopAlarm();
}
@Override
public void onClick(View view) {
switch (view.getId()) {
+ case R.id.overview_error_mute:
+ log.debug("Error dialog mute button pressed");
+ stopAlarm();
+ break;
case R.id.overview_error_ok:
log.debug("Error dialog ok button pressed");
dismiss();
@@ -91,4 +95,14 @@ public class ErrorDialog extends DialogFragment implements View.OnClickListener
}
}
+ private void startAlarm() {
+ Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class);
+ alarm.putExtra("soundid", soundId);
+ MainApp.instance().startService(alarm);
+ }
+
+ private void stopAlarm() {
+ Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class);
+ MainApp.instance().stopService(alarm);
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorHelperActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorHelperActivity.java
index 259c9c76eb..90cf9aecd5 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorHelperActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/ErrorHelperActivity.java
@@ -3,6 +3,10 @@ package info.nightscout.androidaps.plugins.Overview.Dialogs;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
+import info.nightscout.androidaps.R;
+import info.nightscout.utils.NSUpload;
+import info.nightscout.utils.SP;
+
public class ErrorHelperActivity extends AppCompatActivity {
public ErrorHelperActivity() {
super();
@@ -17,5 +21,9 @@ public class ErrorHelperActivity extends AppCompatActivity {
errorDialog.setSound(getIntent().getIntExtra("soundid", 0));
errorDialog.setTitle(getIntent().getStringExtra("title"));
errorDialog.show(this.getSupportFragmentManager(), "Error");
+
+ if (SP.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) {
+ NSUpload.uploadError(getIntent().getStringExtra("status"));
+ }
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java
index 775c97d810..69fbfdc149 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java
@@ -159,19 +159,23 @@ public class NewTreatmentDialog extends DialogFragment implements OnClickListene
detailedBolusInfo.carbs = finalCarbsAfterConstraints;
detailedBolusInfo.context = context;
detailedBolusInfo.source = Source.USER;
- ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, 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.treatmentdeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- MainApp.instance().startActivity(i);
+ if (detailedBolusInfo.insulin > 0 || ConfigBuilderPlugin.getActivePump().getPumpDescription().storesCarbInfo) {
+ ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, 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.treatmentdeliveryerror));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ MainApp.instance().startActivity(i);
+ }
}
- }
- });
+ });
+ } else {
+ MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
+ }
Answers.getInstance().logCustom(new CustomEvent("Bolus"));
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java
index 9d4e728d25..594523cea6 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java
@@ -365,19 +365,23 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com
detailedBolusInfo.carbTime = carbTime;
detailedBolusInfo.boluscalc = boluscalcJSON;
detailedBolusInfo.source = Source.USER;
- ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, 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.treatmentdeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- MainApp.instance().startActivity(i);
+ if (detailedBolusInfo.insulin > 0 || ConfigBuilderPlugin.getActivePump().getPumpDescription().storesCarbInfo) {
+ ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, 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.treatmentdeliveryerror));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ MainApp.instance().startActivity(i);
+ }
}
- }
- });
+ });
+ } else {
+ MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
+ }
Answers.getInstance().logCustom(new CustomEvent("Wizard"));
}
}
@@ -472,7 +476,7 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com
// COB
Double c_cob = 0d;
if (cobCheckbox.isChecked()) {
- AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData("Wizard COB");
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensData("Wizard COB");
if(autosensData != null) {
c_cob = autosensData.cob;
@@ -528,12 +532,12 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com
if (calculatedTotalInsulin > 0d || calculatedCarbs > 0d) {
String insulinText = calculatedTotalInsulin > 0d ? (DecimalFormatter.to2Decimal(calculatedTotalInsulin) + "U") : "";
String carbsText = calculatedCarbs > 0d ? (DecimalFormatter.to0Decimal(calculatedCarbs) + "g") : "";
- total.setText(getString(R.string.result) + ": " + insulinText + " " + carbsText);
+ total.setText(MainApp.gs(R.string.result) + ": " + insulinText + " " + carbsText);
okButton.setVisibility(View.VISIBLE);
} else {
// TODO this should also be run when loading the dialog as the OK button is initially visible
// but does nothing if neither carbs nor insulin is > 0
- total.setText(getString(R.string.missing) + " " + DecimalFormatter.to0Decimal(wizard.carbsEquivalent) + "g");
+ total.setText(MainApp.gs(R.string.missing) + " " + DecimalFormatter.to0Decimal(wizard.carbsEquivalent) + "g");
okButton.setVisibility(View.INVISIBLE);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
index a8ad9c7074..fef0a5d4bd 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
@@ -93,8 +93,6 @@ import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.NSClientInternal.broadcasts.BroadcastAckAlarm;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
-import info.nightscout.androidaps.plugins.OpenAPSAMA.DetermineBasalResultAMA;
-import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.CalibrationDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTreatmentDialog;
@@ -148,12 +146,18 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
TextView sage;
TextView pbage;
- CheckBox showPredictionView;
- CheckBox showBasalsView;
- CheckBox showIobView;
- CheckBox showCobView;
- CheckBox showDeviationsView;
- CheckBox showRatiosView;
+ TextView showPredictionLabel;
+ CheckBox showPredictionCheckbox;
+ TextView showBasalsLabel;
+ CheckBox showBasalsCheckbox;
+ TextView showIobLabel;
+ CheckBox showIobCheckbox;
+ TextView showCobLabel;
+ CheckBox showCobCheckbox;
+ TextView showDeviationsLabel;
+ CheckBox showDeviationsCheckbox;
+ TextView showRatiosLabel;
+ CheckBox showRatiosCheckbox;
RecyclerView notificationsView;
LinearLayoutManager llm;
@@ -265,24 +269,37 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
acceptTempLayout = (LinearLayout) view.findViewById(R.id.overview_accepttemplayout);
- showPredictionView = (CheckBox) view.findViewById(R.id.overview_showprediction);
- showBasalsView = (CheckBox) view.findViewById(R.id.overview_showbasals);
- showIobView = (CheckBox) view.findViewById(R.id.overview_showiob);
- showCobView = (CheckBox) view.findViewById(R.id.overview_showcob);
- showDeviationsView = (CheckBox) view.findViewById(R.id.overview_showdeviations);
- showRatiosView = (CheckBox) view.findViewById(R.id.overview_showratios);
- showPredictionView.setChecked(SP.getBoolean("showprediction", false));
- showBasalsView.setChecked(SP.getBoolean("showbasals", true));
- showIobView.setChecked(SP.getBoolean("showiob", false));
- showCobView.setChecked(SP.getBoolean("showcob", false));
- showDeviationsView.setChecked(SP.getBoolean("showdeviations", false));
- showRatiosView.setChecked(SP.getBoolean("showratios", false));
- showPredictionView.setOnCheckedChangeListener(this);
- showBasalsView.setOnCheckedChangeListener(this);
- showIobView.setOnCheckedChangeListener(this);
- showCobView.setOnCheckedChangeListener(this);
- showDeviationsView.setOnCheckedChangeListener(this);
- showRatiosView.setOnCheckedChangeListener(this);
+ showPredictionCheckbox = (CheckBox) view.findViewById(R.id.overview_showprediction);
+ showBasalsCheckbox = (CheckBox) view.findViewById(R.id.overview_showbasals);
+ showIobCheckbox = (CheckBox) view.findViewById(R.id.overview_showiob);
+ showCobCheckbox = (CheckBox) view.findViewById(R.id.overview_showcob);
+ showDeviationsCheckbox = (CheckBox) view.findViewById(R.id.overview_showdeviations);
+ showRatiosCheckbox = (CheckBox) view.findViewById(R.id.overview_showratios);
+ showPredictionCheckbox.setChecked(SP.getBoolean("showprediction", false));
+ showBasalsCheckbox.setChecked(SP.getBoolean("showbasals", true));
+ showIobCheckbox.setChecked(SP.getBoolean("showiob", false));
+ showCobCheckbox.setChecked(SP.getBoolean("showcob", false));
+ showDeviationsCheckbox.setChecked(SP.getBoolean("showdeviations", false));
+ showRatiosCheckbox.setChecked(SP.getBoolean("showratios", false));
+ showPredictionCheckbox.setOnCheckedChangeListener(this);
+ showBasalsCheckbox.setOnCheckedChangeListener(this);
+ showIobCheckbox.setOnCheckedChangeListener(this);
+ showCobCheckbox.setOnCheckedChangeListener(this);
+ showDeviationsCheckbox.setOnCheckedChangeListener(this);
+ showRatiosCheckbox.setOnCheckedChangeListener(this);
+
+ showPredictionLabel = (TextView) view.findViewById(R.id.overview_showprediction_label);
+ showPredictionLabel.setOnClickListener(this);
+ showBasalsLabel = (TextView) view.findViewById(R.id.overview_showbasals_label);
+ showBasalsLabel.setOnClickListener(this);
+ showIobLabel = (TextView) view.findViewById(R.id.overview_showiob_label);
+ showIobLabel.setOnClickListener(this);
+ showCobLabel = (TextView) view.findViewById(R.id.overview_showcob_label);
+ showCobLabel.setOnClickListener(this);
+ showDeviationsLabel = (TextView) view.findViewById(R.id.overview_showdeviations_label);
+ showDeviationsLabel.setOnClickListener(this);
+ showRatiosLabel = (TextView) view.findViewById(R.id.overview_showratios_label);
+ showRatiosLabel.setOnClickListener(this);
notificationsView = (RecyclerView) view.findViewById(R.id.overview_notifications);
notificationsView.setHasFixedSize(true);
@@ -375,24 +392,24 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
case R.id.overview_showiob:
break;
case R.id.overview_showcob:
- showDeviationsView.setOnCheckedChangeListener(null);
- showDeviationsView.setChecked(false);
- showDeviationsView.setOnCheckedChangeListener(this);
+ showDeviationsCheckbox.setOnCheckedChangeListener(null);
+ showDeviationsCheckbox.setChecked(false);
+ showDeviationsCheckbox.setOnCheckedChangeListener(this);
break;
case R.id.overview_showdeviations:
- showCobView.setOnCheckedChangeListener(null);
- showCobView.setChecked(false);
- showCobView.setOnCheckedChangeListener(this);
+ showCobCheckbox.setOnCheckedChangeListener(null);
+ showCobCheckbox.setChecked(false);
+ showCobCheckbox.setOnCheckedChangeListener(this);
break;
case R.id.overview_showratios:
break;
}
- SP.putBoolean("showiob", showIobView.isChecked());
- SP.putBoolean("showprediction", showPredictionView.isChecked());
- SP.putBoolean("showbasals", showBasalsView.isChecked());
- SP.putBoolean("showcob", showCobView.isChecked());
- SP.putBoolean("showdeviations", showDeviationsView.isChecked());
- SP.putBoolean("showratios", showRatiosView.isChecked());
+ SP.putBoolean("showiob", showIobCheckbox.isChecked());
+ SP.putBoolean("showprediction", showPredictionCheckbox.isChecked());
+ SP.putBoolean("showbasals", showBasalsCheckbox.isChecked());
+ SP.putBoolean("showcob", showCobCheckbox.isChecked());
+ SP.putBoolean("showdeviations", showDeviationsCheckbox.isChecked());
+ SP.putBoolean("showratios", showRatiosCheckbox.isChecked());
scheduleUpdateGUI("onGraphCheckboxesCheckedChanged");
}
@@ -619,6 +636,24 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
if (ConfigBuilderPlugin.getActivePump().isSuspended() || !ConfigBuilderPlugin.getActivePump().isInitialized())
ConfigBuilderPlugin.getCommandQueue().readStatus("RefreshClicked", null);
break;
+ case R.id.overview_showprediction_label:
+ showPredictionCheckbox.toggle();
+ break;
+ case R.id.overview_showbasals_label:
+ showBasalsCheckbox.toggle();
+ break;
+ case R.id.overview_showiob_label:
+ showIobCheckbox.toggle();
+ break;
+ case R.id.overview_showcob_label:
+ showCobCheckbox.toggle();
+ break;
+ case R.id.overview_showdeviations_label:
+ showDeviationsCheckbox.toggle();
+ break;
+ case R.id.overview_showratios_label:
+ showRatiosCheckbox.toggle();
+ break;
}
}
@@ -638,7 +673,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
if (ConfigBuilderPlugin.getActiveLoop() != null) {
ConfigBuilderPlugin.getActiveLoop().invoke("Accept temp button", false);
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
- if (finalLastRun != null && finalLastRun.lastAPSRun != null && finalLastRun.constraintsProcessed.changeRequested) {
+ if (finalLastRun != null && finalLastRun.lastAPSRun != null && finalLastRun.constraintsProcessed.isChangeRequested()) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(getContext().getString(R.string.confirmation));
builder.setMessage(getContext().getString(R.string.setbasalquestion) + "\n" + finalLastRun.constraintsProcessed);
@@ -1069,7 +1104,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
boolean showAcceptButton = !MainApp.getConfigBuilder().isClosedModeEnabled(); // Open mode needed
showAcceptButton = showAcceptButton && finalLastRun != null && finalLastRun.lastAPSRun != null; // aps result must exist
showAcceptButton = showAcceptButton && (finalLastRun.lastOpenModeAccept == null || finalLastRun.lastOpenModeAccept.getTime() < finalLastRun.lastAPSRun.getTime()); // never accepted or before last result
- showAcceptButton = showAcceptButton && finalLastRun.constraintsProcessed.changeRequested; // change is requested
+ showAcceptButton = showAcceptButton && finalLastRun.constraintsProcessed.isChangeRequested(); // change is requested
if (showAcceptButton && pump.isInitialized() && !pump.isSuspended() && ConfigBuilderPlugin.getActiveLoop() != null) {
acceptTempLayout.setVisibility(View.VISIBLE);
@@ -1241,19 +1276,19 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// cob
if (cobView != null) { // view must not exists
String cobText = "";
- AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData("Overview COB");
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensData("Overview COB");
if (autosensData != null)
cobText = (int) autosensData.cob + " g";
cobView.setText(cobText);
}
- final boolean showPrediction = showPredictionView.isChecked() && finalLastRun != null && finalLastRun.constraintsProcessed.getClass().equals(DetermineBasalResultAMA.class);
- if (MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class) != null && MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class).isEnabled(PluginBase.APS)) {
- showPredictionView.setVisibility(View.VISIBLE);
- getActivity().findViewById(R.id.overview_showprediction_label).setVisibility(View.VISIBLE);
+ final boolean predictionsAvailable = finalLastRun != null && finalLastRun.request.hasPredictions;
+ if (predictionsAvailable) {
+ showPredictionCheckbox.setVisibility(View.VISIBLE);
+ showPredictionLabel.setVisibility(View.VISIBLE);
} else {
- showPredictionView.setVisibility(View.GONE);
- getActivity().findViewById(R.id.overview_showprediction_label).setVisibility(View.GONE);
+ showPredictionCheckbox.setVisibility(View.GONE);
+ showPredictionLabel.setVisibility(View.GONE);
}
// pump status from ns
@@ -1306,8 +1341,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
final long toTime;
final long fromTime;
final long endTime;
- if (showPrediction) {
- int predHours = (int) (Math.ceil(((DetermineBasalResultAMA) finalLastRun.constraintsProcessed).getLatestPredictionsTime() - System.currentTimeMillis()) / (60 * 60 * 1000));
+ if (predictionsAvailable && showPredictionCheckbox.isChecked()) {
+ int predHours = (int) (Math.ceil(finalLastRun.constraintsProcessed.getLatestPredictionsTime() - System.currentTimeMillis()) / (60 * 60 * 1000));
predHours = Math.min(2, predHours);
predHours = Math.max(0, predHours);
hoursToFetch = rangeToDisplay - predHours;
@@ -1327,14 +1362,14 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// ------------------ 1st graph
Profiler.log(log, from + " - 1st graph - START", updateGUIStart);
- final GraphData graphData = new GraphData(bgGraph);
+ final GraphData graphData = new GraphData(bgGraph, IobCobCalculatorPlugin.getPlugin());
// **** In range Area ****
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine);
// **** BG ****
- if (showPrediction)
- graphData.addBgReadings(fromTime, toTime, lowLine, highLine, (DetermineBasalResultAMA) finalLastRun.constraintsProcessed);
+ if (predictionsAvailable && showPredictionCheckbox.isChecked())
+ graphData.addBgReadings(fromTime, toTime, lowLine, highLine, finalLastRun.constraintsProcessed);
else
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null);
@@ -1345,41 +1380,49 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
graphData.addTreatments(fromTime, endTime);
// add basal data
- if (pump.getPumpDescription().isTempBasalCapable && showBasalsView.isChecked()) {
+ if (pump.getPumpDescription().isTempBasalCapable && showBasalsCheckbox.isChecked()) {
graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2d);
}
+ // add target line
+ graphData.addTargetLine(fromTime, toTime);
+
// **** NOW line ****
graphData.addNowLine(now);
// ------------------ 2nd graph
Profiler.log(log, from + " - 2nd graph - START", updateGUIStart);
- final GraphData secondGraphData = new GraphData(iobGraph);
+ final GraphData secondGraphData = new GraphData(iobGraph, IobCobCalculatorPlugin.getPlugin());
boolean useIobForScale = false;
boolean useCobForScale = false;
boolean useDevForScale = false;
boolean useRatioForScale = false;
+ boolean useDSForScale = false;
- if (showIobView.isChecked()) {
+ if (showIobCheckbox.isChecked()) {
useIobForScale = true;
- } else if (showCobView.isChecked()) {
+ } else if (showCobCheckbox.isChecked()) {
useCobForScale = true;
- } else if (showDeviationsView.isChecked()) {
+ } else if (showDeviationsCheckbox.isChecked()) {
useDevForScale = true;
- } else if (showRatiosView.isChecked()) {
+ } else if (showRatiosCheckbox.isChecked()) {
useRatioForScale = true;
+ } else if (Config.displayDeviationSlope) {
+ useDSForScale = true;
}
- if (showIobView.isChecked())
+ if (showIobCheckbox.isChecked())
secondGraphData.addIob(fromTime, now, useIobForScale, 1d);
- if (showCobView.isChecked())
+ if (showCobCheckbox.isChecked())
secondGraphData.addCob(fromTime, now, useCobForScale, useCobForScale ? 1d : 0.5d);
- if (showDeviationsView.isChecked())
+ if (showDeviationsCheckbox.isChecked())
secondGraphData.addDeviations(fromTime, now, useDevForScale, 1d);
- if (showRatiosView.isChecked())
+ if (showRatiosCheckbox.isChecked())
secondGraphData.addRatio(fromTime, now, useRatioForScale, 1d);
+ if (Config.displayDeviationSlope)
+ secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1d);
// **** NOW line ****
// set manual x bounds to have nice steps
@@ -1392,7 +1435,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
- if (showIobView.isChecked() || showCobView.isChecked() || showDeviationsView.isChecked() || showRatiosView.isChecked()) {
+ if (showIobCheckbox.isChecked() || showCobCheckbox.isChecked() || showDeviationsCheckbox.isChecked() || showRatiosCheckbox.isChecked() || Config.displayDeviationSlope) {
iobGraph.setVisibility(View.VISIBLE);
} else {
iobGraph.setVisibility(View.GONE);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/events/EventOverviewBolusProgress.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/events/EventOverviewBolusProgress.java
index e0fd53a1fd..080dec4bd2 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/events/EventOverviewBolusProgress.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/events/EventOverviewBolusProgress.java
@@ -16,6 +16,10 @@ public class EventOverviewBolusProgress extends Event {
public EventOverviewBolusProgress() {
}
+ public boolean isSMB(){
+ return (t != null) && t.isSMB;
+ }
+
public static EventOverviewBolusProgress getInstance() {
if(eventOverviewBolusProgress == null) {
eventOverviewBolusProgress = new EventOverviewBolusProgress();
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java
index e76714c5b2..02bb1a7b3d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java
@@ -12,7 +12,6 @@ import com.jjoe64.graphview.series.LineGraphSeries;
import com.jjoe64.graphview.series.Series;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import info.nightscout.androidaps.Constants;
@@ -23,12 +22,14 @@ import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
+import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.BasalData;
-import info.nightscout.androidaps.plugins.OpenAPSAMA.DetermineBasalResultAMA;
+import info.nightscout.androidaps.plugins.Loop.APSResult;
+import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.AreaGraphSeries;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DoubleDataPoint;
@@ -37,6 +38,7 @@ import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLab
import info.nightscout.androidaps.plugins.Overview.graphExtensions.Scale;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.ScaledDataPoint;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.TimeAsXAxisLabelFormatter;
+import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.Round;
/**
@@ -51,12 +53,15 @@ public class GraphData {
private String units;
private List series = new ArrayList<>();
- public GraphData(GraphView graph) {
+ private IobCobCalculatorPlugin iobCobCalculatorPlugin;
+
+ public GraphData(GraphView graph, IobCobCalculatorPlugin iobCobCalculatorPlugin) {
units = MainApp.getConfigBuilder().getProfileUnits();
this.graph = graph;
+ this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
}
- public void addBgReadings(long fromTime, long toTime, double lowLine, double highLine, DetermineBasalResultAMA amaResult) {
+ public void addBgReadings(long fromTime, long toTime, double lowLine, double highLine, APSResult apsResult) {
double maxBgValue = 0d;
bgReadingsArray = MainApp.getDbHelper().getBgreadingsDataFromTime(fromTime, true);
List bgListArray = new ArrayList<>();
@@ -65,14 +70,12 @@ public class GraphData {
return;
}
- Iterator it = bgReadingsArray.iterator();
- while (it.hasNext()) {
- BgReading bg = it.next();
+ for (BgReading bg : bgReadingsArray) {
if (bg.value > maxBgValue) maxBgValue = bg.value;
bgListArray.add(bg);
}
- if (amaResult != null) {
- List predArray = amaResult.getPredictions();
+ if (apsResult != null) {
+ List predArray = apsResult.getPredictions();
bgListArray.addAll(predArray);
}
@@ -125,11 +128,11 @@ public class GraphData {
List basalLineArray = new ArrayList<>();
List absoluteBasalLineArray = new ArrayList<>();
double lastLineBasal = 0;
- double lastAbsoluteLineBasal = 0;
+ double lastAbsoluteLineBasal = -1;
double lastBaseBasal = 0;
double lastTempBasal = 0;
for (long time = fromTime; time < toTime; time += 60 * 1000L) {
- BasalData basalData = IobCobCalculatorPlugin.getBasalData(time);
+ BasalData basalData = IobCobCalculatorPlugin.getPlugin().getBasalData(time);
double baseBasalValue = basalData.basal;
double absoluteLineValue = baseBasalValue;
double tempBasalValue = 0;
@@ -218,6 +221,54 @@ public class GraphData {
addSeries(absoluteBasalsLineSeries);
}
+ public void addTargetLine(long fromTime, long toTime) {
+ Profile profile = MainApp.getConfigBuilder().getProfile();
+ if (profile == null) {
+ return;
+ }
+
+ LineGraphSeries targetsSeries;
+
+ Scale targetsScale = new Scale();
+ targetsScale.setMultiplier(1);
+
+ List targetsSeriesArray = new ArrayList<>();
+ double lastTarget = 0;
+
+ if (LoopPlugin.lastRun != null && LoopPlugin.lastRun.constraintsProcessed != null) {
+ APSResult apsResult = LoopPlugin.lastRun.constraintsProcessed;
+ long latestPredictionsTime = apsResult.getLatestPredictionsTime();
+ if (latestPredictionsTime > toTime) {
+ toTime = latestPredictionsTime;
+ }
+ }
+
+ for (long time = fromTime; time < toTime; time += 60 * 1000L) {
+ TempTarget tt = TreatmentsPlugin.getPlugin().getTempTargetFromHistory(time);
+ double value;
+ if (tt == null) {
+ value = (profile.getTargetLow(time) + profile.getTargetHigh(time)) / 2;
+ } else {
+ value = (tt.low + tt.high) / 2;
+ }
+ if (lastTarget > 0 && lastTarget != value) {
+ targetsSeriesArray.add(new DataPoint(time, lastTarget));
+ }
+ lastTarget = value;
+
+ targetsSeriesArray.add(new DataPoint(time, value));
+ }
+
+ DataPoint[] targets = new DataPoint[targetsSeriesArray.size()];
+ targets = targetsSeriesArray.toArray(targets);
+ targetsSeries = new LineGraphSeries<>(targets);
+ targetsSeries.setDrawBackground(false);
+ targetsSeries.setColor(MainApp.sResources.getColor(R.color.tempTargetBackground));
+ targetsSeries.setThickness(2);
+
+ addSeries(targetsSeries);
+ }
+
public void addTreatments(long fromTime, long endTime) {
List filteredTreatments = new ArrayList<>();
@@ -253,7 +304,7 @@ public class GraphData {
}
// Careportal
- List careportalEvents = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, true);
+ List careportalEvents = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true);
for (int tx = 0; tx < careportalEvents.size(); tx++) {
DataPointWithLabelInterface t = careportalEvents.get(tx);
@@ -267,7 +318,7 @@ public class GraphData {
addSeries(new PointsWithLabelGraphSeries<>(treatmentsArray));
}
- double getNearestBg(long date) {
+ private double getNearestBg(long date) {
double bg = 0;
for (int r = bgReadingsArray.size() - 1; r >= 0; r--) {
BgReading reading = bgReadingsArray.get(r);
@@ -287,7 +338,7 @@ public class GraphData {
Scale iobScale = new Scale();
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
- double iob = IobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time).iob;
+ double iob = IobCobCalculatorPlugin.getPlugin().calculateFromTreatmentsAndTempsSynchronized(time).iob;
if (Math.abs(lastIob - iob) > 0.02) {
if (Math.abs(lastIob - iob) > 0.2)
iobArray.add(new ScaledDataPoint(time, lastIob, iobScale));
@@ -322,7 +373,7 @@ public class GraphData {
Scale cobScale = new Scale();
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
- AutosensData autosensData = IobCobCalculatorPlugin.getAutosensData(time);
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time);
if (autosensData != null) {
int cob = (int) autosensData.cob;
if (cob != lastCob) {
@@ -369,7 +420,7 @@ public class GraphData {
Scale devScale = new Scale();
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
- AutosensData autosensData = IobCobCalculatorPlugin.getAutosensData(time);
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time);
if (autosensData != null) {
int color = Color.BLACK; // "="
if (autosensData.pastSensitivity.equals("C")) color = Color.GRAY;
@@ -401,21 +452,21 @@ public class GraphData {
// scale in % of vertical size (like 0.3)
public void addRatio(long fromTime, long toTime, boolean useForScale, double scale) {
- LineGraphSeries ratioSeries;
- List ratioArray = new ArrayList<>();
+ LineGraphSeries ratioSeries;
+ List ratioArray = new ArrayList<>();
Double maxRatioValueFound = 0d;
Scale ratioScale = new Scale(-1d);
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
- AutosensData autosensData = IobCobCalculatorPlugin.getAutosensData(time);
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time);
if (autosensData != null) {
- ratioArray.add(new DataPoint(time, autosensData.autosensRatio));
+ ratioArray.add(new ScaledDataPoint(time, autosensData.autosensRatio, ratioScale));
maxRatioValueFound = Math.max(maxRatioValueFound, Math.abs(autosensData.autosensRatio));
}
}
// RATIOS
- DataPoint[] ratioData = new DataPoint[ratioArray.size()];
+ ScaledDataPoint[] ratioData = new ScaledDataPoint[ratioArray.size()];
ratioData = ratioArray.toArray(ratioData);
ratioSeries = new LineGraphSeries<>(ratioData);
ratioSeries.setColor(MainApp.sResources.getColor(R.color.ratio));
@@ -429,6 +480,50 @@ public class GraphData {
addSeries(ratioSeries);
}
+ // scale in % of vertical size (like 0.3)
+ public void addDeviationSlope(long fromTime, long toTime, boolean useForScale, double scale) {
+ LineGraphSeries dsMaxSeries;
+ LineGraphSeries dsMinSeries;
+ List dsMaxArray = new ArrayList<>();
+ List dsMinArray = new ArrayList<>();
+ Double maxFromMaxValueFound = 0d;
+ Double maxFromMinValueFound = 0d;
+ Scale dsMaxScale = new Scale();
+ Scale dsMinScale = new Scale();
+
+ for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time);
+ if (autosensData != null) {
+ dsMaxArray.add(new ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale));
+ dsMinArray.add(new ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale));
+ maxFromMaxValueFound = Math.max(maxFromMaxValueFound, Math.abs(autosensData.slopeFromMaxDeviation));
+ maxFromMinValueFound = Math.max(maxFromMinValueFound, Math.abs(autosensData.slopeFromMinDeviation));
+ }
+ }
+
+ // Slopes
+ ScaledDataPoint[] ratioMaxData = new ScaledDataPoint[dsMaxArray.size()];
+ ratioMaxData = dsMaxArray.toArray(ratioMaxData);
+ dsMaxSeries = new LineGraphSeries<>(ratioMaxData);
+ dsMaxSeries.setColor(Color.MAGENTA);
+ dsMaxSeries.setThickness(3);
+
+ ScaledDataPoint[] ratioMinData = new ScaledDataPoint[dsMinArray.size()];
+ ratioMinData = dsMinArray.toArray(ratioMinData);
+ dsMinSeries = new LineGraphSeries<>(ratioMinData);
+ dsMinSeries.setColor(Color.YELLOW);
+ dsMinSeries.setThickness(3);
+
+ if (useForScale)
+ maxY = Math.max(maxFromMaxValueFound, maxFromMinValueFound);
+
+ dsMaxScale.setMultiplier(maxY * scale / maxFromMaxValueFound);
+ dsMinScale.setMultiplier(maxY * scale / maxFromMinValueFound);
+
+ addSeries(dsMaxSeries);
+ addSeries(dsMinSeries);
+ }
+
// scale in % of vertical size (like 0.3)
public void addNowLine(long now) {
LineGraphSeries seriesNow;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/DataPointWithLabelInterface.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/DataPointWithLabelInterface.java
index 20d478692a..3f6280431c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/DataPointWithLabelInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/DataPointWithLabelInterface.java
@@ -55,4 +55,5 @@ public interface DataPointWithLabelInterface extends DataPointInterface{
PointsWithLabelGraphSeries.Shape getShape();
float getSize();
int getColor();
+ int getSecondColor();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/PointsWithLabelGraphSeries.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/PointsWithLabelGraphSeries.java
index 7606a71f17..0051518bb4 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/PointsWithLabelGraphSeries.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphExtensions/PointsWithLabelGraphSeries.java
@@ -60,17 +60,12 @@ public class PointsWithLabelGraphSeries e
* You can also render a custom drawing via {@link com.jjoe64.graphview.series.PointsGraphSeries.CustomShape}
*/
public enum Shape {
- /**
- * draws a point / circle
- */
- POINT,
-
- /**
- * draws a triangle
- */
+ BG,
+ PREDICTION,
TRIANGLE,
RECTANGLE,
BOLUS,
+ SMB,
EXTENDEDBOLUS,
PROFILE,
MBG,
@@ -141,9 +136,6 @@ public class PointsWithLabelGraphSeries e
Iterator values = getValues(minX, maxX);
// draw background
- double lastEndY = 0;
- double lastEndX = 0;
-
// draw data
double diffY = maxY - minY;
@@ -154,9 +146,8 @@ public class PointsWithLabelGraphSeries e
float graphLeft = graphView.getGraphContentLeft();
float graphTop = graphView.getGraphContentTop();
- lastEndY = 0;
- lastEndX = 0;
- float firstX = 0;
+ float scaleX = (float) (graphWidth / diffX);
+
int i=0;
while (values.hasNext()) {
E value = values.next();
@@ -171,9 +162,6 @@ public class PointsWithLabelGraphSeries e
double ratX = valX / diffX;
double x = graphWidth * ratX;
- double orgX = x;
- double orgY = y;
-
// overdraw
boolean overdraw = false;
if (x > graphWidth) { // end right
@@ -185,6 +173,14 @@ public class PointsWithLabelGraphSeries e
if (y > graphHeight) { // end top
overdraw = true;
}
+
+ long duration = value.getDuration();
+ float endWithDuration = (float) (x + duration * scaleX + graphLeft + 1);
+ // cut off to graph start if needed
+ if (x < 0 && endWithDuration > 0) {
+ x = 0;
+ }
+
/* Fix a bug that continue to show the DOT after Y axis */
if(x < 0) {
overdraw = true;
@@ -195,15 +191,25 @@ public class PointsWithLabelGraphSeries e
registerDataPoint(endX, endY, value);
float xpluslength = 0;
- if (value.getDuration() > 0) {
- xpluslength = endX + Math.min((float) (value.getDuration() * graphWidth / diffX), graphLeft + graphWidth);
+ if (duration > 0) {
+ xpluslength = Math.min(endWithDuration, graphLeft + graphWidth);
}
// draw data point
if (!overdraw) {
- if (value.getShape() == Shape.POINT) {
+ if (value.getShape() == Shape.BG) {
+ mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(0);
canvas.drawCircle(endX, endY, scaledPxSize, mPaint);
+ } else if (value.getShape() == Shape.PREDICTION) {
+ mPaint.setColor(value.getColor());
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setStrokeWidth(0);
+ canvas.drawCircle(endX, endY, scaledPxSize, mPaint);
+ mPaint.setColor(value.getSecondColor());
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setStrokeWidth(0);
+ canvas.drawCircle(endX, endY, scaledPxSize / 3, mPaint);
} else if (value.getShape() == Shape.RECTANGLE) {
canvas.drawRect(endX-scaledPxSize, endY-scaledPxSize, endX+scaledPxSize, endY+scaledPxSize, mPaint);
} else if (value.getShape() == Shape.TRIANGLE) {
@@ -224,6 +230,14 @@ public class PointsWithLabelGraphSeries e
if (value.getLabel() != null) {
drawLabel45(endX, endY, value, canvas);
}
+ } else if (value.getShape() == Shape.SMB) {
+ mPaint.setStrokeWidth(2);
+ Point[] points = new Point[3];
+ points[0] = new Point((int)endX, (int)(endY-value.getSize()));
+ points[1] = new Point((int)(endX+value.getSize()), (int)(endY+value.getSize()*0.67));
+ points[2] = new Point((int)(endX-value.getSize()), (int)(endY+value.getSize()*0.67));
+ mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ drawArrows(points, canvas, mPaint);
} else if (value.getShape() == Shape.EXTENDEDBOLUS) {
mPaint.setStrokeWidth(0);
if (value.getLabel() != null) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/NotificationStore.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/NotificationStore.java
index 1ce92249f7..aa61b48097 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/NotificationStore.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/NotificationStore.java
@@ -21,8 +21,6 @@ import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.Services.AlarmSoundService;
-import info.nightscout.androidaps.plugins.Wear.WearPlugin;
-//Added by Rumen for snooze time
import info.nightscout.utils.SP;
/**
@@ -44,16 +42,12 @@ public class NotificationStore {
}
}
- public Notification get(int index) {
- return store.get(index);
- }
-
- public void add(Notification n) {
+ public synchronized void add(Notification n) {
log.info("Notification received: " + n.text);
- for (int i = 0; i < store.size(); i++) {
- if (get(i).id == n.id) {
- get(i).date = n.date;
- get(i).validTo = n.validTo;
+ for (Notification storeNotification : store) {
+ if (storeNotification.id == n.id) {
+ storeNotification.date = n.date;
+ storeNotification.validTo = n.validTo;
return;
}
}
@@ -72,6 +66,44 @@ public class NotificationStore {
Collections.sort(store, new NotificationComparator());
}
+ public synchronized boolean remove(int id) {
+ for (int i = 0; i < store.size(); i++) {
+ if (store.get(i).id == id) {
+ if (store.get(i).soundId != null) {
+ Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class);
+ MainApp.instance().stopService(alarm);
+ }
+ store.remove(i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public synchronized void removeExpired() {
+ for (int i = 0; i < store.size(); i++) {
+ Notification n = store.get(i);
+ if (n.validTo.getTime() != 0 && n.validTo.getTime() < System.currentTimeMillis()) {
+ store.remove(i);
+ i--;
+ }
+ }
+ }
+
+ public void snoozeTo(long timeToSnooze) {
+ log.debug("Snoozing alarm until: " + timeToSnooze);
+ SP.putLong("snoozedTo", timeToSnooze);
+ }
+
+ public void unSnooze() {
+ if (Notification.isAlarmForStaleData()) {
+ Notification notification = new Notification(Notification.NSALARM, MainApp.sResources.getString(R.string.nsalarm_staledata), Notification.URGENT);
+ SP.putLong("snoozedTo", System.currentTimeMillis());
+ add(notification);
+ log.debug("Snoozed to current time and added back notification!");
+ }
+ }
+
private void raiseSystemNotification(Notification n) {
Context context = MainApp.instance().getApplicationContext();
NotificationManager mgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -95,42 +127,4 @@ public class NotificationStore {
}
mgr.notify(n.id, notificationBuilder.build());
}
-
- public boolean remove(int id) {
- for (int i = 0; i < store.size(); i++) {
- if (get(i).id == id) {
- if (get(i).soundId != null) {
- Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class);
- MainApp.instance().stopService(alarm);
- }
- store.remove(i);
- return true;
- }
- }
- return false;
- }
-
- public void removeExpired() {
- for (int i = 0; i < store.size(); i++) {
- Notification n = get(i);
- if (n.validTo.getTime() != 0 && n.validTo.getTime() < System.currentTimeMillis()) {
- store.remove(i);
- i--;
- }
- }
- }
-
- public void snoozeTo(long timeToSnooze) {
- log.debug("Snoozing alarm until: " + timeToSnooze);
- SP.putLong("snoozedTo", timeToSnooze);
- }
-
- public void unSnooze() {
- if (Notification.isAlarmForStaleData()) {
- Notification notification = new Notification(Notification.NSALARM, MainApp.sResources.getString(R.string.nsalarm_staledata), Notification.URGENT);
- SP.putLong("snoozedTo", System.currentTimeMillis());
- add(notification);
- log.debug("Snoozed to current time and added back notification!");
- }
- }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java
index 9e631def18..558d01b94d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java
@@ -7,7 +7,7 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v4.app.TaskStackBuilder;
-import android.support.v7.app.NotificationCompat;
+import android.support.v4.app.NotificationCompat;
import com.squareup.otto.Subscribe;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfileFragment.java
deleted file mode 100644
index 74b400e1af..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfileFragment.java
+++ /dev/null
@@ -1,546 +0,0 @@
-package info.nightscout.androidaps.plugins.ProfileCircadianPercentage;
-
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.content.ContextCompat;
-import android.text.Editable;
-import android.text.Html;
-import android.text.TextWatcher;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RadioButton;
-import android.widget.TextView;
-
-import com.andreabaccega.widget.FormEditText;
-import com.squareup.otto.Subscribe;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.events.EventInitializationChanged;
-import info.nightscout.androidaps.events.EventProfileSwitchChange;
-import info.nightscout.androidaps.plugins.Careportal.CareportalFragment;
-import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
-import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
-import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
-import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
-import info.nightscout.utils.DecimalFormatter;
-import info.nightscout.utils.SafeParse;
-
-public class CircadianPercentageProfileFragment extends SubscriberFragment {
- private static Logger log = LoggerFactory.getLogger(CircadianPercentageProfileFragment.class);
-
- private static CircadianPercentageProfilePlugin circadianPercentageProfilePlugin = new CircadianPercentageProfilePlugin();
- private Object snackbarCaller;
-
- public static CircadianPercentageProfilePlugin getPlugin() {
- return circadianPercentageProfilePlugin;
- }
-
- FormEditText diaView;
- RadioButton mgdlView;
- RadioButton mmolView;
- FormEditText targetlowView;
- FormEditText targethighView;
- FormEditText percentageView;
- FormEditText timeshiftView;
- TextView profileView;
- TextView baseprofileIC;
- TextView baseprofileBasal;
- LinearLayout baseprofileBasalLayout;
- TextView baseprofileISF;
- Button profileswitchButton;
- ImageView percentageIcon;
- ImageView timeIcon;
- ImageView basaleditIcon;
- ImageView iceditIcon;
- ImageView isfeditIcon;
- BasalEditDialog basalEditDialog;
- FrameLayout fl;
- Snackbar mSnackBar;
-
- static Boolean percentageViewHint = true;
- static Boolean timeshiftViewHint = true;
-
- TextWatcher textWatch = new TextWatcher() {
-
- @Override
- public void afterTextChanged(Editable s) {
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start,
- int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start,
- int before, int count) {
-
- if (percentageView.testValidity()) {
- if (SafeParse.stringToInt(percentageView.getText().toString()) == 0) {
- circadianPercentageProfilePlugin.percentage = 100;
- } else {
- circadianPercentageProfilePlugin.percentage = SafeParse.stringToInt(percentageView.getText().toString());
- }
- updateProfileInfo();
- }
- if (timeshiftView.testValidity()) {
- circadianPercentageProfilePlugin.timeshift = SafeParse.stringToInt(timeshiftView.getText().toString());
- updateProfileInfo();
- }
- if (diaView.testValidity()) {
- circadianPercentageProfilePlugin.dia = SafeParse.stringToDouble(diaView.getText().toString());
- updateProfileInfo();
- }
- if (targethighView.testValidity()) {
- circadianPercentageProfilePlugin.targetLow = SafeParse.stringToDouble(targetlowView.getText().toString());
- updateProfileInfo();
- }
- if (targetlowView.testValidity()) {
- circadianPercentageProfilePlugin.targetHigh = SafeParse.stringToDouble(targethighView.getText().toString());
- updateProfileInfo();
- }
- circadianPercentageProfilePlugin.storeSettings();
- updateProfileInfo();
- }
- };
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
- showDeprecatedDialog();
-
- View layout = inflater.inflate(R.layout.circadianpercentageprofile_fragment, container, false);
- fl = (FrameLayout) layout.findViewById(R.id.circadianpercentageprofile_framelayout);
- fl.requestFocusFromTouch();
- diaView = (FormEditText) layout.findViewById(R.id.circadianpercentageprofile_dia);
- mgdlView = (RadioButton) layout.findViewById(R.id.circadianpercentageprofile_mgdl);
- mmolView = (RadioButton) layout.findViewById(R.id.circadianpercentageprofile_mmol);
- targetlowView = (FormEditText) layout.findViewById(R.id.circadianpercentageprofile_targetlow);
- targethighView = (FormEditText) layout.findViewById(R.id.circadianpercentageprofile_targethigh);
- percentageView = (FormEditText) layout.findViewById(R.id.circadianpercentageprofile_percentage);
- timeshiftView = (FormEditText) layout.findViewById(R.id.circadianpercentageprofile_timeshift);
- profileView = (TextView) layout.findViewById(R.id.circadianpercentageprofile_profileview);
- baseprofileBasal = (TextView) layout.findViewById(R.id.circadianpercentageprofile_baseprofilebasal);
- baseprofileBasalLayout = (LinearLayout) layout.findViewById(R.id.circadianpercentageprofile_baseprofilebasal_layout);
- baseprofileIC = (TextView) layout.findViewById(R.id.circadianpercentageprofile_baseprofileic);
- baseprofileISF = (TextView) layout.findViewById(R.id.circadianpercentageprofile_baseprofileisf);
- percentageIcon = (ImageView) layout.findViewById(R.id.circadianpercentageprofile_percentageicon);
- timeIcon = (ImageView) layout.findViewById(R.id.circadianpercentageprofile_timeicon);
- profileswitchButton = (Button) layout.findViewById(R.id.circadianpercentageprofile_profileswitch);
-
- basaleditIcon = (ImageView) layout.findViewById(R.id.circadianpercentageprofile_basaledit);
- iceditIcon = (ImageView) layout.findViewById(R.id.circadianpercentageprofile_icedit);
- isfeditIcon = (ImageView) layout.findViewById(R.id.circadianpercentageprofile_isfedit);
-
- if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable) {
- layout.findViewById(R.id.circadianpercentageprofile_baseprofilebasal_layout).setVisibility(View.GONE);
- }
-
- mgdlView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- circadianPercentageProfilePlugin.mgdl = mgdlView.isChecked();
- circadianPercentageProfilePlugin.mmol = !circadianPercentageProfilePlugin.mgdl;
- mmolView.setChecked(circadianPercentageProfilePlugin.mmol);
- circadianPercentageProfilePlugin.storeSettings();
- updateProfileInfo();
- }
- });
- mmolView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- circadianPercentageProfilePlugin.mmol = mmolView.isChecked();
- circadianPercentageProfilePlugin.mgdl = !circadianPercentageProfilePlugin.mmol;
- mgdlView.setChecked(circadianPercentageProfilePlugin.mgdl);
- circadianPercentageProfilePlugin.storeSettings();
- updateProfileInfo();
- }
- });
-
- profileswitchButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
- final OptionsToShow profileswitch = CareportalFragment.PROFILESWITCHDIRECT;
- profileswitch.executeProfileSwitch = true;
- newDialog.setOptions(profileswitch, R.string.careportal_profileswitch);
- newDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
- }
- });
-
- timeIcon.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- timeshiftView.requestFocusFromTouch();
- timeshiftView.setSelection(timeshiftView.getText().length());
- ((InputMethodManager) getContext()
- .getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(timeshiftView, InputMethodManager.SHOW_IMPLICIT);
- }
- });
-
- percentageIcon.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- percentageView.requestFocusFromTouch();
- percentageView.setSelection(percentageView.getText().length());
- ((InputMethodManager) getContext()
- .getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(percentageView, InputMethodManager.SHOW_IMPLICIT);
- }
- });
-
- basaleditIcon.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- basalEditDialog = new BasalEditDialog();
- basalEditDialog.setup(getPlugin().basebasal, getString(R.string.edit_base_basal), CircadianPercentageProfileFragment.this);
- basalEditDialog.show(getFragmentManager(), getString(R.string.edit_base_basal));
- }
- });
-
- isfeditIcon.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- basalEditDialog = new BasalEditDialog();
- basalEditDialog.setup(getPlugin().baseisf, getString(R.string.edit_base_isf), CircadianPercentageProfileFragment.this);
- basalEditDialog.show(getFragmentManager(), getString(R.string.edit_base_isf));
- }
- });
-
- iceditIcon.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- basalEditDialog = new BasalEditDialog();
- basalEditDialog.setup(getPlugin().baseic, getString(R.string.edit_base_ic), CircadianPercentageProfileFragment.this);
- basalEditDialog.show(getFragmentManager(), getString(R.string.edit_base_ic));
- }
- });
-
- /*timeshiftView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus) {
- if(mSnackBar!=null && snackbarCaller == timeshiftView){
- mSnackBar.dismiss();
- }
- timeshiftView.clearFocus();
- fl.requestFocusFromTouch();
- }
- else {
- if (timeshiftViewHint) {
- customSnackbar(view, getString(R.string.timeshift_hint), timeshiftView);
- }
- }
- }
- });
-
- percentageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus) {
- if(mSnackBar!=null && snackbarCaller == percentageView){
- mSnackBar.dismiss();
- }
- percentageView.clearFocus();
- fl.requestFocusFromTouch();
- }
- else {
- if (percentageViewHint) {
- customSnackbar(view, getString(R.string.percentagefactor_hint), percentageView);
- }
- }
- }
- });*/
-
- diaView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus) {
- diaView.clearFocus();
- fl.requestFocusFromTouch();
- }
- }
- });
-
- targethighView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus) {
- targethighView.clearFocus();
- fl.requestFocusFromTouch();
- }
- }
- });
-
- targetlowView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus) {
- targetlowView.clearFocus();
- fl.requestFocusFromTouch();
- }
- }
- });
-
-
- diaView.addTextChangedListener(textWatch);
- targetlowView.addTextChangedListener(textWatch);
- targethighView.addTextChangedListener(textWatch);
- percentageView.addTextChangedListener(textWatch);
- timeshiftView.addTextChangedListener(textWatch);
-
- updateGUI();
-
- onStatusEvent(new EventInitializationChanged());
-
- return layout;
- }
-
- private void showDeprecatedDialog() {
- AlertDialog.Builder adb = new AlertDialog.Builder(getContext());
- adb.setTitle("DEPRECATED! Please migrate!");
- adb.setMessage("CircadianPercentageProfile has been deprecated. " +
- "It is recommended to migrate to LocalProfile.\n\n" +
- "Good news: You won't lose any functionality! Percentage and Timeshift have been ported to the ProfileSwitch :) \n\n " +
- "How to migrate:\n" +
- "1) Press MIGRATE, the system will automatically fill the LocalProfile for you.\n" +
- "2) Switch to LocalProfile in the ConfigBuilder\n" +
- "3) CHECK that all settings are correct in the LocalProfile!!!");
- adb.setIcon(android.R.drawable.ic_dialog_alert);
- adb.setPositiveButton("MIGRATE", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- CircadianPercentageProfilePlugin.migrateToLP();
- }
- });
- adb.setNegativeButton("Cancel", null);
- adb.show();
- }
-
- public void updateGUI() {
- updateProfileInfo();
-
- diaView.removeTextChangedListener(textWatch);
- targetlowView.removeTextChangedListener(textWatch);
- targethighView.removeTextChangedListener(textWatch);
- percentageView.removeTextChangedListener(textWatch);
- timeshiftView.removeTextChangedListener(textWatch);
-
- mgdlView.setChecked(circadianPercentageProfilePlugin.mgdl);
- mmolView.setChecked(circadianPercentageProfilePlugin.mmol);
- diaView.setText(circadianPercentageProfilePlugin.dia.toString());
- targetlowView.setText(circadianPercentageProfilePlugin.targetLow.toString());
- targethighView.setText(circadianPercentageProfilePlugin.targetHigh.toString());
- percentageView.setText("" + circadianPercentageProfilePlugin.percentage);
- timeshiftView.setText("" + circadianPercentageProfilePlugin.timeshift);
-
-
- diaView.addTextChangedListener(textWatch);
- targetlowView.addTextChangedListener(textWatch);
- targethighView.addTextChangedListener(textWatch);
- percentageView.addTextChangedListener(textWatch);
- timeshiftView.addTextChangedListener(textWatch);
-
- }
-
- private void customSnackbar(View view, final String Msg, Object snackbarCaller) {
- if (mSnackBar != null) mSnackBar.dismiss();
-
- this.snackbarCaller = snackbarCaller;
- if (timeshiftViewHint || percentageViewHint) {
- //noinspection WrongConstant
- mSnackBar = Snackbar.make(view, Msg, 7000)
- .setActionTextColor(ContextCompat.getColor(MainApp.instance(), R.color.notificationInfo))
- .setAction(getString(R.string.dont_show_again), new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (Msg.equals(getString(R.string.percentagefactor_hint))) {
- percentageViewHint = false;
- } else if (Msg.equals(getString(R.string.timeshift_hint))) {
- timeshiftViewHint = false;
- }
- }
- });
- view = mSnackBar.getView();
- FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
- params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
- view.setLayoutParams(params);
- view.setBackgroundColor(ContextCompat.getColor(MainApp.instance(), R.color.cardview_dark_background));
- TextView mainTextView = (TextView) (view).findViewById(android.support.design.R.id.snackbar_text);
- mainTextView.setTextColor(ContextCompat.getColor(MainApp.instance(), R.color.mdtp_white));
- mSnackBar.show();
- }
- }
-
- private void updateProfileInfo() {
- StringBuilder sb = new StringBuilder();
- sb.append("");
- sb.append(getString(R.string.nsprofileview_activeprofile_label));
- sb.append("
");
- sb.append("");
- sb.append(getString(R.string.nsprofileview_basal_label));
- sb.append(" ( ∑");
- sb.append(DecimalFormatter.to2Decimal(circadianPercentageProfilePlugin.percentageBasalSum()));
- sb.append("U )");
- sb.append("
" + circadianPercentageProfilePlugin.basalString());
- sb.append("");
- sb.append(getString(R.string.nsprofileview_ic_label));
- sb.append("
" + circadianPercentageProfilePlugin.icString());
- sb.append("");
- sb.append(getString(R.string.nsprofileview_isf_label));
- sb.append("
" + circadianPercentageProfilePlugin.isfString());
- profileView.setText(Html.fromHtml(sb.toString()));
-
- baseprofileBasal.setText(Html.fromHtml("" + getString(R.string.base_profile_label) + " ( ∑" + DecimalFormatter.to2Decimal(circadianPercentageProfilePlugin.baseBasalSum()) + "U )
" +
- "" + getString(R.string.nsprofileview_basal_label) + "
" + circadianPercentageProfilePlugin.baseBasalString()));
- baseprofileIC.setText(Html.fromHtml("" + getString(R.string.nsprofileview_ic_label) + "
" + circadianPercentageProfilePlugin.baseIcString()));
- baseprofileISF.setText(Html.fromHtml("" + getString(R.string.nsprofileview_isf_label) + "
" + circadianPercentageProfilePlugin.baseIsfString()));
- }
-
- @Override
- public void onStop() {
- super.onStop();
- if (basalEditDialog != null && basalEditDialog.isVisible()) {
- basalEditDialog.dismiss();
- }
- basalEditDialog = null;
- fl.requestFocusFromTouch();
- }
-
- public static class BasalEditDialog extends DialogFragment {
-
- private double[] values;
- private String title;
- private CircadianPercentageProfileFragment fragment;
-
- public void setup(double[] values, String title, CircadianPercentageProfileFragment fragment) {
- this.values = values;
- this.title = title;
- this.fragment = fragment;
- }
-
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- getDialog().setTitle(title);
- View view = inflater.inflate(R.layout.circadianpercentageprofile_editbasal_dialog, container, false);
- LinearLayout list = (LinearLayout) view.findViewById(R.id.circadianpp_editbasal_listlayout);
- final EditText[] editTexts = new EditText[24];
- for (int i = 0; i < 24; i++) {
- View childview = inflater.inflate(R.layout.circadianpercentageprofile_listelement, container, false);
- ((TextView) childview.findViewById(R.id.basal_time_elem)).setText((i < 10 ? "0" : "") + i + ":00: ");
-
- ImageView copyprevbutton = (ImageView) childview.findViewById(R.id.basal_copyprev_elem);
-
- if (i == 0) {
- copyprevbutton.setVisibility(View.INVISIBLE);
- } else {
- final int j = i; //needs to be final to be passed to inner class.
- copyprevbutton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- editTexts[j].setText(editTexts[j - 1].getText());
- }
- });
- }
-
- editTexts[i] = ((EditText) childview.findViewById(R.id.basal_edittext_elem));
- editTexts[i].setText(DecimalFormatter.to2Decimal(values[i]));
- list.addView(childview);
- }
- getDialog().setCancelable(true);
-
- view.findViewById(R.id.ok_button).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- for (int i = 0; i < 24; i++) {
- if (editTexts[i].getText().length() != 0) {
- values[i] = SafeParse.stringToDouble(editTexts[i].getText().toString());
- }
- }
- fragment.updateProfileInfo();
- getPlugin().storeSettings();
- dismiss();
- }
- });
-
- view.findViewById(R.id.cancel_action).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- dismiss();
- }
- });
-
- return view;
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- if (basalEditDialog != null && basalEditDialog.isVisible()) {
- basalEditDialog.dismiss();
- }
- basalEditDialog = null;
-
- fl.requestFocusFromTouch();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- onStatusEvent(new EventInitializationChanged());
- fl.requestFocusFromTouch();
- }
-
- @Subscribe
- public void onStatusEvent(final EventInitializationChanged e) {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (!ConfigBuilderPlugin.getActivePump().isInitialized() || ConfigBuilderPlugin.getActivePump().isSuspended()) {
- profileswitchButton.setVisibility(View.GONE);
- } else {
- profileswitchButton.setVisibility(View.VISIBLE);
- }
- }
- });
- }
-
- @Subscribe
- public void onStatusEvent(final EventProfileSwitchChange e) {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- updateGUI();
- }
- });
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfilePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfilePlugin.java
deleted file mode 100644
index ec9c6d1e40..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfilePlugin.java
+++ /dev/null
@@ -1,455 +0,0 @@
-package info.nightscout.androidaps.plugins.ProfileCircadianPercentage;
-
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.text.DecimalFormat;
-
-import info.nightscout.androidaps.Config;
-import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.data.ProfileStore;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.ProfileInterface;
-import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
-import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
-import info.nightscout.utils.DecimalFormatter;
-import info.nightscout.utils.NSUpload;
-import info.nightscout.utils.SP;
-import info.nightscout.utils.SafeParse;
-import info.nightscout.utils.ToastUtils;
-
-/**
- * Created by Adrian on 12.11.2016.
- * Based on SimpleProfile created by mike on 05.08.2016.
- */
-public class CircadianPercentageProfilePlugin implements PluginBase, ProfileInterface {
- public static final String SETTINGS_PREFIX = "CircadianPercentageProfile";
- private static Logger log = LoggerFactory.getLogger(CircadianPercentageProfilePlugin.class);
-
- private boolean fragmentEnabled = false;
- private boolean fragmentVisible = false;
-
- private static ProfileStore convertedProfile = null;
- private static String convertedProfileName = null;
-
- boolean mgdl;
- boolean mmol;
- Double dia;
- Double targetLow;
- Double targetHigh;
- public int percentage;
- public int timeshift;
- double[] basebasal = new double[]{1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d};
- double[] baseisf = new double[]{35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d, 35d};
- double[] baseic = new double[]{4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d, 4d};
-
- public CircadianPercentageProfilePlugin() {
- loadSettings();
- }
-
- @Override
- public String getFragmentClass() {
- return CircadianPercentageProfileFragment.class.getName();
- }
-
- @Override
- public int getType() {
- return PluginBase.PROFILE;
- }
-
- @Override
- public String getName() {
- return MainApp.instance().getString(R.string.circadian_percentage_profile);
- }
-
- @Override
- public String getNameShort() {
- String name = MainApp.sResources.getString(R.string.circadian_percentage_profile_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 == PROFILE && fragmentEnabled;
- }
-
- @Override
- public boolean isVisibleInTabs(int type) {
- return type == PROFILE && 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 == PROFILE) this.fragmentEnabled = fragmentEnabled;
- }
-
- @Override
- public void setFragmentVisible(int type, boolean fragmentVisible) {
- if (type == PROFILE) this.fragmentVisible = fragmentVisible;
- }
-
- @Override
- public int getPreferencesId() {
- return -1;
- }
-
- void storeSettings() {
- if (Config.logPrefsChange)
- log.debug("Storing settings");
- SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
- SharedPreferences.Editor editor = settings.edit();
- editor.putBoolean(SETTINGS_PREFIX + "mmol", mmol);
- editor.putBoolean(SETTINGS_PREFIX + "mgdl", mgdl);
- editor.putString(SETTINGS_PREFIX + "dia", dia.toString());
- editor.putString(SETTINGS_PREFIX + "targetlow", targetLow.toString());
- editor.putString(SETTINGS_PREFIX + "targethigh", targetHigh.toString());
- editor.putString(SETTINGS_PREFIX + "timeshift", timeshift + "");
- editor.putString(SETTINGS_PREFIX + "percentage", percentage + "");
-
-
- for (int i = 0; i < 24; i++) {
- editor.putString(SETTINGS_PREFIX + "basebasal" + i, DecimalFormatter.to2Decimal(basebasal[i]));
- editor.putString(SETTINGS_PREFIX + "baseisf" + i, DecimalFormatter.to2Decimal(baseisf[i]));
- editor.putString(SETTINGS_PREFIX + "baseic" + i, DecimalFormatter.to2Decimal(baseic[i]));
- }
- editor.commit();
- createConvertedProfile();
- }
-
- void loadSettings() {
- if (Config.logPrefsChange)
- log.debug("Loading stored settings");
-
- mgdl = SP.getBoolean(SETTINGS_PREFIX + "mgdl", true);
- mmol = SP.getBoolean(SETTINGS_PREFIX + "mmol", false);
- dia = SP.getDouble(SETTINGS_PREFIX + "dia", Constants.defaultDIA);
- targetLow = SP.getDouble(SETTINGS_PREFIX + "targetlow", 80d);
- targetHigh = SP.getDouble(SETTINGS_PREFIX + "targethigh", 120d);
- percentage = SP.getInt(SETTINGS_PREFIX + "percentage", 100);
- timeshift = SP.getInt(SETTINGS_PREFIX + "timeshift", 0);
-
- for (int i = 0; i < 24; i++) {
- basebasal[i] = SP.getDouble(SETTINGS_PREFIX + "basebasal" + i, basebasal[i]);
- baseic[i] = SP.getDouble(SETTINGS_PREFIX + "baseic" + i, baseic[i]);
- baseisf[i] = SP.getDouble(SETTINGS_PREFIX + "baseisf" + i, baseisf[i]);
- }
- }
-
- public String externallySetParameters(int timeshift, int percentage) {
-
- String msg = "";
-
- if (!fragmentEnabled) {
- msg += "NO CPP!" + "\n";
- }
-
- //check for validity
- if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
- msg += String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Percentage") + "\n";
- }
- if (timeshift < 0 || timeshift > 23) {
- msg += String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Timeshift") + "\n";
- }
- final Profile profile = MainApp.getConfigBuilder().getProfile();
-
- if (profile == null || profile.getBasal() == null) {
- msg += MainApp.sResources.getString(R.string.cpp_notloadedplugins) + "\n";
- }
- if (!"".equals(msg)) {
- msg += MainApp.sResources.getString(R.string.cpp_valuesnotstored);
- return msg;
- }
-
- //store profile
- this.timeshift = timeshift;
- this.percentage = percentage;
- storeSettings();
-
-
- //send profile to pumpe
- new NewNSTreatmentDialog(); //init
- NewNSTreatmentDialog.doProfileSwitch(this.getProfile(), this.getProfileName(), 0, percentage, timeshift);
-
- //return formatted string
- /*msg += "%: " + this.percentage + " h: +" + this.timeshift;
- msg += "\n";
- msg += "\nBasal:\n" + basalString() + "\n";
- msg += "\nISF:\n" + isfString() + "\n";
- msg += "\nIC:\n" + isfString() + "\n";*/
-
- return msg;
- }
-
- public static void migrateToLP() {
- SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
- SharedPreferences.Editor editor = settings.edit();
- editor.putBoolean("LocalProfile" + "mmol", SP.getBoolean(SETTINGS_PREFIX + "mmol", false));
- editor.putBoolean("LocalProfile" + "mgdl", SP.getBoolean(SETTINGS_PREFIX + "mgdl", true));
- editor.putString("LocalProfile" + "dia", "" + SP.getDouble(SETTINGS_PREFIX + "dia", Constants.defaultDIA));
- editor.putString("LocalProfile" + "ic", getLPic());
- editor.putString("LocalProfile" + "isf", getLPisf());
- editor.putString("LocalProfile" + "basal", getLPbasal());
- try {
- JSONArray targetLow = new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", SP.getDouble(SETTINGS_PREFIX + "targetlow", 120d)));
- JSONArray targetHigh = new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", SP.getDouble(SETTINGS_PREFIX + "targethigh", 120d)));
- editor.putString("LocalProfile" + "targetlow", targetLow.toString());
- editor.putString("LocalProfile" + "targethigh", targetHigh.toString());
- } catch (JSONException e) {
- e.printStackTrace();
- }
- editor.commit();
- LocalProfilePlugin lp = MainApp.getSpecificPlugin(LocalProfilePlugin.class);
- lp.loadSettings();
-
- /* TODO: remove Settings and switch to LP later on
- * For now only nag the user every time (s)he opens the CPP fragment and offer to migrate.
- * Keep settings for now in order to allow the user to check that the migration went well.
- */
- //removeSettings();
-
- }
-
- public static String getLPisf() {
- return getLPConversion("baseisf", 35d);
- }
-
- public static String getLPic() {
- return getLPConversion("baseic", 4);
- }
-
- public static String getLPbasal() {
- return getLPConversion("basebasal", 1);
- }
-
- public static String getLPConversion(String type, double defaultValue) {
- try {
- JSONArray jsonArray = new JSONArray();
- double last = -1d;
-
- for (int i = 0; i < 24; i++) {
- double value = SP.getDouble(SETTINGS_PREFIX + type + i, defaultValue);
- String time;
- DecimalFormat df = new DecimalFormat("00");
- time = df.format(i) + ":00";
- if (last != value) {
- jsonArray.put(new JSONObject().put("time", time).put("timeAsSeconds", i * 60 * 60).put("value", value));
- }
- last = value;
- }
- return jsonArray.toString();
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return LocalProfilePlugin.DEFAULTARRAY;
- }
-
- static void removeSettings() {
- if (Config.logPrefsChange)
- log.debug("Removing settings");
- SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
- SharedPreferences.Editor editor = settings.edit();
- editor.remove(SETTINGS_PREFIX + "mmol");
- editor.remove(SETTINGS_PREFIX + "mgdl");
- editor.remove(SETTINGS_PREFIX + "dia");
- editor.remove(SETTINGS_PREFIX + "targetlow");
- editor.remove(SETTINGS_PREFIX + "targethigh");
- editor.remove(SETTINGS_PREFIX + "timeshift");
- editor.remove(SETTINGS_PREFIX + "percentage");
-
-
- for (int i = 0; i < 24; i++) {
- editor.remove(SETTINGS_PREFIX + "basebasal");
- editor.remove(SETTINGS_PREFIX + "baseisf" + i);
- editor.remove(SETTINGS_PREFIX + "baseic" + i);
- }
- editor.commit();
- }
-
- private void createConvertedProfile() {
- JSONObject json = new JSONObject();
- JSONObject store = new JSONObject();
- JSONObject profile = new JSONObject();
-
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append(DecimalFormatter.to2Decimal(sum(basebasal)));
- stringBuilder.append("U@");
- stringBuilder.append(percentage);
- stringBuilder.append("%>");
- stringBuilder.append(timeshift);
- stringBuilder.append("h");
- String profileName = stringBuilder.toString();
-
- try {
- json.put("defaultProfile", profileName);
- json.put("store", store);
- profile.put("dia", dia);
-
- int offset = -(timeshift % 24) + 24;
-
- JSONArray icArray = new JSONArray();
- JSONArray isfArray = new JSONArray();
- JSONArray basalArray = new JSONArray();
- for (int i = 0; i < 24; i++) {
- String time;
- DecimalFormat df = new DecimalFormat("00");
- time = df.format(i) + ":00";
- icArray.put(new JSONObject().put("time", time).put("timeAsSeconds", i * 60 * 60).put("value", baseic[(offset + i) % 24] * 100d / percentage));
- isfArray.put(new JSONObject().put("time", time).put("timeAsSeconds", i * 60 * 60).put("value", baseisf[(offset + i) % 24] * 100d / percentage));
- basalArray.put(new JSONObject().put("time", time).put("timeAsSeconds", i * 60 * 60).put("value", basebasal[(offset + i) % 24] * percentage / 100d));
- }
- profile.put("carbratio", icArray);
- profile.put("sens", isfArray);
- profile.put("basal", basalArray);
-
-
- profile.put("target_low", new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", targetLow)));
- profile.put("target_high", new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", targetHigh)));
- profile.put("units", mgdl ? Constants.MGDL : Constants.MMOL);
- store.put(profileName, profile);
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- convertedProfile = new ProfileStore(json);
- convertedProfileName = profileName;
- }
-
- @Override
- public ProfileStore getProfile() {
- if (convertedProfile == null)
- createConvertedProfile();
-
- performLimitCheck();
- return convertedProfile;
- }
-
- @Override
- public String getUnits() {
- return mgdl ? Constants.MGDL : Constants.MMOL;
- }
-
- @Override
- public String getProfileName() {
- if (convertedProfile == null)
- createConvertedProfile();
-
- performLimitCheck();
- return convertedProfileName;
- }
-
- private void performLimitCheck() {
- if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
- String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Percentage");
- log.error(msg);
- NSUpload.uploadError(msg);
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
- percentage = Math.max(percentage, Constants.CPP_MIN_PERCENTAGE);
- percentage = Math.min(percentage, Constants.CPP_MAX_PERCENTAGE);
- }
- }
-
- String basalString() {
- return profileString(basebasal, timeshift, percentage, true);
- }
-
- String icString() {
- return profileString(baseic, timeshift, percentage, false);
- }
-
- String isfString() {
- return profileString(baseisf, timeshift, percentage, false);
- }
-
- String baseIcString() {
- return profileString(baseic, 0, 100, false);
- }
-
- String baseIsfString() {
- return profileString(baseisf, 0, 100, false);
- }
-
- String baseBasalString() {
- return profileString(basebasal, 0, 100, true);
- }
-
- public double baseBasalSum() {
- return sum(basebasal);
- }
-
- public double percentageBasalSum() {
- double result = 0;
- for (int i = 0; i < basebasal.length; i++) {
- result += SafeParse.stringToDouble(DecimalFormatter.to2Decimal(basebasal[i] * percentage / 100d));
- }
- return result;
- }
-
-
- public static double sum(double values[]) {
- double result = 0;
- for (int i = 0; i < values.length; i++) {
- result += values[i];
- }
- return result;
- }
-
-
- private static String profileString(double[] values, int timeshift, int percentage, boolean inc) {
- timeshift = -(timeshift % 24) + 24;
- StringBuilder sb = new StringBuilder();
- sb.append("");
- sb.append(0);
- sb.append("h: ");
- sb.append("");
- sb.append(DecimalFormatter.to2Decimal(values[(timeshift + 0) % 24] * (inc ? percentage / 100d : 100d / percentage)));
- double prevVal = values[(timeshift + 0) % 24];
- for (int i = 1; i < 24; i++) {
- if (prevVal != values[(timeshift + i) % 24]) {
- sb.append(", ");
- sb.append("");
- sb.append(i);
- sb.append("h: ");
- sb.append("");
- sb.append(DecimalFormatter.to2Decimal(values[(timeshift + i) % 24] * (inc ? percentage / 100d : 100d / percentage)));
- prevVal = values[(timeshift + i) % 24];
- }
- }
- return sb.toString();
- }
-
- public int getPercentage() {
- return percentage;
- }
-
- public int getTimeshift() {
- return timeshift;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/AbstractDanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/AbstractDanaRPlugin.java
new file mode 100644
index 0000000000..fb04b0e105
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/AbstractDanaRPlugin.java
@@ -0,0 +1,560 @@
+package info.nightscout.androidaps.plugins.PumpDanaR;
+
+import android.support.annotation.Nullable;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+
+import java.util.Date;
+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.R;
+import info.nightscout.androidaps.data.Profile;
+import info.nightscout.androidaps.data.ProfileStore;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.db.ExtendedBolus;
+import info.nightscout.androidaps.db.TemporaryBasal;
+import info.nightscout.androidaps.interfaces.ConstraintsInterface;
+import info.nightscout.androidaps.interfaces.DanaRInterface;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.ProfileInterface;
+import info.nightscout.androidaps.interfaces.PumpDescription;
+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.notifications.Notification;
+import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
+import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractDanaRExecutionService;
+import info.nightscout.utils.DateUtil;
+import info.nightscout.utils.DecimalFormatter;
+import info.nightscout.utils.Round;
+import info.nightscout.utils.SP;
+
+/**
+ * Created by mike on 28.01.2018.
+ */
+
+public abstract class AbstractDanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
+ protected Logger log;
+
+ protected boolean mPluginPumpEnabled = false;
+ protected boolean mPluginProfileEnabled = false;
+ protected boolean mFragmentPumpVisible = true;
+
+ protected AbstractDanaRExecutionService sExecutionService;
+
+ protected DanaRPump pump = DanaRPump.getInstance();
+ protected boolean useExtendedBoluses = false;
+
+ public PumpDescription pumpDescription = new PumpDescription();
+
+ @Override
+ public String getFragmentClass() {
+ return DanaRFragment.class.getName();
+ }
+
+ // Plugin base interface
+ @Override
+ public int getType() {
+ return PluginBase.PUMP;
+ }
+
+ @Override
+ public String getNameShort() {
+ String name = MainApp.sResources.getString(R.string.danarpump_shortname);
+ if (!name.trim().isEmpty()) {
+ //only if translation exists
+ return name;
+ }
+ // use long name as fallback
+ return getName();
+ }
+
+ @Override
+ public boolean isEnabled(int type) {
+ if (type == PluginBase.PROFILE) return mPluginProfileEnabled && mPluginPumpEnabled;
+ else if (type == PluginBase.PUMP) return mPluginPumpEnabled;
+ else if (type == PluginBase.CONSTRAINTS) return mPluginPumpEnabled;
+ return false;
+ }
+
+ @Override
+ public boolean isVisibleInTabs(int type) {
+ if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
+ else if (type == PluginBase.PUMP) return mFragmentPumpVisible;
+ return false;
+ }
+
+ @Override
+ public boolean canBeHidden(int type) {
+ return true;
+ }
+
+ @Override
+ public boolean hasFragment() {
+ return true;
+ }
+
+ @Override
+ public boolean showInList(int type) {
+ return type == PUMP;
+ }
+
+ @Override
+ public void setFragmentEnabled(int type, boolean fragmentEnabled) {
+ if (type == PluginBase.PROFILE)
+ mPluginProfileEnabled = fragmentEnabled;
+ else if (type == PluginBase.PUMP)
+ mPluginPumpEnabled = fragmentEnabled;
+ // if pump profile was enabled need to switch to another too
+ if (type == PluginBase.PUMP && !fragmentEnabled && mPluginProfileEnabled) {
+ setFragmentEnabled(PluginBase.PROFILE, false);
+ setFragmentVisible(PluginBase.PROFILE, false);
+ NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
+ NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
+ }
+ }
+
+ @Override
+ public void setFragmentVisible(int type, boolean fragmentVisible) {
+ if (type == PluginBase.PUMP)
+ mFragmentPumpVisible = fragmentVisible;
+ }
+
+ @Override
+ public boolean isSuspended() {
+ return pump.pumpSuspended;
+ }
+
+ @Override
+ public boolean isBusy() {
+ if (sExecutionService == null) return false;
+ return sExecutionService.isConnected() || sExecutionService.isConnecting();
+ }
+
+ // Pump interface
+ @Override
+ public PumpEnactResult setNewBasalProfile(Profile profile) {
+ PumpEnactResult result = new PumpEnactResult();
+
+ if (sExecutionService == null) {
+ log.error("setNewBasalProfile sExecutionService is null");
+ result.comment = "setNewBasalProfile sExecutionService is null";
+ return result;
+ }
+ if (!isInitialized()) {
+ log.error("setNewBasalProfile not initialized");
+ Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
+ return result;
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
+ }
+ if (!sExecutionService.updateBasalsInPump(profile)) {
+ Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
+ return result;
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
+ MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
+ Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.sResources.getString(R.string.profile_set_ok), Notification.INFO, 60);
+ MainApp.bus().post(new EventNewNotification(notification));
+ result.success = true;
+ result.enacted = true;
+ result.comment = "OK";
+ return result;
+ }
+ }
+
+ @Override
+ public boolean isThisProfileSet(Profile profile) {
+ if (!isInitialized())
+ return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
+ if (pump.pumpProfiles == null)
+ return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
+ int basalValues = pump.basal48Enable ? 48 : 24;
+ int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
+ for (int h = 0; h < basalValues; h++) {
+ Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
+ Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
+ if (profileValue == null) return true;
+ if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
+ log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Date lastDataTime() {
+ return new Date(pump.lastConnection);
+ }
+
+ @Override
+ public double getBaseBasalRate() {
+ return pump.currentBasal;
+ }
+
+ @Override
+ public void stopBolusDelivering() {
+ if (sExecutionService == null) {
+ log.error("stopBolusDelivering sExecutionService is null");
+ return;
+ }
+ sExecutionService.bolusStop();
+ }
+
+ @Override
+ public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
+ PumpEnactResult result = new PumpEnactResult();
+ ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
+ percent = configBuilderPlugin.applyBasalConstraints(percent);
+ if (percent < 0) {
+ result.isTempCancel = false;
+ result.enacted = false;
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
+ log.error("setTempBasalPercent: Invalid input");
+ return result;
+ }
+ if (percent > getPumpDescription().maxTempPercent)
+ percent = getPumpDescription().maxTempPercent;
+ TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
+ if (runningTB != null && runningTB.percentRate == percent && !enforceNew) {
+ result.enacted = false;
+ result.success = true;
+ result.isTempCancel = false;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.duration = pump.tempBasalRemainingMin;
+ result.percent = pump.tempBasalPercent;
+ result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
+ result.isPercent = true;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalPercent: Correct value already set");
+ return result;
+ }
+ int durationInHours = Math.max(durationInMinutes / 60, 1);
+ boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
+ if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) {
+ result.enacted = true;
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.isTempCancel = false;
+ result.duration = pump.tempBasalRemainingMin;
+ result.percent = pump.tempBasalPercent;
+ result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
+ result.isPercent = true;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalPercent: OK");
+ return result;
+ }
+ result.enacted = false;
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.tempbasaldeliveryerror);
+ log.error("setTempBasalPercent: Failed to set temp basal");
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
+ ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
+ insulin = configBuilderPlugin.applyBolusConstraints(insulin);
+ // needs to be rounded
+ int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
+ insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
+
+ PumpEnactResult result = new PumpEnactResult();
+ ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
+ result.enacted = false;
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.duration = pump.extendedBolusRemainingMinutes;
+ result.absolute = pump.extendedBolusAbsoluteRate;
+ result.isPercent = false;
+ result.isTempCancel = false;
+ if (Config.logPumpActions)
+ log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
+ return result;
+ }
+ boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
+ if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
+ result.enacted = true;
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.isTempCancel = false;
+ result.duration = pump.extendedBolusRemainingMinutes;
+ result.absolute = pump.extendedBolusAbsoluteRate;
+ if (! SP.getBoolean("danar_useextended", false)) result.bolusDelivered = pump.extendedBolusAmount;
+ result.isPercent = false;
+ if (Config.logPumpActions)
+ log.debug("setExtendedBolus: OK");
+ return result;
+ }
+ result.enacted = false;
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
+ log.error("setExtendedBolus: Failed to extended bolus");
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult cancelExtendedBolus() {
+ PumpEnactResult result = new PumpEnactResult();
+ ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (runningEB != null) {
+ sExecutionService.extendedBolusStop();
+ result.enacted = true;
+ result.isTempCancel = true;
+ }
+ if (!pump.isExtendedInProgress) {
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ if (Config.logPumpActions)
+ log.debug("cancelExtendedBolus: OK");
+ return result;
+ } else {
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
+ log.error("cancelExtendedBolus: Failed to cancel extended bolus");
+ return result;
+ }
+ }
+
+ @Override
+ public void connect(String from) {
+ if (sExecutionService != null) {
+ sExecutionService.connect();
+ pumpDescription.basalStep = pump.basalStep;
+ pumpDescription.bolusStep = pump.bolusStep;
+ }
+ }
+
+ @Override
+ public boolean isConnected() {
+ return sExecutionService != null && sExecutionService.isConnected();
+ }
+
+ @Override
+ public boolean isConnecting() {
+ return sExecutionService != null && sExecutionService.isConnecting();
+ }
+
+ @Override
+ public void disconnect(String from) {
+ if (sExecutionService != null) sExecutionService.disconnect(from);
+ }
+
+ @Override
+ public void stopConnecting() {
+ if (sExecutionService != null) sExecutionService.stopConnecting();
+ }
+
+ @Override
+ public void getPumpStatus() {
+ if (sExecutionService != null) sExecutionService.getPumpStatus();
+ }
+
+ @Override
+ public JSONObject getJSONStatus() {
+ if (pump.lastConnection + 5 * 60 * 1000L < System.currentTimeMillis()) {
+ return null;
+ }
+ JSONObject pumpjson = new JSONObject();
+ JSONObject battery = new JSONObject();
+ JSONObject status = new JSONObject();
+ JSONObject extended = new JSONObject();
+ try {
+ battery.put("percent", pump.batteryRemaining);
+ status.put("status", pump.pumpSuspended ? "suspended" : "normal");
+ status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
+ extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
+ extended.put("PumpIOB", pump.iob);
+ if (pump.lastBolusTime.getTime() != 0) {
+ extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
+ extended.put("LastBolusAmount", pump.lastBolusAmount);
+ }
+ TemporaryBasal tb = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
+ if (tb != null) {
+ extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
+ extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
+ extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
+ }
+ ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (eb != null) {
+ extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
+ extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
+ extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
+ }
+ extended.put("BaseBasalRate", getBaseBasalRate());
+ try {
+ extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
+ } catch (Exception e) {
+ }
+
+ pumpjson.put("battery", battery);
+ pumpjson.put("status", status);
+ pumpjson.put("extended", extended);
+ pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
+ pumpjson.put("clock", DateUtil.toISOString(new Date()));
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ return pumpjson;
+ }
+
+ @Override
+ public String deviceID() {
+ return pump.serialNumber;
+ }
+
+ @Override
+ public PumpDescription getPumpDescription() {
+ return pumpDescription;
+ }
+
+ /**
+ * DanaR interface
+ */
+
+ @Override
+ public PumpEnactResult loadHistory(byte type) {
+ return sExecutionService.loadHistory(type);
+ }
+
+ /**
+ * Constraint interface
+ */
+
+ @Override
+ public boolean isLoopEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isClosedModeEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isAutosensModeEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isAMAModeEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isSMBModeEnabled() {
+ return true;
+ }
+
+ @SuppressWarnings("PointlessBooleanExpression")
+ @Override
+ public Double applyBasalConstraints(Double absoluteRate) {
+ double origAbsoluteRate = absoluteRate;
+ if (pump != null) {
+ if (absoluteRate > pump.maxBasal) {
+ absoluteRate = pump.maxBasal;
+ if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
+ log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
+ }
+ }
+ return absoluteRate;
+ }
+
+ @SuppressWarnings("PointlessBooleanExpression")
+ @Override
+ public Integer applyBasalConstraints(Integer percentRate) {
+ Integer origPercentRate = percentRate;
+ if (percentRate < 0) percentRate = 0;
+ if (percentRate > getPumpDescription().maxTempPercent)
+ percentRate = getPumpDescription().maxTempPercent;
+ if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
+ log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
+ return percentRate;
+ }
+
+ @SuppressWarnings("PointlessBooleanExpression")
+ @Override
+ public Double applyBolusConstraints(Double insulin) {
+ double origInsulin = insulin;
+ if (pump != null) {
+ if (insulin > pump.maxBolus) {
+ insulin = pump.maxBolus;
+ if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
+ log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
+ }
+ }
+ return insulin;
+ }
+
+ @Override
+ public Integer applyCarbsConstraints(Integer carbs) {
+ return carbs;
+ }
+
+ @Override
+ public Double applyMaxIOBConstraints(Double maxIob) {
+ return maxIob;
+ }
+
+ @Nullable
+ @Override
+ public ProfileStore getProfile() {
+ if (pump.lastSettingsRead == 0)
+ return null; // no info now
+ return pump.createConvertedProfile();
+ }
+
+ @Override
+ public String getUnits() {
+ return pump.getUnits();
+ }
+
+ @Override
+ public String getProfileName() {
+ return pump.createConvertedProfileName();
+ }
+
+ // Reply for sms communicator
+ public String shortStatus(boolean veryShort) {
+ String ret = "";
+ if (pump.lastConnection != 0) {
+ Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
+ int agoMin = (int) (agoMsec / 60d / 1000d);
+ ret += "LastConn: " + agoMin + " minago\n";
+ }
+ if (pump.lastBolusTime.getTime() != 0) {
+ ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
+ }
+ TemporaryBasal activeTemp = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
+ if (activeTemp != null) {
+ ret += "Temp: " + activeTemp.toStringFull() + "\n";
+ }
+ ExtendedBolus activeExtendedBolus = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (activeExtendedBolus != null) {
+ ret += "Extended: " + activeExtendedBolus.toString() + "\n";
+ }
+ if (!veryShort) {
+ ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
+ }
+ ret += "IOB: " + pump.iob + "U\n";
+ ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
+ ret += "Batt: " + pump.batteryRemaining + "\n";
+ return ret;
+ }
+ // TODO: daily total constraint
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/BluetoothDevicePreference.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/BluetoothDevicePreference.java
index 63e14f0921..e39fdcfdaa 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/BluetoothDevicePreference.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/BluetoothDevicePreference.java
@@ -6,6 +6,7 @@ import android.preference.ListPreference;
import android.util.AttributeSet;
import java.util.Set;
+import java.util.Vector;
public class BluetoothDevicePreference extends ListPreference {
@@ -13,25 +14,22 @@ public class BluetoothDevicePreference extends ListPreference {
super(context, attrs);
BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
- Integer size = 0;
- if (bta != null) {
- size += bta.getBondedDevices().size();
- }
- CharSequence[] entries = new CharSequence[size];
- int i = 0;
+ Vector entries = new Vector();
if (bta != null) {
Set pairedDevices = bta.getBondedDevices();
for (BluetoothDevice dev : pairedDevices) {
- entries[i] = dev.getName();
- i++;
+ String name = dev.getName();
+ if(name != null) {
+ entries.add(name);
+ }
}
}
- setEntries(entries);
- setEntryValues(entries);
+ setEntries(entries.toArray(new CharSequence[0]));
+ setEntryValues(entries.toArray(new CharSequence[0]));
}
public BluetoothDevicePreference(Context context) {
this(context, null);
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java
index 8ac6bb306b..2ca5788aba 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java
@@ -21,8 +21,15 @@ import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Date;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.events.EventTempBasalChange;
@@ -49,27 +56,24 @@ public class DanaRFragment extends SubscriberFragment {
}
};
- TextView lastConnectionView;
- TextView btConnectionView;
- TextView lastBolusView;
- TextView dailyUnitsView;
- TextView basaBasalRateView;
- TextView tempBasalView;
- TextView extendedBolusView;
- TextView batteryView;
- TextView reservoirView;
- TextView iobView;
- TextView firmwareView;
- TextView basalStepView;
- TextView bolusStepView;
- TextView serialNumberView;
- TextView queueView;
- Button viewProfileButton;
- Button historyButton;
- Button statsButton;
+ @BindView(R.id.danar_lastconnection) TextView lastConnectionView;
+ @BindView(R.id.danar_btconnection) TextView btConnectionView;
+ @BindView(R.id.danar_lastbolus) TextView lastBolusView;
+ @BindView(R.id.danar_dailyunits) TextView dailyUnitsView;
+ @BindView(R.id.danar_basabasalrate) TextView basaBasalRateView;
+ @BindView(R.id.danar_tempbasal) TextView tempBasalView;
+ @BindView(R.id.danar_extendedbolus) TextView extendedBolusView;
+ @BindView(R.id.danar_battery) TextView batteryView;
+ @BindView(R.id.danar_reservoir) TextView reservoirView;
+ @BindView(R.id.danar_iob) TextView iobView;
+ @BindView(R.id.danar_firmware) TextView firmwareView;
+ @BindView(R.id.danar_basalstep) TextView basalStepView;
+ @BindView(R.id.danar_bolusstep) TextView bolusStepView;
+ @BindView(R.id.danar_serialnumber) TextView serialNumberView;
+ @BindView(R.id.danar_queue) TextView queueView;
- LinearLayout pumpStatusLayout;
- TextView pumpStatusView;
+ @BindView(R.id.overview_pumpstatuslayout) LinearLayout pumpStatusLayout;
+ @BindView(R.id.overview_pumpstatus) TextView pumpStatusView;
public DanaRFragment() {
}
@@ -91,61 +95,10 @@ public class DanaRFragment extends SubscriberFragment {
Bundle savedInstanceState) {
try {
View view = inflater.inflate(R.layout.danar_fragment, container, false);
- btConnectionView = (TextView) view.findViewById(R.id.danar_btconnection);
- lastConnectionView = (TextView) view.findViewById(R.id.danar_lastconnection);
- lastBolusView = (TextView) view.findViewById(R.id.danar_lastbolus);
- dailyUnitsView = (TextView) view.findViewById(R.id.danar_dailyunits);
- basaBasalRateView = (TextView) view.findViewById(R.id.danar_basabasalrate);
- tempBasalView = (TextView) view.findViewById(R.id.danar_tempbasal);
- extendedBolusView = (TextView) view.findViewById(R.id.danar_extendedbolus);
- batteryView = (TextView) view.findViewById(R.id.danar_battery);
- reservoirView = (TextView) view.findViewById(R.id.danar_reservoir);
- iobView = (TextView) view.findViewById(R.id.danar_iob);
- firmwareView = (TextView) view.findViewById(R.id.danar_firmware);
- viewProfileButton = (Button) view.findViewById(R.id.danar_viewprofile);
- historyButton = (Button) view.findViewById(R.id.danar_history);
- statsButton = (Button) view.findViewById(R.id.danar_stats);
- basalStepView = (TextView) view.findViewById(R.id.danar_basalstep);
- bolusStepView = (TextView) view.findViewById(R.id.danar_bolusstep);
- serialNumberView = (TextView) view.findViewById(R.id.danar_serialnumber);
- queueView = (TextView) view.findViewById(R.id.danar_queue);
+ unbinder = ButterKnife.bind(this, view);
- pumpStatusView = (TextView) view.findViewById(R.id.overview_pumpstatus);
pumpStatusView.setBackgroundColor(MainApp.sResources.getColor(R.color.colorInitializingBorder));
- pumpStatusLayout = (LinearLayout) view.findViewById(R.id.overview_pumpstatuslayout);
- viewProfileButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- FragmentManager manager = getFragmentManager();
- ProfileViewDialog profileViewDialog = new ProfileViewDialog();
- profileViewDialog.show(manager, "ProfileViewDialog");
- }
- });
-
- historyButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
- }
- });
-
- statsButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startActivity(new Intent(getContext(), DanaRStatsActivity.class));
- }
- });
-
- btConnectionView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- log.debug("Clicked connect to pump");
- ConfigBuilderPlugin.getCommandQueue().readStatus("Clicked connect to pump", null);
- }
- });
-
- updateGUI();
return view;
} catch (Exception e) {
Crashlytics.logException(e);
@@ -154,6 +107,26 @@ public class DanaRFragment extends SubscriberFragment {
return null;
}
+ @OnClick(R.id.danar_history) void onHistoryClick() {
+ startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
+ }
+
+ @OnClick(R.id.danar_viewprofile) void onViewProfileClick() {
+ FragmentManager manager = getFragmentManager();
+ ProfileViewDialog profileViewDialog = new ProfileViewDialog();
+ profileViewDialog.show(manager, "ProfileViewDialog");
+ }
+
+ @OnClick(R.id.danar_stats) void onStatsClick() {
+ startActivity(new Intent(getContext(), DanaRStatsActivity.class));
+ }
+
+ @OnClick(R.id.danar_btconnection) void onBtConnectionClick() {
+ log.debug("Clicked connect to pump");
+ DanaRPump.getInstance().lastConnection = 0;
+ ConfigBuilderPlugin.getCommandQueue().readStatus("Clicked connect to pump", null);
+ }
+
@Subscribe
public void onStatusEvent(final EventPumpStatusChanged c) {
Activity activity = getActivity();
@@ -212,8 +185,8 @@ public class DanaRFragment extends SubscriberFragment {
@Override
public void run() {
DanaRPump pump = DanaRPump.getInstance();
- if (pump.lastConnection.getTime() != 0) {
- Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
+ if (pump.lastConnection != 0) {
+ Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
int agoMin = (int) (agoMsec / 60d / 1000d);
lastConnectionView.setText(DateUtil.timeString(pump.lastConnection) + " (" + String.format(MainApp.sResources.getString(R.string.minago), agoMin) + ")");
SetWarnColor.setColor(lastConnectionView, agoMin, 16d, 31d);
@@ -244,8 +217,9 @@ public class DanaRFragment extends SubscriberFragment {
tempBasalView.setText("");
}
}
- if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
- extendedBolusView.setText(MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString());
+ ExtendedBolus activeExtendedBolus = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (activeExtendedBolus != null) {
+ extendedBolusView.setText(activeExtendedBolus.toString());
} else {
extendedBolusView.setText("");
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java
index 4ba660db66..289e10c518 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java
@@ -5,69 +5,30 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
-import android.support.annotation.Nullable;
import com.squareup.otto.Subscribe;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Date;
-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.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.PumpEnactResult;
-import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.interfaces.ConstraintsInterface;
-import info.nightscout.androidaps.interfaces.DanaRInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
-import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.data.ProfileStore;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
-import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
-import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService;
-import info.nightscout.utils.DateUtil;
-import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
/**
* Created by mike on 05.08.2016.
*/
-public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
- private static Logger log = LoggerFactory.getLogger(DanaRPlugin.class);
-
- @Override
- public String getFragmentClass() {
- return DanaRFragment.class.getName();
- }
-
- private static boolean fragmentPumpEnabled = false;
- private static boolean fragmentProfileEnabled = false;
- private static boolean fragmentPumpVisible = true;
-
- private static DanaRExecutionService sExecutionService;
-
-
- private static DanaRPump pump = DanaRPump.getInstance();
- private static boolean useExtendedBoluses = false;
+public class DanaRPlugin extends AbstractDanaRPlugin {
private static DanaRPlugin plugin = null;
@@ -77,9 +38,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
return plugin;
}
- public static PumpDescription pumpDescription = new PumpDescription();
-
public DanaRPlugin() {
+ log = LoggerFactory.getLogger(DanaRPlugin.class);
useExtendedBoluses = SP.getBoolean("danar_useextended", false);
Context context = MainApp.instance().getApplicationContext();
@@ -110,6 +70,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
pumpDescription.basalMinimumRate = 0.04d;
pumpDescription.isRefillingCapable = true;
+
+ pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@@ -145,83 +107,17 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
}
// Plugin base interface
- @Override
- public int getType() {
- return PluginBase.PUMP;
- }
-
@Override
public String getName() {
return MainApp.instance().getString(R.string.danarpump);
}
- @Override
- public String getNameShort() {
- String name = MainApp.sResources.getString(R.string.danarpump_shortname);
- if (!name.trim().isEmpty()) {
- //only if translation exists
- return name;
- }
- // use long name as fallback
- return getName();
- }
-
- @Override
- public boolean isEnabled(int type) {
- if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
- else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
- else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
- return false;
- }
-
- @Override
- public boolean isVisibleInTabs(int type) {
- if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
- else if (type == PluginBase.PUMP) return fragmentPumpVisible;
- return false;
- }
-
- @Override
- public boolean canBeHidden(int type) {
- return true;
- }
-
- @Override
- public boolean hasFragment() {
- return true;
- }
-
- @Override
- public boolean showInList(int type) {
- return type == PUMP;
- }
-
- @Override
- public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- if (type == PluginBase.PROFILE)
- fragmentProfileEnabled = fragmentEnabled;
- else if (type == PluginBase.PUMP)
- fragmentPumpEnabled = fragmentEnabled;
- // if pump profile was enabled need to switch to another too
- if (type == PluginBase.PUMP && !fragmentEnabled && fragmentProfileEnabled) {
- setFragmentEnabled(PluginBase.PROFILE, false);
- setFragmentVisible(PluginBase.PROFILE, false);
- NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
- NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
- }
- }
-
- @Override
- public void setFragmentVisible(int type, boolean fragmentVisible) {
- if (type == PluginBase.PUMP)
- fragmentPumpVisible = fragmentVisible;
- }
-
@Override
public int getPreferencesId() {
return R.xml.pref_danar;
}
+ // Pump interface
@Override
public boolean isFakingTempsByExtendedBoluses() {
return useExtendedBoluses;
@@ -229,82 +125,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
@Override
public boolean isInitialized() {
- return pump.lastConnection.getTime() > 0 && pump.isExtendedBolusEnabled && pump.maxBasal > 0;
- }
-
- @Override
- public boolean isSuspended() {
- return pump.pumpSuspended;
- }
-
- @Override
- public boolean isBusy() {
- if (sExecutionService == null) return false;
- return sExecutionService.isConnected() || sExecutionService.isConnecting();
- }
-
- // Pump interface
- @Override
- public PumpEnactResult setNewBasalProfile(Profile profile) {
- PumpEnactResult result = new PumpEnactResult();
-
- if (sExecutionService == null) {
- log.error("setNewBasalProfile sExecutionService is null");
- result.comment = "setNewBasalProfile sExecutionService is null";
- return result;
- }
- if (!isInitialized()) {
- log.error("setNewBasalProfile not initialized");
- Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
- MainApp.bus().post(new EventNewNotification(notification));
- result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
- return result;
- } else {
- MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
- }
- if (!sExecutionService.updateBasalsInPump(profile)) {
- Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
- MainApp.bus().post(new EventNewNotification(notification));
- result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
- return result;
- } else {
- MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
- MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
- result.success = true;
- result.enacted = true;
- result.comment = "OK";
- return result;
- }
- }
-
- @Override
- public boolean isThisProfileSet(Profile profile) {
- if (!isInitialized())
- return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
- if (pump.pumpProfiles == null)
- return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
- int basalValues = pump.basal48Enable ? 48 : 24;
- int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
- for (int h = 0; h < basalValues; h++) {
- Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
- Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
- if (profileValue == null) return true;
- if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
- log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Date lastDataTime() {
- return pump.lastConnection;
- }
-
- @Override
- public double getBaseBasalRate() {
- return pump.currentBasal;
+ return pump.lastConnection > 0 && pump.isExtendedBolusEnabled && pump.maxBasal > 0;
}
@Override
@@ -313,8 +134,9 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
detailedBolusInfo.insulin = configBuilderPlugin.applyBolusConstraints(detailedBolusInfo.insulin);
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
Treatment t = new Treatment();
+ t.isSMB = detailedBolusInfo.isSMB;
boolean connectionOK = false;
- if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, t);
+ if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, detailedBolusInfo.carbTime, t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@@ -337,15 +159,6 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
}
}
- @Override
- public void stopBolusDelivering() {
- if (sExecutionService == null) {
- log.error("stopBolusDelivering sExecutionService is null");
- return;
- }
- sExecutionService.bolusStop();
- }
-
// This is called from APS
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) {
@@ -498,107 +311,12 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
return result;
}
- @Override
- public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
- PumpEnactResult result = new PumpEnactResult();
- ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
- percent = configBuilderPlugin.applyBasalConstraints(percent);
- if (percent < 0) {
- result.isTempCancel = false;
- result.enacted = false;
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
- log.error("setTempBasalPercent: Invalid input");
- return result;
- }
- if (percent > getPumpDescription().maxTempPercent)
- percent = getPumpDescription().maxTempPercent;
- TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
- if (runningTB != null && runningTB.percentRate == percent && !enforceNew) {
- result.enacted = false;
- result.success = true;
- result.isTempCancel = false;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.duration = pump.tempBasalRemainingMin;
- result.percent = pump.tempBasalPercent;
- result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
- result.isPercent = true;
- if (Config.logPumpActions)
- log.debug("setTempBasalPercent: Correct value already set");
- return result;
- }
- int durationInHours = Math.max(durationInMinutes / 60, 1);
- boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
- if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) {
- result.enacted = true;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.isTempCancel = false;
- result.duration = pump.tempBasalRemainingMin;
- result.percent = pump.tempBasalPercent;
- result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
- result.isPercent = true;
- if (Config.logPumpActions)
- log.debug("setTempBasalPercent: OK");
- return result;
- }
- result.enacted = false;
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.tempbasaldeliveryerror);
- log.error("setTempBasalPercent: Failed to set temp basal");
- return result;
- }
-
- @Override
- public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
- ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
- insulin = configBuilderPlugin.applyBolusConstraints(insulin);
- // needs to be rounded
- int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
- insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
-
- PumpEnactResult result = new PumpEnactResult();
- ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
- result.enacted = false;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.duration = pump.extendedBolusRemainingMinutes;
- result.absolute = pump.extendedBolusAbsoluteRate;
- result.isPercent = false;
- result.isTempCancel = false;
- if (Config.logPumpActions)
- log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
- return result;
- }
- boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
- if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
- result.enacted = true;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.isTempCancel = false;
- result.duration = pump.extendedBolusRemainingMinutes;
- result.absolute = pump.extendedBolusAbsoluteRate;
- result.bolusDelivered = pump.extendedBolusAmount;
- result.isPercent = false;
- if (Config.logPumpActions)
- log.debug("setExtendedBolus: OK");
- return result;
- }
- result.enacted = false;
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
- log.error("setExtendedBolus: Failed to extended bolus");
- return result;
- }
-
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress())
return cancelRealTempBasal();
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress() && useExtendedBoluses) {
- PumpEnactResult cancelEx = cancelExtendedBolus();
- return cancelEx;
+ return cancelExtendedBolus();
}
PumpEnactResult result = new PumpEnactResult();
result.success = true;
@@ -632,257 +350,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
}
}
- @Override
- public PumpEnactResult cancelExtendedBolus() {
- PumpEnactResult result = new PumpEnactResult();
- ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (runningEB != null) {
- sExecutionService.extendedBolusStop();
- result.enacted = true;
- result.isTempCancel = true;
- }
- if (!pump.isExtendedInProgress) {
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- if (Config.logPumpActions)
- log.debug("cancelExtendedBolus: OK");
- return result;
- } else {
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
- log.error("cancelExtendedBolus: Failed to cancel extended bolus");
- return result;
- }
- }
-
- @Override
- public void connect(String from) {
- if (sExecutionService != null) {
- sExecutionService.connect(from);
- pumpDescription.basalStep = pump.basalStep;
- pumpDescription.bolusStep = pump.bolusStep;
- }
- }
-
- @Override
- public boolean isConnected() {
- return sExecutionService != null && sExecutionService.isConnected();
- }
-
- @Override
- public boolean isConnecting() {
- return sExecutionService != null && sExecutionService.isConnecting();
- }
-
- @Override
- public void disconnect(String from) {
- if (sExecutionService != null) sExecutionService.disconnect(from);
- }
-
- @Override
- public void stopConnecting() {
- if (sExecutionService != null) sExecutionService.stopConnecting();
- }
-
- @Override
- public void getPumpStatus() {
- if (sExecutionService != null) sExecutionService.getPumpStatus();
- }
-
- @Override
- public JSONObject getJSONStatus() {
- if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
- return null;
- }
- JSONObject pumpjson = new JSONObject();
- JSONObject battery = new JSONObject();
- JSONObject status = new JSONObject();
- JSONObject extended = new JSONObject();
- try {
- battery.put("percent", pump.batteryRemaining);
- status.put("status", pump.pumpSuspended ? "suspended" : "normal");
- status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
- extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
- extended.put("PumpIOB", pump.iob);
- if (pump.lastBolusTime.getTime() != 0) {
- extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
- extended.put("LastBolusAmount", pump.lastBolusAmount);
- }
- TemporaryBasal tb = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
- if (tb != null) {
- extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
- extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
- extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
- }
- ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (eb != null) {
- extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
- extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
- extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
- }
- extended.put("BaseBasalRate", getBaseBasalRate());
- try {
- extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
- } catch (Exception e) {
- }
-
- pumpjson.put("battery", battery);
- pumpjson.put("status", status);
- pumpjson.put("extended", extended);
- pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
- pumpjson.put("clock", DateUtil.toISOString(new Date()));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return pumpjson;
- }
-
- @Override
- public String deviceID() {
- return pump.serialNumber;
- }
-
- @Override
- public PumpDescription getPumpDescription() {
- return pumpDescription;
- }
-
- /**
- * DanaR interface
- */
-
- @Override
- public PumpEnactResult loadHistory(byte type) {
- return sExecutionService.loadHistory(type);
- }
-
@Override
public PumpEnactResult loadEvents() {
return null; // no history, not needed
}
-
- /**
- * Constraint interface
- */
-
- @Override
- public boolean isLoopEnabled() {
- return true;
- }
-
- @Override
- public boolean isClosedModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isAutosensModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isAMAModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isSMBModeEnabled() {
- return true;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Double applyBasalConstraints(Double absoluteRate) {
- double origAbsoluteRate = absoluteRate;
- if (pump != null) {
- if (absoluteRate > pump.maxBasal) {
- absoluteRate = pump.maxBasal;
- if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
- log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
- }
- }
- return absoluteRate;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Integer applyBasalConstraints(Integer percentRate) {
- Integer origPercentRate = percentRate;
- if (percentRate < 0) percentRate = 0;
- if (percentRate > getPumpDescription().maxTempPercent)
- percentRate = getPumpDescription().maxTempPercent;
- if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
- log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
- return percentRate;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Double applyBolusConstraints(Double insulin) {
- double origInsulin = insulin;
- if (pump != null) {
- if (insulin > pump.maxBolus) {
- insulin = pump.maxBolus;
- if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
- log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
- }
- }
- return insulin;
- }
-
- @Override
- public Integer applyCarbsConstraints(Integer carbs) {
- return carbs;
- }
-
- @Override
- public Double applyMaxIOBConstraints(Double maxIob) {
- return maxIob;
- }
-
- @Nullable
- @Override
- public ProfileStore getProfile() {
- if (pump.lastSettingsRead.getTime() == 0)
- return null; // no info now
- return pump.createConvertedProfile();
- }
-
- @Override
- public String getUnits() {
- return pump.getUnits();
- }
-
- @Override
- public String getProfileName() {
- return pump.createConvertedProfileName();
- }
-
- // Reply for sms communicator
- public String shortStatus(boolean veryShort) {
- String ret = "";
- if (pump.lastConnection.getTime() != 0) {
- Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
- int agoMin = (int) (agoMsec / 60d / 1000d);
- ret += "LastConn: " + agoMin + " minago\n";
- }
- if (pump.lastBolusTime.getTime() != 0) {
- ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
- }
- if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
- ret += "Temp: " + MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
- }
- if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
- ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
- }
- if (!veryShort) {
- ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
- }
- ret += "IOB: " + pump.iob + "U\n";
- ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
- ret += "Batt: " + pump.batteryRemaining + "\n";
- return ret;
- }
- // TODO: daily total constraint
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java
index 9f88011c96..0e1a9ceb75 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java
@@ -56,8 +56,8 @@ public class DanaRPump {
public static final int CARBS = 14;
public static final int PRIMECANNULA = 15;
- public Date lastConnection = new Date(0);
- public Date lastSettingsRead = new Date(0);
+ public long lastConnection = 0;
+ public long lastSettingsRead =0;
// Info
public String serialNumber = "";
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/SerialIOThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/SerialIOThread.java
index a333faecea..2f377a566a 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/SerialIOThread.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/SerialIOThread.java
@@ -13,12 +13,13 @@ import java.io.OutputStream;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageHashTable;
+import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractSerialIOThread;
import info.nightscout.utils.CRC;
/**
* Created by mike on 17.07.2016.
*/
-public class SerialIOThread extends Thread {
+public class SerialIOThread extends AbstractSerialIOThread {
private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
private InputStream mInputStream = null;
@@ -28,10 +29,10 @@ public class SerialIOThread extends Thread {
private boolean mKeepRunning = true;
private byte[] mReadBuff = new byte[0];
- MessageBase processedMessage;
+ private MessageBase processedMessage;
public SerialIOThread(BluetoothSocket rfcommSocket) {
- super(SerialIOThread.class.toString());
+ super();
mRfCommSocket = rfcommSocket;
try {
@@ -137,6 +138,7 @@ public class SerialIOThread extends Thread {
}
}
+ @Override
public synchronized void sendMessage(MessageBase message) {
if (!mRfCommSocket.isConnected()) {
log.error("Socket not connected on sendMessage");
@@ -172,6 +174,7 @@ public class SerialIOThread extends Thread {
}
}
+ @Override
public void disconnect(String reason) {
mKeepRunning = false;
try {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgInitConnStatusTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgInitConnStatusTime.java
index 17f90a1ba7..fe0d280113 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgInitConnStatusTime.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgInitConnStatusTime.java
@@ -35,8 +35,8 @@ public class MsgInitConnStatusTime extends MessageBase {
MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).setFragmentVisible(PluginBase.PUMP, true);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentEnabled(PluginBase.PUMP, false);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentVisible(PluginBase.PUMP, false);
- DanaRPump.getInstance().lastConnection = new Date(0); // mark not initialized
+ DanaRPump.getInstance().lastConnection = 0; // mark not initialized
//If profile coming from pump, switch it as well
if(MainApp.getSpecificPlugin(DanaRPlugin.class).isEnabled(PluginBase.PROFILE)){
(MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentEnabled(PluginBase.PROFILE, false);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingBasal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingBasal.java
index e1a7e45315..a47803c1b0 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingBasal.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingBasal.java
@@ -23,7 +23,7 @@ public class MsgSettingBasal extends MessageBase {
pump.pumpProfiles[pump.activeProfile] = new double[24];
for (int index = 0; index < 24; index++) {
int basal = intFromBuff(bytes, 2 * index, 2);
- if (basal < DanaRPlugin.pumpDescription.basalMinimumRate) basal = 0;
+ if (basal < DanaRPlugin.getPlugin().pumpDescription.basalMinimumRate) basal = 0;
pump.pumpProfiles[pump.activeProfile][index] = basal / 100d;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java
index 2d54d4f4a2..5d7b4b65ac 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java
@@ -6,10 +6,12 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
+import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
+import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
/**
* Created by mike on 13.12.2016.
@@ -40,6 +42,11 @@ public class MsgSettingMeal extends MessageBase {
log.debug("Is Config U/d: " + pump.isConfigUD);
}
+ // DanaRKorean is not possible to set to 0.01 but it works when controlled from AAPS
+ if (DanaRKoreanPlugin.getPlugin().isEnabled(PluginBase.PUMP)) {
+ pump.basalStep = 0.01d;
+ }
+
if (pump.basalStep != 0.01d) {
Notification notification = new Notification(Notification.WRONGBASALSTEP, MainApp.sResources.getString(R.string.danar_setbasalstep001), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBolusExtended.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBolusExtended.java
index 256ccc18da..c97340f44b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBolusExtended.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBolusExtended.java
@@ -69,8 +69,8 @@ public class MsgStatusBolusExtended extends MessageBase {
DanaRPump pump = DanaRPump.getInstance();
long now = System.currentTimeMillis();
- if (treatmentsInterface.isInHistoryExtendedBoluslInProgress()) {
- ExtendedBolus extendedBolus = treatmentsInterface.getExtendedBolusFromHistory(System.currentTimeMillis());
+ ExtendedBolus extendedBolus = treatmentsInterface.getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (extendedBolus != null) {
if (pump.isExtendedInProgress) {
if (extendedBolus.absoluteRate() != pump.extendedBolusAbsoluteRate) {
// Close current extended
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/AbstractDanaRExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/AbstractDanaRExecutionService.java
new file mode 100644
index 0000000000..d853c9abf1
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/AbstractDanaRExecutionService.java
@@ -0,0 +1,225 @@
+package info.nightscout.androidaps.plugins.PumpDanaR.services;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.SystemClock;
+
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.UUID;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.Profile;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.events.EventPumpStatusChanged;
+import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
+import info.nightscout.androidaps.plugins.PumpDanaR.SerialIOThread;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryAlarm;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBasalHour;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBolus;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryCarbo;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDailyInsulin;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDone;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryError;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryGlucose;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryRefill;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistorySuspend;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStart;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStop;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
+import info.nightscout.utils.SP;
+import info.nightscout.utils.ToastUtils;
+
+/**
+ * Created by mike on 28.01.2018.
+ */
+
+public abstract class AbstractDanaRExecutionService extends Service {
+ protected Logger log;
+
+ protected String mDevName;
+
+ protected BluetoothSocket mRfcommSocket;
+ protected BluetoothDevice mBTDevice;
+
+ protected DanaRPump mDanaRPump = DanaRPump.getInstance();
+ protected Treatment mBolusingTreatment = null;
+
+ protected Boolean mConnectionInProgress = false;
+
+ protected AbstractSerialIOThread mSerialIOThread;
+
+ protected IBinder mBinder;
+
+ protected final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
+
+ public abstract boolean updateBasalsInPump(final Profile profile);
+
+ public abstract void connect();
+
+ public abstract void getPumpStatus();
+
+ public abstract PumpEnactResult loadEvents();
+
+ public abstract boolean bolus(double amount, int carbs, long carbtime, final Treatment t);
+
+ public abstract boolean highTempBasal(int percent); // Rv2 only
+
+ public abstract boolean tempBasal(int percent, int durationInHours);
+
+ public abstract boolean tempBasalStop();
+
+ public abstract boolean extendedBolus(double insulin, int durationInHalfHours);
+
+ public abstract boolean extendedBolusStop();
+
+
+ protected BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ String action = intent.getAction();
+ if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
+ log.debug("Device was disconnected " + device.getName());//Device was disconnected
+ if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
+ if (mSerialIOThread != null) {
+ mSerialIOThread.disconnect("BT disconnection broadcast");
+ }
+ MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
+ }
+ }
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ return START_STICKY;
+ }
+
+ public boolean isConnected() {
+ return mRfcommSocket != null && mRfcommSocket.isConnected();
+ }
+
+ public boolean isConnecting() {
+ return mConnectionInProgress;
+ }
+
+ public void disconnect(String from) {
+ if (mSerialIOThread != null)
+ mSerialIOThread.disconnect(from);
+ }
+
+ public void stopConnecting() {
+ if (mSerialIOThread != null)
+ mSerialIOThread.disconnect("stopConnecting");
+ }
+
+ protected void getBTSocketForSelectedPump() {
+ mDevName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ if (bluetoothAdapter != null) {
+ Set bondedDevices = bluetoothAdapter.getBondedDevices();
+
+ for (BluetoothDevice device : bondedDevices) {
+ if (mDevName.equals(device.getName())) {
+ mBTDevice = device;
+ try {
+ mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
+ } catch (IOException e) {
+ log.error("Error creating socket: ", e);
+ }
+ break;
+ }
+ }
+ } else {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
+ }
+ if (mBTDevice == null) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
+ }
+ }
+
+ public void bolusStop() {
+ if (Config.logDanaBTComm)
+ log.debug("bolusStop >>>>> @ " + (mBolusingTreatment == null ? "" : mBolusingTreatment.insulin));
+ MsgBolusStop stop = new MsgBolusStop();
+ stop.forced = true;
+ if (isConnected()) {
+ mSerialIOThread.sendMessage(stop);
+ while (!stop.stopped) {
+ mSerialIOThread.sendMessage(stop);
+ SystemClock.sleep(200);
+ }
+ } else {
+ stop.stopped = true;
+ }
+ }
+
+ public PumpEnactResult loadHistory(byte type) {
+ PumpEnactResult result = new PumpEnactResult();
+ if (!isConnected()) return result;
+ MessageBase msg = null;
+ switch (type) {
+ case RecordTypes.RECORD_TYPE_ALARM:
+ msg = new MsgHistoryAlarm();
+ break;
+ case RecordTypes.RECORD_TYPE_BASALHOUR:
+ msg = new MsgHistoryBasalHour();
+ break;
+ case RecordTypes.RECORD_TYPE_BOLUS:
+ msg = new MsgHistoryBolus();
+ break;
+ case RecordTypes.RECORD_TYPE_CARBO:
+ msg = new MsgHistoryCarbo();
+ break;
+ case RecordTypes.RECORD_TYPE_DAILY:
+ msg = new MsgHistoryDailyInsulin();
+ break;
+ case RecordTypes.RECORD_TYPE_ERROR:
+ msg = new MsgHistoryError();
+ break;
+ case RecordTypes.RECORD_TYPE_GLUCOSE:
+ msg = new MsgHistoryGlucose();
+ break;
+ case RecordTypes.RECORD_TYPE_REFILL:
+ msg = new MsgHistoryRefill();
+ break;
+ case RecordTypes.RECORD_TYPE_SUSPEND:
+ msg = new MsgHistorySuspend();
+ break;
+ }
+ MsgHistoryDone done = new MsgHistoryDone();
+ mSerialIOThread.sendMessage(new MsgPCCommStart());
+ SystemClock.sleep(400);
+ mSerialIOThread.sendMessage(msg);
+ while (!done.received && mRfcommSocket.isConnected()) {
+ SystemClock.sleep(100);
+ }
+ SystemClock.sleep(200);
+ mSerialIOThread.sendMessage(new MsgPCCommStop());
+ result.success = true;
+ result.comment = "OK";
+ return result;
+ }
+
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/AbstractSerialIOThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/AbstractSerialIOThread.java
new file mode 100644
index 0000000000..1cca0b2512
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/AbstractSerialIOThread.java
@@ -0,0 +1,13 @@
+package info.nightscout.androidaps.plugins.PumpDanaR.services;
+
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
+
+/**
+ * Created by mike on 28.01.2018.
+ */
+
+public abstract class AbstractSerialIOThread extends Thread {
+
+ public abstract void sendMessage(MessageBase message);
+ public abstract void disconnect(String reason);
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java
index 0aa4b176c7..63215464a8 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java
@@ -1,41 +1,33 @@
package info.nightscout.androidaps.plugins.PumpDanaR.services;
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothSocket;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
-import android.os.IBinder;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
-import java.util.Set;
-import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
-import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
+import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.SerialIOThread;
@@ -45,18 +37,6 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgCheckValue;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryAlarm;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBasalHour;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBolus;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryCarbo;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDailyInsulin;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDone;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryError;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryGlucose;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryRefill;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistorySuspend;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStart;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetActivateBasalProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetBasalProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetCarbsEntry;
@@ -67,9 +47,9 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTempBasalStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTime;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingActiveProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingBasal;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMeal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingGlucose;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMaxValues;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMeal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatios;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatiosAll;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingPumpTime;
@@ -78,51 +58,18 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatus;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBasic;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBolusExtended;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusTempBasal;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRNewStatus;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
-public class DanaRExecutionService extends Service {
- private static Logger log = LoggerFactory.getLogger(DanaRExecutionService.class);
-
- private String devName;
-
- private SerialIOThread mSerialIOThread;
- private BluetoothSocket mRfcommSocket;
- private BluetoothDevice mBTDevice;
-
- private IBinder mBinder = new LocalBinder();
-
- private DanaRPump danaRPump = DanaRPump.getInstance();
- private Treatment bolusingTreatment = null;
-
- private static Boolean connectionInProgress = false;
-
- private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
-
- private BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- String action = intent.getAction();
- if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
- log.debug("Device was disconnected " + device.getName());//Device was disconnected
- if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
- if (mSerialIOThread != null) {
- mSerialIOThread.disconnect("BT disconnection broadcast");
- }
- MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
- }
- }
- }
- };
+public class DanaRExecutionService extends AbstractDanaRExecutionService{
public DanaRExecutionService() {
+ log = LoggerFactory.getLogger(DanaRExecutionService.class);
+ mBinder = new LocalBinder();
+
registerBus();
MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
}
@@ -133,17 +80,6 @@ public class DanaRExecutionService extends Service {
}
}
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
-
- return START_STICKY;
- }
-
private void registerBus() {
try {
MainApp.bus().unregister(this);
@@ -154,49 +90,27 @@ public class DanaRExecutionService extends Service {
}
@Subscribe
- public void onStatusEvent(EventAppExit event) {
- if (Config.logFunctionCalls)
- log.debug("EventAppExit received");
-
+ public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
- mSerialIOThread.disconnect("Application exit");
-
- MainApp.instance().getApplicationContext().unregisterReceiver(receiver);
-
- stopSelf();
- if (Config.logFunctionCalls)
- log.debug("EventAppExit finished");
+ mSerialIOThread.disconnect("EventPreferenceChange");
}
- public boolean isConnected() {
- return mRfcommSocket != null && mRfcommSocket.isConnected();
- }
-
- public boolean isConnecting() {
- return connectionInProgress;
- }
-
- public void disconnect(String from) {
- if (mSerialIOThread != null)
- mSerialIOThread.disconnect(from);
- }
-
- public void connect(String from) {
- if (danaRPump.password != -1 && danaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
+ public void connect() {
+ if (mDanaRPump.password != -1 && mDanaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
return;
}
- if (connectionInProgress)
+ if (mConnectionInProgress)
return;
new Thread(new Runnable() {
@Override
public void run() {
- connectionInProgress = true;
+ mConnectionInProgress = true;
getBTSocketForSelectedPump();
if (mRfcommSocket == null || mBTDevice == null) {
- connectionInProgress = false;
+ mConnectionInProgress = false;
return; // Device not found
}
@@ -217,48 +131,11 @@ public class DanaRExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED, 0));
}
- connectionInProgress = false;
+ mConnectionInProgress = false;
}
}).start();
}
- public void stopConnecting() {
- if (mSerialIOThread != null)
- mSerialIOThread.disconnect("stopConnecting");
- }
-
- private void getBTSocketForSelectedPump() {
- devName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- if (bluetoothAdapter != null) {
- Set bondedDevices = bluetoothAdapter.getBondedDevices();
-
- for (BluetoothDevice device : bondedDevices) {
- if (devName.equals(device.getName())) {
- mBTDevice = device;
- try {
- mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
- } catch (IOException e) {
- log.error("Error creating socket: ", e);
- }
- break;
- }
- }
- } else {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
- }
- if (mBTDevice == null) {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
- }
- }
-
- @Subscribe
- public void onStatusEvent(final EventPreferenceChange pch) {
- if (mSerialIOThread != null)
- mSerialIOThread.disconnect("EventPreferenceChange");
- }
-
public void getPumpStatus() {
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpstatus)));
@@ -268,7 +145,7 @@ public class DanaRExecutionService extends Service {
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
MsgCheckValue checkValue = new MsgCheckValue();
- if (danaRPump.isNewPump) {
+ if (mDanaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@@ -283,8 +160,8 @@ public class DanaRExecutionService extends Service {
mSerialIOThread.sendMessage(exStatusMsg);
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus)));
- Date now = new Date();
- if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRPlugin.class).isInitialized()) {
+ long now = System.currentTimeMillis();
+ if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRPlugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
@@ -298,26 +175,26 @@ public class DanaRExecutionService extends Service {
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
- long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
+ long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
- timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
+ timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
- danaRPump.lastSettingsRead = now;
+ mDanaRPump.lastSettingsRead = now;
}
- danaRPump.lastConnection = now;
+ mDanaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
- if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
- log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
+ if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
+ log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
- NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
+ NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
}
} catch (Exception e) {
log.error("Unhandled exception", e);
@@ -326,10 +203,10 @@ public class DanaRExecutionService extends Service {
public boolean tempBasal(int percent, int durationInHours) {
if (!isConnected()) return false;
- if (danaRPump.isTempBasalInProgress) {
+ if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
- waitMsec(500);
+ SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
@@ -365,11 +242,16 @@ public class DanaRExecutionService extends Service {
return true;
}
- public boolean bolus(double amount, int carbs, final Treatment t) {
+ @Override
+ public PumpEnactResult loadEvents() {
+ return null;
+ }
+
+ public boolean bolus(double amount, int carbs, long carbtime, final Treatment t) {
if (!isConnected()) return false;
if (BolusProgressDialog.stopPressed) return false;
- bolusingTreatment = t;
+ mBolusingTreatment = t;
int preferencesSpeed = SP.getInt(R.string.key_danars_bolusspeed, 0);
MessageBase start;
if (preferencesSpeed == 0)
@@ -379,7 +261,7 @@ public class DanaRExecutionService extends Service {
MsgBolusStop stop = new MsgBolusStop(amount, t);
if (carbs > 0) {
- mSerialIOThread.sendMessage(new MsgSetCarbsEntry(System.currentTimeMillis(), carbs));
+ mSerialIOThread.sendMessage(new MsgSetCarbsEntry(carbtime, carbs));
}
MsgBolusProgress progress = new MsgBolusProgress(amount, t); // initialize static variables
@@ -392,20 +274,20 @@ public class DanaRExecutionService extends Service {
return false;
}
while (!stop.stopped && !start.failed) {
- waitMsec(100);
+ SystemClock.sleep(100);
if ((System.currentTimeMillis() - progress.lastReceive) > 15 * 1000L) { // if i didn't receive status for more than 15 sec expecting broken comm
stop.stopped = true;
stop.forced = true;
log.debug("Communication stopped");
}
}
- waitMsec(300);
+ SystemClock.sleep(300);
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
bolusingEvent.t = t;
bolusingEvent.percent = 99;
- bolusingTreatment = null;
+ mBolusingTreatment = null;
int speed = 12;
switch (preferencesSpeed) {
@@ -437,11 +319,11 @@ public class DanaRExecutionService extends Service {
ConfigBuilderPlugin.getCommandQueue().independentConnect("bolusingInterrupted", new Callback() {
@Override
public void run() {
- if (danaRPump.lastBolusTime.getTime() > System.currentTimeMillis() - 60 * 1000L) { // last bolus max 1 min old
- t.insulin = danaRPump.lastBolusAmount;
- log.debug("Used bolus amount from history: " + danaRPump.lastBolusAmount);
+ if (mDanaRPump.lastBolusTime.getTime() > System.currentTimeMillis() - 60 * 1000L) { // last bolus max 1 min old
+ t.insulin = mDanaRPump.lastBolusAmount;
+ log.debug("Used bolus amount from history: " + mDanaRPump.lastBolusAmount);
} else {
- log.debug("Bolus amount in history too old: " + danaRPump.lastBolusTime.toLocaleString());
+ log.debug("Bolus amount in history too old: " + mDanaRPump.lastBolusTime.toLocaleString());
}
synchronized (o) {
o.notify();
@@ -460,22 +342,6 @@ public class DanaRExecutionService extends Service {
return true;
}
- public void bolusStop() {
- if (Config.logDanaBTComm)
- log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
- MsgBolusStop stop = new MsgBolusStop();
- stop.forced = true;
- if (isConnected()) {
- mSerialIOThread.sendMessage(stop);
- while (!stop.stopped) {
- mSerialIOThread.sendMessage(stop);
- waitMsec(200);
- }
- } else {
- stop.stopped = true;
- }
- }
-
public boolean carbsEntry(int amount) {
if (!isConnected()) return false;
MsgSetCarbsEntry msg = new MsgSetCarbsEntry(System.currentTimeMillis(), amount);
@@ -483,51 +349,9 @@ public class DanaRExecutionService extends Service {
return true;
}
- public PumpEnactResult loadHistory(byte type) {
- PumpEnactResult result = new PumpEnactResult();
- if (!isConnected()) return result;
- MessageBase msg = null;
- switch (type) {
- case RecordTypes.RECORD_TYPE_ALARM:
- msg = new MsgHistoryAlarm();
- break;
- case RecordTypes.RECORD_TYPE_BASALHOUR:
- msg = new MsgHistoryBasalHour();
- break;
- case RecordTypes.RECORD_TYPE_BOLUS:
- msg = new MsgHistoryBolus();
- break;
- case RecordTypes.RECORD_TYPE_CARBO:
- msg = new MsgHistoryCarbo();
- break;
- case RecordTypes.RECORD_TYPE_DAILY:
- msg = new MsgHistoryDailyInsulin();
- break;
- case RecordTypes.RECORD_TYPE_ERROR:
- msg = new MsgHistoryError();
- break;
- case RecordTypes.RECORD_TYPE_GLUCOSE:
- msg = new MsgHistoryGlucose();
- break;
- case RecordTypes.RECORD_TYPE_REFILL:
- msg = new MsgHistoryRefill();
- break;
- case RecordTypes.RECORD_TYPE_SUSPEND:
- msg = new MsgHistorySuspend();
- break;
- }
- MsgHistoryDone done = new MsgHistoryDone();
- mSerialIOThread.sendMessage(new MsgPCCommStart());
- waitMsec(400);
- mSerialIOThread.sendMessage(msg);
- while (!done.received && mRfcommSocket.isConnected()) {
- waitMsec(100);
- }
- waitMsec(200);
- mSerialIOThread.sendMessage(new MsgPCCommStop());
- result.success = true;
- result.comment = "OK";
- return result;
+ @Override
+ public boolean highTempBasal(int percent) {
+ return false;
}
public boolean updateBasalsInPump(final Profile profile) {
@@ -538,13 +362,25 @@ public class DanaRExecutionService extends Service {
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
- danaRPump.lastSettingsRead = new Date(0); // force read full settings
+ mDanaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
}
- private void waitMsec(long msecs) {
- SystemClock.sleep(msecs);
+ @Subscribe
+ public void onStatusEvent(EventAppExit event) {
+ if (Config.logFunctionCalls)
+ log.debug("EventAppExit received");
+
+ if (mSerialIOThread != null)
+ mSerialIOThread.disconnect("Application exit");
+
+ MainApp.instance().getApplicationContext().unregisterReceiver(receiver);
+
+ stopSelf();
+ if (Config.logFunctionCalls)
+ log.debug("EventAppExit finished");
}
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java
index f269aff112..81e8aad052 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java
@@ -5,71 +5,31 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
-import android.support.annotation.Nullable;
import com.squareup.otto.Subscribe;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Date;
-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.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.data.PumpEnactResult;
-import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.interfaces.ConstraintsInterface;
-import info.nightscout.androidaps.interfaces.DanaRInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
-import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
-import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
-import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
-import info.nightscout.androidaps.plugins.PumpDanaR.DanaRFragment;
-import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
+import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService;
-import info.nightscout.utils.DateUtil;
-import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
/**
* Created by mike on 05.08.2016.
*/
-public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
- private static Logger log = LoggerFactory.getLogger(DanaRKoreanPlugin.class);
-
- @Override
- public String getFragmentClass() {
- return DanaRFragment.class.getName();
- }
-
- private static boolean fragmentPumpEnabled = false;
- private static boolean fragmentProfileEnabled = false;
- private static boolean fragmentPumpVisible = true;
-
- private static DanaRKoreanExecutionService sExecutionService;
-
-
- private static DanaRPump pump = DanaRPump.getInstance();
- private boolean useExtendedBoluses = false;
+public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
private static DanaRKoreanPlugin plugin = null;
@@ -79,9 +39,8 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
return plugin;
}
- public static PumpDescription pumpDescription = new PumpDescription();
-
public DanaRKoreanPlugin() {
+ log = LoggerFactory.getLogger(DanaRKoreanPlugin.class);
useExtendedBoluses = SP.getBoolean("danar_useextended", false);
Context context = MainApp.instance().getApplicationContext();
@@ -112,6 +71,8 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
pumpDescription.basalMinimumRate = 0.1d;
pumpDescription.isRefillingCapable = true;
+
+ pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@@ -147,83 +108,17 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
}
// Plugin base interface
- @Override
- public int getType() {
- return PluginBase.PUMP;
- }
-
@Override
public String getName() {
return MainApp.instance().getString(R.string.danarkoreanpump);
}
- @Override
- public String getNameShort() {
- String name = MainApp.sResources.getString(R.string.danarpump_shortname);
- if (!name.trim().isEmpty()) {
- //only if translation exists
- return name;
- }
- // use long name as fallback
- return getName();
- }
-
- @Override
- public boolean isEnabled(int type) {
- if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
- else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
- else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
- return false;
- }
-
- @Override
- public boolean isVisibleInTabs(int type) {
- if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
- else if (type == PluginBase.PUMP) return fragmentPumpVisible;
- return false;
- }
-
- @Override
- public boolean canBeHidden(int type) {
- return true;
- }
-
- @Override
- public boolean hasFragment() {
- return true;
- }
-
- @Override
- public boolean showInList(int type) {
- return type == PUMP;
- }
-
- @Override
- public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- if (type == PluginBase.PROFILE)
- fragmentProfileEnabled = fragmentEnabled;
- else if (type == PluginBase.PUMP)
- fragmentPumpEnabled = fragmentEnabled;
- // if pump profile was enabled need to switch to another too
- if (type == PluginBase.PUMP && !fragmentEnabled && fragmentProfileEnabled) {
- setFragmentEnabled(PluginBase.PROFILE, false);
- setFragmentVisible(PluginBase.PROFILE, false);
- NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
- NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
- }
- }
-
- @Override
- public void setFragmentVisible(int type, boolean fragmentVisible) {
- if (type == PluginBase.PUMP)
- fragmentPumpVisible = fragmentVisible;
- }
-
@Override
public int getPreferencesId() {
return R.xml.pref_danarkorean;
}
+ // Pump interface
@Override
public boolean isFakingTempsByExtendedBoluses() {
return useExtendedBoluses;
@@ -231,82 +126,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
@Override
public boolean isInitialized() {
- return pump.lastConnection.getTime() > 0 && pump.maxBasal > 0 && !pump.isConfigUD && !pump.isEasyModeEnabled && pump.isExtendedBolusEnabled;
- }
-
- @Override
- public boolean isSuspended() {
- return pump.pumpSuspended;
- }
-
- @Override
- public boolean isBusy() {
- if (sExecutionService == null) return false;
- return sExecutionService.isConnected() || sExecutionService.isConnecting();
- }
-
- // Pump interface
- @Override
- public PumpEnactResult setNewBasalProfile(Profile profile) {
- PumpEnactResult result = new PumpEnactResult();
-
- if (sExecutionService == null) {
- log.error("setNewBasalProfile sExecutionService is null");
- result.comment = "setNewBasalProfile sExecutionService is null";
- return result;
- }
- if (!isInitialized()) {
- log.error("setNewBasalProfile not initialized");
- Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
- MainApp.bus().post(new EventNewNotification(notification));
- result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
- return result;
- } else {
- MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
- }
- if (!sExecutionService.updateBasalsInPump(profile)) {
- Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
- MainApp.bus().post(new EventNewNotification(notification));
- result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
- return result;
- } else {
- MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
- MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
- result.success = true;
- result.enacted = true;
- result.comment = "OK";
- return result;
- }
- }
-
- @Override
- public boolean isThisProfileSet(Profile profile) {
- if (!isInitialized())
- return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
- if (pump.pumpProfiles == null)
- return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
- int basalValues = pump.basal48Enable ? 48 : 24;
- int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
- for (int h = 0; h < basalValues; h++) {
- Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
- Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
- if (profileValue == null) return true;
- if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
- log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Date lastDataTime() {
- return pump.lastConnection;
- }
-
- @Override
- public double getBaseBasalRate() {
- return pump.currentBasal;
+ return pump.lastConnection > 0 && pump.maxBasal > 0 && !pump.isConfigUD && !pump.isEasyModeEnabled && pump.isExtendedBolusEnabled;
}
@Override
@@ -315,8 +135,9 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
detailedBolusInfo.insulin = configBuilderPlugin.applyBolusConstraints(detailedBolusInfo.insulin);
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
Treatment t = new Treatment();
+ t.isSMB = detailedBolusInfo.isSMB;
boolean connectionOK = false;
- if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, t);
+ if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, detailedBolusInfo.carbTime, t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@@ -339,15 +160,6 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
}
}
- @Override
- public void stopBolusDelivering() {
- if (sExecutionService == null) {
- log.error("stopBolusDelivering sExecutionService is null");
- return;
- }
- sExecutionService.bolusStop();
- }
-
// This is called from APS
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) {
@@ -500,107 +312,12 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
return result;
}
- @Override
- public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
- PumpEnactResult result = new PumpEnactResult();
- ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
- percent = configBuilderPlugin.applyBasalConstraints(percent);
- if (percent < 0) {
- result.isTempCancel = false;
- result.enacted = false;
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
- log.error("setTempBasalPercent: Invalid input");
- return result;
- }
- if (percent > getPumpDescription().maxTempPercent)
- percent = getPumpDescription().maxTempPercent;
- TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
- if (runningTB != null && runningTB.percentRate == percent && enforceNew) {
- result.enacted = false;
- result.success = true;
- result.isTempCancel = false;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.duration = pump.tempBasalRemainingMin;
- result.percent = pump.tempBasalPercent;
- result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
- result.isPercent = true;
- if (Config.logPumpActions)
- log.debug("setTempBasalPercent: Correct value already set");
- return result;
- }
- int durationInHours = Math.max(durationInMinutes / 60, 1);
- boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
- if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) {
- result.enacted = true;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.isTempCancel = false;
- result.duration = pump.tempBasalRemainingMin;
- result.percent = pump.tempBasalPercent;
- result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
- result.isPercent = true;
- if (Config.logPumpActions)
- log.debug("setTempBasalPercent: OK");
- return result;
- }
- result.enacted = false;
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
- log.error("setTempBasalPercent: Failed to set temp basal");
- return result;
- }
-
- @Override
- public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
- ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
- insulin = configBuilderPlugin.applyBolusConstraints(insulin);
- // needs to be rounded
- int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
- insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
-
- PumpEnactResult result = new PumpEnactResult();
- ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
- result.enacted = false;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.duration = pump.extendedBolusRemainingMinutes;
- result.absolute = pump.extendedBolusAbsoluteRate;
- result.isPercent = false;
- result.isTempCancel = false;
- if (Config.logPumpActions)
- log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
- return result;
- }
- boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
- if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
- result.enacted = true;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.isTempCancel = false;
- result.duration = pump.extendedBolusRemainingMinutes;
- result.absolute = pump.extendedBolusAbsoluteRate;
- result.bolusDelivered = pump.extendedBolusAmount;
- result.isPercent = false;
- if (Config.logPumpActions)
- log.debug("setExtendedBolus: OK");
- return result;
- }
- result.enacted = false;
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
- log.error("setExtendedBolus: Failed to extended bolus");
- return result;
- }
-
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress())
return cancelRealTempBasal();
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress() && useExtendedBoluses) {
- PumpEnactResult cancelEx = cancelExtendedBolus();
- return cancelEx;
+ return cancelExtendedBolus();
}
PumpEnactResult result = new PumpEnactResult();
result.success = true;
@@ -634,257 +351,8 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
}
}
- @Override
- public PumpEnactResult cancelExtendedBolus() {
- PumpEnactResult result = new PumpEnactResult();
- ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (runningEB != null) {
- sExecutionService.extendedBolusStop();
- result.enacted = true;
- result.isTempCancel = true;
- }
- if (!pump.isExtendedInProgress) {
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- if (Config.logPumpActions)
- log.debug("cancelExtendedBolus: OK");
- return result;
- } else {
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
- log.error("cancelExtendedBolus: Failed to cancel extended bolus");
- return result;
- }
- }
-
- @Override
- public void connect(String from) {
- if (sExecutionService != null) {
- sExecutionService.connect(from);
- pumpDescription.basalStep = pump.basalStep;
- pumpDescription.bolusStep = pump.bolusStep;
- }
- }
-
- @Override
- public boolean isConnected() {
- return sExecutionService != null && sExecutionService.isConnected();
- }
-
- @Override
- public boolean isConnecting() {
- return sExecutionService != null && sExecutionService.isConnecting();
- }
-
- @Override
- public void disconnect(String from) {
- if (sExecutionService != null) sExecutionService.disconnect(from);
- }
-
- @Override
- public void stopConnecting() {
- if (sExecutionService != null) sExecutionService.stopConnecting();
- }
-
- @Override
- public void getPumpStatus() {
- if (sExecutionService != null) sExecutionService.getPumpStatus();
- }
-
- @Override
- public JSONObject getJSONStatus() {
- if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
- return null;
- }
- JSONObject pumpjson = new JSONObject();
- JSONObject battery = new JSONObject();
- JSONObject status = new JSONObject();
- JSONObject extended = new JSONObject();
- try {
- battery.put("percent", pump.batteryRemaining);
- status.put("status", pump.pumpSuspended ? "suspended" : "normal");
- status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
- extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
- extended.put("PumpIOB", pump.iob);
- if (pump.lastBolusTime.getTime() != 0) {
- extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
- extended.put("LastBolusAmount", pump.lastBolusAmount);
- }
- TemporaryBasal tb = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
- if (tb != null) {
- extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
- extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
- extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
- }
- ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (eb != null) {
- extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
- extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
- extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
- }
- extended.put("BaseBasalRate", getBaseBasalRate());
- try {
- extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
- } catch (Exception e) {
- }
-
- pumpjson.put("battery", battery);
- pumpjson.put("status", status);
- pumpjson.put("extended", extended);
- pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
- pumpjson.put("clock", DateUtil.toISOString(new Date()));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return pumpjson;
- }
-
- @Override
- public String deviceID() {
- return pump.serialNumber;
- }
-
- @Override
- public PumpDescription getPumpDescription() {
- return pumpDescription;
- }
-
- /**
- * DanaR interface
- */
-
- @Override
- public PumpEnactResult loadHistory(byte type) {
- return sExecutionService.loadHistory(type);
- }
-
@Override
public PumpEnactResult loadEvents() {
return null; // no history, not needed
}
-
- /**
- * Constraint interface
- */
-
- @Override
- public boolean isLoopEnabled() {
- return true;
- }
-
- @Override
- public boolean isClosedModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isAutosensModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isAMAModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isSMBModeEnabled() {
- return true;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Double applyBasalConstraints(Double absoluteRate) {
- double origAbsoluteRate = absoluteRate;
- if (pump != null) {
- if (absoluteRate > pump.maxBasal) {
- absoluteRate = pump.maxBasal;
- if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
- log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
- }
- }
- return absoluteRate;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Integer applyBasalConstraints(Integer percentRate) {
- Integer origPercentRate = percentRate;
- if (percentRate < 0) percentRate = 0;
- if (percentRate > getPumpDescription().maxTempPercent)
- percentRate = getPumpDescription().maxTempPercent;
- if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
- log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
- return percentRate;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Double applyBolusConstraints(Double insulin) {
- double origInsulin = insulin;
- if (pump != null) {
- if (insulin > pump.maxBolus) {
- insulin = pump.maxBolus;
- if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
- log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
- }
- }
- return insulin;
- }
-
- @Override
- public Integer applyCarbsConstraints(Integer carbs) {
- return carbs;
- }
-
- @Override
- public Double applyMaxIOBConstraints(Double maxIob) {
- return maxIob;
- }
-
- @Nullable
- @Override
- public ProfileStore getProfile() {
- if (pump.lastSettingsRead.getTime() == 0)
- return null; // no info now
- return pump.createConvertedProfile();
- }
-
- @Override
- public String getUnits() {
- return pump.getUnits();
- }
-
- @Override
- public String getProfileName() {
- return pump.createConvertedProfileName();
- }
-
- // Reply for sms communicator
- public String shortStatus(boolean veryShort) {
- String ret = "";
- if (pump.lastConnection.getTime() != 0) {
- Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
- int agoMin = (int) (agoMsec / 60d / 1000d);
- ret += "LastConn: " + agoMin + " minago\n";
- }
- if (pump.lastBolusTime.getTime() != 0) {
- ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
- }
- if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
- ret += "Temp: " + MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
- }
- if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
- ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
- }
- if (!veryShort) {
- ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
- }
- ret += "IOB: " + pump.iob + "U\n";
- ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
- ret += "Batt: " + pump.batteryRemaining + "\n";
- return ret;
- }
- // TODO: daily total constraint
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/SerialIOThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/SerialIOThread.java
index 8672afdcb0..9a8f3edb05 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/SerialIOThread.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/SerialIOThread.java
@@ -13,13 +13,14 @@ import java.io.OutputStream;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractSerialIOThread;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MessageHashTable_k;
import info.nightscout.utils.CRC;
/**
* Created by mike on 17.07.2016.
*/
-public class SerialIOThread extends Thread {
+public class SerialIOThread extends AbstractSerialIOThread {
private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
private InputStream mInputStream = null;
@@ -29,10 +30,10 @@ public class SerialIOThread extends Thread {
private boolean mKeepRunning = true;
private byte[] mReadBuff = new byte[0];
- MessageBase processedMessage;
+ private MessageBase processedMessage;
public SerialIOThread(BluetoothSocket rfcommSocket) {
- super(SerialIOThread.class.toString());
+ super();
mRfCommSocket = rfcommSocket;
try {
@@ -138,6 +139,7 @@ public class SerialIOThread extends Thread {
}
}
+ @Override
public synchronized void sendMessage(MessageBase message) {
if (!mRfCommSocket.isConnected()) {
log.error("Socket not connected on sendMessage");
@@ -173,6 +175,7 @@ public class SerialIOThread extends Thread {
}
}
+ @Override
public void disconnect(String reason) {
mKeepRunning = false;
try {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgInitConnStatusTime_k.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgInitConnStatusTime_k.java
index 641dce79f3..3cf47b656f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgInitConnStatusTime_k.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgInitConnStatusTime_k.java
@@ -37,7 +37,7 @@ public class MsgInitConnStatusTime_k extends MessageBase {
MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).setFragmentVisible(PluginBase.PUMP, false);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentEnabled(PluginBase.PUMP, true);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentVisible(PluginBase.PUMP, true);
- DanaRPump.getInstance().lastConnection = new Date(0); // mark not initialized
+ DanaRPump.getInstance().lastConnection = 0; // mark not initialized
//If profile coming from pump, switch it as well
if (MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isEnabled(PluginBase.PROFILE)) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgSettingBasal_k.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgSettingBasal_k.java
index 72a8be4e42..5c8b40b959 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgSettingBasal_k.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/comm/MsgSettingBasal_k.java
@@ -24,7 +24,7 @@ public class MsgSettingBasal_k extends MessageBase {
pump.pumpProfiles[pump.activeProfile] = new double[24];
for (int index = 0; index < 24; index++) {
int basal = intFromBuff(bytes, 2 * index, 2);
- if (basal < DanaRKoreanPlugin.pumpDescription.basalMinimumRate) basal = 0;
+ if (basal < DanaRKoreanPlugin.getPlugin().pumpDescription.basalMinimumRate) basal = 0;
pump.pumpProfiles[pump.activeProfile][index] = basal / 100d;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java
index 4efff4a5ad..6d1ccc132d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java
@@ -1,58 +1,36 @@
package info.nightscout.androidaps.plugins.PumpDanaRKorean.services;
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothSocket;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
-import android.os.IBinder;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
-import java.util.Set;
-import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
-import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
-import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusProgress;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryAlarm;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBasalHour;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBolus;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryCarbo;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDailyInsulin;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDone;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryError;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryGlucose;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryRefill;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistorySuspend;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStart;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetCarbsEntry;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStop;
@@ -68,56 +46,23 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingPumpTime;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingShippingInfo;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBolusExtended;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusTempBasal;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRNewStatus;
+import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractDanaRExecutionService;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.SerialIOThread;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgCheckValue_k;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgSettingBasal_k;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgStatusBasic_k;
-import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
-public class DanaRKoreanExecutionService extends Service {
- private static Logger log = LoggerFactory.getLogger(DanaRKoreanExecutionService.class);
-
- private String devName;
-
- private SerialIOThread mSerialIOThread;
- private BluetoothSocket mRfcommSocket;
- private BluetoothDevice mBTDevice;
-
- private IBinder mBinder = new LocalBinder();
-
- private DanaRPump danaRPump = DanaRPump.getInstance();
- private Treatment bolusingTreatment = null;
-
- private static Boolean connectionInProgress = false;
-
- private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
-
- private BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- String action = intent.getAction();
- if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
- log.debug("Device was disconnected " + device.getName());//Device was disconnected
- if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
- if (mSerialIOThread != null) {
- mSerialIOThread.disconnect("BT disconnection broadcast");
- }
- MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
- }
- }
- }
- };
+public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
public DanaRKoreanExecutionService() {
+ log = LoggerFactory.getLogger(DanaRKoreanExecutionService.class);
+ mBinder = new LocalBinder();
+
registerBus();
MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
}
@@ -128,17 +73,6 @@ public class DanaRKoreanExecutionService extends Service {
}
}
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
-
- return START_STICKY;
- }
-
private void registerBus() {
try {
MainApp.bus().unregister(this);
@@ -163,35 +97,28 @@ public class DanaRKoreanExecutionService extends Service {
log.debug("EventAppExit finished");
}
- public boolean isConnected() {
- return mRfcommSocket != null && mRfcommSocket.isConnected();
- }
-
- public boolean isConnecting() {
- return connectionInProgress;
- }
-
- public void disconnect(String from) {
+ @Subscribe
+ public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
- mSerialIOThread.disconnect(from);
+ mSerialIOThread.disconnect("EventPreferenceChange");
}
- public void connect(String from) {
- if (danaRPump.password != -1 && danaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
+ public void connect() {
+ if (mDanaRPump.password != -1 && mDanaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
return;
}
- if (connectionInProgress)
+ if (mConnectionInProgress)
return;
new Thread(new Runnable() {
@Override
public void run() {
- connectionInProgress = true;
+ mConnectionInProgress = true;
getBTSocketForSelectedPump();
if (mRfcommSocket == null || mBTDevice == null) {
- connectionInProgress = false;
+ mConnectionInProgress = false;
return; // Device not found
}
@@ -212,48 +139,11 @@ public class DanaRKoreanExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED, 0));
}
- connectionInProgress = false;
+ mConnectionInProgress = false;
}
}).start();
}
- public void stopConnecting() {
- if (mSerialIOThread != null)
- mSerialIOThread.disconnect("stopConnecting");
- }
-
- private void getBTSocketForSelectedPump() {
- devName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- if (bluetoothAdapter != null) {
- Set bondedDevices = bluetoothAdapter.getBondedDevices();
-
- for (BluetoothDevice device : bondedDevices) {
- if (devName.equals(device.getName())) {
- mBTDevice = device;
- try {
- mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
- } catch (IOException e) {
- log.error("Error creating socket: ", e);
- }
- break;
- }
- }
- } else {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
- }
- if (mBTDevice == null) {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
- }
- }
-
- @Subscribe
- public void onStatusEvent(final EventPreferenceChange pch) {
- if (mSerialIOThread != null)
- mSerialIOThread.disconnect("EventPreferenceChange");
- }
-
public void getPumpStatus() {
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpstatus)));
@@ -263,7 +153,7 @@ public class DanaRKoreanExecutionService extends Service {
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
MsgCheckValue_k checkValue = new MsgCheckValue_k();
- if (danaRPump.isNewPump) {
+ if (mDanaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@@ -278,8 +168,8 @@ public class DanaRKoreanExecutionService extends Service {
mSerialIOThread.sendMessage(exStatusMsg);
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus)));
- Date now = new Date();
- if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isInitialized()) {
+ long now = System.currentTimeMillis();
+ if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingMeal());
@@ -290,39 +180,38 @@ public class DanaRKoreanExecutionService extends Service {
mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
- long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
+ long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
- timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
+ timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
- danaRPump.lastSettingsRead = now;
+ mDanaRPump.lastSettingsRead = now;
}
- danaRPump.lastConnection = now;
+ mDanaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
- if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
- log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
+ if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
+ log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
- NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
+ NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
- return;
}
public boolean tempBasal(int percent, int durationInHours) {
if (!isConnected()) return false;
- if (danaRPump.isTempBasalInProgress) {
+ if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
- waitMsec(500);
+ SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
@@ -358,16 +247,21 @@ public class DanaRKoreanExecutionService extends Service {
return true;
}
- public boolean bolus(double amount, int carbs, final Treatment t) {
+ @Override
+ public PumpEnactResult loadEvents() {
+ return null;
+ }
+
+ public boolean bolus(double amount, int carbs, long carbtime, final Treatment t) {
if (!isConnected()) return false;
if (BolusProgressDialog.stopPressed) return false;
- bolusingTreatment = t;
+ mBolusingTreatment = t;
MsgBolusStart start = new MsgBolusStart(amount);
MsgBolusStop stop = new MsgBolusStop(amount, t);
if (carbs > 0) {
- mSerialIOThread.sendMessage(new MsgSetCarbsEntry(System.currentTimeMillis(), carbs));
+ mSerialIOThread.sendMessage(new MsgSetCarbsEntry(carbtime, carbs));
}
MsgBolusProgress progress = new MsgBolusProgress(amount, t); // initialize static variables
@@ -380,37 +274,21 @@ public class DanaRKoreanExecutionService extends Service {
return false;
}
while (!stop.stopped && !start.failed) {
- waitMsec(100);
+ SystemClock.sleep(100);
if ((System.currentTimeMillis() - progress.lastReceive) > 15 * 1000L) { // if i didn't receive status for more than 15 sec expecting broken comm
stop.stopped = true;
stop.forced = true;
log.debug("Communication stopped");
}
}
- waitMsec(300);
+ SystemClock.sleep(300);
- bolusingTreatment = null;
+ mBolusingTreatment = null;
ConfigBuilderPlugin.getCommandQueue().readStatus("bolusOK", null);
return true;
}
- public void bolusStop() {
- if (Config.logDanaBTComm)
- log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
- MsgBolusStop stop = new MsgBolusStop();
- stop.forced = true;
- if (isConnected()) {
- mSerialIOThread.sendMessage(stop);
- while (!stop.stopped) {
- mSerialIOThread.sendMessage(stop);
- waitMsec(200);
- }
- } else {
- stop.stopped = true;
- }
- }
-
public boolean carbsEntry(int amount) {
if (!isConnected()) return false;
MsgSetCarbsEntry msg = new MsgSetCarbsEntry(System.currentTimeMillis(), amount);
@@ -418,51 +296,9 @@ public class DanaRKoreanExecutionService extends Service {
return true;
}
- public PumpEnactResult loadHistory(byte type) {
- PumpEnactResult result = new PumpEnactResult();
- if (!isConnected()) return result;
- MessageBase msg = null;
- switch (type) {
- case RecordTypes.RECORD_TYPE_ALARM:
- msg = new MsgHistoryAlarm();
- break;
- case RecordTypes.RECORD_TYPE_BASALHOUR:
- msg = new MsgHistoryBasalHour();
- break;
- case RecordTypes.RECORD_TYPE_BOLUS:
- msg = new MsgHistoryBolus();
- break;
- case RecordTypes.RECORD_TYPE_CARBO:
- msg = new MsgHistoryCarbo();
- break;
- case RecordTypes.RECORD_TYPE_DAILY:
- msg = new MsgHistoryDailyInsulin();
- break;
- case RecordTypes.RECORD_TYPE_ERROR:
- msg = new MsgHistoryError();
- break;
- case RecordTypes.RECORD_TYPE_GLUCOSE:
- msg = new MsgHistoryGlucose();
- break;
- case RecordTypes.RECORD_TYPE_REFILL:
- msg = new MsgHistoryRefill();
- break;
- case RecordTypes.RECORD_TYPE_SUSPEND:
- msg = new MsgHistorySuspend();
- break;
- }
- MsgHistoryDone done = new MsgHistoryDone();
- mSerialIOThread.sendMessage(new MsgPCCommStart());
- waitMsec(400);
- mSerialIOThread.sendMessage(msg);
- while (!done.received && mRfcommSocket.isConnected()) {
- waitMsec(100);
- }
- waitMsec(200);
- mSerialIOThread.sendMessage(new MsgPCCommStop());
- result.success = true;
- result.comment = "OK";
- return result;
+ @Override
+ public boolean highTempBasal(int percent) {
+ return false;
}
public boolean updateBasalsInPump(final Profile profile) {
@@ -471,13 +307,10 @@ public class DanaRKoreanExecutionService extends Service {
double[] basal = DanaRPump.buildDanaRProfileRecord(profile);
MsgSetSingleBasalProfile msgSet = new MsgSetSingleBasalProfile(basal);
mSerialIOThread.sendMessage(msgSet);
- danaRPump.lastSettingsRead = new Date(0); // force read full settings
+ mDanaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
}
- private void waitMsec(long msecs) {
- SystemClock.sleep(msecs);
- }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java
index ed9f98651f..2ef65d4337 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java
@@ -189,6 +189,8 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
pumpDescription.basalMinimumRate = 0.04d;
pumpDescription.isRefillingCapable = true;
+
+ pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@@ -346,7 +348,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Nullable
@Override
public ProfileStore getProfile() {
- if (pump.lastSettingsRead.getTime() == 0)
+ if (pump.lastSettingsRead == 0)
return null; // no info now
return pump.createConvertedProfile();
}
@@ -365,7 +367,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public boolean isInitialized() {
- return pump.lastConnection.getTime() > 0 && pump.maxBasal > 0;
+ return pump.lastConnection > 0 && pump.maxBasal > 0;
}
@Override
@@ -436,7 +438,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public Date lastDataTime() {
- return pump.lastConnection;
+ return new Date(pump.lastConnection);
}
@Override
@@ -475,9 +477,10 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
DetailedBolusInfoStorage.add(detailedBolusInfo); // will be picked up on reading history
Treatment t = new Treatment();
+ t.isSMB = detailedBolusInfo.isSMB;
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || carbs > 0)
- connectionOK = danaRSService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000 + 1000, t); // +1000 to make the record different
+ connectionOK = danaRSService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000, t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@@ -751,7 +754,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public JSONObject getJSONStatus() {
- if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
+ if (pump.lastConnection + 5 * 60 * 1000L < System.currentTimeMillis()) {
return null;
}
JSONObject pumpjson = new JSONObject();
@@ -810,19 +813,21 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public String shortStatus(boolean veryShort) {
String ret = "";
- if (pump.lastConnection.getTime() != 0) {
- Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
+ if (pump.lastConnection != 0) {
+ Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (pump.lastBolusTime.getTime() != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
}
- if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
- ret += "Temp: " + MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
+ TemporaryBasal activeTemp = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
+ if (activeTemp != null) {
+ ret += "Temp: " + activeTemp.toStringFull() + "\n";
}
- if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
- ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
+ ExtendedBolus activeExtendedBolus = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (activeExtendedBolus != null) {
+ ret += "Extended: " + activeExtendedBolus.toString() + "\n";
}
if (!veryShort) {
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Set_Event_History.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Set_Event_History.java
index 4e559a77df..84ead83665 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Set_Event_History.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Set_Event_History.java
@@ -9,6 +9,7 @@ import java.util.Calendar;
import java.util.GregorianCalendar;
import info.nightscout.androidaps.Config;
+import info.nightscout.utils.DateUtil;
public class DanaRS_Packet_APS_Set_Event_History extends DanaRS_Packet {
private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_APS_Set_Event_History.class);
@@ -30,6 +31,8 @@ public class DanaRS_Packet_APS_Set_Event_History extends DanaRS_Packet {
this.time = time;
this.param1 = param1;
this.param2 = param2;
+ if (Config.logDanaMessageDetail)
+ log.debug("Set history entry: " + DateUtil.dateAndTimeString(time) + " type: " + type + " param1: " + param1 + " param2: " + param2);
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/BLEComm.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/BLEComm.java
index f8d18a4d22..2901c4b863 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/BLEComm.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/BLEComm.java
@@ -164,6 +164,8 @@ public class BLEComm {
scheduledDisconnection = null;
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
+ log.debug("disconnect not possible: (mBluetoothAdapter == null) " + (mBluetoothAdapter == null));
+ log.debug("disconnect not possible: (mBluetoothGatt == null) " + (mBluetoothGatt == null));
return;
}
setCharacteristicNotification(getUARTReadBTGattChar(), false);
@@ -257,6 +259,8 @@ public class BLEComm {
log.debug("setCharacteristicNotification");
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
log.debug("BluetoothAdapter not initialized_ERROR");
+ isConnecting = false;
+ isConnected = false;
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
@@ -266,20 +270,25 @@ public class BLEComm {
log.debug("readCharacteristic");
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
log.debug("BluetoothAdapter not initialized_ERROR");
+ isConnecting = false;
+ isConnected = false;
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
public void writeCharacteristic_NO_RESPONSE(final BluetoothGattCharacteristic characteristic, final byte[] data) {
- if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
- log.debug("BluetoothAdapter not initialized_ERROR");
- return;
- }
-
new Thread(new Runnable() {
public void run() {
SystemClock.sleep(WRITE_DELAY_MILLIS);
+
+ if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
+ log.debug("BluetoothAdapter not initialized_ERROR");
+ isConnecting = false;
+ isConnected = false;
+ return;
+ }
+
characteristic.setValue(data);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
log.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data));
@@ -306,6 +315,8 @@ public class BLEComm {
log.debug("getSupportedGattServices");
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
log.debug("BluetoothAdapter not initialized_ERROR");
+ isConnecting = false;
+ isConnected = false;
return null;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java
index 7790257640..b35704f176 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java
@@ -131,8 +131,8 @@ public class DanaRSService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingtempbasalstatus)));
bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State());
- Date now = new Date();
- if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()) {
+ long now = System.currentTimeMillis();
+ if (danaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
bleComm.sendMessage(new DanaRS_Packet_General_Get_Shipping_Information()); // serial no
bleComm.sendMessage(new DanaRS_Packet_General_Get_Pump_Check()); // firmware
@@ -156,7 +156,6 @@ public class DanaRSService extends Service {
loadEvents();
- danaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
@@ -190,6 +189,7 @@ public class DanaRSService extends Service {
else
lastHistoryFetched = 0;
log.debug("Events loaded");
+ danaRPump.lastConnection = System.currentTimeMillis();
return new PumpEnactResult().success(true);
}
@@ -357,7 +357,7 @@ public class DanaRSService extends Service {
bleComm.sendMessage(msgSet);
DanaRS_Packet_Basal_Set_Profile_Number msgActivate = new DanaRS_Packet_Basal_Set_Profile_Number(0);
bleComm.sendMessage(msgActivate);
- danaRPump.lastSettingsRead = new Date(0); // force read full settings
+ danaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java
index b4eb969852..4fbf45cd44 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java
@@ -5,68 +5,31 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
-import android.support.annotation.Nullable;
import com.squareup.otto.Subscribe;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Date;
-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.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.data.PumpEnactResult;
-import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
-import info.nightscout.androidaps.interfaces.ConstraintsInterface;
-import info.nightscout.androidaps.interfaces.DanaRInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
-import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
-import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
-import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
-import info.nightscout.androidaps.plugins.PumpDanaR.DanaRFragment;
-import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
+import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.services.DanaRv2ExecutionService;
-import info.nightscout.utils.DateUtil;
-import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
/**
* Created by mike on 05.08.2016.
*/
-public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
- private static Logger log = LoggerFactory.getLogger(DanaRv2Plugin.class);
-
- @Override
- public String getFragmentClass() {
- return DanaRFragment.class.getName();
- }
-
- private static boolean fragmentPumpEnabled = false;
- private static boolean fragmentProfileEnabled = false;
- private static boolean fragmentPumpVisible = true;
-
- private static DanaRv2ExecutionService sExecutionService;
-
+public class DanaRv2Plugin extends AbstractDanaRPlugin {
private static DanaRv2Plugin plugin = null;
@@ -76,11 +39,10 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
return plugin;
}
- private static DanaRPump pump = DanaRPump.getInstance();
-
- private static PumpDescription pumpDescription = new PumpDescription();
-
private DanaRv2Plugin() {
+ log = LoggerFactory.getLogger(DanaRv2Plugin.class);
+ useExtendedBoluses = false;
+
Context context = MainApp.instance().getApplicationContext();
Intent intent = new Intent(context, DanaRv2ExecutionService.class);
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
@@ -109,6 +71,8 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
pumpDescription.basalMinimumRate = 0.04d;
pumpDescription.isRefillingCapable = true;
+
+ pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@@ -132,78 +96,11 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
}
// Plugin base interface
- @Override
- public int getType() {
- return PluginBase.PUMP;
- }
-
@Override
public String getName() {
return MainApp.instance().getString(R.string.danarv2pump);
}
- @Override
- public String getNameShort() {
- String name = MainApp.sResources.getString(R.string.danarpump_shortname);
- if (!name.trim().isEmpty()) {
- //only if translation exists
- return name;
- }
- // use long name as fallback
- return getName();
- }
-
- @Override
- public boolean isEnabled(int type) {
- if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
- else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
- else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
- return false;
- }
-
- @Override
- public boolean isVisibleInTabs(int type) {
- if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
- else if (type == PluginBase.PUMP) return fragmentPumpVisible;
- return false;
- }
-
- @Override
- public boolean canBeHidden(int type) {
- return true;
- }
-
- @Override
- public boolean hasFragment() {
- return true;
- }
-
- @Override
- public boolean showInList(int type) {
- return type == PUMP;
- }
-
- @Override
- public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- if (type == PluginBase.PROFILE)
- fragmentProfileEnabled = fragmentEnabled;
- else if (type == PluginBase.PUMP)
- fragmentPumpEnabled = fragmentEnabled;
- // if pump profile was enabled need to switch to another too
- if (type == PluginBase.PUMP && !fragmentEnabled && fragmentProfileEnabled) {
- setFragmentEnabled(PluginBase.PROFILE, false);
- setFragmentVisible(PluginBase.PROFILE, false);
- NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
- NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
- }
- }
-
- @Override
- public void setFragmentVisible(int type, boolean fragmentVisible) {
- if (type == PluginBase.PUMP)
- fragmentPumpVisible = fragmentVisible;
- }
-
@Override
public int getPreferencesId() {
return R.xml.pref_danarv2;
@@ -216,86 +113,10 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public boolean isInitialized() {
- return pump.lastConnection.getTime() > 0 && pump.maxBasal > 0;
- }
-
- @Override
- public boolean isSuspended() {
- return pump.pumpSuspended;
- }
-
- @Override
- public boolean isBusy() {
- if (sExecutionService == null) return false;
- return sExecutionService.isConnected() || sExecutionService.isConnecting();
+ return pump.lastConnection > 0 && pump.maxBasal > 0;
}
// Pump interface
- @Override
- public PumpEnactResult setNewBasalProfile(Profile profile) {
- PumpEnactResult result = new PumpEnactResult();
-
- if (sExecutionService == null) {
- log.error("setNewBasalProfile sExecutionService is null");
- result.comment = "setNewBasalProfile sExecutionService is null";
- return result;
- }
- if (!isInitialized()) {
- log.error("setNewBasalProfile not initialized");
- Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
- MainApp.bus().post(new EventNewNotification(notification));
- result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
- return result;
- } else {
- MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
- }
- if (!sExecutionService.updateBasalsInPump(profile)) {
- Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
- MainApp.bus().post(new EventNewNotification(notification));
- result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
- return result;
- } else {
- MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
- MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
- Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.sResources.getString(R.string.profile_set_ok), Notification.INFO, 60);
- MainApp.bus().post(new EventNewNotification(notification));
- result.success = true;
- result.enacted = true;
- result.comment = "OK";
- return result;
- }
- }
-
- @Override
- public boolean isThisProfileSet(Profile profile) {
- if (!isInitialized())
- return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
- if (pump.pumpProfiles == null)
- return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
- int basalValues = pump.basal48Enable ? 48 : 24;
- int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
- for (int h = 0; h < basalValues; h++) {
- Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
- Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
- if (profileValue == null) return true;
- if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
- log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Date lastDataTime() {
- return pump.lastConnection;
- }
-
- @Override
- public double getBaseBasalRate() {
- return pump.currentBasal;
- }
-
@Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
@@ -327,9 +148,10 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
DetailedBolusInfoStorage.add(detailedBolusInfo); // will be picked up on reading history
Treatment t = new Treatment();
+ t.isSMB = detailedBolusInfo.isSMB;
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || carbs > 0)
- connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000 + 1000, t); // +1000 to make the record different
+ connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000, t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@@ -511,49 +333,6 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
return result;
}
- @Override
- public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
- ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
- insulin = configBuilderPlugin.applyBolusConstraints(insulin);
- // needs to be rounded
- int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
- insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
-
- PumpEnactResult result = new PumpEnactResult();
- ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
- result.enacted = false;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.duration = pump.extendedBolusRemainingMinutes;
- result.absolute = pump.extendedBolusAbsoluteRate;
- result.isPercent = false;
- result.isTempCancel = false;
- if (Config.logPumpActions)
- log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
- return result;
- }
- boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
- if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
- result.enacted = true;
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- result.isTempCancel = false;
- result.duration = pump.extendedBolusRemainingMinutes;
- result.absolute = pump.extendedBolusAbsoluteRate;
- result.bolusDelivered = pump.extendedBolusAmount;
- result.isPercent = false;
- if (Config.logPumpActions)
- log.debug("setExtendedBolus: OK");
- return result;
- }
- result.enacted = false;
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
- log.error("setExtendedBolus: Failed to extended bolus");
- return result;
- }
-
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
PumpEnactResult result = new PumpEnactResult();
@@ -579,257 +358,8 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
}
}
- @Override
- public PumpEnactResult cancelExtendedBolus() {
- PumpEnactResult result = new PumpEnactResult();
- ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (runningEB != null) {
- sExecutionService.extendedBolusStop();
- result.enacted = true;
- result.isTempCancel = true;
- }
- if (!pump.isExtendedInProgress) {
- result.success = true;
- result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
- if (Config.logPumpActions)
- log.debug("cancelExtendedBolus: OK");
- return result;
- } else {
- result.success = false;
- result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
- log.error("cancelExtendedBolus: Failed to cancel extended bolus");
- return result;
- }
- }
-
- @Override
- public void connect(String from) {
- if (sExecutionService != null) {
- sExecutionService.connect(from);
- pumpDescription.basalStep = pump.basalStep;
- pumpDescription.bolusStep = pump.bolusStep;
- }
- }
-
- @Override
- public boolean isConnected() {
- return sExecutionService != null && sExecutionService.isConnected();
- }
-
- @Override
- public boolean isConnecting() {
- return sExecutionService != null && sExecutionService.isConnecting();
- }
-
- @Override
- public void disconnect(String from) {
- if (sExecutionService != null) sExecutionService.disconnect(from);
- }
-
- @Override
- public void stopConnecting() {
- if (sExecutionService != null) sExecutionService.stopConnecting();
- }
-
- @Override
- public void getPumpStatus() {
- if (sExecutionService != null) sExecutionService.getPumpStatus();
- }
-
- @Override
- public JSONObject getJSONStatus() {
- if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
- return null;
- }
- JSONObject pumpjson = new JSONObject();
- JSONObject battery = new JSONObject();
- JSONObject status = new JSONObject();
- JSONObject extended = new JSONObject();
- try {
- battery.put("percent", pump.batteryRemaining);
- status.put("status", pump.pumpSuspended ? "suspended" : "normal");
- status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
- extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
- extended.put("PumpIOB", pump.iob);
- if (pump.lastBolusTime.getTime() != 0) {
- extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
- extended.put("LastBolusAmount", pump.lastBolusAmount);
- }
- TemporaryBasal tb = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
- if (tb != null) {
- extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
- extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
- extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
- }
- ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (eb != null) {
- extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
- extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
- extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
- }
- extended.put("BaseBasalRate", getBaseBasalRate());
- try {
- extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
- } catch (Exception e) {
- }
-
- pumpjson.put("battery", battery);
- pumpjson.put("status", status);
- pumpjson.put("extended", extended);
- pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
- pumpjson.put("clock", DateUtil.toISOString(new Date()));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return pumpjson;
- }
-
- @Override
- public String deviceID() {
- return pump.serialNumber;
- }
-
- @Override
- public PumpDescription getPumpDescription() {
- return pumpDescription;
- }
-
- /**
- * DanaR interface
- */
-
- @Override
- public PumpEnactResult loadHistory(byte type) {
- return sExecutionService.loadHistory(type);
- }
-
@Override
public PumpEnactResult loadEvents() {
return sExecutionService.loadEvents();
}
-
- /**
- * Constraint interface
- */
-
- @Override
- public boolean isLoopEnabled() {
- return true;
- }
-
- @Override
- public boolean isClosedModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isAutosensModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isAMAModeEnabled() {
- return true;
- }
-
- @Override
- public boolean isSMBModeEnabled() {
- return true;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Double applyBasalConstraints(Double absoluteRate) {
- double origAbsoluteRate = absoluteRate;
- if (pump != null) {
- if (absoluteRate > pump.maxBasal) {
- absoluteRate = pump.maxBasal;
- if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
- log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
- }
- }
- return absoluteRate;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Integer applyBasalConstraints(Integer percentRate) {
- Integer origPercentRate = percentRate;
- if (percentRate < 0) percentRate = 0;
- if (percentRate > getPumpDescription().maxTempPercent)
- percentRate = getPumpDescription().maxTempPercent;
- if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
- log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
- return percentRate;
- }
-
- @SuppressWarnings("PointlessBooleanExpression")
- @Override
- public Double applyBolusConstraints(Double insulin) {
- double origInsulin = insulin;
- if (pump != null) {
- if (insulin > pump.maxBolus) {
- insulin = pump.maxBolus;
- if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
- log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
- }
- }
- return insulin;
- }
-
- @Override
- public Integer applyCarbsConstraints(Integer carbs) {
- return carbs;
- }
-
- @Override
- public Double applyMaxIOBConstraints(Double maxIob) {
- return maxIob;
- }
-
- @Nullable
- @Override
- public ProfileStore getProfile() {
- if (pump.lastSettingsRead.getTime() == 0)
- return null; // no info now
- return pump.createConvertedProfile();
- }
-
- @Override
- public String getUnits() {
- return pump.getUnits();
- }
-
- @Override
- public String getProfileName() {
- return pump.createConvertedProfileName();
- }
-
- // Reply for sms communicator
- public String shortStatus(boolean veryShort) {
- String ret = "";
- if (pump.lastConnection.getTime() != 0) {
- Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
- int agoMin = (int) (agoMsec / 60d / 1000d);
- ret += "LastConn: " + agoMin + " minago\n";
- }
- if (pump.lastBolusTime.getTime() != 0) {
- ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
- }
- if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
- ret += "Temp: " + MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
- }
- if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
- ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
- }
- if (!veryShort) {
- ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
- }
- ret += "IOB: " + pump.iob + "U\n";
- ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
- ret += "Batt: " + pump.batteryRemaining + "\n";
- return ret;
- }
- // TODO: daily total constraint
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/SerialIOThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/SerialIOThread.java
index 343a176e56..a12e2085aa 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/SerialIOThread.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/SerialIOThread.java
@@ -13,13 +13,14 @@ import java.io.OutputStream;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractSerialIOThread;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MessageHashTable_v2;
import info.nightscout.utils.CRC;
/**
* Created by mike on 17.07.2016.
*/
-public class SerialIOThread extends Thread {
+public class SerialIOThread extends AbstractSerialIOThread {
private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
private InputStream mInputStream = null;
@@ -29,10 +30,10 @@ public class SerialIOThread extends Thread {
private boolean mKeepRunning = true;
private byte[] mReadBuff = new byte[0];
- MessageBase processedMessage;
+ private MessageBase processedMessage;
public SerialIOThread(BluetoothSocket rfcommSocket) {
- super(SerialIOThread.class.toString());
+ super();
mRfCommSocket = rfcommSocket;
try {
@@ -138,6 +139,7 @@ public class SerialIOThread extends Thread {
}
}
+ @Override
public synchronized void sendMessage(MessageBase message) {
if (!mRfCommSocket.isConnected()) {
log.error("Socket not connected on sendMessage");
@@ -173,6 +175,7 @@ public class SerialIOThread extends Thread {
}
}
+ @Override
public void disconnect(String reason) {
mKeepRunning = false;
try {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MsgCheckValue_v2.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MsgCheckValue_v2.java
index 9869ef0895..60133d8d25 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MsgCheckValue_v2.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MsgCheckValue_v2.java
@@ -40,6 +40,7 @@ public class MsgCheckValue_v2 extends MessageBase {
pump.protocol = intFromBuff(bytes, 1, 1);
pump.productCode = intFromBuff(bytes, 2, 1);
if (pump.model != DanaRPump.EXPORT_MODEL) {
+ pump.lastConnection = 0;
Notification notification = new Notification(Notification.WRONG_DRIVER, MainApp.sResources.getString(R.string.pumpdrivercorrected), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
MainApp.getSpecificPlugin(DanaRPlugin.class).disconnect("Wrong Model");
@@ -48,7 +49,7 @@ public class MsgCheckValue_v2 extends MessageBase {
MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).setFragmentVisible(PluginBase.PUMP, true);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentEnabled(PluginBase.PUMP, false);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentVisible(PluginBase.PUMP, false);
- DanaRPump.getInstance().lastConnection = new Date(0); // mark not initialized
+ DanaRPump.getInstance().lastConnection = 0; // mark not initialized
//If profile coming from pump, switch it as well
if(MainApp.getSpecificPlugin(DanaRPlugin.class).isEnabled(PluginBase.PROFILE)){
@@ -63,6 +64,7 @@ public class MsgCheckValue_v2 extends MessageBase {
}
if (pump.protocol != 2) {
+ pump.lastConnection = 0;
Notification notification = new Notification(Notification.WRONG_DRIVER, MainApp.sResources.getString(R.string.pumpdrivercorrected), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
DanaRKoreanPlugin.getPlugin().disconnect("Wrong Model");
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java
index 71a2f9ac79..943054d4a2 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java
@@ -1,52 +1,66 @@
package info.nightscout.androidaps.plugins.PumpDanaRv2.services;
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothSocket;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
-import android.os.IBinder;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
-import java.util.Set;
-import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
-import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
-import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
+import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
-import info.nightscout.androidaps.plugins.PumpDanaR.comm.*;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusProgress;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetActivateBasalProfile;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetBasalProfile;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetCarbsEntry;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStart;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStop;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTempBasalStart;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTempBasalStop;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTime;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingActiveProfile;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingBasal;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingGlucose;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMaxValues;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMeal;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatios;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatiosAll;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingPumpTime;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingShippingInfo;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatus;
+import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBasic;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRNewStatus;
+import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractDanaRExecutionService;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.SerialIOThread;
+import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgCheckValue_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgHistoryEvents_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgSetAPSTempBasalStart_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgSetHistoryEntry_v2;
-import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgCheckValue_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgStatusBolusExtended_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgStatusTempBasal_v2;
import info.nightscout.androidaps.queue.Callback;
@@ -54,47 +68,16 @@ import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
-public class DanaRv2ExecutionService extends Service {
- private static Logger log = LoggerFactory.getLogger(DanaRv2ExecutionService.class);
-
- private String devName;
-
- private SerialIOThread mSerialIOThread;
- private BluetoothSocket mRfcommSocket;
- private BluetoothDevice mBTDevice;
-
- private IBinder mBinder = new LocalBinder();
-
- private DanaRPump danaRPump;
- private Treatment bolusingTreatment = null;
-
- private static Boolean connectionInProgress = false;
-
- private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
+public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
private long lastHistoryFetched = 0;
- private BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- String action = intent.getAction();
- if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
- log.debug("Device was disconnected " + device.getName());//Device was disconnected
- if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
- if (mSerialIOThread != null) {
- mSerialIOThread.disconnect("BT disconnection broadcast");
- }
- MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
- }
- }
- }
- };
-
public DanaRv2ExecutionService() {
+ log = LoggerFactory.getLogger(DanaRv2ExecutionService.class);
+ mBinder = new LocalBinder();
+
registerBus();
MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
- danaRPump = DanaRPump.getInstance();
}
public class LocalBinder extends Binder {
@@ -103,17 +86,6 @@ public class DanaRv2ExecutionService extends Service {
}
}
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
-
- return START_STICKY;
- }
-
private void registerBus() {
try {
MainApp.bus().unregister(this);
@@ -138,35 +110,28 @@ public class DanaRv2ExecutionService extends Service {
log.debug("EventAppExit finished");
}
- public boolean isConnected() {
- return mRfcommSocket != null && mRfcommSocket.isConnected();
- }
-
- public boolean isConnecting() {
- return connectionInProgress;
- }
-
- public void disconnect(String from) {
+ @Subscribe
+ public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
- mSerialIOThread.disconnect(from);
+ mSerialIOThread.disconnect("EventPreferenceChange");
}
- public void connect(String from) {
- if (danaRPump.password != -1 && danaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
+ public void connect() {
+ if (mDanaRPump.password != -1 && mDanaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
return;
}
- if (connectionInProgress)
+ if (mConnectionInProgress)
return;
new Thread(new Runnable() {
@Override
public void run() {
- connectionInProgress = true;
+ mConnectionInProgress = true;
getBTSocketForSelectedPump();
if (mRfcommSocket == null || mBTDevice == null) {
- connectionInProgress = false;
+ mConnectionInProgress = false;
return; // Device not found
}
@@ -187,48 +152,11 @@ public class DanaRv2ExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED, 0));
}
- connectionInProgress = false;
+ mConnectionInProgress = false;
}
}).start();
}
- public void stopConnecting() {
- if (mSerialIOThread != null)
- mSerialIOThread.disconnect("stopConnecting");
- }
-
- private void getBTSocketForSelectedPump() {
- devName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- if (bluetoothAdapter != null) {
- Set bondedDevices = bluetoothAdapter.getBondedDevices();
-
- for (BluetoothDevice device : bondedDevices) {
- if (devName.equals(device.getName())) {
- mBTDevice = device;
- try {
- mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
- } catch (IOException e) {
- log.error("Error creating socket: ", e);
- }
- break;
- }
- }
- } else {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
- }
- if (mBTDevice == null) {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
- }
- }
-
- @Subscribe
- public void onStatusEvent(final EventPreferenceChange pch) {
- if (mSerialIOThread != null)
- mSerialIOThread.disconnect("EventPreferenceChange");
- }
-
public void getPumpStatus() {
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpstatus)));
@@ -238,7 +166,7 @@ public class DanaRv2ExecutionService extends Service {
MsgStatusBolusExtended_v2 exStatusMsg = new MsgStatusBolusExtended_v2();
MsgCheckValue_v2 checkValue = new MsgCheckValue_v2();
- if (danaRPump.isNewPump) {
+ if (mDanaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@@ -253,8 +181,8 @@ public class DanaRv2ExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingextendedbolusstatus)));
mSerialIOThread.sendMessage(exStatusMsg);
- Date now = new Date();
- if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) {
+ long now = System.currentTimeMillis();
+ if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
@@ -268,28 +196,27 @@ public class DanaRv2ExecutionService extends Service {
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
- long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
+ long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
- timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
+ timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
- danaRPump.lastSettingsRead = now;
+ mDanaRPump.lastSettingsRead = now;
}
loadEvents();
- danaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
- if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
- log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
+ if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
+ log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
- NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
+ NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
}
} catch (Exception e) {
log.error("Unhandled exception", e);
@@ -299,10 +226,10 @@ public class DanaRv2ExecutionService extends Service {
public boolean tempBasal(int percent, int durationInHours) {
if (!isConnected()) return false;
- if (danaRPump.isTempBasalInProgress) {
+ if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
- waitMsec(500);
+ SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
@@ -314,10 +241,10 @@ public class DanaRv2ExecutionService extends Service {
public boolean highTempBasal(int percent) {
if (!isConnected()) return false;
- if (danaRPump.isTempBasalInProgress) {
+ if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
- waitMsec(500);
+ SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetAPSTempBasalStart_v2(percent));
@@ -362,7 +289,7 @@ public class DanaRv2ExecutionService extends Service {
if (BolusProgressDialog.stopPressed) return false;
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.startingbolus)));
- bolusingTreatment = t;
+ mBolusingTreatment = t;
final int preferencesSpeed = SP.getInt(R.string.key_danars_bolusspeed, 0);
MessageBase start;
if (preferencesSpeed == 0)
@@ -390,7 +317,7 @@ public class DanaRv2ExecutionService extends Service {
return false;
}
while (!stop.stopped && !start.failed) {
- waitMsec(100);
+ SystemClock.sleep(100);
if ((System.currentTimeMillis() - progress.lastReceive) > 15 * 1000L) { // if i didn't receive status for more than 15 sec expecting broken comm
stop.stopped = true;
stop.forced = true;
@@ -403,7 +330,7 @@ public class DanaRv2ExecutionService extends Service {
bolusingEvent.t = t;
bolusingEvent.percent = 99;
- bolusingTreatment = null;
+ mBolusingTreatment = null;
int speed = 12;
switch (preferencesSpeed) {
case 0:
@@ -440,14 +367,14 @@ public class DanaRv2ExecutionService extends Service {
public void bolusStop() {
if (Config.logDanaBTComm)
- log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
+ log.debug("bolusStop >>>>> @ " + (mBolusingTreatment == null ? "" : mBolusingTreatment.insulin));
MsgBolusStop stop = new MsgBolusStop();
stop.forced = true;
if (isConnected()) {
mSerialIOThread.sendMessage(stop);
while (!stop.stopped) {
mSerialIOThread.sendMessage(stop);
- waitMsec(200);
+ SystemClock.sleep(200);
}
} else {
stop.stopped = true;
@@ -464,57 +391,10 @@ public class DanaRv2ExecutionService extends Service {
return true;
}
- public PumpEnactResult loadHistory(byte type) {
- PumpEnactResult result = new PumpEnactResult();
- if (!isConnected()) return result;
- MessageBase msg = null;
- switch (type) {
- case RecordTypes.RECORD_TYPE_ALARM:
- msg = new MsgHistoryAlarm();
- break;
- case RecordTypes.RECORD_TYPE_BASALHOUR:
- msg = new MsgHistoryBasalHour();
- break;
- case RecordTypes.RECORD_TYPE_BOLUS:
- msg = new MsgHistoryBolus();
- break;
- case RecordTypes.RECORD_TYPE_CARBO:
- msg = new MsgHistoryCarbo();
- break;
- case RecordTypes.RECORD_TYPE_DAILY:
- msg = new MsgHistoryDailyInsulin();
- break;
- case RecordTypes.RECORD_TYPE_ERROR:
- msg = new MsgHistoryError();
- break;
- case RecordTypes.RECORD_TYPE_GLUCOSE:
- msg = new MsgHistoryGlucose();
- break;
- case RecordTypes.RECORD_TYPE_REFILL:
- msg = new MsgHistoryRefill();
- break;
- case RecordTypes.RECORD_TYPE_SUSPEND:
- msg = new MsgHistorySuspend();
- break;
- }
- MsgHistoryDone done = new MsgHistoryDone();
- mSerialIOThread.sendMessage(new MsgPCCommStart());
- waitMsec(400);
- mSerialIOThread.sendMessage(msg);
- while (!done.received && mRfcommSocket.isConnected()) {
- waitMsec(100);
- }
- waitMsec(200);
- mSerialIOThread.sendMessage(new MsgPCCommStop());
- result.success = true;
- result.comment = "OK";
- return result;
- }
-
public PumpEnactResult loadEvents() {
if (!isConnected())
return new PumpEnactResult().success(false);
- waitMsec(300);
+ SystemClock.sleep(300);
MsgHistoryEvents_v2 msg;
if (lastHistoryFetched == 0) {
msg = new MsgHistoryEvents_v2();
@@ -525,13 +405,14 @@ public class DanaRv2ExecutionService extends Service {
}
mSerialIOThread.sendMessage(msg);
while (!msg.done && mRfcommSocket.isConnected()) {
- waitMsec(100);
+ SystemClock.sleep(100);
}
- waitMsec(200);
+ SystemClock.sleep(200);
if (MsgHistoryEvents_v2.lastEventTimeLoaded != 0)
lastHistoryFetched = MsgHistoryEvents_v2.lastEventTimeLoaded - 45 * 60 * 1000L; //always load last 45 min;
else
lastHistoryFetched = 0;
+ mDanaRPump.lastConnection = System.currentTimeMillis();
return new PumpEnactResult().success(true);
}
@@ -543,13 +424,10 @@ public class DanaRv2ExecutionService extends Service {
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
- danaRPump.lastSettingsRead = new Date(0); // force read full settings
+ mDanaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
}
- private void waitMsec(long msecs) {
- SystemClock.sleep(msecs);
- }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpFragment.java
index ebaf2b19dd..fc8d8f7356 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpFragment.java
@@ -18,6 +18,8 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.db.ExtendedBolus;
+import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.PumpVirtual.events.EventVirtualPumpUpdateGui;
@@ -81,13 +83,15 @@ public class VirtualPumpFragment extends SubscriberFragment {
public void run() {
VirtualPumpPlugin virtualPump = VirtualPumpPlugin.getPlugin();
basaBasalRateView.setText(virtualPump.getBaseBasalRate() + "U");
- if (MainApp.getConfigBuilder().isTempBasalInProgress()) {
- tempBasalView.setText(MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()).toStringFull());
+ TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
+ if (activeTemp != null) {
+ tempBasalView.setText(activeTemp.toStringFull());
} else {
tempBasalView.setText("");
}
- if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
- extendedBolusView.setText(MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString());
+ ExtendedBolus activeExtendedBolus = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
+ if (activeExtendedBolus != null) {
+ extendedBolusView.setText(activeExtendedBolus.toString());
} else {
extendedBolusView.setText("");
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityAAPS/SensitivityAAPSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityAAPS/SensitivityAAPSPlugin.java
index f02cdd9371..ebe8ddfe31 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityAAPS/SensitivityAAPSPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityAAPS/SensitivityAAPSPlugin.java
@@ -11,6 +11,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.List;
+import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
@@ -104,7 +105,7 @@ public class SensitivityAAPSPlugin implements PluginBase, SensitivityInterface{
@Override
public AutosensResult detectSensitivity(long fromTime, long toTime) {
- LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getAutosensDataTable();
+ LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
String age = SP.getString(R.string.key_age, "");
int defaultHours = 24;
@@ -118,7 +119,7 @@ public class SensitivityAAPSPlugin implements PluginBase, SensitivityInterface{
return new AutosensResult();
}
- AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
+ AutosensData current = IobCobCalculatorPlugin.getPlugin().getAutosensData(toTime); // this is running inside lock already
if (current == null) {
log.debug("No autosens data available");
return new AutosensResult();
@@ -191,8 +192,10 @@ public class SensitivityAAPSPlugin implements PluginBase, SensitivityInterface{
log.debug(ratioLimit);
}
- log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " percentile: " + percentile + " ratio: " + ratio);
- log.debug("Sensitivity to: deviations " + Arrays.toString(deviations));
+ if (Config.logAutosensData) {
+ log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " percentile: " + percentile + " ratio: " + ratio + " mealCOB: " + current.cob);
+ log.debug("Sensitivity to: deviations " + Arrays.toString(deviations));
+ }
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref0/SensitivityOref0Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref0/SensitivityOref0Plugin.java
index 9aedf22d44..eaabb4ecc9 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref0/SensitivityOref0Plugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref0/SensitivityOref0Plugin.java
@@ -7,8 +7,10 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.List;
+import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
@@ -102,7 +104,7 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
@Override
public AutosensResult detectSensitivity(long fromTime, long toTime) {
- LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getAutosensDataTable();
+ LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
String age = SP.getString(R.string.key_age, "");
int defaultHours = 24;
@@ -118,7 +120,7 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
return new AutosensResult();
}
- AutosensData current = IobCobCalculatorPlugin.getLastAutosensData("SensitivityOref0"); // this is running inside lock already
+ AutosensData current = IobCobCalculatorPlugin.getPlugin().getAutosensData(toTime); // this is running inside lock already
if (current == null) {
log.debug("No current autosens data available");
return new AutosensResult();
@@ -199,10 +201,8 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
log.debug(ratioLimit);
}
- double newisf = Math.round(Profile.toMgdl(sens, profile.getUnits()) / ratio);
- if (ratio != 1) {
- log.debug("ISF adjusted from " + Profile.toMgdl(sens, profile.getUnits()) + " to " + newisf);
- }
+ if (Config.logAutosensData)
+ log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " ratio: " + ratio + " mealCOB: " + current.cob);
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityWeightedAverage/SensitivityWeightedAveragePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityWeightedAverage/SensitivityWeightedAveragePlugin.java
index 046cd056fa..91053e2654 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityWeightedAverage/SensitivityWeightedAveragePlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityWeightedAverage/SensitivityWeightedAveragePlugin.java
@@ -101,7 +101,7 @@ public class SensitivityWeightedAveragePlugin implements PluginBase, Sensitivity
@Override
public AutosensResult detectSensitivity(long fromTime, long toTime) {
- LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getAutosensDataTable();
+ LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
String age = SP.getString(R.string.key_age, "");
int defaultHours = 24;
@@ -116,7 +116,7 @@ public class SensitivityWeightedAveragePlugin implements PluginBase, Sensitivity
return new AutosensResult();
}
- AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
+ AutosensData current = IobCobCalculatorPlugin.getPlugin().getAutosensData(toTime); // this is running inside lock already
if (current == null) {
if (Config.logAutosensData)
log.debug("No autosens data available");
@@ -217,7 +217,7 @@ public class SensitivityWeightedAveragePlugin implements PluginBase, Sensitivity
}
if (Config.logAutosensData)
- log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " weightedaverage: " + average + " ratio: " + ratio);
+ log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " weightedaverage: " + average + " ratio: " + ratio + " mealCOB: " + current.cob);
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceDexcomG5/SourceDexcomG5Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceDexcomG5/SourceDexcomG5Plugin.java
index 04f5700dae..8b9734cb79 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceDexcomG5/SourceDexcomG5Plugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceDexcomG5/SourceDexcomG5Plugin.java
@@ -39,8 +39,7 @@ public class SourceDexcomG5Plugin implements PluginBase, BgSourceInterface {
@Override
public String getNameShort() {
- // use long name as fallback (no tabs)
- return getName();
+ return MainApp.gs(R.string.dexcomG5_shortname);
}
@Override
@@ -82,4 +81,9 @@ public class SourceDexcomG5Plugin implements PluginBase, BgSourceInterface {
public int getPreferencesId() {
return R.xml.pref_dexcomg5;
}
+
+ @Override
+ public boolean advancedFilteringSupported() {
+ return true;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java
index 51fd755b07..eb9a6b1c6b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java
@@ -83,4 +83,8 @@ public class SourceGlimpPlugin implements PluginBase, BgSourceInterface {
}
+ @Override
+ public boolean advancedFilteringSupported() {
+ return false;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java
index e530dd563b..1111c8c9eb 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java
@@ -83,4 +83,8 @@ public class SourceMM640gPlugin implements PluginBase, BgSourceInterface {
}
+ @Override
+ public boolean advancedFilteringSupported() {
+ return false;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java
index 1928448f0e..f43c44047e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java
@@ -85,4 +85,8 @@ public class SourceNSClientPlugin implements PluginBase, BgSourceInterface {
}
+ @Override
+ public boolean advancedFilteringSupported() {
+ return true;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java
index 7f73d457e7..532492d40e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java
@@ -84,4 +84,8 @@ public class SourceXdripPlugin implements PluginBase, BgSourceInterface {
}
+ @Override
+ public boolean advancedFilteringSupported() {
+ return false;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java
index 6fcbcfe951..b10ad96697 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java
@@ -20,6 +20,7 @@ import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Treatments.fragments.TreatmentsBolusFragment;
+import info.nightscout.androidaps.plugins.Treatments.fragments.TreatmentsCareportalFragment;
import info.nightscout.androidaps.plugins.Treatments.fragments.TreatmentsExtendedBolusesFragment;
import info.nightscout.androidaps.plugins.Treatments.fragments.TreatmentsProfileSwitchFragment;
import info.nightscout.androidaps.plugins.Treatments.fragments.TreatmentsTempTargetFragment;
@@ -33,6 +34,7 @@ public class TreatmentsFragment extends SubscriberFragment implements View.OnCli
TextView tempBasalsTab;
TextView tempTargetTab;
TextView profileSwitchTab;
+ TextView careportalTab;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -45,11 +47,13 @@ public class TreatmentsFragment extends SubscriberFragment implements View.OnCli
tempBasalsTab = (TextView) view.findViewById(R.id.treatments_tempbasals);
tempTargetTab = (TextView) view.findViewById(R.id.treatments_temptargets);
profileSwitchTab = (TextView) view.findViewById(R.id.treatments_profileswitches);
+ careportalTab = (TextView) view.findViewById(R.id.treatments_careportal);
treatmentsTab.setOnClickListener(this);
extendedBolusesTab.setOnClickListener(this);
tempBasalsTab.setOnClickListener(this);
tempTargetTab.setOnClickListener(this);
profileSwitchTab.setOnClickListener(this);
+ careportalTab.setOnClickListener(this);
setFragment(new TreatmentsBolusFragment());
setBackgroundColorOnSelected(treatmentsTab);
@@ -87,6 +91,10 @@ public class TreatmentsFragment extends SubscriberFragment implements View.OnCli
setFragment(new TreatmentsProfileSwitchFragment());
setBackgroundColorOnSelected(profileSwitchTab);
break;
+ case R.id.treatments_careportal:
+ setFragment(new TreatmentsCareportalFragment());
+ setBackgroundColorOnSelected(careportalTab);
+ break;
}
}
@@ -104,6 +112,7 @@ public class TreatmentsFragment extends SubscriberFragment implements View.OnCli
tempBasalsTab.setBackgroundColor(MainApp.sResources.getColor(R.color.defaultbackground));
tempTargetTab.setBackgroundColor(MainApp.sResources.getColor(R.color.defaultbackground));
profileSwitchTab.setBackgroundColor(MainApp.sResources.getColor(R.color.defaultbackground));
+ careportalTab.setBackgroundColor(MainApp.sResources.getColor(R.color.defaultbackground));
selected.setBackgroundColor(MainApp.sResources.getColor(R.color.tabBgColorSelected));
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java
index 900eba7a40..1842d3b504 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java
@@ -8,6 +8,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Config;
@@ -197,6 +198,8 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
Iob tIOB = t.iobCalc(time, dia);
total.iob += tIOB.iobContrib;
total.activity += tIOB.activityContrib;
+ if (t.date > total.lastBolusTime)
+ total.lastBolusTime = t.date;
if (!t.isSMB) {
// instead of dividing the DIA that only worked on the bilinear curves,
// multiply the time the treatment is seen active.
@@ -204,9 +207,6 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
long snoozeTime = t.date + (long) (timeSinceTreatment * SP.getDouble("openapsama_bolussnooze_dia_divisor", 2.0));
Iob bIOB = t.iobCalc(snoozeTime, dia);
total.bolussnooze += bIOB.iobContrib;
- } else {
- total.basaliob += t.insulin;
- total.microBolusIOB += tIOB.iobContrib;
}
}
@@ -244,6 +244,7 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
if (t > dia_ago && t <= now) {
if (treatment.carbs >= 1) {
result.carbs += treatment.carbs;
+ result.lastCarbTime = t;
}
if (treatment.insulin > 0 && treatment.mealBolus) {
result.boluses += treatment.insulin;
@@ -251,10 +252,13 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
}
}
- AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensDataSynchronized("getMealData()");
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensDataSynchronized("getMealData()");
if (autosensData != null) {
result.mealCOB = autosensData.cob;
+ result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation;
+ result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation;
}
+ result.lastBolusTime = getLastBolusTime();
return result;
}
@@ -276,6 +280,18 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
return in5minback;
}
+ @Override
+ public long getLastBolusTime() {
+ long now = System.currentTimeMillis();
+ long last = 0;
+ for (Treatment t : treatments) {
+ if (t.date > last && t.insulin > 0 && t.isValid && t.date <= now)
+ last = t.date;
+ }
+ log.debug("Last bolus time: " + new Date(last).toLocaleString());
+ return last;
+ }
+
@Override
public boolean isInHistoryRealTempBasalInProgress() {
return getRealTempBasalFromHistory(System.currentTimeMillis()) != null;
@@ -327,6 +343,12 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
IobTotal calc = t.iobCalc(time);
//log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basaliob);
total.plus(calc);
+ if (!t.isEndingEvent()) {
+ total.lastTempDate = t.date;
+ total.lastTempDuration = t.durationInMinutes;
+ total.lastTempRate = t.tempBasalConvertedToAbsolute(t.date);
+ }
+
}
}
if (ConfigBuilderPlugin.getActivePump().isFakingTempsByExtendedBoluses()) {
@@ -337,6 +359,12 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
if (e.date > time) continue;
IobTotal calc = e.iobCalc(time);
totalExt.plus(calc);
+ TemporaryBasal t = new TemporaryBasal(e);
+ if (!t.isEndingEvent() && t.date > total.lastTempDate) {
+ total.lastTempDate = t.date;
+ total.lastTempDuration = t.durationInMinutes;
+ total.lastTempRate = t.tempBasalConvertedToAbsolute(t.date);
+ }
}
}
// Convert to basal iob
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsBolusFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsBolusFragment.java
index d096fd8549..99c89f0706 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsBolusFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsBolusFragment.java
@@ -81,7 +81,7 @@ public class TreatmentsBolusFragment extends SubscriberFragment implements View.
Iob iob = t.iobCalc(System.currentTimeMillis(), profile.getDia());
holder.iob.setText(DecimalFormatter.to2Decimal(iob.iobContrib) + " U");
holder.activity.setText(DecimalFormatter.to3Decimal(iob.activityContrib) + " U");
- holder.mealOrCorrection.setText(t.mealBolus ? MainApp.sResources.getString(R.string.mealbolus) : MainApp.sResources.getString(R.string.correctionbous));
+ holder.mealOrCorrection.setText(t.isSMB ? "SMB" : t.mealBolus ? MainApp.sResources.getString(R.string.mealbolus) : MainApp.sResources.getString(R.string.correctionbous));
holder.ph.setVisibility(t.source == Source.PUMP ? View.VISIBLE : View.GONE);
holder.ns.setVisibility(NSUpload.isIdValid(t._id) ? View.VISIBLE : View.GONE);
holder.invalid.setVisibility(t.isValid ? View.GONE : View.VISIBLE);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsCareportalFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsCareportalFragment.java
new file mode 100644
index 0000000000..7218198b43
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsCareportalFragment.java
@@ -0,0 +1,192 @@
+package info.nightscout.androidaps.plugins.Treatments.fragments;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.CardView;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.squareup.otto.Subscribe;
+
+import java.util.List;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.Services.Intents;
+import info.nightscout.androidaps.db.CareportalEvent;
+import info.nightscout.androidaps.events.EventCareportalEventChange;
+import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
+import info.nightscout.androidaps.plugins.NSClientInternal.UploadQueue;
+import info.nightscout.utils.DateUtil;
+import info.nightscout.utils.NSUpload;
+import info.nightscout.utils.SP;
+import info.nightscout.utils.Translator;
+
+/**
+ * Created by mike on 13/01/17.
+ */
+
+public class TreatmentsCareportalFragment extends SubscriberFragment implements View.OnClickListener {
+
+ RecyclerView recyclerView;
+ LinearLayoutManager llm;
+ Button refreshFromNS;
+
+ Context context;
+
+ public class RecyclerViewAdapter extends RecyclerView.Adapter {
+
+ List careportalEventList;
+
+ RecyclerViewAdapter(List careportalEventList) {
+ this.careportalEventList = careportalEventList;
+ }
+
+ @Override
+ public CareportalEventsViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+ View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.treatments_careportal_item, viewGroup, false);
+ CareportalEventsViewHolder CareportalEventsViewHolder = new CareportalEventsViewHolder(v);
+ return CareportalEventsViewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(CareportalEventsViewHolder holder, int position) {
+ CareportalEvent careportalEvent = careportalEventList.get(position);
+ holder.ns.setVisibility(NSUpload.isIdValid(careportalEvent._id) ? View.VISIBLE : View.GONE);
+ holder.date.setText(DateUtil.dateAndTimeString(careportalEvent.date));
+ holder.note.setText(careportalEvent.getNotes());
+ holder.type.setText(Translator.translate(careportalEvent.eventType));
+ holder.remove.setTag(careportalEvent);
+ }
+
+ @Override
+ public int getItemCount() {
+ return careportalEventList.size();
+ }
+
+ @Override
+ public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+ super.onAttachedToRecyclerView(recyclerView);
+ }
+
+ public class CareportalEventsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+ CardView cv;
+ TextView date;
+ TextView type;
+ TextView note;
+ TextView remove;
+ TextView ns;
+
+ CareportalEventsViewHolder(View itemView) {
+ super(itemView);
+ cv = (CardView) itemView.findViewById(R.id.careportal_cardview);
+ date = (TextView) itemView.findViewById(R.id.careportal_date);
+ type = (TextView) itemView.findViewById(R.id.careportal_type);
+ note = (TextView) itemView.findViewById(R.id.careportal_note);
+ ns = (TextView) itemView.findViewById(R.id.ns_sign);
+ remove = (TextView) itemView.findViewById(R.id.careportal_remove);
+ remove.setOnClickListener(this);
+ remove.setPaintFlags(remove.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
+ }
+
+ @Override
+ public void onClick(View v) {
+ final CareportalEvent careportalEvent = (CareportalEvent) v.getTag();
+ switch (v.getId()) {
+ case R.id.careportal_remove:
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(MainApp.sResources.getString(R.string.confirmation));
+ builder.setMessage(MainApp.sResources.getString(R.string.removerecord) + "\n" + DateUtil.dateAndTimeString(careportalEvent.date));
+ builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ final String _id = careportalEvent._id;
+ if (NSUpload.isIdValid(_id)) {
+ NSUpload.removeCareportalEntryFromNS(_id);
+ } else {
+ UploadQueue.removeID("dbAdd", _id);
+ }
+ MainApp.getDbHelper().delete(careportalEvent);
+ }
+ });
+ builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null);
+ builder.show();
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.treatments_careportal_fragment, container, false);
+
+ recyclerView = (RecyclerView) view.findViewById(R.id.careportal_recyclerview);
+ recyclerView.setHasFixedSize(true);
+ llm = new LinearLayoutManager(view.getContext());
+ recyclerView.setLayoutManager(llm);
+
+ RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEventsFromTime(false));
+ recyclerView.setAdapter(adapter);
+
+ refreshFromNS = (Button) view.findViewById(R.id.careportal_refreshfromnightscout);
+ refreshFromNS.setOnClickListener(this);
+
+ context = getContext();
+
+ boolean nsUploadOnly = SP.getBoolean(R.string.key_ns_upload_only, false);
+ if (nsUploadOnly)
+ refreshFromNS.setVisibility(View.GONE);
+
+ updateGUI();
+ return view;
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.careportal_refreshfromnightscout:
+ AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
+ builder.setTitle(this.getContext().getString(R.string.confirmation));
+ builder.setMessage(this.getContext().getString(R.string.refresheventsfromnightscout) + " ?");
+ builder.setPositiveButton(this.getContext().getString(R.string.ok), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ MainApp.getDbHelper().resetCareportalEvents();
+ Intent restartNSClient = new Intent(Intents.ACTION_RESTART);
+ MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient);
+ }
+ });
+ builder.setNegativeButton(this.getContext().getString(R.string.cancel), null);
+ builder.show();
+ break;
+ }
+
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventCareportalEventChange ev) {
+ updateGUI();
+ }
+
+ @Override
+ protected void updateGUI() {
+ Activity activity = getActivity();
+ if (activity != null)
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEventsFromTime(false)), false);
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java
index da276af3c2..febd7509f5 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java
@@ -44,6 +44,7 @@ import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.BolusWizard;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
+import info.nightscout.utils.HardLimits;
import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse;
import info.nightscout.utils.ToastUtils;
@@ -149,11 +150,11 @@ public class ActionStringHandler {
low *= Constants.MMOLL_TO_MGDL;
high *= Constants.MMOLL_TO_MGDL;
}
- if (low < Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
+ if (low < HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
sendError("Min-BG out of range!");
return;
}
- if (high < Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
+ if (high < HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
sendError("Max-BG out of range!");
return;
}
@@ -503,7 +504,7 @@ public class ActionStringHandler {
return "Last result not available!";
}
- if (!result.changeRequested) {
+ if (!result.isChangeRequested()) {
ret += MainApp.sResources.getString(R.string.nochangerequested) + "\n";
} else if (result.rate == 0 && result.duration == 0) {
ret += MainApp.sResources.getString(R.string.canceltemp) + "\n";
@@ -577,18 +578,18 @@ public class ActionStringHandler {
//check for validity
if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
- msg += String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Percentage") + "\n";
+ msg += String.format(MainApp.sResources.getString(R.string.valueoutofrange), "Profile-Percentage") + "\n";
}
if (timeshift < 0 || timeshift > 23) {
- msg += String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Timeshift") + "\n";
+ msg += String.format(MainApp.sResources.getString(R.string.valueoutofrange), "Profile-Timeshift") + "\n";
}
final Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null || profile.getBasal() == null) {
- msg += MainApp.sResources.getString(R.string.cpp_notloadedplugins) + "\n";
+ msg += MainApp.sResources.getString(R.string.notloadedplugins) + "\n";
}
if (!"".equals(msg)) {
- msg += MainApp.sResources.getString(R.string.cpp_valuesnotstored);
+ msg += MainApp.sResources.getString(R.string.valuesnotstored);
String rTitle = "STATUS";
String rAction = "statusmessage";
WearPlugin.getPlugin().requestActionConfirmation(rTitle, msg, rAction);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java
index 3316d68d12..b72a767278 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java
@@ -197,10 +197,12 @@ public class WearPlugin implements PluginBase {
@Subscribe
public void onStatusEvent(final EventOverviewBolusProgress ev) {
- Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
- intent.putExtra("progresspercent", ev.percent);
- intent.putExtra("progressstatus", ev.status);
- ctx.startService(intent);
+ if(!ev.isSMB()||SP.getBoolean("wear_notifySMB", false)) {
+ Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
+ intent.putExtra("progresspercent", ev.percent);
+ intent.putExtra("progressstatus", ev.status);
+ ctx.startService(intent);
+ }
}
@Subscribe
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java
index 65b5a2557d..74423fe7ac 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java
@@ -523,27 +523,31 @@ public class WatchUpdaterService extends WearableListenerService implements
private void sendStatus() {
if (googleApiClient.isConnected()) {
-
- TreatmentsInterface treatmentsInterface = MainApp.getConfigBuilder();
- treatmentsInterface.updateTotalIOBTreatments();
- IobTotal bolusIob = treatmentsInterface.getLastCalculationTreatments().round();
- treatmentsInterface.updateTotalIOBTempBasals();
- IobTotal basalIob = treatmentsInterface.getLastCalculationTempBasals().round();
-
- String iobSum = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob);
- String iobDetail = "(" + DecimalFormatter.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.to2Decimal(basalIob.basaliob) + ")";
- String cobString = generateCOBString();
- String currentBasal = generateBasalString(treatmentsInterface);
-
- //bgi
- String bgiString = "";
Profile profile = MainApp.getConfigBuilder().getProfile();
+ String status = MainApp.instance().getString(R.string.noprofile);
+ String iobSum, iobDetail, cobString, currentBasal, bgiString;
+ iobSum = iobDetail = cobString = currentBasal = bgiString = "";
if(profile!=null) {
+ TreatmentsInterface treatmentsInterface = MainApp.getConfigBuilder();
+ treatmentsInterface.updateTotalIOBTreatments();
+ IobTotal bolusIob = treatmentsInterface.getLastCalculationTreatments().round();
+ treatmentsInterface.updateTotalIOBTempBasals();
+ IobTotal basalIob = treatmentsInterface.getLastCalculationTempBasals().round();
+
+ iobSum = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob);
+ iobDetail = "(" + DecimalFormatter.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.to2Decimal(basalIob.basaliob) + ")";
+ cobString = generateCOBString();
+ currentBasal = generateBasalString(treatmentsInterface);
+
+ //bgi
+
+
double bgi = -(bolusIob.activity + basalIob.activity) * 5 * profile.getIsf();
bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.to1Decimal(bgi);
+
+ status = generateStatusString(profile, currentBasal,iobSum, iobDetail, bgiString);
}
- String status = generateStatusString(profile, currentBasal,iobSum, iobDetail, bgiString);
//batteries
int phoneBattery = getBatteryLevel(getApplicationContext());
@@ -637,6 +641,11 @@ public class WatchUpdaterService extends WearableListenerService implements
private String generateBasalString(TreatmentsInterface treatmentsInterface) {
String basalStringResult;
+
+ Profile profile = MainApp.getConfigBuilder().getProfile();
+ if (profile == null)
+ return "";
+
TemporaryBasal activeTemp = treatmentsInterface.getTempBasalFromHistory(System.currentTimeMillis());
if (activeTemp != null) {
basalStringResult = activeTemp.toStringShort();
@@ -644,7 +653,7 @@ public class WatchUpdaterService extends WearableListenerService implements
if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false)) {
basalStringResult = "100%";
} else {
- basalStringResult = DecimalFormatter.to2Decimal(MainApp.getConfigBuilder().getProfile().getBasal()) + "U/h";
+ basalStringResult = DecimalFormatter.to2Decimal(profile.getBasal()) + "U/h";
}
}
return basalStringResult;
@@ -654,7 +663,7 @@ public class WatchUpdaterService extends WearableListenerService implements
private String generateCOBString() {
String cobStringResult = "--";
- AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData("WatcherUpdaterService");
+ AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensData("WatcherUpdaterService");
if (autosensData != null) {
cobStringResult = (int) autosensData.cob + "g";
}
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java
index 04da1cd9a9..b41a1727b3 100644
--- a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java
+++ b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java
@@ -32,6 +32,7 @@ import info.nightscout.androidaps.queue.commands.CommandExtendedBolus;
import info.nightscout.androidaps.queue.commands.CommandLoadEvents;
import info.nightscout.androidaps.queue.commands.CommandLoadHistory;
import info.nightscout.androidaps.queue.commands.CommandReadStatus;
+import info.nightscout.androidaps.queue.commands.CommandSMBBolus;
import info.nightscout.androidaps.queue.commands.CommandSetProfile;
import info.nightscout.androidaps.queue.commands.CommandTempBasalAbsolute;
import info.nightscout.androidaps.queue.commands.CommandTempBasalPercent;
@@ -151,30 +152,35 @@ public class CommandQueue {
// returns true if command is queued
public boolean bolus(DetailedBolusInfo detailedBolusInfo, Callback callback) {
- if (isRunning(Command.CommandType.BOLUS)) {
+ Command.CommandType type = detailedBolusInfo.isSMB ? Command.CommandType.SMB_BOLUS : Command.CommandType.BOLUS;
+
+ if (isRunning(type)) {
if (callback != null)
callback.result(executingNowError()).run();
return false;
}
// remove all unfinished boluses
- removeAll(Command.CommandType.BOLUS);
+ removeAll(type);
// apply constraints
detailedBolusInfo.insulin = MainApp.getConfigBuilder().applyBolusConstraints(detailedBolusInfo.insulin);
detailedBolusInfo.carbs = MainApp.getConfigBuilder().applyCarbsConstraints((int) detailedBolusInfo.carbs);
// add new command to queue
- add(new CommandBolus(detailedBolusInfo, callback));
+ if (detailedBolusInfo.isSMB) {
+ add(new CommandSMBBolus(detailedBolusInfo, callback));
+ } else {
+ add(new CommandBolus(detailedBolusInfo, callback));
+ // Bring up bolus progress dialog (start here, so the dialog is shown when the bolus is requested,
+ // not when the Bolus command is starting. The command closes the dialog upon completion).
+ showBolusProgressDialog(detailedBolusInfo.insulin, detailedBolusInfo.context);
+ // Notify Wear about upcoming bolus
+ MainApp.bus().post(new EventBolusRequested(detailedBolusInfo.insulin));
+ }
notifyAboutNewCommand();
- // Notify Wear about upcoming bolus
- MainApp.bus().post(new EventBolusRequested(detailedBolusInfo.insulin));
-
- // Bring up bolus progress dialog
- showBolusProgressDialog(detailedBolusInfo.insulin, detailedBolusInfo.context);
-
return true;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java
index cf89bff194..10efffffe8 100644
--- a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java
+++ b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java
@@ -16,6 +16,8 @@ import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissBolusprogressIfRunning;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.queue.events.EventQueueChanged;
import info.nightscout.utils.SP;
@@ -53,12 +55,6 @@ public class QueueThread extends Thread {
while (true) {
PumpInterface pump = ConfigBuilderPlugin.getActivePump();
long secondsElapsed = (System.currentTimeMillis() - connectionStartTime) / 1000;
- if (pump.isConnecting()) {
- log.debug("QUEUE: connecting " + secondsElapsed);
- MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTING, (int) secondsElapsed));
- SystemClock.sleep(1000);
- continue;
- }
if (!pump.isConnected() && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) {
MainApp.bus().post(new EventDismissBolusprogressIfRunning(null));
@@ -75,19 +71,37 @@ public class QueueThread extends Thread {
//write time
SP.putLong(R.string.key_btwatchdog_lastbark, System.currentTimeMillis());
//toggle BT
+ pump.stopConnecting();
+ pump.disconnect("watchdog");
+ SystemClock.sleep(1000);
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.disable();
SystemClock.sleep(1000);
mBluetoothAdapter.enable();
SystemClock.sleep(1000);
//start over again once after watchdog barked
+ //Notification notification = new Notification(Notification.OLD_NSCLIENT, "Watchdog", Notification.URGENT);
+ //MainApp.bus().post(new EventNewNotification(notification));
connectionStartTime = lastCommandTime = System.currentTimeMillis();
+ pump.connect("watchdog");
} else {
queue.clear();
+ log.debug("QUEUE: no connection possible");
+ MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
+ pump.disconnect("Queue empty");
+ MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
return;
}
}
+ if (pump.isConnecting()) {
+ log.debug("QUEUE: connecting " + secondsElapsed);
+ MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTING, (int) secondsElapsed));
+ SystemClock.sleep(1000);
+ continue;
+ }
+
+
if (!pump.isConnected()) {
log.debug("QUEUE: connect");
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTING, (int) secondsElapsed));
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/Command.java b/app/src/main/java/info/nightscout/androidaps/queue/commands/Command.java
index 5129c7983f..8875ff84a8 100644
--- a/app/src/main/java/info/nightscout/androidaps/queue/commands/Command.java
+++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/Command.java
@@ -11,6 +11,7 @@ import info.nightscout.androidaps.queue.Callback;
public abstract class Command {
public enum CommandType {
BOLUS,
+ SMB_BOLUS,
TEMPBASAL,
EXTENDEDBOLUS,
BASALPROFILE,
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSMBBolus.java b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSMBBolus.java
new file mode 100644
index 0000000000..e1b268106a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSMBBolus.java
@@ -0,0 +1,46 @@
+package info.nightscout.androidaps.queue.commands;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.data.DetailedBolusInfo;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissBolusprogressIfRunning;
+import info.nightscout.androidaps.queue.Callback;
+import info.nightscout.utils.DecimalFormatter;
+
+/**
+ * Created by mike on 09.11.2017.
+ */
+
+public class CommandSMBBolus extends Command {
+ private static Logger log = LoggerFactory.getLogger(CommandSMBBolus.class);
+ DetailedBolusInfo detailedBolusInfo;
+
+ public CommandSMBBolus(DetailedBolusInfo detailedBolusInfo, Callback callback) {
+ commandType = CommandType.SMB_BOLUS;
+ this.detailedBolusInfo = detailedBolusInfo;
+ this.callback = callback;
+ }
+
+ @Override
+ public void execute() {
+ PumpEnactResult r;
+ if (detailedBolusInfo.deliverAt != 0 && detailedBolusInfo.deliverAt + 60 * 1000L > System.currentTimeMillis())
+ r = ConfigBuilderPlugin.getActivePump().deliverTreatment(detailedBolusInfo);
+ else {
+ r = new PumpEnactResult().enacted(false).success(false).comment("SMB request too old");
+ log.debug("SMB bolus canceled. delivetAt=" + detailedBolusInfo.deliverAt + " now=" + System.currentTimeMillis());
+ }
+
+ if (callback != null)
+ callback.result(r).run();
+ }
+
+ public String status() {
+ return "SMBBOLUS " + DecimalFormatter.to1Decimal(detailedBolusInfo.insulin) + "U";
+ }
+}
diff --git a/app/src/main/java/info/nightscout/utils/HardLimits.java b/app/src/main/java/info/nightscout/utils/HardLimits.java
index ff92cf2e87..1b39951b85 100644
--- a/app/src/main/java/info/nightscout/utils/HardLimits.java
+++ b/app/src/main/java/info/nightscout/utils/HardLimits.java
@@ -1,5 +1,8 @@
package info.nightscout.utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
@@ -8,17 +11,90 @@ import info.nightscout.androidaps.R;
*/
public class HardLimits {
- final static double MAXBOLUS_ADULT = 17d;
- final static double MAXBOLUS_TEENAGE = 10d;
- final static double MAXBOLUS_CHILD = 5d;
+ private static Logger log = LoggerFactory.getLogger(HardLimits.class);
- public static double maxBolus() {
- String age = SP.getString(R.string.key_age, "");
+ final static int CHILD = 0;
+ final static int TEENAGE = 1;
+ final static int ADULT = 2;
+ final static int RESISTANTADULT = 3;
- if (age.equals(MainApp.sResources.getString(R.string.key_adult))) return MAXBOLUS_ADULT;
- if (age.equals(MainApp.sResources.getString(R.string.key_teenage))) return MAXBOLUS_TEENAGE;
- if (age.equals(MainApp.sResources.getString(R.string.key_child))) return MAXBOLUS_CHILD;
- return MAXBOLUS_ADULT;
+ final static double[] MAXBOLUS = {5d, 10d, 17d, 21d};
+
+ // 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};
+
+ public static final double MINDIA = 2;
+ public static final double MAXDIA = 7;
+
+ public static final double MINIC = 2;
+ public static final double MAXIC = 100;
+
+ public static final double MINISF = 2; // mgdl
+ public static final double MAXISF = 720; // mgdl
+
+ public static final double[] MAXIOB_AMA = {3, 5, 7, 7};
+ public static final double[] MAXIOB_SMB = {3, 6, 10, 12};
+
+ public static final double[] MAXBASAL = {2, 5, 10, 12};
+
+
+ private static int loadAge() {
+ String sp_age = SP.getString(R.string.key_age, "");
+ int age;
+
+ if (sp_age.equals(MainApp.sResources.getString(R.string.key_child)))
+ age = CHILD;
+ else if (sp_age.equals(MainApp.sResources.getString(R.string.key_teenage)))
+ age = TEENAGE;
+ else if (sp_age.equals(MainApp.sResources.getString(R.string.key_adult)))
+ age = ADULT;
+ else if (sp_age.equals(MainApp.sResources.getString(R.string.key_resistantadult)))
+ age = RESISTANTADULT;
+ else age = ADULT;
+
+ return age;
}
+ public static double maxBolus() {
+ return MAXBOLUS[loadAge()];
+ }
+
+ public static double maxIobAMA() {
+ return MAXIOB_AMA[loadAge()];
+ }
+
+ public static double maxIobSMB() {
+ return MAXIOB_SMB[loadAge()];
+ }
+
+ public static double maxBasal() {
+ return MAXBASAL[loadAge()];
+ }
+
+ // safety checks
+ public static boolean checkOnlyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
+ return value.equals(verifyHardLimits(value, valueName, lowLimit, highLimit));
+ }
+
+ public static Double verifyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
+ Double newvalue = value;
+ if (newvalue < lowLimit || newvalue > highLimit) {
+ newvalue = Math.max(newvalue, lowLimit);
+ newvalue = Math.min(newvalue, highLimit);
+ String msg = String.format(MainApp.sResources.getString(R.string.valueoutofrange), valueName);
+ msg += ".\n";
+ msg += String.format(MainApp.sResources.getString(R.string.valuelimitedto), value, newvalue);
+ log.error(msg);
+ NSUpload.uploadError(msg);
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
+ }
+ return newvalue;
+ }
}
diff --git a/app/src/main/java/info/nightscout/utils/LocalAlertUtils.java b/app/src/main/java/info/nightscout/utils/LocalAlertUtils.java
index e74818d447..915d8bfb27 100644
--- a/app/src/main/java/info/nightscout/utils/LocalAlertUtils.java
+++ b/app/src/main/java/info/nightscout/utils/LocalAlertUtils.java
@@ -1,9 +1,7 @@
package info.nightscout.utils;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Date;
@@ -17,13 +15,14 @@ import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
-import info.nightscout.androidaps.receivers.KeepAliveReceiver;
/**
* Created by adrian on 17/12/17.
*/
public class LocalAlertUtils {
+ private static Logger log = LoggerFactory.getLogger(LocalAlertUtils.class);
+
public static int missedReadingsThreshold() {
return SP.getInt(MainApp.sResources.getString(R.string.key_missed_bg_readings_threshold), 30) * 60 * 1000;
}
@@ -34,14 +33,18 @@ public class LocalAlertUtils {
public static void checkPumpUnreachableAlarm(Date lastConnection, boolean isStatusOutdated) {
boolean alarmTimeoutExpired = lastConnection.getTime() + pumpUnreachableThreshold() < System.currentTimeMillis();
- boolean nextAlarmOccurrenceReached = SP.getLong("nextPumpDisconnectedAlarm", 0l) < System.currentTimeMillis();
+ boolean nextAlarmOccurrenceReached = SP.getLong("nextPumpDisconnectedAlarm", 0L) < System.currentTimeMillis();
if (Config.APS && SP.getBoolean(MainApp.sResources.getString(R.string.key_enable_pump_unreachable_alert), true)
&& isStatusOutdated && alarmTimeoutExpired && nextAlarmOccurrenceReached && !ConfigBuilderPlugin.getActiveLoop().isDisconnected()) {
+ log.debug("Generating pump unreachable alarm. lastConnection: " + DateUtil.dateAndTimeString(lastConnection) + " isStatusOutdated: " + isStatusOutdated);
Notification n = new Notification(Notification.PUMP_UNREACHABLE, MainApp.sResources.getString(R.string.pump_unreachable), Notification.URGENT);
n.soundId = R.raw.alarm;
SP.putLong("nextPumpDisconnectedAlarm", System.currentTimeMillis() + pumpUnreachableThreshold());
MainApp.bus().post(new EventNewNotification(n));
+ if (SP.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) {
+ NSUpload.uploadError(n.text);
+ }
}
}
@@ -91,6 +94,9 @@ public class LocalAlertUtils {
n.soundId = R.raw.alarm;
SP.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold());
MainApp.bus().post(new EventNewNotification(n));
+ if (SP.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) {
+ NSUpload.uploadError(n.text);
+ }
}
}
}
diff --git a/app/src/main/java/info/nightscout/utils/NSUpload.java b/app/src/main/java/info/nightscout/utils/NSUpload.java
index 2ec3a57dd6..690b239128 100644
--- a/app/src/main/java/info/nightscout/utils/NSUpload.java
+++ b/app/src/main/java/info/nightscout/utils/NSUpload.java
@@ -199,17 +199,8 @@ public class NSUpload {
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun));
deviceStatus.suggested = apsResult.json();
- if (lastRun.request instanceof DetermineBasalResultMA) {
- DetermineBasalResultMA result = (DetermineBasalResultMA) lastRun.request;
- deviceStatus.iob = result.iob.json();
- deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
- }
-
- if (lastRun.request instanceof DetermineBasalResultAMA) {
- DetermineBasalResultAMA result = (DetermineBasalResultAMA) lastRun.request;
- deviceStatus.iob = result.iob.json();
- deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
- }
+ deviceStatus.iob = lastRun.request.iob.json();
+ deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
if (lastRun.setByPump != null && lastRun.setByPump.enacted) { // enacted
deviceStatus.enacted = lastRun.request.json();
@@ -408,6 +399,7 @@ public class NSUpload {
try {
data.put("eventType", "Announcement");
data.put("created_at", DateUtil.toISOString(new Date()));
+ data.put("enteredBy", SP.getString("careportal_enteredby", MainApp.gs(R.string.app_name)));
data.put("notes", error);
data.put("isAnnouncement", true);
} catch (JSONException e) {
diff --git a/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so b/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so
deleted file mode 100644
index 69e283b5fe..0000000000
Binary files a/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so b/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so
deleted file mode 100644
index 0c717bc3e8..0000000000
Binary files a/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/armeabi/libBleCommandUtil.so b/app/src/main/jniLibs/armeabi/libBleCommandUtil.so
deleted file mode 100644
index a51a8c7d9a..0000000000
Binary files a/app/src/main/jniLibs/armeabi/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/mips/libBleCommandUtil.so b/app/src/main/jniLibs/mips/libBleCommandUtil.so
deleted file mode 100644
index fcff5eb6b2..0000000000
Binary files a/app/src/main/jniLibs/mips/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/mips64/libBleCommandUtil.so b/app/src/main/jniLibs/mips64/libBleCommandUtil.so
deleted file mode 100644
index a8a292ea13..0000000000
Binary files a/app/src/main/jniLibs/mips64/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/x86/libBleCommandUtil.so b/app/src/main/jniLibs/x86/libBleCommandUtil.so
deleted file mode 100644
index 638a9def95..0000000000
Binary files a/app/src/main/jniLibs/x86/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/x86_64/libBleCommandUtil.so b/app/src/main/jniLibs/x86_64/libBleCommandUtil.so
deleted file mode 100644
index 94873d3732..0000000000
Binary files a/app/src/main/jniLibs/x86_64/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml
new file mode 100644
index 0000000000..e6bb3ca920
--- /dev/null
+++ b/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml
new file mode 100644
index 0000000000..24835127dd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_first_page_black_24dp.xml b/app/src/main/res/drawable/ic_first_page_black_24dp.xml
new file mode 100644
index 0000000000..483f56c7c2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_first_page_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_last_page_black_24dp.xml b/app/src/main/res/drawable/ic_last_page_black_24dp.xml
new file mode 100644
index 0000000000..0d04354c14
--- /dev/null
+++ b/app/src/main/res/drawable/ic_last_page_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_historybrowse.xml b/app/src/main/res/layout/activity_historybrowse.xml
new file mode 100644
index 0000000000..a4959eb3f7
--- /dev/null
+++ b/app/src/main/res/layout/activity_historybrowse.xml
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/circadianpercentageprofile_editbasal_dialog.xml b/app/src/main/res/layout/circadianpercentageprofile_editbasal_dialog.xml
deleted file mode 100644
index ac703d6536..0000000000
--- a/app/src/main/res/layout/circadianpercentageprofile_editbasal_dialog.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/circadianpercentageprofile_fragment.xml b/app/src/main/res/layout/circadianpercentageprofile_fragment.xml
deleted file mode 100644
index 3e712004ff..0000000000
--- a/app/src/main/res/layout/circadianpercentageprofile_fragment.xml
+++ /dev/null
@@ -1,307 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/circadianpercentageprofile_listelement.xml b/app/src/main/res/layout/circadianpercentageprofile_listelement.xml
deleted file mode 100644
index 28d72b2a09..0000000000
--- a/app/src/main/res/layout/circadianpercentageprofile_listelement.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/overview_error_dialog.xml b/app/src/main/res/layout/overview_error_dialog.xml
index e32007ad68..0a8fa5483b 100644
--- a/app/src/main/res/layout/overview_error_dialog.xml
+++ b/app/src/main/res/layout/overview_error_dialog.xml
@@ -13,12 +13,20 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
+
+
diff --git a/app/src/main/res/layout/overview_fragment.xml b/app/src/main/res/layout/overview_fragment.xml
index 158fd6b9b5..bc699bad3c 100644
--- a/app/src/main/res/layout/overview_fragment.xml
+++ b/app/src/main/res/layout/overview_fragment.xml
@@ -270,6 +270,7 @@
app:buttonTint="@color/basal" />
-
-
+ android:layout_weight="1" />
-
-
-
-
-
+
diff --git a/app/src/main/res/layout/overview_fragment_nsclient.xml b/app/src/main/res/layout/overview_fragment_nsclient.xml
index bf38114595..bfec8cd179 100644
--- a/app/src/main/res/layout/overview_fragment_nsclient.xml
+++ b/app/src/main/res/layout/overview_fragment_nsclient.xml
@@ -479,7 +479,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- app:buttonTint="@color/prediction" />
+ android:buttonTint="@color/prediction" />
+ android:buttonTint="@color/basal" />
+ android:buttonTint="@color/iob" />
+ android:buttonTint="@color/cob" />
+ android:buttonTint="@color/deviations" />
+ android:buttonTint="@color/prediction" />
+ android:buttonTint="@color/basal" />
+ android:buttonTint="@color/iob" />
+ android:buttonTint="@color/cob" />
+ android:buttonTint="@color/deviations" />
+ android:buttonTint="@color/prediction" />
+ android:buttonTint="@color/basal" />
+ android:buttonTint="@color/iob" />
+ android:buttonTint="@color/cob" />
+ android:buttonTint="@color/deviations" />
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/treatments_careportal_item.xml b/app/src/main/res/layout/treatments_careportal_item.xml
new file mode 100644
index 0000000000..9f688d2438
--- /dev/null
+++ b/app/src/main/res/layout/treatments_careportal_item.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/treatments_fragment.xml b/app/src/main/res/layout/treatments_fragment.xml
index e7b33aee51..ec4421708c 100644
--- a/app/src/main/res/layout/treatments_fragment.xml
+++ b/app/src/main/res/layout/treatments_fragment.xml
@@ -71,6 +71,16 @@
android:paddingRight="5dp"
android:text="@string/profileswitch" />
+
+
+
diff --git a/app/src/main/res/raw/boluserror.mp3 b/app/src/main/res/raw/boluserror.mp3
index 5a1f3ea1c9..be2eb9b5b1 100644
Binary files a/app/src/main/res/raw/boluserror.mp3 and b/app/src/main/res/raw/boluserror.mp3 differ
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 312b02b69a..e7fd632207 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -310,8 +310,8 @@
Loop has been enabled
Loop is disabled
Loop is enabled
- %.2f ограничен до %.2f
- Стойността %s е извън границите
+ %.2f ограничен до %.2f
+ Стойността %s е извън границите
Remote basal setting is not allowed
Remote command is not allowed
To start basal %.2fU/h reply with code %s
@@ -357,7 +357,6 @@
Редактирай Инс. чувствителност
Редактирай Инс./ВХ
Базов профил:
- Процентен профил
Диапазон за визуализация
Стойност на линиите за ниска и висока КЗ (mmol/l) за телефона и часовника
Ниска КЗ под
@@ -420,7 +419,6 @@
Вцел
ЛПр
DANA
- ППр
ВБ
ОСН
ВП
@@ -445,7 +443,6 @@
По подразбиране: 2\nBolus snooze се активира след като поставите болус за основно хранене, така Loop няма да пуснка/намаля базалите веднага след като сте се хранили. Примерът тук е с 2; така при 3 часа DIA това ще означава че bolus snooze ще бъде внимателно изместен 1.5 часа (3DIA/2).
По подразбиране: 3.0\nТова е настройка на количеството на покачване на КЗ при усвояване на въглехидратите за всеки 5 минути. По подразбиране 3мг/дл/5мин. Това се отразява на това колко бързо се усвояват COB според алгоритъма, и как това се отразява в предвиждането на КЗ, когато тя не се покачва или пада с различен темп от очакваното.
Внимание! Обикновено Вие не трябва да променяте тези стойности. Моля НАТИСНЕТЕ ТУК, прочетете текста и бъдете сигурни, че го РАЗБИРАТЕ преди да направите каквито и да е промени!
- http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html
Позволени са само числа
Позволени са числа между %1$s - %2$s
Полето не може да бъде празно
@@ -613,9 +610,8 @@
чрез Среднопретеглената стойност
OK
Откажи
- трябва да е активно за да изпрати стойностите към помпата!
- Не всички профили са заредени!
- Стойностите не са запазени!
+ Не всички профили са заредени!
+ Стойностите не са запазени!
Изчисти лога
неуспешно - моля проверете телефона
Недостъпно
@@ -677,4 +673,64 @@
Настройки на часовник
Задаване временни цели и въвеждане Лечения от часовник Android wear
Контролиране от часовник
+ Closed Loop е позволен
+ Чете историята на помпата
+ Настройва базалният профил
+ Опитва се да възстанови връзката
+ Доставянето на болуса и проверката на историята на помпата са неуспешни, моля, проверете помпата и ако е доставен болус го добавете като запис през Careportal
+ Модифицирано приложение за изтегляне
+ Задайте стъпка на базала 0.01 Е/ч
+ Dexcom G5 приложение (модифицирано)
+ Качвай данните за КЗ в NS
+ В xDrip+ изберете 640g/Eversense за източник на данни
+ Изпращай данни за КЗ към xDrip+
+ Аларма при липса на данни за КЗ
+ Аларма при недостъпна помпа
+ Командата се изпълнява в момента
+ Грешка при доставяне на удължен болус
+ Храна
+ Има данни за КЗ от избрания източник
+ ИНФО
+ Локални аларми
+ Loop разрешен
+ Максимален IOB е зададен правилно
+ Базалната стойност е заместена от минимално подържаната
+ Липсват данни за КЗ
+ Само отрицателни
+ Не
+ ]]>
+ КЗ от NS
+ NSClient има права за запис
+ Калкулиране на базален IOB
+ Калкулиране на КЗ
+ Калкулиране на Болус IOB
+ Калкулиране на COB
+ Калкулиране суперболус
+ Калкулиране на временни цели
+ Калкулиране на тенденция КЗ
+ Само положителни
+ Обработва се събитие
+ Помпата е недостъпна
+ Лимит за недостъпна помпа [мин]
+ Драйверът за помпата е коригиран
+ Оставащ инсулин
+ Стартира доставка на болус
+ Неподдържан фърмуер на помпата
+ Спешна аларма
+ Очаква края на болуса. Остават %d сек.
+ Показвай делта с още един десетичен знак
+ Показвай подробна делта
+ Да
+ Невалиден профил: %s
+ En
+ Използвай системни известия за аларми и съобщения
+ Внимание
+ Минимум: %3.1f U
+ Максимум: %3.1f U
+ Средно: %3.1f U
+ Нормално
+ Ниско
+ Няма достатъчно инсулин в резервоара
+ Празен
+ Обнови
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 751d559130..f162e70a90 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -96,7 +96,7 @@
Splnit:
Cíl:
OK
- Součaný bazál
+ Současný bazál
Modul zakázán
Vstupní glykémie
Vstupní parametry
@@ -122,7 +122,7 @@
Hodnota
Zdůvodnění
Bezpečnost
- Použít prodloužený bolusy pro >200%
+ Použít prodloužené bolusy pro >200%
Spustit nový prodloužený bolus:
Spustit nový dočasný bazál:
Jednoduchý profil
@@ -152,7 +152,7 @@
Maximální povolené sacharidy [g]
Bezpečnost zadání ošetřeni
Nepodporovaná verze NSClient
- Virtualní pumpa
+ Virtuální pumpa
Základní hodnota bazálu
Baterie
Prodloužený bolus
@@ -205,8 +205,8 @@
Vybrané zařízení nenalezeno
Provedeno
Licenční ujednání
- ROZUMÍM A PORVZUJI
- h zpět
+ ROZUMÍM A POTVRZUJI
+ hodin zpět
Nenalezen bluetooth adaptér
Procent
Obnovit profil
@@ -266,7 +266,7 @@
Podávání %.2fU inzulínu
Zkontrolovat, zda jsou glykémie a údaje z pumpy viditelné v Nightscoutu
Nastavit vizualizaci a monitoring, analyzovat bazály a koeficienty
- Provozovat několik dní otevřenou smyčku a ručně potrvrzovat doporučené dočasné bazály
+ Provozovat několik dní otevřenou smyčku a ručně potvrzovat doporučené dočasné bazály
Začít s otevřenou smyčkou
Na základě předchozích zkušeností rozhodnout, jaký je třeba maximální bazál a nastavit ho v pumpě a v aplikaci
Porozumět otevřené smyčce a doporučeným dočasným bazálům
@@ -276,7 +276,7 @@
Zapnout uzavřenou smyčku, zvyšovat max IOB nad 0 a snižovat cílovou glykémii
Jeden týden úspěšného používání s běžným příjmem sacharidů
Upravit bazály a koeficinty, když bude potřeba a povolit automatickou detekci citlivosti na inzulín
- Povolit další fukce pro běžné používání jako AMA
+ Povolit další funkce pro běžné používání jako AMA
Dosaženo limitu
Aplikováno %.2fU
Smyčka byla zakázána
@@ -285,7 +285,7 @@
Smyčka je povolena
Spanish
Není vybrán žádný profil
- Hodnota %s je mimo přednastavený rozsah
+ Hodnota %s je mimo přednastavený rozsah
Vzdálené posílání příkazů není povoleno
Na spuštění bazálu %.2fU/h odpověz SMS s kódem %s
Na ukončení bazálu odpověz SMS s kódem %s
@@ -313,7 +313,6 @@
Tlačítko 1
Tlačítko 2
Tlačítko 3
- Cirkadiánní procentuální profil
DIA:
Smyčka zakázána
Editovat základní bazál:
@@ -326,8 +325,8 @@
Nízký stav baterie
mg/dl
mmol/l
- Pouze náhráváni do NS (zakázaná synchronizace)
- Pouze náhrávání dat do NS. Neplatí pro glykémie, dokud není vybraní místní zdroj dat jako xDrip. Neplatí pro profily, pokud se používá NS profil.
+ Pouze nahrávání do NS (zakázaná synchronizace)
+ Pouze nahrávání dat do NS. Neplatí pro glykémie, dokud není vybraný místní zdroj dat jako xDrip. Neplatí pro profily, pokud se používá NS profil.
Otevřít nastavení na hodinkách Wear
Jiné
Hodnota v procentech, kterou bude základní profil vynásoben.
@@ -337,7 +336,7 @@
Pumpa není inicializována
Chyba pumpy
Pumpa vypnuta
- Znovu poslat všechny data
+ Znovu poslat všechna data
Opravdu resetovat všechny databáze
Cílový rozsah:
Čas v hodinách, o který bude bazál posunutý.
@@ -375,7 +374,7 @@
Používat autodetekci senzitivity
Data detekce senzitivity
Ladící informace
- %.2f omezeno na %.2f
+ %.2f omezeno na %.2f
Odstranit záznam:
Krátkodobý průměr
Obnovit události z NS
@@ -395,7 +394,6 @@
MPRF
DANA
KONF
- CPP
PÉČE
Rozšířené nastavení
Vždy používat krátkodobý průměrný rozdíl glykémií místo rozdílu posledních 2 hodnot
@@ -502,7 +500,7 @@
Menu smyčky
Smyčka pozastavena
Pozastaveno (%d min)
- %s potřebuje vypnout optimalizace baterie pro optimalní výkon
+ %s potřebuje vypnout optimalizace baterie pro optimální výkon
Prosím povolte oprávnění
Uvolnit
Pozastavit smyčku na 10 h
@@ -512,7 +510,7 @@
Zakázat smyčku
Smyčka obnovena
Smyčka pozastavena
- Vzdálení příkaz není povolen
+ Vzdálený příkaz není povolen
K pozastavení smyčky na %d minut odpověz SMS s kódem %s
Chybná doba trvání
Logovat spuštění aplikace do NS
@@ -550,9 +548,8 @@
SEN
COB
Detekce citlivosti
- Všechny profily nenačteny
- musí být aktivovaný, aby šly poslat hodnoty do pumpy!
- Hodnoty nejsou uloženy!
+ Všechny profily nenačteny
+ Hodnoty nejsou uloženy!
DanaRv2
ODCH
Zařízení
@@ -571,8 +568,8 @@
Nastavení alarmů
Povolit odesílání do ostatních aplikací (jako xDrip)
Povolení odesílaní
- Zakazát nahrávání do NS
- Všechny data odeslaná do NS jsou zahozena. AAPS je připojen k NS, ale nedělá do něj žádné změny.
+ Zakázat nahrávání do NS
+ Všechna data odeslaná do NS jsou zahozena. AAPS je připojen k NS, ale nedělá do něj žádné změny.
Vysoká
Nízká
Zastaralá data
@@ -670,4 +667,113 @@
Fiasp
Ultra rychlý - Oref
Čekání na konec bolusu. Zbývá %d sek.
+ Povolit další funkce pro běžné používání jako SMB
+ Výchozí hodnota: 3 Toto je klíčová hodnota zabezpečení. Říká, že maximánlní nastavitelný bazál je trojnásobkem maximálního denního bazálu. Patrně to nebudete muset měnit, případně si přečtete o tématu \"3x max denní; 4x aktuální\"
+ Výchozí hodnota: 4 Toto je druhá klíčová hodnota. Říká, že maximální hodnota dočasného bazálu nikdy nebude větší, než čtyřnásobek aktuálního bazálu. Je to proto, aby se lidé nedostali do hodnot nebezpečných bazálu dříve, než pochpí jak OpenAPS pracuje. Znovy vychozí hodnota je 4 a většina lidí ji nidky nebude muset změnit. Pokud nestačí, obvykle je problém někde jinde.
+ Výchozí hodnota: 1.2 Toto je bezpečnostní nastavení pro detekci sensitivity. Říká, že autosens může zvýšit bazály, snížit ISF a snížit cílovou hodnotu glykémie o 20%
+ Výchozí hodnota: 0.7 Toto je bezpečnostní nastavení pro detekci sensitivity. Říká, že autosens může snížit bazály, zvýšit ISF a zvýšit cílovou hodnotu glykémie na 70%
+ Výchozí hodnota: zapnuto Toto nastavení říká, že autosens může měnit také cílové hodnoty glykémií.
+ Výchozí hodnota: 2 Toto nastavení říká, po jakou část z hodnoty DIA smyčka po bolusu čeká a nereaguje na změny glykémií (zde 3DIA/2 = 1,5h)
+ Výchozí hodnota: 3.0 Tato hodnota definuje minimální část strávených sacharidů za každých 5 min. Výchozí hodnota je 3mg/dl/5min. Tato hodnota ovlivňuje výpočet COB
+ Pozor! Za normálních okolností tyto hodnoty nemusíte měnit. Klikněte ZDE, PŘEČTĚTE si informace a UJISTĚTE se, že jim rozumíte dříve, než je začnete měnit.
+ Interval pro detekci senzitivity [h]
+ Počet hodin do minulosti pro detekci senzitivity
+ Jídlo
+ g
+ ]]>
+ kJ
+ En
+ Pr
+ Tuk
+ Příkaz je právě prováděn
+ Ovladač pumpy opraven
+ Pumpa nedostupná
+ Chybějící glykémie
+ Používat systémové notifikace pro výstrahy a oznámení
+ Místní výstrahy
+ Výstraha při nedostupných glykémiích
+ Výstraha při nedostupné pumpě
+ Limit pro nedostupnost pumpy [min]
+ Urgetní alarm
+ INFO
+ Bluetooth
+ Hlídač BT
+ Vypne na 1 sek bluetooth v telefonu, pokud se nedaří připojit k pumpě. Může to pomoci u telefonů, které mají problémy s BT
+ DexcomG5 aplikace (upravená)
+ Nahrávat data do NS
+ Nastavení nahrávání z G5
+ Upravená aplikace pro stažení
+ Zobrazovat detailní změny
+ Zobrazovat rozdíl s jedním desetinným místem navíc
+ Nepodporovaný firmware v pumpě
+ Odesílat data do xDrip+
+ V xDrip+ vyberte zdroj dat 640g/Eversense
+ Glykémie z NS
+ Hodnota bazálu nahrazena minimální možnou
+ Kalkulace glykémie
+ Kalkulace bolusového IOB
+ Kalkulace bazálního IOB
+ Kalkulace trendu
+ Kalkulace superbolusu
+ Ano
+ No
+ Pouze kladné
+ Pouze záporné
+ Kalkulace COB
+ Kalkulace s dočasným cílem
+ Smyčka povolena
+ APS vybráno
+ NSClient má povolení k zápisu
+ Uzavřená smyčka povolena
+ Maximální IOB nastaveno správně
+ Glykémie dostupné z vybraného zdroje
+ Bazální hodnoty nejsou zarovnané na celé hodiny: %s
+ Chybný profil: %s
+ Programování pumpy pro bolus
+ Obnovit
+ Stav
+ Aktivita
+ Žádné spojení %d min
+ %d%% (%d min zbývá)
+ Inicializace
+ Odpojeno
+ Vypnuto díky chybě
+ Vypnuto uživatelem
+ Beží
+ Rušení dočasného bazálu
+ Nastavování doč. bazálu (%d%% / %d min)
+ Bolus (%.1f U)
+ Obnovování
+ Nikdy
+ Požadovaná operace není pumpou podporována
+ Nebezpečné použití: extended nebo multiwave bolus je aktivní. Pumpa byla vypnuta jen na 6 hodin. Povolené jsou pouze normální bolusy.
+ Nebezpečné použití: pumpa má nastavený jiný bazální profil než první. Smyčka byla zakázána. Nastavete první profil a znovu načtěte.
+ Bolus stejné velikosti už byl během poslední minuty požadován. Jako preventivní ochrana před zdvojeným bolusem byla operace zakázána.
+ Teď
+ Načítání historie pumpy
+ Výstrahy
+ Nastavení bazálního profilu
+ V zásobníku je málo inzulínu
+ Slabá baterie v pumpě
+ Pumpa hlásí chybu E%d: %s
+ Pokouším se obnovit spojení
+ Provádění bolusu a čtení historie selhalo. Zkontrolujte pumpu a zadejte bolus přes péči
+ Provádění bolusu selhalo. Zdá se, že žádný bolus nebyl podán. Zkontrolujte pumpu a případně pošlete bolus znovu. Jako bezpečnostní opatření podání bolusu není opakováno.
+ Pouze %.2f U z bolusu %.2f bylo podáno díky chybě. Zkontrolujte pumpu a proveďte nápravu.
+ Historie
+ Varování o ukončeném dočasném bazálu bylo potvrzeno.
+ Varování
+ Prázdný
+ Nízký
+ Normální
+ Průměr: %3.1f U
+ Maximum: %3.1f U
+ Minimum: %3.1f U
+ Pro přečtení historie chyb dlouze stiskněte tlačítko ALERTS. Varování: může to způsobit chybu, že pumpa bude odmítat všechny připojení a je pak vyžadováno stisknutí tlačítka na pumpě pro obnovení komunikace.
+ Je vyžadována aktualizace času na pumpě
+ Pro přečtení celkových denních dávek dlouze stikněte na pumpě tlačítko TDDS. Varování: může to způsobit chybu, že pumpa bude odmítat všechna připojení a je pak vyžadováno stisknutí tlačítka na pumpě pro obnovení komunikace.
+ Toto načte kompletní historii pumpy a stavy. Všechno v My Data a hodnoty bazálů. Bolusy a dočasné bazály budou přidány do ošetření, pokud neexistují. Může to způsobit duplicity díky nepřesnosti času v pumpě. Nedoporučuje se pokud používáte smyčku a je určeno pouze pro speciální připady. Varování: může to způsobit chybu, že pumpa bude odmítat všechny připojení a je pak vyžadováno stisknutí tlačítka na pumpě pro obnovení komunikace.
+ Opravdu chcete přečíst historii z pumpy a nést důsledky z toho vyplývající?
+ Nedostatek inzulínu pro takovýto bolus
+ Chyba spuštění extended bolusu
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 33a4b1bed4..225c5598b7 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -311,7 +311,6 @@
LP
DANA
CONF
- CPP
CP
Bitte verwende nur Ziffern.
Pflichtfeld
@@ -394,9 +393,8 @@
Pumpenbatterie-Wechsel
SAGE
Insulin
- Es sind nicht alle Profile geladen!
- muss aktiviert werden, um Werte an die Pumpe zu senden!
- Werte nicht gespeichert!
+ Es sind nicht alle Profile geladen!
+ Werte nicht gespeichert!
Aktiviere verlängerten Bolus in der Pumpe
DanaR Stats
# Tage
@@ -481,7 +479,7 @@
OAPS
OpenAPS AMA
Skript Debug
- Wert %s ist außerhalb des festen Limits
+ Wert %s ist außerhalb des festen Limits
Kalibrierung
Kalibrierung
Button-Text:
@@ -579,7 +577,7 @@
Unbekannter Befehl oder falsche Antwort
Falsche Dauer
Einstellungen freischalten
- %.2f limitiert auf %.2f
+ %.2f limitiert auf %.2f
S-Bolus
Model: %02X Protokoll: %02X Code: %02X
Empfindlichkeitserkennung
@@ -620,7 +618,6 @@
Prozentsatz
Zeitverschiebung
BAT
- CircadianPercentage-Profil
Zeitüberschreitung der Verbindung
Füllen
DE-Bolus
@@ -711,9 +708,6 @@
Aktivität
%d%% (%d Min. verbleibend)
Keine Verbindung zur Pumpe seit %d Min.
- Bolusabgabe gestoppt
- Bolusabgabe wird abgebrochen
- Fehlerprotokol
Status
Keine Verbindung zur Pumpe
Gestoppt (Benutzer)
@@ -727,7 +721,6 @@
Bitte starte dein Telefon neu oder starte AndroidAPS in den System-Einstellungen neu. Andernfalls wird AndroidAPS nicht protokolliert (wichtig zum Nachverfolgen und Verifizieren, dass der Algorithmus korrekt funktioniert)
TBR
%.1f IE (%s, %s)
- Nutze System-Benachrichtigungen für Alarme
Ein gleich großer Bolus wurde in der letzten Minute angefordert. Dies ist nicht zulässig, um ungewollte Doppelboli zu verhindern und vor eventuellen Bugs zu schützen.
Historie wird gelesen
Basalratenprofil wird aktualisiert
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index b9fd9bff78..d6d79fc774 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -307,8 +307,8 @@
Το κύκλωμα ενεργοποιήθηκε
Κύκλωμα απενεργοποιημένο
Κύκλωμα ενεργοποιημένο
- %.2f limited to %.2f
- Τιμή %s είναι έξω από τα όρια
+ %.2f limited to %.2f
+ Τιμή %s είναι έξω από τα όρια
"Δεν επιτρέπεται η απομακρυσμένη ρύθμιση βασικού ρυθμού "
Δεν επιτρέπεται απομακρυσμένη εντολή
Για έναρξη βασικού %.2fU/h SMS με κωσικό %s
@@ -354,7 +354,6 @@
Ρύθμιση Βασικού-ISF:
Ρύθμιση Βασικού-IC:
Βασικό Προφίλ:
- Ποσοστό προφίλ κυκλώματος
Εύρος εμφάνισης
Υψηλό και Χαμηλό σημείο για την γραφική στην Επισκόπηση και Smartwatch
ΧΑΜΗΛΟ σημείο
@@ -417,7 +416,6 @@
TT
LP
DANA
- CPP
TB
HOME
VPUMP
@@ -611,9 +609,8 @@
Σταθμισμένος μέσος όρος ευαισθησίας
OK
Ακύρωση
- Χρειάζεται να ενεργοποιηθεί για να στείλει τιμές στην αντλία!
- Δεν έχουν φορτωθεί όλα τα προφίλ
- Οι τιμές δεν αποθηκεύτηκαν!
+ Δεν έχουν φορτωθεί όλα τα προφίλ
+ Οι τιμές δεν αποθηκεύτηκαν!
Επισκόπηση ειδοποιήσεων
Αποστολή ειδοποιήσεων ως ειδήσεων για τα ρολόγια
Ενεργοποιήστε την αποστολή σε άλλες εφαρμογές (όπως xDrip)
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 7259194dee..900eae0ef9 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -2,7 +2,6 @@
Seguridad tratamientos
Máximo Bolo permitido [U]
Máximos carbohidratos permitidos [g]
-
Preferencias
Refrescar tratamientos desde NS
Backup
@@ -12,7 +11,6 @@
Usar bolos extendidos para> 200%
DanaR dispositivo Bluetooth
Usar siempre valor basal absoluto
-
Objetivo:
Meta:
Inicio
@@ -39,7 +37,7 @@
Insulina [U]
Carbohidratos [g]
Glucosa
- Hidratos Carbono
+ Carbohidratos
Corrección
U
Bolo IOB
@@ -53,7 +51,7 @@
Depósito:
OK
Error de SQL
- Última ejecución
+ Última acción
Parámetros de entrada
Estado de glucosa
Basal temporal actual
@@ -61,7 +59,7 @@
Perfil
Datos de comidas
Resultado
- No hay disponibles datos de glucosa
+ No hay datos disponibles de glucosa
Sin perfil disponible
No se dispone de bomba
Ninguna acción requerida
@@ -72,7 +70,6 @@
Glucosa
Delta
Delta Media
-
Config Builder
Objetivos
OpenAPS MA
@@ -82,18 +79,15 @@
Tratamientos
Bomba virtual
Careportal
-
-
Bomba
Tratamientos
- Temp Basales
+ Basales temporales
Perfil
APS
General
días
Duración mínima
Restricciones
-
Lazo
Lazo
APS
@@ -124,15 +118,14 @@
xDrip
NSClient
Modo APS
-
Lazo cerrado
Lazo abierto
Nueva propuesta disponible
- Versión de NSClient no soportada
+ Versión de NSClient no apoyada
NSClient no instalado. Registro perdido!
BG disponible en NS
Estado de la bomba disponible en NS
- Aceptados
+ Acceptado manualmente
LAZO DESACTIVADO POR RESTRICCIONES
Czech
English
@@ -144,7 +137,7 @@
NOTA
Pregunta
Ejercicio
- Cambio Lugar Bomba
+ Cambio Lugar Cánula
Insertar sensor
Iniciar sensor
Cambio Cartucho insulina
@@ -155,14 +148,13 @@
Combo bolo
Basal Temporal Inicio
Basal Temporal Fin
- Hidratos Carbono Corrección
+ Corrección Carbohidratos
OpenAPS Offline
-
Tipo de evento
Otro
Medidor
Sensor
- Hidratos Carbono
+ Carbohidratos
Insulina
Tiempo absorción
Dividir
@@ -196,7 +188,6 @@
Bulgarian
DESCARTAR
Idioma
-
DanaR
Conectando
Conectado
@@ -206,7 +197,7 @@
Acuerdo de licencia de usuario final
No deben utilizarse para tomar decisiones médicas. NO HAY GARANTÍA PARA EL PROGRAMA, la extensión permitida por la legislación aplicable. Excepto cuando se indique de otra forma por escrito, los tenedores del copyright y / u otras partes proporcionan el programa \"tal cual\" sin garantía de ningún tipo, ya sea expresa o implícita, incluyendo, pero no limitado a, las garantías implícitas de COMERCIALIZACIÓN E IDONEIDAD PARA UN FIN DETERMINADO . TODO EL RIESGO EN CUANTO A LA CALIDAD Y RENDIMIENTO DEL PROGRAMA ES CON USTED. SI EL PROGRAMA TIENE UN ERROR, asume el coste de cualquier servicio, reparación o corrección.
Entiendo y acepto
- Salvar
+ Guardar
No se encuentra adaptador Bluetooth
El dispositivo seleccionado no se encuentra
Error de conexión de la bomba
@@ -215,7 +206,7 @@
Unidades diarias
Último bolo:
h antes
- Datos invalidos
+ Datos inválidos
Valor no establecido correctamente
Recargar Perfil
Ver perfil
@@ -231,8 +222,8 @@
XXXXXXXXXX +; + YYYYYYYYYY
Para entregar bolo% .2fU responder con código% s
Bolo falló
- Bolo% .2fU entregado con éxito
- Entregando% .2fU
+ Bolo %.2fU entregado con éxito
+ Entregando %.2fU
Bolo remoto no permitido
Dedo
Sensor
@@ -274,8 +265,8 @@
Oclusión
Detener
Parar pulsado
- Esperando bomba. Click to refresh.
- Va a entregar %.2fU
+ Esperando bomba. Pulsar para actualizar.
+ Se entregará % .2fU
Configuración de visualización y monitoreo, y el análisis de los basales y ratios
Comprobar que los datos de BG están disponibles en Nightscout, y que los datos de la bomba de insulina se están subiendo
Empezar con bucle abierto
@@ -294,27 +285,27 @@
Korean
Acciones
Corr
- Loop Inactivo
+ Lazo Inactivo
Bolo Comida
- Valor %s fuera de limites
+ Valor %s fuera de limites
Botón Texto:
- Carbs:
+ Carbohidratos:
Validar:
Añadir
Editar
Eliminar
Asistente
Ajustes asistente
- Loop se ha desactivado
- Loop se ha activado
- Loop inactivo
- loop activo
+ Lazo se ha desactivado
+ Lazo se ha activado
+ Lazo inactivo
+ Lazo activo
Basal temporal cancelada
Fallo cancelación basal temporal
Fallo inicio basal temporal
Basal temporal %.2fU/h para %d min iniciada correctamente
Permitir comandos SMS remotos
- Para parar basal temporal responder con codigo %s
+ Para parar basal temporal responder con código %s
AndroidAPS iniciado
Español
NS solo subida (sinc. inactiva)
@@ -326,26 +317,25 @@
Comando desconocido o respuesta incorrecta
¡Por favor asegurar que la cantidad coincide con la especificación del set de infusión!
Para iniciar basal %.2fU/h responder con código %s
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
+ "ACC"
+ "REL"
+ "BombaV"
+ "Trat"
+ "ObjTempAmpl"
+ "ObjTemp"
+ "SMS"
+ "PerfSipmple"
+ "Perf"
+ "General"
+ "Obj"
+ "Oaps"
+ "Lazo"
+ "PerfLoc"
+ "Dana"
+ "Conf"
+ "CP"
Actividad
- Por favo reinicia el teléfono o AndroidAPS desde ajustes de sistema, sino AndroidAPS no guardara registros (importantes para trazar y verificar que el algoritmo funciona correctamente)
+ Por favor reinicia el teléfono o AndroidAPS desde ajustes de sistema, sino AndroidAPS no guardará registros (importantes para trazar y verificar que el algoritmo funcione correctamente)
Matriz de %d elementos. Valor actual:
Ratio Basal:
Valor basal menor del mínimo. Perfil no fijado.
@@ -356,14 +346,14 @@
Inhabilitar EasyUI modo en bomba
Habilitar bolos extendidos en bomba
Cambio de modo de U/d a U/h en bomba
- Comida temprano
+ Comer pronto
Marca ALTA
Iniciando . . .
Perfil Local
Media Larga Delta
Marca BAJO
Batería Baja
- %dmin antes
+ %dmin antes
Usar característica AMA autosens
Datos Autosens
Factor porcentual para multiplicar el perfil base
@@ -379,15 +369,426 @@
Media corta delta
Bolo:
Último BG:
- %dmin antes
+ %dmin antes
Bolo %.2fU enviado correctamente
Rango Objetivo:
Unidades:
Sólo se permiten caracteres numéricos
- Sólo se permiten dígitos en el rango %1$s - %2$s
+ Sólo se permiten dígitos en el rango %1$s - %2$s
Este campo no puede estar vacío
Número de teléfono inválido
Esperando bomba
Italian
AndroidAPS
+ hollandes
+ Griego
+ Ruso
+ Sueco
+ Max U/h para el perfil base
+ "Max IOB basal OpenAPs puede emitir "
+ Para enviar calibracion %.2f responder con código %s
+ Entregaré %.2fU
+ Duración de acitividad de insulina
+ Errores
+ habilitar funciones adicionales para uso durante el día como SMB
+ %.2f limitado a %.2f
+ no permitido el mando remoto
+ Para cancelar loop por %d minutos responde con código %s
+ Rellenar/Llenar
+ Llenar/Rellenar cantidad de insulina estándar
+ Tiempo en horas en el que el perfil será movido
+ mg/dl
+ mmol/l
+ DIA:
+ Editar Base-Basal:
+ Edidat Base-ISF:
+ Editar Base-IC:
+ Reloj
+ Abrir ajustes en reloj
+ Batería de la bomba descargada
+ DanaR Korean
+ BG:
+ MDI
+ MM640g
+ Avisos permanentes
+ DATOS CADUCADOS
+ OpenAPS AMA
+ Script debug
+ Renovar datos desde NS
+ DanaR Stats
+ Dosis diaria cumulativa
+ "Dosis diaria ampliada exponencialmente "
+ Base
+ Bolo
+ Dosis diaria
+ Fecha
+ Cuota
+ # Días
+ Peso
+ Probablemente impreciso usando bolo para llenar/rellenar!
+ Datos caducados pro favor pincha RELOAD
+ Basal total
+ Basal diaria *2
+ Tab titulo corto
+ Ajustes Delta
+ Usa siempre delta media corto en vez de delta simple
+ Recomendado si los datos de origen no filtrados como xDrip son inestables.
+ Ajustes avancados
+ Modelo: %02X Protocolo: %02X Codigo: %02X
+ Perfiles
+ max_daily_safety_multiplier
+ "Valor por defecte: 3 Esto es valor de seguridad establecido pos OpenAPS. Limita tu base al máximo de x3 de tu base máxima. No necesitas cambiar esto, pero debes tener en cuenta, que esto se esta discutiento sobre „3 x max diario; 4x actual“ pro razones de seguridad. "
+ current_basal_safety_multiplier
+ "Ajuste pro defecto: 4 Esto es la otra mitad de los ajustes de seguridad de OpenAPS y la otra mitad de \"3x max diario, 4x actual\". Esto significa, que tu base no puede ser mas alta que el numero que multiplica tu base. Esto es para evitar que las personas se encuentren en situaciones peligrosas por aumentar mucho la base sin entender el algoritmo del sistema. El ajuste por defecto es x4. La mayoría de las personas nunca tendra que cambiar estos ajustes, si no debe modificar otros ajustes en la terapia. "
+ autosens_max
+ "Ajuste por defecto: 1.2\nEsto es un multilicador para autosens (y pronto autotune) para poner un 20% limite máximo a la cota de autosens ratio, la que determina cuantos ajustes autosens puede hacer a la base, a cuanto puede ajustar ISF y a cuanto puede bajar el objective de glucosa. "
+ autosens_min
+ Ajuste pro defecto: 0.7\nEl otro lade de limitaciones de seguridad de autosens, limitando a cuanto puede bajar la base y a cuanto puede subir ISF y BG objectivos.
+ autosens_adjust_targets
+ Ajuste pro defcto: true\nEsto se usa para permitir autosens a ajustar objectivos BG en addicion a ISF y bases.
+ bolussnooze_dia_divisor
+ Ajuste pro defecto: 2 \nDormir bolo es iniciado después de proveder un bolo para comida, así el loop no interactuará con low temps cuando acabas de comer. El ajuste pro defecto es 2; quiere decir con el DIA de 3 h el bolo será dormido por fases por 1.5 h (3DIA/2).
+ 5_min_carb_impact
+ "Ajustes pro defecto: 3.0\nEsto es un ajuste pro defecto para la absorcion de carbohidratos pro 5 minutos. Por defecto se espera 3mg/dl/5min. Esto afecta la velocidad de reduccion de COB y cuanta absorcion se usa para calcular el BG futuro previsto, si la glucosa diminua mas de lo previsto o aumenta mas de lo previsto. "
+ "Atención!\nNormalment no tienes que editar los valores a continuacion. Por favor PINCHA AQUI y LEE el texto y PROCURA ENTENDER antes de cambiar alguno de los valores. "
+ http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html
+ numero de telefonp incorrecto
+ Copiar al Clipboard
+ Copiado al clipboard
+ mostrar log
+ Calibracion
+ Calibracion
+ Mandar calibracion %.lf a xDrip?
+ xDrip+ no instalado
+ Calibracion mandada a xDrip
+ Calibracion remota no admitida
+ Mandar calibracion tiene que ser activada en xDrip.
+ xDrip no recibe calibraciones
+ no mostrar otra vez
+ Bomba parada. Pincha para aktualizar
+ bomba parada
+ recibir estado de bomba
+ iniciando base temporal
+ parando base temporal
+ iniciando bolo prolongado
+ parando bolo prolongado
+ actualizando cuota base
+ Desconectando
+ Efectuando
+ Ajustes bomba virtual
+ Subiendo estado a NS
+ Contrasena invalida
+ Contrasena para ajustes
+ desbloquear ajustes
+ llegando al limite de insulina diario
+ NSClient
+ NSCI
+ URL:
+ Autoscroll
+ Reiniciar
+ NSClient
+ Nightscout URL
+ Indica Nightscout URL
+ NS API secret
+ NS API secret
+ Indica NS API secret (min 12 chars)
+ Nombre aparato
+ Indica nombre aparato
+ Se usara para enteredBy field
+ entregar ahora
+ borrar cola
+ mostrar cola
+ Cola:
+ Estado:
+ Pausado
+ Borrar log
+ NSCLIENT no tiene derecho para editar. API secret incorrecto?
+ Ajustes reloj
+ mostrar detalles IOB
+ Separar IOB en bolo y base en el reloj
+ sin efecto - por favor controlar en móvil
+ no disponible
+ Edad paciente
+ Menor de edad
+ Adolescente
+ Adulto
+ Por favor elige edad del paciente para emplear limites de seguridad
+ Glimp
+ Aparato parece no soportar optimisacion de bateria whitelisting!
+ Por favor permita Permission
+ %s necesita optimisacion de bateria whitelisting para funcionar bien
+ Loop desactivado
+ desactivado (%d m)
+ Superbolus (%d m)
+ Loop menu
+ Desactivar loop por 1h
+ Desactivar loop por 2h
+ Desactivar loop por 3h
+ Desactivar loop por 10 h
+ Desconectar bomba por 30 min
+ Desconectar bomba por 1 h
+ Desconectar bomba por 2 h
+ Desconectar bomba por 3 h
+ Desconectar bomba por 10 h
+ Reiniciar
+ duracion incorrecta
+ Loop desactivado
+ Loop reiniciado
+ Tendencia 15 min
+ COB
+ Superbolo
+ Indica app start en NS
+ Aplicacion existente para aplicar ajustes.
+ DanaRv2
+ Insulina
+ Insulina acción rápida
+ Novorapid, Novolog, Humalog
+ Fiasp
+ INS
+ Insulina acción rápida prolongada
+ activar superbolo en wizard
+ Activar función superbolo en wizard. No lo actives hasta que hayas aprendido lo que realmente hace. PUEDE CAUSAR SOBREDOSIS DE INSULINA usandolo sin precaucion!
+ IOB
+ COB
+ PRE
+ BAS
+ Firmware
+ Estado de bluetooth
+ Sobre
+ "Falta permitir SMS "
+ DEV
+ xDrip Status (reloj)
+ xDrip Statusline (reloj)
+ xds
+ Mostrar BGI
+ agregar BGI a status line
+ No upload to NS
+ Todos los datos mandados a NS son borrados. AAPS esta conectado to NS pero no hay cambios en NS
+ Nivel base
+ Nivel bolo
+ Bolo prolongado
+ "Objectivo temporal "
+ cancelar bolo prolongado
+ Edad sensor
+ Edad cánula
+ Edad insulina
+ horas
+ Tipo base
+ Falta ISF en perfil. Usando ajuste por defecto.
+ Falta IC en perfil. Usando ajuste por defecto.
+ Falta base en perfil. Usando ajuste por defecto.
+ "Falta objectivo en perfil. Usando ajuste por defecto. "
+ Perfil invalido !!!
+ CambioPerfil
+ Edad bateria bomba
+ Cambio bateria bomba
+ Opciones alama
+ Urgente alto
+ Alto
+ Bajo
+ Urgente bajo
+ Actualmente puesto a %f
+ Stale data
+ Urgent stale data
+ Stale data threshold [min]
+ Urgent stale data threshold [min]
+ Interval para autosens [h]
+ Horas en el pasado para detectar sensividad (tiempo de absorcion de carbohidratos no incluidos)
+ SEN
+ "Ignora evenos de cambio de perfil "
+ "Totos los cambios de perfil son ignorados y se usa siempre el perfil actual "
+ Bomba
+ OpenAPS
+ Aparato
+ Uploader
+ Deteccion sensividad
+ SENS
+ Sensitivity Oref0
+ Sensitivity AAPS
+ Ajustes absorcion
+ Tiempo max absorcion comida [h]
+ Tiempo esperado en el que todos los carbohidratos son absorbados
+ mostrar bolo prolongado en %
+ SAGE
+ IAGE
+ CAGE
+ PBAGE
+ OAPS
+ UPLD
+ BAS
+ EXT
+ Pantalle proteccion
+ Cierre
+ Al activar autosens recuerda editar todos carbohidratos comidos. Si no, sensividad será calculada incorrectamente !!!
+ Sensitivity WeightedAverage
+ OK
+ Cancelar
+ Faltan perfiles!
+ Valores no guardados!
+ Resumen avisos
+ Mandar resumen de avisos como avisos de confirmacion por reloj.
+ Accu-Chek Combo
+ COMBO
+ Activar mensajes a otras aplicaciones (como xDrip).
+ Activar mensajes locales.
+ ACTIVITY Y FEEDBACK
+ CARBS Y BOLUS
+ CGM Y OPENAPS
+ PUMP
+ Valor base [U/h]
+ Duracion [min]
+ IOB Curve Peak Time
+ Peak Time [min]
+ Free-Peak Oref
+ Rapid-Acting Oref
+ Ultra-Rapid Oref
+ DIA de %s demasiado corto - usando %s!
+ ACTIVAR PERFIL
+ Fecha
+ INVALIDO
+ Esperando para conectar con bomba
+ Coneccion OK
+ Coneccion fuera de tiempo
+ CONECTANDO
+ aparato no enconrado
+ Deposito vacio
+ Alerta de control de BG
+ Insulina restante en deposito
+ DanaRS
+ Dana
+ Bomba sleccionada
+ Conectar bomba nueva
+ Velocidad bolo
+ Poner paso base a 0.01 U/h
+ Numero de serie
+ Porcientos
+ Cambio de tiepmo
+ Ojbectivo temporal por defecto
+ duracion comiendopronto
+ objectivo comiendopronto
+ duracion actividad
+ objectivo actividad
+ Prime
+ recibiendo estado de bolo prolongado
+ recibiendo estado bolo
+ recibiendo estado bolo temporal
+ recibiendo ah´justes bomba
+ recibiendo hora bomba
+ usar otra vez
+ Control desde reloj
+ editar y emitir abjectivos temp. y tratamientos por reloj
+ Fuera tiempo coneccion
+ comida
+ g
+ ]]>
+ kJ
+ En
+ Pr
+ Grasa
+ ]]>
+ Esperande terminar bolo. Faltan %d seg.
+ Processando
+ "Iniciando emisioin bolo "
+ Orden se esta efectuando en este momento
+ control de la bomba corigido
+ bomba no alcanzable
+ "Falta lectura BG "
+ Usa avisos del sistema para alarmas y avisos
+ Alarma local
+ Alarma si no llegan datos BG
+ Alarma si bomba no es alcanzable
+ Alarma urgente
+ INFO
+ Bluetooth
+ BT Watchdog
+ Apaga el bluetooth del móvil por un segundo si no hay coneccion con la bomba. Esto ayuda con algunos moviles con problemas de establecer coneccion bluetooth estable.
+ DexcomG5 App (patched)
+ Envias datos BG a NS
+ G5 upload ajustes
+ APK adaptada para bajar
+ "mostrar detalles delta "
+ mostrar delta con una plaza decimal mas
+ firmware de la bomba no apoyada
+ mandar BG a xDrip
+ En xDrip elige 640g/Eversense date source
+ NSClient BG
+ Valor base remplazado por valor mínimo
+ Calculacion BG
+ Calculacion bolo IOB
+ Calculacion base IOB
+ Calculacion tendencia
+ Calculacion superbolo
+ Si
+ No
+ Solo positivo
+ Solo negativo
+ Calculacion COB
+ Calculacion objectivo temporal
+ Loop activado
+ APS seleccionado
+ NSClient tiene permission de escribir
+ Modo cerrado activado
+ Máximo IOB puesto correctamente
+ BG adquirible del origen seleccionado
+ Valores base no asignados a las horas: %s
+ Perfil invalido: %s
+ Programando bomba para emitir bolo
+ Actualizar
+ TDDS
+ Estado
+ Actividad
+ Ninguna coneccnion por %d min
+ %d%% (%d min restan)
+ %.1f U (%s, %s)
+ Iniciando
+ Desconectado
+ Apagado por error
+ Apagado por usario
+ Funcionando
+ Cancelando TBR
+ Poniendo TBR (%d%% / %d min)
+ Emitiendo bolo (%.1f U)
+ Actualizando
+ Nunca
+ "Acción no disponible en la bomba "
+ Uso inseguro: bolo prolongado o multiwave activo. Modo Loop ha sido puesto a baja emision para solo 6 horas. Solo bolo normal se puede emitir en modo loop.
+ "Uso inseguro: la bomba usa base diferente a la primera. El loop ha sido apagado. Elige primero perfil en la bomba y acualiza. "
+ Un bolo de mismo valor ha sido dado durante el pasado minuto. Para evitar bolos dobles y asegurarse contra bugs esto no es permitido.
+ Ahora
+ Leiendo historia bomba
+ Alarmas
+ " Activando perfil base "
+ "Nivel del deposito bajo "
+ Bateria casi agotada
+ La bomba muesta el error E%d: %s
+ Para leer historial de los errores, pincha unos segundo el boton \"ALARMAS\" ATENCION: esto puede causar un bug. La bomba no vuelve a conectarse - necesitas pulsar un boton en la misma bomba para reiniciarse. Deberias evitar esto.
+ Para leer el hisorial TDD de la bomba pulsa el boton TDDS unso segundos. ATENCION: esto puede causar un bug. La bomba no vuelve a conectarse - necesitas pulsar un boton en la misma bomba para reiniciarse. Deberias evitar esto.
+ Mínimo: %3.1f U
+ Media: %3.1f U
+ Máximo: %3.1f U
+ Bajo
+ Vacio
+ Normal
+ Se necesita actualizar reloj de la bomba
+ Historial
+ Alerta
+ "Esto lee todo el historial y estado de la bomba, tus datos, la base. Bolos, basales temporales y tratamientos seran copiados y agregados si no existen ya. Esto puede causar duplicaciones, por que la hora de la bomba no es precisa. Es uso de esto con el loop normal solo deb ser usado en cirumstancisas especiales. Si de todas meneras quieres usar esto pulsa este boton unos segundos otra vez. ADVERTENCIA: esto puede causar un bug. La bomba no vuelve a conectarse - necesitas pulsar un boton en la misma bomba para reiniciarse. Deberias evitar esto. "
+ "Estas seguro, de que quieres leer todos los datos de la bomba y acceptar las consequencias de esta acción? "
+ TBR cancelada, advertencia acceptada
+ Emision del bolo fallado. Ningún bolo se ha emitido. Para asegurarse, por favor controle la bomba para evitar bolo doble. Para evitar bugs no se reinician bolos automaticamente.
+ "Solo %.2f U del bolo mandado de %.2f U ha sido emitido por causa de un error. Por favorn controla la bomba para confirmar y toma acciones apropiadas. "
+ "Fallo de emitir bolo y de controlar historical de la bomba.Por favor controla manualmente y crea un record en Careportal si el bolo ha sido emitido. "
+ Reestablecido coneccion fallada.
+ "No hay suficiente insulina en el deposito para emitir bolo. "
+ "Error al emitir bolo prolongado. "
+ bomba no alcanzable treshold [min]
+ TT
+ Versión no acceptada de Nightscout
+ Activar loop
+ Desactivar loop
+ Base:
+ Base temporal no emitida
+ Base temporal
+ Delta:
+ IOB:
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000000..f75eedfb62
--- /dev/null
+++ b/app/src/main/res/values-fr/strings.xml
@@ -0,0 +1,842 @@
+
+
+ AndroidAPS
+ Traitements de sécurité
+ Bolus max. autorisé [U]
+ Glucides max. autorisés [g]
+ Préférences
+ Actualiser les données depuis NS
+ Sauvegarde
+ Alarme test
+ "Réinitialiser les Bases de Données "
+ Voulez-vous vraiment réinitialiser les bases de données ?
+ Quitter
+ Utiliser les bolus étendus à > 200%
+ Dispositif Bluetooth DanaR
+ utiliser toujours les valeurs absolues du basal
+ Rebootez votre smartphone ou redémarrez AndroidAPS depuis les paramètres système sinon AndroidAPS ne sera pas connecté ( important de suivre et vérifier que les algorithmes fonctionnent correctement)!
+ Objectif:
+ Activer
+ Gate :
+ Vérifier
+ Unités
+ Durée d’Action
+ Profil actif
+ "I:G (Ratio Insuline/Glucides)"
+ "Facteur SI"
+ Basal
+ Cible
+ Insuline:
+ PAS DE PROFIL PRÉDÉFINI
+ Glucides:
+ IR:
+ IR:
+ Activité:
+ IR Totale:
+ Activité IR Totale:
+ Dur:
+ Ratio:
+ Ins:
+ IR:
+ IR Totale:
+ Insuline:
+ Glucides:
+ G
+ CT
+ Glucides
+ Corr
+ U
+ Bolus IR
+ TOTAL
+ "Exécuter maintenant "
+ POMPE VIRTUELLE
+ Bolus étendu
+ OK
+ Erreur SQL
+ Dérnière exécution
+ Paramètres de saisie
+ État de la glycémie
+ Débit temporaire actuel
+ Données IR
+ Profil
+ Données repas
+ Résultat
+ Pas de données glycémiques dispo
+ Pas de profil dispo
+ Pas de pompe dispo
+ Requête
+ "Taux "
+ Durée
+ Raison
+ Glucose
+ Delta
+ Delta:
+ Moyenne
+ Config Builder
+ Objectifs
+ OpenAPS MA
+ Aperçu
+ Profil NS
+ Profil simple
+ Basal Tempo
+ Traitements
+ Pompe virtuelle
+ Careportal
+ Pompe
+ Traitements
+ Basaux tempo
+ Profil
+ APS
+ Général
+ Jours
+ Durée minimale
+ Restrictions
+ Loop
+ Loop
+ APS
+ Après traitement des restrictions
+ "Défini par pompe "
+ Dérnière mise en marche
+ OK
+ Annuler
+ Pas d\'APS séléctionné ou résultat fourni
+ Sécurité
+ Plugin désactivé
+ Violation des restrictions
+ Erreur administration bolus
+ Erreur administration temporaire
+ Valeur Basal [%]
+ % (100% = current)
+ Acceptez nouveau basal temp
+ Bolus
+ Calculateur de Bolus
+ Restriction appliquée!
+ Confirmation
+ Entrez nouveau traitement
+ Bolus
+ Bolus:
+ Basal
+ Basal:
+ Glucides
+ Changez vos entrées!
+ Définir un nouveau bolus étendu
+ Source de glycémie
+ xDrip
+ NSClient
+ Mode APS
+ Boucle fermée
+ Boucle ouverte
+ "Loop Désactivé "
+ Désactiver Loop
+ Activer Loop
+ "Nouvelle recommendation dispo "
+ Version Nightscout incompatible
+ NSClient non installé. Enregistrement perdu!
+ G disponible sur NS
+ état pompe non dispo sur NS
+ Activation manuelle
+ "LOOP DÉSACTIVÉ PAR RÉSTRICTIONS "
+ Czech
+ English
+ Basal IR
+ "Réstriction du Bolus appliquée "
+ Réstriction des Glucides appliquée
+ Contrôle de Glycémie
+ Notification
+ Remarque
+ Activité Physique
+ Changement Zone D\'insertion
+ Insertion Capteur CGM
+ Début Capteur CGM
+ Changement du Réservoir
+ Changement de Profile
+ "Bolus Goûter "
+ Bolus Repas
+ Bolus de correction
+ "Bolus Combiné "
+ "Lancer Débit Temporaire "
+ Fin du Débit Temporaire
+ Correction Glucides
+ OpenAPS Offline
+ "Type d'événement "
+ Autre
+ Lecteur
+ Capteur
+ Glucides
+ Insuline
+ Durée glucides
+ "Diviser "
+ Durée
+ "Pour cent "
+ Absolu
+ Remarques
+ "Heure de l'événement "
+ Profil
+ Entré par
+ Source de Glycémie
+ Pas de profil téléchargé encore depuis NS
+ Basal Tempo
+ Bolus étendu
+ Version Nightscout:
+ TRANSMETTRE
+ Manquants
+ Activé
+ Visible
+ Up
+ Préférences exportées
+ Exporter les paramètres au
+ Importer les paramètres depuis
+ Paramètres importés
+ Fichier introuvable
+ Exporter les paramètres
+ Importer les paramètres
+ Hollandais
+ Allemand
+ Espagnol
+ Grec
+ Italien
+ Russe
+ Suédois
+ "U/hr Max avec laquelle le débit temp pourra être programmé "
+ Cette valeur est appelée basal maximum dans le contexte OpenAPS
+ Le Basal IR maximum que l\'OpenAPS pourra délivrer [U]
+ Cette valeur est appelée Max IOB dans le contexte OpenAPS
+ Bulgare
+ DanaR
+ REJETER
+ Langue
+ Connection en cours
+ Connectée
+ Déconnectée
+ Paramètres pompe DanaR
+ Nightscout
+ Contrat de Licence pour Utilisateur Final
+ MUST NOT BE USED TO MAKE MEDICAL DECISIONS. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+ JE COMPRENDS ET J\'ACCEPTE LES CONDITIONS DU CONTRAT
+ Sauvegarder
+ L\'adaptateur bluetooth est introuvable
+ L\'appareil sélectionné est introuvable
+ Erreur connection pompe
+ IR affichée sur pompe
+ Unités Journalières
+ h passées
+ Données saisies invalides
+ Valeur n\'est pas reglée correctement
+ Actualiser le profil
+ Consulter le profil
+ Activée
+ Commentaire
+ Pour cent
+ Absolu
+ Annuler basal tempo
+ Communicateur SMS
+ Attente de résultat
+ Numéros de tél autorisés
+ +XXXXXXXXXX;+YYYYYYYYYY
+ Administrer bolus %.2fU retour avec un code %s
+ Envoyer calibrage %.2fU retour avec un code %s
+ Bolus interrompu
+ Bolus %.2fU administré avec succès
+ " %.2fU va être administré"
+ %.2fU de bolus administré avec succès
+ Entrain d\'administrer %.2fU
+ Autoriser les commandes à distance par SMS
+ Bolus à distance non autorisé
+ Doigt
+ Capteur
+ Manuel
+ Cible Temporaire
+ Annulation Cible Temporaire
+ Paramètres du profil DanaR
+ "Durée d'Action [h] "
+ Durée d\'Action d\'Insuline
+ La mise à jour du profil basal a échouée
+ Historique
+ Actualiser
+ Téléchargement en cours
+ Bolus e
+ Bolus DS
+ Bolus DE
+ Erreur
+ Remplir
+ Heure basal
+ Glucose
+ Glucides
+ Alarme
+ Total %d des enregistrements téléchargés
+ Bolus S
+ Alarmes
+ Heures Basal
+ Bolus
+ Glucides
+ Insuline quotidienne
+ Erreurs
+ Glucose
+ Remplir
+ Arrêter
+ Mot de passe pompe
+ "Mot de passe pompe incorrect "
+ Pompe occupée
+ Délivré
+ Arrêté
+ Occlusion
+ Stop
+ Boutton Stop Activé
+ Attente connection pompe
+ Attente connection pompe. Cliquez sur Actualiser
+ %.2fU va être administré
+ Paramétrez la visualisation et la surveillance des données, analysez les débits de base et les ratios
+ Vérifiez que la G est disponible sur Nightscout, et les données d’insuline sur pompe ont été téléchargées
+ Commencez par le système boucle ouverte
+ Utilisez le système Open Loop pour quelques jours, et activez manuellement plusieurs débits de base tempo
+ Comprendre votre système boucle ouverte, y compris ses recommandations de débit de base tempo
+ "Partant de ce constat, décidez quel est le débit de base maximum à choisir, et entrez le dans la pompe et les préférences "
+ Commencez par utiliser la boucle fermée avec le système Low Glucose Suspend
+ Pas de changement demandé
+ Version Nightscout incompatible
+ Utiliser le système de boucle fermée avec max IOB = 0 pour quelques jours sans avoir beaucoup d’événements LGS
+ Ajustez votre système boucle fermée, augmentez la fonction « max IOB » au dela de 0 et diminuez progressivement vos cibles glycémiques
+ Utiliser pendant quelques jours, et au moins une nuit sans les alarmes d’hypoglycémie, avant la baisse de G
+ Ajustez les débits de base et les ratios si besoin, ensuite activez « auto-sens »
+ Une semaine réussie avec des journées en boucle fermée, avec un entrée normale de glucides
+ Activez d’autres fonctionalités pour l’utilisation journalière, tel que advanced meal assist
+ Vous avez atteint la limite maximale
+ Aucun profil séléctionné
+ Loop a été désactivé
+ Loop a été désactivé
+ "Loop est désactivé "
+ Loop est activé
+ %.2f limité à %.2f
+ La valeur %s est hors limites strictes
+ Le réglage du basal à distance n\'est pas autorisé
+ La commande à distance n\'est pas autorisée
+ Lancer le basal %.2fU/h retour avec un code %s
+ Suspendre Loop pour %d minutes retour avec un code %s
+ Démarrage réussi pour %.2fU/h de basal tempo pour %d min
+ Démarage échoué pour basal tempo
+ Arrêter basal tempo retour avec un code %s
+ Basal tempo annulé
+ Annulation basal tempo échouée
+ "Commande inconnue ou fausse réponse "
+ Assistant Bolus Rapide
+ Paramètres assistant bolus rapide
+ Titre sur la touche:
+ Glucides:
+ Valide:
+ Ajouter
+ Éditer
+ Retirer
+ Repas
+ Corr
+ Coréenne
+ Actions
+ AndroidAPS est lancé
+ Uniquement téléchargement NS (sync désactivée)
+ Uniquement téléchargement NS. Ceci n’est pas efficace pour les SGV à moins qu’une source locale comme xDrip soit sélectionnée. Ceci n’est pas efficace sur les profils lorsque les profils NS sont utilisés
+ Pompe non initialisée!
+ Pompe non initialisée, profil non prédéfini
+ Amorcer/Remplir
+ Veuillez à ce que la quantité corresponde à la spécification de votre KT!
+ Autres
+ Remplir/Amorcer des quantités standard d’insuline
+ Touche 1
+ Touche 2
+ Touche 3
+ Le facteur pourcentage avec lequel le profil de base sera multiplié
+ Temps en heures avec lequel le profil sera modifié en round-robin
+ Unités
+ mg/dl
+ mmol/l
+ Durée d\'Action d\'Insuline
+ Fourchette cible:
+ "Éditer Débit de Base: "
+ "Éditer Facteur SI de Base: "
+ "Éditer I:G de Base: "
+ Profil de Base:
+ Écart de visualisation
+ Les repères hauts et bas sur les graphiques pour l’apercu et la montre
+ Repère BAS
+ Repère HAUT
+ Wear
+ Retransmettre toutes les données
+ Afficher les Paramètres sur la Montre
+ Erreur Pompe
+ Niveau Batterie Bas
+ Arrêt de la Pompe
+ Baterie Pompe déchargée
+ DanaR Coréenne
+ Taux du Débit de Base:
+ Réglage du profil de base a échoué
+ Mise à jour du profil de base dans la pompe
+ Désactiver le mode Facile UI dans la pompe
+ Activer les bolus étendus dans la pompe
+ "Modifier le mode U/d au U/h dans la pompe "
+ Le débit de base est en dessous du minimum. Profil non prédéfini!
+ G:
+ Dernière G:
+ MIQ (Multiples Injections Quotidiennes)
+ MM640g
+ Notification En Cours
+ DONNÉES ANCIENNES
+ %d min passées
+ %dmin passées
+ Profil Local
+ OpenAPS AMA
+ Courte moyenne delta
+ Longue moyenne delta
+ Panoplie de %d d\'élements. Valeur réelle
+ Données autosens
+ Script de débogage
+ Utiliser la fonction AMA autosens
+ Actualiser les événements depuis NS
+ Manger Bientôt
+ Activité
+ Retirer l\'enregistrement:
+ Dana Stats
+ DTQ Cumulative
+ DTQ avec Pondération Exponentielle
+ Basal
+ Bolus
+ DTQ
+ Date
+ Ratio
+ # Jours
+ Pondération
+ Peut-être inexact(e) si les bolus sont utilisés pour l’amorçage et le remplissage!
+ Pour les anciennes données appuyez sur Actualiser svp
+ Débit de Base Total
+ DBT*2
+ En cours d\'initialisation...
+ ACT
+ CONF
+ LOOP
+ SP
+ OAPS
+ TT
+ LP
+ DANA
+ TB
+ HOME
+ POMPEV
+ PROFIL NS
+ TRAITER
+ CP
+ OBJ
+ WEAR
+ SMS
+ Raccourcir les titres des onglets
+ Paramètres Delta
+ Toujours utilisez une moyenne (delta) courte au lieu d’une moyenne normale
+ Utile quand les données provenant de sources non filtrées lorsque xDrip devient bruyant
+ Paramètres Avancés
+ Modèle: %02X Protocole: %02X Code: %02X
+ Profil
+ Valeur par défaut : true
+ Seuls les chiffres numériques qui se trouvent dans la fourchette %1$s - %2$s sont autorisés
+ Le champs ne doit pas être vide
+ Num de tél est invalide
+ "Num tél du SMS invalide "
+ Copier dans le Presse-Papiers
+ Copier dans le Presse-Papiers
+ Afficher le journal
+ Étalonnage
+ Étalonnage
+ Transmettre l\'étalonnage %.1f à xDrip?
+ xDrip+ n\'est pas installé
+ Étalonnage envoyé à xDrip
+ L\'étalonnage à distance n\'est pas autorisé
+ "Étalonnage envoyé. La récepetion doit être activée dans xDrip. "
+ xDrip ne reçoit pas les étalonnages
+ Ne plus montrer ce message
+ Pompe suspendue. Cliquez pour actualiser le profile
+ Pompe suspendue
+ Obtenir l\'état de pompe
+ Définir basal tempo
+ Arrêter basal tempo
+ Définir bolus étendu
+ Arrêter bolus étendu
+ Mettre à jour les taux de debit de base
+ Déconnexion en cours
+ Exécution en cours
+ "Paramètres pompe virtuelle "
+ Téléchargement d\'état sur NS
+ Mauvais mot de passe
+ Mot de passe pour paramètres
+ Déverrouiller
+ L\'insuline journalière s\'approche de la limite
+ NSClient
+ NCSI
+ URL:
+ Défilement automatique
+ Redémarrer
+ NSClient
+ URL Nightscout
+ Entrez L’URL Nightscout
+ NS API secret
+ NS API secret
+ Entrez NS API secret (12 carac. min)
+ Nom de l\'appareil
+ Entrez le nom de l\'appareil
+ Cela sera utilisé pour le champ \"Entré par\"
+ Transmettre maintenant
+ Vider la file d\'attente
+ Afficher la file d\'attente
+ File d\'attente:
+ État
+ Interrompu
+ Effacer l\'histo
+ NSCLIENT ne possède pas la permission d\'écriture. Mauvais API secret?
+ Paramètres Wear
+ Afficher l\'IR détaillée
+ Décomposer l’IR dans l\'IR du bolus et basal sur la montre
+ Sans succès - vérifiez votre téléphone
+ Non disponible
+ l\'Age du patient
+ " Enfant"
+ Adolescent
+ Adulte
+ Veuillez sélectionner l’âge du patient pour paramétrer les limites de sécurité svp
+ Glimp
+ Le dispositif n’apparaît pas pour renforcer la liste blanche de l’optimisation de batterie!
+ Autorisez l\'accès svp
+ % a besoin de la liste blanche de l’optimisation batterie pour une bonne performance
+ Loop suspendu
+ Suspendu (%d m)
+ Superbolus (%d m)
+ Menu loop
+ Suspendre Loop pour 1h
+ Suspendre Loop pour 2h
+ Suspendre Loop pour 3h
+ Suspendre Loop pour 10h
+ Déconnecter la pompe 30min
+ Déconnecter la pompe 1h
+ Déconnecter la pompe 2h
+ Déconnecter la pompe 3h
+ Déconnecter la pompe 10h
+ Reprendre
+ Durée incorrecte
+ Loop suspendu
+ Loop relancé
+ Tendance 15 min
+ GR
+ Superbolus
+ Entrer le démarrage de l\'app dans NS
+ Sortir de l’application pour modifier les réglages
+ DanaRv2
+ Insuline
+ Insuline à action rapide
+ Novorapid, Humalog, Apidra
+ Fiasp
+ INS
+ Insuline Rapide à Action Prolongée
+ Activer les Superbolus dans l’assistant
+ Activer la fonctionalité superbolus dans l’assistant. Ne pas l’activez jusqu’au moment où vous appreniez comment il fonctionne réellement. IL PEUT PROVOQUER UNE OVERDOSE D’INSULINE SI UTILISÉ AVEUGLÉMENT!
+ " IR"
+ GR
+ "PRÉ "
+ BAS
+ Firmware
+ État Bluetooth
+ à propos de
+ Autorisation SMS manquante
+ DEV
+ État Xdrip (hr)
+ Barre d\'état pour xDrip (Montre)
+ xds
+ Afficher l’IG
+ Ajouter l’IG sur la barre d\'état
+ Pas de téléchargement sur NS
+ Toutes les données envoyées à NS sont abandonées. AAPS est connecté à NS mais aucun changement dans NS n’est fait
+ Incrément Basal
+ Incrément Bolus
+ Bolus étendu
+ Cible Tempo
+ Annuler Bolus étendu
+ Durée capteur
+ Durée canule
+ Durée d\'insuline
+ Heures
+ Type du Basal
+ "Facteur SI manquant dans le profile. Utilisez les valeurs par défaut. "
+ I:G manquant dans le profile. Utilisez les valeurs par défaut.
+ Basal manquant dans le profile. Utilisez les valeurs par défaut
+ Cible manquante dans le profile. Utilisez les valeurs par défaut
+ Profile incorrect!!!
+ Changement de Profil
+ Durée batterie pompe
+ Changement Batterie Pompe
+ Options d\'alarme
+ "Haute urgent "
+ Haute
+ Basse
+ Basse urgent
+ Actuellement programmé à %f
+ "Données obsolètes "
+ Données obsolètes urgent
+ "Seuil des données obsolètes [min] "
+ Seuil d\'urgence pour les données obsolètes [min]
+ "l’intervalle pour autosens [h] "
+ Le nombre d’heures écoulées pour la détection de sensibilité (le temps d’absorption des glucides est exclu)
+ SEN
+ Ignorer les événements de changement de profil
+ Tout les événements de changement de profils sont ignorés et le profil actif reste le seul profil en activité continue
+ Pompe
+ OpenAPS
+ Dispositif
+ Uploader
+ Détection de sensibilité
+ SENS
+ Sensibilité Oref0
+ "Sensibilité AAPS "
+ Paramètres d’absorption
+ Durée maximale d’absorption pour un repas
+ Le temps estimé en heures pour une absorbption totale des glucides d’un repas
+ Afficher le bolus étendu en %
+ SAGE
+ IAGE
+ CAGE
+ PBAGE
+ OAPS
+ UPLD
+ BAS
+ EXT
+ Écran verrouillé
+ verrouiller
+ En activant la fonction Autosens, n’oubliez pas de rentrer tout les glucides consommés. Sinon les déviations de glucides seront incorrectement identifiées alors que la sensibilité change !!
+ Sensibilité avec moyenne pondérée
+ OK
+ Annuler
+ Pas tous les profils sont téléchargés!
+ Valeurs non enregistrées!
+ Notifications d\'aperçu
+ Transférez les notifications d’aperçu comme des messages de confirmation sur la montre.
+ Activer les transmissions de données sur d\'autres app. (ex. Xdrip)
+ Activer les transmissions locales.
+ ACTIVITÉ et FEEDBACK
+ Question
+ Succès
+ Se connecter pour %d s
+ POMPE
+ "Valeur Basal [U/h] "
+ Durée [min]
+ Durée du Pic de la Courbe IR
+ Réglage Durée Insuline Post Prandiale Oref
+ "Durée du Pic [min] "
+ "Insuline à Action Rapide Oref "
+ Insuline à Action Ultra Rapide Oref
+ Durée d’Action pour %s trop courte - utiliser %s à la place!
+ ACTIVER LE PROFIL
+ " Date"
+ INVALID
+ Attente pour le jumelage avec la pompe
+ Jumelage réussi
+ Jumelage interrompu
+ JUMELAGE
+ Jusqu\'à présent aucun appareil n\'a été trouvé
+ Réservoir vide
+ Alerte de mesure de glycémie
+ Niveau d\'insuline restant
+ DanaRS
+ Dana
+ Pompe selectionée
+ Jumeler nouvelle pompe
+ Vitesse bolus
+ Régler incrément basal à 0.01 U/h
+ numéro de série
+ Pourcentage
+ Time shift
+ Cibles Temporaires par défaut
+ Durée pour le prochain repas
+ Cible pour le prochain repas
+ Durée d\'activité
+ Cible pour l\'activité
+ Amorcer
+ Obtenir l\'état du bolus étendu
+ Obtenir l\'état du bolus
+ Obtenir l\'état du basal tempo
+ Obtenir les paramètres pompe
+ Obtenir l\'heure sur la pompe
+ réutiliser
+ Commandes depuis la montre
+ Définir les Cibles Temp et entrer les Traitements depuis la montre
+ Connexion interrompue
+ Aliments
+ Attendre la fin du bolus. %d sec. restants
+ Traitement d\'événement
+ Administration du bolus lancée
+ Commande exécutée à l\'instant
+ Pilote pompe corrigé
+ "Pompe hors de portée "
+ Léctures de glycémie qui manquent
+ Utiliser le système de notifications pour les alertes et les notifications
+ Alertes locales
+ Alerte si aucune donnée glycémique n’est reçue
+ Alerte si la pompe est hors portée
+ Seuil de \"hors portée\" à la pompe
+ Bluetooth
+ BT Watchdog
+ Ceci va arrêter le Bluetooth du tel pour une seconde si la pompe n’est pas connectée. Cela pourrait aider dans certains tél où la connexion Bluetooth reste bancale.
+ App Dexcom G5 (adaptée)
+ Télécharger Les données glycémiques sur NS
+ Paramètres de téléchargement du G5
+ APK personalisée pour le téléchargement
+ Afficher le delta détaillé
+ Afficher delta avec une décimale supplémentaire
+ "Firmware pompe incompatible "
+ Transmettre les données G sur xDrip+
+ Dans xDrip+ veuillez séléctionner 640g/Eversense comme source de données
+ "Glycémie NSClient"
+ "Valeur du basal remplacée par la valeur minimale supportée "
+ Calcul de G
+ Calcul IR du Bolus
+ Calcul IR du Basal
+ Calcul de tendance
+ Calcul SuperBolus
+ Oui
+ Non
+ Caclcul GR
+ Dernière connexion
+ GLUCIDES et BOLUS
+ CGM et OPENAPS
+ Basal Tempo
+ Dernier bolus
+ INFO
+ Cible temporaire
+ Activer des fonctionalités suplémentaires pour l’usage diurne, telle que la fonction SMB
+ Normalement vous ne devez pas changer les valeurs mentionnées ci-dessous. CLIQUEZ ICI et LISEZ bien le texte et assurez-vous de bien le COMPRENDRE avant de changer n’importe quelle valeur
+ Valeur par Défaut : 3.0. Ceci est le réglage par défaut de l\'impact d\'absorption de glucides pendant 5 minutes. Le réglage par défaut représente 3mg/dl/5min. Ceci aura des répercussions sur quelle vitesse les GR (Glucides Restants) seront décomposés dans le sang, et combien d\'absorption de glucides sera prise en considération pour évaluer la prochaine glycémie envisagée, quand la glycémie sera en baisse plus que prévu, ou ne sera pas en hausse comme c\'était prévu
+ "Valeur par défaut : 3 Ceci est la clé de paramètre de limite de sécurité de l’OpenAPS. Ceci va limiter vos débits de base à une limite 3x, cela va être votre débit de base maximum (Pour ces personnes). Il est probable que vous n’auriez pas besoin de changer cela, mais vous devrez être conscient de ce qui a est évoqué pour le “3x max daily; 4x current” pour les limites de sécurité. "
+ Valeur par défaut : 4 Ceci est l’autre moitié de la clé de paramètre de limite de sécurité pour l’OpenAPS, et l’autre moitié de “3x max daily, 4x current” des paramètres limites de sécurité. Quel que soit le basal maximum prédéfini dans votre pompe, il ne pourra pas être plus haut que ce nombre multiplié par le taux de base actuel. Ceci est fait pour ne pas mettre l’utilisateur en danger en programmant excessivement des débits de base maximum trop élevés avant de comprendre comment l’algorithme fonctionne. Encore une fois, la valeur par défaut est 4x, la plupart des gens n’auront jamais besoin d’ajuster ce paramètre, plutôt ils auront tendance besoin d’ajuster d’autres paramètres s’ils voient qu’ils se retrouvent dans ce paramètre de limite de sécurité.
+ Valeur par défaut: 1.2 Ceci est la limite du multiplicateur pour autosens (ensuite autotune) pour être programmé à 20% en limite maximale, ceci dit va définir sur quel seuil maximum le ratio autosens pourra être programmé, à son tour va déterminer à partir de quelle valeur maximale autosens pourra ajuster les débits de base, et à partir de quelle valeur minimale va -t -il ajuster le Facteur SI (Facteur de sensibilité à l\'insuline), et à partir de quelle valeur minimale pourra t-il déterminer la cible glycémique
+ Valeur par défaut: 0.7 l’autre aspect pour les limites de sécurité pour autosens, choisir une limite qui détermine à partir de quelle valeur minimale autosens va -t -il ajuster le basal , et à partir de quelle valeur maximale pourra t-il (autosens) ajuster le Facteur SI (Facteur de sensibilité à l\'insuline) et cible glycémiques.
+ g
+ ]]>
+ kJ
+ En
+ Proteines
+ Gras (Lipides)
+ ]]>
+ "Alarme d'urgence "
+ Minutes maximales de basal pour limiter le SMB de
+ Seulement positif
+ Seulement négatif
+ Loop activé
+ APS Séléctionné
+ NSClient possède la permission d\'écriture
+ Le mode boucle fermée activé
+ "IR Maximale reglée correctement "
+ Glycémie dispo depuis la source selectionnée
+ Les valeurs du basal ne sont pas alignées sur la valeur heure : %s
+ Profile incorrect: %s
+ Programmer la pompe pour administrer un bolus
+ Actualiser
+ TDDS
+ État
+ Activité
+ Pas de connexion depuis %d min
+ %d%% (%d min restantes)
+ Initialisation
+ Déconnectée
+ Suspendu pour cause d\'erreur
+ Suspendu par l\'utilisateur
+ En cours d\'exécution
+ OpenAPS SMB
+ SMB
+ utiliser-smb
+ utiliser-uam
+ Activer UAM
+ Activer SMB
+ Utiliser les Super Micro Bolus au lieu des débits de base temporaires pour une action rapide
+ Détection des repas non annoncés
+ Annulation en cours du TBR
+ "Paramétrer TBR (%d%% / %d min) "
+ "Administration du bolus en cours (%.1f U) "
+ Actualisation en cours
+ Jamais
+ L\'opération demandée n\'est pas prise en charge par la pompe
+ Utilisation dangereuse : les bolus étendus ou carrés sont actifs. Le mode Loop a été programmé pour le low suspend seulement pour 6 heures. Uniquement les bolus normaux sont pris en charge par le mode Loop
+ Utilisation dangereuse : la pompe utilise un profile taux basal différent de celui du premier. Le Loop a été désactivé
+ Un bolus avec la même quantité d’insuline a été demandé au cours de la dernière minute. Pour prévenir l’administration accidentelle de deux bolus à la fois et pour protéger contre les bugs quand ceci (bolus) non autorisé
+ Maintenant
+ Lecture historique pompe
+ Alertes
+ Définir le profil basal
+ Niveau cartouche pompe bas
+ Niveau batterie pompe bas
+ La pompe affiche l’erreur E%d: %s
+ Pour lire l’historique des erreurs de pompe, Appuyez longuement sur le bouton ALERTES, WARNING : ceci peut provoquer un bug et ce dernier va ordonner la pompe à rejeter toutes les tentatives de connexion et qui va nécessiter d’appuyer un bouton sur la pompe pour restaurer et par conséquent le bug devrait être évité
+ Pour lire l’historique DTQ de la pompe, Appuyez longuement les boutons DTQS, WARNING : ceci peut provoquer un bug ce qui ordonne la pompe à rejeter toutes les tentatives de connexion et qui va nécessiter d’appuyer un bouton sur la pompe pour restaurer et par conséquent le bug devrait être évité
+ Minimum: %3.1f U
+ Moyen: %3.1f U
+ Maximum: %3.1f U
+ Bas
+ Vide
+ Normal
+ Mise à jour nécessaire pour l\'heure de la pompe
+ Historique
+ Warning
+ Ceci va lire l’historique et l’état complet de la pompe. Tout ce qui est dans les données et le taux du basal. Les bolus et les TBRs seront ajoutés aux traitements s’ils n’existent pas déjà. Cela peut provoquer une duplication des entrées parce que l’heure de la pompe est imprécise. Utilisant cette fonction quand la boucle normale est fortement déconseillée et réservée à des circonstances spéciales. Si vous voulez toujours essayer cela, appuyez longuement encore ce ce bouton. WARNING : ceci peut provoquer un bug ce qui ordonne la pompe à rejeter toutes les tentatives de connexion et qui va nécessiter d’appuyer un bouton sur la pompe pour restaurer et par conséquent le bug devrait être évité
+ Êtes-vous sur de bien vouloir lire toutes les données de la pompe et assumer les conséquences de cette action?
+ TBR ANNULÉ warning confirmé
+ Administration bolus échouée. Il semble qu’aucun bolus n’a été administré. Pour être sûr, Veuillez vérifier la pompe pour éviter un double bolus ensuite re bolusez une nouvelle fois
+ Seulement %.2f U de %.2f U du bolus demandé a été administré dû à une erreur. Veuillez svp vérifier la pompe pour contrôler cela et prendre les mesures appropriées
+ L’administration du bolus et la vérification de l’historique de la pompe ont échoué, Veuillez vérifier la pompe et créez un enregistrement bolus en utilisant Careportal tab si le bolus a été délivré
+ "Reconnexion après perte de connexion "
+ Pas assez d\'insuline restante dans le réservoir pour le bolus
+ Erreur administration bolus étendu
+ Insight
+ Pompe Insight
+ État
+ Modifié
+ POMPE ARRÊTÉE
+ L\'état du programme mis à jour
+ passé(e)s
+ avec
+ TBR actif
+ il vous reste min
+ Carnet
+ Dernière action completée
+ min
+ Restant supérieur
+ total
+ en amont avec
+ Rester toujours connectée
+ "Utiliser les vrais annulations TBR "
+ Annuler réellement TBR (creation d\'alarme pompe)au lieu de programmer 90% ou 110% du TBR pour 15 minutes
+ EN VEILLE
+ SYNCHRONISATION
+ CHARGÉ
+ SYNCHRONISÉ
+ STARTUP
+ besoins
+ Non connectée à l\'application compagnon
+ L\'application compagnon ne semble pas être installée
+ "Application compagnon incompatible, besoin de version "
+ Inconnue
+ Attente du code de confirmation
+ Code rejeté
+ Liaison avec app
+ Non authorisé
+ Incompatible
+ Deuxième
+ minute
+ heure
+ jour
+ semaine
+ s
+ Activer toujours SMB
+ Activer SMB avec les glucides
+ Activer SMB lorsque les GR sont actifs
+ Activer SMB avec les cibles tempo
+ "Activer SMB lorsqu'il y a une cible tempo active "
+ Activer SMB avec des cibles tempo hautes
+ Activer SMB lorsqu\'il y a une cible tempo active (exercice)
+ Activer SMB après les glucides
+ "Activer toujours SMB de manière autonome pour les bolus. Ceci est possible uniquement avec une source de glycémie ayant un filtrage de données parfait comme le G5 "
+ Activer SMB pour 6h après les glucides, même s’il y a 0 GR (Glucides Restants). Ceci est possible uniquement avec une source de glycémie ayant un filtrage de données parfait comme le G5
+ Français
+ "Seulement les chiffres numériques sont authorisés "
+ Niveau Batterie
+ Niveau Réservoir
+ Taux du Débit de Base
+
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 148b1aab2d..b508ea3051 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -66,8 +66,6 @@
Cancellare Target Temporanea
Cambia il tuo imput
Ragazzi
- Percentuale del profilo circadiano
- CPP
Chiusura Loop
Commenti
Configurazione Strutturale
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 3b62dffeab..0fb09a78d0 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -129,9 +129,9 @@
APS 모드
Closed Loop
Open Loop
- Loop 비활성화됨
- Loop 비활성화하기
- Loop 활성화하기
+ Loop 중지됨
+ Loop 중지하기
+ Loop 실행하기
새로운 제안이 있습니다
지원하지 않는 NSClient 버전입니다
지원하지 않는 Nightscout 버전입니다
@@ -183,7 +183,7 @@
임시기초주입
확장식사주입
Nightscout 버전:
- 보내기
+ 전송하기
Missing
사용
보이기
@@ -252,13 +252,12 @@
Finger
Sensor
Manual
- 임시 목표
- 임시 목표 취소
+ 임시목표
+ 임시목표 취소
DanaR 프로파일 설정
인슐린활동시간(DIA) [h]
Duration of Insulin Activity
기초주입 프로파일 갱신 실패
- 과거기록
새로고침
업로드중
E bolus
@@ -306,14 +305,15 @@
필요하면 기초주입과 비율을 조절하고, auto-sens를 활성화한다.
평소의 탄수화물을 입력하면서 1주일동안 낮시간대에 loop를 성공적으로 사용해본다.
AMA(Advanced Meal Assist)같은 낮시간대를 위한 추가적인 기능들을 실행하여 본다.
+ 낮시간대에 SMB(Super Micro Bolus)같은 추가기능을 활성화해 사용해본다.
허용된 제한값에 도달하였습니다
프로파일이 선택되지 않았습니다
Loop가 중지되었습니다.
Loop가 실행되었습니다.
Loop가 중지중입니다.
Loop가 실행중입니다.
- %.2f limited to %.2f
- 값 %s 은 하드리밋(Hard Limit)를 벗어났습니다
+ %.2f, %.2f으로 제한됨
+ %s값이 하드리밋(Hard Limit)를 벗어났습니다
원격 기초주입설정이 허가되지 않았습니다
원격 명령이 허가되지 않았습니다
기초주입 %.2fU/h 을 실행하려면 %s 를 입력하고 답장하세요
@@ -359,7 +359,6 @@
Edit Base-ISF:
Edit Base-IC:
Base Profile:
- CircadianPercentageProfile
차트 표시 범위
개요/스마트워치 차트 표시용 고/저혈당 선
저혈당 선
@@ -385,20 +384,20 @@
MM640g
연속 알림
OLD DATA
- %d분전
- %dmin ago
+ %d분전
+ %dmin ago
Local Profile
OpenAPS AMA
Short avg. delta
Long avg. delta
- Array of %d elements.\nActual value:
+ Array of %d elements.\nActual value:
Autosens 정보
Script debug
AMA autosens 기능 사용하기
NS에서 이벤트 새로고침
Eating Soon
Activity
- Remove record:
+ 기록 삭제:
DanaR 통계
누적 일총량
지수가중 일총량
@@ -422,7 +421,6 @@
TT
LP
DANA
- CPP
TB
HOME
VPUMP
@@ -437,7 +435,7 @@
단순델타값 대신 단기평균델타값을 항상 사용합니다.
xDrip의 혈당데이터에 노이즈가 심할경우 유용합니다.
고급 설정
- Model: %02X Protocol: %02X Code: %02X
+ 모델: %02X 프로토콜: %02X 코드: %02X
프로파일
기본값: 3\n이 값은 중요한 OpenAPS 안전장치입니다. 이 값의 역할은 펌프에 설정되어 있는 최대기초주입량보다 3배를 초과할 수 없게 제한하는 것입니다. 이 값을 변경할 필요는 없을 것이지만, 안전을 위해 "3x max daily; 4x current"이 의미하는 바를 알고 있어야 합니다.
기본값: 4\n이 값은 "3x max daily; 4x current"의 나머지 절반에 해당하는 또 다른 중요한 OpenAPS 안전장치입니다. 이 값은 펌프에 설정된 최대기초주입량과 관계없이, 설정된 현재시간의 기초주입량에 이 값을 곱한 양을 초과할 수 없게됩니다. 이는 알고리즘의 작동 방식을 이해하기 전에 과도하게 높은 최대 기본을 설정하여 위험한 상황에 빠지지 않도록 보호하기 위한 것입니다. 다시한번, 기본 값은 4배인 것을 알아두세요; 일반적으로 이것을 조정할 필요는 전혀 없으며, 대신 이 안전장치를 변경해야할것처럼 생각이 된다면, 다른 설정을 변경해야 할 가능성이 더 큽니다.
@@ -449,12 +447,12 @@
주의!\n보통의 경우 아래의 값을 변경하면 안됩니다. 이 값들을 변경하기 전에 반드시 이곳을 클릭하고 글을 정독해서 확실하게 이해를 하여야 합니다.
http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html
숫자만 입력가능합니다.
- 이 범위(%1$s - %2$s)안에 해당하는 숫자만 입력가능합니다.
+ 이 범위(%1$s - %2$s)안에 해당하는 숫자만 입력가능합니다.
필수 입력 항목입니다.
폰번호가 유효하지 않습니다
SMS폰번호가 유효하지 않습니다
- Copy To Clipboard
- Copied to clipboard
+ 클립보드에 복사
+ 클립보드에 복사되었습니다
로그 보기
보정
혈당 보정
@@ -476,7 +474,7 @@
연결끊기중
실행중
가상펌프 설정
- Upload status to NS
+ NS에 상태 업로드하기
잘못된 비밀번호
설정 비밀번호
설정 잠금해제
@@ -484,7 +482,7 @@
내장 NSClient
NSCI
URL:
- Autoscroll
+ 자동스크롤
Restart
내장 NSClient
Nightscout URL
@@ -500,13 +498,13 @@
Show queue
Queue:
Status:
- Paused
+ 일시중지
Clear log
NSCLIENT이 쓰기 권한이 없습니다. 잘못된 API secret인지 확인해보세요
웨어 설정
IOB 자세하게 보여주기
워치페이스에 IOB를 식사주입IOB와 기초주입IOB로 나누어서 보여줍니다.
- not successful - please check phone
+ 성공하지 못했습니다. 폰을 확인하세요
알수없음
나이
어린이
@@ -516,10 +514,9 @@
Glimp
Device does not appear to support battery optimization whitelisting!
권한을 허용하세요.
- %s needs battery optimalization whitelisting for proper performance
Loop 일시중지
일시중지중 (%d분)
- Superbolus (%d분)
+ 수퍼 식사주입 (%d분)
Loop 메뉴
1시간동안 Loop 일시중지
2시간동안 Loop 일시중지
@@ -530,24 +527,24 @@
2시간동안 펌프 일시중지
3시간동안 펌프 일시중지
10시간동안 펌프 일시중지
- 재시작
+ 재실행
기간이 잘못되었습니다.
- Loop가 일시중지되었습니다.
- Loop가 재시작되었습니다.
+ Loop가 일시중지 되었습니다.
+ Loop가 재실행 되었습니다.
15분 추이
COB
- Superbolus
+ 수퍼 식사주입
앱시작을 NS에 기록하기
설정을 적용하기위해 앱을 종료합니다.
다나Rv2
인슐린
Fast Acting Insulin
- Novorapid, Novolog, Humalog
- Fiasp
+ 노보래피드, 휴마로그, 에피드라
+ 피아스프(Fiasp)
INS
Fast Acting Insulin Prolonged
- 마법사에서 Superbolus 활성화하기
- 마법사에서 Superbolus 기능을 활성화합니다. 어떤 기능인지 확실히 알기전까지 활성화 하지 마세요. 제대로 알지 못하고 사용하면 일슐린이 과다 주입될 수 있습니다!
+ 마법사에서 수퍼 식사주입 활성화하기
+ 마법사에서 수퍼 식사주입 기능을 활성화합니다. 어떤 기능인지 확실히 알기전까지 활성화 하지 마세요. 제대로 알지 못하고 사용하면 일슐린이 과다 주입될 수 있습니다!
IOB
COB
PRE
@@ -584,15 +581,15 @@
펌프배터리사용기간
펌프 배터리 교체
알람 옵션
- Urgent high
- High
- Low
- Urgent low
+ 위험 고혈당
+ 고혈당
+ 저혈당
+ 위험 저혈당
Currently set to %f
- Stale data
- Urgent stale data
- Stale data threshold [min]
- Urgent stale data threshold [min]
+ 누락 데이터
+ 위험 누락 데이터
+ 누락 데이터 기준값[분]
+ 위험 누락 데이터 기준값[분]
autosens 시간 [h]
민감도를 감지하기 위해 계산될 총 시간 (탄수화물 흡수 시간은 제외됩니다.)
SEN
@@ -604,8 +601,8 @@
Uploader
민감도 감지
SENS
- Sensitivity Oref0
- Sensitivity AAPS
+ 민감도 Oref0
+ 민감도 AAPS
흡수 설정
식사 최대 흡수 시간 [h]
식사로 섭취한 탄수화물이 모두 흡수될기까지 예상되는 시간
@@ -621,12 +618,11 @@
화면 잠금
잠금
Autosense 기능을 켜면 모든 섭취된 탄수화물양을 입력하십시오. 그렇지 않으면 탄수화물 편차(deviations)가 민감도 변화로 잘못 인식될것입니다!!
- Sensitivity WeightedAverage
+ 민감도 가중평균
OK
Cancel
- needs to be activated to send values to the pump!
- Not all profiles loaded!
- Values not stored!
+ Not all profiles loaded!
+ Values not stored!
개요 알림
개요 알림을 웨어확인메세지로 전달합니다.
(xDrip 같은) 다른 앱으로의 브로드캐스트를 활성화합니다.
@@ -637,13 +633,13 @@
펌프
Basal value [U/h]
Duration [min]
- IOB Curve Peak Time
- Peak Time [min]
+ IOB 커브 피크 시간
+ 피크 시간[분]
Free-Peak Oref
Rapid-Acting Oref
Ultra-Rapid Oref
- "DIA of %s too short - using %s instead!"
- ACTIVATE PROFILE
+ "DIA %s는 너무 짧습니다. 대신 %s을 사용하세요!"
+ 프로파일 활성화하기
Date
INVALID
펌프연동 대기중
@@ -678,4 +674,60 @@
워치로 작동하기
임시목표와 관리입력을 워치로 설정합니다.
연결시간초과
+ 음식
+ g
+ ]]>
+ kJ
+ En
+ Pr
+ Fat
+ ]]>
+ 식사주입 종료를 기다리고 있습니다. %d초 남았습니다.
+ 이벤트 처리중
+ 식사주입을 시작합니다.
+ 명령을 지금 실행합니다.
+ 펌프 드라이버가 수정되었습니다.
+ 펌프에 연결할 수 없습니다.
+ 혈당 읽기가 누락되었습니다.
+ 경고와 알림시 시스템 알림 사용하기
+ 자체 경고 기능
+ 혈당 데이터 누락시 경고하기
+ 펌프와 연결불가시 경고하기
+ 펌프 연결불가 기준시간[분]
+ 긴급 알람
+ 정보
+ 블루투스
+ 블루투스 감시기능
+ 펌프에 연결이 되지 않을때 폰의 블루투스를 1초간 껐다 켭니다. 블루투스 스택이 정지되는 일부폰에 이 기능이 도움이 됩니다.
+ (패치된) DexcomG5 앱
+ NS에 혈당데이터 업로드하기
+ G5업로드 세팅
+ Customized APK for download
+ 델타(혈당증분값) 자세히 보여주기
+ 소수점 한자리 더 추가된 델타 보여주기
+ 지원되지 않는 펌프 펌웨어
+ 혈당 데이터를 xDrip+에 전송하기
+ xDrip+ 데이터 소스에서 640g/Eversense을 선택하세요
+ 지원되는 최소값으로 기초주입량이 대체되었습니다.
+ 혈당 계산
+ 식사주입 IOB 계산
+ 기초주입 IOB 계산
+ 추세계산
+ 수퍼 식사주입 계산
+ 네
+ 아니오
+ 양수만
+ 음수만
+ COB 계산
+ 임시목표 계산
+ Loop 활성화됨
+ APS 선택됨
+ NSClient가 쓰기권한이 있습니다
+ Closed 모드가 활성화됨
+ 최대 IOB가 바르게 설정됨
+ 선택한 소스에서 혈당이 들어옵니다.
+ 기초주입값이 시간단위로 설정되지 않았습니다: %s
+ 유효하지 않은 프로파일: %s
+ 펌프 이력
+ 확장식사주입 에러
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index e40e9c2b59..5090a130a9 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -159,9 +159,8 @@
Gekopieerd naar klembord
Kopieren naar klembord
Correctie
- Niet alle profielen zijn geladen!
- Moet geactiveerd worden om waardes naat de pomp te verzenden!
- Waarden niet opgeslagen!
+ Niet alle profielen zijn geladen!
+ Waarden niet opgeslagen!
Čeština
Alarm
Basaal uur
@@ -308,7 +307,6 @@
Verkeerde ingave
Pomp IOB
Basaal:
- CPP
Dagtotaal insuline
Datum
Totaal basaal
@@ -451,7 +449,7 @@
Geen profiel beschikbaar
Maximaal basaal IOB OpenAPS kan toedienen [E]
Profiel
- Waarde %s is buiten de toegestane limieten
+ Waarde %s is buiten de toegestane limieten
Basis basale dosis
Laatse berekening
Laatste uitvoering
@@ -521,7 +519,6 @@
Basaal stap
Bolus limiet ingesteld
KH limiet ingesteld
- CircadianPercentageProfiel
S Bolus
DanaR Statistiek
Cumulative TDD
@@ -627,7 +624,7 @@
Model: %02X Protokoll: %02X Code: %02X
Verbonden gedurende %d s
Totaal %d gegevens geupload
- %.2f gelimitteerd tot %.2f
+ %.2f gelimitteerd tot %.2f
Om de loop te onderbreken voor %d minuten antwoord met de code %s
Tijdelijk basaal %.2fE/u voor %d minuten succesvol gestart
Gemiddelde gevoeligheid
@@ -676,16 +673,12 @@
Bedieningen via horloge
Ampull leeg
Wachten op koppelen van de pomp
- Storingen
Wijzigingen van profiel
Bluetooth
Voeding
Waarschuwing bij niet bereikbare pomp
Een bolus met dezelfde hoeveelheid was gevraagd binnen de minuut. Om accidentiële of door bugs veroorzaakte dubbele bolussen te vermijden is deze bolus geannuleerd
- estopt Bolus toediening wordt
Vet
- Bolus toediening gestopt
- Gebruik systeem notificaties voor waarschuwingen
Toon gedetaillieerde delta
Niet ondersteune pomp firmware
DexcomG5 App (aangepast)
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000000..ae999de5b6
--- /dev/null
+++ b/app/src/main/res/values-ro/strings.xml
@@ -0,0 +1,590 @@
+
+
+ Setări siguranță tratament
+ Bolus maxim admis [U]
+ Carbohidrați admiși maxim [g]
+
+ Preferințe
+ Încarcă tratamentele din NS
+ Backup
+ Testează alarma
+ Resetează bazele de date
+ Sigur resetați bazele de date?
+ Ieșire
+ Folosiți bolusuri extinse pentru >200%
+ Dispozitive bluetooth DanaR
+ Folosesțe întotdeauna valori absolute ale bazalei
+ Restartați telefonul sau reporniți aplicația AndroidAPS din System Settings \naltfel AndroidAPS nu va putea face loguri (importante pentru verificarea corectitudinii funcționării algoritmului)!
+
+ Obiectiv:
+ Poartă:
+ Start
+ Verifică
+ Unități
+ DIA
+ Profil activ
+ IC
+ ISF
+ Bazală
+ Țintă
+ NICIUN PROFIL SETAT
+ Insulină:
+ Carbohidrați:
+ IOB:
+ IOB:
+ Activitate:
+ Total IOB:
+ Total IOB activitate:
+ Durată:
+ Rpt:
+ Ins:
+ IOB:
+ IOB totală:
+ Cantitatea de insulină
+ Cantitatea de carbohidrați
+ BG
+ Carbohidrați
+ Corecție
+ U
+ Bolus IOB
+ TOTAL
+ Fă acum
+ POMPĂ VIRTUALĂ
+ Rata bazală normală
+ Bazală temporară
+ Bolus extins
+ Baterie
+ Rezervor
+ OK
+ Eroare SQL
+ Ultima acțiune
+ Parametri de intrare
+ Stare glicemie
+ Temp curentă
+ Date IOB
+ Profil
+ Date despre masă
+ Rezultat
+ Nu există date despre glicemie
+ Niciun profil disponibil
+ Nicio pompă disponibilă
+ Nu este solicitată nicio schimbare
+ Solicită
+ Ținta de jos
+ Rată
+ Durată
+ Motiv
+ Glicemie
+ Diferență
+ Diferență:
+ Diferență medie
+
+ Constructor de configurație
+ Obiective
+ OpenAPS MA
+ Privire ansamblu
+ Profil NS
+ Profil simplu
+ Bazale temporare
+ Tratamente
+ Pompă virtuală
+ Careportal
+
+
+ Pompă
+ Tratamente
+ Bazale temporare
+ Profil
+ APS
+ General
+ zile
+ Durată minimă
+ Constrângeri
+
+ Loop
+ Loop
+ APS
+ Constrângeri după procesare
+ Setat de pompă
+ Ultima acțiune
+ Doriți reîncărcarea tratamentelor din Nightscout
+ Doriți reîncărcarea țintelor temporare din Nightscout
+ OK
+ Renunță
+ NICIUN ALGORITM SELECTAT SAU REZULTAT GENERAT
+ Siguranță
+ Modulul este dezactivat
+ Constrângere încălcată
+ Eroare injectare bolus
+ Eroare acțiune bazală temporară
+ Basal value
+ % (100% = curentă)
+ Acceptă noua bazală temporară:
+ Bolus
+ Calculator
+ Constrângere aplicată!
+ Confirmare
+ Introduceți noul tratament:
+ Bolus
+ Bolus:
+ Bazală
+ Bazală:
+ Carbohidrați
+ Schimbați textul!
+ Stabiliți un nou bolus extins:
+ Sursa glicemiei
+ xDrip
+ NSClient
+ Mod APS
+
+ Buclă închisă
+ Buclă deschisă
+ Buclă inactivă
+ Dezactivează bucla
+ Activează bucla
+
+ O nouă sugestie este disponibilă
+ Versiune incorectă de NSClient
+ NSClient nu este instalat. Înregistrare pierdută!
+ Glicemie disponibilă în NS
+ Starea pompei disponibilă în NS
+ Acțiuni manuale
+ BUCLĂ DEZACTIVATĂ DE CONSTRÂNGERI
+ Czech
+ English
+ IOB bazală
+ Constrângere de bolus aplicată
+ Constrângere de carbohidrați aplicată
+ Verificare glicemie
+ Anunț
+ Notă
+ Întrebare
+ Exercițiu
+ Schimbare loc pompă
+ Inserare senzor
+ Start senzor
+ Schimbare cartuș insulină
+ Schimbare profil
+ Gustare
+ Masă
+ Corecție
+ Bolus combo
+ Start bazală temporară
+ Sfârșit bazală temporară
+ Corecție carbohidrați
+ OpenAPS Offline
+
+ Tip eveniment
+ Altul
+ Glucometru
+ Senzor
+ Carbohidrați
+ Insulină
+ Ora carbohidrați
+ Împarte
+ Durată
+ Procent
+ Absolut
+ min
+ Note
+ Ora evenimentului
+ Profil
+ Înregistrat de
+ Tip glicemie
+ Nu am încărcat încă un profil din NS
+ Bazală temporară
+ Bolus extins
+ Versiune NSClient:
+ Versiune Nightscout:
+ TRIMITE
+ Lipsă
+ Activ
+ Vizibil
+ Sus
+ Am exportat preferințele
+ Exportă setările către
+ Import setările din
+ Setări importate
+ Nu am găsit fișierul
+ Exportă setările
+ Importă setările
+ German
+ Spanish
+ Greek
+ Italian
+ Russian
+ Valoarea minimă acceptată a glicemiei (țintă jos).
+ Valoarea maximă acceptată a glicemiei (țintă sus).
+ Maximul de unițăți de insulină pe oră (U/h) poate fi setat la
+ Această valoare este denumită bazală maximă în contextul OpenAPS
+ Maximul de bazală IOB pe care o poate da OpenAPS[U]
+ Această valoare este denumită Max IOB în contextul OpenAPS\nAceastă valoare este implicit nulă (0). După câteva zile sau săptămâni, în funcție de opțiunea dumneavoastră, puteți ajusta acest număr.
+ Bulgarian
+ RENUNȚĂ
+ Limba
+
+ DanaR
+ Se conectează
+ Conectat
+ Deconectat
+ Sincronizează profilul către pompă
+ Setări pompă DanaR
+ Nightscout
+ Licență utilizator final
+ NU TREBUIE SĂ FOLOSIȚI PENTRU LUAREA DE DECIZII MEDICALE. NU EXISTĂ RĂSPUNDERE LEGALĂ SAU GARANȚIE PENTRU ACEST PROGRAM, ÎN LIMITA APLICABILĂ A LEGII. CU EXCEPTIA CAZURILOR SPECIAL MENȚIONATE, AUTORUL ȘI/SAU ALTE PERSOANE IMPLICATE PUN LA DISPOZIȚIE ACEST PROGRAM FĂRĂ NICIO GARANȚIE, IMPLICITĂ SAU EXPLICITĂ, INCLUZÂND, DAR FĂRĂ A SE LIMITA LA, GARANȚIILE LEGATE DE VĂNZAREA SAU POTRIVIREA PENTRU UN ANUME SCOP. ÎNTREGUL RISC LEGAT DE CALITATEA ȘI PERFORMANȚA ACESTUI PROGRAM CAD ÎN RESPONSABILITATEA DUMNEAVOASTRĂ. DACĂ PROGRAMUL SE DOVEDEȘTE A FI DEFECT, DUMNEAVOASTRĂ VĂ ASUMAȚI ÎNTREAGA RĂSPUNDERE, PRECUM ȘI TOATE COSTURILE LEGATE DE SERVICE, REPARAȚII SAU CORECȚII.
+ ÎNȚELEG ȘI SUNT DE ACORD
+ Salvează
+ Nu s-a găsit niciun adaptor bluetooth
+ Dispozitivul selectat nu a fost găsit
+ Eroare de corecție a pompei
+ IOB din pompă
+ Unități zilnice
+ Ultimul bolus:
+ ore
+ Date de intrare incorecte
+ Valoare setată incorect
+ Reîncarcă profilul
+ Afișează profilul
+ Făcut
+ Comentariu
+ Succes
+ Procent
+ Absolut
+ Renunță la bazala temporară
+ SMS Communicator
+ Se așteaptă rezultatul
+ Numere de telefon permise
+ +XXXXXXXXXX;+YYYYYYYYYY
+ Pentru a livra un bolus de %.2fU răspundeți cu codul %s
+ Pentru a trimite calibrarea cu %.2f răspundeți cu codul %s
+ Bolus eșuat
+ Bolusul de %.2fU livrat cu succes
+ Se va livra un bolus de %.2fU
+ Bolusul de %.2fU a fost livrat cu succes
+ Se livrează %.2fU
+ Permite comenzi distante prin SMS
+ Bolusare prin comenzi de la distanță interzise
+ Deget
+ Senzor
+ Manual
+ Țintă temporară
+ Renunțare la ținta temporară
+ Setări de profil DanaR
+ DIA [h]
+ Durata de Acțiune a Insulinei (DIA)
+ Setarea profilului bazalei eșuată
+ Istoric
+ Reîncărcare
+ Se trimite
+ E bolus
+ DS bolus
+ DE bolus
+ eroare
+ reumplere
+ bazală pe oră
+ glicemie
+ carbohidrați
+ alarmă
+ S-au transmis %d înregistrări
+ S bolus
+ Alarme
+ Ore bazale
+ Bolusuri
+ Carbohidrați
+ Insulină zilnică
+ Erori
+ Glicemie
+ Reumplere
+ Suspendare
+ Conectare de %d s
+ Parola pompei
+ Parola pompei greșită!
+ Pompa face altă acțiune
+ Livrat
+ Oprit
+ Ocluzie
+ Stop
+ STOP APĂSAT
+ Se așteaptă pompa
+ Se așteaptă pompa. Apasă pentru reîncărcare.
+ Se vor livra %.2fU
+ Se stabilesc vizualizările și monitorizarea și se analizează bazalele și valorile ratelor
+ Verificați că vedeți glicemia în Nightscout și că datele despre insulină date de pompă sunt înregistrate în site
+ Pornire cu buclă deschisă
+ Rulați modul buclă deschisă pentru câteva zile și faceți manual bazalele temporare sugerate
+ Trebuie să se înțeleagă modalitatea de funcționare a buclei deschise, incluzând recomandările de bazală temporară
+ Pe baza acestei experiențe, decideți care va fi bazala maximă și setați această valoare în pompă și în preferințe
+ Se începe etapa de buclă închisă cu Suspendarea Insulinei la Valori Glicemie Mici (Low Glucose Suspend = LGS)
+ Folosiți sistemul în buclă închisă cu IOB maxim = 0 pentru câteva zile fără prea multe evenimente LGS
+ Acordați fin performanța buclei închise, prin mărirea valorii max IOB peste 0 și micșorarea graduală a țintelor glicemice
+ Folosiți pentru câteva zile și cel puțin o noapte fără a avea alarme de hipoglicemie înainte de scăderea glicemiei
+ Ajustați bazalele și ratele dacă este cazul și apoi activați auto-sens
+ O săptămână de folosire cu succes a sistemului cu buclă închisă cu introducerea normală de carbohidrați
+ Folosirea instrumentelor adiționale pentru timpul zilei, cum ar fi asistența avansată pentru mese
+ Ați atins limita permisă
+ Valoare țintă pentru calcule
+ Niciun profil selectat
+ Bucla a fost dezactivată
+ Bucla a fost activată
+ Bucla este dezactivată
+ Bucla este activată
+ %.2f limitat la %.2f
+ Valoarea %s este în afara limitelor
+ Setarea de la distanță a bazalei nu este permisă
+ Comanda de la distanță nu este permisă
+ Pentru pornirea bazalei de %.2fU/h trimiteți codul %s
+ Pentru suspendarea buclei pentru %d minute trimiteți codul %s
+ Bazala temporară %.2fU/h pentru %d minute a fost trimisă cu succes
+ Trimiterea bazalei temporare a eșuat
+ Pentru oprirea bazalei temporare trimiteți codul %s
+ Bazala temporară a fost anulată
+ Renunțarea la bazala temporară a eșuat
+ Comandă necunoscută sau răspuns greșit
+
+ AsistentRapid
+ Setări AsistentRapid
+ Text buton:
+ Carbohidrați:
+ Valid:
+ Adaugă
+ Editează
+ Șterge
+ Masă
+ Corecție
+ Korean
+ Acțiuni
+ AndroidAPS a pornit
+ Doar încărcare în NS (sincronizare dezactivată)
+ Please deactivate "NS upload only" to use this feature.
+ Doar încărcare în NS. Nu are efect asupra SGV decât în cazul selectării unei surse locale, precum xDrip. Nu acționează asupra Profilelor cât timp se folosesc profilele din Nightscout.
+ Pompa nu este inițializată!
+ Pompa nu este inițializată, profilul nu este setat!
+ Pregătire/umplere
+ Asigurați-vă că aveți cantitatea specificată de instrucțiunile setului de infuzie!
+ Alte
+ Button 1
+ Pregătire/umplere cu cantitățile standard de insulină.
+ Buton 2
+ Buton 3
+ Procentul factorului cu care profilul bazal va fi mărit.
+ Time in hours by which the profile will be shifted round robin.
+ Timpul în ore în care profilul va fi rotunjit prin metoda round-robin
+ TRIMITE CĂTRE POMPĂ
+ Unități:
+ mg/dl
+ mmol/l
+ DIA:
+ Intervalul țintă:
+ Editează bazala normală:
+ Editează ISF normal:
+ Editează IC normal:
+ Profilul de bază:
+ Sfârșit bazală temporară
+ Început bazală temporară
+ Intervalul pentru vizualizare
+ Valoarea maximă și minimă pentru graficele din vizualizare și pentru smartwatch
+ Pragul HIPO
+ Pragul HIPER
+ Wear
+ Retrimite toate datele
+ Deschide setările pe Wear
+ Eroare de pompă
+ Baterie aproape descărcată
+ Pompa se oprește
+ Bateria pompei este descărcată
+ DanaR Korean
+ Driver de pompă selectat greșit
+ Rată bazală:
+ Setarea profilului bazalei a eșuat
+ Profilul bazalei a fost modificat în pompă
+ Dezactivează modul EasyUI în pompă
+ Activează bolusuri extinse în pompă
+ Schimbă din modul U/d în U/h în pompă
+ Valoarea bazalei este sub minim. Profilul nu este setat!
+ Glicemie:
+ Ultima glicemie:
+ MDI
+ MM640g
+ Notificare activă
+ DATE VECHI
+ acum %dmin
+ acum %dmin
+ Profil local
+ OpenAPS AMA
+ Media scurtă a deviației
+ Media lungă a deviației
+ Matrice cu %d elemente.\nValorea efectivă:
+ Date Autosens
+ Script debug
+ Folosește opțiunea autosens AMA
+ Țintă temporară
+ Reîncarcă țintele temporare din NS
+ Masă în curând
+ Activitate
+ Șterge înregistrarea:
+ Statistici DanaR
+ TDD cumulat
+ TDD cântărit exponențial
+ Bazală
+ Bolus
+ TDD
+ Data
+ Rata
+ # Zile
+ Greutate
+ Posibil fără acuratețe bună în cazul folosirii de bolusuri pentru pornire/umplere!
+ Date vechi, apăsați "RELOAD"
+ Total bazală normală
+ TBB * 2
+ Inițializare...
+ ACT
+ CONF
+ BUCL
+ SP
+ OAPS
+ TT
+ LP
+ DANA
+ TB
+ ACASĂ
+ POMPĂV
+ PROFILNS
+ TRAT
+ CP
+ OBI
+ WEAR
+ SMS
+ Scurtează titlurile taburilor
+ Setări diferențe
+ Folosește întotdeauna media scurtă a diferenței în locul diferenței simple
+ Folositor când datele vin de la surse nefiltrate, ca atunci când xDrip are măsurători zgomotoase.
+ Setări avansate
+ Model: %02X Protocol: %02X Cod: %02X
+ Profil
+ Valoare implicită: 3\nAceasta este o setare de critică de securitate a OpenAPS. Asta înseamnă că se limitează bazala lade 3x valoarea maximă a bazalelor tale.Cel mai probabil nu veți schimba această valoare, dar trebuie să țineți cont de ce se discută despre “3x max zilnic; 4x curent” ca valori de siguranță.
+ Valoare implicită: 4\nAceasta este cealaltă jumătate a cheii de siguranță a OpenAPS și cealaltă jumătate a "3x max zilnic; 4x curent" al setărilor de siguranță.Aceasta înseamnă că bazala dumneavoastră, indiferent de bazala maximă configurată în pompă, nu poate fi mai mare de acest număr înmulțit cu nivelul curent al bazalei active. Această limitare este impusă pentru a evita posibilitatea de a intra pe un teritoriu periculos prin setarea unei bazale maxime excesiv de mari înainte de a înțelege funcționarea algoritmului. Din nou, valoarea implictă este 4x; majoritatea oamenilor nu vor trebui să ajusteze această valoare și vor modifica, mai degrabă, alte valori dacă vor simți că această valoare le stă în cale.
+ Valoare implicită: 1.2\nAceasta este valoarea limită de multiplicare pentru autosens (și pentru autotune, în curând) pentru a seta o limită maximă de 20% din cât de mare poate fi raportul autosens, care, la rândul ei, determină cât de mult poate autosens să modifice bazalele, cât de jos poate modifica ISF și cât de jos poate pune ținta glicemiei.
+ Valoare implicită: 0.7\nCealaltă parte a limitelor autosens, care limitează cât de jos poate ajusta bazalele și cât de mult poate mări ISF și țintele de glicemie.
+ Valoare implicită: adevărat\nAceasta se folosește pentru a permite autosens să ajusteze țintele de glicemie, pe lângă modificările asupra ISF și bazalelor.
+ Valoare implicită: 2\nAmânarea bolusului este aplicată după ce ați făcut un bolus de masă, astfel încât bucla să nu reacționeze cu ținte bazale temporare scăzute atunci când tocmai ați mâncat. Exemplul de față și valoarea implicită sunt 2; astfel o durată de acțiune a insulinei (DIA) de 3 ore duce la o eliminare treptată a întârzierii setării bazalelor temporare după 1.5 ore (3DIA/2).
+ Valoare implicită: 3.0\nAceasta este o setare ce privește impactul carbohidraților pe o durată de 5 minute. Valoarea implicită este de așteptat a fi 3mg/dl/5min. Aceasta afectează cât de mult se scade valoarea COB și cât de mare este presupusă a fi absorbția de carbohidrați în calcularea valorii prezise a glicemiei, atunci când glicemia scade cu mai mult decât s-a estimat sau când nu crește așa cum s-a așteptat.
+ Atenție!\nÎn mod normal nu este nevoie să modificați valorile de mai jos. Vă rog să APĂSAȚI AICI și să CITIȚI textul și să vă asigurați că l-ați ÎNȚELES înainte de a schimba valorile.
+ http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html
+ Se acceptă numai valori numerice.
+ Se acceptă numai valori numerice între %1s - %2s.
+ Acest câmp nu trebuie lăsat necompletat
+ Numărul de telefon este invalid
+ Număr de telefon SMS invalid
+ Copiază în clipboard
+ Copiat în clipboard
+ Afișează istoricul
+ Calibrare
+ Glicemie calibrare
+ Trimite calibrarea %.1f către xDrip?
+ xDrip+ nu este instalat.
+ Calibrare trimisă către xDrip
+ Calibrarea la distanță nu este permisă
+ Calibrare trimisă. Recepționarea trebuie să fie activată și în xDrip.
+ xDrip nu recepționează calibrări
+ Nu mai afișa din nou
+ Livrarea de insulină este suspendată. Apăsați pentru verificarea statusului
+ Livrare de insulină suspendată
+ Se primește starea pompei
+ Se setează bazala temporară
+ Se oprește bazala temporară
+ Se pornește bolusul extins
+ Se oprește bolusul extins
+ Se restabilesc ratele bazale
+ Se deconectează
+ Se execută
+ Setări pompă virtuală
+ Trimitere status către NS
+ Parolă greșită
+ Parola pentru setări
+ Deblochează setările
+ Se apropie limita zilnică de insulină
+ NSClient
+ NSCI
+ URL:
+ Autoscroll
+ Restart
+ NSClient
+ Adresa Nightscout
+ Introduceți adresa Nightscout
+ Cheia API NS
+ Cheia API NS
+ Introduceți cheia API NS (min 12 caractere)
+ Numele dispozitivului
+ Introduceți numele dispozitivului
+ Se va folosi pentru câmpul introdusDe
+ Livrează acum
+ Curăță coada de așteptare
+ Arată coada de așteptare
+ Coadă:
+ Status:
+ Suspendat
+ Șterge istoricul
+ NSCLIENT nu are permisiuni de scriere. Cheia API este corect scrisă?
+ Setări Wear
+ Arată IOB detaliat
+ Separă IOB în bolus și IOB bazal pe ceas
+ fără succes - verificați telefonul
+ Nu este disponibil
+ Vârsta pacientului
+ Copil
+ Adolescent
+ Adult
+ Vă rog să selectați vârsta pacientului în vederea stabilirii valorilor maxime admise de siguranță
+ Glimp
+ Se pare că dispozitivul nu suportă excluderea din lista de optimizare a bateriei!
+ Vă rog să activați permisiunea
+ %s necesită excluderea din lista de optimizare a bateriei pentru funcționare corespunzătoare
+ Buclă suspendată
+ Suspendată (%d m)
+ Superbolus (%d m)
+ Meniul pentru buclă
+ Suspendă bucla pentru 1h
+ Suspendă bucla pentru 2h
+ Suspendă bucla pentru 3h
+ Suspendă bucla pentru 10 h
+ Deconectează pompa pentru 30 min
+ Deconectează pompa pentru 1h
+ Deconectează pompa pentru 2h
+ Deconectează pompa pentru 3h
+ Deconectează pompa pentru 10h
+ Restabilește
+ Durată greșită
+ Buclă suspendată
+ Buclă restabilită
+ Tendință 15min
+ COB
+ Superbolus
+ Înregistrează pornirea aplicației în NS
+ Se iese din aplicație în vederea aplicării setărilor.
+ Insulină
+ Insulină rapidă
+ Novorapid, Novolog, Humalog
+ INS
+ Insulină rapidă cu efect prelungit
+ Activează superbolus în asistent
+ Activează funcționalitatea de superbolus în asistentul de buclă. Nu activați până nu înțelegeți ce face cu adevărat. DACĂ ESTE FOLOSIT ÎN NECUNOȘTINȚĂ DE CAUZĂ POATE DUCE LA SUPRADOZĂ DE INSULINĂ!
+ IOB
+ COB
+ PRE
+ BAS
+ Firmware
+ Ultima conectare
+ Status bluetooth
+ Despre
+ Lipsesc permisiunile de SMS
+ DEV
+ Status xDrip (ceas)
+ Linie de status xDrip (ceas)
+ xds
+ Arată BGI
+ Adaugă BGI în linia de status
+ Fără trimitere către NS
+ Toate trimiterile de date către NS sunt oprite. AAPS este conectat la NS dar nu se fac schimbări în NS
+ Pas bazală
+ Pas bolus
+
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 1535d82c26..929834952d 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -79,8 +79,6 @@
отмена времнной цели
измените введенные данные
ребенок
- суточный процентный профиль
- СПП
очистка очереди
очистка лога
замкнутый цикл
@@ -362,8 +360,8 @@
результат
выполнить сейчас
отладка скрипта
- %.2f ограничено до %.2f
- величина %s недопустима
+ %.2f ограничено до %.2f
+ величина %s недопустима
открытый цикл
есть новое предложение
другое
@@ -581,9 +579,8 @@
сенсор пропаботал
ВОЗРСенс
определение чувствительности
- не все профили загружены!
- требует активации для отправки данных на помпу!
- Данные не сохранены!
+ не все профили загружены!
+ Данные не сохранены!
Просмотреть расширенный болюс %
DanaRv2
дата
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index b27b70da43..2fba574ff2 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -80,8 +80,6 @@
Temp Mål BG Slut
Ändra inmatning
Barn
- Cirkadisk Profil Procent
- CPP
Ta bort kö
Rensa inmatningar
Closed Loop
@@ -477,8 +475,8 @@
Andra
Ny behandlingsrekommendation tillgänglig
Open Loop
- Värde %s är utanför gränserna
- %.2f begränsad till %.2f
+ Värde %s är utanför gränserna
+ %.2f begränsad till %.2f
Kör nu
Fråga
Profil
@@ -546,8 +544,7 @@
Batteribyte Pump
Sensor ålder
SAGE
- Måste vara aktiverad för att kunna skicka värden till pumpen
- Värden sparas inte
+ Värden sparas inte
Möjligen felvärde om man använder bolus för att priming/fyllning!
Ändra Base-IC:
Ändra Base-ISF:
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index ad6a2e1166..4f096c46a3 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -15,37 +15,45 @@
- @string/bg_lang
- @string/cs_lang
- @string/de_lang
+ - @string/fr_lang
- @string/nl_lang
- @string/es_lang
- @string/el_lang
- @string/it_lang
- @string/ko_lang
+ - @string/ro_lang
- @string/ru_lang
- @string/sv_lang
+ - @string/zh_lang
- en
- bg
- cs
- de
+ - fr
- nl
- es
- el
- it
- ko
+ - ro
- ru
- sv
+ - zh-rCN
- @string/child
- @string/teenage
- @string/adult
+ - @string/resistantadult
- @string/key_child
- @string/key_teenage
- @string/key_adult
+ - @string/key_resistantadult
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 4c5c58c993..67def00b04 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -5,6 +5,8 @@
#FFFB8C00
#FFFFCC03
#8BC34A
+ #ffea00
+ #ff9500
#FFFFFF
#00FF00
#FF0000
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a92fc9bb5e..2b6077860c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -209,8 +209,11 @@
Spanish
Greek
Italian
+ Romanian
Russian
Swedish
+ French
+ Chinese
Max U/hr a Temp Basal can be set to
This value is called max basal in OpenAPS context
Maximum basal IOB OpenAPS can deliver [U]
@@ -268,7 +271,6 @@
DIA [h]
Duration of Insulin Activity
Failed to update basal profile
- Errors
Reload
Uploading
E bolus
@@ -323,8 +325,8 @@
Loop has been enabled
Loop is disabled
Loop is enabled
- %.2f limited to %.2f
- Value %s is out of hard limits
+ %.2f limited to %.2f
+ Value %s is out of hard limits
Remote basal setting is not allowed
Remote command is not allowed
To start basal %.2fU/h reply with code %s
@@ -334,7 +336,7 @@
To stop temp basal reply with code %s
Temp basal canceled
Canceling temp basal failed
- Uknonwn command or wrong reply
+ Uknown command or wrong reply
QuickWizard
QuickWizard settings
@@ -371,7 +373,6 @@
Edit Base-ISF:
Edit Base-IC:
Base Profile:
- CircadianPercentageProfile
Range for Visualization
High and low mark for the charts in Overview and Smartwatch
LOW mark
@@ -434,7 +435,6 @@
TT
LP
DANA
- CPP
TB
HOME
VPUMP
@@ -452,9 +452,9 @@
Model: %02X Protocol: %02X Code: %02X
Profile
max_daily_safety_multiplier
- Default value: 3\nThis is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware that’s what is discussed about “3x max daily; 4x current” for safety caps.
+ Default value: 3 This is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware that’s what is discussed about “3x max daily; 4x current” for safety caps.
current_basal_safety_multiplier
- Default value: 4\nThis is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.
+ Default value: 4 This is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.
autosens_max
Default value: 1.2\nThis is a multiplier cap for autosens (and soon autotune) to set a 20% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target.
autosens_min
@@ -464,9 +464,9 @@
bolussnooze_dia_divisor
Default value: 2\nBolus snooze is enacted after you do a meal bolus, so the loop won’t counteract with low temps when you’ve just eaten. The example here and default is 2; so a 3 hour DIA means that bolus snooze will be gradually phased out over 1.5 hours (3DIA/2).
min_5m_carbimpact
- Default value: 3.0\nThis is a setting for default carb absorption impact per 5 minutes. The default is an expected 3mg/dl/5min. This affects how fast COB are decayed, and how much carb absorption is assumed in calculating future predicted BG, when BG is falling more than expected, or not rising as much as expected.
+ Default value: 3.0 This is a setting for default carb absorption impact per 5 minutes. The default is an expected 3mg/dl/5min. This affects how fast COB are decayed, and how much carb absorption is assumed in calculating future predicted BG, when BG is falling more than expected, or not rising as much as expected.
Attention!\nNormally you do not have to change these values below. Please CLICK HERE and READ the text and make sure you UNDERSTAND it before change any of these values.
- http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html
+ http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html
Only numeric digits are allowed.
Only numeric digits within the range %1$s - %2$s are allowed.
The field must not be empty
@@ -542,10 +542,12 @@
Child
Teenage
Adult
+ Insulin resistant adult
age
child
teenage
adult
+ resistantadult
Please select patient age to setup safety limits
I_understand
Glimp
@@ -592,7 +594,7 @@
BAS
Firmware
Last connection
- Bluetooh status
+ Bluetooth status
About
Missing SMS permission
DEV
@@ -677,9 +679,8 @@
Sensitivity WeightedAverage
OK
Cancel
- needs to be activated to send values to the pump!
- Not all profiles loaded!
- Values not stored!
+ Not all profiles loaded!
+ Values not stored!
Overview Notifications
Pass the Overview Notifications through as wear confirmation messages.
Accu-Chek Combo
@@ -692,6 +693,14 @@
PUMP
Basal value [U/h]
Duration [min]
+ OpenAPS SMB
+ SMB
+ use_smb
+ use_uam
+ Enable UAM
+ Enable SMB
+ Use Super Micro Boluses instead of temp basal for faster action
+ Detection of Unannounced meals
insulin_oref_peak
IOB Curve Peak Time
Peak Time [min]
@@ -781,11 +790,14 @@
Switches off the phone\'s bluetooth for one second if no connection to the pump is possible. This may help on some phones where the bluetooth stack freezes.
DexcomG5 App (patched)
Upload BG data to NS
- dexcomg5_nsupload
+ dexcomg5_nsupload
G5 upload settings
Customized APK for download
Show detailed delta
Show delta with one more decimal place
+ 45 60 75 90 105 120
+ Max minutes of basal to limit SMB to
+ smbmaxminutes
Unsupported pump firmware
Send BG data to xDrip+
dexcomg5_xdripupload
@@ -818,7 +830,7 @@
Activity
No connection for %d min
%d%% (%d min remaining)
- %.1f U (%s, %s)
+ %.1f U (%s, %s)
Initializing
Disconnected
Suspended due to error
@@ -852,7 +864,7 @@
Pump clock update needed
History
Warning
- This will read the full history and state of the pump. Everything in \"My Data\" and the basal rate. Boluses and TBRs will be added to Treatments if they don\'t already exist. This can cause entries to be duplicated because the pump\'s time is imprecise. Using this when normally looping with the pump is highly discouraged and reserved for special circumstances. If you still want to do this, long press this button again.\n\nWARNING: this can trigger a bug which causes the pump to reject all connection attempts and requires pressing a button on the pump to recover and should therefore be avoided.
+ This will read the full history and state of the pump. Everything in My Data and the basal rate. Boluses and TBRs will be added to Treatments if they don\'t already exist. This can cause entries to be duplicated because the pump\'s time is imprecise. Using this when normally looping with the pump is highly discouraged and reserved for special circumstances. If you still want to do this, long press this button again. WARNING: this can trigger a bug which causes the pump to reject all connection attempts and requires pressing a button on the pump to recover and should therefore be avoided.
Are you really sure you want to read all pump data and take the consequences of this action?
TBR CANCELLED warning was confirmed
Bolus delivery failed. It appears no bolus was delivered. To be sure, please check the pump to avoid a double bolus and then bolus again. To guard against bugs, boluses are not automatically retried.
@@ -907,5 +919,29 @@
Connect preemptively
Automatically connect when AndroidAPS screens are opened, before any pump command is requested, to reduce connection delay
Not recommended due to battery drain
+ enableSMB_always
+ enableSMB_with_COB
+ enableSMB_with_temptarget
+ enableSMB_after_carbs
+ enableSMB_with_high_temptarget
+ Enable SMB always
+ Enable SMB always independently to boluses. Possible only with BG source with nice filtering of data like G5
+ Enable SMB after carbs
+ Enable SMB for 6h after carbs, even with 0 COB. Possible only with BG source with nice filtering of data like G5
+ Enable SMB with COB
+ Enable SMB when there is COB active.
+ Enable SMB with temp targets
+ Enable SMB when there is temp target active (eating soon, exercise)
+ Enable SMB with high temp targets
+ Enable SMB when there is high temp target active (exercise)
+ Let current temp basal run
+ Mute
+ History browser
+ Notify on SMB
+ Show SMB on the watch like a standard bolus.
+ ns_create_announcements_from_errors
+ Create announcements from errors
+ Create Nightscout announcement for error dialogs and local alerts (also viewable in Careportal under Treatments)
+ G5
diff --git a/app/src/main/res/xml/pref_advanced.xml b/app/src/main/res/xml/pref_advanced.xml
index 25beb5fda7..4a617c29ec 100644
--- a/app/src/main/res/xml/pref_advanced.xml
+++ b/app/src/main/res/xml/pref_advanced.xml
@@ -4,125 +4,113 @@
-
-
+
+
+ android:summary="@string/ns_upload_only_summary"
+ android:title="@string/ns_upload_only" />
+ android:summary="@string/ns_noupload_summary"
+ android:title="@string/ns_noupload" />
-
+
+ android:summary="@string/enablesuperbolus_summary"
+ android:title="@string/enablesuperbolus" />
-
+
+ android:summary="@string/always_use_shortavg_summary"
+ android:title="@string/always_use_shortavg" />
-
-
+
+
-
-
-
-
-
+
+
+
+
+ android:digits="0123456789.,"
+ android:inputType="numberDecimal"
+ android:key="openapsama_bolussnooze_dia_divisor"
+ android:maxLines="20"
+ android:selectAllOnFocus="true"
+ android:singleLine="true"
+ android:title="@string/openapsama_bolussnooze_dia_divisor"
+ validate:maxNumber="10"
+ validate:minNumber="1"
+ validate:testType="floatNumericRange" />
-
+
+ android:summary="@string/do_not_track_profile_switch_summary"
+ android:title="@string/do_not_track_profile_switch" />
+
+
+
diff --git a/app/src/main/res/xml/pref_openapssmb.xml b/app/src/main/res/xml/pref_openapssmb.xml
new file mode 100644
index 0000000000..da0b64a91c
--- /dev/null
+++ b/app/src/main/res/xml/pref_openapssmb.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/pref_others.xml b/app/src/main/res/xml/pref_others.xml
index 548b99e5b9..ba16f09c2f 100644
--- a/app/src/main/res/xml/pref_others.xml
+++ b/app/src/main/res/xml/pref_others.xml
@@ -1,5 +1,6 @@
-
+
@@ -76,12 +77,16 @@
android:defaultValue="true"
android:key="@string/key_enable_pump_unreachable_alert"
android:title="@string/enable_pump_unreachable_alert" />
-
+ android:title="@string/pump_unreachable_threshold">
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePluginTest.java
new file mode 100644
index 0000000000..83e9442364
--- /dev/null
+++ b/app/src/test/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePluginTest.java
@@ -0,0 +1,153 @@
+package info.nightscout.androidaps.plugins.Insulin;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import info.nightscout.androidaps.data.Iob;
+import info.nightscout.androidaps.db.Treatment;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Created by triplem on 07.01.18.
+ */
+
+public class InsulinOrefBasePluginTest extends InsulinOrefBasePlugin {
+
+ private int peak;
+ private double dia;
+
+ private boolean shortDiaNotificationSend;
+
+ @Before
+ public void setUp() throws Exception {
+ this.peak = 0;
+ this.dia = InsulinOrefBasePlugin.MIN_DIA;
+ this.shortDiaNotificationSend = false;
+ }
+
+ @Test
+ public void testGetDia() throws Exception {
+ assertEquals(InsulinOrefBasePlugin.MIN_DIA, this.getDia(), 0);
+
+ this.dia = InsulinOrefBasePlugin.MIN_DIA + 1;
+ assertEquals(InsulinOrefBasePlugin.MIN_DIA + 1, this.getDia(), 0);
+
+ this.dia = InsulinOrefBasePlugin.MIN_DIA - 1;
+ assertEquals(InsulinOrefBasePlugin.MIN_DIA, this.getDia(), 0);
+ assertTrue(this.shortDiaNotificationSend);
+ }
+
+ @Test
+ public void testIobCalcForTreatment() {
+ Treatment treatment = new Treatment();
+ Iob expected = new Iob();
+
+ assertEquals(expected, this.iobCalcForTreatment(treatment, 0, 0d));
+
+ this.peak = 30;
+ this.dia = 4;
+ long time = System.currentTimeMillis();
+
+ // check directly after bolus
+ treatment.date = time;
+ treatment.insulin = 10d;
+ assertEquals(10d, this.iobCalcForTreatment(treatment, time).iobContrib, 0.1);
+
+ // check after 1 hour
+ treatment.date = time - 1 * 60 * 60 * 1000; // 1 hour
+ treatment.insulin = 10d;
+ assertEquals(3.92, this.iobCalcForTreatment(treatment, time).iobContrib, 0.1);
+
+ // check after 2 hour
+ treatment.date = time - 2 * 60 * 60 * 1000; // 1 hour
+ treatment.insulin = 10d;
+ assertEquals(0.77, this.iobCalcForTreatment(treatment, time).iobContrib, 0.1);
+
+ // check after 3 hour
+ treatment.date = time - 3 * 60 * 60 * 1000; // 1 hour
+ treatment.insulin = 10d;
+ assertEquals(0.10, this.iobCalcForTreatment(treatment, time).iobContrib, 0.1);
+
+ // check after dia
+ treatment.date = time - 4 * 60 * 60 * 1000;
+ treatment.insulin = 10d;
+ assertEquals(0d, this.iobCalcForTreatment(treatment, time).iobContrib, 0.1);
+ }
+
+
+ /**
+ * this method is implemented to allow tests of the iobCalcForTreatment calculation
+ * @return
+ */
+ @Override
+ int getPeak() {
+ return this.peak;
+ }
+
+ /**
+ * Userdefined Dia is implemented to allow tests of the getDia method
+ *
+ * @return
+ */
+ public double getUserDefinedDia() {
+ return this.dia;
+ }
+
+ void sendShortDiaNotification(double dia) {
+ this.shortDiaNotificationSend = true;
+ }
+
+
+ // the following methods are implemented, but not needed...
+ @Override
+ String commentStandardText() {
+ return null;
+ }
+
+ @Override
+ public String getFragmentClass() {
+ return null;
+ }
+
+ @Override
+ public int getId() {
+ return 0;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public String getFriendlyName() {
+ return null;
+ }
+
+ @Override
+ public boolean isEnabled(int type) {
+ return false;
+ }
+
+ @Override
+ public boolean isVisibleInTabs(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 0;
+ }
+}
diff --git a/build.gradle b/build.gradle
index 7e01a0aa59..0bbe15c8a2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,6 +10,8 @@ buildscript {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+
+ classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0'
}
}
@@ -17,6 +19,16 @@ allprojects {
repositories {
jcenter()
google()
+
+ maven {
+ url "https://maven.google.com"
+ }
+ ivy {
+ url 'https://github.com/'
+ layout 'pattern', {
+ artifact '/[organisation]/[module]/archive/[revision].[ext]'
+ }
+ }
}
}
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java
index ea5b41176b..fab81aafb9 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java
@@ -70,7 +70,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
public boolean layoutSet = false;
public boolean bIsRound = false;
public int pointSize = 2;
- public int missed_readings_alert_id = 818;
public BgGraphBuilder bgGraphBuilder;
public LineChartView chart;
public ArrayList bgDataList = new ArrayList<>();
@@ -181,7 +180,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
}
);
- ListenerService.requestData(this);
wakeLock.acquire(50);
}
@@ -638,8 +636,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
chart.setLineChartData(bgGraphBuilder.lineData());
chart.setViewportCalculationEnabled(true);
chart.setMaximumViewport(chart.getMaximumViewport());
- } else {
- ListenerService.requestData(this);
}
}