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
|
||||
var five_min_blocks = (2 * 60) / 5;
|
||||
var target_delta = target_bg - eventual_bg;
|
||||
var expectedDelta = round(bgi + (target_delta / five_min_blocks), 1);
|
||||
return expectedDelta;
|
||||
return /* expectedDelta */ round(bgi + (target_delta / five_min_blocks), 1);
|
||||
}
|
||||
|
||||
|
||||
function convert_bg(value, profile)
|
||||
{
|
||||
if (profile.out_units == "mmol/L")
|
||||
if (profile.out_units === "mmol/L")
|
||||
{
|
||||
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 deliverAt = new Date();
|
||||
if (currentTime) {
|
||||
deliverAt = new Date(currentTime);
|
||||
}
|
||||
|
||||
if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
|
||||
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 systemTime = new Date();
|
||||
if (currentTime) {
|
||||
systemTime = currentTime;
|
||||
}
|
||||
var bgTime = new Date(glucose_status.date);
|
||||
var minAgo = round( (systemTime - bgTime) / 60 / 1000 ,1);
|
||||
|
||||
var bg = glucose_status.glucose;
|
||||
if (bg < 39) { //Dexcom is in ??? mode or calibrating
|
||||
rT.reason = "CGM is calibrating or in ??? state";
|
||||
var noise = glucose_status.noise;
|
||||
// 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
|
||||
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
|
||||
rT.reason += ". Canceling high temp basal of "+currenttemp.rate;
|
||||
}
|
||||
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
||||
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.temp = 'absolute';
|
||||
rT.duration = 0;
|
||||
rT.rate = 0;
|
||||
rT.duration = 30;
|
||||
rT.rate = basal;
|
||||
return rT;
|
||||
//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.deliverAt = deliverAt;
|
||||
rT.temp = 'absolute';
|
||||
|
@ -115,14 +195,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
|
||||
var sensitivityRatio;
|
||||
var high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity;
|
||||
var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled basal (which might change)
|
||||
var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled target (which might change)
|
||||
if ( profile.half_basal_exercise_target ) {
|
||||
var halfBasalTarget = profile.half_basal_exercise_target;
|
||||
} else {
|
||||
var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%)
|
||||
halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%)
|
||||
// 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default)
|
||||
}
|
||||
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget + 10
|
||||
if ( high_temptarget_raises_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
|
||||
// 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)
|
||||
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
|
||||
sensitivityRatio = round(sensitivityRatio,2);
|
||||
console.error("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
||||
} else if (typeof autosens_data !== 'undefined' ) {
|
||||
console.log("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
||||
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||
sensitivityRatio = autosens_data.ratio;
|
||||
console.error("Autosens ratio: "+sensitivityRatio+"; ");
|
||||
console.log("Autosens ratio: "+sensitivityRatio+"; ");
|
||||
}
|
||||
if (sensitivityRatio) {
|
||||
basal = profile.current_basal * sensitivityRatio;
|
||||
basal = round_basal(basal, profile);
|
||||
if (basal != profile_current_basal) {
|
||||
console.error("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
||||
if (basal !== profile_current_basal) {
|
||||
console.log("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
||||
} 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
|
||||
if (profile.temptargetSet) {
|
||||
//console.error("Temp Target set, not adjusting with autosens; ");
|
||||
} else if (typeof autosens_data !== 'undefined' ) {
|
||||
//console.log("Temp Target set, not adjusting with autosens; ");
|
||||
} 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 ) {
|
||||
// with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range
|
||||
min_bg = round((min_bg - 60) / autosens_data.ratio) + 60;
|
||||
max_bg = round((max_bg - 60) / autosens_data.ratio) + 60;
|
||||
new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60;
|
||||
var new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60;
|
||||
// don't allow target_bg below 80
|
||||
new_target_bg = Math.max(80, new_target_bg);
|
||||
if (target_bg == new_target_bg) {
|
||||
console.error("target_bg unchanged: "+new_target_bg+"; ");
|
||||
if (target_bg === new_target_bg) {
|
||||
console.log("target_bg unchanged: "+new_target_bg+"; ");
|
||||
} 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;
|
||||
}
|
||||
|
@ -197,34 +277,33 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
|
||||
var profile_sens = round(profile.sens,1)
|
||||
var sens = profile.sens;
|
||||
if (typeof autosens_data !== 'undefined' ) {
|
||||
if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||
sens = profile.sens / sensitivityRatio;
|
||||
sens = round(sens, 1);
|
||||
if (sens != profile_sens) {
|
||||
console.error("ISF from "+profile_sens+" to "+sens);
|
||||
if (sens !== profile_sens) {
|
||||
console.log("ISF from "+profile_sens+" to "+sens);
|
||||
} 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);
|
||||
|
||||
// compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
|
||||
var lastTempAge;
|
||||
if (typeof iob_data.lastTemp !== 'undefined' ) {
|
||||
lastTempAge = round(( new Date().getTime() - iob_data.lastTemp.date ) / 60000); // in minutes
|
||||
// } ---- added to not produce errors
|
||||
lastTempAge = round(( new Date(systemTime).getTime() - iob_data.lastTemp.date ) / 60000); // in minutes
|
||||
} else {
|
||||
lastTempAge = 0;
|
||||
}
|
||||
//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");
|
||||
rT.temp = 'absolute';
|
||||
rT.deliverAt = deliverAt;
|
||||
if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate != iob_data.lastTemp.rate ) {
|
||||
rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; setting neutral temp of "+basal+".";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
if ( 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; canceling temp";
|
||||
return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp);
|
||||
}
|
||||
if ( currenttemp && iob_data.lastTemp && currenttemp.duration > 0 ) {
|
||||
// TODO: fix this (lastTemp.duration is how long it has run; currenttemp.duration is time left
|
||||
|
@ -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));
|
||||
var lastTempEnded = lastTempAge - iob_data.lastTemp.duration
|
||||
if ( lastTempEnded > 5 ) {
|
||||
rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; setting neutral temp of "+basal+".";
|
||||
if ( lastTempEnded > 5 && lastTempAge > 10 ) {
|
||||
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));
|
||||
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
|
||||
//if ( tempModulus < 25 && tempModulus > 5 ) {
|
||||
|
@ -264,37 +343,44 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
if (iob_data.iob > 0) {
|
||||
var naive_eventualBG = round( bg - (iob_data.iob * sens) );
|
||||
} else { // if IOB is negative, be more conservative and use the lower of sens, profile.sens
|
||||
var naive_eventualBG = round( bg - (iob_data.iob * Math.min(sens, profile.sens) ) );
|
||||
naive_eventualBG = round( bg - (iob_data.iob * Math.min(sens, profile.sens) ) );
|
||||
}
|
||||
// and adjust it for the deviation above
|
||||
var eventualBG = naive_eventualBG + deviation;
|
||||
// calculate what portion of that is due to bolussnooze
|
||||
//var bolusContrib = iob_data.bolussnooze * sens;
|
||||
// and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime
|
||||
//var naive_snoozeBG = round( naive_eventualBG + 1.5 * bolusContrib );
|
||||
// adjust that for deviation like we did eventualBG
|
||||
//var snoozeBG = naive_snoozeBG + deviation;
|
||||
|
||||
// adjust target BG range if needed to safely bring down high BG faster without causing lows
|
||||
if ( bg > max_bg && profile.adv_target_adjustments && ! profile.temptargetSet ) {
|
||||
// raise target for noisy / raw CGM data
|
||||
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
|
||||
var adjustedMinBG = round(Math.max(80, min_bg - (bg - min_bg)/3 ),0);
|
||||
var adjustedTargetBG =round( Math.max(80, target_bg - (bg - target_bg)/3 ),0);
|
||||
var adjustedMaxBG = round(Math.max(80, max_bg - (bg - max_bg)/3 ),0);
|
||||
adjustedMinBG = round(Math.max(80, min_bg - (bg - min_bg)/3 ),0);
|
||||
adjustedTargetBG =round( Math.max(80, target_bg - (bg - target_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
|
||||
//console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG);
|
||||
if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) {
|
||||
console.error("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
||||
console.log("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
||||
min_bg = adjustedMinBG;
|
||||
} 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 > 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;
|
||||
} 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 > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) {
|
||||
|
@ -321,7 +407,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
, 'bg': bg
|
||||
, 'tick': tick
|
||||
, 'eventualBG': eventualBG
|
||||
//, 'snoozeBG': snoozeBG
|
||||
, 'insulinReq': 0
|
||||
, 'reservoir' : reservoir_data // The expected reservoir volume at which to deliver the microbolus (the reservoir volume from right before the last pumphistory run)
|
||||
, 'deliverAt' : deliverAt // The time at which the microbolus should be delivered
|
||||
|
@ -341,71 +426,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
ZTpredBGs.push(bg);
|
||||
UAMpredBGs.push(bg);
|
||||
|
||||
// enable SMB whenever we have COB or UAM is enabled
|
||||
// SMB is disabled by default, unless explicitly enabled in preferences.json
|
||||
var enableSMB=false;
|
||||
// disable SMB when a high temptarget is set
|
||||
if (! microBolusAllowed) {
|
||||
console.error("SMB disabled (!microBolusAllowed)")
|
||||
} else if (! profile.allowSMB_with_high_temptarget && profile.temptargetSet && target_bg > 100) {
|
||||
console.error("SMB disabled due to high temptarget of",target_bg);
|
||||
enableSMB=false;
|
||||
// enable SMB/UAM (if enabled in preferences) while we have COB
|
||||
} else if (profile.enableSMB_with_COB === true && meal_data.mealCOB) {
|
||||
if (meal_data.bwCarbs) {
|
||||
if (profile.A52_risk_enable) {
|
||||
console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard")
|
||||
enableSMB=true;
|
||||
} else {
|
||||
console.error("SMB not enabled for Bolus Wizard COB");
|
||||
}
|
||||
} else {
|
||||
console.error("SMB enabled for COB of",meal_data.mealCOB);
|
||||
enableSMB=true;
|
||||
}
|
||||
// enable SMB/UAM (if enabled in preferences) for a full 6 hours after any carb entry
|
||||
// (6 hours is defined in carbWindow in lib/meal/total.js)
|
||||
} else if (profile.enableSMB_after_carbs === true && meal_data.carbs ) {
|
||||
if (meal_data.bwCarbs) {
|
||||
if (profile.A52_risk_enable) {
|
||||
console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard")
|
||||
enableSMB=true;
|
||||
} else {
|
||||
console.error("SMB not enabled for Bolus Wizard carbs");
|
||||
}
|
||||
} else {
|
||||
console.error("SMB enabled for 6h after carb entry");
|
||||
enableSMB=true;
|
||||
}
|
||||
// enable SMB/UAM (if enabled in preferences) if a low temptarget is set
|
||||
} else if (profile.enableSMB_with_temptarget === true && (profile.temptargetSet && target_bg < 100)) {
|
||||
if (meal_data.bwFound) {
|
||||
if (profile.A52_risk_enable) {
|
||||
console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard")
|
||||
enableSMB=true;
|
||||
} else {
|
||||
console.error("enableSMB_with_temptarget not supported within 6h of using Bolus Wizard");
|
||||
}
|
||||
} else {
|
||||
console.error("SMB enabled for temptarget of",convert_bg(target_bg, profile));
|
||||
enableSMB=true;
|
||||
}
|
||||
// enable SMB/UAM if always-on (unless previously disabled for high temptarget)
|
||||
} else if (profile.enableSMB_always === true) {
|
||||
if (meal_data.bwFound) {
|
||||
if (profile.A52_risk_enable === true) {
|
||||
console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard")
|
||||
enableSMB=true;
|
||||
} else {
|
||||
console.error("enableSMB_always not supported within 6h of using Bolus Wizard");
|
||||
}
|
||||
} else {
|
||||
console.error("SMB enabled due to enableSMB_always");
|
||||
enableSMB=true;
|
||||
}
|
||||
} else {
|
||||
console.error("SMB disabled (no enableSMB preferences active)");
|
||||
}
|
||||
var enableSMB = enable_smb(
|
||||
profile,
|
||||
microBolusAllowed,
|
||||
meal_data,
|
||||
target_bg
|
||||
);
|
||||
|
||||
// enable UAM (if enabled in preferences)
|
||||
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
|
||||
// CI = current carb impact on BG in mg/dL/5m
|
||||
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)
|
||||
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
|
||||
var csf = profile.sens / profile.carb_ratio;
|
||||
} else {
|
||||
//var csf = profile.sens / profile.carb_ratio;
|
||||
//} else {
|
||||
// otherwise, use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments
|
||||
// so that autotuned CR is still in effect even when basals and ISF are being adjusted by autosens
|
||||
var csf = sens / profile.carb_ratio;
|
||||
}
|
||||
//var 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
|
||||
// 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) {
|
||||
console.error("Limiting carb impact from",ci,"to",maxCI,"mg/dL/5m (",maxCarbAbsorptionRate,"g/h )");
|
||||
ci = maxCI;
|
||||
}
|
||||
// set meal_carbimpact high enough to absorb all meal carbs over 6 hours
|
||||
// total_impact (mg/dL) = CSF (mg/dL/g) * carbs (g)
|
||||
//console.error(csf * meal_data.carbs);
|
||||
// meal_carbimpact (mg/dL/5m) = CSF (mg/dL/g) * carbs (g) / 6 (h) * (1h/60m) * 5 (m/5m) * 2 (for linear decay)
|
||||
//var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1)
|
||||
var remainingCATimeMin = 3; // h; before carb absorption starts
|
||||
// adjust remainingCATime (instead of CR) for autosens
|
||||
var remainingCATimeMin = 3; // h; duration of expected not-yet-observed carb absorption
|
||||
// adjust remainingCATime (instead of CR) for autosens if sensitivityRatio defined
|
||||
if (sensitivityRatio){
|
||||
remainingCATimeMin = remainingCATimeMin / sensitivityRatio;
|
||||
}
|
||||
// 20 g/h means that anything <= 60g will get a remainingCATimeMin, 80g will get 4h, and 120g 6h
|
||||
// when actual absorption ramps up it will take over from remainingCATime
|
||||
var assumedCarbAbsorptionRate = 20; // g/h; maximum rate to assume carbs will absorb if no CI observed
|
||||
var remainingCATime = remainingCATimeMin; // added by mike https://github.com/openaps/oref0/issues/884
|
||||
var remainingCATime = remainingCATimeMin;
|
||||
if (meal_data.carbs) {
|
||||
// if carbs * assumedCarbAbsorptionRate > remainingCATimeMin, raise it
|
||||
// so <= 90g is assumed to take 3h, and 120g=4h
|
||||
remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.mealCOB/assumedCarbAbsorptionRate);
|
||||
var lastCarbAge = round(( new Date().getTime() - meal_data.lastCarbTime ) / 60000);
|
||||
var lastCarbAge = round(( new Date(systemTime).getTime() - meal_data.lastCarbTime ) / 60000);
|
||||
//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 = round(remainingCATime,1);
|
||||
//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)
|
||||
var remainingCIpeak = remainingCarbs * csf * 5 / 60 / (remainingCATime/2);
|
||||
//console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI,remainingCATime);
|
||||
//if (meal_data.mealCOB * 3 > meal_data.carbs) { }
|
||||
|
||||
// calculate peak deviation in last hour, and slope from that to current deviation
|
||||
var slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation,2);
|
||||
|
@ -488,17 +519,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
var slopeFromDeviations = Math.min(slopeFromMaxDeviation,-slopeFromMinDeviation/3);
|
||||
//console.error(slopeFromMaxDeviation);
|
||||
|
||||
aci = 10;
|
||||
var aci = 10;
|
||||
//5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m)
|
||||
// duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m)
|
||||
// limit cid to remainingCATime hours: the reset goes to remainingCI
|
||||
if (ci == 0) {
|
||||
if (ci === 0) {
|
||||
// avoid divide by zero
|
||||
cid = 0;
|
||||
} else {
|
||||
cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci ));
|
||||
}
|
||||
acid = Math.max(0, meal_data.mealCOB * csf / aci );
|
||||
var acid = Math.max(0, meal_data.mealCOB * csf / aci );
|
||||
// duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay)
|
||||
console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (~2h peak):",round(remainingCIpeak,1),"mg/dL per 5m");
|
||||
//console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours");
|
||||
|
@ -529,18 +560,18 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
try {
|
||||
iobArray.forEach(function(iobTick) {
|
||||
//console.error(iobTick);
|
||||
predBGI = round(( -iobTick.activity * sens * 5 ), 2);
|
||||
predZTBGI = round(( -iobTick.iobWithZeroTemp.activity * sens * 5 ), 2);
|
||||
var predBGI = round(( -iobTick.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
|
||||
// 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;
|
||||
// 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
|
||||
// eventually accounting for all carbs (if they can be absorbed over DIA)
|
||||
predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) );
|
||||
predACI = Math.max(0, Math.max(0,aci) * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) );
|
||||
var predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*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
|
||||
// bilinear curve peaking at remainingCIpeak at remainingCATime/2 hours (remainingCATime/2*12 * 5m)
|
||||
// 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;
|
||||
remainingCIs.push(round(remainingCI,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;
|
||||
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
|
||||
// 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
|
||||
// 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);
|
||||
// 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) {
|
||||
//console.error(UAMpredBGs.length,slopeFromDeviations, predUCI);
|
||||
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
|
||||
// look ahead 60m (regardless of insulin type) so as to be less aggressive on slower insulins
|
||||
var insulinPeakTime = 60;
|
||||
// add 30m to allow for insluin delivery (SMBs or temps)
|
||||
// add 30m to allow for insulin delivery (SMBs or temps)
|
||||
insulinPeakTime = 90;
|
||||
var insulinPeak5m = (insulinPeakTime/60)*12;
|
||||
//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
|
||||
//console.error("PredBGs:",JSON.stringify(predBGs));
|
||||
} 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) {
|
||||
console.error("predCIs (mg/dL/5m):",predCIs.join(" "));
|
||||
console.error("remainingCIs: ",remainingCIs.join(" "));
|
||||
}
|
||||
//,"totalCA:",round(totalCA,2),"remainingCItotal/csf+totalCA:",round(remainingCItotal/csf+totalCA,2));
|
||||
rT.predBGs = {};
|
||||
IOBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=IOBpredBGs.length-1; i > 12; i--) {
|
||||
if (IOBpredBGs[i-1] != IOBpredBGs[i]) { break; }
|
||||
if (IOBpredBGs[i-1] !== IOBpredBGs[i]) { break; }
|
||||
else { IOBpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.IOB = IOBpredBGs;
|
||||
|
@ -619,10 +649,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
ZTpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=ZTpredBGs.length-1; i > 6; i--) {
|
||||
//if (ZTpredBGs[i-1] != ZTpredBGs[i]) { break; }
|
||||
for (i=ZTpredBGs.length-1; i > 6; i--) {
|
||||
// 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(); }
|
||||
}
|
||||
rT.predBGs.ZT = ZTpredBGs;
|
||||
|
@ -631,19 +660,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
aCOBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=aCOBpredBGs.length-1; i > 12; i--) {
|
||||
if (aCOBpredBGs[i-1] != aCOBpredBGs[i]) { break; }
|
||||
for (i=aCOBpredBGs.length-1; i > 12; i--) {
|
||||
if (aCOBpredBGs[i-1] !== aCOBpredBGs[i]) { break; }
|
||||
else { aCOBpredBGs.pop(); }
|
||||
}
|
||||
// disable for now. may want to add a preference to re-enable
|
||||
//rT.predBGs.aCOB = aCOBpredBGs;
|
||||
}
|
||||
if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
|
||||
COBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=COBpredBGs.length-1; i > 12; i--) {
|
||||
if (COBpredBGs[i-1] != COBpredBGs[i]) { break; }
|
||||
for (i=COBpredBGs.length-1; i > 12; i--) {
|
||||
if (COBpredBGs[i-1] !== COBpredBGs[i]) { break; }
|
||||
else { COBpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.COB = COBpredBGs;
|
||||
|
@ -655,8 +682,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
UAMpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=UAMpredBGs.length-1; i > 12; i--) {
|
||||
if (UAMpredBGs[i-1] != UAMpredBGs[i]) { break; }
|
||||
for (i=UAMpredBGs.length-1; i > 12; i--) {
|
||||
if (UAMpredBGs[i-1] !== UAMpredBGs[i]) { break; }
|
||||
else { UAMpredBGs.pop(); }
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -733,14 +760,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
//console.error("minUAMPredBG:",minUAMPredBG,"minZTGuardBG:",minZTGuardBG,"minZTUAMPredBG:",minZTUAMPredBG);
|
||||
// if any carbs have been entered recently
|
||||
if (meal_data.carbs) {
|
||||
// average the minIOBPredBG and minUAMPredBG if available
|
||||
/*
|
||||
if ( minUAMPredBG < 999 ) {
|
||||
avgMinPredBG = round( (minIOBPredBG+minUAMPredBG)/2 );
|
||||
} else {
|
||||
avgMinPredBG = minIOBPredBG;
|
||||
}
|
||||
*/
|
||||
|
||||
// if UAM is disabled, use max of minIOBPredBG, minCOBPredBG
|
||||
if ( ! enableUAM && minCOBPredBG < 999 ) {
|
||||
|
@ -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
|
||||
} else if ( minCOBPredBG < 999 ) {
|
||||
// calculate blendedMinPredBG based on how many carbs remain as COB
|
||||
//blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minUAMPredBG;
|
||||
blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG;
|
||||
var blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG;
|
||||
// if blendedMinPredBG > minCOBPredBG, use that instead
|
||||
minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG));
|
||||
// if carbs have been entered, but have expired, use minUAMPredBG
|
||||
} else {
|
||||
//minPredBG = minUAMPredBG;
|
||||
} else if ( enableUAM ) {
|
||||
minPredBG = minZTUAMPredBG;
|
||||
} else {
|
||||
minPredBG = minGuardBG;
|
||||
}
|
||||
// in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG
|
||||
} else if ( enableUAM ) {
|
||||
//minPredBG = round(Math.max(minIOBPredBG,minUAMPredBG));
|
||||
minPredBG = round(Math.max(minIOBPredBG,minZTUAMPredBG));
|
||||
}
|
||||
|
||||
// make sure minPredBG isn't higher than avgPredBG
|
||||
minPredBG = Math.min( minPredBG, avgPredBG );
|
||||
|
||||
console.error("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG);
|
||||
console.log("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG);
|
||||
if (minCOBPredBG < 999) {
|
||||
console.error(" minCOBPredBG: "+minCOBPredBG);
|
||||
console.log(" minCOBPredBG: "+minCOBPredBG);
|
||||
}
|
||||
if (minUAMPredBG < 999) {
|
||||
console.error(" minUAMPredBG: "+minUAMPredBG);
|
||||
console.log(" minUAMPredBG: "+minUAMPredBG);
|
||||
}
|
||||
console.error(" avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"/",meal_data.carbs);
|
||||
// But if the COB line falls off a cliff, don't trust UAM too much:
|
||||
|
@ -790,9 +808,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
rT.reason += ", UAMpredBG " + convert_bg(lastUAMpredBG, profile)
|
||||
}
|
||||
rT.reason += "; ";
|
||||
//var bgUndershoot = threshold - Math.min(minGuardBG, Math.max( naive_eventualBG, eventualBG ));
|
||||
// use naive_eventualBG if above 40, but switch to minGuardBG if both eventualBGs hit floor of 39
|
||||
//var carbsReqBG = Math.max( naive_eventualBG, eventualBG );
|
||||
var carbsReqBG = naive_eventualBG;
|
||||
if ( carbsReqBG < 40 ) {
|
||||
carbsReqBG = Math.min( minGuardBG, carbsReqBG );
|
||||
|
@ -802,14 +818,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
var minutesAboveMinBG = 240;
|
||||
var minutesAboveThreshold = 240;
|
||||
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);
|
||||
if ( COBpredBGs[i] < min_bg ) {
|
||||
minutesAboveMinBG = 5*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var i=0; i<COBpredBGs.length; i++) {
|
||||
for (i=0; i<COBpredBGs.length; i++) {
|
||||
//console.error(COBpredBGs[i], threshold);
|
||||
if ( COBpredBGs[i] < threshold ) {
|
||||
minutesAboveThreshold = 5*i;
|
||||
|
@ -817,14 +833,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
}
|
||||
} else {
|
||||
for (var i=0; i<IOBpredBGs.length; i++) {
|
||||
for (i=0; i<IOBpredBGs.length; i++) {
|
||||
//console.error(IOBpredBGs[i], min_bg);
|
||||
if ( IOBpredBGs[i] < min_bg ) {
|
||||
minutesAboveMinBG = 5*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var i=0; i<IOBpredBGs.length; i++) {
|
||||
for (i=0; i<IOBpredBGs.length; i++) {
|
||||
//console.error(IOBpredBGs[i], threshold);
|
||||
if ( IOBpredBGs[i] < threshold ) {
|
||||
minutesAboveThreshold = 5*i;
|
||||
|
@ -848,9 +864,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
if ( minutesAboveThreshold < 240 || minutesAboveMinBG < 60 ) {
|
||||
console.error("BG projected to remain above",convert_bg(threshold,profile),"for",minutesAboveThreshold,"minutes");
|
||||
}
|
||||
// include at least minutesAboveMinBG worth of zero temps in calculating carbsReq
|
||||
// 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)
|
||||
//var zeroTempDuration = Math.max(30,minutesAboveMinBG);
|
||||
var zeroTempDuration = minutesAboveThreshold;
|
||||
// BG undershoot, minus effect of zero temps until hitting min_bg, converted to grams, minus COB
|
||||
var zeroTempEffect = profile.current_basal*sens*zeroTempDuration/60;
|
||||
|
@ -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
|
||||
} else if ( bg < threshold || minGuardBG < threshold ) {
|
||||
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 durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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:
|
||||
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
|
||||
|
@ -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
|
||||
// use snoozeBG to more gradually ramp in any counteraction of the user's boluses
|
||||
// multiply by 2 to low-temp faster for increased hypo safety
|
||||
//var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / sens);
|
||||
var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / sens);
|
||||
insulinReq = round( insulinReq , 2);
|
||||
// calculate naiveInsulinReq based on naive_eventualBG
|
||||
|
@ -914,7 +934,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
naiveInsulinReq = round( naiveInsulinReq , 2);
|
||||
if (minDelta < 0 && minDelta > expectedDelta) {
|
||||
// if we're barely falling, newinsulinReq should be barely negative
|
||||
//rT.reason += ", Snooze BG " + convert_bg(snoozeBG, profile);
|
||||
var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2);
|
||||
//console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
||||
insulinReq = newinsulinReq;
|
||||
|
@ -922,6 +941,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// rate required to deliver insulinReq less insulin over 30m:
|
||||
var rate = basal + (2 * insulinReq);
|
||||
rate = round_basal(rate, profile);
|
||||
|
||||
// if required temp < existing temp basal
|
||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||
// if current temp would deliver a lot (30% of basal) less than the required insulin,
|
||||
|
@ -937,18 +957,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
} else {
|
||||
// calculate a long enough zero temp to eventually correct back up to target
|
||||
if ( rate <=0 ) {
|
||||
var bgUndershoot = target_bg - naive_eventualBG;
|
||||
var worstCaseInsulinReq = bgUndershoot / sens;
|
||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
bgUndershoot = target_bg - naive_eventualBG;
|
||||
worstCaseInsulinReq = bgUndershoot / sens;
|
||||
durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
if (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 {
|
||||
durationReq = round(durationReq/30)*30;
|
||||
durationReq = Math.min(60,Math.max(0,durationReq));
|
||||
durationReq = Math.min(120,Math.max(0,durationReq));
|
||||
}
|
||||
//console.error(durationReq);
|
||||
//rT.reason += "insulinReq " + insulinReq + "; "
|
||||
if (durationReq > 0) {
|
||||
rT.reason += ", setting " + durationReq + "m zero temp. ";
|
||||
return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp);
|
||||
|
@ -995,8 +1014,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
|
||||
// eventual BG is at/above target
|
||||
// if iob is over max, just cancel any temps
|
||||
// if we're not here because of SMB, eventual BG is at/above target
|
||||
if (! (microBolusAllowed && rT.COB)) {
|
||||
if ( eventualBG >= max_bg ) {
|
||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " >= " + convert_bg(max_bg, profile) + ", ";
|
||||
}
|
||||
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
|
||||
//console.error(minPredBG,eventualBG);
|
||||
//var insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
||||
var insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
||||
// when dropping, but not as fast as expected, reduce insulinReq proportionally
|
||||
// to the what fraction of expectedDelta we're dropping at
|
||||
//if (minDelta < 0 && minDelta > expectedDelta) {
|
||||
//var newinsulinReq = round(( insulinReq * (1 - (minDelta / expectedDelta)) ), 2);
|
||||
//console.error("Reducing insulinReq from " + insulinReq + " to " + newinsulinReq + " for minDelta " + minDelta + " vs. expectedDelta " + expectedDelta);
|
||||
//insulinReq = newinsulinReq;
|
||||
//}
|
||||
insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
||||
// if that would put us over max_iob, then reduce accordingly
|
||||
if (insulinReq > max_iob-iob_data.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:
|
||||
var rate = basal + (2 * insulinReq);
|
||||
rate = basal + (2 * insulinReq);
|
||||
rate = round_basal(rate, profile);
|
||||
insulinReq = round(insulinReq,3);
|
||||
rT.insulinReq = insulinReq;
|
||||
//console.error(iob_data.lastBolusTime);
|
||||
// minutes since last bolus
|
||||
var lastBolusAge = round(( new Date().getTime() - iob_data.lastBolusTime ) / 60000,1);
|
||||
var lastBolusAge = round(( new Date(systemTime).getTime() - iob_data.lastBolusTime ) / 60000,1);
|
||||
//console.error(lastBolusAge);
|
||||
//console.error(profile.temptargetSet, target_bg, rT.COB);
|
||||
// only allow microboluses with COB or low temp targets, or within DIA hours of a bolus
|
||||
if (microBolusAllowed && enableSMB && bg > threshold) {
|
||||
// never bolus more than maxSMBBasalMinutes worth of basal
|
||||
mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3);
|
||||
if (typeof profile.maxSMBBasalMinutes == 'undefined' ) {
|
||||
maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
||||
var mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3);
|
||||
if (typeof profile.maxSMBBasalMinutes === 'undefined' ) {
|
||||
var maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
||||
console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m");
|
||||
// if IOB covers more than COB, limit maxBolus to 30m of basal
|
||||
} else if ( iob_data.iob > mealInsulinReq && iob_data.iob > 0 ) {
|
||||
console.error("IOB",iob_data.iob,"> COB",meal_data.mealCOB+"; mealInsulinReq =",mealInsulinReq);
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
console.error("profile.maxSMBBasalMinutes:",profile.maxSMBBasalMinutes,"profile.current_basal:",profile.current_basal);
|
||||
maxBolus = round( profile.current_basal * profile.maxSMBBasalMinutes / 60 ,1);
|
||||
}
|
||||
// bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest 0.1U
|
||||
microBolus = Math.floor(Math.min(insulinReq/2,maxBolus)*10)/10;
|
||||
// bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest bolus increment
|
||||
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
|
||||
var smbTarget = target_bg;
|
||||
var worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens;
|
||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens;
|
||||
durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
|
||||
// if insulinReq > 0 but not enough for a microBolus, don't set an SMB zero temp
|
||||
if (insulinReq > 0 && microBolus < 0.1) {
|
||||
if (insulinReq > 0 && microBolus < profile.bolus_increment) {
|
||||
durationReq = 0;
|
||||
}
|
||||
|
||||
var smbLowTempReq = 0;
|
||||
if (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) {
|
||||
durationReq = round(durationReq/30)*30;
|
||||
durationReq = Math.min(120,Math.max(0,durationReq));
|
||||
durationReq = Math.min(60,Math.max(0,durationReq));
|
||||
} else {
|
||||
// if SMB durationReq is less than 30m, set a nonzero low temp
|
||||
smbLowTempReq = round( basal * durationReq/30 ,2);
|
||||
|
@ -1085,17 +1102,23 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
rT.reason += ". ";
|
||||
|
||||
//allow SMBs every 3 minutes
|
||||
var nextBolusMins = round(3-lastBolusAge,1);
|
||||
//allow SMBs every 3 minutes by default
|
||||
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",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) {
|
||||
rT.units = microBolus;
|
||||
rT.reason += "Microbolusing " + microBolus + "U. ";
|
||||
}
|
||||
} else {
|
||||
rT.reason += "Waiting " + nextBolusMins + "m to microbolus again. ";
|
||||
rT.reason += "Waiting " + nextBolusMins + "m " + nextBolusSeconds + "s to microbolus again. ";
|
||||
}
|
||||
//rT.reason += ". ";
|
||||
|
||||
|
@ -1106,11 +1129,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
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);
|
||||
|
@ -1120,13 +1138,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
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
|
||||
rT.reason += currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " > 2 * insulinReq. Setting temp basal of " + rate + "U/hr. ";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
|
||||
if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set
|
||||
if (typeof currenttemp.duration === 'undefined' || currenttemp.duration === 0) { // no temp is set
|
||||
rT.reason += "no temp, setting " + rate + "U/hr. ";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
|
|
|
@ -107,10 +107,6 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval {
|
|||
return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours;
|
||||
}
|
||||
|
||||
public String age() {
|
||||
return age(OverviewFragment.shorttextmode);
|
||||
}
|
||||
|
||||
public boolean isOlderThan(double hours) {
|
||||
return getHoursFromStart() > hours;
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ abstract class PluginsModule {
|
|||
abstract fun bindMDIPlugin(plugin: MDIPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@NotNSClient
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
@IntKey(180)
|
||||
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.data.Profile;
|
||||
import info.nightscout.androidaps.events.EventCustomCalculationFinished;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
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.configBuilder.ProfileFunction;
|
||||
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.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
|
||||
|
@ -60,6 +62,7 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
|||
@Inject ActivePluginProvider activePlugin;
|
||||
@Inject BuildHelper buildHelper;
|
||||
@Inject FabricPrivacy fabricPrivacy;
|
||||
@Inject OverviewMenus overviewMenus;
|
||||
|
||||
private CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
|
@ -171,7 +174,7 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
|||
iobGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
|
||||
iobGraph.getGridLabelRenderer().setNumVerticalLabels(5);
|
||||
|
||||
setupChartMenu();
|
||||
overviewMenus.setupChartMenu(findViewById(R.id.overview_chartMenuButton));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -194,7 +197,7 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
|||
updateGUI("EventAutosensCalculationFinished");
|
||||
}
|
||||
}
|
||||
}, exception -> fabricPrivacy.logException(exception))
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventIobCalculationProgress.class)
|
||||
|
@ -204,6 +207,11 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
|||
iobCalculationProgressView.setText(event.getProgress());
|
||||
}, exception -> fabricPrivacy.logException(exception))
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventRefreshOverview.class)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(event -> updateGUI("EventRefreshOverview") , fabricPrivacy::logException)
|
||||
);
|
||||
// set start of current day
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(System.currentTimeMillis());
|
||||
|
@ -367,124 +375,4 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
|||
});
|
||||
}).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"),
|
||||
NOTIFICATION("NOTIFICATION"),
|
||||
NSCLIENT("NSCLIENT"),
|
||||
OVERVIEW("OVERVIEW", defaultValue = false),
|
||||
PUMP("PUMP"),
|
||||
PUMPBTCOMM("PUMPBTCOMM", defaultValue = false),
|
||||
PUMPCOMM("PUMPCOMM"),
|
||||
|
|
|
@ -81,7 +81,7 @@ class LoopFragment : DaggerFragment() {
|
|||
loop_request?.text = it.request?.toSpanned() ?: ""
|
||||
loop_constraintsprocessed?.text = it.constraintsProcessed?.toSpanned() ?: ""
|
||||
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_smbexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
|
||||
|
|
|
@ -13,6 +13,7 @@ import android.os.SystemClock;
|
|||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
@ -104,7 +105,7 @@ public class LoopPlugin extends PluginBase {
|
|||
public PumpEnactResult tbrSetByPump = null;
|
||||
public PumpEnactResult smbSetByPump = null;
|
||||
public String source = null;
|
||||
public Date lastAPSRun = null;
|
||||
public long lastAPSRun = DateUtil.now();
|
||||
public long lastTBREnact = 0;
|
||||
public long lastSMBEnact = 0;
|
||||
public long lastTBRRequest = 0;
|
||||
|
@ -112,7 +113,7 @@ public class LoopPlugin extends PluginBase {
|
|||
public long lastOpenModeAccept;
|
||||
}
|
||||
|
||||
public LastRun lastRun = null;
|
||||
@Nullable public LastRun lastRun = null;
|
||||
|
||||
@Inject
|
||||
public LoopPlugin(
|
||||
|
@ -381,7 +382,6 @@ public class LoopPlugin extends PluginBase {
|
|||
if (lastRun == null) lastRun = new LastRun();
|
||||
lastRun.request = result;
|
||||
lastRun.constraintsProcessed = resultAfterConstraints;
|
||||
lastRun.lastAPSRun = new Date();
|
||||
lastRun.source = ((PluginBase) usedAPS).getName();
|
||||
lastRun.tbrSetByPump = null;
|
||||
lastRun.smbSetByPump = null;
|
||||
|
@ -423,7 +423,7 @@ public class LoopPlugin extends PluginBase {
|
|||
public void run() {
|
||||
if (result.enacted || result.success) {
|
||||
lastRun.tbrSetByPump = result;
|
||||
lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
|
||||
lastRun.lastTBRRequest = lastRun.lastAPSRun;
|
||||
lastRun.lastTBREnact = DateUtil.now();
|
||||
rxBus.send(new EventLoopUpdateGui());
|
||||
applySMBRequest(resultAfterConstraints, new Callback() {
|
||||
|
@ -432,7 +432,7 @@ public class LoopPlugin extends PluginBase {
|
|||
//Callback is only called if a bolus was acutally requested
|
||||
if (result.enacted || result.success) {
|
||||
lastRun.smbSetByPump = result;
|
||||
lastRun.lastSMBRequest = lastRun.lastAPSRun.getTime();
|
||||
lastRun.lastSMBRequest = lastRun.lastAPSRun;
|
||||
lastRun.lastSMBEnact = DateUtil.now();
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
|
@ -512,7 +512,7 @@ public class LoopPlugin extends PluginBase {
|
|||
public void run() {
|
||||
if (result.enacted) {
|
||||
lastRun.tbrSetByPump = result;
|
||||
lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
|
||||
lastRun.lastTBRRequest = lastRun.lastAPSRun;
|
||||
lastRun.lastTBREnact = DateUtil.now();
|
||||
lastRun.lastOpenModeAccept = DateUtil.now();
|
||||
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.iob.iobCobCalculator.GlucoseStatus;
|
||||
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.utils.SafeParse;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
|
||||
public class DetermineBasalAdapterSMBJS {
|
||||
private final HasAndroidInjector injector;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
|
@ -47,6 +50,8 @@ public class DetermineBasalAdapterSMBJS {
|
|||
@Inject ResourceHelper resourceHelper;
|
||||
@Inject ProfileFunction profileFunction;
|
||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
||||
@Inject ActivePluginProvider activePluginProvider;
|
||||
|
||||
|
||||
private ScriptReader mScriptReader;
|
||||
private JSONObject mProfile;
|
||||
|
@ -57,6 +62,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
private JSONObject mAutosensData = null;
|
||||
private boolean mMicrobolusAllowed;
|
||||
private boolean mSMBAlwaysAllowed;
|
||||
private long mCurrentTime;
|
||||
|
||||
private String storedCurrentTemp = null;
|
||||
private String storedIobData = null;
|
||||
|
@ -67,6 +73,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
private String storedAutosens_data = null;
|
||||
private String storedMicroBolusAllowed = null;
|
||||
private String storedSMBAlwaysAllowed = null;
|
||||
private String storedCurrentTime = null;
|
||||
|
||||
private String scriptDebug = "";
|
||||
|
||||
|
@ -98,6 +105,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined");
|
||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed));
|
||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + (storedSMBAlwaysAllowed = "" + mSMBAlwaysAllowed));
|
||||
aapsLogger.debug(LTag.APS, "CurrentTime: " + (storedCurrentTime = "" + mCurrentTime));
|
||||
|
||||
|
||||
DetermineBasalResultSMB determineBasalResultSMB = null;
|
||||
|
@ -140,7 +148,8 @@ public class DetermineBasalAdapterSMBJS {
|
|||
makeParam(mMealData, rhino, scope),
|
||||
setTempBasalFunctionsObj,
|
||||
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
|
||||
) throws JSONException {
|
||||
|
||||
String units = profile.getUnits();
|
||||
Double pumpbolusstep = activePluginProvider.getActivePump().getPumpDescription().bolusStep;
|
||||
mProfile = new JSONObject();
|
||||
|
||||
mProfile.put("max_iob", maxIob);
|
||||
|
@ -242,8 +253,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
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));
|
||||
|
||||
// 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("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||
mProfile.put("low_temptarget_lowers_sensitivity", false);
|
||||
|
@ -267,13 +277,17 @@ public class DetermineBasalAdapterSMBJS {
|
|||
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
|
||||
|
||||
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_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false));
|
||||
mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
|
||||
mProfile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering);
|
||||
mProfile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering);
|
||||
mProfile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes));
|
||||
mProfile.put("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("temptargetSet", tempTargetSet);
|
||||
|
@ -302,6 +316,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
|
||||
mGlucoseStatus = new JSONObject();
|
||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose);
|
||||
mGlucoseStatus.put("noise", glucoseStatus.noise);
|
||||
|
||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
|
||||
|
@ -332,6 +347,8 @@ public class DetermineBasalAdapterSMBJS {
|
|||
mMicrobolusAllowed = microBolusAllowed;
|
||||
mSMBAlwaysAllowed = advancedFiltering;
|
||||
|
||||
mCurrentTime = now;
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
//public final static boolean enableSMB_after_carbs = false; // enable supermicrobolus for 6h after carbs, even with 0 COB
|
||||
//public final static boolean allowSMB_with_high_temptarget = false; // allow supermicrobolus (if otherwise enabled) even with high temp targets
|
||||
public final static int 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 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)
|
||||
// useCustomPeakTime:false // allows changing insulinPeakTime
|
||||
// insulinPeakTime:75 // number of minutes after a bolus activity peaks. defaults to 55m for Fiasp if useCustomPeakTime: false
|
||||
public final static int carbsReqThreshold = 1; // grams of carbsReq to trigger a pushover
|
||||
// offline_hotspot:false // enabled an offline-only local wifi hotspot if no Internet available
|
||||
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.interfaces.*
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.ArrayList;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Lazy;
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.R;
|
||||
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.ActivePluginProvider;
|
||||
import info.nightscout.androidaps.interfaces.BgSourceInterface;
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
||||
import info.nightscout.androidaps.interfaces.InsulinInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
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.LTag;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin;
|
||||
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.plugins.configBuilder.events.EventConfigBuilderUpdateGui;
|
||||
import info.nightscout.androidaps.utils.OKDialog;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package info.nightscout.androidaps.plugins.configBuilder
|
||||
|
||||
import info.nightscout.androidaps.Config
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Singleton
|
||||
class PluginStore @Inject constructor(
|
||||
|
@ -27,6 +26,7 @@ class PluginStore @Inject constructor(
|
|||
return pluginStore!!
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
|
||||
|
||||
private var activeBgSource: BgSourceInterface? = null
|
||||
|
@ -83,6 +83,7 @@ class PluginStore @Inject constructor(
|
|||
var pluginsInCategory: ArrayList<PluginBase>?
|
||||
|
||||
// PluginType.APS
|
||||
if (!Config.NSCLIENT && !Config.PUMPCONTROL) {
|
||||
pluginsInCategory = getSpecificPluginsList(PluginType.APS)
|
||||
activeAPS = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface?
|
||||
if (activeAPS == null) {
|
||||
|
@ -91,6 +92,7 @@ class PluginStore @Inject constructor(
|
|||
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface")
|
||||
}
|
||||
setFragmentVisiblities((activeAPS as PluginBase).name, pluginsInCategory, PluginType.APS)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -56,7 +56,7 @@ class VersionCheckerUtils @Inject constructor(
|
|||
}
|
||||
}.start()
|
||||
} 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")
|
||||
fun compareWithCurrentVersion(newVersion: String?, currentVersion: String) {
|
||||
|
|
|
@ -125,7 +125,7 @@ class DataBroadcastPlugin @Inject constructor(
|
|||
|
||||
private fun bgStatus(bundle: Bundle) {
|
||||
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.putLong("glucoseTimeStamp", lastBG.date) // timestamp
|
||||
|
@ -158,10 +158,9 @@ class DataBroadcastPlugin @Inject constructor(
|
|||
bundle.putInt("rigBattery", nsDeviceStatus.uploaderStatus.replace("%", "").trim { it <= ' ' }.toInt())
|
||||
|
||||
if (Config.APS && lazyLoopPlugin.get().lastRun?.lastTBREnact != 0L) { //we are AndroidAPS
|
||||
bundle.putLong("suggestedTimeStamp", lazyLoopPlugin.get().lastRun?.lastAPSRun?.time
|
||||
?: -1L)
|
||||
bundle.putLong("suggestedTimeStamp", lazyLoopPlugin.get().lastRun?.lastAPSRun ?: -1L)
|
||||
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
|
||||
?: -1L)
|
||||
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 n6 = Settings.Global.getString(context.contentResolver, "device_name")
|
||||
|
||||
// name we use for SMS OTP token in communicator
|
||||
val otpName = otp.name().trim()
|
||||
val defaultOtpName = resourceHelper.gs(R.string.smscommunicator_default_user_display_name)
|
||||
// name provided (hopefully) by user
|
||||
val patientName = sp.getString(R.string.key_patient_name, "")
|
||||
val defaultPatientName = resourceHelper.gs(R.string.patient_name_default)
|
||||
|
||||
// name we detect from OS
|
||||
val systemName = n1 ?: n2 ?: n3 ?: n4 ?: n5 ?: n6 ?: defaultOtpName
|
||||
val name = if (otpName.length > 0 && otpName != defaultOtpName) otpName else systemName
|
||||
val systemName = n1 ?: n2 ?: n3 ?: n4 ?: n5 ?: n6 ?: defaultPatientName
|
||||
val name = if (patientName.isNotEmpty() && patientName != defaultPatientName) patientName else systemName
|
||||
return name
|
||||
}
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ public class NSUpload {
|
|||
DeviceStatus deviceStatus = new DeviceStatus();
|
||||
try {
|
||||
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
|
||||
APSResult apsResult = lastRun.request;
|
||||
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
|
||||
*/
|
||||
fun extendedStatusLight(cageView: TextView, iAgeView: TextView,
|
||||
reservoirView: TextView, sageView: TextView,
|
||||
batteryView: TextView) {
|
||||
fun extendedStatusLight(cageView: TextView?, iAgeView: TextView?,
|
||||
reservoirView: TextView?, sageView: TextView?,
|
||||
batteryView: TextView?) {
|
||||
val pump = activePlugin.activePump
|
||||
handleAge("cage", CareportalEvent.SITECHANGE, cageView, "CAN ",
|
||||
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) {
|
||||
val urgent = nsSettingsStatus.getExtendedWarnValue(nsSettingPlugin, "urgent", defaultUrgentThreshold.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,
|
||||
|
@ -132,14 +132,14 @@ class StatusLightHandler @Inject constructor(
|
|||
}
|
||||
|
||||
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) {
|
||||
val notavailable = if (useShortText) "-" else resourceHelper.gs(R.string.notavailable)
|
||||
fun handleAge(age: TextView?, prefix: String, eventType: String, warnThreshold: Double, urgentThreshold: Double) {
|
||||
val notavailable = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable)
|
||||
val careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventType)
|
||||
if (careportalEvent != null) {
|
||||
age?.setTextColor(determineTextColor(careportalEvent, warnThreshold, urgentThreshold))
|
||||
age?.text = prefix + careportalEvent.age(useShortText)
|
||||
age?.text = prefix + careportalEvent.age(resourceHelper.shortTextMode())
|
||||
} else {
|
||||
age?.text = notavailable
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class GraphData(injector: HasAndroidInjector, private val graph: GraphView, priv
|
|||
var maxBgValue = Double.MIN_VALUE
|
||||
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
||||
if (bgReadingsArray?.isEmpty() != false) {
|
||||
aapsLogger.debug(LTag.OVERVIEW, "No BG data.")
|
||||
aapsLogger.debug("No BG data.")
|
||||
maxY = 10.0
|
||||
minY = 0.0
|
||||
return
|
||||
|
|
|
@ -719,7 +719,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
override fun run() {
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
detailedBolusInfo.carbs = anInteger().toDouble()
|
||||
detailedBolusInfo.source = Source.USER
|
||||
detailedBolusInfo.date = secondLong()
|
||||
if (activePlugin.activePump.pumpDescription.storesCarbInfo) {
|
||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
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
|
||||
|
||||
import android.util.Base64
|
||||
import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator
|
||||
import com.eatthepath.otp.HmacOneTimePasswordGenerator
|
||||
import com.google.common.io.BaseEncoding
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -23,7 +23,7 @@ class OneTimePassword @Inject constructor(
|
|||
|
||||
private var key: SecretKey? = null
|
||||
private var pin: String = ""
|
||||
private val totp = TimeBasedOneTimePasswordGenerator()
|
||||
private val totp = HmacOneTimePasswordGenerator()
|
||||
|
||||
init {
|
||||
instance = this
|
||||
|
@ -48,8 +48,8 @@ class OneTimePassword @Inject constructor(
|
|||
* Name of master device (target of OTP)
|
||||
*/
|
||||
fun name(): String {
|
||||
val defaultUserName = resourceHelper.gs(R.string.smscommunicator_default_user_display_name)
|
||||
var userName = sp.getString(R.string.key_smscommunicator_otp_name, defaultUserName).replace(":", "").trim()
|
||||
val defaultUserName = resourceHelper.gs(R.string.patient_name_default)
|
||||
var userName = sp.getString(R.string.key_patient_name, defaultUserName).replace(":", "").trim()
|
||||
if (userName.isEmpty())
|
||||
userName = defaultUserName
|
||||
return userName
|
||||
|
@ -119,6 +119,6 @@ class OneTimePassword @Inject constructor(
|
|||
* Return URI used to provision Authenticator apps
|
||||
*/
|
||||
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
|
||||
rTitle = resourceHelper.gs(R.string.openloop_newsuggestion)
|
||||
rAction = "changeRequest"
|
||||
val finalLastRun = loopPlugin.lastRun
|
||||
rMessage += finalLastRun.constraintsProcessed
|
||||
loopPlugin.lastRun?.let {
|
||||
rMessage += it.constraintsProcessed
|
||||
wearPlugin.requestChangeConfirmation(rTitle, rMessage, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = rAction
|
||||
}
|
||||
return
|
||||
} else if ("cancelChangeRequest" == act[0]) { ////////////////////////////////////////////// CANCEL CHANGE REQUEST NOTIFICATION
|
||||
rAction = "cancelChangeRequest"
|
||||
|
@ -406,9 +407,10 @@ class ActionStringHandler @Inject constructor(
|
|||
}
|
||||
val aps = activePlugin.activeAPS
|
||||
ret += "APS: " + (aps as PluginBase).name
|
||||
if (loopPlugin.lastRun != null) {
|
||||
if (loopPlugin.lastRun.lastAPSRun != null) ret += "\nLast Run: " + DateUtil.timeString(loopPlugin.lastRun.lastAPSRun)
|
||||
if (loopPlugin.lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + DateUtil.timeString(loopPlugin.lastRun.lastTBREnact)
|
||||
val lastRun = loopPlugin.lastRun
|
||||
if (lastRun != null) {
|
||||
ret += "\nLast Run: " + DateUtil.timeString(lastRun.lastAPSRun)
|
||||
if (lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + DateUtil.timeString(lastRun.lastTBREnact)
|
||||
}
|
||||
} else {
|
||||
ret += "LOOP DISABLED\n"
|
||||
|
|
|
@ -26,6 +26,7 @@ public class GlucoseStatus {
|
|||
private HasAndroidInjector injector;
|
||||
|
||||
public double glucose = 0d;
|
||||
public double noise = 0d;
|
||||
public double delta = 0d;
|
||||
public double avgdelta = 0d;
|
||||
public double short_avgdelta = 0d;
|
||||
|
@ -35,6 +36,7 @@ public class GlucoseStatus {
|
|||
|
||||
public String log() {
|
||||
return "Glucose: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl " +
|
||||
"Noise: " + DecimalFormatter.to0Decimal(noise) + " " +
|
||||
"Delta: " + DecimalFormatter.to0Decimal(delta) + " mg/dl" +
|
||||
"Short avg. delta: " + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl " +
|
||||
"Long avg. delta: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
|
||||
|
@ -47,6 +49,7 @@ public class GlucoseStatus {
|
|||
|
||||
public GlucoseStatus round() {
|
||||
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.avgdelta = Round.roundTo(this.avgdelta, 0.01);
|
||||
this.short_avgdelta = Round.roundTo(this.short_avgdelta, 0.01);
|
||||
|
@ -93,6 +96,7 @@ public class GlucoseStatus {
|
|||
if (sizeRecords == 1) {
|
||||
GlucoseStatus status = new GlucoseStatus(injector);
|
||||
status.glucose = now.value;
|
||||
status.noise = 0d;
|
||||
status.short_avgdelta = 0d;
|
||||
status.delta = 0d;
|
||||
status.long_avgdelta = 0d;
|
||||
|
@ -150,6 +154,7 @@ public class GlucoseStatus {
|
|||
GlucoseStatus status = new GlucoseStatus(injector);
|
||||
status.glucose = now.value;
|
||||
status.date = now_date;
|
||||
status.noise = 0d; //for now set to nothing as not all CGMs report noise
|
||||
|
||||
status.short_avgdelta = average(short_deltas);
|
||||
|
||||
|
|
|
@ -281,6 +281,10 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
|
|||
|
||||
// return true if new record is created
|
||||
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 {
|
||||
Treatment old;
|
||||
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
|
||||
// IOB displayed in NS
|
||||
private fun checkAPS() {
|
||||
val usedAPS = activePlugin.activeAPS
|
||||
var shouldUploadStatus = false
|
||||
if (Config.NSCLIENT) return
|
||||
if (Config.PUMPCONTROL) shouldUploadStatus = true
|
||||
if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
|
||||
else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
|
||||
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) {
|
||||
lastIobUpload = DateUtil.now()
|
||||
NSUpload.uploadDeviceStatus(loopPlugin, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump)
|
||||
|
|
|
@ -198,6 +198,14 @@ class SWDefinition @Inject constructor(
|
|||
.add(SWBreak(injector))
|
||||
.validator(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)
|
||||
.skippable(false)
|
||||
.add(SWBreak(injector))
|
||||
|
@ -389,6 +397,7 @@ class SWDefinition @Inject constructor(
|
|||
.add(screenUnits)
|
||||
.add(displaySettings)
|
||||
.add(screenNsClient)
|
||||
.add(screenPatientName)
|
||||
.add(screenAge)
|
||||
.add(screenInsulin)
|
||||
.add(screenBgSource)
|
||||
|
@ -415,6 +424,7 @@ class SWDefinition @Inject constructor(
|
|||
.add(screenUnits)
|
||||
.add(displaySettings)
|
||||
.add(screenNsClient)
|
||||
.add(screenPatientName)
|
||||
.add(screenAge)
|
||||
.add(screenInsulin)
|
||||
.add(screenBgSource)
|
||||
|
@ -437,6 +447,7 @@ class SWDefinition @Inject constructor(
|
|||
.add(displaySettings)
|
||||
.add(screenNsClient)
|
||||
.add(screenBgSource)
|
||||
.add(screenPatientName)
|
||||
.add(screenAge)
|
||||
.add(screenInsulin)
|
||||
.add(screenSensitivity)
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.os.Bundle
|
|||
import com.crashlytics.android.Crashlytics
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import info.nightscout.androidaps.BuildConfig
|
||||
import info.nightscout.androidaps.Config
|
||||
import info.nightscout.androidaps.MainApp
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
|
@ -132,6 +133,7 @@ class FabricPrivacy @Inject constructor(
|
|||
val hashes: List<String> = signatureVerifierPlugin.shortHashes()
|
||||
if (hashes.isNotEmpty()) mainApp.firebaseAnalytics.setUserProperty("Hash", hashes[0])
|
||||
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.activeBgSource.let { mainApp.firebaseAnalytics.setUserProperty("BgSource", it::class.java.simpleName) }
|
||||
mainApp.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName)
|
||||
|
|
|
@ -11,8 +11,6 @@ import info.nightscout.androidaps.utils.alertDialogs.AlertDialogHelper
|
|||
|
||||
object OKDialog {
|
||||
@SuppressLint("InflateParams")
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun show(context: Context, title: String, message: String, runnable: Runnable? = null) {
|
||||
var notEmptytitle = title
|
||||
if (notEmptytitle.isEmpty()) notEmptytitle = context.getString(R.string.message)
|
||||
|
|
|
@ -20,4 +20,5 @@ interface ResourceHelper {
|
|||
fun decodeResource(id : Int) : Bitmap
|
||||
fun getDisplayMetrics(): DisplayMetrics
|
||||
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
|
||||
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_usescale">Gebruik de schaalfunctie: houd de BG grafiek lang ingedrukt</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="codeinvalid">Code ongeldig</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_aaps_version">AAPS Version</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_encryption">File encryption</string>
|
||||
|
||||
|
@ -612,6 +612,10 @@
|
|||
<string name="key_adult" translatable="false">adult</string>
|
||||
<string name="key_resistantadult" translatable="false">resistantadult</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="Glimp">Glimp</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="wear_detailed_delta_title">Show detailed delta</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_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="dexcomg5_xdripupload_title">Send BG data to xDrip+</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="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="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="custom">Custom</string>
|
||||
<string name="largetimedifftitle">Large Time Difference</string>
|
||||
|
@ -1385,6 +1402,7 @@
|
|||
<string name="tidepool_upload_bg">Upload BG tests</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_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>
|
||||
|
@ -1760,19 +1778,15 @@
|
|||
<!-- SMS Communicator & OTP Authenticator -->
|
||||
|
||||
<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_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_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_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_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>
|
||||
|
||||
|
|
|
@ -20,6 +20,14 @@
|
|||
android:key="@string/key_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">
|
||||
|
||||
<Preference
|
||||
|
|
|
@ -73,13 +73,41 @@
|
|||
android:summary="@string/enablesmbaftercarbs_summary"
|
||||
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:entries="@array/smbMaxMinutes"
|
||||
android:entryValues="@array/smbMaxMinutes"
|
||||
android:key="@string/key_smbmaxminutes"
|
||||
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
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_use_uam"
|
||||
|
@ -87,6 +115,18 @@
|
|||
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 -->
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
|
@ -103,6 +143,20 @@
|
|||
android:summary="@string/low_temptarget_lowers_sensitivity_summary"
|
||||
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
|
||||
android:key="absorption_smb_advanced"
|
||||
android:title="@string/advancedsettings_title">
|
||||
|
|
|
@ -49,14 +49,6 @@
|
|||
android:title="@string/smscommunicator_otp_pin"
|
||||
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>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in a new issue