Merge remote-tracking branch 'origin/dagger3' into rs
This commit is contained in:
commit
aa8ddc67e5
|
@ -31,14 +31,13 @@ function calculate_expected_delta(target_bg, eventual_bg, bgi) {
|
||||||
// (hours * mins_per_hour) / 5 = how many 5 minute periods in 2h = 24
|
// (hours * mins_per_hour) / 5 = how many 5 minute periods in 2h = 24
|
||||||
var five_min_blocks = (2 * 60) / 5;
|
var five_min_blocks = (2 * 60) / 5;
|
||||||
var target_delta = target_bg - eventual_bg;
|
var target_delta = target_bg - eventual_bg;
|
||||||
var expectedDelta = round(bgi + (target_delta / five_min_blocks), 1);
|
return /* expectedDelta */ round(bgi + (target_delta / five_min_blocks), 1);
|
||||||
return expectedDelta;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function convert_bg(value, profile)
|
function convert_bg(value, profile)
|
||||||
{
|
{
|
||||||
if (profile.out_units == "mmol/L")
|
if (profile.out_units === "mmol/L")
|
||||||
{
|
{
|
||||||
return round(value / 18, 1).toFixed(1);
|
return round(value / 18, 1).toFixed(1);
|
||||||
}
|
}
|
||||||
|
@ -48,10 +47,76 @@ function convert_bg(value, profile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data) {
|
function enable_smb(
|
||||||
|
profile,
|
||||||
|
microBolusAllowed,
|
||||||
|
meal_data,
|
||||||
|
target_bg
|
||||||
|
) {
|
||||||
|
// disable SMB when a high temptarget is set
|
||||||
|
if (! microBolusAllowed) {
|
||||||
|
console.error("SMB disabled (!microBolusAllowed)");
|
||||||
|
return false;
|
||||||
|
} else if (! profile.allowSMB_with_high_temptarget && profile.temptargetSet && target_bg > 100) {
|
||||||
|
console.error("SMB disabled due to high temptarget of",target_bg);
|
||||||
|
return false;
|
||||||
|
} else if (meal_data.bwFound === true && profile.A52_risk_enable === false) {
|
||||||
|
console.error("SMB disabled due to Bolus Wizard activity in the last 6 hours.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable SMB/UAM if always-on (unless previously disabled for high temptarget)
|
||||||
|
if (profile.enableSMB_always === true) {
|
||||||
|
if (meal_data.bwFound) {
|
||||||
|
console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard");
|
||||||
|
} else {
|
||||||
|
console.error("SMB enabled due to enableSMB_always");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable SMB/UAM (if enabled in preferences) while we have COB
|
||||||
|
if (profile.enableSMB_with_COB === true && meal_data.mealCOB) {
|
||||||
|
if (meal_data.bwCarbs) {
|
||||||
|
console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard");
|
||||||
|
} else {
|
||||||
|
console.error("SMB enabled for COB of",meal_data.mealCOB);
|
||||||
|
}
|
||||||
|
return 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)
|
||||||
|
if (profile.enableSMB_after_carbs === true && meal_data.carbs ) {
|
||||||
|
if (meal_data.bwCarbs) {
|
||||||
|
console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard");
|
||||||
|
} else {
|
||||||
|
console.error("SMB enabled for 6h after carb entry");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable SMB/UAM (if enabled in preferences) if a low temptarget is set
|
||||||
|
if (profile.enableSMB_with_temptarget === true && (profile.temptargetSet && target_bg < 100)) {
|
||||||
|
if (meal_data.bwFound) {
|
||||||
|
console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard");
|
||||||
|
} else {
|
||||||
|
console.error("SMB enabled for temptarget of",convert_bg(target_bg, profile));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error("SMB disabled (no enableSMB preferences active or no condition satisfied)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime) {
|
||||||
var rT = {}; //short for requestedTemp
|
var rT = {}; //short for requestedTemp
|
||||||
|
|
||||||
var deliverAt = new Date();
|
var deliverAt = new Date();
|
||||||
|
if (currentTime) {
|
||||||
|
deliverAt = new Date(currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
|
if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
|
||||||
rT.error ='Error: could not get current basal rate';
|
rT.error ='Error: could not get current basal rate';
|
||||||
|
@ -61,26 +126,41 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
var basal = profile_current_basal;
|
var basal = profile_current_basal;
|
||||||
|
|
||||||
var systemTime = new Date();
|
var systemTime = new Date();
|
||||||
|
if (currentTime) {
|
||||||
|
systemTime = currentTime;
|
||||||
|
}
|
||||||
var bgTime = new Date(glucose_status.date);
|
var bgTime = new Date(glucose_status.date);
|
||||||
var minAgo = round( (systemTime - bgTime) / 60 / 1000 ,1);
|
var minAgo = round( (systemTime - bgTime) / 60 / 1000 ,1);
|
||||||
|
|
||||||
var bg = glucose_status.glucose;
|
var bg = glucose_status.glucose;
|
||||||
if (bg < 39) { //Dexcom is in ??? mode or calibrating
|
var noise = glucose_status.noise;
|
||||||
rT.reason = "CGM is calibrating or in ??? state";
|
// 38 is an xDrip error state that usually indicates sensor failure
|
||||||
|
// all other BG values between 11 and 37 mg/dL reflect non-error-code BG values, so we should zero temp for those
|
||||||
|
if (bg <= 10 || bg === 38 || noise >= 3) { //Dexcom is in ??? mode or calibrating, or xDrip reports high noise
|
||||||
|
rT.reason = "CGM is calibrating, in ??? state, or noise is high";
|
||||||
}
|
}
|
||||||
if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future
|
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;
|
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 is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps
|
||||||
|
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
||||||
|
} else if ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 ) {
|
||||||
|
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
||||||
|
rT.reason = "CGM was just calibrated";
|
||||||
|
} else {
|
||||||
|
rT.reason = "Error: CGM data is unchanged for the past ~45m";
|
||||||
}
|
}
|
||||||
if (bg < 39 || minAgo > 12 || minAgo < -5) {
|
}
|
||||||
if (currenttemp.rate >= basal) { // high temp is running
|
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
||||||
rT.reason += ". Canceling high temp basal of "+currenttemp.rate;
|
if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 ) ) {
|
||||||
|
if (currenttemp.rate > basal) { // high temp is running
|
||||||
|
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
||||||
rT.deliverAt = deliverAt;
|
rT.deliverAt = deliverAt;
|
||||||
rT.temp = 'absolute';
|
rT.temp = 'absolute';
|
||||||
rT.duration = 0;
|
rT.duration = 30;
|
||||||
rT.rate = 0;
|
rT.rate = basal;
|
||||||
return rT;
|
return rT;
|
||||||
//return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
//return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||||
} else if ( currenttemp.rate == 0 && currenttemp.duration > 30 ) { //shorten long zero temps to 30m
|
} 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.reason += ". Shortening " + currenttemp.duration + "m long zero temp to 30m. ";
|
||||||
rT.deliverAt = deliverAt;
|
rT.deliverAt = deliverAt;
|
||||||
rT.temp = 'absolute';
|
rT.temp = 'absolute';
|
||||||
|
@ -115,14 +195,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
|
|
||||||
var sensitivityRatio;
|
var sensitivityRatio;
|
||||||
var high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity;
|
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)
|
var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled target (which might change)
|
||||||
if ( profile.half_basal_exercise_target ) {
|
if ( profile.half_basal_exercise_target ) {
|
||||||
var halfBasalTarget = profile.half_basal_exercise_target;
|
var halfBasalTarget = profile.half_basal_exercise_target;
|
||||||
} else {
|
} else {
|
||||||
var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%)
|
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)
|
// 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
|
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget
|
||||||
|| profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
|
|| 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
|
// 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
|
// 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
|
||||||
|
@ -132,36 +212,36 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// limit sensitivityRatio to profile.autosens_max (1.2x by default)
|
// limit sensitivityRatio to profile.autosens_max (1.2x by default)
|
||||||
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
|
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
|
||||||
sensitivityRatio = round(sensitivityRatio,2);
|
sensitivityRatio = round(sensitivityRatio,2);
|
||||||
console.error("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
console.log("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
||||||
} else if (typeof autosens_data !== 'undefined' ) {
|
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||||
sensitivityRatio = autosens_data.ratio;
|
sensitivityRatio = autosens_data.ratio;
|
||||||
console.error("Autosens ratio: "+sensitivityRatio+"; ");
|
console.log("Autosens ratio: "+sensitivityRatio+"; ");
|
||||||
}
|
}
|
||||||
if (sensitivityRatio) {
|
if (sensitivityRatio) {
|
||||||
basal = profile.current_basal * sensitivityRatio;
|
basal = profile.current_basal * sensitivityRatio;
|
||||||
basal = round_basal(basal, profile);
|
basal = round_basal(basal, profile);
|
||||||
if (basal != profile_current_basal) {
|
if (basal !== profile_current_basal) {
|
||||||
console.error("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
console.log("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
||||||
} else {
|
} else {
|
||||||
console.error("Basal unchanged: "+basal+"; ");
|
console.log("Basal unchanged: "+basal+"; ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120
|
// adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120
|
||||||
if (profile.temptargetSet) {
|
if (profile.temptargetSet) {
|
||||||
//console.error("Temp Target set, not adjusting with autosens; ");
|
//console.log("Temp Target set, not adjusting with autosens; ");
|
||||||
} else if (typeof autosens_data !== 'undefined' ) {
|
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||||
if ( profile.sensitivity_raises_target && autosens_data.ratio < 1 || profile.resistance_lowers_target && autosens_data.ratio > 1 ) {
|
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
|
// 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;
|
min_bg = round((min_bg - 60) / autosens_data.ratio) + 60;
|
||||||
max_bg = round((max_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;
|
var new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60;
|
||||||
// don't allow target_bg below 80
|
// don't allow target_bg below 80
|
||||||
new_target_bg = Math.max(80, new_target_bg);
|
new_target_bg = Math.max(80, new_target_bg);
|
||||||
if (target_bg == new_target_bg) {
|
if (target_bg === new_target_bg) {
|
||||||
console.error("target_bg unchanged: "+new_target_bg+"; ");
|
console.log("target_bg unchanged: "+new_target_bg+"; ");
|
||||||
} else {
|
} else {
|
||||||
console.error("target_bg from "+target_bg+" to "+new_target_bg+"; ");
|
console.log("target_bg from "+target_bg+" to "+new_target_bg+"; ");
|
||||||
}
|
}
|
||||||
target_bg = new_target_bg;
|
target_bg = new_target_bg;
|
||||||
}
|
}
|
||||||
|
@ -197,34 +277,33 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
|
|
||||||
var profile_sens = round(profile.sens,1)
|
var profile_sens = round(profile.sens,1)
|
||||||
var sens = profile.sens;
|
var sens = profile.sens;
|
||||||
if (typeof autosens_data !== 'undefined' ) {
|
if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||||
sens = profile.sens / sensitivityRatio;
|
sens = profile.sens / sensitivityRatio;
|
||||||
sens = round(sens, 1);
|
sens = round(sens, 1);
|
||||||
if (sens != profile_sens) {
|
if (sens !== profile_sens) {
|
||||||
console.error("ISF from "+profile_sens+" to "+sens);
|
console.log("ISF from "+profile_sens+" to "+sens);
|
||||||
} else {
|
} else {
|
||||||
console.error("ISF unchanged: "+sens);
|
console.log("ISF unchanged: "+sens);
|
||||||
}
|
}
|
||||||
//console.error(" (autosens ratio "+sensitivityRatio+")");
|
//console.log(" (autosens ratio "+sensitivityRatio+")");
|
||||||
}
|
}
|
||||||
console.error("; CR:",profile.carb_ratio);
|
console.error("; CR:",profile.carb_ratio);
|
||||||
|
|
||||||
// compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
|
// compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
|
||||||
var lastTempAge;
|
var lastTempAge;
|
||||||
if (typeof iob_data.lastTemp !== 'undefined' ) {
|
if (typeof iob_data.lastTemp !== 'undefined' ) {
|
||||||
lastTempAge = round(( new Date().getTime() - iob_data.lastTemp.date ) / 60000); // in minutes
|
lastTempAge = round(( new Date(systemTime).getTime() - iob_data.lastTemp.date ) / 60000); // in minutes
|
||||||
// } ---- added to not produce errors
|
|
||||||
} else {
|
} else {
|
||||||
lastTempAge = 0;
|
lastTempAge = 0;
|
||||||
}
|
}
|
||||||
//console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m");
|
//console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m");
|
||||||
tempModulus = (lastTempAge + currenttemp.duration) % 30;
|
var tempModulus = (lastTempAge + currenttemp.duration) % 30;
|
||||||
console.error("currenttemp:",currenttemp,"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m");
|
console.error("currenttemp:",currenttemp,"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m");
|
||||||
rT.temp = 'absolute';
|
rT.temp = 'absolute';
|
||||||
rT.deliverAt = deliverAt;
|
rT.deliverAt = deliverAt;
|
||||||
if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate != iob_data.lastTemp.rate ) {
|
if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate !== iob_data.lastTemp.rate && lastTempAge > 10 && currenttemp.duration ) {
|
||||||
rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; setting neutral temp of "+basal+".";
|
rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; canceling temp";
|
||||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
if ( currenttemp && iob_data.lastTemp && currenttemp.duration > 0 ) {
|
if ( currenttemp && iob_data.lastTemp && currenttemp.duration > 0 ) {
|
||||||
// TODO: fix this (lastTemp.duration is how long it has run; currenttemp.duration is time left
|
// TODO: fix this (lastTemp.duration is how long it has run; currenttemp.duration is time left
|
||||||
|
@ -234,10 +313,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
//}
|
//}
|
||||||
//console.error(lastTempAge, round(iob_data.lastTemp.duration,1), round(lastTempAge - iob_data.lastTemp.duration,1));
|
//console.error(lastTempAge, round(iob_data.lastTemp.duration,1), round(lastTempAge - iob_data.lastTemp.duration,1));
|
||||||
var lastTempEnded = lastTempAge - iob_data.lastTemp.duration
|
var lastTempEnded = lastTempAge - iob_data.lastTemp.duration
|
||||||
if ( lastTempEnded > 5 ) {
|
if ( lastTempEnded > 5 && lastTempAge > 10 ) {
|
||||||
rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; setting neutral temp of "+basal+".";
|
rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; canceling temp";
|
||||||
//console.error(currenttemp, round(iob_data.lastTemp,1), round(lastTempAge,1));
|
//console.error(currenttemp, round(iob_data.lastTemp,1), round(lastTempAge,1));
|
||||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
// TODO: figure out a way to do this check that doesn't fail across basal schedule boundaries
|
// TODO: figure out a way to do this check that doesn't fail across basal schedule boundaries
|
||||||
//if ( tempModulus < 25 && tempModulus > 5 ) {
|
//if ( tempModulus < 25 && tempModulus > 5 ) {
|
||||||
|
@ -264,37 +343,44 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
if (iob_data.iob > 0) {
|
if (iob_data.iob > 0) {
|
||||||
var naive_eventualBG = round( bg - (iob_data.iob * sens) );
|
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
|
} 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) ) );
|
naive_eventualBG = round( bg - (iob_data.iob * Math.min(sens, profile.sens) ) );
|
||||||
}
|
}
|
||||||
// and adjust it for the deviation above
|
// and adjust it for the deviation above
|
||||||
var eventualBG = naive_eventualBG + deviation;
|
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
|
// raise target for noisy / raw CGM data
|
||||||
if ( bg > max_bg && profile.adv_target_adjustments && ! profile.temptargetSet ) {
|
if (glucose_status.noise >= 2) {
|
||||||
|
// increase target at least 10% (default 30%) for raw / noisy data
|
||||||
|
var noisyCGMTargetMultiplier = Math.max( 1.1, profile.noisyCGMTargetMultiplier );
|
||||||
|
// don't allow maxRaw above 250
|
||||||
|
var maxRaw = Math.min( 250, profile.maxRaw );
|
||||||
|
var adjustedMinBG = round(Math.min(200, min_bg * noisyCGMTargetMultiplier ));
|
||||||
|
var adjustedTargetBG = round(Math.min(200, target_bg * noisyCGMTargetMultiplier ));
|
||||||
|
var adjustedMaxBG = round(Math.min(200, max_bg * noisyCGMTargetMultiplier ));
|
||||||
|
console.log("Raising target_bg for noisy / raw CGM data, from "+target_bg+" to "+adjustedTargetBG+"; ");
|
||||||
|
min_bg = adjustedMinBG;
|
||||||
|
target_bg = adjustedTargetBG;
|
||||||
|
max_bg = adjustedMaxBG;
|
||||||
|
// adjust target BG range if configured to bring down high BG faster
|
||||||
|
} else 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
|
// 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);
|
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);
|
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);
|
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
|
// if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedMinBG, don’t use it
|
||||||
//console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG);
|
//console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG);
|
||||||
if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) {
|
if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) {
|
||||||
console.error("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
console.log("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
||||||
min_bg = adjustedMinBG;
|
min_bg = adjustedMinBG;
|
||||||
} else {
|
} else {
|
||||||
console.error("min_bg unchanged: "+min_bg+"; ");
|
console.log("min_bg unchanged: "+min_bg+"; ");
|
||||||
}
|
}
|
||||||
// if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedTargetBG, don’t use it
|
// 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) {
|
if (eventualBG > adjustedTargetBG && naive_eventualBG > adjustedTargetBG && target_bg > adjustedTargetBG) {
|
||||||
console.error("target_bg from "+target_bg+" to "+adjustedTargetBG+"; ");
|
console.log("target_bg from "+target_bg+" to "+adjustedTargetBG+"; ");
|
||||||
target_bg = adjustedTargetBG;
|
target_bg = adjustedTargetBG;
|
||||||
} else {
|
} else {
|
||||||
console.error("target_bg unchanged: "+target_bg+"; ");
|
console.log("target_bg unchanged: "+target_bg+"; ");
|
||||||
}
|
}
|
||||||
// if eventualBG, naive_eventualBG, and max_bg aren't all above adjustedMaxBG, don’t use it
|
// 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) {
|
if (eventualBG > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) {
|
||||||
|
@ -321,7 +407,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
, 'bg': bg
|
, 'bg': bg
|
||||||
, 'tick': tick
|
, 'tick': tick
|
||||||
, 'eventualBG': eventualBG
|
, 'eventualBG': eventualBG
|
||||||
//, 'snoozeBG': snoozeBG
|
|
||||||
, 'insulinReq': 0
|
, '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)
|
, '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
|
, 'deliverAt' : deliverAt // The time at which the microbolus should be delivered
|
||||||
|
@ -341,71 +426,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
ZTpredBGs.push(bg);
|
ZTpredBGs.push(bg);
|
||||||
UAMpredBGs.push(bg);
|
UAMpredBGs.push(bg);
|
||||||
|
|
||||||
// enable SMB whenever we have COB or UAM is enabled
|
var enableSMB = enable_smb(
|
||||||
// SMB is disabled by default, unless explicitly enabled in preferences.json
|
profile,
|
||||||
var enableSMB=false;
|
microBolusAllowed,
|
||||||
// disable SMB when a high temptarget is set
|
meal_data,
|
||||||
if (! microBolusAllowed) {
|
target_bg
|
||||||
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)
|
// enable UAM (if enabled in preferences)
|
||||||
var enableUAM=(profile.enableUAM);
|
var enableUAM=(profile.enableUAM);
|
||||||
|
|
||||||
|
@ -417,43 +444,48 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// calculate current carb absorption rate, and how long to absorb all carbs
|
// calculate current carb absorption rate, and how long to absorb all carbs
|
||||||
// CI = current carb impact on BG in mg/dL/5m
|
// CI = current carb impact on BG in mg/dL/5m
|
||||||
ci = round((minDelta - bgi),1);
|
ci = round((minDelta - bgi),1);
|
||||||
uci = round((minDelta - bgi),1);
|
var uci = round((minDelta - bgi),1);
|
||||||
// ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g)
|
// ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g)
|
||||||
if (profile.temptargetSet) {
|
|
||||||
|
// TODO: remove commented-out code for old behavior
|
||||||
|
//if (profile.temptargetSet) {
|
||||||
// if temptargetSet, use unadjusted profile.sens to allow activity mode sensitivityRatio to adjust CR
|
// if temptargetSet, use unadjusted profile.sens to allow activity mode sensitivityRatio to adjust CR
|
||||||
var csf = profile.sens / profile.carb_ratio;
|
//var csf = profile.sens / profile.carb_ratio;
|
||||||
} else {
|
//} else {
|
||||||
// otherwise, use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments
|
// 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
|
// 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 csf = sens / profile.carb_ratio;
|
||||||
}
|
//}
|
||||||
|
// 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 TT or autosens
|
||||||
|
// this avoids overdosing insulin for large meals when low temp targets are active
|
||||||
|
csf = sens / profile.carb_ratio;
|
||||||
|
console.error("profile.sens:",profile.sens,"sens:",sens,"CSF:",csf);
|
||||||
|
|
||||||
var maxCarbAbsorptionRate = 30; // g/h; maximum rate to assume carbs will absorb if no CI observed
|
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
|
// limit Carb Impact to maxCarbAbsorptionRate * csf in mg/dL per 5m
|
||||||
maxCI = round(maxCarbAbsorptionRate*csf*5/60,1)
|
var maxCI = round(maxCarbAbsorptionRate*csf*5/60,1)
|
||||||
if (ci > maxCI) {
|
if (ci > maxCI) {
|
||||||
console.error("Limiting carb impact from",ci,"to",maxCI,"mg/dL/5m (",maxCarbAbsorptionRate,"g/h )");
|
console.error("Limiting carb impact from",ci,"to",maxCI,"mg/dL/5m (",maxCarbAbsorptionRate,"g/h )");
|
||||||
ci = maxCI;
|
ci = maxCI;
|
||||||
}
|
}
|
||||||
// set meal_carbimpact high enough to absorb all meal carbs over 6 hours
|
var remainingCATimeMin = 3; // h; duration of expected not-yet-observed carb absorption
|
||||||
// total_impact (mg/dL) = CSF (mg/dL/g) * carbs (g)
|
// adjust remainingCATime (instead of CR) for autosens if sensitivityRatio defined
|
||||||
//console.error(csf * meal_data.carbs);
|
if (sensitivityRatio){
|
||||||
// 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;
|
remainingCATimeMin = remainingCATimeMin / sensitivityRatio;
|
||||||
|
}
|
||||||
// 20 g/h means that anything <= 60g will get a remainingCATimeMin, 80g will get 4h, and 120g 6h
|
// 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
|
// 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 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
|
var remainingCATime = remainingCATimeMin;
|
||||||
if (meal_data.carbs) {
|
if (meal_data.carbs) {
|
||||||
// if carbs * assumedCarbAbsorptionRate > remainingCATimeMin, raise it
|
// if carbs * assumedCarbAbsorptionRate > remainingCATimeMin, raise it
|
||||||
// so <= 90g is assumed to take 3h, and 120g=4h
|
// so <= 90g is assumed to take 3h, and 120g=4h
|
||||||
remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.mealCOB/assumedCarbAbsorptionRate);
|
remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.mealCOB/assumedCarbAbsorptionRate);
|
||||||
var lastCarbAge = round(( new Date().getTime() - meal_data.lastCarbTime ) / 60000);
|
var lastCarbAge = round(( new Date(systemTime).getTime() - meal_data.lastCarbTime ) / 60000);
|
||||||
//console.error(meal_data.lastCarbTime, lastCarbAge);
|
//console.error(meal_data.lastCarbTime, lastCarbAge);
|
||||||
|
|
||||||
fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs;
|
var fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs;
|
||||||
remainingCATime = remainingCATimeMin + 1.5 * lastCarbAge/60;
|
remainingCATime = remainingCATimeMin + 1.5 * lastCarbAge/60;
|
||||||
remainingCATime = round(remainingCATime,1);
|
remainingCATime = round(remainingCATime,1);
|
||||||
//console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime)
|
//console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime)
|
||||||
|
@ -478,7 +510,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / (remainingCATime/2) (h)
|
// 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);
|
var remainingCIpeak = remainingCarbs * csf * 5 / 60 / (remainingCATime/2);
|
||||||
//console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI,remainingCATime);
|
//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
|
// calculate peak deviation in last hour, and slope from that to current deviation
|
||||||
var slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation,2);
|
var slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation,2);
|
||||||
|
@ -488,17 +519,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
var slopeFromDeviations = Math.min(slopeFromMaxDeviation,-slopeFromMinDeviation/3);
|
var slopeFromDeviations = Math.min(slopeFromMaxDeviation,-slopeFromMinDeviation/3);
|
||||||
//console.error(slopeFromMaxDeviation);
|
//console.error(slopeFromMaxDeviation);
|
||||||
|
|
||||||
aci = 10;
|
var aci = 10;
|
||||||
//5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m)
|
//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)
|
// 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
|
// limit cid to remainingCATime hours: the reset goes to remainingCI
|
||||||
if (ci == 0) {
|
if (ci === 0) {
|
||||||
// avoid divide by zero
|
// avoid divide by zero
|
||||||
cid = 0;
|
cid = 0;
|
||||||
} else {
|
} else {
|
||||||
cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci ));
|
cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci ));
|
||||||
}
|
}
|
||||||
acid = Math.max(0, meal_data.mealCOB * csf / aci );
|
var acid = Math.max(0, meal_data.mealCOB * csf / aci );
|
||||||
// duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay)
|
// 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("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");
|
//console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours");
|
||||||
|
@ -529,18 +560,18 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
try {
|
try {
|
||||||
iobArray.forEach(function(iobTick) {
|
iobArray.forEach(function(iobTick) {
|
||||||
//console.error(iobTick);
|
//console.error(iobTick);
|
||||||
predBGI = round(( -iobTick.activity * sens * 5 ), 2);
|
var predBGI = round(( -iobTick.activity * sens * 5 ), 2);
|
||||||
predZTBGI = round(( -iobTick.iobWithZeroTemp.activity * sens * 5 ), 2);
|
var predZTBGI = round(( -iobTick.iobWithZeroTemp.activity * sens * 5 ), 2);
|
||||||
// for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero
|
// for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero
|
||||||
// over 60 minutes (data points every 5m)
|
// over 60 minutes (data points every 5m)
|
||||||
predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) );
|
var predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) );
|
||||||
IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev;
|
IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev;
|
||||||
// calculate predBGs with long zero temp without deviations
|
// calculate predBGs with long zero temp without deviations
|
||||||
ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI;
|
var ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI;
|
||||||
// for COBpredBGs, predicted carb impact drops linearly from current carb impact down to zero
|
// 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)
|
// 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) ) );
|
var 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) ) );
|
var 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
|
// 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)
|
// bilinear curve peaking at remainingCIpeak at remainingCATime/2 hours (remainingCATime/2*12 * 5m)
|
||||||
// and ending at remainingCATime h (remainingCATime*12 * 5m intervals)
|
// and ending at remainingCATime h (remainingCATime*12 * 5m intervals)
|
||||||
|
@ -549,18 +580,18 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
remainingCItotal += predCI+remainingCI;
|
remainingCItotal += predCI+remainingCI;
|
||||||
remainingCIs.push(round(remainingCI,0));
|
remainingCIs.push(round(remainingCI,0));
|
||||||
predCIs.push(round(predCI,0));
|
predCIs.push(round(predCI,0));
|
||||||
//console.error(round(predCI,1)+"+"+round(remainingCI,1)+" ");
|
//console.log(round(predCI,1)+"+"+round(remainingCI,1)+" ");
|
||||||
COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI;
|
COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI;
|
||||||
aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI;
|
var aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI;
|
||||||
// for UAMpredBGs, predicted carb impact drops at slopeFromDeviations
|
// for UAMpredBGs, predicted carb impact drops at slopeFromDeviations
|
||||||
// calculate predicted CI from UAM based on slopeFromDeviations
|
// calculate predicted CI from UAM based on slopeFromDeviations
|
||||||
predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*slopeFromDeviations ) );
|
var predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*slopeFromDeviations ) );
|
||||||
// if slopeFromDeviations is too flat, predicted deviation impact drops linearly from
|
// if slopeFromDeviations is too flat, predicted deviation impact drops linearly from
|
||||||
// current deviation down to zero over 3h (data points every 5m)
|
// 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) ) );
|
var predUCImax = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(3*60/5,1) ) );
|
||||||
//console.error(predUCIslope, predUCImax);
|
//console.error(predUCIslope, predUCImax);
|
||||||
// predicted CI from UAM is the lesser of CI based on deviationSlope or DIA
|
// predicted CI from UAM is the lesser of CI based on deviationSlope or DIA
|
||||||
predUCI = Math.min(predUCIslope, predUCImax);
|
var predUCI = Math.min(predUCIslope, predUCImax);
|
||||||
if(predUCI>0) {
|
if(predUCI>0) {
|
||||||
//console.error(UAMpredBGs.length,slopeFromDeviations, predUCI);
|
//console.error(UAMpredBGs.length,slopeFromDeviations, predUCI);
|
||||||
UAMduration=round((UAMpredBGs.length+1)*5/60,1);
|
UAMduration=round((UAMpredBGs.length+1)*5/60,1);
|
||||||
|
@ -582,7 +613,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// set minPredBGs starting when currently-dosed insulin activity will peak
|
// 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
|
// look ahead 60m (regardless of insulin type) so as to be less aggressive on slower insulins
|
||||||
var insulinPeakTime = 60;
|
var insulinPeakTime = 60;
|
||||||
// add 30m to allow for insluin delivery (SMBs or temps)
|
// add 30m to allow for insulin delivery (SMBs or temps)
|
||||||
insulinPeakTime = 90;
|
insulinPeakTime = 90;
|
||||||
var insulinPeak5m = (insulinPeakTime/60)*12;
|
var insulinPeak5m = (insulinPeakTime/60)*12;
|
||||||
//console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve);
|
//console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve);
|
||||||
|
@ -599,19 +630,18 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// set eventualBG to include effect of carbs
|
// set eventualBG to include effect of carbs
|
||||||
//console.error("PredBGs:",JSON.stringify(predBGs));
|
//console.error("PredBGs:",JSON.stringify(predBGs));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled:",e);
|
console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled");
|
||||||
}
|
}
|
||||||
if (meal_data.mealCOB) {
|
if (meal_data.mealCOB) {
|
||||||
console.error("predCIs (mg/dL/5m):",predCIs.join(" "));
|
console.error("predCIs (mg/dL/5m):",predCIs.join(" "));
|
||||||
console.error("remainingCIs: ",remainingCIs.join(" "));
|
console.error("remainingCIs: ",remainingCIs.join(" "));
|
||||||
}
|
}
|
||||||
//,"totalCA:",round(totalCA,2),"remainingCItotal/csf+totalCA:",round(remainingCItotal/csf+totalCA,2));
|
|
||||||
rT.predBGs = {};
|
rT.predBGs = {};
|
||||||
IOBpredBGs.forEach(function(p, i, theArray) {
|
IOBpredBGs.forEach(function(p, i, theArray) {
|
||||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||||
});
|
});
|
||||||
for (var i=IOBpredBGs.length-1; i > 12; i--) {
|
for (var i=IOBpredBGs.length-1; i > 12; i--) {
|
||||||
if (IOBpredBGs[i-1] != IOBpredBGs[i]) { break; }
|
if (IOBpredBGs[i-1] !== IOBpredBGs[i]) { break; }
|
||||||
else { IOBpredBGs.pop(); }
|
else { IOBpredBGs.pop(); }
|
||||||
}
|
}
|
||||||
rT.predBGs.IOB = IOBpredBGs;
|
rT.predBGs.IOB = IOBpredBGs;
|
||||||
|
@ -619,10 +649,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
ZTpredBGs.forEach(function(p, i, theArray) {
|
ZTpredBGs.forEach(function(p, i, theArray) {
|
||||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||||
});
|
});
|
||||||
for (var i=ZTpredBGs.length-1; i > 6; i--) {
|
for (i=ZTpredBGs.length-1; i > 6; i--) {
|
||||||
//if (ZTpredBGs[i-1] != ZTpredBGs[i]) { break; }
|
|
||||||
// stop displaying ZTpredBGs once they're rising and above target
|
// stop displaying ZTpredBGs once they're rising and above target
|
||||||
if (ZTpredBGs[i-1] >= ZTpredBGs[i] || ZTpredBGs[i] < target_bg) { break; }
|
if (ZTpredBGs[i-1] >= ZTpredBGs[i] || ZTpredBGs[i] <= target_bg) { break; }
|
||||||
else { ZTpredBGs.pop(); }
|
else { ZTpredBGs.pop(); }
|
||||||
}
|
}
|
||||||
rT.predBGs.ZT = ZTpredBGs;
|
rT.predBGs.ZT = ZTpredBGs;
|
||||||
|
@ -631,19 +660,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
aCOBpredBGs.forEach(function(p, i, theArray) {
|
aCOBpredBGs.forEach(function(p, i, theArray) {
|
||||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||||
});
|
});
|
||||||
for (var i=aCOBpredBGs.length-1; i > 12; i--) {
|
for (i=aCOBpredBGs.length-1; i > 12; i--) {
|
||||||
if (aCOBpredBGs[i-1] != aCOBpredBGs[i]) { break; }
|
if (aCOBpredBGs[i-1] !== aCOBpredBGs[i]) { break; }
|
||||||
else { aCOBpredBGs.pop(); }
|
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 )) {
|
if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
|
||||||
COBpredBGs.forEach(function(p, i, theArray) {
|
COBpredBGs.forEach(function(p, i, theArray) {
|
||||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||||
});
|
});
|
||||||
for (var i=COBpredBGs.length-1; i > 12; i--) {
|
for (i=COBpredBGs.length-1; i > 12; i--) {
|
||||||
if (COBpredBGs[i-1] != COBpredBGs[i]) { break; }
|
if (COBpredBGs[i-1] !== COBpredBGs[i]) { break; }
|
||||||
else { COBpredBGs.pop(); }
|
else { COBpredBGs.pop(); }
|
||||||
}
|
}
|
||||||
rT.predBGs.COB = COBpredBGs;
|
rT.predBGs.COB = COBpredBGs;
|
||||||
|
@ -655,8 +682,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
UAMpredBGs.forEach(function(p, i, theArray) {
|
UAMpredBGs.forEach(function(p, i, theArray) {
|
||||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||||
});
|
});
|
||||||
for (var i=UAMpredBGs.length-1; i > 12; i--) {
|
for (i=UAMpredBGs.length-1; i > 12; i--) {
|
||||||
if (UAMpredBGs[i-1] != UAMpredBGs[i]) { break; }
|
if (UAMpredBGs[i-1] !== UAMpredBGs[i]) { break; }
|
||||||
else { UAMpredBGs.pop(); }
|
else { UAMpredBGs.pop(); }
|
||||||
}
|
}
|
||||||
rT.predBGs.UAM = UAMpredBGs;
|
rT.predBGs.UAM = UAMpredBGs;
|
||||||
|
@ -666,7 +693,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set eventualBG and snoozeBG based on COB or UAM predBGs
|
// set eventualBG based on COB or UAM predBGs
|
||||||
rT.eventualBG = eventualBG;
|
rT.eventualBG = eventualBG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,14 +760,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
//console.error("minUAMPredBG:",minUAMPredBG,"minZTGuardBG:",minZTGuardBG,"minZTUAMPredBG:",minZTUAMPredBG);
|
//console.error("minUAMPredBG:",minUAMPredBG,"minZTGuardBG:",minZTGuardBG,"minZTUAMPredBG:",minZTUAMPredBG);
|
||||||
// if any carbs have been entered recently
|
// if any carbs have been entered recently
|
||||||
if (meal_data.carbs) {
|
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 UAM is disabled, use max of minIOBPredBG, minCOBPredBG
|
||||||
if ( ! enableUAM && minCOBPredBG < 999 ) {
|
if ( ! enableUAM && minCOBPredBG < 999 ) {
|
||||||
|
@ -748,30 +767,29 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher
|
// if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher
|
||||||
} else if ( minCOBPredBG < 999 ) {
|
} else if ( minCOBPredBG < 999 ) {
|
||||||
// calculate blendedMinPredBG based on how many carbs remain as COB
|
// calculate blendedMinPredBG based on how many carbs remain as COB
|
||||||
//blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minUAMPredBG;
|
var blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG;
|
||||||
blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG;
|
|
||||||
// if blendedMinPredBG > minCOBPredBG, use that instead
|
// if blendedMinPredBG > minCOBPredBG, use that instead
|
||||||
minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG));
|
minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG));
|
||||||
// if carbs have been entered, but have expired, use minUAMPredBG
|
// if carbs have been entered, but have expired, use minUAMPredBG
|
||||||
} else {
|
} else if ( enableUAM ) {
|
||||||
//minPredBG = minUAMPredBG;
|
|
||||||
minPredBG = minZTUAMPredBG;
|
minPredBG = minZTUAMPredBG;
|
||||||
|
} else {
|
||||||
|
minPredBG = minGuardBG;
|
||||||
}
|
}
|
||||||
// in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG
|
// in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG
|
||||||
} else if ( enableUAM ) {
|
} else if ( enableUAM ) {
|
||||||
//minPredBG = round(Math.max(minIOBPredBG,minUAMPredBG));
|
|
||||||
minPredBG = round(Math.max(minIOBPredBG,minZTUAMPredBG));
|
minPredBG = round(Math.max(minIOBPredBG,minZTUAMPredBG));
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure minPredBG isn't higher than avgPredBG
|
// make sure minPredBG isn't higher than avgPredBG
|
||||||
minPredBG = Math.min( minPredBG, avgPredBG );
|
minPredBG = Math.min( minPredBG, avgPredBG );
|
||||||
|
|
||||||
console.error("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG);
|
console.log("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG);
|
||||||
if (minCOBPredBG < 999) {
|
if (minCOBPredBG < 999) {
|
||||||
console.error(" minCOBPredBG: "+minCOBPredBG);
|
console.log(" minCOBPredBG: "+minCOBPredBG);
|
||||||
}
|
}
|
||||||
if (minUAMPredBG < 999) {
|
if (minUAMPredBG < 999) {
|
||||||
console.error(" minUAMPredBG: "+minUAMPredBG);
|
console.log(" minUAMPredBG: "+minUAMPredBG);
|
||||||
}
|
}
|
||||||
console.error(" avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"/",meal_data.carbs);
|
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:
|
// But if the COB line falls off a cliff, don't trust UAM too much:
|
||||||
|
@ -790,9 +808,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
rT.reason += ", UAMpredBG " + convert_bg(lastUAMpredBG, profile)
|
rT.reason += ", UAMpredBG " + convert_bg(lastUAMpredBG, profile)
|
||||||
}
|
}
|
||||||
rT.reason += "; ";
|
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
|
// 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;
|
var carbsReqBG = naive_eventualBG;
|
||||||
if ( carbsReqBG < 40 ) {
|
if ( carbsReqBG < 40 ) {
|
||||||
carbsReqBG = Math.min( minGuardBG, carbsReqBG );
|
carbsReqBG = Math.min( minGuardBG, carbsReqBG );
|
||||||
|
@ -802,14 +818,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
var minutesAboveMinBG = 240;
|
var minutesAboveMinBG = 240;
|
||||||
var minutesAboveThreshold = 240;
|
var minutesAboveThreshold = 240;
|
||||||
if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
|
if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
|
||||||
for (var i=0; i<COBpredBGs.length; i++) {
|
for (i=0; i<COBpredBGs.length; i++) {
|
||||||
//console.error(COBpredBGs[i], min_bg);
|
//console.error(COBpredBGs[i], min_bg);
|
||||||
if ( COBpredBGs[i] < min_bg ) {
|
if ( COBpredBGs[i] < min_bg ) {
|
||||||
minutesAboveMinBG = 5*i;
|
minutesAboveMinBG = 5*i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var i=0; i<COBpredBGs.length; i++) {
|
for (i=0; i<COBpredBGs.length; i++) {
|
||||||
//console.error(COBpredBGs[i], threshold);
|
//console.error(COBpredBGs[i], threshold);
|
||||||
if ( COBpredBGs[i] < threshold ) {
|
if ( COBpredBGs[i] < threshold ) {
|
||||||
minutesAboveThreshold = 5*i;
|
minutesAboveThreshold = 5*i;
|
||||||
|
@ -817,14 +833,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (var i=0; i<IOBpredBGs.length; i++) {
|
for (i=0; i<IOBpredBGs.length; i++) {
|
||||||
//console.error(IOBpredBGs[i], min_bg);
|
//console.error(IOBpredBGs[i], min_bg);
|
||||||
if ( IOBpredBGs[i] < min_bg ) {
|
if ( IOBpredBGs[i] < min_bg ) {
|
||||||
minutesAboveMinBG = 5*i;
|
minutesAboveMinBG = 5*i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var i=0; i<IOBpredBGs.length; i++) {
|
for (i=0; i<IOBpredBGs.length; i++) {
|
||||||
//console.error(IOBpredBGs[i], threshold);
|
//console.error(IOBpredBGs[i], threshold);
|
||||||
if ( IOBpredBGs[i] < threshold ) {
|
if ( IOBpredBGs[i] < threshold ) {
|
||||||
minutesAboveThreshold = 5*i;
|
minutesAboveThreshold = 5*i;
|
||||||
|
@ -848,9 +864,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
if ( minutesAboveThreshold < 240 || minutesAboveMinBG < 60 ) {
|
if ( minutesAboveThreshold < 240 || minutesAboveMinBG < 60 ) {
|
||||||
console.error("BG projected to remain above",convert_bg(threshold,profile),"for",minutesAboveThreshold,"minutes");
|
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
|
// include at least minutesAboveThreshold worth of zero temps in calculating carbsReq
|
||||||
// always include at least 30m worth of zero temp (carbs to 80, low temp up to target)
|
// 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;
|
var zeroTempDuration = minutesAboveThreshold;
|
||||||
// BG undershoot, minus effect of zero temps until hitting min_bg, converted to grams, minus COB
|
// BG undershoot, minus effect of zero temps until hitting min_bg, converted to grams, minus COB
|
||||||
var zeroTempEffect = profile.current_basal*sens*zeroTempDuration/60;
|
var zeroTempEffect = profile.current_basal*sens*zeroTempDuration/60;
|
||||||
|
@ -871,7 +886,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// predictive low glucose suspend mode: BG is / is projected to be < threshold
|
// predictive low glucose suspend mode: BG is / is projected to be < threshold
|
||||||
} else if ( bg < threshold || minGuardBG < threshold ) {
|
} else if ( bg < threshold || minGuardBG < threshold ) {
|
||||||
rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile);
|
rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile);
|
||||||
var bgUndershoot = target_bg - minGuardBG;
|
bgUndershoot = target_bg - minGuardBG;
|
||||||
var worstCaseInsulinReq = bgUndershoot / sens;
|
var worstCaseInsulinReq = bgUndershoot / sens;
|
||||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||||
durationReq = round(durationReq/30)*30;
|
durationReq = round(durationReq/30)*30;
|
||||||
|
@ -880,6 +895,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
return tempBasalFunctions.setTempBasal(0, durationReq, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(0, durationReq, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if not in LGS mode, cancel temps before the top of the hour to reduce beeping/vibration
|
||||||
|
// console.error(profile.skip_neutral_temps, rT.deliverAt.getMinutes());
|
||||||
|
if ( profile.skip_neutral_temps && rT.deliverAt.getMinutes() >= 55 ) {
|
||||||
|
rT.reason += "; Canceling temp at " + rT.deliverAt.getMinutes() + "m past the hour. ";
|
||||||
|
return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp);
|
||||||
|
}
|
||||||
|
|
||||||
if (eventualBG < min_bg) { // if eventual BG is below target:
|
if (eventualBG < min_bg) { // if eventual BG is below target:
|
||||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " < " + convert_bg(min_bg, profile);
|
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 5m or 30m avg BG is rising faster than expected delta
|
||||||
|
@ -904,9 +926,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate 30m low-temp required to get projected BG up to target
|
// 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
|
// 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);
|
var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / sens);
|
||||||
insulinReq = round( insulinReq , 2);
|
insulinReq = round( insulinReq , 2);
|
||||||
// calculate naiveInsulinReq based on naive_eventualBG
|
// calculate naiveInsulinReq based on naive_eventualBG
|
||||||
|
@ -914,7 +934,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
naiveInsulinReq = round( naiveInsulinReq , 2);
|
naiveInsulinReq = round( naiveInsulinReq , 2);
|
||||||
if (minDelta < 0 && minDelta > expectedDelta) {
|
if (minDelta < 0 && minDelta > expectedDelta) {
|
||||||
// if we're barely falling, newinsulinReq should be barely negative
|
// 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);
|
var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2);
|
||||||
//console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
//console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
||||||
insulinReq = newinsulinReq;
|
insulinReq = newinsulinReq;
|
||||||
|
@ -922,6 +941,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
// rate required to deliver insulinReq less insulin over 30m:
|
// rate required to deliver insulinReq less insulin over 30m:
|
||||||
var rate = basal + (2 * insulinReq);
|
var rate = basal + (2 * insulinReq);
|
||||||
rate = round_basal(rate, profile);
|
rate = round_basal(rate, profile);
|
||||||
|
|
||||||
// if required temp < existing temp basal
|
// if required temp < existing temp basal
|
||||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||||
// if current temp would deliver a lot (30% of basal) less than the required insulin,
|
// if current temp would deliver a lot (30% of basal) less than the required insulin,
|
||||||
|
@ -937,18 +957,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
} else {
|
} else {
|
||||||
// calculate a long enough zero temp to eventually correct back up to target
|
// calculate a long enough zero temp to eventually correct back up to target
|
||||||
if ( rate <=0 ) {
|
if ( rate <=0 ) {
|
||||||
var bgUndershoot = target_bg - naive_eventualBG;
|
bgUndershoot = target_bg - naive_eventualBG;
|
||||||
var worstCaseInsulinReq = bgUndershoot / sens;
|
worstCaseInsulinReq = bgUndershoot / sens;
|
||||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||||
if (durationReq < 0) {
|
if (durationReq < 0) {
|
||||||
durationReq = 0;
|
durationReq = 0;
|
||||||
// don't set an SMB zero temp longer than 60 minutess
|
// don't set a temp longer than 120 minutes
|
||||||
} else {
|
} else {
|
||||||
durationReq = round(durationReq/30)*30;
|
durationReq = round(durationReq/30)*30;
|
||||||
durationReq = Math.min(60,Math.max(0,durationReq));
|
durationReq = Math.min(120,Math.max(0,durationReq));
|
||||||
}
|
}
|
||||||
//console.error(durationReq);
|
//console.error(durationReq);
|
||||||
//rT.reason += "insulinReq " + insulinReq + "; "
|
|
||||||
if (durationReq > 0) {
|
if (durationReq > 0) {
|
||||||
rT.reason += ", setting " + durationReq + "m zero temp. ";
|
rT.reason += ", setting " + durationReq + "m zero temp. ";
|
||||||
return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp);
|
||||||
|
@ -995,8 +1014,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
|
|
||||||
// eventual BG is at/above target
|
// eventual BG is at/above target
|
||||||
// if iob is over max, just cancel any temps
|
// if iob is over max, just cancel any temps
|
||||||
// if we're not here because of SMB, eventual BG is at/above target
|
if ( eventualBG >= max_bg ) {
|
||||||
if (! (microBolusAllowed && rT.COB)) {
|
|
||||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " >= " + convert_bg(max_bg, profile) + ", ";
|
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " >= " + convert_bg(max_bg, profile) + ", ";
|
||||||
}
|
}
|
||||||
if (iob_data.iob > max_iob) {
|
if (iob_data.iob > max_iob) {
|
||||||
|
@ -1012,15 +1030,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
|
|
||||||
// insulinReq is the additional insulin required to get minPredBG down to target_bg
|
// insulinReq is the additional insulin required to get minPredBG down to target_bg
|
||||||
//console.error(minPredBG,eventualBG);
|
//console.error(minPredBG,eventualBG);
|
||||||
//var insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
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 that would put us over max_iob, then reduce accordingly
|
||||||
if (insulinReq > max_iob-iob_data.iob) {
|
if (insulinReq > max_iob-iob_data.iob) {
|
||||||
rT.reason += "max_iob " + max_iob + ", ";
|
rT.reason += "max_iob " + max_iob + ", ";
|
||||||
|
@ -1028,49 +1038,56 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
}
|
}
|
||||||
|
|
||||||
// rate required to deliver insulinReq more insulin over 30m:
|
// rate required to deliver insulinReq more insulin over 30m:
|
||||||
var rate = basal + (2 * insulinReq);
|
rate = basal + (2 * insulinReq);
|
||||||
rate = round_basal(rate, profile);
|
rate = round_basal(rate, profile);
|
||||||
insulinReq = round(insulinReq,3);
|
insulinReq = round(insulinReq,3);
|
||||||
rT.insulinReq = insulinReq;
|
rT.insulinReq = insulinReq;
|
||||||
//console.error(iob_data.lastBolusTime);
|
//console.error(iob_data.lastBolusTime);
|
||||||
// minutes since last bolus
|
// minutes since last bolus
|
||||||
var lastBolusAge = round(( new Date().getTime() - iob_data.lastBolusTime ) / 60000,1);
|
var lastBolusAge = round(( new Date(systemTime).getTime() - iob_data.lastBolusTime ) / 60000,1);
|
||||||
//console.error(lastBolusAge);
|
//console.error(lastBolusAge);
|
||||||
//console.error(profile.temptargetSet, target_bg, rT.COB);
|
//console.error(profile.temptargetSet, target_bg, rT.COB);
|
||||||
// only allow microboluses with COB or low temp targets, or within DIA hours of a bolus
|
// only allow microboluses with COB or low temp targets, or within DIA hours of a bolus
|
||||||
if (microBolusAllowed && enableSMB && bg > threshold) {
|
if (microBolusAllowed && enableSMB && bg > threshold) {
|
||||||
// never bolus more than maxSMBBasalMinutes worth of basal
|
// never bolus more than maxSMBBasalMinutes worth of basal
|
||||||
mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3);
|
var mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3);
|
||||||
if (typeof profile.maxSMBBasalMinutes == 'undefined' ) {
|
if (typeof profile.maxSMBBasalMinutes === 'undefined' ) {
|
||||||
maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
var maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
||||||
console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m");
|
console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m");
|
||||||
// if IOB covers more than COB, limit maxBolus to 30m of basal
|
// if IOB covers more than COB, limit maxBolus to 30m of basal
|
||||||
} else if ( iob_data.iob > mealInsulinReq && iob_data.iob > 0 ) {
|
} else if ( iob_data.iob > mealInsulinReq && iob_data.iob > 0 ) {
|
||||||
console.error("IOB",iob_data.iob,"> COB",meal_data.mealCOB+"; mealInsulinReq =",mealInsulinReq);
|
console.error("IOB",iob_data.iob,"> COB",meal_data.mealCOB+"; mealInsulinReq =",mealInsulinReq);
|
||||||
|
if (profile.maxUAMSMBBasalMinutes) {
|
||||||
|
console.error("profile.maxUAMSMBBasalMinutes:",profile.maxUAMSMBBasalMinutes,"profile.current_basal:",profile.current_basal);
|
||||||
|
maxBolus = round( profile.current_basal * profile.maxUAMSMBBasalMinutes / 60 ,1);
|
||||||
|
} else {
|
||||||
|
console.error("profile.maxUAMSMBBasalMinutes undefined: defaulting to 30m");
|
||||||
maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("profile.maxSMBBasalMinutes:",profile.maxSMBBasalMinutes,"profile.current_basal:",profile.current_basal);
|
console.error("profile.maxSMBBasalMinutes:",profile.maxSMBBasalMinutes,"profile.current_basal:",profile.current_basal);
|
||||||
maxBolus = round( profile.current_basal * profile.maxSMBBasalMinutes / 60 ,1);
|
maxBolus = round( profile.current_basal * profile.maxSMBBasalMinutes / 60 ,1);
|
||||||
}
|
}
|
||||||
// bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest 0.1U
|
// bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest bolus increment
|
||||||
microBolus = Math.floor(Math.min(insulinReq/2,maxBolus)*10)/10;
|
var roundSMBTo = 1 / profile.bolus_increment;
|
||||||
|
var microBolus = Math.floor(Math.min(insulinReq/2,maxBolus)*roundSMBTo)/roundSMBTo;
|
||||||
// calculate a long enough zero temp to eventually correct back up to target
|
// calculate a long enough zero temp to eventually correct back up to target
|
||||||
var smbTarget = target_bg;
|
var smbTarget = target_bg;
|
||||||
var worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens;
|
worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens;
|
||||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
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 but not enough for a microBolus, don't set an SMB zero temp
|
||||||
if (insulinReq > 0 && microBolus < 0.1) {
|
if (insulinReq > 0 && microBolus < profile.bolus_increment) {
|
||||||
durationReq = 0;
|
durationReq = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var smbLowTempReq = 0;
|
var smbLowTempReq = 0;
|
||||||
if (durationReq <= 0) {
|
if (durationReq <= 0) {
|
||||||
durationReq = 0;
|
durationReq = 0;
|
||||||
// don't set a temp longer than 120 minutes
|
// don't set an SMB zero temp longer than 60 minutes
|
||||||
} else if (durationReq >= 30) {
|
} else if (durationReq >= 30) {
|
||||||
durationReq = round(durationReq/30)*30;
|
durationReq = round(durationReq/30)*30;
|
||||||
durationReq = Math.min(120,Math.max(0,durationReq));
|
durationReq = Math.min(60,Math.max(0,durationReq));
|
||||||
} else {
|
} else {
|
||||||
// if SMB durationReq is less than 30m, set a nonzero low temp
|
// if SMB durationReq is less than 30m, set a nonzero low temp
|
||||||
smbLowTempReq = round( basal * durationReq/30 ,2);
|
smbLowTempReq = round( basal * durationReq/30 ,2);
|
||||||
|
@ -1085,17 +1102,23 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
}
|
}
|
||||||
rT.reason += ". ";
|
rT.reason += ". ";
|
||||||
|
|
||||||
//allow SMBs every 3 minutes
|
//allow SMBs every 3 minutes by default
|
||||||
var nextBolusMins = round(3-lastBolusAge,1);
|
var SMBInterval = 3;
|
||||||
|
if (profile.SMBInterval) {
|
||||||
|
// allow SMBIntervals between 1 and 10 minutes
|
||||||
|
SMBInterval = Math.min(10,Math.max(1,profile.SMBInterval));
|
||||||
|
}
|
||||||
|
var nextBolusMins = round(SMBInterval-lastBolusAge,0);
|
||||||
|
var nextBolusSeconds = round((SMBInterval - lastBolusAge) * 60, 0) % 60;
|
||||||
//console.error(naive_eventualBG, insulinReq, worstCaseInsulinReq, durationReq);
|
//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);
|
console.error("naive_eventualBG",naive_eventualBG+",",durationReq+"m "+smbLowTempReq+"U/h temp needed; last bolus",lastBolusAge+"m ago; maxBolus: "+maxBolus);
|
||||||
if (lastBolusAge > 3) {
|
if (lastBolusAge > SMBInterval) {
|
||||||
if (microBolus > 0) {
|
if (microBolus > 0) {
|
||||||
rT.units = microBolus;
|
rT.units = microBolus;
|
||||||
rT.reason += "Microbolusing " + microBolus + "U. ";
|
rT.reason += "Microbolusing " + microBolus + "U. ";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rT.reason += "Waiting " + nextBolusMins + "m to microbolus again. ";
|
rT.reason += "Waiting " + nextBolusMins + "m " + nextBolusSeconds + "s to microbolus again. ";
|
||||||
}
|
}
|
||||||
//rT.reason += ". ";
|
//rT.reason += ". ";
|
||||||
|
|
||||||
|
@ -1106,11 +1129,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
return rT;
|
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);
|
var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
|
||||||
|
@ -1120,13 +1138,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
rate = round_basal(maxSafeBasal, profile);
|
rate = round_basal(maxSafeBasal, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
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
|
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. ";
|
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);
|
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set
|
if (typeof currenttemp.duration === 'undefined' || currenttemp.duration === 0) { // no temp is set
|
||||||
rT.reason += "no temp, setting " + rate + "U/hr. ";
|
rT.reason += "no temp, setting " + rate + "U/hr. ";
|
||||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,10 +107,6 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval {
|
||||||
return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours;
|
return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String age() {
|
|
||||||
return age(OverviewFragment.shorttextmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOlderThan(double hours) {
|
public boolean isOlderThan(double hours) {
|
||||||
return getHoursFromStart() > hours;
|
return getHoursFromStart() > hours;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ abstract class PluginsModule {
|
||||||
abstract fun bindMDIPlugin(plugin: MDIPlugin): PluginBase
|
abstract fun bindMDIPlugin(plugin: MDIPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@NotNSClient
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@IntKey(180)
|
@IntKey(180)
|
||||||
abstract fun bindVirtualPumpPlugin(plugin: VirtualPumpPlugin): PluginBase
|
abstract fun bindVirtualPumpPlugin(plugin: VirtualPumpPlugin): PluginBase
|
||||||
|
|
|
@ -28,6 +28,7 @@ import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity;
|
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity;
|
||||||
import info.nightscout.androidaps.data.Profile;
|
import info.nightscout.androidaps.data.Profile;
|
||||||
import info.nightscout.androidaps.events.EventCustomCalculationFinished;
|
import info.nightscout.androidaps.events.EventCustomCalculationFinished;
|
||||||
|
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
|
@ -35,6 +36,7 @@ import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.OverviewFragment;
|
import info.nightscout.androidaps.plugins.general.overview.OverviewFragment;
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.OverviewMenus;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData;
|
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData;
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
|
||||||
|
@ -60,6 +62,7 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
||||||
@Inject ActivePluginProvider activePlugin;
|
@Inject ActivePluginProvider activePlugin;
|
||||||
@Inject BuildHelper buildHelper;
|
@Inject BuildHelper buildHelper;
|
||||||
@Inject FabricPrivacy fabricPrivacy;
|
@Inject FabricPrivacy fabricPrivacy;
|
||||||
|
@Inject OverviewMenus overviewMenus;
|
||||||
|
|
||||||
private CompositeDisposable disposable = new CompositeDisposable();
|
private CompositeDisposable disposable = new CompositeDisposable();
|
||||||
|
|
||||||
|
@ -171,7 +174,7 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
||||||
iobGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
|
iobGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
|
||||||
iobGraph.getGridLabelRenderer().setNumVerticalLabels(5);
|
iobGraph.getGridLabelRenderer().setNumVerticalLabels(5);
|
||||||
|
|
||||||
setupChartMenu();
|
overviewMenus.setupChartMenu(findViewById(R.id.overview_chartMenuButton));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -194,7 +197,7 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
||||||
updateGUI("EventAutosensCalculationFinished");
|
updateGUI("EventAutosensCalculationFinished");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, exception -> fabricPrivacy.logException(exception))
|
}, fabricPrivacy::logException)
|
||||||
);
|
);
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
.toObservable(EventIobCalculationProgress.class)
|
.toObservable(EventIobCalculationProgress.class)
|
||||||
|
@ -204,6 +207,11 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
||||||
iobCalculationProgressView.setText(event.getProgress());
|
iobCalculationProgressView.setText(event.getProgress());
|
||||||
}, exception -> fabricPrivacy.logException(exception))
|
}, exception -> fabricPrivacy.logException(exception))
|
||||||
);
|
);
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventRefreshOverview.class)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(event -> updateGUI("EventRefreshOverview") , fabricPrivacy::logException)
|
||||||
|
);
|
||||||
// set start of current day
|
// set start of current day
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
calendar.setTimeInMillis(System.currentTimeMillis());
|
calendar.setTimeInMillis(System.currentTimeMillis());
|
||||||
|
@ -367,124 +375,4 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
||||||
});
|
});
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupChartMenu() {
|
|
||||||
chartButton = findViewById(R.id.overview_chartMenuButton);
|
|
||||||
chartButton.setOnClickListener(v -> {
|
|
||||||
MenuItem item, dividerItem;
|
|
||||||
CharSequence title;
|
|
||||||
int titleMaxChars = 0;
|
|
||||||
SpannableString s;
|
|
||||||
PopupMenu popup = new PopupMenu(v.getContext(), v);
|
|
||||||
|
|
||||||
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.BAS.ordinal(), Menu.NONE, resourceHelper.gs(R.string.overview_show_basals));
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.basal, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showBasal);
|
|
||||||
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTPRIM.ordinal(), Menu.NONE, resourceHelper.gs(R.string.overview_show_activity));
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showActPrim);
|
|
||||||
|
|
||||||
dividerItem = popup.getMenu().add("");
|
|
||||||
dividerItem.setEnabled(false);
|
|
||||||
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.IOB.ordinal(), Menu.NONE, resourceHelper.gs(R.string.overview_show_iob));
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showIob);
|
|
||||||
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.COB.ordinal(), Menu.NONE, resourceHelper.gs(R.string.overview_show_cob));
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showCob);
|
|
||||||
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEV.ordinal(), Menu.NONE, resourceHelper.gs(R.string.overview_show_deviations));
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showDev);
|
|
||||||
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.SEN.ordinal(), Menu.NONE, resourceHelper.gs(R.string.overview_show_sensitivity));
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.ratio, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showRat);
|
|
||||||
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTSEC.ordinal(), Menu.NONE, resourceHelper.gs(R.string.overview_show_activity));
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showActSec);
|
|
||||||
|
|
||||||
|
|
||||||
if (buildHelper.isDev()) {
|
|
||||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope");
|
|
||||||
title = item.getTitle();
|
|
||||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
|
||||||
s = new SpannableString(title);
|
|
||||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0);
|
|
||||||
item.setTitle(s);
|
|
||||||
item.setCheckable(true);
|
|
||||||
item.setChecked(showDevslope);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fairly good guestimate for required divider text size...
|
|
||||||
title = new String(new char[titleMaxChars + 10]).replace("\0", "_");
|
|
||||||
dividerItem.setTitle(title);
|
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener(item1 -> {
|
|
||||||
if (item1.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showbasals", !item1.isChecked());
|
|
||||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.IOB.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showiob", !item1.isChecked());
|
|
||||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.COB.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showcob", !item1.isChecked());
|
|
||||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEV.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showdeviations", !item1.isChecked());
|
|
||||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showratios", !item1.isChecked());
|
|
||||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTPRIM.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showactivityprimary", !item1.isChecked());
|
|
||||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTSEC.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showactivitysecondary", !item1.isChecked());
|
|
||||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) {
|
|
||||||
sp.putBoolean("hist_showdevslope", !item1.isChecked());
|
|
||||||
}
|
|
||||||
updateGUI("onGraphCheckboxesCheckedChanged");
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
|
|
||||||
popup.setOnDismissListener(menu -> chartButton.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp));
|
|
||||||
popup.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires
|
||||||
LOCATION("LOCATION"),
|
LOCATION("LOCATION"),
|
||||||
NOTIFICATION("NOTIFICATION"),
|
NOTIFICATION("NOTIFICATION"),
|
||||||
NSCLIENT("NSCLIENT"),
|
NSCLIENT("NSCLIENT"),
|
||||||
OVERVIEW("OVERVIEW", defaultValue = false),
|
|
||||||
PUMP("PUMP"),
|
PUMP("PUMP"),
|
||||||
PUMPBTCOMM("PUMPBTCOMM", defaultValue = false),
|
PUMPBTCOMM("PUMPBTCOMM", defaultValue = false),
|
||||||
PUMPCOMM("PUMPCOMM"),
|
PUMPCOMM("PUMPCOMM"),
|
||||||
|
|
|
@ -81,7 +81,7 @@ class LoopFragment : DaggerFragment() {
|
||||||
loop_request?.text = it.request?.toSpanned() ?: ""
|
loop_request?.text = it.request?.toSpanned() ?: ""
|
||||||
loop_constraintsprocessed?.text = it.constraintsProcessed?.toSpanned() ?: ""
|
loop_constraintsprocessed?.text = it.constraintsProcessed?.toSpanned() ?: ""
|
||||||
loop_source?.text = it.source ?: ""
|
loop_source?.text = it.source ?: ""
|
||||||
loop_lastrun?.text = it.lastAPSRun?.let { lastRun -> DateUtil.dateAndTimeString(lastRun.time) }
|
loop_lastrun?.text = DateUtil.dateAndTimeString(it.lastAPSRun)
|
||||||
?: ""
|
?: ""
|
||||||
loop_smbrequest_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest)
|
loop_smbrequest_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest)
|
||||||
loop_smbexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
|
loop_smbexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import android.os.SystemClock;
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ public class LoopPlugin extends PluginBase {
|
||||||
public PumpEnactResult tbrSetByPump = null;
|
public PumpEnactResult tbrSetByPump = null;
|
||||||
public PumpEnactResult smbSetByPump = null;
|
public PumpEnactResult smbSetByPump = null;
|
||||||
public String source = null;
|
public String source = null;
|
||||||
public Date lastAPSRun = null;
|
public long lastAPSRun = DateUtil.now();
|
||||||
public long lastTBREnact = 0;
|
public long lastTBREnact = 0;
|
||||||
public long lastSMBEnact = 0;
|
public long lastSMBEnact = 0;
|
||||||
public long lastTBRRequest = 0;
|
public long lastTBRRequest = 0;
|
||||||
|
@ -112,7 +113,7 @@ public class LoopPlugin extends PluginBase {
|
||||||
public long lastOpenModeAccept;
|
public long lastOpenModeAccept;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LastRun lastRun = null;
|
@Nullable public LastRun lastRun = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LoopPlugin(
|
public LoopPlugin(
|
||||||
|
@ -381,7 +382,6 @@ public class LoopPlugin extends PluginBase {
|
||||||
if (lastRun == null) lastRun = new LastRun();
|
if (lastRun == null) lastRun = new LastRun();
|
||||||
lastRun.request = result;
|
lastRun.request = result;
|
||||||
lastRun.constraintsProcessed = resultAfterConstraints;
|
lastRun.constraintsProcessed = resultAfterConstraints;
|
||||||
lastRun.lastAPSRun = new Date();
|
|
||||||
lastRun.source = ((PluginBase) usedAPS).getName();
|
lastRun.source = ((PluginBase) usedAPS).getName();
|
||||||
lastRun.tbrSetByPump = null;
|
lastRun.tbrSetByPump = null;
|
||||||
lastRun.smbSetByPump = null;
|
lastRun.smbSetByPump = null;
|
||||||
|
@ -423,7 +423,7 @@ public class LoopPlugin extends PluginBase {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (result.enacted || result.success) {
|
if (result.enacted || result.success) {
|
||||||
lastRun.tbrSetByPump = result;
|
lastRun.tbrSetByPump = result;
|
||||||
lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
|
lastRun.lastTBRRequest = lastRun.lastAPSRun;
|
||||||
lastRun.lastTBREnact = DateUtil.now();
|
lastRun.lastTBREnact = DateUtil.now();
|
||||||
rxBus.send(new EventLoopUpdateGui());
|
rxBus.send(new EventLoopUpdateGui());
|
||||||
applySMBRequest(resultAfterConstraints, new Callback() {
|
applySMBRequest(resultAfterConstraints, new Callback() {
|
||||||
|
@ -432,7 +432,7 @@ public class LoopPlugin extends PluginBase {
|
||||||
//Callback is only called if a bolus was acutally requested
|
//Callback is only called if a bolus was acutally requested
|
||||||
if (result.enacted || result.success) {
|
if (result.enacted || result.success) {
|
||||||
lastRun.smbSetByPump = result;
|
lastRun.smbSetByPump = result;
|
||||||
lastRun.lastSMBRequest = lastRun.lastAPSRun.getTime();
|
lastRun.lastSMBRequest = lastRun.lastAPSRun;
|
||||||
lastRun.lastSMBEnact = DateUtil.now();
|
lastRun.lastSMBEnact = DateUtil.now();
|
||||||
} else {
|
} else {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
|
@ -512,7 +512,7 @@ public class LoopPlugin extends PluginBase {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (result.enacted) {
|
if (result.enacted) {
|
||||||
lastRun.tbrSetByPump = result;
|
lastRun.tbrSetByPump = result;
|
||||||
lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
|
lastRun.lastTBRRequest = lastRun.lastAPSRun;
|
||||||
lastRun.lastTBREnact = DateUtil.now();
|
lastRun.lastTBREnact = DateUtil.now();
|
||||||
lastRun.lastOpenModeAccept = DateUtil.now();
|
lastRun.lastOpenModeAccept = DateUtil.now();
|
||||||
NSUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump());
|
NSUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump());
|
||||||
|
|
|
@ -34,11 +34,14 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||||
import info.nightscout.androidaps.utils.SafeParse;
|
import info.nightscout.androidaps.utils.SafeParse;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
|
|
||||||
|
|
||||||
public class DetermineBasalAdapterSMBJS {
|
public class DetermineBasalAdapterSMBJS {
|
||||||
private final HasAndroidInjector injector;
|
private final HasAndroidInjector injector;
|
||||||
@Inject AAPSLogger aapsLogger;
|
@Inject AAPSLogger aapsLogger;
|
||||||
|
@ -47,6 +50,8 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
@Inject ResourceHelper resourceHelper;
|
@Inject ResourceHelper resourceHelper;
|
||||||
@Inject ProfileFunction profileFunction;
|
@Inject ProfileFunction profileFunction;
|
||||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
@Inject TreatmentsPlugin treatmentsPlugin;
|
||||||
|
@Inject ActivePluginProvider activePluginProvider;
|
||||||
|
|
||||||
|
|
||||||
private ScriptReader mScriptReader;
|
private ScriptReader mScriptReader;
|
||||||
private JSONObject mProfile;
|
private JSONObject mProfile;
|
||||||
|
@ -57,6 +62,7 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
private JSONObject mAutosensData = null;
|
private JSONObject mAutosensData = null;
|
||||||
private boolean mMicrobolusAllowed;
|
private boolean mMicrobolusAllowed;
|
||||||
private boolean mSMBAlwaysAllowed;
|
private boolean mSMBAlwaysAllowed;
|
||||||
|
private long mCurrentTime;
|
||||||
|
|
||||||
private String storedCurrentTemp = null;
|
private String storedCurrentTemp = null;
|
||||||
private String storedIobData = null;
|
private String storedIobData = null;
|
||||||
|
@ -67,6 +73,7 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
private String storedAutosens_data = null;
|
private String storedAutosens_data = null;
|
||||||
private String storedMicroBolusAllowed = null;
|
private String storedMicroBolusAllowed = null;
|
||||||
private String storedSMBAlwaysAllowed = null;
|
private String storedSMBAlwaysAllowed = null;
|
||||||
|
private String storedCurrentTime = null;
|
||||||
|
|
||||||
private String scriptDebug = "";
|
private String scriptDebug = "";
|
||||||
|
|
||||||
|
@ -98,6 +105,7 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined");
|
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined");
|
||||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed));
|
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed));
|
||||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + (storedSMBAlwaysAllowed = "" + mSMBAlwaysAllowed));
|
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + (storedSMBAlwaysAllowed = "" + mSMBAlwaysAllowed));
|
||||||
|
aapsLogger.debug(LTag.APS, "CurrentTime: " + (storedCurrentTime = "" + mCurrentTime));
|
||||||
|
|
||||||
|
|
||||||
DetermineBasalResultSMB determineBasalResultSMB = null;
|
DetermineBasalResultSMB determineBasalResultSMB = null;
|
||||||
|
@ -140,7 +148,8 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
makeParam(mMealData, rhino, scope),
|
makeParam(mMealData, rhino, scope),
|
||||||
setTempBasalFunctionsObj,
|
setTempBasalFunctionsObj,
|
||||||
new Boolean(mMicrobolusAllowed),
|
new Boolean(mMicrobolusAllowed),
|
||||||
makeParam(null, rhino, scope) // reservoir data as undefined
|
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||||
|
new Long(mCurrentTime)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,6 +236,8 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
boolean advancedFiltering
|
boolean advancedFiltering
|
||||||
) throws JSONException {
|
) throws JSONException {
|
||||||
|
|
||||||
|
String units = profile.getUnits();
|
||||||
|
Double pumpbolusstep = activePluginProvider.getActivePump().getPumpDescription().bolusStep;
|
||||||
mProfile = new JSONObject();
|
mProfile = new JSONObject();
|
||||||
|
|
||||||
mProfile.put("max_iob", maxIob);
|
mProfile.put("max_iob", maxIob);
|
||||||
|
@ -242,7 +253,6 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
|
mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
|
||||||
mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
|
mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
|
||||||
|
|
||||||
// TODO AS-FIX
|
|
||||||
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
||||||
mProfile.put("high_temptarget_raises_sensitivity", false);
|
mProfile.put("high_temptarget_raises_sensitivity", false);
|
||||||
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||||
|
@ -267,13 +277,17 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
|
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
|
||||||
|
|
||||||
boolean smbEnabled = sp.getBoolean(resourceHelper.gs(R.string.key_use_smb), false);
|
boolean smbEnabled = sp.getBoolean(resourceHelper.gs(R.string.key_use_smb), false);
|
||||||
|
mProfile.put("SMBInterval", sp.getInt("key_smbinterval", SMBDefaults.SMBInterval));
|
||||||
mProfile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false));
|
mProfile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false));
|
||||||
mProfile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false));
|
mProfile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false));
|
||||||
mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
|
mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
|
||||||
mProfile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering);
|
mProfile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering);
|
||||||
mProfile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering);
|
mProfile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering);
|
||||||
mProfile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes));
|
mProfile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes));
|
||||||
mProfile.put("carbsReqThreshold", SMBDefaults.carbsReqThreshold);
|
mProfile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes));
|
||||||
|
//set the min SMB amount to be the amount set by the pump.
|
||||||
|
mProfile.put("bolus_increment", pumpbolusstep);
|
||||||
|
mProfile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold));
|
||||||
|
|
||||||
mProfile.put("current_basal", basalrate);
|
mProfile.put("current_basal", basalrate);
|
||||||
mProfile.put("temptargetSet", tempTargetSet);
|
mProfile.put("temptargetSet", tempTargetSet);
|
||||||
|
@ -302,6 +316,7 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
|
|
||||||
mGlucoseStatus = new JSONObject();
|
mGlucoseStatus = new JSONObject();
|
||||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose);
|
mGlucoseStatus.put("glucose", glucoseStatus.glucose);
|
||||||
|
mGlucoseStatus.put("noise", glucoseStatus.noise);
|
||||||
|
|
||||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||||
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
|
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
|
||||||
|
@ -332,6 +347,8 @@ public class DetermineBasalAdapterSMBJS {
|
||||||
mMicrobolusAllowed = microBolusAllowed;
|
mMicrobolusAllowed = microBolusAllowed;
|
||||||
mSMBAlwaysAllowed = advancedFiltering;
|
mSMBAlwaysAllowed = advancedFiltering;
|
||||||
|
|
||||||
|
mCurrentTime = now;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
|
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
|
||||||
|
|
|
@ -55,10 +55,13 @@ public class SMBDefaults {
|
||||||
// *** WARNING *** DO NOT USE enableSMB_always or enableSMB_after_carbs with xDrip+, Libre, or similar
|
// *** 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 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 boolean allowSMB_with_high_temptarget = false; // allow supermicrobolus (if otherwise enabled) even with high temp targets
|
||||||
|
public final static int SMBInterval = 3; // minimum interval between SMBs, in minutes. (limited between 1 and 10 min)
|
||||||
public final static int maxSMBBasalMinutes = 30; // maximum minutes of basal that can be delivered as a single SMB with uncovered COB
|
public final static int maxSMBBasalMinutes = 30; // maximum minutes of basal that can be delivered as a single SMB with uncovered COB
|
||||||
|
public final static int maxUAMSMBBasalMinutes = 30; // maximum minutes of basal that can be delivered as a single SMB when IOB exceeds COB
|
||||||
// curve:"rapid-acting" // Supported curves: "bilinear", "rapid-acting" (Novolog, Novorapid, Humalog, Apidra) and "ultra-rapid" (Fiasp)
|
// curve:"rapid-acting" // Supported curves: "bilinear", "rapid-acting" (Novolog, Novorapid, Humalog, Apidra) and "ultra-rapid" (Fiasp)
|
||||||
// useCustomPeakTime:false // allows changing insulinPeakTime
|
// useCustomPeakTime:false // allows changing insulinPeakTime
|
||||||
// insulinPeakTime:75 // number of minutes after a bolus activity peaks. defaults to 55m for Fiasp if useCustomPeakTime: false
|
// 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
|
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
|
// offline_hotspot:false // enabled an offline-only local wifi hotspot if no Internet available
|
||||||
|
public final static double bolus_increment = 0.1; // minimum bolus that can be delivered as an SMB
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import info.nightscout.androidaps.activities.PreferencesActivity
|
||||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.util.ArrayList;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Lazy;
|
|
||||||
import dagger.android.HasAndroidInjector;
|
import dagger.android.HasAndroidInjector;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.events.EventAppInitialized;
|
import info.nightscout.androidaps.events.EventAppInitialized;
|
||||||
|
@ -18,7 +17,6 @@ import info.nightscout.androidaps.events.EventRebuildTabs;
|
||||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||||
import info.nightscout.androidaps.interfaces.BgSourceInterface;
|
import info.nightscout.androidaps.interfaces.BgSourceInterface;
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.InsulinInterface;
|
import info.nightscout.androidaps.interfaces.InsulinInterface;
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||||
|
@ -30,13 +28,7 @@ import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin;
|
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui;
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.OKDialog;
|
import info.nightscout.androidaps.utils.OKDialog;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package info.nightscout.androidaps.plugins.configBuilder
|
package info.nightscout.androidaps.plugins.configBuilder
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import java.util.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class PluginStore @Inject constructor(
|
class PluginStore @Inject constructor(
|
||||||
|
@ -27,6 +26,7 @@ class PluginStore @Inject constructor(
|
||||||
return pluginStore!!
|
return pluginStore!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
|
lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
|
||||||
|
|
||||||
private var activeBgSource: BgSourceInterface? = null
|
private var activeBgSource: BgSourceInterface? = null
|
||||||
|
@ -83,6 +83,7 @@ class PluginStore @Inject constructor(
|
||||||
var pluginsInCategory: ArrayList<PluginBase>?
|
var pluginsInCategory: ArrayList<PluginBase>?
|
||||||
|
|
||||||
// PluginType.APS
|
// PluginType.APS
|
||||||
|
if (!Config.NSCLIENT && !Config.PUMPCONTROL) {
|
||||||
pluginsInCategory = getSpecificPluginsList(PluginType.APS)
|
pluginsInCategory = getSpecificPluginsList(PluginType.APS)
|
||||||
activeAPS = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface?
|
activeAPS = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface?
|
||||||
if (activeAPS == null) {
|
if (activeAPS == null) {
|
||||||
|
@ -91,6 +92,7 @@ class PluginStore @Inject constructor(
|
||||||
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface")
|
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface")
|
||||||
}
|
}
|
||||||
setFragmentVisiblities((activeAPS as PluginBase).name, pluginsInCategory, PluginType.APS)
|
setFragmentVisiblities((activeAPS as PluginBase).name, pluginsInCategory, PluginType.APS)
|
||||||
|
}
|
||||||
|
|
||||||
// PluginType.INSULIN
|
// PluginType.INSULIN
|
||||||
pluginsInCategory = getSpecificPluginsList(PluginType.INSULIN)
|
pluginsInCategory = getSpecificPluginsList(PluginType.INSULIN)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.configBuilder
|
package info.nightscout.androidaps.plugins.configBuilder.events
|
||||||
|
|
||||||
import info.nightscout.androidaps.events.EventUpdateGui
|
import info.nightscout.androidaps.events.EventUpdateGui
|
||||||
|
|
|
@ -56,7 +56,7 @@ class VersionCheckerUtils @Inject constructor(
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
} else
|
} else
|
||||||
aapsLogger.debug(LTag.CORE, "Github master version no checked. No connectivity")
|
aapsLogger.debug(LTag.CORE, "Github master version not checked. No connectivity")
|
||||||
|
|
||||||
@Suppress("SameParameterValue")
|
@Suppress("SameParameterValue")
|
||||||
fun compareWithCurrentVersion(newVersion: String?, currentVersion: String) {
|
fun compareWithCurrentVersion(newVersion: String?, currentVersion: String) {
|
||||||
|
|
|
@ -125,7 +125,7 @@ class DataBroadcastPlugin @Inject constructor(
|
||||||
|
|
||||||
private fun bgStatus(bundle: Bundle) {
|
private fun bgStatus(bundle: Bundle) {
|
||||||
val lastBG: BgReading = iobCobCalculatorPlugin.lastBg() ?: return
|
val lastBG: BgReading = iobCobCalculatorPlugin.lastBg() ?: return
|
||||||
val glucoseStatus = GlucoseStatus(injector).getGlucoseStatusData() ?: return
|
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData ?: return
|
||||||
|
|
||||||
bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl
|
bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl
|
||||||
bundle.putLong("glucoseTimeStamp", lastBG.date) // timestamp
|
bundle.putLong("glucoseTimeStamp", lastBG.date) // timestamp
|
||||||
|
@ -158,10 +158,9 @@ class DataBroadcastPlugin @Inject constructor(
|
||||||
bundle.putInt("rigBattery", nsDeviceStatus.uploaderStatus.replace("%", "").trim { it <= ' ' }.toInt())
|
bundle.putInt("rigBattery", nsDeviceStatus.uploaderStatus.replace("%", "").trim { it <= ' ' }.toInt())
|
||||||
|
|
||||||
if (Config.APS && lazyLoopPlugin.get().lastRun?.lastTBREnact != 0L) { //we are AndroidAPS
|
if (Config.APS && lazyLoopPlugin.get().lastRun?.lastTBREnact != 0L) { //we are AndroidAPS
|
||||||
bundle.putLong("suggestedTimeStamp", lazyLoopPlugin.get().lastRun?.lastAPSRun?.time
|
bundle.putLong("suggestedTimeStamp", lazyLoopPlugin.get().lastRun?.lastAPSRun ?: -1L)
|
||||||
?: -1L)
|
|
||||||
bundle.putString("suggested", lazyLoopPlugin.get().lastRun?.request?.json().toString())
|
bundle.putString("suggested", lazyLoopPlugin.get().lastRun?.request?.json().toString())
|
||||||
if (lazyLoopPlugin.get().lastRun.tbrSetByPump != null && lazyLoopPlugin.get().lastRun.tbrSetByPump.enacted) {
|
if (lazyLoopPlugin.get().lastRun?.tbrSetByPump != null && lazyLoopPlugin.get().lastRun?.tbrSetByPump?.enacted == true) {
|
||||||
bundle.putLong("enactedTimeStamp", lazyLoopPlugin.get().lastRun?.lastTBREnact
|
bundle.putLong("enactedTimeStamp", lazyLoopPlugin.get().lastRun?.lastTBREnact
|
||||||
?: -1L)
|
?: -1L)
|
||||||
bundle.putString("enacted", lazyLoopPlugin.get().lastRun?.request?.json().toString())
|
bundle.putString("enacted", lazyLoopPlugin.get().lastRun?.request?.json().toString())
|
||||||
|
|
|
@ -125,13 +125,13 @@ class ImportExportPrefs @Inject constructor(
|
||||||
val n5 = Settings.Secure.getString(context.contentResolver, "lock_screen_owner_info")
|
val n5 = Settings.Secure.getString(context.contentResolver, "lock_screen_owner_info")
|
||||||
val n6 = Settings.Global.getString(context.contentResolver, "device_name")
|
val n6 = Settings.Global.getString(context.contentResolver, "device_name")
|
||||||
|
|
||||||
// name we use for SMS OTP token in communicator
|
// name provided (hopefully) by user
|
||||||
val otpName = otp.name().trim()
|
val patientName = sp.getString(R.string.key_patient_name, "")
|
||||||
val defaultOtpName = resourceHelper.gs(R.string.smscommunicator_default_user_display_name)
|
val defaultPatientName = resourceHelper.gs(R.string.patient_name_default)
|
||||||
|
|
||||||
// name we detect from OS
|
// name we detect from OS
|
||||||
val systemName = n1 ?: n2 ?: n3 ?: n4 ?: n5 ?: n6 ?: defaultOtpName
|
val systemName = n1 ?: n2 ?: n3 ?: n4 ?: n5 ?: n6 ?: defaultPatientName
|
||||||
val name = if (otpName.length > 0 && otpName != defaultOtpName) otpName else systemName
|
val name = if (patientName.isNotEmpty() && patientName != defaultPatientName) patientName else systemName
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ public class NSUpload {
|
||||||
DeviceStatus deviceStatus = new DeviceStatus();
|
DeviceStatus deviceStatus = new DeviceStatus();
|
||||||
try {
|
try {
|
||||||
LoopPlugin.LastRun lastRun = loopPlugin.lastRun;
|
LoopPlugin.LastRun lastRun = loopPlugin.lastRun;
|
||||||
if (lastRun != null && lastRun.lastAPSRun.getTime() > System.currentTimeMillis() - 300 * 1000L) {
|
if (lastRun != null && lastRun.lastAPSRun > System.currentTimeMillis() - 300 * 1000L) {
|
||||||
// do not send if result is older than 1 min
|
// do not send if result is older than 1 min
|
||||||
APSResult apsResult = lastRun.request;
|
APSResult apsResult = lastRun.request;
|
||||||
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun));
|
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun));
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,825 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.overview
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.ContextMenu
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.OnLongClickListener
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import dagger.android.support.DaggerFragment
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
|
import info.nightscout.androidaps.Constants
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.dialogs.CalibrationDialog
|
||||||
|
import info.nightscout.androidaps.dialogs.CarbsDialog
|
||||||
|
import info.nightscout.androidaps.dialogs.InsulinDialog
|
||||||
|
import info.nightscout.androidaps.dialogs.TreatmentDialog
|
||||||
|
import info.nightscout.androidaps.dialogs.WizardDialog
|
||||||
|
import info.nightscout.androidaps.events.*
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||||
|
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||||
|
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.source.XdripPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.queue.CommandQueue
|
||||||
|
import info.nightscout.androidaps.utils.*
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import kotlinx.android.synthetic.main.careportal_stats_fragment.*
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.*
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_activeprofile
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_apsmode
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_arrow
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_basebasal
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_bg
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_bggraph
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_carbsbutton
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_chartMenuButton
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_cob
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_extendedbolus
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_insulinbutton
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_iob
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_iobcalculationprogess
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_iobgraph
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_looplayout
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_notifications
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_pumpstatus
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_pumpstatuslayout
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_quickwizardbutton
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_sensitivity
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_temptarget
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_treatmentbutton
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment.overview_wizardbutton
|
||||||
|
import kotlinx.android.synthetic.main.overview_fragment_nsclient_tablet.*
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.ScheduledFuture
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickListener {
|
||||||
|
@Inject lateinit var injector: HasAndroidInjector
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
|
@Inject lateinit var statusLightHandler: StatusLightHandler
|
||||||
|
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||||
|
@Inject lateinit var loopPlugin: LoopPlugin
|
||||||
|
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
|
||||||
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
|
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||||
|
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
||||||
|
@Inject lateinit var xdripPlugin: XdripPlugin
|
||||||
|
@Inject lateinit var notificationStore: NotificationStore
|
||||||
|
@Inject lateinit var actionStringHandler: ActionStringHandler
|
||||||
|
@Inject lateinit var quickWizard: QuickWizard
|
||||||
|
@Inject lateinit var buildHelper: BuildHelper
|
||||||
|
@Inject lateinit var commandQueue: CommandQueue
|
||||||
|
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||||
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
|
@Inject lateinit var overviewMenus: OverviewMenus
|
||||||
|
|
||||||
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
private var smallWidth = false
|
||||||
|
private var smallHeight = false
|
||||||
|
private lateinit var dm: DisplayMetrics
|
||||||
|
private var rangeToDisplay = 6 // for graph
|
||||||
|
private var loopHandler = Handler()
|
||||||
|
private var refreshLoop: Runnable? = null
|
||||||
|
|
||||||
|
private val worker = Executors.newSingleThreadScheduledExecutor()
|
||||||
|
private var scheduledUpdate: ScheduledFuture<*>? = null
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?): View? {
|
||||||
|
|
||||||
|
//check screen width
|
||||||
|
dm = DisplayMetrics()
|
||||||
|
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
||||||
|
|
||||||
|
val screenWidth = dm.widthPixels
|
||||||
|
val screenHeight = dm.heightPixels
|
||||||
|
smallWidth = screenWidth <= Constants.SMALL_WIDTH
|
||||||
|
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
|
||||||
|
val landscape = screenHeight < screenWidth
|
||||||
|
|
||||||
|
return when {
|
||||||
|
resourceHelper.gb(R.bool.isTablet) && Config.NSCLIENT ->
|
||||||
|
inflater.inflate(R.layout.overview_fragment_nsclient_tablet, container, false)
|
||||||
|
|
||||||
|
Config.NSCLIENT ->
|
||||||
|
inflater.inflate(R.layout.overview_fragment_nsclient, container, false)
|
||||||
|
|
||||||
|
smallHeight || landscape ->
|
||||||
|
inflater.inflate(R.layout.overview_fragment_landscape, container, false)
|
||||||
|
|
||||||
|
else ->
|
||||||
|
inflater.inflate(R.layout.overview_fragment, container, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
if (smallWidth) overview_arrow?.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 35f)
|
||||||
|
overview_pumpstatus?.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder))
|
||||||
|
|
||||||
|
overview_notifications?.setHasFixedSize(false)
|
||||||
|
overview_notifications?.layoutManager = LinearLayoutManager(view.context)
|
||||||
|
val axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
|
||||||
|
overview_bggraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
|
||||||
|
overview_bggraph?.gridLabelRenderer?.reloadStyles()
|
||||||
|
overview_iobgraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
|
||||||
|
overview_iobgraph?.gridLabelRenderer?.reloadStyles()
|
||||||
|
overview_iobgraph?.gridLabelRenderer?.isHorizontalLabelsVisible = false
|
||||||
|
overview_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||||
|
overview_iobgraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||||
|
overview_iobgraph?.gridLabelRenderer?.numVerticalLabels = 3
|
||||||
|
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
|
||||||
|
|
||||||
|
overview_bggraph?.setOnLongClickListener {
|
||||||
|
rangeToDisplay += 6
|
||||||
|
rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay
|
||||||
|
sp.putInt(R.string.key_rangetodisplay, rangeToDisplay)
|
||||||
|
updateGUI("rangeChange")
|
||||||
|
sp.putBoolean(R.string.key_objectiveusescale, true)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
overviewMenus.setupChartMenu(overview_chartMenuButton)
|
||||||
|
|
||||||
|
overview_accepttempbutton?.setOnClickListener(this)
|
||||||
|
overview_treatmentbutton?.setOnClickListener(this)
|
||||||
|
overview_wizardbutton?.setOnClickListener(this)
|
||||||
|
overview_calibrationbutton?.setOnClickListener(this)
|
||||||
|
overview_cgmbutton?.setOnClickListener(this)
|
||||||
|
overview_insulinbutton?.setOnClickListener(this)
|
||||||
|
overview_carbsbutton?.setOnClickListener(this)
|
||||||
|
overview_quickwizardbutton?.setOnClickListener(this)
|
||||||
|
overview_quickwizardbutton?.setOnLongClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
disposable.clear()
|
||||||
|
loopHandler.removeCallbacksAndMessages(null)
|
||||||
|
overview_apsmode?.let { unregisterForContextMenu(it) }
|
||||||
|
overview_activeprofile?.let { unregisterForContextMenu(it) }
|
||||||
|
overview_temptarget?.let { unregisterForContextMenu(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventRefreshOverview::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI(it.from) }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventExtendedBolusChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventExtendedBolusChange") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventTempBasalChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventTempBasalChange") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventTreatmentChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventTreatmentChange") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventTempTargetChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventTempTargetChange") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventAcceptOpenLoopChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventCareportalEventChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventInitializationChanged::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventInitializationChanged") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventAutosensCalculationFinished") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventProfileNeedsUpdate::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventProfileNeedsUpdate") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventPreferenceChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventPreferenceChange") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventNewOpenLoopNotification::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventPumpStatusChanged::class.java)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ updatePumpStatus(it) }) { fabricPrivacy.logException(it) })
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventIobCalculationProgress::class.java)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ overview_iobcalculationprogess?.text = it.progress }) { fabricPrivacy.logException(it) })
|
||||||
|
|
||||||
|
refreshLoop = Runnable {
|
||||||
|
scheduleUpdateGUI("refreshLoop")
|
||||||
|
loopHandler.postDelayed(refreshLoop, 60 * 1000L)
|
||||||
|
}
|
||||||
|
loopHandler.postDelayed(refreshLoop, 60 * 1000L)
|
||||||
|
|
||||||
|
overview_apsmode?.let { registerForContextMenu(overview_apsmode) }
|
||||||
|
overview_activeprofile?.let { registerForContextMenu(it) }
|
||||||
|
overview_temptarget?.let { registerForContextMenu(it) }
|
||||||
|
updateGUI("onResume")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo?) {
|
||||||
|
super.onCreateContextMenu(menu, v, menuInfo)
|
||||||
|
overviewMenus.createContextMenu(menu, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onContextItemSelected(item: MenuItem): Boolean {
|
||||||
|
val manager = fragmentManager
|
||||||
|
return if (manager != null && overviewMenus.onContextItemSelected(item, manager)) true else super.onContextItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
val manager = fragmentManager ?: return
|
||||||
|
// try to fix https://fabric.io/nightscout3/android/apps/info.nightscout.androidaps/issues/5aca7a1536c7b23527eb4be7?time=last-seven-days
|
||||||
|
// https://stackoverflow.com/questions/14860239/checking-if-state-is-saved-before-committing-a-fragmenttransaction
|
||||||
|
if (manager.isStateSaved) return
|
||||||
|
activity?.let { activity ->
|
||||||
|
when (v.id) {
|
||||||
|
R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { TreatmentDialog().show(manager, "Overview") })
|
||||||
|
R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { WizardDialog().show(manager, "Overview") })
|
||||||
|
R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { InsulinDialog().show(manager, "Overview") })
|
||||||
|
R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { onClickQuickWizard() })
|
||||||
|
R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { CarbsDialog().show(manager, "Overview") })
|
||||||
|
|
||||||
|
R.id.overview_pumpstatus -> {
|
||||||
|
if (activePlugin.activePump.isSuspended || !activePlugin.activePump.isInitialized) commandQueue.readStatus("RefreshClicked", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.overview_cgmbutton -> {
|
||||||
|
if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
|
||||||
|
openCgmApp("com.eveningoutpost.dexdrip")
|
||||||
|
else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
|
||||||
|
dexcomPlugin.findDexcomPackageName()?.let {
|
||||||
|
openCgmApp(it)
|
||||||
|
}
|
||||||
|
?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.overview_calibrationbutton -> {
|
||||||
|
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) {
|
||||||
|
CalibrationDialog().show(manager, "CalibrationDialog")
|
||||||
|
} else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
|
||||||
|
try {
|
||||||
|
dexcomPlugin.findDexcomPackageName()?.let {
|
||||||
|
startActivity(Intent("com.dexcom.cgm.activities.MeterEntryActivity").setPackage(it))
|
||||||
|
}
|
||||||
|
?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed))
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.g5appnotdetected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.overview_accepttempbutton -> {
|
||||||
|
profileFunction.getProfile() ?: return
|
||||||
|
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||||
|
val lastRun = loopPlugin.lastRun
|
||||||
|
loopPlugin.invoke("Accept temp button", false)
|
||||||
|
if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed.isChangeRequested) {
|
||||||
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.pump_tempbasal_label), lastRun.constraintsProcessed.toSpanned(), Runnable {
|
||||||
|
aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL")
|
||||||
|
overview_accepttempbutton?.visibility = View.GONE
|
||||||
|
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
||||||
|
actionStringHandler.handleInitiate("cancelChangeRequest")
|
||||||
|
loopPlugin.acceptChangeRequest()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openCgmApp(packageName: String) {
|
||||||
|
context?.let {
|
||||||
|
val packageManager = it.packageManager
|
||||||
|
try {
|
||||||
|
val intent = packageManager.getLaunchIntentForPackage(packageName)
|
||||||
|
?: throw ActivityNotFoundException()
|
||||||
|
intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
it.startActivity(intent)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
OKDialog.show(it, "", resourceHelper.gs(R.string.error_starting_cgm))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLongClick(v: View): Boolean {
|
||||||
|
when (v.id) {
|
||||||
|
R.id.overview_quickwizardbutton -> {
|
||||||
|
startActivity(Intent(v.context, QuickWizardListActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onClickQuickWizard() {
|
||||||
|
val actualBg = iobCobCalculatorPlugin.actualBg()
|
||||||
|
val profile = profileFunction.getProfile()
|
||||||
|
val profileName = profileFunction.getProfileName()
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val quickWizardEntry = quickWizard.getActive()
|
||||||
|
if (quickWizardEntry != null && actualBg != null && profile != null) {
|
||||||
|
overview_quickwizardbutton?.visibility = View.VISIBLE
|
||||||
|
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
|
||||||
|
if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) {
|
||||||
|
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
|
||||||
|
activity?.let {
|
||||||
|
if (abs(wizard.insulinAfterConstraints - wizard.calculatedTotalInsulin) >= pump.pumpDescription.pumpType.determineCorrectBolusStepSize(wizard.insulinAfterConstraints) || carbsAfterConstraints != quickWizardEntry.carbs()) {
|
||||||
|
OKDialog.show(it, resourceHelper.gs(R.string.treatmentdeliveryerror), resourceHelper.gs(R.string.constraints_violation) + "\n" + resourceHelper.gs(R.string.changeyourinput))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wizard.confirmAndExecute(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePumpStatus(event: EventPumpStatusChanged) {
|
||||||
|
val status = event.getStatus(resourceHelper)
|
||||||
|
if (status != "") {
|
||||||
|
overview_pumpstatus?.text = status
|
||||||
|
overview_pumpstatuslayout?.visibility = View.VISIBLE
|
||||||
|
overview_looplayout?.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
overview_pumpstatuslayout?.visibility = View.GONE
|
||||||
|
overview_looplayout?.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun processButtonsVisibility() {
|
||||||
|
val lastBG = iobCobCalculatorPlugin.lastBg()
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val profile = profileFunction.getProfile()
|
||||||
|
val profileName = profileFunction.getProfileName()
|
||||||
|
val actualBG = iobCobCalculatorPlugin.actualBg()
|
||||||
|
|
||||||
|
// QuickWizard button
|
||||||
|
val quickWizardEntry = quickWizard.getActive()
|
||||||
|
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized && !pump.isSuspended) {
|
||||||
|
overview_quickwizardbutton?.visibility = View.VISIBLE
|
||||||
|
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false)
|
||||||
|
overview_quickwizardbutton?.text = quickWizardEntry.buttonText() + "\n" + resourceHelper.gs(R.string.format_carbs, quickWizardEntry.carbs()) +
|
||||||
|
" " + resourceHelper.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin)
|
||||||
|
if (wizard.calculatedTotalInsulin <= 0) overview_quickwizardbutton?.visibility = View.GONE
|
||||||
|
} else overview_quickwizardbutton?.visibility = View.GONE
|
||||||
|
|
||||||
|
// **** Temp button ****
|
||||||
|
val lastRun = loopPlugin.lastRun
|
||||||
|
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||||
|
|
||||||
|
val showAcceptButton = !closedLoopEnabled.value() && // Open mode needed
|
||||||
|
lastRun != null &&
|
||||||
|
(lastRun.lastOpenModeAccept == 0L || lastRun.lastOpenModeAccept < lastRun.lastAPSRun) &&// never accepted or before last result
|
||||||
|
lastRun.constraintsProcessed.isChangeRequested // change is requested
|
||||||
|
|
||||||
|
if (showAcceptButton && pump.isInitialized && !pump.isSuspended && loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||||
|
overview_accepttempbutton?.visibility = View.VISIBLE
|
||||||
|
overview_accepttempbutton?.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
|
||||||
|
} else {
|
||||||
|
overview_accepttempbutton?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// **** Various treatment buttons ****
|
||||||
|
overview_carbsbutton?.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized && !pump.isSuspended) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
|
||||||
|
overview_treatmentbutton?.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
|
||||||
|
overview_wizardbutton?.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
|
||||||
|
overview_insulinbutton?.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
|
||||||
|
|
||||||
|
// **** Calibration & CGM buttons ****
|
||||||
|
val xDripIsBgSource = xdripPlugin.isEnabled(PluginType.BGSOURCE)
|
||||||
|
val dexcomIsSource = dexcomPlugin.isEnabled(PluginType.BGSOURCE)
|
||||||
|
overview_calibrationbutton?.visibility = ((xDripIsBgSource || dexcomIsSource) && actualBG != null && sp.getBoolean(R.string.key_show_calibration_button, true)).toVisibility()
|
||||||
|
overview_cgmbutton?.visibility = (sp.getBoolean(R.string.key_show_cgm_button, false) && (xDripIsBgSource || dexcomIsSource)).toVisibility()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun scheduleUpdateGUI(from: String) {
|
||||||
|
class UpdateRunnable : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
activity?.runOnUiThread {
|
||||||
|
updateGUI(from)
|
||||||
|
scheduledUpdate = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prepare task for execution in 500 milliseconds
|
||||||
|
// cancel waiting task to prevent multiple updates
|
||||||
|
scheduledUpdate?.cancel(false)
|
||||||
|
val task: Runnable = UpdateRunnable()
|
||||||
|
scheduledUpdate = worker.schedule(task, 500, TimeUnit.MILLISECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
fun updateGUI(from: String) {
|
||||||
|
aapsLogger.debug("UpdateGUI from $from")
|
||||||
|
|
||||||
|
overview_time?.text = DateUtil.timeString(Date())
|
||||||
|
|
||||||
|
if (!profileFunction.isProfileValid("Overview")) {
|
||||||
|
overview_pumpstatus?.setText(R.string.noprofileset)
|
||||||
|
overview_pumpstatuslayout?.visibility = View.VISIBLE
|
||||||
|
overview_looplayout?.visibility = View.GONE
|
||||||
|
return
|
||||||
|
}
|
||||||
|
notificationStore.updateNotifications(overview_notifications)
|
||||||
|
overview_pumpstatuslayout?.visibility = View.GONE
|
||||||
|
overview_looplayout?.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
val profile = profileFunction.getProfile() ?: return
|
||||||
|
val actualBG = iobCobCalculatorPlugin.actualBg()
|
||||||
|
val lastBG = iobCobCalculatorPlugin.lastBg()
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val units = profileFunction.getUnits()
|
||||||
|
val lowLine = defaultValueHelper.determineLowLine()
|
||||||
|
val highLine = defaultValueHelper.determineHighLine()
|
||||||
|
|
||||||
|
//Start with updating the BG as it is unaffected by loop.
|
||||||
|
// **** BG value ****
|
||||||
|
if (lastBG != null) {
|
||||||
|
val color = when {
|
||||||
|
lastBG.valueToUnits(units) < lowLine -> resourceHelper.gc(R.color.low)
|
||||||
|
lastBG.valueToUnits(units) > highLine -> resourceHelper.gc(R.color.high)
|
||||||
|
else -> resourceHelper.gc(R.color.inrange)
|
||||||
|
}
|
||||||
|
|
||||||
|
overview_bg?.text = lastBG.valueToUnitsToString(units)
|
||||||
|
overview_bg?.setTextColor(color)
|
||||||
|
overview_arrow?.text = lastBG.directionToSymbol()
|
||||||
|
overview_arrow?.setTextColor(color)
|
||||||
|
|
||||||
|
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
|
||||||
|
if (glucoseStatus != null) {
|
||||||
|
overview_delta?.text = "Δ ${Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)} $units"
|
||||||
|
overview_deltashort?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||||
|
overview_avgdelta?.text = "øΔ15m: ${Profile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)}\nøΔ40m: ${Profile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)}"
|
||||||
|
} else {
|
||||||
|
overview_delta?.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
||||||
|
overview_deltashort?.text = "---"
|
||||||
|
overview_avgdelta?.text = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// strike through if BG is old
|
||||||
|
overview_bg?.let { overview_bg ->
|
||||||
|
var flag = overview_bg.paintFlags
|
||||||
|
flag = if (actualBG == null) {
|
||||||
|
flag or Paint.STRIKE_THRU_TEXT_FLAG
|
||||||
|
} else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||||
|
overview_bg.paintFlags = flag
|
||||||
|
}
|
||||||
|
overview_timeago?.text = DateUtil.minAgo(resourceHelper, lastBG.date)
|
||||||
|
overview_timeagoshort?.text = "(" + DateUtil.minAgoShort(lastBG.date) + ")"
|
||||||
|
|
||||||
|
}
|
||||||
|
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||||
|
|
||||||
|
// open loop mode
|
||||||
|
if (Config.APS && pump.pumpDescription.isTempBasalCapable) {
|
||||||
|
overview_apsmode?.visibility = View.VISIBLE
|
||||||
|
when {
|
||||||
|
loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuperBolus -> {
|
||||||
|
overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopsuperbolusfor), loopPlugin.minutesToEndOfSuspend())
|
||||||
|
overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||||
|
overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
|
}
|
||||||
|
|
||||||
|
loopPlugin.isDisconnected -> {
|
||||||
|
overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopdisconnectedfor), loopPlugin.minutesToEndOfSuspend())
|
||||||
|
overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical))
|
||||||
|
overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical))
|
||||||
|
}
|
||||||
|
|
||||||
|
loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuspended -> {
|
||||||
|
overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
|
||||||
|
overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||||
|
overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
|
}
|
||||||
|
|
||||||
|
pump.isSuspended -> {
|
||||||
|
overview_apsmode?.text = resourceHelper.gs(R.string.pumpsuspended)
|
||||||
|
overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||||
|
overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
|
}
|
||||||
|
|
||||||
|
loopPlugin.isEnabled(PluginType.LOOP) -> {
|
||||||
|
overview_apsmode?.text = if (closedLoopEnabled.value()) resourceHelper.gs(R.string.closedloop) else resourceHelper.gs(R.string.openloop)
|
||||||
|
overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
||||||
|
overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
overview_apsmode?.text = resourceHelper.gs(R.string.disabledloop)
|
||||||
|
overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical))
|
||||||
|
overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
overview_apsmode?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// temp target
|
||||||
|
val tempTarget = treatmentsPlugin.tempTargetFromHistory
|
||||||
|
if (tempTarget != null) {
|
||||||
|
overview_temptarget?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
|
overview_temptarget?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||||
|
overview_temptarget?.text = Profile.toTargetRangeString(tempTarget.low, tempTarget.high, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.end(), resourceHelper)
|
||||||
|
} else {
|
||||||
|
overview_temptarget?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
||||||
|
overview_temptarget?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
||||||
|
overview_temptarget?.text = Profile.toTargetRangeString(profile.targetLowMgdl, profile.targetHighMgdl, Constants.MGDL, units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basal, TBR
|
||||||
|
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
|
||||||
|
overview_basebasal?.text = activeTemp?.let { if (resourceHelper.shortTextMode()) "T: " + activeTemp.toStringVeryShort() else activeTemp.toStringFull() }
|
||||||
|
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)
|
||||||
|
overview_basebasal?.setOnClickListener {
|
||||||
|
var fullText = "${resourceHelper.gs(R.string.pump_basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}"
|
||||||
|
if (activeTemp != null)
|
||||||
|
fullText += "\n" + resourceHelper.gs(R.string.pump_tempbasal_label) + ": " + activeTemp.toStringFull()
|
||||||
|
activity?.let {
|
||||||
|
OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overview_basebasal?.setTextColor(activeTemp?.let { resourceHelper.gc(R.color.basal) }
|
||||||
|
?: resourceHelper.gc(R.color.defaulttextcolor))
|
||||||
|
|
||||||
|
// Extended bolus
|
||||||
|
val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())
|
||||||
|
overview_extendedbolus?.text = if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses) {
|
||||||
|
if (resourceHelper.shortTextMode()) resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate())
|
||||||
|
else extendedBolus.toStringMedium()
|
||||||
|
} else ""
|
||||||
|
overview_extendedbolus?.setOnClickListener {
|
||||||
|
if (extendedBolus != null) activity?.let {
|
||||||
|
OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
overview_activeprofile?.text = profileFunction.getProfileNameWithDuration()
|
||||||
|
if (profile.percentage != 100 || profile.timeshift != 0) {
|
||||||
|
overview_activeprofile?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||||
|
overview_activeprofile?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
|
} else {
|
||||||
|
overview_activeprofile?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
||||||
|
overview_activeprofile?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
||||||
|
}
|
||||||
|
|
||||||
|
processButtonsVisibility()
|
||||||
|
|
||||||
|
// iob
|
||||||
|
treatmentsPlugin.updateTotalIOBTreatments()
|
||||||
|
treatmentsPlugin.updateTotalIOBTempBasals()
|
||||||
|
val bolusIob = treatmentsPlugin.lastCalculationTreatments.round()
|
||||||
|
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round()
|
||||||
|
overview_iob?.text = when {
|
||||||
|
resourceHelper.shortTextMode() -> {
|
||||||
|
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gb(R.bool.isTablet) -> {
|
||||||
|
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + " (" +
|
||||||
|
resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) +
|
||||||
|
resourceHelper.gs(R.string.basal) + ": " + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + " (" +
|
||||||
|
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "/" +
|
||||||
|
resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overview_iob?.setOnClickListener {
|
||||||
|
activity?.let {
|
||||||
|
OKDialog.show(it, resourceHelper.gs(R.string.iob),
|
||||||
|
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" +
|
||||||
|
resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "\n" +
|
||||||
|
resourceHelper.gs(R.string.basal) + ": " + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NSClient mode
|
||||||
|
statusLightHandler.updateAge(careportal_sensorage, careportal_insulinage, careportal_canulaage, careportal_pbage)
|
||||||
|
// Mode modes
|
||||||
|
if (sp.getBoolean(R.string.key_show_statuslights, false)) {
|
||||||
|
if (sp.getBoolean(R.string.key_show_statuslights_extended, false))
|
||||||
|
statusLightHandler.extendedStatusLight(overview_canulaage, overview_insulinage, overview_reservoirlevel, overview_sensorage, overview_batterylevel)
|
||||||
|
else
|
||||||
|
statusLightHandler.statusLight(overview_canulaage, overview_insulinage, overview_reservoirlevel, overview_sensorage, overview_batterylevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cob
|
||||||
|
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
|
||||||
|
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Overview COB")
|
||||||
|
if (cobInfo.displayCob != null) {
|
||||||
|
cobText = DecimalFormatter.to0Decimal(cobInfo.displayCob)
|
||||||
|
if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")"
|
||||||
|
}
|
||||||
|
overview_cob?.text = cobText
|
||||||
|
|
||||||
|
val lastRun = loopPlugin.lastRun
|
||||||
|
val predictionsAvailable = if (Config.APS) lastRun?.request?.hasPredictions == true else Config.NSCLIENT
|
||||||
|
|
||||||
|
// pump status from ns
|
||||||
|
overview_pump?.text = nsDeviceStatus.pumpStatus
|
||||||
|
overview_pump?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.pump), nsDeviceStatus.extendedPumpStatus) } }
|
||||||
|
|
||||||
|
// OpenAPS status from ns
|
||||||
|
overview_openaps?.text = nsDeviceStatus.openApsStatus
|
||||||
|
overview_openaps?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.openaps), nsDeviceStatus.extendedOpenApsStatus) } }
|
||||||
|
|
||||||
|
// Uploader status from ns
|
||||||
|
overview_uploader?.text = nsDeviceStatus.uploaderStatusSpanned
|
||||||
|
overview_uploader?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } }
|
||||||
|
|
||||||
|
// Sensitivity
|
||||||
|
iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData ->
|
||||||
|
overview_sensitivity?.text = String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ****** GRAPH *******
|
||||||
|
Thread(Runnable {
|
||||||
|
|
||||||
|
// align to hours
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
calendar.timeInMillis = System.currentTimeMillis()
|
||||||
|
calendar[Calendar.MILLISECOND] = 0
|
||||||
|
calendar[Calendar.SECOND] = 0
|
||||||
|
calendar[Calendar.MINUTE] = 0
|
||||||
|
calendar.add(Calendar.HOUR, 1)
|
||||||
|
val hoursToFetch: Int
|
||||||
|
val toTime: Long
|
||||||
|
val fromTime: Long
|
||||||
|
val endTime: Long
|
||||||
|
val apsResult = if (Config.APS) lastRun?.constraintsProcessed else NSDeviceStatus.getAPSResult(injector)
|
||||||
|
if (predictionsAvailable && apsResult != null && sp.getBoolean("showprediction", false)) {
|
||||||
|
var predHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt()
|
||||||
|
predHours = min(2, predHours)
|
||||||
|
predHours = max(0, predHours)
|
||||||
|
hoursToFetch = rangeToDisplay - predHours
|
||||||
|
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||||
|
fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs()
|
||||||
|
endTime = toTime + T.hours(predHours.toLong()).msecs()
|
||||||
|
} else {
|
||||||
|
hoursToFetch = rangeToDisplay
|
||||||
|
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||||
|
fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs()
|
||||||
|
endTime = toTime
|
||||||
|
}
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
|
||||||
|
// ------------------ 1st graph
|
||||||
|
val graphData = GraphData(injector, overview_bggraph, iobCobCalculatorPlugin)
|
||||||
|
|
||||||
|
// **** In range Area ****
|
||||||
|
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine)
|
||||||
|
|
||||||
|
// **** BG ****
|
||||||
|
if (predictionsAvailable && sp.getBoolean("showprediction", false)) graphData.addBgReadings(fromTime, toTime, lowLine, highLine,
|
||||||
|
apsResult?.predictions) else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
|
||||||
|
|
||||||
|
// set manual x bounds to have nice steps
|
||||||
|
graphData.formatAxis(fromTime, endTime)
|
||||||
|
|
||||||
|
// Treatments
|
||||||
|
graphData.addTreatments(fromTime, endTime)
|
||||||
|
if (sp.getBoolean("showactivityprimary", true))
|
||||||
|
graphData.addActivity(fromTime, endTime, false, 0.8)
|
||||||
|
|
||||||
|
// add basal data
|
||||||
|
if (pump.pumpDescription.isTempBasalCapable && sp.getBoolean("showbasals", true))
|
||||||
|
graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2)
|
||||||
|
|
||||||
|
// add target line
|
||||||
|
graphData.addTargetLine(fromTime, toTime, profile, loopPlugin.lastRun)
|
||||||
|
|
||||||
|
// **** NOW line ****
|
||||||
|
graphData.addNowLine(now)
|
||||||
|
|
||||||
|
// ------------------ 2nd graph
|
||||||
|
val secondGraphData = GraphData(injector, overview_iobgraph, iobCobCalculatorPlugin)
|
||||||
|
var useIobForScale = false
|
||||||
|
var useCobForScale = false
|
||||||
|
var useDevForScale = false
|
||||||
|
var useRatioForScale = false
|
||||||
|
var useDSForScale = false
|
||||||
|
var useIAForScale = false
|
||||||
|
// finally enforce drawing of graphs
|
||||||
|
when {
|
||||||
|
sp.getBoolean("showiob", true) ->
|
||||||
|
useIobForScale = true
|
||||||
|
sp.getBoolean("showcob", true) ->
|
||||||
|
useCobForScale = true
|
||||||
|
sp.getBoolean("showdeviations", false) ->
|
||||||
|
useDevForScale = true
|
||||||
|
sp.getBoolean("showratios", false) ->
|
||||||
|
useRatioForScale = true
|
||||||
|
sp.getBoolean("showactivitysecondary", false) ->
|
||||||
|
useIAForScale = true
|
||||||
|
sp.getBoolean("showdevslope", false) ->
|
||||||
|
useDSForScale = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sp.getBoolean("showiob", true)) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, sp.getBoolean("showprediction", false))
|
||||||
|
if (sp.getBoolean("showcob", true)) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
||||||
|
if (sp.getBoolean("showdeviations", false)) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0)
|
||||||
|
if (sp.getBoolean("showratios", false)) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
|
||||||
|
if (sp.getBoolean("showactivitysecondary", true)) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8)
|
||||||
|
if (sp.getBoolean("showdevslope", false) && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
|
||||||
|
|
||||||
|
// **** NOW line ****
|
||||||
|
// set manual x bounds to have nice steps
|
||||||
|
secondGraphData.formatAxis(fromTime, endTime)
|
||||||
|
secondGraphData.addNowLine(now)
|
||||||
|
|
||||||
|
// do GUI update
|
||||||
|
val activity = activity
|
||||||
|
activity?.runOnUiThread {
|
||||||
|
if (sp.getBoolean("showiob", true)
|
||||||
|
|| sp.getBoolean("showcob", true)
|
||||||
|
|| sp.getBoolean("showdeviations", false)
|
||||||
|
|| sp.getBoolean("showratios", false)
|
||||||
|
|| sp.getBoolean("showactivitysecondary", false)
|
||||||
|
|| sp.getBoolean("showdevslope", false)) {
|
||||||
|
overview_iobgraph?.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
overview_iobgraph?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
// finally enforce drawing of graphs
|
||||||
|
graphData.performUpdate()
|
||||||
|
secondGraphData.performUpdate()
|
||||||
|
}
|
||||||
|
}).start()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,436 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.overview
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import android.view.ContextMenu
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageButton
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.db.Source
|
||||||
|
import info.nightscout.androidaps.db.TempTarget
|
||||||
|
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
|
||||||
|
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
||||||
|
import info.nightscout.androidaps.dialogs.TempTargetDialog
|
||||||
|
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
|
import info.nightscout.androidaps.interfaces.PumpDescription
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class OverviewMenus @Inject constructor(
|
||||||
|
private val aapsLogger: AAPSLogger,
|
||||||
|
private val resourceHelper: ResourceHelper,
|
||||||
|
private val sp: SP,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
|
private val context: Context,
|
||||||
|
private val buildHelper: BuildHelper,
|
||||||
|
private val defaultValueHelper: DefaultValueHelper,
|
||||||
|
private val activePlugin: ActivePluginProvider,
|
||||||
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val commandQueue: CommandQueueProvider,
|
||||||
|
private val configBuilderPlugin: ConfigBuilderPlugin,
|
||||||
|
private val loopPlugin: LoopPlugin
|
||||||
|
) {
|
||||||
|
|
||||||
|
enum class CharType {
|
||||||
|
PRE, BAS, IOB, COB, DEV, SEN, ACTPRIM, ACTSEC, DEVSLOPE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setupChartMenu(chartButton: ImageButton) {
|
||||||
|
chartButton.setOnClickListener { v: View ->
|
||||||
|
val predictionsAvailable: Boolean = when {
|
||||||
|
Config.APS -> loopPlugin.lastRun?.request?.hasPredictions ?: false
|
||||||
|
Config.NSCLIENT -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
//var item: MenuItem
|
||||||
|
val dividerItem: MenuItem
|
||||||
|
//var title: CharSequence
|
||||||
|
var titleMaxChars = 0
|
||||||
|
//var s: SpannableString
|
||||||
|
val popup = PopupMenu(v.context, v)
|
||||||
|
if (predictionsAvailable) {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.PRE.ordinal, Menu.NONE, "Predictions")
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.prediction)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showprediction", true)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.BAS.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_basals))
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.basal)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showbasals", true)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.ACTPRIM.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity))
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.activity)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showactivityprimary", true)
|
||||||
|
dividerItem = popup.menu.add("")
|
||||||
|
dividerItem.isEnabled = false
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.IOB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_iob))
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.iob)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showiob", true)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.COB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_cob))
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.cob)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showcob", true)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.DEV.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_deviations))
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.deviations)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showdeviations", false)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.SEN.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_sensitivity))
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.ratio)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showratios", false)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.ACTSEC.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity))
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.activity)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showactivitysecondary", true)
|
||||||
|
}
|
||||||
|
if (buildHelper.isDev()) {
|
||||||
|
val item = popup.menu.add(Menu.NONE, CharType.DEVSLOPE.ordinal, Menu.NONE, "Deviation slope")
|
||||||
|
val title = item.title
|
||||||
|
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||||
|
val s = SpannableString(title)
|
||||||
|
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.devslopepos)), 0, s.length, 0)
|
||||||
|
item.title = s
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = sp.getBoolean("showdevslope", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fairly good estimate for required divider text size...
|
||||||
|
dividerItem.title = String(CharArray(titleMaxChars + 10)).replace("\u0000", "_")
|
||||||
|
popup.setOnMenuItemClickListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
CharType.PRE.ordinal -> sp.putBoolean("showprediction", !it.isChecked)
|
||||||
|
CharType.BAS.ordinal -> sp.putBoolean("showbasals", !it.isChecked)
|
||||||
|
CharType.IOB.ordinal -> sp.putBoolean("showiob", !it.isChecked)
|
||||||
|
CharType.COB.ordinal -> sp.putBoolean("showcob", !it.isChecked)
|
||||||
|
CharType.DEV.ordinal -> sp.putBoolean("showdeviations", !it.isChecked)
|
||||||
|
CharType.SEN.ordinal -> sp.putBoolean("showratios", !it.isChecked)
|
||||||
|
CharType.ACTPRIM.ordinal -> sp.putBoolean("showactivityprimary", !it.isChecked)
|
||||||
|
CharType.ACTSEC.ordinal -> sp.putBoolean("showactivitysecondary", !it.isChecked)
|
||||||
|
CharType.DEVSLOPE.ordinal -> sp.putBoolean("showdevslope", !it.isChecked)
|
||||||
|
}
|
||||||
|
rxBus.send(EventRefreshOverview("OnMenuItemClickListener"))
|
||||||
|
return@setOnMenuItemClickListener true
|
||||||
|
}
|
||||||
|
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp)
|
||||||
|
popup.setOnDismissListener { chartButton.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp) }
|
||||||
|
popup.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createContextMenu(menu: ContextMenu, v: View) {
|
||||||
|
when (v.id) {
|
||||||
|
R.id.overview_apsmode -> {
|
||||||
|
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
|
||||||
|
if (!profileFunction.isProfileValid("ContextMenuCreation")) return
|
||||||
|
menu.setHeaderTitle(resourceHelper.gs(R.string.loop))
|
||||||
|
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||||
|
menu.add(resourceHelper.gs(R.string.disableloop))
|
||||||
|
if (!loopPlugin.isSuspended) {
|
||||||
|
menu.add(resourceHelper.gs(R.string.suspendloopfor1h))
|
||||||
|
menu.add(resourceHelper.gs(R.string.suspendloopfor2h))
|
||||||
|
menu.add(resourceHelper.gs(R.string.suspendloopfor3h))
|
||||||
|
menu.add(resourceHelper.gs(R.string.suspendloopfor10h))
|
||||||
|
} else {
|
||||||
|
if (!loopPlugin.isDisconnected) {
|
||||||
|
menu.add(resourceHelper.gs(R.string.resume))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||||
|
menu.add(resourceHelper.gs(R.string.enableloop))
|
||||||
|
}
|
||||||
|
if (!loopPlugin.isDisconnected) {
|
||||||
|
showSuspendPump(menu, pumpDescription)
|
||||||
|
} else {
|
||||||
|
menu.add(resourceHelper.gs(R.string.reconnect))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.overview_activeprofile -> {
|
||||||
|
menu.setHeaderTitle(resourceHelper.gs(R.string.profile))
|
||||||
|
menu.add(resourceHelper.gs(R.string.danar_viewprofile))
|
||||||
|
if (activePlugin.activeProfileInterface.profile != null) {
|
||||||
|
menu.add(resourceHelper.gs(R.string.careportal_profileswitch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.overview_temptarget -> {
|
||||||
|
menu.setHeaderTitle(resourceHelper.gs(R.string.careportal_temporarytarget))
|
||||||
|
menu.add(resourceHelper.gs(R.string.custom))
|
||||||
|
menu.add(resourceHelper.gs(R.string.eatingsoon))
|
||||||
|
menu.add(resourceHelper.gs(R.string.activity))
|
||||||
|
menu.add(resourceHelper.gs(R.string.hypo))
|
||||||
|
if (activePlugin.activeTreatments.tempTargetFromHistory != null) {
|
||||||
|
menu.add(resourceHelper.gs(R.string.cancel))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showSuspendPump(menu: ContextMenu, pumpDescription: PumpDescription) {
|
||||||
|
if (pumpDescription.tempDurationStep15mAllowed) menu.add(resourceHelper.gs(R.string.disconnectpumpfor15m))
|
||||||
|
if (pumpDescription.tempDurationStep30mAllowed) menu.add(resourceHelper.gs(R.string.disconnectpumpfor30m))
|
||||||
|
menu.add(resourceHelper.gs(R.string.disconnectpumpfor1h))
|
||||||
|
menu.add(resourceHelper.gs(R.string.disconnectpumpfor2h))
|
||||||
|
menu.add(resourceHelper.gs(R.string.disconnectpumpfor3h))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onContextItemSelected(item: MenuItem, manager: FragmentManager): Boolean {
|
||||||
|
val profile = profileFunction.getProfile() ?: return true
|
||||||
|
when (item.title) {
|
||||||
|
resourceHelper.gs(R.string.disableloop) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: LOOP DISABLED")
|
||||||
|
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
||||||
|
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
|
||||||
|
configBuilderPlugin.storeSettings("DisablingLoop")
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (!result.success) {
|
||||||
|
ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
loopPlugin.createOfflineEvent(24 * 60) // upload 24h, we don't know real duration
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.enableloop) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: LOOP ENABLED")
|
||||||
|
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
||||||
|
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
||||||
|
configBuilderPlugin.storeSettings("EnablingLoop")
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
loopPlugin.createOfflineEvent(0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.resume), resourceHelper.gs(R.string.reconnect) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: RESUME")
|
||||||
|
loopPlugin.suspendTo(0L)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (!result.success) {
|
||||||
|
val i = Intent(context, ErrorHelperActivity::class.java)
|
||||||
|
i.putExtra("soundid", R.raw.boluserror)
|
||||||
|
i.putExtra("status", result.comment)
|
||||||
|
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
||||||
|
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
context.startActivity(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
sp.putBoolean(R.string.key_objectiveusereconnect, true)
|
||||||
|
loopPlugin.createOfflineEvent(0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.suspendloopfor1h) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: SUSPEND 1h")
|
||||||
|
loopPlugin.suspendLoop(60)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.suspendloopfor2h) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: SUSPEND 2h")
|
||||||
|
loopPlugin.suspendLoop(120)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.suspendloopfor3h) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: SUSPEND 3h")
|
||||||
|
loopPlugin.suspendLoop(180)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.suspendloopfor10h) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: SUSPEND 10h")
|
||||||
|
loopPlugin.suspendLoop(600)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.disconnectpumpfor15m) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: DISCONNECT 15m")
|
||||||
|
loopPlugin.disconnectPump(15, profile)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.disconnectpumpfor30m) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: DISCONNECT 30m")
|
||||||
|
loopPlugin.disconnectPump(30, profile)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.disconnectpumpfor1h) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: DISCONNECT 1h")
|
||||||
|
loopPlugin.disconnectPump(60, profile)
|
||||||
|
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.disconnectpumpfor2h) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: DISCONNECT 2h")
|
||||||
|
loopPlugin.disconnectPump(120, profile)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.disconnectpumpfor3h) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: DISCONNECT 3h")
|
||||||
|
loopPlugin.disconnectPump(180, profile)
|
||||||
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.careportal_profileswitch) -> {
|
||||||
|
ProfileSwitchDialog().show(manager, "Overview")
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.danar_viewprofile) -> {
|
||||||
|
val args = Bundle()
|
||||||
|
args.putLong("time", DateUtil.now())
|
||||||
|
args.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal)
|
||||||
|
val pvd = ProfileViewerDialog()
|
||||||
|
pvd.arguments = args
|
||||||
|
pvd.show(manager, "ProfileViewDialog")
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.eatingsoon) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: TEMP TARGET EATING SOON")
|
||||||
|
val target = Profile.toMgdl(defaultValueHelper.determineEatingSoonTT(), profileFunction.getUnits())
|
||||||
|
val tempTarget = TempTarget()
|
||||||
|
.date(System.currentTimeMillis())
|
||||||
|
.duration(defaultValueHelper.determineEatingSoonTTDuration())
|
||||||
|
.reason(resourceHelper.gs(R.string.eatingsoon))
|
||||||
|
.source(Source.USER)
|
||||||
|
.low(target)
|
||||||
|
.high(target)
|
||||||
|
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.activity) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: TEMP TARGET ACTIVITY")
|
||||||
|
val target = Profile.toMgdl(defaultValueHelper.determineActivityTT(), profileFunction.getUnits())
|
||||||
|
val tempTarget = TempTarget()
|
||||||
|
.date(DateUtil.now())
|
||||||
|
.duration(defaultValueHelper.determineActivityTTDuration())
|
||||||
|
.reason(resourceHelper.gs(R.string.activity))
|
||||||
|
.source(Source.USER)
|
||||||
|
.low(target)
|
||||||
|
.high(target)
|
||||||
|
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.hypo) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: TEMP TARGET HYPO")
|
||||||
|
val target = Profile.toMgdl(defaultValueHelper.determineHypoTT(), profileFunction.getUnits())
|
||||||
|
val tempTarget = TempTarget()
|
||||||
|
.date(DateUtil.now())
|
||||||
|
.duration(defaultValueHelper.determineHypoTTDuration())
|
||||||
|
.reason(resourceHelper.gs(R.string.hypo))
|
||||||
|
.source(Source.USER)
|
||||||
|
.low(target)
|
||||||
|
.high(target)
|
||||||
|
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.custom) -> {
|
||||||
|
TempTargetDialog().show(manager, "Overview")
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHelper.gs(R.string.cancel) -> {
|
||||||
|
aapsLogger.debug("USER ENTRY: TEMP TARGET CANCEL")
|
||||||
|
val tempTarget = TempTarget()
|
||||||
|
.source(Source.USER)
|
||||||
|
.date(DateUtil.now())
|
||||||
|
.duration(0)
|
||||||
|
.low(0.0)
|
||||||
|
.high(0.0)
|
||||||
|
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -89,9 +89,9 @@ class StatusLightHandler @Inject constructor(
|
||||||
/**
|
/**
|
||||||
* applies the extended statusLight subview on the overview fragment
|
* applies the extended statusLight subview on the overview fragment
|
||||||
*/
|
*/
|
||||||
fun extendedStatusLight(cageView: TextView, iAgeView: TextView,
|
fun extendedStatusLight(cageView: TextView?, iAgeView: TextView?,
|
||||||
reservoirView: TextView, sageView: TextView,
|
reservoirView: TextView?, sageView: TextView?,
|
||||||
batteryView: TextView) {
|
batteryView: TextView?) {
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
handleAge("cage", CareportalEvent.SITECHANGE, cageView, "CAN ",
|
handleAge("cage", CareportalEvent.SITECHANGE, cageView, "CAN ",
|
||||||
48, 72)
|
48, 72)
|
||||||
|
@ -112,11 +112,11 @@ class StatusLightHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleAge(nsSettingPlugin: String, eventName: String, view: TextView, text: String,
|
private fun handleAge(nsSettingPlugin: String, eventName: String, view: TextView?, text: String,
|
||||||
defaultWarnThreshold: Int, defaultUrgentThreshold: Int) {
|
defaultWarnThreshold: Int, defaultUrgentThreshold: Int) {
|
||||||
val urgent = nsSettingsStatus.getExtendedWarnValue(nsSettingPlugin, "urgent", defaultUrgentThreshold.toDouble())
|
val urgent = nsSettingsStatus.getExtendedWarnValue(nsSettingPlugin, "urgent", defaultUrgentThreshold.toDouble())
|
||||||
val warn = nsSettingsStatus.getExtendedWarnValue(nsSettingPlugin, "warn", defaultWarnThreshold.toDouble())
|
val warn = nsSettingsStatus.getExtendedWarnValue(nsSettingPlugin, "warn", defaultWarnThreshold.toDouble())
|
||||||
handleAge(view, text, eventName, warn, urgent, true)
|
handleAge(view, text, eventName, warn, urgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLevel(criticalSetting: Int, criticalDefaultValue: Double,
|
private fun handleLevel(criticalSetting: Int, criticalDefaultValue: Double,
|
||||||
|
@ -132,14 +132,14 @@ class StatusLightHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleAge(age: TextView?, eventType: String, warnThreshold: Double, urgentThreshold: Double) =
|
private fun handleAge(age: TextView?, eventType: String, warnThreshold: Double, urgentThreshold: Double) =
|
||||||
handleAge(age, "", eventType, warnThreshold, urgentThreshold, OverviewFragment.shorttextmode)
|
handleAge(age, "", eventType, warnThreshold, urgentThreshold)
|
||||||
|
|
||||||
fun handleAge(age: TextView?, prefix: String, eventType: String, warnThreshold: Double, urgentThreshold: Double, useShortText: Boolean) {
|
fun handleAge(age: TextView?, prefix: String, eventType: String, warnThreshold: Double, urgentThreshold: Double) {
|
||||||
val notavailable = if (useShortText) "-" else resourceHelper.gs(R.string.notavailable)
|
val notavailable = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable)
|
||||||
val careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventType)
|
val careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventType)
|
||||||
if (careportalEvent != null) {
|
if (careportalEvent != null) {
|
||||||
age?.setTextColor(determineTextColor(careportalEvent, warnThreshold, urgentThreshold))
|
age?.setTextColor(determineTextColor(careportalEvent, warnThreshold, urgentThreshold))
|
||||||
age?.text = prefix + careportalEvent.age(useShortText)
|
age?.text = prefix + careportalEvent.age(resourceHelper.shortTextMode())
|
||||||
} else {
|
} else {
|
||||||
age?.text = notavailable
|
age?.text = notavailable
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ class GraphData(injector: HasAndroidInjector, private val graph: GraphView, priv
|
||||||
var maxBgValue = Double.MIN_VALUE
|
var maxBgValue = Double.MIN_VALUE
|
||||||
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
||||||
if (bgReadingsArray?.isEmpty() != false) {
|
if (bgReadingsArray?.isEmpty() != false) {
|
||||||
aapsLogger.debug(LTag.OVERVIEW, "No BG data.")
|
aapsLogger.debug("No BG data.")
|
||||||
maxY = 10.0
|
maxY = 10.0
|
||||||
minY = 0.0
|
minY = 0.0
|
||||||
return
|
return
|
||||||
|
|
|
@ -719,7 +719,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val detailedBolusInfo = DetailedBolusInfo()
|
val detailedBolusInfo = DetailedBolusInfo()
|
||||||
detailedBolusInfo.carbs = anInteger().toDouble()
|
detailedBolusInfo.carbs = anInteger().toDouble()
|
||||||
|
detailedBolusInfo.source = Source.USER
|
||||||
detailedBolusInfo.date = secondLong()
|
detailedBolusInfo.date = secondLong()
|
||||||
|
if (activePlugin.activePump.pumpDescription.storesCarbInfo) {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
@ -733,6 +735,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true)
|
||||||
|
var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger)
|
||||||
|
replyText += "\n" + activePlugin.activePump.shortStatus(true)
|
||||||
|
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package info.nightscout.androidaps.plugins.general.smsCommunicator.otp
|
package info.nightscout.androidaps.plugins.general.smsCommunicator.otp
|
||||||
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator
|
import com.eatthepath.otp.HmacOneTimePasswordGenerator
|
||||||
import com.google.common.io.BaseEncoding
|
import com.google.common.io.BaseEncoding
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
@ -23,7 +23,7 @@ class OneTimePassword @Inject constructor(
|
||||||
|
|
||||||
private var key: SecretKey? = null
|
private var key: SecretKey? = null
|
||||||
private var pin: String = ""
|
private var pin: String = ""
|
||||||
private val totp = TimeBasedOneTimePasswordGenerator()
|
private val totp = HmacOneTimePasswordGenerator()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
instance = this
|
instance = this
|
||||||
|
@ -48,8 +48,8 @@ class OneTimePassword @Inject constructor(
|
||||||
* Name of master device (target of OTP)
|
* Name of master device (target of OTP)
|
||||||
*/
|
*/
|
||||||
fun name(): String {
|
fun name(): String {
|
||||||
val defaultUserName = resourceHelper.gs(R.string.smscommunicator_default_user_display_name)
|
val defaultUserName = resourceHelper.gs(R.string.patient_name_default)
|
||||||
var userName = sp.getString(R.string.key_smscommunicator_otp_name, defaultUserName).replace(":", "").trim()
|
var userName = sp.getString(R.string.key_patient_name, defaultUserName).replace(":", "").trim()
|
||||||
if (userName.isEmpty())
|
if (userName.isEmpty())
|
||||||
userName = defaultUserName
|
userName = defaultUserName
|
||||||
return userName
|
return userName
|
||||||
|
@ -119,6 +119,6 @@ class OneTimePassword @Inject constructor(
|
||||||
* Return URI used to provision Authenticator apps
|
* Return URI used to provision Authenticator apps
|
||||||
*/
|
*/
|
||||||
fun provisioningURI(): String? =
|
fun provisioningURI(): String? =
|
||||||
key?.let { "otpauth://totp/AndroidAPS:" + URLEncoder.encode(name(), "utf-8") + "?secret=" + BaseEncoding.base32().encode(it.encoded).replace("=", "") + "&issuer=AndroidAPS" }
|
key?.let { "otpauth://totp/AndroidAPS:" + URLEncoder.encode(name(), "utf-8").replace("+", "%20") + "?secret=" + BaseEncoding.base32().encode(it.encoded).replace("=", "") + "&issuer=AndroidAPS" }
|
||||||
|
|
||||||
}
|
}
|
|
@ -291,11 +291,12 @@ class ActionStringHandler @Inject constructor(
|
||||||
} else if ("changeRequest" == act[0]) { ////////////////////////////////////////////// CHANGE REQUEST
|
} else if ("changeRequest" == act[0]) { ////////////////////////////////////////////// CHANGE REQUEST
|
||||||
rTitle = resourceHelper.gs(R.string.openloop_newsuggestion)
|
rTitle = resourceHelper.gs(R.string.openloop_newsuggestion)
|
||||||
rAction = "changeRequest"
|
rAction = "changeRequest"
|
||||||
val finalLastRun = loopPlugin.lastRun
|
loopPlugin.lastRun?.let {
|
||||||
rMessage += finalLastRun.constraintsProcessed
|
rMessage += it.constraintsProcessed
|
||||||
wearPlugin.requestChangeConfirmation(rTitle, rMessage, rAction)
|
wearPlugin.requestChangeConfirmation(rTitle, rMessage, rAction)
|
||||||
lastSentTimestamp = System.currentTimeMillis()
|
lastSentTimestamp = System.currentTimeMillis()
|
||||||
lastConfirmActionString = rAction
|
lastConfirmActionString = rAction
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else if ("cancelChangeRequest" == act[0]) { ////////////////////////////////////////////// CANCEL CHANGE REQUEST NOTIFICATION
|
} else if ("cancelChangeRequest" == act[0]) { ////////////////////////////////////////////// CANCEL CHANGE REQUEST NOTIFICATION
|
||||||
rAction = "cancelChangeRequest"
|
rAction = "cancelChangeRequest"
|
||||||
|
@ -406,9 +407,10 @@ class ActionStringHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
val aps = activePlugin.activeAPS
|
val aps = activePlugin.activeAPS
|
||||||
ret += "APS: " + (aps as PluginBase).name
|
ret += "APS: " + (aps as PluginBase).name
|
||||||
if (loopPlugin.lastRun != null) {
|
val lastRun = loopPlugin.lastRun
|
||||||
if (loopPlugin.lastRun.lastAPSRun != null) ret += "\nLast Run: " + DateUtil.timeString(loopPlugin.lastRun.lastAPSRun)
|
if (lastRun != null) {
|
||||||
if (loopPlugin.lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + DateUtil.timeString(loopPlugin.lastRun.lastTBREnact)
|
ret += "\nLast Run: " + DateUtil.timeString(lastRun.lastAPSRun)
|
||||||
|
if (lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + DateUtil.timeString(lastRun.lastTBREnact)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret += "LOOP DISABLED\n"
|
ret += "LOOP DISABLED\n"
|
||||||
|
|
|
@ -26,6 +26,7 @@ public class GlucoseStatus {
|
||||||
private HasAndroidInjector injector;
|
private HasAndroidInjector injector;
|
||||||
|
|
||||||
public double glucose = 0d;
|
public double glucose = 0d;
|
||||||
|
public double noise = 0d;
|
||||||
public double delta = 0d;
|
public double delta = 0d;
|
||||||
public double avgdelta = 0d;
|
public double avgdelta = 0d;
|
||||||
public double short_avgdelta = 0d;
|
public double short_avgdelta = 0d;
|
||||||
|
@ -35,6 +36,7 @@ public class GlucoseStatus {
|
||||||
|
|
||||||
public String log() {
|
public String log() {
|
||||||
return "Glucose: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl " +
|
return "Glucose: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl " +
|
||||||
|
"Noise: " + DecimalFormatter.to0Decimal(noise) + " " +
|
||||||
"Delta: " + DecimalFormatter.to0Decimal(delta) + " mg/dl" +
|
"Delta: " + DecimalFormatter.to0Decimal(delta) + " mg/dl" +
|
||||||
"Short avg. delta: " + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl " +
|
"Short avg. delta: " + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl " +
|
||||||
"Long avg. delta: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
|
"Long avg. delta: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
|
||||||
|
@ -47,6 +49,7 @@ public class GlucoseStatus {
|
||||||
|
|
||||||
public GlucoseStatus round() {
|
public GlucoseStatus round() {
|
||||||
this.glucose = Round.roundTo(this.glucose, 0.1);
|
this.glucose = Round.roundTo(this.glucose, 0.1);
|
||||||
|
this.noise = Round.roundTo(this.noise, 0.01);
|
||||||
this.delta = Round.roundTo(this.delta, 0.01);
|
this.delta = Round.roundTo(this.delta, 0.01);
|
||||||
this.avgdelta = Round.roundTo(this.avgdelta, 0.01);
|
this.avgdelta = Round.roundTo(this.avgdelta, 0.01);
|
||||||
this.short_avgdelta = Round.roundTo(this.short_avgdelta, 0.01);
|
this.short_avgdelta = Round.roundTo(this.short_avgdelta, 0.01);
|
||||||
|
@ -93,6 +96,7 @@ public class GlucoseStatus {
|
||||||
if (sizeRecords == 1) {
|
if (sizeRecords == 1) {
|
||||||
GlucoseStatus status = new GlucoseStatus(injector);
|
GlucoseStatus status = new GlucoseStatus(injector);
|
||||||
status.glucose = now.value;
|
status.glucose = now.value;
|
||||||
|
status.noise = 0d;
|
||||||
status.short_avgdelta = 0d;
|
status.short_avgdelta = 0d;
|
||||||
status.delta = 0d;
|
status.delta = 0d;
|
||||||
status.long_avgdelta = 0d;
|
status.long_avgdelta = 0d;
|
||||||
|
@ -150,6 +154,7 @@ public class GlucoseStatus {
|
||||||
GlucoseStatus status = new GlucoseStatus(injector);
|
GlucoseStatus status = new GlucoseStatus(injector);
|
||||||
status.glucose = now.value;
|
status.glucose = now.value;
|
||||||
status.date = now_date;
|
status.date = now_date;
|
||||||
|
status.noise = 0d; //for now set to nothing as not all CGMs report noise
|
||||||
|
|
||||||
status.short_avgdelta = average(short_deltas);
|
status.short_avgdelta = average(short_deltas);
|
||||||
|
|
||||||
|
|
|
@ -281,6 +281,10 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
|
||||||
|
|
||||||
// return true if new record is created
|
// return true if new record is created
|
||||||
public UpdateReturn createOrUpdate(Treatment treatment) {
|
public UpdateReturn createOrUpdate(Treatment treatment) {
|
||||||
|
if (treatment != null && treatment.source == Source.NONE) {
|
||||||
|
log.error("Coder error: source is not set for treatment: " + treatment, new Exception());
|
||||||
|
//FabricPrivacy.logException(new Exception("Coder error: source is not set for treatment: " + treatment));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Treatment old;
|
Treatment old;
|
||||||
treatment.date = DatabaseHelper.roundDateToSec(treatment.date);
|
treatment.date = DatabaseHelper.roundDateToSec(treatment.date);
|
||||||
|
|
|
@ -98,13 +98,12 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
|
||||||
// if there is no BG available, we have to upload anyway to have correct
|
// if there is no BG available, we have to upload anyway to have correct
|
||||||
// IOB displayed in NS
|
// IOB displayed in NS
|
||||||
private fun checkAPS() {
|
private fun checkAPS() {
|
||||||
val usedAPS = activePlugin.activeAPS
|
|
||||||
var shouldUploadStatus = false
|
var shouldUploadStatus = false
|
||||||
if (Config.NSCLIENT) return
|
if (Config.NSCLIENT) return
|
||||||
if (Config.PUMPCONTROL) shouldUploadStatus = true
|
if (Config.PUMPCONTROL) shouldUploadStatus = true
|
||||||
if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
|
else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
|
||||||
shouldUploadStatus = true
|
shouldUploadStatus = true
|
||||||
else if (DateUtil.isOlderThan(usedAPS.lastAPSRun, 5)) shouldUploadStatus = true
|
else if (DateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true
|
||||||
if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY) && shouldUploadStatus) {
|
if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY) && shouldUploadStatus) {
|
||||||
lastIobUpload = DateUtil.now()
|
lastIobUpload = DateUtil.now()
|
||||||
NSUpload.uploadDeviceStatus(loopPlugin, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump)
|
NSUpload.uploadDeviceStatus(loopPlugin, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump)
|
||||||
|
|
|
@ -198,6 +198,14 @@ class SWDefinition @Inject constructor(
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.validator(SWValidator { nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth })
|
.validator(SWValidator { nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth })
|
||||||
.visibility(SWValidator { !(nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth) })
|
.visibility(SWValidator { !(nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth) })
|
||||||
|
private val screenPatientName = SWScreen(injector, R.string.patient_name)
|
||||||
|
.skippable(true)
|
||||||
|
.add(SWInfotext(injector)
|
||||||
|
.label(R.string.patient_name_summary))
|
||||||
|
.add(SWEditString(injector)
|
||||||
|
.validator(SWTextValidator { text: String -> text.length > 0 })
|
||||||
|
.preferenceId(R.string.key_patient_name)
|
||||||
|
.updateDelay(5))
|
||||||
private val screenAge = SWScreen(injector, R.string.patientage)
|
private val screenAge = SWScreen(injector, R.string.patientage)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
|
@ -389,6 +397,7 @@ class SWDefinition @Inject constructor(
|
||||||
.add(screenUnits)
|
.add(screenUnits)
|
||||||
.add(displaySettings)
|
.add(displaySettings)
|
||||||
.add(screenNsClient)
|
.add(screenNsClient)
|
||||||
|
.add(screenPatientName)
|
||||||
.add(screenAge)
|
.add(screenAge)
|
||||||
.add(screenInsulin)
|
.add(screenInsulin)
|
||||||
.add(screenBgSource)
|
.add(screenBgSource)
|
||||||
|
@ -415,6 +424,7 @@ class SWDefinition @Inject constructor(
|
||||||
.add(screenUnits)
|
.add(screenUnits)
|
||||||
.add(displaySettings)
|
.add(displaySettings)
|
||||||
.add(screenNsClient)
|
.add(screenNsClient)
|
||||||
|
.add(screenPatientName)
|
||||||
.add(screenAge)
|
.add(screenAge)
|
||||||
.add(screenInsulin)
|
.add(screenInsulin)
|
||||||
.add(screenBgSource)
|
.add(screenBgSource)
|
||||||
|
@ -437,6 +447,7 @@ class SWDefinition @Inject constructor(
|
||||||
.add(displaySettings)
|
.add(displaySettings)
|
||||||
.add(screenNsClient)
|
.add(screenNsClient)
|
||||||
.add(screenBgSource)
|
.add(screenBgSource)
|
||||||
|
.add(screenPatientName)
|
||||||
.add(screenAge)
|
.add(screenAge)
|
||||||
.add(screenInsulin)
|
.add(screenInsulin)
|
||||||
.add(screenSensitivity)
|
.add(screenSensitivity)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.os.Bundle
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import info.nightscout.androidaps.BuildConfig
|
import info.nightscout.androidaps.BuildConfig
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
@ -132,6 +133,7 @@ class FabricPrivacy @Inject constructor(
|
||||||
val hashes: List<String> = signatureVerifierPlugin.shortHashes()
|
val hashes: List<String> = signatureVerifierPlugin.shortHashes()
|
||||||
if (hashes.isNotEmpty()) mainApp.firebaseAnalytics.setUserProperty("Hash", hashes[0])
|
if (hashes.isNotEmpty()) mainApp.firebaseAnalytics.setUserProperty("Hash", hashes[0])
|
||||||
activePlugin.activePump.let { mainApp.firebaseAnalytics.setUserProperty("Pump", it::class.java.simpleName) }
|
activePlugin.activePump.let { mainApp.firebaseAnalytics.setUserProperty("Pump", it::class.java.simpleName) }
|
||||||
|
if (!Config.NSCLIENT && !Config.PUMPCONTROL)
|
||||||
activePlugin.activeAPS.let { mainApp.firebaseAnalytics.setUserProperty("Aps", it::class.java.simpleName) }
|
activePlugin.activeAPS.let { mainApp.firebaseAnalytics.setUserProperty("Aps", it::class.java.simpleName) }
|
||||||
activePlugin.activeBgSource.let { mainApp.firebaseAnalytics.setUserProperty("BgSource", it::class.java.simpleName) }
|
activePlugin.activeBgSource.let { mainApp.firebaseAnalytics.setUserProperty("BgSource", it::class.java.simpleName) }
|
||||||
mainApp.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName)
|
mainApp.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName)
|
||||||
|
|
|
@ -11,8 +11,6 @@ import info.nightscout.androidaps.utils.alertDialogs.AlertDialogHelper
|
||||||
|
|
||||||
object OKDialog {
|
object OKDialog {
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
@JvmStatic
|
|
||||||
@JvmOverloads
|
|
||||||
fun show(context: Context, title: String, message: String, runnable: Runnable? = null) {
|
fun show(context: Context, title: String, message: String, runnable: Runnable? = null) {
|
||||||
var notEmptytitle = title
|
var notEmptytitle = title
|
||||||
if (notEmptytitle.isEmpty()) notEmptytitle = context.getString(R.string.message)
|
if (notEmptytitle.isEmpty()) notEmptytitle = context.getString(R.string.message)
|
||||||
|
|
|
@ -20,4 +20,5 @@ interface ResourceHelper {
|
||||||
fun decodeResource(id : Int) : Bitmap
|
fun decodeResource(id : Int) : Bitmap
|
||||||
fun getDisplayMetrics(): DisplayMetrics
|
fun getDisplayMetrics(): DisplayMetrics
|
||||||
fun dpToPx(dp: Int): Int
|
fun dpToPx(dp: Int): Int
|
||||||
|
fun shortTextMode(): Boolean
|
||||||
}
|
}
|
|
@ -68,4 +68,6 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont
|
||||||
val scale = context.resources.displayMetrics.density
|
val scale = context.resources.displayMetrics.density
|
||||||
return (dp * scale + 0.5f).toInt()
|
return (dp * scale + 0.5f).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun shortTextMode() : Boolean = !gb(R.bool.isTablet) && Config.NSCLIENT
|
||||||
}
|
}
|
|
@ -35,6 +35,7 @@
|
||||||
<string name="objectives_useloop">Inhoud van loop plugin weergeven</string>
|
<string name="objectives_useloop">Inhoud van loop plugin weergeven</string>
|
||||||
<string name="objectives_usescale">Gebruik de schaalfunctie: houd de BG grafiek lang ingedrukt</string>
|
<string name="objectives_usescale">Gebruik de schaalfunctie: houd de BG grafiek lang ingedrukt</string>
|
||||||
<string name="objectives_button_enter">Enter</string>
|
<string name="objectives_button_enter">Enter</string>
|
||||||
|
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Als je ten minste 3 maanden closed loop ervaring hebt met een ander doe-het-zelf systeem dan kun je wellicht een code aanvragen om doelen over te slaan. Zie https://androidaps.readthedocs.io/en/latest/CROWDIN/nl/Usage/Objectives.html#doelen-overslaan voor details.</string>
|
||||||
<string name="codeaccepted">Code geaccepteerd</string>
|
<string name="codeaccepted">Code geaccepteerd</string>
|
||||||
<string name="codeinvalid">Code ongeldig</string>
|
<string name="codeinvalid">Code ongeldig</string>
|
||||||
<string name="objectives_exam_objective">Bewijs je kennis</string>
|
<string name="objectives_exam_objective">Bewijs je kennis</string>
|
||||||
|
|
|
@ -276,7 +276,7 @@
|
||||||
<string name="metadata_label_created_at">Created at</string>
|
<string name="metadata_label_created_at">Created at</string>
|
||||||
<string name="metadata_label_aaps_version">AAPS Version</string>
|
<string name="metadata_label_aaps_version">AAPS Version</string>
|
||||||
<string name="metadata_label_aaps_flavour">Build Variant</string>
|
<string name="metadata_label_aaps_flavour">Build Variant</string>
|
||||||
<string name="metadata_label_device_name">Exporting device name</string>
|
<string name="metadata_label_device_name">Exporting device patient name</string>
|
||||||
<string name="metadata_label_device_model">Exporting device model</string>
|
<string name="metadata_label_device_model">Exporting device model</string>
|
||||||
<string name="metadata_label_encryption">File encryption</string>
|
<string name="metadata_label_encryption">File encryption</string>
|
||||||
|
|
||||||
|
@ -612,6 +612,10 @@
|
||||||
<string name="key_adult" translatable="false">adult</string>
|
<string name="key_adult" translatable="false">adult</string>
|
||||||
<string name="key_resistantadult" translatable="false">resistantadult</string>
|
<string name="key_resistantadult" translatable="false">resistantadult</string>
|
||||||
<string name="patientage_summary">Please select patient age to setup safety limits</string>
|
<string name="patientage_summary">Please select patient age to setup safety limits</string>
|
||||||
|
<string name="patient_name">Patient name</string>
|
||||||
|
<string name="patient_name_summary">Please provide patient name or nickname to differentiate among multiple setups</string>
|
||||||
|
<string name="patient_name_default" comment="This is default patient display name, when user does not provide real one">User</string>
|
||||||
|
<string name="key_patient_name" translatable="false">patient_name</string>
|
||||||
<string name="key_i_understand" translatable="false">I_understand</string>
|
<string name="key_i_understand" translatable="false">I_understand</string>
|
||||||
<string name="Glimp">Glimp</string>
|
<string name="Glimp">Glimp</string>
|
||||||
<string name="needwhitelisting">%1$s needs battery optimalization whitelisting for proper performance</string>
|
<string name="needwhitelisting">%1$s needs battery optimalization whitelisting for proper performance</string>
|
||||||
|
@ -863,8 +867,15 @@
|
||||||
<string name="bgsource_upload">BG upload settings</string>
|
<string name="bgsource_upload">BG upload settings</string>
|
||||||
<string name="wear_detailed_delta_title">Show detailed delta</string>
|
<string name="wear_detailed_delta_title">Show detailed delta</string>
|
||||||
<string name="wear_detailed_delta_summary">Show delta with one more decimal place</string>
|
<string name="wear_detailed_delta_summary">Show delta with one more decimal place</string>
|
||||||
|
<string name="key_smbinterval" translatable="false">smbinterval</string>
|
||||||
|
<string name="smbinterval_summary">How frequently SMBs will be given in min</string>
|
||||||
<string name="smbmaxminutes">SMB max minutes</string>
|
<string name="smbmaxminutes">SMB max minutes</string>
|
||||||
<string name="smbmaxminutes_summary">Max minutes of basal to limit SMB to</string>
|
<string name="smbmaxminutes_summary">Max minutes of basal to limit SMB to</string>
|
||||||
|
<string name="uamsmbmaxminutes">UAM SMB max minutes</string>
|
||||||
|
<string name="uamsmbmaxminutes_summary">Max minutes of basal to limit SMB to for UAM</string>
|
||||||
|
<string name="key_carbsReqThreshold" translatable="false">carbsReqThreshold</string>
|
||||||
|
<string name="carbsReqThreshold">Carb suggestion threshold</string>
|
||||||
|
<string name="carbsReqThreshold_summary">When Carbs are suggested, how many carbs will prompt a notification</string>
|
||||||
<string name="unsupportedfirmware">Unsupported pump firmware</string>
|
<string name="unsupportedfirmware">Unsupported pump firmware</string>
|
||||||
<string name="dexcomg5_xdripupload_title">Send BG data to xDrip+</string>
|
<string name="dexcomg5_xdripupload_title">Send BG data to xDrip+</string>
|
||||||
<string name="key_dexcomg5_xdripupload" translatable="false">dexcomg5_xdripupload</string>
|
<string name="key_dexcomg5_xdripupload" translatable="false">dexcomg5_xdripupload</string>
|
||||||
|
@ -1181,6 +1192,12 @@
|
||||||
<string name="high_temptarget_raises_sensitivity_summary"><![CDATA[Raise sensitivity for temptargets >= 100]]></string>
|
<string name="high_temptarget_raises_sensitivity_summary"><![CDATA[Raise sensitivity for temptargets >= 100]]></string>
|
||||||
<string name="low_temptarget_lowers_sensitivity_title">Low temptarget lowers sensitivity</string>
|
<string name="low_temptarget_lowers_sensitivity_title">Low temptarget lowers sensitivity</string>
|
||||||
<string name="low_temptarget_lowers_sensitivity_summary"><![CDATA[Lower sensitivity for temptargets < 100]]></string>
|
<string name="low_temptarget_lowers_sensitivity_summary"><![CDATA[Lower sensitivity for temptargets < 100]]></string>
|
||||||
|
<string name="key_resistance_lowers_target" translatable="false">resistance_lowers_target</string>
|
||||||
|
<string name="resistance_lowers_target_title">Resistance lowers target</string>
|
||||||
|
<string name="resistance_lowers_target_summary">When resistance is detected, lower the target glucose</string>
|
||||||
|
<string name="key_sensitivity_raises_target" translatable="false">sensitivity_raises_target</string>
|
||||||
|
<string name="sensitivity_raises_target_title">Sensitivity raises target</string>
|
||||||
|
<string name="sensitivity_raises_target_summary">When sensitivity is detected, raise the target glucose</string>
|
||||||
<string name="combo_invalid_setup">Invalid pump setup, check the docs and verify that the Quick Info menu is named QUICK INFO using the 360 configuration software.</string>
|
<string name="combo_invalid_setup">Invalid pump setup, check the docs and verify that the Quick Info menu is named QUICK INFO using the 360 configuration software.</string>
|
||||||
<string name="custom">Custom</string>
|
<string name="custom">Custom</string>
|
||||||
<string name="largetimedifftitle">Large Time Difference</string>
|
<string name="largetimedifftitle">Large Time Difference</string>
|
||||||
|
@ -1385,6 +1402,7 @@
|
||||||
<string name="tidepool_upload_bg">Upload BG tests</string>
|
<string name="tidepool_upload_bg">Upload BG tests</string>
|
||||||
|
|
||||||
<string name="key_smbmaxminutes" translatable="false">smbmaxminutes</string>
|
<string name="key_smbmaxminutes" translatable="false">smbmaxminutes</string>
|
||||||
|
<string name="key_uamsmbmaxminutes" translatable="false">uamsmbmaxminutes</string>
|
||||||
<string name="dst_plugin_name" translatable="false">Daylight Saving time</string>
|
<string name="dst_plugin_name" translatable="false">Daylight Saving time</string>
|
||||||
<string name="dst_in_24h_warning">Daylight Saving time change in 24h or less</string>
|
<string name="dst_in_24h_warning">Daylight Saving time change in 24h or less</string>
|
||||||
<string name="dst_loop_disabled_warning">Daylight Saving time change less than 3 hours ago - Closed loop disabled</string>
|
<string name="dst_loop_disabled_warning">Daylight Saving time change less than 3 hours ago - Closed loop disabled</string>
|
||||||
|
@ -1760,19 +1778,15 @@
|
||||||
<!-- SMS Communicator & OTP Authenticator -->
|
<!-- SMS Communicator & OTP Authenticator -->
|
||||||
|
|
||||||
<string name="key_smscommunicator_otp_enabled" translatable="false">smscommunicator_otp_enabled</string>
|
<string name="key_smscommunicator_otp_enabled" translatable="false">smscommunicator_otp_enabled</string>
|
||||||
<string name="key_smscommunicator_otp_name" translatable="false">smscommunicator_otp_name</string>
|
|
||||||
<string name="key_smscommunicator_otp_password" translatable="false">smscommunicator_otp_password</string>
|
<string name="key_smscommunicator_otp_password" translatable="false">smscommunicator_otp_password</string>
|
||||||
<string name="key_smscommunicator_otp_secret" translatable="false">smscommunicator_otp_secret</string>
|
<string name="key_smscommunicator_otp_secret" translatable="false">smscommunicator_otp_secret</string>
|
||||||
|
|
||||||
<string name="smscommunicator_default_user_display_name" comment="This is default user display name, shown by Authenticators">User</string>
|
|
||||||
<string name="smscommunicator_code_from_authenticator_for" comment="This is continuation of sentence: To [ACTION] reply with code">from Authenticator app for: %1$s</string>
|
<string name="smscommunicator_code_from_authenticator_for" comment="This is continuation of sentence: To [ACTION] reply with code">from Authenticator app for: %1$s</string>
|
||||||
|
|
||||||
<string name="smscommunicator_otp_enabled">Enable Authenticator</string>
|
<string name="smscommunicator_otp_enabled">Enable Authenticator</string>
|
||||||
<string name="smscommunicator_otp_enabled_summary">Authenticate commands using One Time Passwords generated by Google Authenticator or similar 2FA apps.</string>
|
<string name="smscommunicator_otp_enabled_summary">Authenticate commands using One Time Passwords generated by Google Authenticator or similar 2FA apps.</string>
|
||||||
<string name="smscommunicator_otp_pin">Additional PIN at token end</string>
|
<string name="smscommunicator_otp_pin">Additional PIN at token end</string>
|
||||||
<string name="smscommunicator_otp_pin_summary">Additional digits that should be memorised and glued at end of each generated One Time Password</string>
|
<string name="smscommunicator_otp_pin_summary">Additional digits that should be memorised and glued at end of each generated One Time Password</string>
|
||||||
<string name="smscommunicator_otp_name">User name for Authenticator</string>
|
|
||||||
<string name="smscommunicator_otp_name_summary">User name displayed along with generated OTP on Authenticator App</string>
|
|
||||||
|
|
||||||
<string name="smscomunicator_tab_otp_label">Authenticator setup</string>
|
<string name="smscomunicator_tab_otp_label">Authenticator setup</string>
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,14 @@
|
||||||
android:key="@string/key_language"
|
android:key="@string/key_language"
|
||||||
android:title="@string/language" />
|
android:title="@string/language" />
|
||||||
|
|
||||||
|
|
||||||
|
<EditTextPreference
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:key="@string/key_patient_name"
|
||||||
|
android:title="@string/patient_name"
|
||||||
|
android:summary="@string/patient_name_summary"
|
||||||
|
/>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/protection">
|
<PreferenceCategory android:title="@string/protection">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
|
|
@ -73,13 +73,41 @@
|
||||||
android:summary="@string/enablesmbaftercarbs_summary"
|
android:summary="@string/enablesmbaftercarbs_summary"
|
||||||
android:title="@string/enablesmbaftercarbs" />
|
android:title="@string/enablesmbaftercarbs" />
|
||||||
|
|
||||||
<ListPreference
|
<info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
|
||||||
|
android:defaultValue="3"
|
||||||
|
android:digits="0123456789"
|
||||||
|
android:inputType="number"
|
||||||
|
android:key="key_smbinterval"
|
||||||
|
android:maxLines="20"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:title="@string/smbinterval_summary"
|
||||||
|
validate:maxNumber="10"
|
||||||
|
validate:minNumber="1"
|
||||||
|
validate:testType="numericRange" />
|
||||||
|
|
||||||
|
<info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
|
||||||
android:defaultValue="30"
|
android:defaultValue="30"
|
||||||
android:entries="@array/smbMaxMinutes"
|
android:entries="@array/smbMaxMinutes"
|
||||||
android:entryValues="@array/smbMaxMinutes"
|
android:entryValues="@array/smbMaxMinutes"
|
||||||
android:key="@string/key_smbmaxminutes"
|
android:key="@string/key_smbmaxminutes"
|
||||||
android:title="@string/smbmaxminutes_summary" />
|
android:title="@string/smbmaxminutes_summary" />
|
||||||
|
|
||||||
|
<info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
|
||||||
|
android:defaultValue="30"
|
||||||
|
android:dialogMessage="@string/uamsmbmaxminutes"
|
||||||
|
android:digits="0123456789"
|
||||||
|
android:inputType="number"
|
||||||
|
android:key="@string/key_uamsmbmaxminutes"
|
||||||
|
android:maxLines="20"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:title="@string/uamsmbmaxminutes_summary"
|
||||||
|
validate:maxNumber="120"
|
||||||
|
validate:minNumber="15"
|
||||||
|
validate:testType="numericRange" />
|
||||||
|
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="@string/key_use_uam"
|
android:key="@string/key_use_uam"
|
||||||
|
@ -87,6 +115,18 @@
|
||||||
android:title="@string/enableuam" />
|
android:title="@string/enableuam" />
|
||||||
|
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:key="@string/key_sensitivity_raises_target"
|
||||||
|
android:summary="@string/sensitivity_raises_target_summary"
|
||||||
|
android:title="@string/sensitivity_raises_target_title"
|
||||||
|
/>
|
||||||
|
<SwitchPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/key_resistance_lowers_target"
|
||||||
|
android:summary="@string/resistance_lowers_target_summary"
|
||||||
|
android:title="@string/resistance_lowers_target_title"
|
||||||
|
/>
|
||||||
<!-- TODO AS-FIX -->
|
<!-- TODO AS-FIX -->
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
|
@ -103,6 +143,20 @@
|
||||||
android:summary="@string/low_temptarget_lowers_sensitivity_summary"
|
android:summary="@string/low_temptarget_lowers_sensitivity_summary"
|
||||||
android:title="@string/low_temptarget_lowers_sensitivity_title" />
|
android:title="@string/low_temptarget_lowers_sensitivity_title" />
|
||||||
|
|
||||||
|
<info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
|
||||||
|
android:key="@string/key_carbsReqThreshold"
|
||||||
|
android:title="@string/carbsReqThreshold"
|
||||||
|
android:defaultValue="1"
|
||||||
|
android:dialogMessage="@string/carbsReqThreshold_summary"
|
||||||
|
android:digits="0123456789"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLines="20"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
validate:maxNumber="10"
|
||||||
|
validate:minNumber="1"
|
||||||
|
validate:testType="numericRange"/>
|
||||||
|
|
||||||
<androidx.preference.PreferenceScreen
|
<androidx.preference.PreferenceScreen
|
||||||
android:key="absorption_smb_advanced"
|
android:key="absorption_smb_advanced"
|
||||||
android:title="@string/advancedsettings_title">
|
android:title="@string/advancedsettings_title">
|
||||||
|
|
|
@ -49,14 +49,6 @@
|
||||||
android:title="@string/smscommunicator_otp_pin"
|
android:title="@string/smscommunicator_otp_pin"
|
||||||
validate:testType="pinStrength" />
|
validate:testType="pinStrength" />
|
||||||
|
|
||||||
<info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
|
|
||||||
android:dependency="@string/key_smscommunicator_remotecommandsallowed"
|
|
||||||
android:key="@string/key_smscommunicator_otp_name"
|
|
||||||
android:summary="@string/smscommunicator_otp_name_summary"
|
|
||||||
android:title="@string/smscommunicator_otp_name"
|
|
||||||
validate:testType="personName" />
|
|
||||||
|
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in a new issue