Merge branch 'dev'
Conflicts: app/src/main/res/values/strings.xml
This commit is contained in:
commit
678fbedcbf
|
@ -37,7 +37,7 @@
|
|||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
|
61
app/src/main/assets/OpenAPSAMA/basal-set-temp.js
Normal file
61
app/src/main/assets/OpenAPSAMA/basal-set-temp.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
'use strict';
|
||||
|
||||
function reason(rT, msg) {
|
||||
rT.reason = (rT.reason ? rT.reason + '. ' : '') + msg;
|
||||
console.error(msg);
|
||||
}
|
||||
|
||||
var tempBasalFunctions = {};
|
||||
|
||||
tempBasalFunctions.getMaxSafeBasal = function getMaxSafeBasal(profile) {
|
||||
|
||||
var max_daily_safety_multiplier = (isNaN(profile.max_daily_safety_multiplier) || profile.max_daily_safety_multiplier == null) ? 3 : profile.max_daily_safety_multiplier;
|
||||
var current_basal_safety_multiplier = (isNaN(profile.current_basal_safety_multiplier) || profile.current_basal_safety_multiplier == null) ? 4 : profile.current_basal_safety_multiplier;
|
||||
|
||||
return Math.min(profile.max_basal, max_daily_safety_multiplier * profile.max_daily_basal, current_basal_safety_multiplier * profile.current_basal);
|
||||
};
|
||||
|
||||
tempBasalFunctions.setTempBasal = function setTempBasal(rate, duration, profile, rT, currenttemp) {
|
||||
//var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal);
|
||||
|
||||
var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
|
||||
var round_basal = require('./round-basal');
|
||||
|
||||
if (rate < 0) {
|
||||
rate = 0;
|
||||
} // if >30m @ 0 required, zero temp will be extended to 30m instead
|
||||
else if (rate > maxSafeBasal) {
|
||||
rate = maxSafeBasal;
|
||||
}
|
||||
|
||||
var suggestedRate = round_basal(rate, profile);
|
||||
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && typeof(currenttemp.rate) !== 'undefined' && currenttemp.duration > 20 && suggestedRate <= currenttemp.rate * 1.2 && suggestedRate >= currenttemp.rate * 0.8) {
|
||||
rT.reason += ", but "+currenttemp.duration+"m left and " + currenttemp.rate + " ~ req " + suggestedRate + "U/hr: no action required";
|
||||
return rT;
|
||||
}
|
||||
|
||||
if (suggestedRate === profile.current_basal) {
|
||||
if (profile.skip_neutral_temps) {
|
||||
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && currenttemp.duration > 0) {
|
||||
reason(rT, 'Suggested rate is same as profile rate, a temp basal is active, canceling current temp');
|
||||
rT.duration = 0;
|
||||
rT.rate = 0;
|
||||
return rT;
|
||||
} else {
|
||||
reason(rT, 'Suggested rate is same as profile rate, no temp basal is active, doing nothing');
|
||||
return rT;
|
||||
}
|
||||
} else {
|
||||
reason(rT, 'Setting neutral temp basal of ' + profile.current_basal + 'U/hr');
|
||||
rT.duration = duration;
|
||||
rT.rate = suggestedRate;
|
||||
return rT;
|
||||
}
|
||||
} else {
|
||||
rT.duration = duration;
|
||||
rT.rate = suggestedRate;
|
||||
return rT;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = tempBasalFunctions;
|
487
app/src/main/assets/OpenAPSAMA/determine-basal.js
Normal file
487
app/src/main/assets/OpenAPSAMA/determine-basal.js
Normal file
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
Determine Basal
|
||||
|
||||
Released under MIT license. See the accompanying LICENSE.txt file for
|
||||
full terms and conditions
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
var round_basal = require('../round-basal')
|
||||
|
||||
// Rounds value to 'digits' decimal places
|
||||
function round(value, digits)
|
||||
{
|
||||
var scale = Math.pow(10, digits);
|
||||
return Math.round(value * scale) / scale;
|
||||
}
|
||||
|
||||
// we expect BG to rise or fall at the rate of BGI,
|
||||
// adjusted by the rate at which BG would need to rise /
|
||||
// fall to get eventualBG to target over DIA/2 hours
|
||||
function calculate_expected_delta(dia, target_bg, eventual_bg, bgi) {
|
||||
// (hours * mins_per_hour) / 5 = how many 5 minute periods in dia/2
|
||||
var dia_in_5min_blocks = (dia/2 * 60) / 5;
|
||||
var target_delta = target_bg - eventual_bg;
|
||||
var expectedDelta = round(bgi + (target_delta / dia_in_5min_blocks), 1);
|
||||
return expectedDelta;
|
||||
}
|
||||
|
||||
|
||||
function convert_bg(value, profile)
|
||||
{
|
||||
if (profile.out_units == "mmol/L")
|
||||
{
|
||||
return round(value / 18, 1).toFixed(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return value.toFixed(0);
|
||||
}
|
||||
}
|
||||
|
||||
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions) {
|
||||
var rT = { //short for requestedTemp
|
||||
};
|
||||
|
||||
if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
|
||||
rT.error ='Error: could not get current basal rate';
|
||||
return rT;
|
||||
}
|
||||
var basal = profile.current_basal;
|
||||
if (typeof autosens_data !== 'undefined' ) {
|
||||
basal = profile.current_basal * autosens_data.ratio;
|
||||
basal = round_basal(basal, profile);
|
||||
if (basal != profile.current_basal) {
|
||||
console.error("Adjusting basal from "+profile.current_basal+" to "+basal);
|
||||
}
|
||||
}
|
||||
|
||||
var bg = glucose_status.glucose;
|
||||
// TODO: figure out how to use raw isig data to estimate BG
|
||||
if (bg < 39) { //Dexcom is in ??? mode or calibrating
|
||||
rT.reason = "CGM is calibrating or in ??? state";
|
||||
if (basal <= currenttemp.rate * 1.2) { // high temp is running
|
||||
rT.reason += "; setting current basal of " + basal + " as temp";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
} else { //do nothing.
|
||||
rT.reason += ", temp " + currenttemp.rate + " <~ current basal " + basal + "U/hr";
|
||||
return rT;
|
||||
}
|
||||
}
|
||||
|
||||
var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver
|
||||
|
||||
// if target_bg is set, great. otherwise, if min and max are set, then set target to their average
|
||||
var target_bg;
|
||||
var min_bg;
|
||||
var max_bg;
|
||||
if (typeof profile.min_bg !== 'undefined') {
|
||||
min_bg = profile.min_bg;
|
||||
}
|
||||
if (typeof profile.max_bg !== 'undefined') {
|
||||
max_bg = profile.max_bg;
|
||||
}
|
||||
if (typeof profile.target_bg !== 'undefined') {
|
||||
target_bg = profile.target_bg;
|
||||
} else {
|
||||
if (typeof profile.min_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') {
|
||||
target_bg = (profile.min_bg + profile.max_bg) / 2;
|
||||
} else {
|
||||
rT.error ='Error: could not determine target_bg';
|
||||
return rT;
|
||||
}
|
||||
}
|
||||
|
||||
// adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120
|
||||
if (typeof autosens_data !== 'undefined' && profile.autosens_adjust_targets) {
|
||||
if (profile.temptargetSet) {
|
||||
console.error("Temp Target set, not adjusting with autosens");
|
||||
} else {
|
||||
min_bg = Math.round((min_bg - 60) / autosens_data.ratio) + 60;
|
||||
max_bg = Math.round((max_bg - 60) / autosens_data.ratio) + 60;
|
||||
new_target_bg = Math.round((target_bg - 60) / autosens_data.ratio) + 60;
|
||||
if (target_bg == new_target_bg) {
|
||||
console.error("target_bg unchanged:", new_target_bg);
|
||||
} else {
|
||||
console.error("Adjusting target_bg from", target_bg, "to", new_target_bg);
|
||||
}
|
||||
target_bg = new_target_bg;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof iob_data === 'undefined' ) {
|
||||
rT.error ='Error: iob_data undefined';
|
||||
return rT;
|
||||
}
|
||||
|
||||
var iobArray = iob_data;
|
||||
if (typeof(iob_data.length) && iob_data.length > 1) {
|
||||
iob_data = iobArray[0];
|
||||
//console.error(JSON.stringify(iob_data[0]));
|
||||
}
|
||||
|
||||
if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' ) {
|
||||
rT.error ='Error: iob_data missing some property';
|
||||
return rT;
|
||||
}
|
||||
|
||||
var tick;
|
||||
|
||||
if (glucose_status.delta > -0.5) {
|
||||
tick = "+" + round(glucose_status.delta,0);
|
||||
} else {
|
||||
tick = round(glucose_status.delta,0);
|
||||
}
|
||||
var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
var minAvgDelta = Math.min(glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
|
||||
var sens = profile.sens;
|
||||
if (typeof autosens_data !== 'undefined' ) {
|
||||
sens = profile.sens / autosens_data.ratio;
|
||||
sens = round(sens, 1);
|
||||
if (sens != profile.sens) {
|
||||
console.error("Adjusting sens from "+profile.sens+" to "+sens);
|
||||
}
|
||||
}
|
||||
|
||||
//calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone
|
||||
var bgi = round(( -iob_data.activity * sens * 5 ), 2);
|
||||
// project deviations for 30 minutes
|
||||
var deviation = Math.round( 30 / 5 * ( minDelta - bgi ) );
|
||||
// don't overreact to a big negative delta: use minAvgDelta if deviation is negative
|
||||
if (deviation < 0) {
|
||||
deviation = Math.round( (30 / 5) * ( minAvgDelta - bgi ) );
|
||||
}
|
||||
|
||||
// calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity
|
||||
if (iob_data.iob > 0) {
|
||||
var naive_eventualBG = Math.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 = Math.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 = Math.round( naive_eventualBG + 1.5 * bolusContrib );
|
||||
// adjust that for deviation like we did eventualBG
|
||||
var snoozeBG = naive_snoozeBG + deviation;
|
||||
|
||||
var expectedDelta = calculate_expected_delta(profile.dia, target_bg, eventualBG, bgi);
|
||||
if (typeof eventualBG === 'undefined' || isNaN(eventualBG)) {
|
||||
rT.error ='Error: could not calculate eventualBG';
|
||||
return rT;
|
||||
}
|
||||
|
||||
// min_bg of 90 -> threshold of 70, 110 -> 80, and 130 -> 90
|
||||
var threshold = min_bg - 0.5*(min_bg-50);
|
||||
|
||||
rT = {
|
||||
'temp': 'absolute'
|
||||
, 'bg': bg
|
||||
, 'tick': tick
|
||||
, 'eventualBG': eventualBG
|
||||
, 'snoozeBG': snoozeBG
|
||||
};
|
||||
|
||||
var basaliob;
|
||||
if (iob_data.basaliob) { basaliob = iob_data.basaliob; }
|
||||
else { basaliob = iob_data.iob - iob_data.bolussnooze; }
|
||||
|
||||
// generate predicted future BGs based on IOB, COB, and current absortpion rate
|
||||
|
||||
var COBpredBGs = [];
|
||||
var aCOBpredBGs = [];
|
||||
var IOBpredBGs = [];
|
||||
COBpredBGs.push(bg);
|
||||
aCOBpredBGs.push(bg);
|
||||
IOBpredBGs.push(bg);
|
||||
//console.error(meal_data);
|
||||
// carb impact and duration are 0 unless changed below
|
||||
var ci = 0;
|
||||
var cid = 0;
|
||||
// calculate current carb absorption rate, and how long to absorb all carbs
|
||||
// CI = current carb impact on BG in mg/dL/5m
|
||||
ci = Math.round((minDelta - bgi)*10)/10;
|
||||
if (meal_data.mealCOB * 2 > meal_data.carbs) {
|
||||
// set ci to a minimum of 3mg/dL/5m (default) if less than half of carbs have absorbed
|
||||
ci = Math.max(profile.min_5m_carbimpact, ci);
|
||||
}
|
||||
aci = 10;
|
||||
//5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m)
|
||||
cid = meal_data.mealCOB * ( sens / profile.carb_ratio ) / ci;
|
||||
acid = meal_data.mealCOB * ( sens / profile.carb_ratio ) / aci;
|
||||
console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",Math.round(10*cid/6)/10,"hours");
|
||||
console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",Math.round(10*acid/6)/10,"hours");
|
||||
var minPredBG = 999;
|
||||
var maxPredBG = bg;
|
||||
var eventualPredBG = bg;
|
||||
try {
|
||||
iobArray.forEach(function(iobTick) {
|
||||
//console.error(iobTick);
|
||||
predBGI = round(( -iobTick.activity * sens * 5 ), 2);
|
||||
// predicted deviation impact drops linearly from current deviation down to zero
|
||||
// over 60 minutes (data points every 5m)
|
||||
predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) );
|
||||
IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev;
|
||||
//IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI;
|
||||
// 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, ci * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) );
|
||||
predACI = Math.max(0, aci * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) );
|
||||
COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI;
|
||||
aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI;
|
||||
//console.error(predBGI, predCI, predBG);
|
||||
IOBpredBGs.push(IOBpredBG);
|
||||
COBpredBGs.push(COBpredBG);
|
||||
aCOBpredBGs.push(aCOBpredBG);
|
||||
// wait 45m before setting minPredBG
|
||||
if ( COBpredBGs.length > 9 && (COBpredBG < minPredBG) ) { minPredBG = COBpredBG; }
|
||||
if ( COBpredBG > maxPredBG ) { maxPredBG = COBpredBG; }
|
||||
});
|
||||
// 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.");
|
||||
}
|
||||
rT.predBGs = {};
|
||||
IOBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = Math.round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=IOBpredBGs.length-1; i > 12; i--) {
|
||||
if (IOBpredBGs[i-1] != IOBpredBGs[i]) { break; }
|
||||
else { IOBpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.IOB = IOBpredBGs;
|
||||
if (meal_data.mealCOB > 0) {
|
||||
aCOBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = Math.round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=aCOBpredBGs.length-1; i > 12; i--) {
|
||||
if (aCOBpredBGs[i-1] != aCOBpredBGs[i]) { break; }
|
||||
else { aCOBpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.aCOB = aCOBpredBGs;
|
||||
}
|
||||
if (meal_data.mealCOB > 0 && ci > 0 ) {
|
||||
COBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = Math.round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=COBpredBGs.length-1; i > 12; i--) {
|
||||
if (COBpredBGs[i-1] != COBpredBGs[i]) { break; }
|
||||
else { COBpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.COB = COBpredBGs;
|
||||
eventualBG = Math.max(eventualBG, Math.round(COBpredBGs[COBpredBGs.length-1]) );
|
||||
rT.eventualBG = eventualBG;
|
||||
minPredBG = Math.min(minPredBG, eventualBG);
|
||||
// set snoozeBG to minPredBG
|
||||
snoozeBG = Math.round(Math.max(snoozeBG,minPredBG));
|
||||
rT.snoozeBG = snoozeBG;
|
||||
}
|
||||
|
||||
rT.COB=meal_data.mealCOB;
|
||||
rT.IOB=iob_data.iob;
|
||||
rT.reason="COB: " + meal_data.mealCOB + ", Dev: " + deviation + ", BGI: " + bgi + ", ISF: " + convert_bg(sens, profile) + ", Target: " + convert_bg(target_bg, profile) + "; ";
|
||||
if (bg < threshold) { // low glucose suspend mode: BG is < ~80
|
||||
rT.reason += "BG " + convert_bg(bg, profile) + "<" + convert_bg(threshold, profile);
|
||||
if ((glucose_status.delta <= 0 && minDelta <= 0) || (glucose_status.delta < expectedDelta && minDelta < expectedDelta) || bg < 60 ) {
|
||||
// BG is still falling / rising slower than predicted
|
||||
return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp);
|
||||
}
|
||||
if (glucose_status.delta > minDelta) {
|
||||
rT.reason += ", delta " + glucose_status.delta + ">0";
|
||||
} else {
|
||||
rT.reason += ", min delta " + minDelta.toFixed(2) + ">0";
|
||||
}
|
||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr";
|
||||
return rT;
|
||||
} else {
|
||||
rT.reason += "; setting current basal of " + basal + " as temp";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventualBG < min_bg) { // if eventual BG is below target:
|
||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " < " + convert_bg(min_bg, profile);
|
||||
// if 5m or 30m avg BG is rising faster than expected delta
|
||||
if (minDelta > expectedDelta && minDelta > 0) {
|
||||
if (glucose_status.delta > minDelta) {
|
||||
rT.reason += ", but Delta " + tick + " > Exp. Delta " + expectedDelta;
|
||||
} else {
|
||||
rT.reason += ", but Min. Delta " + minDelta.toFixed(2) + " > Exp. Delta " + expectedDelta;
|
||||
}
|
||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr";
|
||||
return rT;
|
||||
} else {
|
||||
rT.reason += "; setting current basal of " + basal + " as temp";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventualBG < min_bg) {
|
||||
// if we've bolused recently, we can snooze until the bolus IOB decays (at double speed)
|
||||
if (snoozeBG > min_bg) { // if adding back in the bolus contribution BG would be above min
|
||||
rT.reason += ", bolus snooze: eventual BG range " + convert_bg(eventualBG, profile) + "-" + convert_bg(snoozeBG, profile);
|
||||
//console.error(currenttemp, basal );
|
||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr";
|
||||
return rT;
|
||||
} else {
|
||||
rT.reason += "; setting current basal of " + basal + " as temp";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
}
|
||||
} else {
|
||||
// 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);
|
||||
if (minDelta < 0 && minDelta > expectedDelta) {
|
||||
// if we're barely falling, newinsulinReq should be barely negative
|
||||
rT.reason += ", Snooze BG " + convert_bg(snoozeBG, profile);
|
||||
var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2);
|
||||
//console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
||||
insulinReq = newinsulinReq;
|
||||
}
|
||||
// rate required to deliver insulinReq less insulin over 30m:
|
||||
var rate = basal + (2 * insulinReq);
|
||||
rate = round_basal(rate, profile);
|
||||
// if required temp < existing temp basal
|
||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||
if (insulinScheduled < insulinReq - basal*0.3) { // if current temp would deliver a lot (30% of basal) less than the required insulin, raise the rate
|
||||
rT.reason += ", "+currenttemp.duration + "m@" + (currenttemp.rate - basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " < req " + insulinReq + "-" + basal*0.3;
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate >= currenttemp.rate * 0.8)) {
|
||||
rT.reason += ", temp " + currenttemp.rate + " ~< req " + rate + "U/hr";
|
||||
return rT;
|
||||
} else {
|
||||
rT.reason += ", setting " + rate + "U/hr";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there is a low-temp running, and eventualBG would be below min_bg without it, let it run
|
||||
if (round_basal(currenttemp.rate, profile) < round_basal(basal, profile) ) {
|
||||
var lowtempimpact = (currenttemp.rate - basal) * (currenttemp.duration/60) * sens;
|
||||
var adjEventualBG = eventualBG + lowtempimpact;
|
||||
if ( adjEventualBG < min_bg ) {
|
||||
rT.reason += "letting low temp of " + currenttemp.rate + " run.";
|
||||
return rT;
|
||||
}
|
||||
}
|
||||
|
||||
// if eventual BG is above min but BG is falling faster than expected Delta
|
||||
if (minDelta < expectedDelta) {
|
||||
if (glucose_status.delta < minDelta) {
|
||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Delta " + tick + " < Exp. Delta " + expectedDelta;
|
||||
} else {
|
||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Min. Delta " + minDelta.toFixed(2) + " < Exp. Delta " + expectedDelta;
|
||||
}
|
||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr";
|
||||
return rT;
|
||||
} else {
|
||||
rT.reason += "; setting current basal of " + basal + " as temp";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
}
|
||||
}
|
||||
// eventualBG or snoozeBG (from minPredBG) is below max_bg
|
||||
if (eventualBG < max_bg || snoozeBG < max_bg) {
|
||||
// if there is a high-temp running and eventualBG > max_bg, let it run
|
||||
if (eventualBG > max_bg && round_basal(currenttemp.rate, profile) > round_basal(basal, profile) ) {
|
||||
rT.reason += ", " + eventualBG + " > " + max_bg + ": no action required (letting high temp of " + currenttemp.rate + " run)."
|
||||
return rT;
|
||||
}
|
||||
|
||||
rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(snoozeBG, profile)+" in range: no temp required";
|
||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr";
|
||||
return rT;
|
||||
} else {
|
||||
rT.reason += "; setting current basal of " + basal + " as temp";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
}
|
||||
}
|
||||
|
||||
// eventual BG is at/above target:
|
||||
// if iob is over max, just cancel any temps
|
||||
var basaliob;
|
||||
if (iob_data.basaliob) { basaliob = iob_data.basaliob; }
|
||||
else { basaliob = iob_data.iob - iob_data.bolussnooze; }
|
||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " >= " + convert_bg(max_bg, profile) + ", ";
|
||||
if (basaliob > max_iob) {
|
||||
rT.reason += "basaliob " + round(basaliob,2) + " > max_iob " + max_iob;
|
||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr";
|
||||
return rT;
|
||||
} else {
|
||||
rT.reason += "; setting current basal of " + basal + " as temp";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
}
|
||||
} else { // otherwise, calculate 30m high-temp required to get projected BG down to target
|
||||
|
||||
// insulinReq is the additional insulin required to get down to max bg:
|
||||
// if in meal assist mode, check if snoozeBG is lower, as eventualBG is not dependent on IOB
|
||||
var insulinReq = round( (Math.min(snoozeBG,eventualBG) - target_bg) / sens, 2);
|
||||
if (minDelta < 0 && minDelta > expectedDelta) {
|
||||
var newinsulinReq = round(( insulinReq * (1 - (minDelta / expectedDelta)) ), 2);
|
||||
//console.error("Reducing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
||||
insulinReq = newinsulinReq;
|
||||
}
|
||||
// if that would put us over max_iob, then reduce accordingly
|
||||
if (insulinReq > max_iob-basaliob) {
|
||||
rT.reason += "max_iob " + max_iob + ", ";
|
||||
insulinReq = max_iob-basaliob;
|
||||
}
|
||||
|
||||
// rate required to deliver insulinReq more insulin over 30m:
|
||||
var rate = basal + (2 * insulinReq);
|
||||
rate = round_basal(rate, profile);
|
||||
|
||||
// var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * basal);
|
||||
|
||||
var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
|
||||
|
||||
if (rate > maxSafeBasal) {
|
||||
rT.reason += "adj. req. rate: "+rate+" to maxSafeBasal: "+maxSafeBasal+", ";
|
||||
rate = round_basal(maxSafeBasal, profile);
|
||||
}
|
||||
|
||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||
if (insulinScheduled >= insulinReq * 2) { // if current temp would deliver >2x more than the required insulin, lower the rate
|
||||
rT.reason += currenttemp.duration + "m@" + (currenttemp.rate - basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " > 2 * req " + insulinReq + ". Setting temp basal of " + rate + "U/hr";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
|
||||
if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set
|
||||
rT.reason += "no temp, setting " + rate + "U/hr";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
|
||||
if (currenttemp.duration > 5 && (round_basal(rate, profile) <= round_basal(currenttemp.rate, profile))) { // if required temp <~ existing temp basal
|
||||
rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr";
|
||||
return rT;
|
||||
}
|
||||
|
||||
// required temp > existing temp basal
|
||||
rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = determine_basal;
|
46
app/src/main/assets/OpenAPSAMA/round-basal.js
Normal file
46
app/src/main/assets/OpenAPSAMA/round-basal.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
var endsWith = function endsWith(text, val) {
|
||||
return text.indexOf(val, text.length - val.length) !== -1;
|
||||
}
|
||||
|
||||
var round_basal = function round_basal(basal, profile) {
|
||||
|
||||
/* x23 and x54 pumps change basal increment depending on how much basal is being delivered:
|
||||
0.025u for 0.025 < x < 0.975
|
||||
0.05u for 1 < x < 9.95
|
||||
0.1u for 10 < x
|
||||
To round numbers nicely for the pump, use a scale factor of (1 / increment). */
|
||||
|
||||
var lowest_rate_scale = 20;
|
||||
|
||||
// Has profile even been passed in?
|
||||
if (typeof profile !== 'undefined')
|
||||
{
|
||||
// Make sure optional model has been set
|
||||
if (typeof profile.model == 'string')
|
||||
{
|
||||
if (endsWith(profile.model, "54") || endsWith(profile.model, "23"))
|
||||
{
|
||||
lowest_rate_scale = 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rounded_result = basal;
|
||||
// Shouldn't need to check against 0 as pumps can't deliver negative basal anyway?
|
||||
if (basal < 1)
|
||||
{
|
||||
rounded_basal = Math.round(basal * lowest_rate_scale) / lowest_rate_scale;
|
||||
}
|
||||
else if (basal < 10)
|
||||
{
|
||||
rounded_basal = Math.round(basal * 20) / 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
rounded_basal = Math.round(basal * 10) / 10;
|
||||
}
|
||||
|
||||
return rounded_basal;
|
||||
}
|
||||
|
||||
exports = module.exports = round_basal
|
|
@ -7,7 +7,7 @@ public class Config {
|
|||
// MAIN FUCTIONALITY
|
||||
public static final boolean APS = BuildConfig.APS;
|
||||
// PLUGINS
|
||||
public static final boolean OPENAPSMAENABLED = APS;
|
||||
public static final boolean OPENAPSENABLED = APS;
|
||||
public static final boolean LOOPENABLED = APS;
|
||||
public static final boolean WEAR = BuildConfig.WEAR;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.j256.ormlite.stmt.query.In;
|
|||
* Created by mike on 07.06.2016.
|
||||
*/
|
||||
public class Constants {
|
||||
public static final String MGDL = "mg/dl"; // This is Nightscout representation
|
||||
public static final String MGDL = "mg/dl"; // This is Nightscout's representation
|
||||
public static final String MMOL = "mmol";
|
||||
|
||||
public static final double MMOLL_TO_MGDL = 18; // 18.0182;
|
||||
|
@ -24,8 +24,21 @@ public class Constants {
|
|||
|
||||
public static final long keepAliveMsecs = 5 * 60 * 1000L;
|
||||
|
||||
// SMS COMMUNICATOR
|
||||
|
||||
public static final long remoteBolusMinDistance = 15 * 60 * 1000L;
|
||||
|
||||
|
||||
// AMA
|
||||
public static final int MAX_DAILY_SAFETY_MULTIPLIER = 3;
|
||||
public static final int CURRENT_BASAL_SAFETY_MULTIPLIER = 4;
|
||||
|
||||
public static final int BOLUSSNOOZE_DIA_ADVISOR = 2;
|
||||
public static final double AUTOSENS_MAX = 1.2d;
|
||||
public static final double AUTOSENS_MIN = 0.7d;
|
||||
public static final boolean AUTOSENS_ADJUST_TARGETS = false;
|
||||
public static final double MIN_5M_CARBIMPACT = 3d;
|
||||
|
||||
// Circadian Percentage Profile
|
||||
public static final int CPP_MIN_PERCENTAGE = 50;
|
||||
public static final int CPP_MAX_PERCENTAGE = 200;
|
||||
|
|
|
@ -29,6 +29,7 @@ import info.nightscout.androidaps.plugins.Loop.LoopFragment;
|
|||
import info.nightscout.androidaps.plugins.MDI.MDIFragment;
|
||||
import info.nightscout.androidaps.plugins.NSProfile.NSProfileFragment;
|
||||
import info.nightscout.androidaps.plugins.Objectives.ObjectivesFragment;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAFragment;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAFragment;
|
||||
import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
|
||||
import info.nightscout.androidaps.plugins.SafetyFragment.SafetyFragment;
|
||||
|
@ -38,6 +39,7 @@ import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gFragment;
|
|||
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientFragment;
|
||||
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripFragment;
|
||||
import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.TempTargetRangeFragment;
|
||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
|
||||
import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpFragment;
|
||||
import info.nightscout.androidaps.plugins.Wear.WearFragment;
|
||||
|
@ -82,11 +84,13 @@ public class MainApp extends Application {
|
|||
pluginsList.add(MDIFragment.getPlugin());
|
||||
pluginsList.add(VirtualPumpFragment.getPlugin());
|
||||
if (Config.LOOPENABLED) pluginsList.add(LoopFragment.getPlugin());
|
||||
if (Config.OPENAPSMAENABLED) pluginsList.add(OpenAPSMAFragment.getPlugin());
|
||||
if (Config.OPENAPSENABLED) pluginsList.add(OpenAPSMAFragment.getPlugin());
|
||||
if (Config.OPENAPSENABLED) pluginsList.add(OpenAPSAMAFragment.getPlugin());
|
||||
pluginsList.add(NSProfileFragment.getPlugin());
|
||||
pluginsList.add(SimpleProfileFragment.getPlugin());
|
||||
pluginsList.add(LocalProfileFragment.getPlugin());
|
||||
pluginsList.add(CircadianPercentageProfileFragment.getPlugin());
|
||||
pluginsList.add(TempTargetRangeFragment.getPlugin());
|
||||
pluginsList.add(TreatmentsFragment.getPlugin());
|
||||
pluginsList.add(TempBasalsFragment.getPlugin());
|
||||
pluginsList.add(SafetyFragment.getPlugin());
|
||||
|
|
|
@ -15,9 +15,9 @@ import info.nightscout.androidaps.events.EventPreferenceChange;
|
|||
import info.nightscout.androidaps.events.EventRefreshGui;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.plugins.DanaR.BluetoothDevicePreference;
|
||||
import info.nightscout.androidaps.plugins.DanaR.DanaRFragment;
|
||||
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
|
||||
import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
|
||||
import info.nightscout.utils.LocaleHelper;
|
||||
|
||||
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
@ -85,8 +85,10 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
addPreferencesFromResource(R.xml.pref_treatments);
|
||||
if (Config.APS)
|
||||
addPreferencesFromResource(R.xml.pref_closedmode);
|
||||
if (Config.OPENAPSMAENABLED)
|
||||
if (Config.OPENAPSENABLED)
|
||||
addPreferencesFromResource(R.xml.pref_openapsma);
|
||||
if (MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class).isEnabled(PluginBase.APS))
|
||||
addPreferencesFromResource(R.xml.pref_openapsama);
|
||||
addPreferencesFromResource(R.xml.pref_nightscout);
|
||||
if (Config.DANAR) {
|
||||
DanaRPlugin danaRPlugin = (DanaRPlugin) MainApp.getSpecificPlugin(DanaRPlugin.class);
|
||||
|
|
|
@ -29,6 +29,7 @@ import info.nightscout.androidaps.MainApp;
|
|||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.DanaRHistoryRecord;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.db.Treatment;
|
||||
import info.nightscout.androidaps.events.EventNewBG;
|
||||
import info.nightscout.androidaps.events.EventNewBasalProfile;
|
||||
|
@ -39,12 +40,16 @@ import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
|||
import info.nightscout.androidaps.plugins.DanaR.History.DanaRNSHistorySync;
|
||||
import info.nightscout.androidaps.plugins.NSProfile.NSProfilePlugin;
|
||||
import info.nightscout.androidaps.plugins.Objectives.ObjectivesPlugin;
|
||||
import info.nightscout.androidaps.plugins.Overview.Notification;
|
||||
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
|
||||
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
|
||||
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
|
||||
import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin;
|
||||
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin;
|
||||
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.events.EventTempTargetRangeChange;
|
||||
import info.nightscout.androidaps.receivers.DataReceiver;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.client.data.NSSgv;
|
||||
|
@ -251,10 +256,15 @@ public class DataService extends IntentService {
|
|||
ConfigBuilderPlugin.nsClientVersionCode = bundles.getInt("nsclientversioncode"); // for ver 1.17 contains 117
|
||||
ConfigBuilderPlugin.nsClientVersionName = bundles.getString("nsclientversionname");
|
||||
log.debug("Got versions: NSClient: " + ConfigBuilderPlugin.nsClientVersionName + " Nightscout: " + ConfigBuilderPlugin.nightscoutVersionName);
|
||||
if (ConfigBuilderPlugin.nsClientVersionCode < 118)
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.unsupportedclientver));
|
||||
if (ConfigBuilderPlugin.nsClientVersionCode < 121) {
|
||||
Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.sResources.getString(R.string.unsupportedclientver), Notification.URGENT);
|
||||
MainApp.bus().post(new EventNewNotification(notification));
|
||||
} else {
|
||||
MainApp.bus().post(new EventDismissNotification(Notification.OLD_NSCLIENT));
|
||||
}
|
||||
} else {
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.unsupportedclientver));
|
||||
Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.sResources.getString(R.string.unsupportedclientver), Notification.URGENT);
|
||||
MainApp.bus().post(new EventNewNotification(notification));
|
||||
}
|
||||
if (bundles.containsKey("status")) {
|
||||
try {
|
||||
|
@ -379,6 +389,7 @@ public class DataService extends IntentService {
|
|||
JSONObject trJson = new JSONObject(trstring);
|
||||
String _id = trJson.getString("_id");
|
||||
removeTreatmentFromDb(_id);
|
||||
handleRemoveTempTargetRecord(trJson);
|
||||
}
|
||||
|
||||
if (bundles.containsKey("treatments")) {
|
||||
|
@ -388,6 +399,7 @@ public class DataService extends IntentService {
|
|||
JSONObject trJson = jsonArray.getJSONObject(i);
|
||||
String _id = trJson.getString("_id");
|
||||
removeTreatmentFromDb(_id);
|
||||
handleRemoveTempTargetRecord(trJson);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -443,6 +455,7 @@ public class DataService extends IntentService {
|
|||
private void handleAddedTreatment(String trstring) throws JSONException, SQLException {
|
||||
JSONObject trJson = new JSONObject(trstring);
|
||||
handleDanaRHistoryRecords(trJson); // update record _id in history
|
||||
handleAddChangeTempTargetRecord(trJson);
|
||||
if (!trJson.has("insulin") && !trJson.has("carbs")) {
|
||||
if (Config.logIncommingData)
|
||||
log.debug("ADD: Uninterested treatment: " + trstring);
|
||||
|
@ -480,8 +493,16 @@ public class DataService extends IntentService {
|
|||
treatment.created_at = new Date(trJson.getLong("mills"));
|
||||
if (trJson.has("eventType")) {
|
||||
treatment.mealBolus = true;
|
||||
if (trJson.get("eventType").equals("Correction Bolus")) treatment.mealBolus = false;
|
||||
if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0)
|
||||
if (trJson.get("eventType").equals("Correction Bolus"))
|
||||
treatment.mealBolus = false;
|
||||
double carbs = treatment.carbs;
|
||||
if (trJson.has("boluscalc")) {
|
||||
JSONObject boluscalc = trJson.getJSONObject("boluscalc");
|
||||
if (boluscalc.has("carbs")) {
|
||||
carbs = Math.max(boluscalc.getDouble("carbs"), carbs);
|
||||
}
|
||||
}
|
||||
if (carbs <= 0)
|
||||
treatment.mealBolus = false;
|
||||
}
|
||||
treatment.setTimeIndex(treatment.getTimeIndex());
|
||||
|
@ -499,6 +520,7 @@ public class DataService extends IntentService {
|
|||
private void handleChangedTreatment(String trstring) throws JSONException, SQLException {
|
||||
JSONObject trJson = new JSONObject(trstring);
|
||||
handleDanaRHistoryRecords(trJson); // update record _id in history
|
||||
handleAddChangeTempTargetRecord(trJson);
|
||||
if (!trJson.has("insulin") && !trJson.has("carbs")) {
|
||||
if (Config.logIncommingData)
|
||||
log.debug("CHANGE: Uninterested treatment: " + trstring);
|
||||
|
@ -532,8 +554,16 @@ public class DataService extends IntentService {
|
|||
treatment.created_at = new Date(trJson.getLong("mills"));
|
||||
if (trJson.has("eventType")) {
|
||||
treatment.mealBolus = true;
|
||||
if (trJson.get("eventType").equals("Correction Bolus")) treatment.mealBolus = false;
|
||||
if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0)
|
||||
if (trJson.get("eventType").equals("Correction Bolus"))
|
||||
treatment.mealBolus = false;
|
||||
double carbs = treatment.carbs;
|
||||
if (trJson.has("boluscalc")) {
|
||||
JSONObject boluscalc = trJson.getJSONObject("boluscalc");
|
||||
if (boluscalc.has("carbs")) {
|
||||
carbs = Math.max(boluscalc.getDouble("carbs"), carbs);
|
||||
}
|
||||
}
|
||||
if (carbs <= 0)
|
||||
treatment.mealBolus = false;
|
||||
}
|
||||
treatment.setTimeIndex(treatment.getTimeIndex());
|
||||
|
@ -573,6 +603,86 @@ public class DataService extends IntentService {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"_id": "58795998aa86647ba4d68ce7",
|
||||
"enteredBy": "",
|
||||
"eventType": "Temporary Target",
|
||||
"reason": "Eating Soon",
|
||||
"targetTop": 80,
|
||||
"targetBottom": 80,
|
||||
"duration": 120,
|
||||
"created_at": "2017-01-13T22:50:00.782Z",
|
||||
"carbs": null,
|
||||
"insulin": null
|
||||
}
|
||||
*/
|
||||
|
||||
public void handleAddChangeTempTargetRecord(JSONObject trJson) throws JSONException, SQLException {
|
||||
if (trJson.has("eventType") && trJson.getString("eventType").equals("Temporary Target")) {
|
||||
if (Config.logIncommingData)
|
||||
log.debug("Processing TempTarget record: " + trJson.toString());
|
||||
Dao<TempTarget, Long> daoTempTargets = MainApp.getDbHelper().getDaoTempTargets();
|
||||
QueryBuilder<TempTarget, Long> queryBuilder = daoTempTargets.queryBuilder();
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("_id", trJson.getString("_id")).or().eq("timeIndex", trJson.getLong("mills"));
|
||||
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
|
||||
List<TempTarget> list = daoTempTargets.query(preparedQuery);
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
if (profile == null) return; // no profile data, better ignore than do something wrong
|
||||
String units = profile.getUnits();
|
||||
if (list.size() == 0) {
|
||||
// Record does not exists. add
|
||||
TempTarget newRecord = new TempTarget();
|
||||
newRecord.timeStart = new Date(trJson.getLong("mills"));
|
||||
newRecord.duration = trJson.getInt("duration");
|
||||
newRecord.low = NSProfile.toMgdl(trJson.getDouble("targetBottom"), units);
|
||||
newRecord.high = NSProfile.toMgdl(trJson.getDouble("targetTop"), units);
|
||||
newRecord.reason = trJson.getString("reason");
|
||||
newRecord._id = trJson.getString("_id");
|
||||
newRecord.setTimeIndex(newRecord.getTimeIndex());
|
||||
daoTempTargets.createIfNotExists(newRecord);
|
||||
if (Config.logIncommingData)
|
||||
log.debug("Adding TempTarget record to database: " + newRecord.log());
|
||||
MainApp.bus().post(new EventTempTargetRangeChange());
|
||||
} else if (list.size() == 1) {
|
||||
if (Config.logIncommingData)
|
||||
log.debug("Updating TempTarget record in database: " + trJson.getString("_id"));
|
||||
TempTarget record = list.get(0);
|
||||
record.timeStart = new Date(trJson.getLong("mills"));
|
||||
record.duration = trJson.getInt("duration");
|
||||
record.low = NSProfile.toMgdl(trJson.getDouble("targetBottom"), units);
|
||||
record.high = NSProfile.toMgdl(trJson.getDouble("targetTop"), units);
|
||||
record.reason = trJson.getString("reason");
|
||||
record._id = trJson.getString("_id");
|
||||
daoTempTargets.update(record);
|
||||
MainApp.bus().post(new EventTempTargetRangeChange());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRemoveTempTargetRecord(JSONObject trJson) throws JSONException, SQLException {
|
||||
if (trJson.has("_id")) {
|
||||
Dao<TempTarget, Long> daoTempTargets = MainApp.getDbHelper().getDaoTempTargets();
|
||||
QueryBuilder<TempTarget, Long> queryBuilder = daoTempTargets.queryBuilder();
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("_id", trJson.getString("_id"));
|
||||
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
|
||||
List<TempTarget> list = daoTempTargets.query(preparedQuery);
|
||||
|
||||
if (list.size() == 1) {
|
||||
TempTarget record = list.get(0);
|
||||
if (Config.logIncommingData)
|
||||
log.debug("Removing TempTarget record from database: " + record.log());
|
||||
daoTempTargets.delete(record);
|
||||
MainApp.bus().post(new EventTempTargetRangeChange());
|
||||
} else {
|
||||
if (Config.logIncommingData)
|
||||
log.debug("TempTarget not found database: " + trJson.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Treatment findById(String _id) {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
import info.nightscout.utils.Round;
|
||||
|
||||
/**
|
||||
* Created by mike on 04.01.2017.
|
||||
*/
|
||||
|
||||
public class GlucoseStatus {
|
||||
public double glucose = 0d;
|
||||
public double delta = 0d;
|
||||
public double avgdelta = 0d;
|
||||
public double short_avgdelta = 0d;
|
||||
public double long_avgdelta = 0d;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MainApp.sResources.getString(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" +
|
||||
MainApp.sResources.getString(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" +
|
||||
MainApp.sResources.getString(R.string.short_avgdelta) + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl\n" +
|
||||
MainApp.sResources.getString(R.string.long_avgdelta) + " " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
|
||||
}
|
||||
|
||||
public Spanned toSpanned() {
|
||||
return Html.fromHtml("<b>" + MainApp.sResources.getString(R.string.glucose) + "</b>: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl<br>" +
|
||||
"<b>" + MainApp.sResources.getString(R.string.delta) + "</b>: " + DecimalFormatter.to0Decimal(delta) + " mg/dl<br>" +
|
||||
"<b>" + MainApp.sResources.getString(R.string.short_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl<br>" +
|
||||
"<b>" + MainApp.sResources.getString(R.string.long_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl");
|
||||
}
|
||||
|
||||
public GlucoseStatus() {
|
||||
}
|
||||
|
||||
public GlucoseStatus round() {
|
||||
this.glucose = Round.roundTo(this.glucose, 0.1);
|
||||
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);
|
||||
this.long_avgdelta = Round.roundTo(this.long_avgdelta, 0.01);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GlucoseStatus getGlucoseStatusData() {
|
||||
// load 45min
|
||||
long fromtime = (long) (new Date().getTime() - 60 * 1000L * 45);
|
||||
List<BgReading> data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false);
|
||||
|
||||
int sizeRecords = data.size();
|
||||
if (sizeRecords < 4 || data.get(0).timeIndex < new Date().getTime() - 7 * 60 * 1000L) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BgReading now = data.get(0);
|
||||
long now_date = now.timeIndex;
|
||||
double change;
|
||||
|
||||
ArrayList<Double> last_deltas = new ArrayList<Double>();
|
||||
ArrayList<Double> short_deltas = new ArrayList<Double>();
|
||||
ArrayList<Double> long_deltas = new ArrayList<Double>();
|
||||
|
||||
for (int i = 1; i < data.size(); i++) {
|
||||
if (data.get(i).value > 38) {
|
||||
BgReading then = data.get(i);
|
||||
long then_date = then.timeIndex;
|
||||
double avgdelta = 0;
|
||||
int minutesago;
|
||||
|
||||
minutesago = Math.round((now_date - then_date) / (1000 * 60));
|
||||
// multiply by 5 to get the same units as delta, i.e. mg/dL/5m
|
||||
change = now.value - then.value;
|
||||
avgdelta = change / minutesago * 5;
|
||||
|
||||
// use the average of all data points in the last 2.5m for all further "now" calculations
|
||||
if (0 < minutesago && minutesago < 2.5) {
|
||||
now.value = (now.value + then.value) / 2;
|
||||
now_date = (now_date + then_date) / 2;
|
||||
// short_deltas are calculated from everything ~5-15 minutes ago
|
||||
} else if (2.5 < minutesago && minutesago < 17.5) {
|
||||
//console.error(minutesago, avgdelta);
|
||||
short_deltas.add(avgdelta);
|
||||
// last_deltas are calculated from everything ~5 minutes ago
|
||||
if (2.5 < minutesago && minutesago < 7.5) {
|
||||
last_deltas.add(avgdelta);
|
||||
}
|
||||
// long_deltas are calculated from everything ~20-40 minutes ago
|
||||
} else if (17.5 < minutesago && minutesago < 42.5) {
|
||||
long_deltas.add(avgdelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlucoseStatus status = new GlucoseStatus();
|
||||
status.glucose = now.value;
|
||||
status.delta = average(last_deltas);
|
||||
status.short_avgdelta = average(short_deltas);
|
||||
status.long_avgdelta = average(long_deltas);
|
||||
status.avgdelta = status.short_avgdelta; // for OpenAPS MA
|
||||
|
||||
return status.round();
|
||||
}
|
||||
|
||||
public static double average(ArrayList<Double> array) {
|
||||
double sum = 0d;
|
||||
|
||||
if (array.size() == 0)
|
||||
return 0d;
|
||||
|
||||
for (Double value : array) {
|
||||
sum += value;
|
||||
}
|
||||
return sum / array.size();
|
||||
}
|
||||
}
|
137
app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
Normal file
137
app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.Round;
|
||||
|
||||
public class IobTotal {
|
||||
public Double iob;
|
||||
public Double activity;
|
||||
public Double bolussnooze;
|
||||
public Double basaliob;
|
||||
public Double netbasalinsulin;
|
||||
public Double hightempinsulin;
|
||||
|
||||
public Double netInsulin = 0d; // for calculations from temp basals only
|
||||
public Double netRatio = 0d; // for calculations from temp basals only
|
||||
|
||||
long time;
|
||||
|
||||
public IobTotal(long time) {
|
||||
this.iob = 0d;
|
||||
this.activity = 0d;
|
||||
this.bolussnooze = 0d;
|
||||
this.basaliob = 0d;
|
||||
this.netbasalinsulin = 0d;
|
||||
this.hightempinsulin = 0d;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public IobTotal plus(IobTotal other) {
|
||||
iob += other.iob;
|
||||
activity += other.activity;
|
||||
bolussnooze += other.bolussnooze;
|
||||
basaliob += other.basaliob;
|
||||
netbasalinsulin += other.netbasalinsulin;
|
||||
hightempinsulin += other.hightempinsulin;
|
||||
netInsulin += other.netInsulin;
|
||||
netRatio += other.netRatio;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static IobTotal combine(IobTotal bolusIOB, IobTotal basalIob) {
|
||||
IobTotal result = new IobTotal(bolusIOB.time);
|
||||
result.iob = bolusIOB.iob + basalIob.basaliob;
|
||||
result.activity = bolusIOB.activity + basalIob.activity;
|
||||
result.bolussnooze = bolusIOB.bolussnooze;
|
||||
result.basaliob = basalIob.basaliob;
|
||||
result.netbasalinsulin = basalIob.netbasalinsulin;
|
||||
result.hightempinsulin = basalIob.hightempinsulin;
|
||||
return result;
|
||||
}
|
||||
|
||||
public IobTotal round() {
|
||||
this.iob = Round.roundTo(this.iob, 0.001);
|
||||
this.activity = Round.roundTo(this.activity, 0.0001);
|
||||
this.bolussnooze = Round.roundTo(this.bolussnooze, 0.0001);
|
||||
this.basaliob = Round.roundTo(this.basaliob, 0.001);
|
||||
this.netbasalinsulin = Round.roundTo(this.netbasalinsulin, 0.001);
|
||||
this.hightempinsulin = Round.roundTo(this.hightempinsulin, 0.001);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("iob", iob);
|
||||
json.put("basaliob", basaliob);
|
||||
json.put("activity", activity);
|
||||
json.put("time", DateUtil.toISOString(new Date()));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public JSONObject determineBasalJson() {
|
||||
JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("iob", iob);
|
||||
json.put("basaliob", basaliob);
|
||||
json.put("bolussnooze", bolussnooze);
|
||||
json.put("activity", activity);
|
||||
json.put("time", DateUtil.toISOString(new Date(time)));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public static IobTotal calulateFromTreatmentsAndTemps() {
|
||||
ConfigBuilderPlugin.getActiveTreatments().updateTotalIOB();
|
||||
IobTotal bolusIob = ConfigBuilderPlugin.getActiveTreatments().getLastCalculation().round();
|
||||
ConfigBuilderPlugin.getActiveTempBasals().updateTotalIOB();
|
||||
IobTotal basalIob = ConfigBuilderPlugin.getActiveTempBasals().getLastCalculation().round();
|
||||
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
|
||||
return iobTotal;
|
||||
}
|
||||
|
||||
public static IobTotal calulateFromTreatmentsAndTemps(long time) {
|
||||
IobTotal bolusIob = ConfigBuilderPlugin.getActiveTreatments().getCalculationToTime(time).round();
|
||||
IobTotal basalIob = ConfigBuilderPlugin.getActiveTempBasals().getCalculationToTime(time).round();
|
||||
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
|
||||
return iobTotal;
|
||||
}
|
||||
|
||||
public static IobTotal[] calculateIobArrayInDia() {
|
||||
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
|
||||
// predict IOB out to DIA plus 30m
|
||||
long time = new Date().getTime();
|
||||
int len = (int) ((profile.getDia() *60 + 30) / 5);
|
||||
IobTotal[] array = new IobTotal[len];
|
||||
int pos = 0;
|
||||
for (int i = 0; i < len; i++){
|
||||
long t = time + i * 5 * 60000;
|
||||
IobTotal iob = calulateFromTreatmentsAndTemps(t);
|
||||
array[pos] = iob;
|
||||
pos++;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static JSONArray convertToJSONArray(IobTotal[] iobArray) {
|
||||
JSONArray array = new JSONArray();
|
||||
for (int i = 0; i < iobArray.length; i ++) {
|
||||
array.put(iobArray[i].determineBasalJson());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.Treatment;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.Autosens;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.AutosensResult;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
|
||||
/**
|
||||
* Created by mike on 04.01.2017.
|
||||
*/
|
||||
public class MealData {
|
||||
public double boluses = 0d;
|
||||
public double carbs = 0d;
|
||||
public double mealCOB = 0.0d; // TODO: add calculation for AMA
|
||||
|
||||
|
||||
public void addTreatment(Treatment treatment) {
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
if (profile == null) return;
|
||||
|
||||
// TODO: not sure how much data do i need for AMA
|
||||
List<BgReading> bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (new Date().getTime() - 60 * 60 * 1000L * profile.getDia() * 2), false);
|
||||
|
||||
long now = new Date().getTime();
|
||||
long dia_ago = now - (new Double(profile.getDia() * 60 * 60 * 1000l)).longValue();
|
||||
long t = treatment.created_at.getTime();
|
||||
if (t > dia_ago && t <= now) {
|
||||
if (treatment.carbs >= 1) {
|
||||
carbs += treatment.carbs;
|
||||
AutosensResult result = Autosens.detectSensitivityandCarbAbsorption(bgReadings, t);
|
||||
double myCarbsAbsorbed = result.carbsAbsorbed;
|
||||
double myMealCOB = Math.max(0, carbs - myCarbsAbsorbed);
|
||||
mealCOB = Math.max(mealCOB, myMealCOB);
|
||||
}
|
||||
if (treatment.insulin > 0 && treatment.mealBolus) {
|
||||
boluses += treatment.insulin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import info.nightscout.client.data.NSProfile;
|
|||
import info.nightscout.utils.DecimalFormatter;
|
||||
import info.nightscout.utils.Round;
|
||||
|
||||
public class PumpEnactResult extends Object implements Parcelable {
|
||||
public class PumpEnactResult extends Object {
|
||||
public boolean success = false; // request was processed successfully (but possible no change was needed)
|
||||
public boolean enacted = false; // request was processed successfully and change has been made
|
||||
public String comment = "";
|
||||
|
@ -85,43 +85,6 @@ public class PumpEnactResult extends Object implements Parcelable {
|
|||
return Html.fromHtml(ret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(success ? 1 : 0);
|
||||
dest.writeInt(enacted ? 1 : 0);
|
||||
dest.writeInt(isPercent ? 1 : 0);
|
||||
dest.writeString(comment);
|
||||
dest.writeInt(duration);
|
||||
dest.writeDouble(absolute);
|
||||
dest.writeInt(percent);
|
||||
}
|
||||
|
||||
public final Parcelable.Creator<PumpEnactResult> CREATOR = new Parcelable.Creator<PumpEnactResult>() {
|
||||
public PumpEnactResult createFromParcel(Parcel in) {
|
||||
return new PumpEnactResult(in);
|
||||
}
|
||||
|
||||
public PumpEnactResult[] newArray(int size) {
|
||||
return new PumpEnactResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected PumpEnactResult(Parcel in) {
|
||||
success = in.readInt() == 1 ? true : false;
|
||||
enacted = in.readInt() == 1 ? true : false;
|
||||
isPercent = in.readInt() == 1 ? true : false;
|
||||
duration = in.readInt();
|
||||
comment = in.readString();
|
||||
absolute = in.readDouble();
|
||||
percent = in.readInt();
|
||||
|
||||
}
|
||||
|
||||
public PumpEnactResult() {
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,7 @@ package info.nightscout.androidaps.db;
|
|||
import android.content.Context;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
|
||||
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
|
@ -27,9 +23,7 @@ import java.util.List;
|
|||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
import info.nightscout.utils.Round;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
|
||||
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||
private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class);
|
||||
|
@ -37,6 +31,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
public static final String DATABASE_NAME = "AndroidAPSDb";
|
||||
public static final String DATABASE_BGREADINGS = "BgReadings";
|
||||
public static final String DATABASE_TEMPBASALS = "TempBasals";
|
||||
public static final String DATABASE_TEMPTARGETS = "TempTargets";
|
||||
public static final String DATABASE_TREATMENTS = "Treatments";
|
||||
public static final String DATABASE_DANARHISTORY = "DanaRHistory";
|
||||
|
||||
|
@ -44,6 +39,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
|
||||
public DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
onCreate(getWritableDatabase(), getConnectionSource());
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,11 +48,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
try {
|
||||
log.info("onCreate");
|
||||
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
|
||||
} catch (SQLException e) {
|
||||
log.error(DatabaseHelper.class.getName(), "Can't create database", e);
|
||||
log.error("Can't create database", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
@ -66,12 +63,13 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
try {
|
||||
log.info(DatabaseHelper.class.getName(), "onUpgrade");
|
||||
TableUtils.dropTable(connectionSource, TempBasal.class, true);
|
||||
TableUtils.dropTable(connectionSource, TempTarget.class, true);
|
||||
TableUtils.dropTable(connectionSource, Treatment.class, true);
|
||||
TableUtils.dropTable(connectionSource, BgReading.class, true);
|
||||
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
|
||||
onCreate(database, connectionSource);
|
||||
} catch (SQLException e) {
|
||||
log.error(DatabaseHelper.class.getName(), "Can't drop databases", e);
|
||||
log.error("Can't drop databases", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
@ -87,35 +85,38 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
public void cleanUpDatabases() {
|
||||
// TODO: call it somewhere
|
||||
log.debug("Before BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
|
||||
getWritableDatabase().delete("BgReadings", "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
|
||||
getWritableDatabase().delete(DATABASE_BGREADINGS, "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
|
||||
log.debug("After BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
|
||||
|
||||
log.debug("Before TempBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPBASALS));
|
||||
getWritableDatabase().delete("TempBasals", "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
|
||||
getWritableDatabase().delete(DATABASE_TEMPBASALS, "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
|
||||
log.debug("After TempBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPBASALS));
|
||||
|
||||
log.debug("Before TempTargets size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPTARGETS));
|
||||
getWritableDatabase().delete(DATABASE_TEMPTARGETS, "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
|
||||
log.debug("After TempTargets size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPTARGETS));
|
||||
|
||||
log.debug("Before Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
|
||||
getWritableDatabase().delete("Treatments", "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
|
||||
getWritableDatabase().delete(DATABASE_TREATMENTS, "timeIndex" + " < '" + (new Date().getTime() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
|
||||
log.debug("After Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
|
||||
|
||||
log.debug("Before History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), "DanaRHistory"));
|
||||
getWritableDatabase().delete("History", "recordDate" + " < '" + (new Date().getTime() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
|
||||
log.debug("After History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), "DanaRHistory"));
|
||||
log.debug("Before History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_DANARHISTORY));
|
||||
getWritableDatabase().delete(DATABASE_DANARHISTORY, "recordDate" + " < '" + (new Date().getTime() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
|
||||
log.debug("After History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_DANARHISTORY));
|
||||
}
|
||||
|
||||
public void resetDatabases() {
|
||||
try {
|
||||
TableUtils.dropTable(connectionSource, TempBasal.class, true);
|
||||
TableUtils.dropTable(connectionSource, TempTarget.class, true);
|
||||
TableUtils.dropTable(connectionSource, Treatment.class, true);
|
||||
TableUtils.dropTable(connectionSource, BgReading.class, true);
|
||||
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
|
||||
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
|
||||
// MainApp.bus().post(new EventNewBG());
|
||||
// MainApp.bus().post(new EventTreatmentChange());
|
||||
// MainApp.bus().post(new EventTempBasalChange());
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -123,7 +124,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
|
||||
public void resetTreatments() {
|
||||
try {
|
||||
|
||||
TableUtils.dropTable(connectionSource, Treatment.class, true);
|
||||
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
|
||||
} catch (SQLException e) {
|
||||
|
@ -131,10 +131,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public void resetTempTargets() {
|
||||
try {
|
||||
TableUtils.dropTable(connectionSource, TempTarget.class, true);
|
||||
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Dao<TempBasal, Long> getDaoTempBasals() throws SQLException {
|
||||
return getDao(TempBasal.class);
|
||||
}
|
||||
|
||||
public Dao<TempTarget, Long> getDaoTempTargets() throws SQLException {
|
||||
return getDao(TempTarget.class);
|
||||
}
|
||||
|
||||
public Dao<Treatment, Long> getDaoTreatments() throws SQLException {
|
||||
return getDao(Treatment.class);
|
||||
}
|
||||
|
@ -189,12 +202,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
public List<BgReading> getDataFromTime(long mills) {
|
||||
public List<BgReading> getBgreadingsDataFromTime(long mills, boolean ascending) {
|
||||
try {
|
||||
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
|
||||
List<BgReading> bgReadings;
|
||||
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", true);
|
||||
queryBuilder.orderBy("timeIndex", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.ge("timeIndex", mills).and().gt("value", 38);
|
||||
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
|
||||
|
@ -206,126 +219,56 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return new ArrayList<BgReading>();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns glucose_status for openAPS or null if no actual data available
|
||||
*/
|
||||
public static class GlucoseStatus implements Parcelable {
|
||||
public double glucose = 0d;
|
||||
public double delta = 0d;
|
||||
public double avgdelta = 0d;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MainApp.sResources.getString(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" +
|
||||
MainApp.sResources.getString(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" +
|
||||
MainApp.sResources.getString(R.string.avgdelta) + " " + DecimalFormatter.to2Decimal(avgdelta) + " mg/dl";
|
||||
}
|
||||
|
||||
public Spanned toSpanned() {
|
||||
return Html.fromHtml("<b>" + MainApp.sResources.getString(R.string.glucose) + "</b>: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl<br>" +
|
||||
"<b>" + MainApp.sResources.getString(R.string.delta) + "</b>: " + DecimalFormatter.to0Decimal(delta) + " mg/dl<br>" +
|
||||
"<b>" + MainApp.sResources.getString(R.string.avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(avgdelta) + " mg/dl");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeDouble(avgdelta);
|
||||
dest.writeDouble(delta);
|
||||
dest.writeDouble(glucose);
|
||||
}
|
||||
|
||||
public final Parcelable.Creator<GlucoseStatus> CREATOR = new Parcelable.Creator<GlucoseStatus>() {
|
||||
public GlucoseStatus createFromParcel(Parcel in) {
|
||||
return new GlucoseStatus(in);
|
||||
}
|
||||
|
||||
public GlucoseStatus[] newArray(int size) {
|
||||
return new GlucoseStatus[size];
|
||||
}
|
||||
};
|
||||
|
||||
private GlucoseStatus(Parcel in) {
|
||||
avgdelta = in.readDouble();
|
||||
delta = in.readDouble();
|
||||
glucose = in.readDouble();
|
||||
}
|
||||
|
||||
public GlucoseStatus() {
|
||||
}
|
||||
|
||||
public GlucoseStatus(Double glucose, Double delta, Double avgdelta) {
|
||||
this.glucose = glucose;
|
||||
this.delta = delta;
|
||||
this.avgdelta = avgdelta;
|
||||
}
|
||||
|
||||
public GlucoseStatus round() {
|
||||
this.glucose = Round.roundTo(this.glucose, 0.1);
|
||||
this.delta = Round.roundTo(this.delta, 0.01);
|
||||
this.avgdelta = Round.roundTo(this.avgdelta, 0.01);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GlucoseStatus getGlucoseStatusData() {
|
||||
GlucoseStatus result = new GlucoseStatus();
|
||||
public List<Treatment> getTreatmentDataFromTime(long mills, boolean ascending) {
|
||||
try {
|
||||
|
||||
Dao<BgReading, Long> daoBgreadings = null;
|
||||
daoBgreadings = getDaoBgReadings();
|
||||
List<BgReading> bgReadings;
|
||||
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", false);
|
||||
queryBuilder.where().gt("value", 38);
|
||||
queryBuilder.limit(4l);
|
||||
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
|
||||
bgReadings = daoBgreadings.query(preparedQuery);
|
||||
|
||||
int sizeRecords = bgReadings.size();
|
||||
|
||||
if (sizeRecords < 4 || bgReadings.get(sizeRecords - 4).timeIndex < new Date().getTime() - 7 * 60 * 1000L) {
|
||||
return null;
|
||||
}
|
||||
|
||||
double minutes = 5;
|
||||
double change;
|
||||
double avg;
|
||||
|
||||
if (bgReadings.size() > 3) {
|
||||
BgReading now = bgReadings.get(sizeRecords - 4);
|
||||
BgReading last = bgReadings.get(sizeRecords - 3);
|
||||
BgReading last1 = bgReadings.get(sizeRecords - 2);
|
||||
BgReading last2 = bgReadings.get(sizeRecords - 1);
|
||||
if (last2.value > 38) {
|
||||
minutes = (now.timeIndex - last2.timeIndex)/(60d*1000);
|
||||
change = now.value - last2.value;
|
||||
} else if (last1.value > 38) {
|
||||
minutes = (now.timeIndex - last1.timeIndex)/(60d*1000);;
|
||||
change = now.value - last1.value;
|
||||
} else if (last.value > 38) {
|
||||
minutes = (now.timeIndex - last.timeIndex)/(60d*1000);
|
||||
change = now.value - last.value;
|
||||
} else {
|
||||
change = 0;
|
||||
}
|
||||
//multiply by 5 to get the same unit as delta, i.e. mg/dL/5m
|
||||
avg = change / minutes * 5;
|
||||
|
||||
result.glucose = now.value;
|
||||
result.delta = (now.value - last.value)*5*60*1000/(now.getTimeIndex() - last.getTimeIndex());
|
||||
result.avgdelta = avg;
|
||||
}
|
||||
Dao<Treatment, Long> daoTreatments = getDaoTreatments();
|
||||
List<Treatment> treatments;
|
||||
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.ge("timeIndex", mills);
|
||||
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
|
||||
treatments = daoTreatments.query(preparedQuery);
|
||||
return treatments;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
result.round();
|
||||
return result;
|
||||
return new ArrayList<Treatment>();
|
||||
}
|
||||
|
||||
public List<TempTarget> getTemptargetsDataFromTime(long mills, boolean ascending) {
|
||||
try {
|
||||
Dao<TempTarget, Long> daoTempTargets = getDaoTempTargets();
|
||||
List<TempTarget> tempTargets;
|
||||
QueryBuilder<TempTarget, Long> queryBuilder = daoTempTargets.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.ge("timeIndex", mills);
|
||||
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
|
||||
tempTargets = daoTempTargets.query(preparedQuery);
|
||||
return tempTargets;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new ArrayList<TempTarget>();
|
||||
}
|
||||
|
||||
|
||||
public List<TempBasal> getTempbasalsDataFromTime(long mills, boolean ascending, boolean isExtended) {
|
||||
try {
|
||||
Dao<TempBasal, Long> daoTempbasals = getDaoTempBasals();
|
||||
List<TempBasal> tempbasals;
|
||||
QueryBuilder<TempBasal, Long> queryBuilder = daoTempbasals.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.ge("timeIndex", mills).and().eq("isExtended", isExtended);
|
||||
PreparedQuery<TempBasal> preparedQuery = queryBuilder.prepare();
|
||||
tempbasals = daoTempbasals.query(preparedQuery);
|
||||
return tempbasals;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new ArrayList<TempBasal>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import java.util.Date;
|
|||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.data.Iob;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
|
@ -53,7 +53,7 @@ public class TempBasal {
|
|||
|
||||
|
||||
public IobTotal iobCalc(Date time) {
|
||||
IobTotal result = new IobTotal();
|
||||
IobTotal result = new IobTotal(time.getTime());
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
|
||||
if (profile == null)
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package info.nightscout.androidaps.db;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.TempTargetRangePlugin;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
|
||||
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPTARGETS)
|
||||
public class TempTarget {
|
||||
private static Logger log = LoggerFactory.getLogger(TempTarget.class);
|
||||
|
||||
public long getTimeIndex() {
|
||||
return timeStart.getTime() - timeStart.getTime() % 1000;
|
||||
}
|
||||
|
||||
public void setTimeIndex(long timeIndex) {
|
||||
this.timeIndex = timeIndex;
|
||||
}
|
||||
|
||||
@DatabaseField(id = true, useGetSet = true)
|
||||
public long timeIndex;
|
||||
|
||||
@DatabaseField
|
||||
public Date timeStart;
|
||||
|
||||
@DatabaseField
|
||||
public double low; // in mgdl
|
||||
|
||||
@DatabaseField
|
||||
public double high; // in mgdl
|
||||
|
||||
@DatabaseField
|
||||
public String reason;
|
||||
|
||||
@DatabaseField
|
||||
public int duration; // in minutes
|
||||
|
||||
@DatabaseField
|
||||
public String _id; // NS _id
|
||||
|
||||
public Date getPlannedTimeEnd() {
|
||||
return new Date(timeStart.getTime() + 60 * 1_000 * duration);
|
||||
}
|
||||
|
||||
public String lowValueToUnitsToString(String units) {
|
||||
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(low);
|
||||
else return DecimalFormatter.to1Decimal(low * Constants.MGDL_TO_MMOLL);
|
||||
}
|
||||
|
||||
public String highValueToUnitsToString(String units) {
|
||||
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(high);
|
||||
else return DecimalFormatter.to1Decimal(low * Constants.MGDL_TO_MMOLL);
|
||||
}
|
||||
|
||||
public boolean isInProgress() {
|
||||
return ((TempTargetRangePlugin) MainApp.getSpecificPlugin(TempTargetRangePlugin.class)).getTempTargetInProgress(new Date().getTime()) == this;
|
||||
}
|
||||
|
||||
public String log() {
|
||||
return "TempTarget{" +
|
||||
"timeIndex=" + timeIndex +
|
||||
", timeStart=" + timeStart +
|
||||
", duration=" + duration +
|
||||
", reason=" + reason +
|
||||
", low=" + low +
|
||||
", high=" + high +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -11,5 +11,5 @@ public interface APSInterface {
|
|||
public APSResult getLastAPSResult();
|
||||
public Date getLastAPSRun();
|
||||
|
||||
public void invoke();
|
||||
public void invoke(String initiator);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package info.nightscout.androidaps.interfaces;
|
|||
import java.util.Date;
|
||||
|
||||
import info.nightscout.androidaps.db.TempBasal;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
|
||||
/**
|
||||
* Created by mike on 14.06.2016.
|
||||
|
@ -11,7 +11,10 @@ import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
|||
public interface TempBasalsInterface {
|
||||
void updateTotalIOB();
|
||||
IobTotal getLastCalculation();
|
||||
IobTotal getCalculationToTime(long time);
|
||||
|
||||
TempBasal getTempBasal (Date time);
|
||||
TempBasal getExtendedBolus (Date time);
|
||||
|
||||
long oldestDataAvaialable();
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@ package info.nightscout.androidaps.interfaces;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.db.Treatment;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
|
||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
|
||||
/**
|
||||
* Created by mike on 14.06.2016.
|
||||
|
@ -14,6 +13,7 @@ public interface TreatmentsInterface {
|
|||
|
||||
void updateTotalIOB();
|
||||
IobTotal getLastCalculation();
|
||||
TreatmentsPlugin.MealData getMealData();
|
||||
IobTotal getCalculationToTime(long time);
|
||||
MealData getMealData();
|
||||
List<Treatment> getTreatments();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.widget.Button;
|
|||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged;
|
||||
|
@ -35,6 +36,7 @@ public class ActionsFragment extends Fragment implements FragmentBase, View.OnCl
|
|||
}
|
||||
|
||||
Button profileSwitch;
|
||||
Button tempTarget;
|
||||
Button extendedBolus;
|
||||
Button tempBasal;
|
||||
Button fill;
|
||||
|
@ -49,11 +51,13 @@ public class ActionsFragment extends Fragment implements FragmentBase, View.OnCl
|
|||
View view = inflater.inflate(R.layout.actions_fragment, container, false);
|
||||
|
||||
profileSwitch = (Button) view.findViewById(R.id.actions_profileswitch);
|
||||
tempTarget = (Button) view.findViewById(R.id.actions_temptarget);
|
||||
extendedBolus = (Button) view.findViewById(R.id.actions_extendedbolus);
|
||||
tempBasal = (Button) view.findViewById(R.id.actions_settempbasal);
|
||||
fill = (Button) view.findViewById(R.id.actions_fill);
|
||||
|
||||
profileSwitch.setOnClickListener(this);
|
||||
tempTarget.setOnClickListener(this);
|
||||
extendedBolus.setOnClickListener(this);
|
||||
tempBasal.setOnClickListener(this);
|
||||
fill.setOnClickListener(this);
|
||||
|
@ -106,6 +110,10 @@ public class ActionsFragment extends Fragment implements FragmentBase, View.OnCl
|
|||
fill.setVisibility(View.GONE);
|
||||
else
|
||||
fill.setVisibility(View.VISIBLE);
|
||||
if (!Config.APS)
|
||||
tempTarget.setVisibility(View.GONE);
|
||||
else
|
||||
tempTarget.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -117,11 +125,18 @@ public class ActionsFragment extends Fragment implements FragmentBase, View.OnCl
|
|||
switch (view.getId()) {
|
||||
case R.id.actions_profileswitch:
|
||||
NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false, false);
|
||||
profileswitch.executeProfileSwitch = true;
|
||||
newDialog.setOptions(profileswitch);
|
||||
newDialog.show(manager, "NewNSTreatmentDialog");
|
||||
break;
|
||||
case R.id.actions_temptarget:
|
||||
NewNSTreatmentDialog newTTDialog = new NewNSTreatmentDialog();
|
||||
final OptionsToShow temptarget = new OptionsToShow(R.id.careportal_temptarget, R.string.careportal_temptarget, false, false, false, false, true, false, false, false, false, true);
|
||||
temptarget.executeTempTarget = true;
|
||||
newTTDialog.setOptions(temptarget);
|
||||
newTTDialog.show(manager, "NewNSTreatmentDialog");
|
||||
break;
|
||||
case R.id.actions_extendedbolus:
|
||||
NewExtendedBolusDialog newExtendedDialog = new NewExtendedBolusDialog();
|
||||
newExtendedDialog.show(manager, "NewExtendedDialog");
|
||||
|
|
|
@ -25,25 +25,26 @@ public class CareportalFragment extends Fragment implements FragmentBase, View.O
|
|||
return careportalPlugin;
|
||||
}
|
||||
|
||||
// bg,insulin,carbs,prebolus,duration,percent,absolute,profile,split
|
||||
final OptionsToShow bgcheck = new OptionsToShow(R.id.careportal_bgcheck, R.string.careportal_bgcheck, true, true, true, false, false, false, false, false, false);
|
||||
final OptionsToShow snackbolus = new OptionsToShow(R.id.careportal_snackbolus, R.string.careportal_snackbolus, true, true, true, true, false, false, false, false, false);
|
||||
final OptionsToShow mealbolus = new OptionsToShow(R.id.careportal_mealbolus, R.string.careportal_mealbolus, true, true, true, true, false, false, false, false, false);
|
||||
final OptionsToShow correctionbolus = new OptionsToShow(R.id.careportal_correctionbolus, R.string.careportal_correctionbolus, true, true, true, true, false, false, false, false, false);
|
||||
final OptionsToShow carbcorrection = new OptionsToShow(R.id.careportal_carbscorrection, R.string.careportal_carbscorrection, true, false, true, false, false, false, false, false, false);
|
||||
final OptionsToShow combobolus = new OptionsToShow(R.id.careportal_combobolus, R.string.careportal_combobolus, true, true, true, true, true, false, false, false, true);
|
||||
final OptionsToShow announcement = new OptionsToShow(R.id.careportal_announcement, R.string.careportal_announcement, true, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow note = new OptionsToShow(R.id.careportal_note, R.string.careportal_note, true, false, false, false, true, false, false, false, false);
|
||||
final OptionsToShow question = new OptionsToShow(R.id.careportal_question, R.string.careportal_question, true, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow exercise = new OptionsToShow(R.id.careportal_exercise, R.string.careportal_exercise, false, false, false, false, true, false, false, false, false);
|
||||
final OptionsToShow sitechange = new OptionsToShow(R.id.careportal_pumpsitechange, R.string.careportal_pumpsitechange, true, true, false, false, false, false, false, false, false);
|
||||
final OptionsToShow sensorstart = new OptionsToShow(R.id.careportal_cgmsensorstart, R.string.careportal_cgmsensorstart, true, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow sensorchange = new OptionsToShow(R.id.careportal_cgmsensorinsert, R.string.careportal_cgmsensorinsert, true, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow insulinchange = new OptionsToShow(R.id.careportal_insulincartridgechange, R.string.careportal_insulincartridgechange, true, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow tempbasalstart = new OptionsToShow(R.id.careportal_tempbasalstart, R.string.careportal_tempbasalstart, true, false, false, false, true, true, true, false, false);
|
||||
final OptionsToShow tempbasalend = new OptionsToShow(R.id.careportal_tempbasalend, R.string.careportal_tempbasalend, true, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
|
||||
final OptionsToShow openapsoffline = new OptionsToShow(R.id.careportal_openapsoffline, R.string.careportal_openapsoffline, false, false, false, false, true, false, false, false, false);
|
||||
// bg,insulin,carbs,prebolus,duration,percent,absolute,profile,split,temptarget
|
||||
final OptionsToShow bgcheck = new OptionsToShow(R.id.careportal_bgcheck, R.string.careportal_bgcheck, true, true, true, false, false, false, false, false, false, false);
|
||||
final OptionsToShow snackbolus = new OptionsToShow(R.id.careportal_snackbolus, R.string.careportal_snackbolus, true, true, true, true, false, false, false, false, false, false);
|
||||
final OptionsToShow mealbolus = new OptionsToShow(R.id.careportal_mealbolus, R.string.careportal_mealbolus, true, true, true, true, false, false, false, false, false, false);
|
||||
final OptionsToShow correctionbolus = new OptionsToShow(R.id.careportal_correctionbolus, R.string.careportal_correctionbolus, true, true, true, true, false, false, false, false, false, false);
|
||||
final OptionsToShow carbcorrection = new OptionsToShow(R.id.careportal_carbscorrection, R.string.careportal_carbscorrection, true, false, true, false, false, false, false, false, false, false);
|
||||
final OptionsToShow combobolus = new OptionsToShow(R.id.careportal_combobolus, R.string.careportal_combobolus, true, true, true, true, true, false, false, false, true, false);
|
||||
final OptionsToShow announcement = new OptionsToShow(R.id.careportal_announcement, R.string.careportal_announcement, true, false, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow note = new OptionsToShow(R.id.careportal_note, R.string.careportal_note, true, false, false, false, true, false, false, false, false, false);
|
||||
final OptionsToShow question = new OptionsToShow(R.id.careportal_question, R.string.careportal_question, true, false, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow exercise = new OptionsToShow(R.id.careportal_exercise, R.string.careportal_exercise, false, false, false, false, true, false, false, false, false, false);
|
||||
final OptionsToShow sitechange = new OptionsToShow(R.id.careportal_pumpsitechange, R.string.careportal_pumpsitechange, true, true, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow sensorstart = new OptionsToShow(R.id.careportal_cgmsensorstart, R.string.careportal_cgmsensorstart, true, false, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow sensorchange = new OptionsToShow(R.id.careportal_cgmsensorinsert, R.string.careportal_cgmsensorinsert, true, false, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow insulinchange = new OptionsToShow(R.id.careportal_insulincartridgechange, R.string.careportal_insulincartridgechange, true, false, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow tempbasalstart = new OptionsToShow(R.id.careportal_tempbasalstart, R.string.careportal_tempbasalstart, true, false, false, false, true, true, true, false, false, false);
|
||||
final OptionsToShow tempbasalend = new OptionsToShow(R.id.careportal_tempbasalend, R.string.careportal_tempbasalend, true, false, false, false, false, false, false, false, false, false);
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false, false);
|
||||
final OptionsToShow openapsoffline = new OptionsToShow(R.id.careportal_openapsoffline, R.string.careportal_openapsoffline, false, false, false, false, true, false, false, false, false, false);
|
||||
final OptionsToShow temptarget = new OptionsToShow(R.id.careportal_temptarget, R.string.careportal_temptarget, false, false, false, false, true, false, false, false, false, true);
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
|
@ -68,6 +69,7 @@ public class CareportalFragment extends Fragment implements FragmentBase, View.O
|
|||
view.findViewById(R.id.careportal_tempbasalend).setOnClickListener(this);
|
||||
view.findViewById(R.id.careportal_tempbasalstart).setOnClickListener(this);
|
||||
view.findViewById(R.id.careportal_openapsoffline).setOnClickListener(this);
|
||||
view.findViewById(R.id.careportal_temptarget).setOnClickListener(this);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -130,6 +132,9 @@ public class CareportalFragment extends Fragment implements FragmentBase, View.O
|
|||
case R.id.careportal_openapsoffline:
|
||||
newDialog.setOptions(openapsoffline);
|
||||
break;
|
||||
case R.id.careportal_temptarget:
|
||||
newDialog.setOptions(temptarget);
|
||||
break;
|
||||
default:
|
||||
newDialog = null;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.widget.RadioButton;
|
|||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
|
||||
import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout;
|
||||
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
|
||||
|
@ -33,6 +34,7 @@ import org.json.JSONObject;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
@ -42,10 +44,13 @@ import java.util.Date;
|
|||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.events.EventNewBasalProfile;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.events.EventTempTargetRangeChange;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.PlusMinusEditText;
|
||||
|
@ -73,6 +78,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
LinearLayout layoutAbsolute;
|
||||
LinearLayout layoutCarbTime;
|
||||
LinearLayout layoutProfile;
|
||||
LinearLayout layoutTempTarget;
|
||||
Button dateButton;
|
||||
Button timeButton;
|
||||
Button okButton;
|
||||
|
@ -91,6 +97,9 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
EditText carbTimeEdit;
|
||||
EditText splitEdit;
|
||||
Spinner profileSpinner;
|
||||
EditText low;
|
||||
EditText high;
|
||||
Spinner reasonSpinner;
|
||||
|
||||
PlusMinusEditText editBg;
|
||||
PlusMinusEditText editCarbs;
|
||||
|
@ -142,6 +151,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
layoutAbsolute = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_absolute_layout);
|
||||
layoutCarbTime = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_carbtime_layout);
|
||||
layoutProfile = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_profile_layout);
|
||||
layoutTempTarget = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_temptarget_layout);
|
||||
|
||||
bgUnitsView = (TextView) view.findViewById(R.id.careportal_newnstreatment_bgunits);
|
||||
meterRadioButton = (RadioButton) view.findViewById(R.id.careportal_newnstreatment_meter);
|
||||
|
@ -193,6 +203,10 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
notesEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_notes);
|
||||
splitEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_splitinput);
|
||||
|
||||
reasonSpinner = (Spinner) view.findViewById(R.id.careportal_newnstreatment_temptarget_reason);
|
||||
low = (EditText) view.findViewById(R.id.careportal_temptarget_low);
|
||||
high = (EditText) view.findViewById(R.id.careportal_temptarget_high);
|
||||
|
||||
eventTime = new Date();
|
||||
dateButton = (Button) view.findViewById(R.id.careportal_newnstreatment_eventdate);
|
||||
timeButton = (Button) view.findViewById(R.id.careportal_newnstreatment_eventtime);
|
||||
|
@ -204,7 +218,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
okButton = (Button) view.findViewById(R.id.careportal_newnstreatment_ok);
|
||||
okButton.setOnClickListener(this);
|
||||
|
||||
// BG
|
||||
// profile
|
||||
profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
ArrayList<CharSequence> profileList;
|
||||
units = Constants.MGDL;
|
||||
|
@ -227,6 +241,17 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
}
|
||||
}
|
||||
|
||||
// temp target
|
||||
ArrayList<CharSequence> reasonList = new ArrayList<CharSequence>();
|
||||
reasonList.add(MainApp.sResources.getString(R.string.eatingsoon));
|
||||
reasonList.add(MainApp.sResources.getString(R.string.activity));
|
||||
reasonList.add(MainApp.sResources.getString(R.string.manual));
|
||||
ArrayAdapter<CharSequence> adapterReason = new ArrayAdapter<CharSequence>(getContext(),
|
||||
android.R.layout.simple_spinner_item, reasonList);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
reasonSpinner.setAdapter(adapterReason);
|
||||
|
||||
// bg
|
||||
bgUnitsView.setText(units);
|
||||
|
||||
// Set BG if not old
|
||||
|
@ -271,6 +296,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
showOrHide(layoutAbsolute, options.absolute);
|
||||
showOrHide(layoutCarbTime, options.prebolus);
|
||||
showOrHide(layoutProfile, options.profile);
|
||||
showOrHide(layoutTempTarget, options.tempTarget);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -403,6 +429,9 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
case R.id.careportal_openapsoffline:
|
||||
data.put("eventType", "OpenAPS Offline");
|
||||
break;
|
||||
case R.id.careportal_temptarget:
|
||||
data.put("eventType", "Temporary Target");
|
||||
break;
|
||||
}
|
||||
if (SafeParse.stringToDouble(bgInputEdit.getText().toString()) != 0d) {
|
||||
data.put("glucose", SafeParse.stringToDouble(bgInputEdit.getText().toString()));
|
||||
|
@ -426,6 +455,12 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
data.put("preBolus", SafeParse.stringToDouble(carbTimeEdit.getText().toString()));
|
||||
if (!notesEdit.getText().toString().equals(""))
|
||||
data.put("notes", notesEdit.getText().toString());
|
||||
if (!reasonSpinner.getSelectedItem().toString().equals(""))
|
||||
data.put("reason", reasonSpinner.getSelectedItem().toString());
|
||||
if (SafeParse.stringToDouble(low.getText().toString()) != 0d)
|
||||
data.put("targetBottom", SafeParse.stringToDouble(low.getText().toString()));
|
||||
if (SafeParse.stringToDouble(high.getText().toString()) != 0d)
|
||||
data.put("targetTop", SafeParse.stringToDouble(high.getText().toString()));
|
||||
data.put("units", units);
|
||||
if (!enteredBy.equals("")) data.put("enteredBy", enteredBy);
|
||||
if (options.eventType == R.id.careportal_combobolus) {
|
||||
|
@ -509,6 +544,14 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
ret += data.get("profile");
|
||||
ret += "\n";
|
||||
}
|
||||
if (data.has("targetBottom") && data.has("targetTop")) {
|
||||
ret += getString(R.string.target_range);
|
||||
ret += " ";
|
||||
ret += data.get("targetBottom");
|
||||
ret += " - ";
|
||||
ret += data.get("targetTop");
|
||||
ret += "\n";
|
||||
}
|
||||
if (data.has("created_at")) {
|
||||
ret += getString(R.string.careportal_newnstreatment_eventtime_label);
|
||||
ret += ": ";
|
||||
|
@ -563,6 +606,35 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
|
|||
} else {
|
||||
ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
|
||||
}
|
||||
if (options.executeTempTarget) {
|
||||
if (data.has("targetBottom") && data.has("targetTop")) {
|
||||
sHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
TempTarget tempTarget = new TempTarget();
|
||||
tempTarget.timeStart = eventTime;
|
||||
tempTarget.duration = data.getInt("duration");
|
||||
tempTarget.reason = data.getString("reason");
|
||||
tempTarget.low = NSProfile.toMgdl(data.getDouble("targetBottom"), MainApp.getConfigBuilder().getActiveProfile().getProfile().getUnits());
|
||||
tempTarget.high = NSProfile.toMgdl(data.getDouble("targetTop"), MainApp.getConfigBuilder().getActiveProfile().getProfile().getUnits());
|
||||
tempTarget.setTimeIndex(tempTarget.getTimeIndex());
|
||||
Dao<TempTarget, Long> dao = MainApp.getDbHelper().getDaoTempTargets();
|
||||
log.debug("Creating new TempTarget db record: " + tempTarget.log());
|
||||
dao.createIfNotExists(tempTarget);
|
||||
MainApp.bus().post(new EventTempTargetRangeChange());
|
||||
ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(getContext().getString(R.string.cancel), null);
|
||||
|
|
|
@ -16,9 +16,11 @@ public class OptionsToShow {
|
|||
public boolean absolute;
|
||||
public boolean profile;
|
||||
public boolean split;
|
||||
public boolean tempTarget;
|
||||
|
||||
// perform direct actions
|
||||
public boolean executeProfileSwitch = false;
|
||||
public boolean executeTempTarget = false;
|
||||
|
||||
public OptionsToShow(int eventType,
|
||||
int eventName,
|
||||
|
@ -30,7 +32,8 @@ public class OptionsToShow {
|
|||
boolean percent,
|
||||
boolean absolute,
|
||||
boolean profile,
|
||||
boolean split) {
|
||||
boolean split,
|
||||
boolean tempTarget) {
|
||||
this.eventType = eventType;
|
||||
this.eventName = eventName;
|
||||
this.bg = bg;
|
||||
|
@ -42,5 +45,6 @@ public class OptionsToShow {
|
|||
this.absolute = absolute;
|
||||
this.profile = profile;
|
||||
this.split = split;
|
||||
this.tempTarget = tempTarget;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ public class CircadianPercentageProfileFragment extends Fragment implements Frag
|
|||
@Override
|
||||
public void onClick(View view) {
|
||||
NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false, false);
|
||||
profileswitch.executeProfileSwitch = true;
|
||||
newDialog.setOptions(profileswitch);
|
||||
newDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
|
||||
|
|
|
@ -43,13 +43,13 @@ import info.nightscout.androidaps.plugins.DanaR.comm.MsgError;
|
|||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.Loop.DeviceStatus;
|
||||
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.DetermineBasalResult;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.DetermineBasalResultAMA;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.DetermineBasalResultMA;
|
||||
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
|
||||
import info.nightscout.androidaps.plugins.Actions.dialogs.NewExtendedBolusDialog;
|
||||
import info.nightscout.androidaps.plugins.Overview.Notification;
|
||||
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
|
||||
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
|
||||
import info.nightscout.client.data.DbLogger;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
|
@ -647,7 +647,7 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
|
|||
emptyDescription.isBolusCapable = false;
|
||||
emptyDescription.isExtendedBolusCapable = false;
|
||||
emptyDescription.isSetBasalProfileCapable = false;
|
||||
emptyDescription.isTempBasalCapable = false;
|
||||
emptyDescription.isTempBasalCapable = true; // needs to be true before real driver is selected
|
||||
emptyDescription.isRefillingCapable = false;
|
||||
return emptyDescription;
|
||||
}
|
||||
|
@ -697,7 +697,8 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
|
|||
|
||||
@Override
|
||||
public boolean isAMAModeEnabled() {
|
||||
boolean result = true;
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
|
||||
boolean result = preferences.getBoolean("openapsama_useautosens", false);
|
||||
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
|
@ -901,8 +902,14 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
|
|||
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun));
|
||||
deviceStatus.suggested = apsResult.json();
|
||||
|
||||
if (lastRun.request instanceof DetermineBasalResult) {
|
||||
DetermineBasalResult result = (DetermineBasalResult) lastRun.request;
|
||||
if (lastRun.request instanceof DetermineBasalResultMA) {
|
||||
DetermineBasalResultMA result = (DetermineBasalResultMA) lastRun.request;
|
||||
deviceStatus.iob = result.iob.json();
|
||||
deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
|
||||
}
|
||||
|
||||
if (lastRun.request instanceof DetermineBasalResultAMA) {
|
||||
DetermineBasalResultAMA result = (DetermineBasalResultAMA) lastRun.request;
|
||||
deviceStatus.iob = result.iob.json();
|
||||
deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
|
||||
}
|
||||
|
@ -974,7 +981,25 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
|
|||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
context.sendBroadcast(intent);
|
||||
DbLogger.dbAdd(intent, data.toString(), NewExtendedBolusDialog.class);
|
||||
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void removeCareportalEntryFromNS(String _id) {
|
||||
try {
|
||||
Context context = MainApp.instance().getApplicationContext();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("action", "dbRemove");
|
||||
bundle.putString("collection", "treatments");
|
||||
bundle.putString("_id", _id);
|
||||
Intent intent = new Intent(Intents.ACTION_DATABASE);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
context.sendBroadcast(intent);
|
||||
DbLogger.dbRemove(intent, _id, ConfigBuilderPlugin.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ public class LocalProfileFragment extends Fragment implements FragmentBase {
|
|||
@Override
|
||||
public void onClick(View view) {
|
||||
NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false, false);
|
||||
profileswitch.executeProfileSwitch = true;
|
||||
newDialog.setOptions(profileswitch);
|
||||
newDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
|
||||
|
|
|
@ -16,7 +16,7 @@ import info.nightscout.utils.DecimalFormatter;
|
|||
/**
|
||||
* Created by mike on 09.06.2016.
|
||||
*/
|
||||
public class APSResult implements Parcelable {
|
||||
public class APSResult {
|
||||
public String reason;
|
||||
public double rate;
|
||||
public int duration;
|
||||
|
@ -51,36 +51,6 @@ public class APSResult implements Parcelable {
|
|||
return Html.fromHtml(MainApp.sResources.getString(R.string.nochangerequested));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(reason);
|
||||
dest.writeDouble(rate);
|
||||
dest.writeInt(duration);
|
||||
dest.writeInt(changeRequested ? 1 : 0);
|
||||
}
|
||||
|
||||
public final Parcelable.Creator<APSResult> CREATOR = new Parcelable.Creator<APSResult>() {
|
||||
public APSResult createFromParcel(Parcel in) {
|
||||
return new APSResult(in);
|
||||
}
|
||||
|
||||
public APSResult[] newArray(int size) {
|
||||
return new APSResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected APSResult(Parcel in) {
|
||||
reason = in.readString();
|
||||
rate = in.readDouble();
|
||||
duration = in.readInt();
|
||||
changeRequested = in.readInt() == 1;
|
||||
}
|
||||
|
||||
public APSResult() {
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public class LoopFragment extends Fragment implements View.OnClickListener, Frag
|
|||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.loop_run:
|
||||
getPlugin().invoke(true);
|
||||
getPlugin().invoke("Loop button", true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,15 +108,15 @@ public class LoopPlugin implements PluginBase {
|
|||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventTreatmentChange ev) {
|
||||
invoke(true);
|
||||
invoke("EventTreatmentChange", true);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventNewBG ev) {
|
||||
invoke(true);
|
||||
invoke("EventNewBG", true);
|
||||
}
|
||||
|
||||
public void invoke(boolean allowNotification) {
|
||||
public void invoke(String initiator, boolean allowNotification) {
|
||||
try {
|
||||
if (Config.logFunctionCalls)
|
||||
log.debug("invoke");
|
||||
|
@ -136,7 +136,7 @@ public class LoopPlugin implements PluginBase {
|
|||
|
||||
APSInterface usedAPS = configBuilder.getActiveAPS();
|
||||
if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginBase.APS)) {
|
||||
usedAPS.invoke();
|
||||
usedAPS.invoke(initiator);
|
||||
result = usedAPS.getLastAPSResult();
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
|
|||
MainApp.sResources.getString(R.string.objectives_6_objective),
|
||||
"",
|
||||
new Date(0),
|
||||
1,
|
||||
14,
|
||||
new Date(0)));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.Round;
|
||||
|
||||
|
||||
public class Autosens {
|
||||
private static Logger log = LoggerFactory.getLogger(Autosens.class);
|
||||
|
||||
public static AutosensResult detectSensitivityandCarbAbsorption(List<BgReading> glucose_data, long mealTime) {
|
||||
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
|
||||
//console.error(mealTime);
|
||||
|
||||
double deviationSum = 0;
|
||||
double carbsAbsorbed = 0;
|
||||
|
||||
List<BgReading> bucketed_data = new ArrayList<>();
|
||||
bucketed_data.add(glucose_data.get(0));
|
||||
int j = 0;
|
||||
for (int i = 1; i < glucose_data.size(); ++i) {
|
||||
long bgTime = glucose_data.get(i).getTimeIndex();
|
||||
long lastbgTime = glucose_data.get(i - 1).getTimeIndex();
|
||||
if (glucose_data.get(i).value < 39 || glucose_data.get(i - 1).value < 39) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
|
||||
if (Math.abs(elapsed_minutes) > 8) {
|
||||
// interpolate missing data points
|
||||
double lastbg = glucose_data.get(i - 1).value;
|
||||
elapsed_minutes = Math.abs(elapsed_minutes);
|
||||
//console.error(elapsed_minutes);
|
||||
long nextbgTime;
|
||||
while (elapsed_minutes > 5) {
|
||||
nextbgTime = lastbgTime + 5 * 60 * 1000;
|
||||
j++;
|
||||
BgReading newBgreading = new BgReading();
|
||||
newBgreading.timeIndex = nextbgTime;
|
||||
double gapDelta = glucose_data.get(i).value - lastbg;
|
||||
//console.error(gapDelta, lastbg, elapsed_minutes);
|
||||
double nextbg = lastbg + (5 / elapsed_minutes * gapDelta);
|
||||
newBgreading.value = Math.round(nextbg);
|
||||
//console.error("Interpolated", bucketed_data[j]);
|
||||
bucketed_data.add(newBgreading);
|
||||
|
||||
elapsed_minutes = elapsed_minutes - 5;
|
||||
lastbg = nextbg;
|
||||
lastbgTime = nextbgTime;
|
||||
}
|
||||
} else if (Math.abs(elapsed_minutes) > 2) {
|
||||
j++;
|
||||
BgReading newBgreading = new BgReading();
|
||||
newBgreading.value = glucose_data.get(i).value;
|
||||
newBgreading.timeIndex = bgTime;
|
||||
bucketed_data.add(newBgreading);
|
||||
} else {
|
||||
bucketed_data.get(j).value = (bucketed_data.get(j).value + glucose_data.get(i).value) / 2;
|
||||
}
|
||||
}
|
||||
//console.error(bucketed_data);
|
||||
double[] avgDeltas = new double[bucketed_data.size() - 2];
|
||||
double[] bgis = new double[bucketed_data.size() - 2];
|
||||
double[] deviations = new double[bucketed_data.size() - 2];
|
||||
|
||||
String debugString = "";
|
||||
for (int i = 0; i < bucketed_data.size() - 3; ++i) {
|
||||
long bgTime = bucketed_data.get(i).timeIndex;
|
||||
int secondsFromMidnight = NSProfile.secondsFromMidnight(new Date(bgTime));
|
||||
|
||||
double sens = NSProfile.toMgdl(profile.getIsf(secondsFromMidnight), profile.getUnits());
|
||||
|
||||
//console.error(bgTime , bucketed_data[i].glucose);
|
||||
double bg;
|
||||
double avgDelta;
|
||||
double delta;
|
||||
bg = bucketed_data.get(i).value;
|
||||
if (bg < 40 || bucketed_data.get(i + 3).value < 40) {
|
||||
log.error("! value < 40");
|
||||
continue;
|
||||
}
|
||||
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
|
||||
delta = (bg - bucketed_data.get(i + 1).value);
|
||||
|
||||
// avgDelta = avgDelta.toFixed(2);
|
||||
IobTotal iob = IobTotal.calulateFromTreatmentsAndTemps(bgTime);
|
||||
|
||||
double bgi = Math.round((-iob.activity * sens * 5) * 100) / 100;
|
||||
// bgi = bgi.toFixed(2);
|
||||
//console.error(delta);
|
||||
double deviation = delta - bgi;
|
||||
// deviation = deviation.toFixed(2);
|
||||
//if (deviation < 0 && deviation > -2) { console.error("BG: "+bg+", avgDelta: "+avgDelta+", BGI: "+bgi+", deviation: "+deviation); }
|
||||
|
||||
// Exclude large positive deviations (carb absorption) from autosens
|
||||
if (avgDelta - bgi < 6) {
|
||||
if (deviation > 0) {
|
||||
debugString += "+";
|
||||
} else if (deviation == 0) {
|
||||
debugString += "=";
|
||||
} else {
|
||||
debugString += "-";
|
||||
}
|
||||
avgDeltas[i] = avgDelta;
|
||||
bgis[i] = bgi;
|
||||
deviations[i] = deviation;
|
||||
deviationSum += deviation;
|
||||
} else {
|
||||
debugString += ">";
|
||||
//console.error(bgTime);
|
||||
}
|
||||
|
||||
// if bgTime is more recent than mealTime
|
||||
if (bgTime > mealTime) {
|
||||
// figure out how many carbs that represents
|
||||
// but always assume at least 3mg/dL/5m (default) absorption
|
||||
double ci = Math.max(deviation, Constants.MIN_5M_CARBIMPACT);
|
||||
double absorbed = ci * profile.getIc(secondsFromMidnight) / sens;
|
||||
// and add that to the running total carbsAbsorbed
|
||||
carbsAbsorbed += absorbed;
|
||||
}
|
||||
}
|
||||
//console.error("");
|
||||
log.debug(debugString);
|
||||
//console.log(JSON.stringify(avgDeltas));
|
||||
//console.log(JSON.stringify(bgis));
|
||||
Arrays.sort(avgDeltas);
|
||||
Arrays.sort(bgis);
|
||||
Arrays.sort(deviations);
|
||||
|
||||
for (double i = 0.9; i > 0.1; i = i - 0.02) {
|
||||
//console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2));
|
||||
if (percentile(deviations, (i + 0.02)) >= 0 && percentile(deviations, i) < 0) {
|
||||
//console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2));
|
||||
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (target 45%-50%)");
|
||||
}
|
||||
}
|
||||
double pSensitive = percentile(deviations, 0.50);
|
||||
double pResistant = percentile(deviations, 0.45);
|
||||
//p30 = percentile(deviations, 0.3);
|
||||
|
||||
// average = deviationSum / deviations.length;
|
||||
|
||||
//console.error("Mean deviation: "+average.toFixed(2));
|
||||
double basalOff = 0;
|
||||
|
||||
if (pSensitive < 0) { // sensitive
|
||||
basalOff = pSensitive * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits());
|
||||
log.debug("Excess insulin sensitivity detected: ");
|
||||
} else if (pResistant > 0) { // resistant
|
||||
basalOff = pResistant * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits());
|
||||
log.debug("Excess insulin resistance detected: ");
|
||||
} else {
|
||||
log.debug("Sensitivity normal.");
|
||||
}
|
||||
double ratio = 1 + (basalOff / profile.getMaxDailyBasal());
|
||||
|
||||
// don't adjust more than 1.5x
|
||||
double rawRatio = ratio;
|
||||
ratio = Math.max(ratio, Constants.AUTOSENS_MIN);
|
||||
ratio = Math.min(ratio, Constants.AUTOSENS_MAX);
|
||||
|
||||
if (ratio != rawRatio) {
|
||||
log.debug("Ratio limited from " + rawRatio + " to " + ratio);
|
||||
}
|
||||
|
||||
double newisf = Math.round(NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()) / ratio);
|
||||
if (ratio != 1) {
|
||||
log.debug("ISF adjusted from " + NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()) + " to " + newisf);
|
||||
}
|
||||
//console.error("Basal adjustment "+basalOff.toFixed(2)+"U/hr");
|
||||
//console.error("Ratio: "+ratio*100+"%: new ISF: "+newisf.toFixed(1)+"mg/dL/U");
|
||||
|
||||
AutosensResult output = new AutosensResult();
|
||||
output.ratio = Round.roundTo(ratio, 0.01);
|
||||
output.carbsAbsorbed = Round.roundTo(carbsAbsorbed, 0.01);
|
||||
return output;
|
||||
}
|
||||
|
||||
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
|
||||
// Returns the value at a given percentile in a sorted numeric array.
|
||||
// "Linear interpolation between closest ranks" method
|
||||
public static double percentile(double[] arr, double p) {
|
||||
if (arr.length == 0) return 0;
|
||||
if (p <= 0) return arr[0];
|
||||
if (p >= 1) return arr[arr.length - 1];
|
||||
|
||||
double index = arr.length * p,
|
||||
lower = Math.floor(index),
|
||||
upper = lower + 1,
|
||||
weight = index % 1;
|
||||
|
||||
if (upper >= arr.length) return arr[(int) lower];
|
||||
return arr[(int) lower] * (1 - weight) + arr[(int) upper] * weight;
|
||||
}
|
||||
|
||||
// Returns the percentile of the given value in a sorted numeric array.
|
||||
public static double percentRank(double[] arr, double v) {
|
||||
for (int i = 0, l = arr.length; i < l; i++) {
|
||||
if (v <= arr[i]) {
|
||||
while (i < l && v == arr[i]) i++;
|
||||
if (i == 0) return 0;
|
||||
if (v != arr[i - 1]) {
|
||||
i += (v - arr[i - 1]) / (arr[i] - arr[i - 1]);
|
||||
}
|
||||
return i / l;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
||||
|
||||
/**
|
||||
* Created by mike on 06.01.2017.
|
||||
*/
|
||||
public class AutosensResult {
|
||||
public double ratio;
|
||||
public double carbsAbsorbed;
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
||||
|
||||
import com.eclipsesource.v8.JavaVoidCallback;
|
||||
import com.eclipsesource.v8.V8;
|
||||
import com.eclipsesource.v8.V8Array;
|
||||
import com.eclipsesource.v8.V8Object;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
|
||||
public class DetermineBasalAdapterAMAJS {
|
||||
private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterAMAJS.class);
|
||||
|
||||
|
||||
private ScriptReader mScriptReader = null;
|
||||
V8 mV8rt;
|
||||
private V8Object mProfile;
|
||||
private V8Object mGlucoseStatus;
|
||||
private V8Array mIobData;
|
||||
private V8Object mMealData;
|
||||
private V8Object mCurrentTemp;
|
||||
private V8Object mAutosensData = null;
|
||||
|
||||
private final String PARAM_currentTemp = "currentTemp";
|
||||
private final String PARAM_iobData = "iobData";
|
||||
private final String PARAM_glucoseStatus = "glucose_status";
|
||||
private final String PARAM_profile = "profile";
|
||||
private final String PARAM_meal_data = "meal_data";
|
||||
private final String PARAM_autosens_data = "autosens_data";
|
||||
|
||||
private String storedCurrentTemp = null;
|
||||
private String storedIobData = null;
|
||||
private String storedGlucoseStatus = null;
|
||||
private String storedProfile = null;
|
||||
private String storedMeal_data = null;
|
||||
private String storedAutosens_data = null;
|
||||
|
||||
private String scriptDebug = "";
|
||||
|
||||
/**
|
||||
* Main code
|
||||
*/
|
||||
|
||||
public DetermineBasalAdapterAMAJS(ScriptReader scriptReader) throws IOException {
|
||||
mV8rt = V8.createV8Runtime();
|
||||
mScriptReader = scriptReader;
|
||||
|
||||
initLogCallback();
|
||||
initProcessExitCallback();
|
||||
initModuleParent();
|
||||
loadScript();
|
||||
}
|
||||
|
||||
public DetermineBasalResultAMA invoke() {
|
||||
|
||||
log.debug(">>> Invoking detemine_basal <<<");
|
||||
log.debug("Glucose status: " + (storedGlucoseStatus = mV8rt.executeStringScript("JSON.stringify(" + PARAM_glucoseStatus + ");")));
|
||||
log.debug("IOB data: " + (storedIobData = mV8rt.executeStringScript("JSON.stringify(" + PARAM_iobData + ");")));
|
||||
log.debug("Current temp: " + (storedCurrentTemp = mV8rt.executeStringScript("JSON.stringify(" + PARAM_currentTemp + ");")));
|
||||
log.debug("Profile: " + (storedProfile = mV8rt.executeStringScript("JSON.stringify(" + PARAM_profile + ");")));
|
||||
log.debug("Meal data: " + (storedMeal_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_meal_data + ");")));
|
||||
if (mAutosensData != null)
|
||||
log.debug("Autosens data: " + (storedAutosens_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_autosens_data + ");")));
|
||||
else
|
||||
log.debug("Autosens data: " + (storedAutosens_data = "undefined"));
|
||||
|
||||
mV8rt.executeVoidScript(
|
||||
"var rT = determine_basal(" +
|
||||
PARAM_glucoseStatus + ", " +
|
||||
PARAM_currentTemp + ", " +
|
||||
PARAM_iobData + ", " +
|
||||
PARAM_profile + ", " +
|
||||
PARAM_autosens_data + ", " +
|
||||
PARAM_meal_data + ", " +
|
||||
"tempBasalFunctions" +
|
||||
");");
|
||||
|
||||
|
||||
String ret = mV8rt.executeStringScript("JSON.stringify(rT);");
|
||||
log.debug("Result: " + ret);
|
||||
|
||||
V8Object v8ObjectReuslt = mV8rt.getObject("rT");
|
||||
|
||||
DetermineBasalResultAMA result = null;
|
||||
try {
|
||||
result = new DetermineBasalResultAMA(v8ObjectReuslt, new JSONObject(ret));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
String getGlucoseStatusParam() {
|
||||
return storedGlucoseStatus;
|
||||
}
|
||||
|
||||
String getCurrentTempParam() {
|
||||
return storedCurrentTemp;
|
||||
}
|
||||
|
||||
String getIobDataParam() {
|
||||
return storedIobData;
|
||||
}
|
||||
|
||||
String getProfileParam() {
|
||||
return storedProfile;
|
||||
}
|
||||
|
||||
String getMealDataParam() {
|
||||
return storedMeal_data;
|
||||
}
|
||||
|
||||
String getAutosensDataParam() {
|
||||
return storedAutosens_data;
|
||||
}
|
||||
|
||||
String getScriptDebug() {
|
||||
return scriptDebug;
|
||||
}
|
||||
|
||||
private void loadScript() throws IOException {
|
||||
mV8rt.executeVoidScript(readFile("OpenAPSAMA/round-basal.js"), "OpenAPSAMA/round-basal.js", 0);
|
||||
mV8rt.executeVoidScript("var round_basal = module.exports;");
|
||||
mV8rt.executeVoidScript("require = function() {return round_basal;};");
|
||||
|
||||
mV8rt.executeVoidScript(readFile("OpenAPSAMA/basal-set-temp.js"), "OpenAPSAMA/basal-set-temp.js ", 0);
|
||||
mV8rt.executeVoidScript("var tempBasalFunctions = module.exports;");
|
||||
|
||||
mV8rt.executeVoidScript(
|
||||
readFile("OpenAPSAMA/determine-basal.js"),
|
||||
"OpenAPSAMA/determine-basal.js",
|
||||
0);
|
||||
mV8rt.executeVoidScript("var determine_basal = module.exports;");
|
||||
mV8rt.executeVoidScript(
|
||||
"var setTempBasal = function (rate, duration, profile, rT, offline) {" +
|
||||
"rT.duration = duration;\n" +
|
||||
" rT.rate = rate;" +
|
||||
"return rT;" +
|
||||
"};",
|
||||
"setTempBasal.js",
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
private void initModuleParent() {
|
||||
mV8rt.executeVoidScript("var module = {\"parent\":Boolean(1)};");
|
||||
}
|
||||
|
||||
private void initProcessExitCallback() {
|
||||
JavaVoidCallback callbackProccessExit = new JavaVoidCallback() {
|
||||
@Override
|
||||
public void invoke(V8Object arg0, V8Array parameters) {
|
||||
if (parameters.length() > 0) {
|
||||
Object arg1 = parameters.get(0);
|
||||
log.error("ProccessExit " + arg1);
|
||||
}
|
||||
}
|
||||
};
|
||||
mV8rt.registerJavaMethod(callbackProccessExit, "proccessExit");
|
||||
mV8rt.executeVoidScript("var process = {\"exit\": function () { proccessExit(); } };");
|
||||
}
|
||||
|
||||
private void initLogCallback() {
|
||||
JavaVoidCallback callbackLog = new JavaVoidCallback() {
|
||||
@Override
|
||||
public void invoke(V8Object arg0, V8Array parameters) {
|
||||
int i = 0;
|
||||
String s = "";
|
||||
while (i < parameters.length()) {
|
||||
Object arg = parameters.get(i);
|
||||
s += arg + " ";
|
||||
i++;
|
||||
}
|
||||
if (!s.equals("") && Config.logAPSResult) {
|
||||
log.debug("Script debug: " + s);
|
||||
scriptDebug += s + "\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
mV8rt.registerJavaMethod(callbackLog, "log");
|
||||
mV8rt.executeVoidScript("var console = {\"log\":log, \"error\":log};");
|
||||
}
|
||||
|
||||
|
||||
public void setData(NSProfile profile,
|
||||
double maxIob,
|
||||
double maxBasal,
|
||||
double minBg,
|
||||
double maxBg,
|
||||
double targetBg,
|
||||
PumpInterface pump,
|
||||
IobTotal[] iobArray,
|
||||
GlucoseStatus glucoseStatus,
|
||||
MealData mealData,
|
||||
double autosensDataRatio,
|
||||
boolean tempTargetSet,
|
||||
double min_5m_carbimpact) {
|
||||
|
||||
String units = profile.getUnits();
|
||||
|
||||
mProfile = new V8Object(mV8rt);
|
||||
mProfile.add("max_iob", maxIob);
|
||||
mProfile.add("carbs_hr", profile.getCarbAbsorbtionRate());
|
||||
mProfile.add("dia", profile.getDia());
|
||||
mProfile.add("type", "current");
|
||||
mProfile.add("max_daily_basal", profile.getMaxDailyBasal());
|
||||
mProfile.add("max_basal", maxBasal);
|
||||
mProfile.add("min_bg", minBg);
|
||||
mProfile.add("max_bg", maxBg);
|
||||
mProfile.add("target_bg", targetBg);
|
||||
mProfile.add("carb_ratio", profile.getIc(profile.secondsFromMidnight()));
|
||||
mProfile.add("sens", NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()).doubleValue(), units));
|
||||
mProfile.add("max_daily_safety_multiplier", Constants.MAX_DAILY_SAFETY_MULTIPLIER);
|
||||
mProfile.add("current_basal_safety_multiplier", Constants.CURRENT_BASAL_SAFETY_MULTIPLIER);
|
||||
mProfile.add("skip_neutral_temps", true);
|
||||
mProfile.add("current_basal", pump.getBaseBasalRate());
|
||||
mProfile.add("temptargetSet", tempTargetSet);
|
||||
mProfile.add("autosens_adjust_targets", Constants.AUTOSENS_ADJUST_TARGETS);
|
||||
mProfile.add("min_5m_carbimpact", min_5m_carbimpact);
|
||||
mV8rt.add(PARAM_profile, mProfile);
|
||||
|
||||
mCurrentTemp = new V8Object(mV8rt);
|
||||
mCurrentTemp.add("temp", "absolute");
|
||||
mCurrentTemp.add("duration", pump.getTempBasalRemainingMinutes());
|
||||
mCurrentTemp.add("rate", pump.getTempBasalAbsoluteRate());
|
||||
mV8rt.add(PARAM_currentTemp, mCurrentTemp);
|
||||
|
||||
mIobData = mV8rt.executeArrayScript(IobTotal.convertToJSONArray(iobArray).toString());
|
||||
mV8rt.add(PARAM_iobData, mIobData);
|
||||
|
||||
mGlucoseStatus = new V8Object(mV8rt);
|
||||
mGlucoseStatus.add("glucose", glucoseStatus.glucose);
|
||||
mGlucoseStatus.add("delta", glucoseStatus.delta);
|
||||
mGlucoseStatus.add("short_avgdelta", glucoseStatus.short_avgdelta);
|
||||
mGlucoseStatus.add("long_avgdelta", glucoseStatus.long_avgdelta);
|
||||
mV8rt.add(PARAM_glucoseStatus, mGlucoseStatus);
|
||||
|
||||
mMealData = new V8Object(mV8rt);
|
||||
mMealData.add("carbs", mealData.carbs);
|
||||
mMealData.add("boluses", mealData.boluses);
|
||||
mMealData.add("mealCOB", mealData.mealCOB);
|
||||
mV8rt.add(PARAM_meal_data, mMealData);
|
||||
|
||||
if (MainApp.getConfigBuilder().isAMAModeEnabled()) {
|
||||
mAutosensData = new V8Object(mV8rt);
|
||||
mAutosensData.add("ratio", autosensDataRatio);
|
||||
mV8rt.add(PARAM_autosens_data, mAutosensData);
|
||||
} else {
|
||||
mV8rt.addUndefined(PARAM_autosens_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void release() {
|
||||
mProfile.release();
|
||||
mCurrentTemp.release();
|
||||
mIobData.release();
|
||||
mMealData.release();
|
||||
mGlucoseStatus.release();
|
||||
if (mAutosensData != null) {
|
||||
mAutosensData.release();
|
||||
}
|
||||
mV8rt.release();
|
||||
}
|
||||
|
||||
public String readFile(String filename) throws IOException {
|
||||
byte[] bytes = mScriptReader.readFile(filename);
|
||||
String string = new String(bytes, "UTF-8");
|
||||
if (string.startsWith("#!/usr/bin/env node")) {
|
||||
string = string.substring(20);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.eclipsesource.v8.V8Object;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
|
||||
public class DetermineBasalResultAMA extends APSResult {
|
||||
public Date date;
|
||||
public JSONObject json = new JSONObject();
|
||||
public double eventualBG;
|
||||
public double snoozeBG;
|
||||
public IobTotal iob;
|
||||
|
||||
public DetermineBasalResultAMA(V8Object result, JSONObject j) {
|
||||
date = new Date();
|
||||
json = j;
|
||||
if (result.contains("error")) {
|
||||
reason = result.getString("error");
|
||||
changeRequested = false;
|
||||
rate = -1;
|
||||
duration = -1;
|
||||
} else {
|
||||
reason = result.getString("reason");
|
||||
eventualBG = result.getDouble("eventualBG");
|
||||
snoozeBG = result.getDouble("snoozeBG");
|
||||
if (result.contains("rate")) {
|
||||
rate = result.getDouble("rate");
|
||||
if (rate < 0d) rate = 0d;
|
||||
changeRequested = true;
|
||||
} else {
|
||||
rate = -1;
|
||||
changeRequested = false;
|
||||
}
|
||||
if (result.contains("duration")) {
|
||||
duration = result.getInteger("duration");
|
||||
changeRequested = changeRequested;
|
||||
} else {
|
||||
duration = -1;
|
||||
changeRequested = false;
|
||||
}
|
||||
}
|
||||
result.release();
|
||||
}
|
||||
|
||||
public DetermineBasalResultAMA() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetermineBasalResultAMA clone() {
|
||||
DetermineBasalResultAMA newResult = new DetermineBasalResultAMA();
|
||||
newResult.reason = new String(reason);
|
||||
newResult.rate = rate;
|
||||
newResult.duration = duration;
|
||||
newResult.changeRequested = changeRequested;
|
||||
newResult.rate = rate;
|
||||
newResult.duration = duration;
|
||||
newResult.changeRequested = changeRequested;
|
||||
|
||||
try {
|
||||
newResult.json = new JSONObject(json.toString());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
newResult.eventualBG = eventualBG;
|
||||
newResult.snoozeBG = snoozeBG;
|
||||
newResult.date = date;
|
||||
return newResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject json() {
|
||||
try {
|
||||
JSONObject ret = new JSONObject(this.json.toString());
|
||||
return ret;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<BgReading> getPredictions() {
|
||||
List<BgReading> array = new ArrayList<>();
|
||||
try {
|
||||
long startTime = date.getTime();
|
||||
if (json.has("predBGs")) {
|
||||
JSONObject predBGs = json.getJSONObject("predBGs");
|
||||
if (predBGs.has("IOB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("IOB");
|
||||
for (int i = 1; i < iob.length(); i ++) {
|
||||
BgReading bg = new BgReading();
|
||||
bg.value = iob.getInt(i);
|
||||
bg.timeIndex = startTime + i * 5 * 60 * 1000L;
|
||||
array.add(bg);
|
||||
}
|
||||
}
|
||||
if (predBGs.has("aCOB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("aCOB");
|
||||
for (int i = 1; i < iob.length(); i ++) {
|
||||
BgReading bg = new BgReading();
|
||||
bg.value = iob.getInt(i);
|
||||
bg.timeIndex = startTime + i * 5 * 60 * 1000L;
|
||||
array.add(bg);
|
||||
}
|
||||
}
|
||||
if (predBGs.has("COB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("COB");
|
||||
for (int i = 1; i < iob.length(); i ++) {
|
||||
BgReading bg = new BgReading();
|
||||
bg.value = iob.getInt(i);
|
||||
bg.timeIndex = startTime + i * 5 * 60 * 1000L;
|
||||
array.add(bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public long getLatestPredictionsTime() {
|
||||
long latest = 0;
|
||||
try {
|
||||
long startTime = date.getTime();
|
||||
if (json.has("predBGs")) {
|
||||
JSONObject predBGs = json.getJSONObject("predBGs");
|
||||
if (predBGs.has("IOB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("IOB");
|
||||
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
|
||||
}
|
||||
if (predBGs.has("aCOB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("aCOB");
|
||||
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
|
||||
}
|
||||
if (predBGs.has("COB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("COB");
|
||||
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return latest;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interfaces.FragmentBase;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.utils.JSONFormatter;
|
||||
|
||||
public class OpenAPSAMAFragment extends Fragment implements View.OnClickListener, FragmentBase {
|
||||
private static Logger log = LoggerFactory.getLogger(OpenAPSAMAFragment.class);
|
||||
|
||||
private static OpenAPSAMAPlugin openAPSAMAPlugin;
|
||||
|
||||
public static OpenAPSAMAPlugin getPlugin() {
|
||||
if(openAPSAMAPlugin ==null){
|
||||
openAPSAMAPlugin = new OpenAPSAMAPlugin();
|
||||
}
|
||||
return openAPSAMAPlugin;
|
||||
}
|
||||
|
||||
Button run;
|
||||
TextView lastRunView;
|
||||
TextView glucoseStatusView;
|
||||
TextView currentTempView;
|
||||
TextView iobDataView;
|
||||
TextView profileView;
|
||||
TextView mealDataView;
|
||||
TextView autosensDataView;
|
||||
TextView resultView;
|
||||
TextView scriptdebugView;
|
||||
TextView requestView;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.openapsama_fragment, container, false);
|
||||
|
||||
run = (Button) view.findViewById(R.id.openapsma_run);
|
||||
run.setOnClickListener(this);
|
||||
lastRunView = (TextView) view.findViewById(R.id.openapsma_lastrun);
|
||||
glucoseStatusView = (TextView) view.findViewById(R.id.openapsma_glucosestatus);
|
||||
currentTempView = (TextView) view.findViewById(R.id.openapsma_currenttemp);
|
||||
iobDataView = (TextView) view.findViewById(R.id.openapsma_iobdata);
|
||||
profileView = (TextView) view.findViewById(R.id.openapsma_profile);
|
||||
mealDataView = (TextView) view.findViewById(R.id.openapsma_mealdata);
|
||||
autosensDataView = (TextView) view.findViewById(R.id.openapsma_autosensdata);
|
||||
scriptdebugView = (TextView) view.findViewById(R.id.openapsma_scriptdebugdata);
|
||||
resultView = (TextView) view.findViewById(R.id.openapsma_result);
|
||||
requestView = (TextView) view.findViewById(R.id.openapsma_request);
|
||||
|
||||
updateGUI();
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.openapsma_run:
|
||||
getPlugin().invoke("OpenAPSAMA button");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
MainApp.bus().unregister(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
MainApp.bus().register(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
|
||||
updateGUI();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventOpenAPSUpdateResultGui ev) {
|
||||
updateResultGUI(ev.text);
|
||||
}
|
||||
|
||||
void updateGUI() {
|
||||
Activity activity = getActivity();
|
||||
if (activity != null)
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DetermineBasalResultAMA lastAPSResult = getPlugin().lastAPSResult;
|
||||
if (lastAPSResult != null) {
|
||||
resultView.setText(JSONFormatter.format(lastAPSResult.json));
|
||||
requestView.setText(lastAPSResult.toSpanned());
|
||||
}
|
||||
DetermineBasalAdapterAMAJS determineBasalAdapterAMAJS = getPlugin().lastDetermineBasalAdapterAMAJS;
|
||||
if (determineBasalAdapterAMAJS != null) {
|
||||
glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getGlucoseStatusParam()));
|
||||
currentTempView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getCurrentTempParam()));
|
||||
try {
|
||||
JSONArray iobArray = new JSONArray(determineBasalAdapterAMAJS.getIobDataParam());
|
||||
iobDataView.setText(String.format(MainApp.sResources.getString(R.string.array_of_elements), iobArray.length()) + "\n" + JSONFormatter.format(iobArray.getString(0)));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
iobDataView.setText("JSONException");
|
||||
}
|
||||
profileView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getProfileParam()));
|
||||
mealDataView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getMealDataParam()));
|
||||
autosensDataView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getAutosensDataParam()));
|
||||
scriptdebugView.setText(determineBasalAdapterAMAJS.getScriptDebug());
|
||||
}
|
||||
if (getPlugin().lastAPSRun != null) {
|
||||
lastRunView.setText(getPlugin().lastAPSRun.toLocaleString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateResultGUI(final String text) {
|
||||
Activity activity = getActivity();
|
||||
if (activity != null)
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultView.setText(text);
|
||||
glucoseStatusView.setText("");
|
||||
currentTempView.setText("");
|
||||
iobDataView.setText("");
|
||||
profileView.setText("");
|
||||
mealDataView.setText("");
|
||||
autosensDataView.setText("");
|
||||
scriptdebugView.setText("");
|
||||
requestView.setText("");
|
||||
lastRunView.setText("");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.interfaces.TempBasalsInterface;
|
||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.TempTargetRangePlugin;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.Round;
|
||||
import info.nightscout.utils.SafeParse;
|
||||
import info.nightscout.utils.ToastUtils;
|
||||
|
||||
/**
|
||||
* Created by mike on 05.08.2016.
|
||||
*/
|
||||
public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
|
||||
private static Logger log = LoggerFactory.getLogger(OpenAPSAMAPlugin.class);
|
||||
|
||||
// last values
|
||||
DetermineBasalAdapterAMAJS lastDetermineBasalAdapterAMAJS = null;
|
||||
Date lastAPSRun = null;
|
||||
DetermineBasalResultAMA lastAPSResult = null;
|
||||
|
||||
boolean fragmentEnabled = false;
|
||||
boolean fragmentVisible = true;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return MainApp.instance().getString(R.string.openapsama);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int type) {
|
||||
return type == APS && fragmentEnabled && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisibleInTabs(int type) {
|
||||
return type == APS && fragmentVisible && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeHidden(int type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragmentVisible(int type, boolean fragmentVisible) {
|
||||
if (type == APS) this.fragmentVisible = fragmentVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
|
||||
if (type == APS) this.fragmentEnabled = fragmentEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return PluginBase.APS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentClass() {
|
||||
return OpenAPSAMAFragment.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public APSResult getLastAPSResult() {
|
||||
return lastAPSResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastAPSRun() {
|
||||
return lastAPSRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String initiator) {
|
||||
log.debug("invoke from " + initiator);
|
||||
lastAPSResult = null;
|
||||
DetermineBasalAdapterAMAJS determineBasalAdapterAMAJS = null;
|
||||
try {
|
||||
determineBasalAdapterAMAJS = new DetermineBasalAdapterAMAJS(new ScriptReader(MainApp.instance().getBaseContext()));
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
PumpInterface pump = MainApp.getConfigBuilder();
|
||||
|
||||
if (!isEnabled(PluginBase.APS)) {
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_disabled)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_disabled));
|
||||
return;
|
||||
}
|
||||
|
||||
if (glucoseStatus == null) {
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noglucosedata)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_noglucosedata));
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile == null) {
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noprofile)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_noprofile));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pump == null) {
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_nopump)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_nopump));
|
||||
return;
|
||||
}
|
||||
|
||||
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
|
||||
String units = profile.getUnits();
|
||||
|
||||
String maxBgDefault = "180";
|
||||
String minBgDefault = "100";
|
||||
String targetBgDefault = "150";
|
||||
if (!units.equals(Constants.MGDL)) {
|
||||
maxBgDefault = "10";
|
||||
minBgDefault = "5";
|
||||
targetBgDefault = "7";
|
||||
}
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
double maxIob = SafeParse.stringToDouble(SP.getString("openapsma_max_iob", "1.5"));
|
||||
double maxBasal = SafeParse.stringToDouble(SP.getString("openapsma_max_basal", "1"));
|
||||
double minBg = NSProfile.toMgdl(SafeParse.stringToDouble(SP.getString("openapsma_min_bg", minBgDefault)), units);
|
||||
double maxBg = NSProfile.toMgdl(SafeParse.stringToDouble(SP.getString("openapsma_max_bg", maxBgDefault)), units);
|
||||
double targetBg = NSProfile.toMgdl(SafeParse.stringToDouble(SP.getString("openapsma_target_bg", targetBgDefault)), units);
|
||||
|
||||
minBg = Round.roundTo(minBg, 0.1d);
|
||||
maxBg = Round.roundTo(maxBg, 0.1d);
|
||||
|
||||
IobTotal[] iobArray = IobTotal.calculateIobArrayInDia();
|
||||
|
||||
MealData mealData = MainApp.getConfigBuilder().getActiveTreatments().getMealData();
|
||||
|
||||
maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob);
|
||||
|
||||
minBg = verifyHardLimits(minBg, "minBg", 72, 180);
|
||||
maxBg = verifyHardLimits(maxBg, "maxBg", 100, 270);
|
||||
targetBg = verifyHardLimits(targetBg, "targetBg", 80, 200);
|
||||
|
||||
boolean isTempTarget = false;
|
||||
TempTargetRangePlugin tempTargetRangePlugin = (TempTargetRangePlugin) MainApp.getSpecificPlugin(TempTargetRangePlugin.class);
|
||||
if (tempTargetRangePlugin != null && tempTargetRangePlugin.isEnabled(PluginBase.GENERAL)) {
|
||||
TempTarget tempTarget = tempTargetRangePlugin.getTempTargetInProgress(new Date().getTime());
|
||||
if (tempTarget != null) {
|
||||
isTempTarget = true;
|
||||
minBg = verifyHardLimits(tempTarget.low, "minBg", 72, 180);
|
||||
maxBg = verifyHardLimits(tempTarget.high, "maxBg", 72, 270);
|
||||
targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", 72, 200);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
maxIob = verifyHardLimits(maxIob, "maxIob", 0, 7);
|
||||
maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, 10);
|
||||
|
||||
if (!checkOnlyHardLimits(profile.getCarbAbsorbtionRate(), "carbs_hr", 4, 100)) return;
|
||||
if (!checkOnlyHardLimits(profile.getDia(), "dia", 2, 7)) return;
|
||||
if (!checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", 2, 100)) return;
|
||||
if (!checkOnlyHardLimits(NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()).doubleValue(), units), "sens", 2, 900)) return;
|
||||
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, 10)) return;
|
||||
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, 5)) return;
|
||||
|
||||
long oldestDataAvailable = MainApp.getConfigBuilder().getActiveTempBasals().oldestDataAvaialable();
|
||||
List<BgReading> bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(Math.max(oldestDataAvailable, (long) (new Date().getTime() - 60 * 60 * 1000L * (24 + profile.getDia()))), false);
|
||||
log.debug("Limiting data to oldest available temps: " + new Date(oldestDataAvailable).toString() + " (" + bgReadings.size() + " records)");
|
||||
AutosensResult autosensResult = Autosens.detectSensitivityandCarbAbsorption(bgReadings, new Date().getTime());
|
||||
|
||||
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobArray, glucoseStatus, mealData,
|
||||
autosensResult.ratio, //autosensDataRatio
|
||||
isTempTarget,
|
||||
Constants.MIN_5M_CARBIMPACT //min_5m_carbimpact
|
||||
);
|
||||
|
||||
|
||||
DetermineBasalResultAMA determineBasalResultAMA = determineBasalAdapterAMAJS.invoke();
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
|
||||
determineBasalResultAMA.changeRequested = false;
|
||||
// limit requests on openloop mode
|
||||
if (!MainApp.getConfigBuilder().isClosedModeEnabled()) {
|
||||
if (MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultAMA.rate - MainApp.getConfigBuilder().getTempBasalAbsoluteRate()) < 0.1)
|
||||
determineBasalResultAMA.changeRequested = false;
|
||||
if (!MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultAMA.rate - MainApp.getConfigBuilder().getBaseBasalRate()) < 0.1)
|
||||
determineBasalResultAMA.changeRequested = false;
|
||||
}
|
||||
|
||||
determineBasalResultAMA.iob = iobArray[0];
|
||||
|
||||
determineBasalAdapterAMAJS.release();
|
||||
|
||||
try {
|
||||
determineBasalResultAMA.json.put("timestamp", DateUtil.toISOString(now));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS;
|
||||
lastAPSResult = determineBasalResultAMA;
|
||||
lastAPSRun = now;
|
||||
MainApp.bus().post(new EventOpenAPSUpdateGui());
|
||||
|
||||
//deviceStatus.suggested = determineBasalResultAMA.json;
|
||||
}
|
||||
|
||||
// safety checks
|
||||
public static boolean checkOnlyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
|
||||
return value.equals(verifyHardLimits(value, valueName, lowLimit, highLimit));
|
||||
}
|
||||
|
||||
public static Double verifyHardLimits(Double value, String valueName, double lowLimit, double highLimit) {
|
||||
if (value < lowLimit || value > highLimit) {
|
||||
String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), valueName);
|
||||
log.error(msg);
|
||||
MainApp.getConfigBuilder().uploadError(msg);
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
|
||||
value = Math.max(value, lowLimit);
|
||||
value = Math.min(value, highLimit);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSMA;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.eclipsesource.v8.JavaVoidCallback;
|
||||
import com.eclipsesource.v8.V8;
|
||||
import com.eclipsesource.v8.V8Array;
|
||||
|
@ -16,15 +13,15 @@ import org.slf4j.LoggerFactory;
|
|||
import java.io.IOException;
|
||||
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
|
||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
|
||||
public class DetermineBasalAdapterJS implements Parcelable {
|
||||
private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterJS.class);
|
||||
public class DetermineBasalAdapterMAJS {
|
||||
private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterMAJS.class);
|
||||
|
||||
|
||||
private ScriptReader mScriptReader = null;
|
||||
|
@ -47,49 +44,11 @@ public class DetermineBasalAdapterJS implements Parcelable {
|
|||
private String storedProfile = null;
|
||||
private String storedMeal_data = null;
|
||||
|
||||
/**
|
||||
* Parcelable implementation
|
||||
* result string for display only
|
||||
**/
|
||||
protected DetermineBasalAdapterJS(Parcel in) {
|
||||
storedCurrentTemp = in.readString();
|
||||
storedIobData = in.readString();
|
||||
storedGlucoseStatus = in.readString();
|
||||
storedProfile = in.readString();
|
||||
storedMeal_data = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(storedCurrentTemp);
|
||||
dest.writeString(storedIobData);
|
||||
dest.writeString(storedGlucoseStatus);
|
||||
dest.writeString(storedProfile);
|
||||
dest.writeString(storedMeal_data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<DetermineBasalAdapterJS> CREATOR = new Creator<DetermineBasalAdapterJS>() {
|
||||
@Override
|
||||
public DetermineBasalAdapterJS createFromParcel(Parcel in) {
|
||||
return new DetermineBasalAdapterJS(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetermineBasalAdapterJS[] newArray(int size) {
|
||||
return new DetermineBasalAdapterJS[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Main code
|
||||
*/
|
||||
|
||||
public DetermineBasalAdapterJS(ScriptReader scriptReader) throws IOException {
|
||||
public DetermineBasalAdapterMAJS(ScriptReader scriptReader) throws IOException {
|
||||
mV8rt = V8.createV8Runtime();
|
||||
mScriptReader = scriptReader;
|
||||
|
||||
|
@ -143,7 +102,7 @@ public class DetermineBasalAdapterJS implements Parcelable {
|
|||
mV8rt.add(PARAM_meal_data, mMealData);
|
||||
}
|
||||
|
||||
public DetermineBasalResult invoke() {
|
||||
public DetermineBasalResultMA invoke() {
|
||||
mV8rt.executeVoidScript(
|
||||
"console.error(\"determine_basal(\"+\n" +
|
||||
"JSON.stringify(" + PARAM_glucoseStatus + ")+ \", \" +\n" +
|
||||
|
@ -170,14 +129,13 @@ public class DetermineBasalAdapterJS implements Parcelable {
|
|||
|
||||
V8Object v8ObjectReuslt = mV8rt.getObject("rT");
|
||||
|
||||
DetermineBasalResult result = null;
|
||||
DetermineBasalResultMA result = null;
|
||||
try {
|
||||
result = new DetermineBasalResult(v8ObjectReuslt, new JSONObject(ret));
|
||||
result = new DetermineBasalResultMA(v8ObjectReuslt, new JSONObject(ret));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Store input params for Parcelable
|
||||
storedGlucoseStatus = mV8rt.executeStringScript("JSON.stringify(" + PARAM_glucoseStatus + ");");
|
||||
storedIobData = mV8rt.executeStringScript("JSON.stringify(" + PARAM_iobData + ");");
|
||||
storedCurrentTemp = mV8rt.executeStringScript("JSON.stringify(" + PARAM_currentTemp + ");");
|
||||
|
@ -266,8 +224,8 @@ public class DetermineBasalAdapterJS implements Parcelable {
|
|||
double targetBg,
|
||||
PumpInterface pump,
|
||||
IobTotal iobData,
|
||||
DatabaseHelper.GlucoseStatus glucoseStatus,
|
||||
TreatmentsPlugin.MealData mealData) {
|
||||
GlucoseStatus glucoseStatus,
|
||||
MealData mealData) {
|
||||
|
||||
String units = profile.getUnits();
|
||||
|
|
@ -8,9 +8,10 @@ import com.eclipsesource.v8.V8Object;
|
|||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
|
||||
public class DetermineBasalResult extends APSResult {
|
||||
public class DetermineBasalResultMA extends APSResult {
|
||||
|
||||
public JSONObject json = new JSONObject();
|
||||
public double eventualBG;
|
||||
|
@ -18,7 +19,7 @@ public class DetermineBasalResult extends APSResult {
|
|||
public String mealAssist;
|
||||
public IobTotal iob;
|
||||
|
||||
public DetermineBasalResult(V8Object result, JSONObject j) {
|
||||
public DetermineBasalResultMA(V8Object result, JSONObject j) {
|
||||
json = j;
|
||||
if (result.contains("error")) {
|
||||
reason = result.getString("error");
|
||||
|
@ -52,43 +53,12 @@ public class DetermineBasalResult extends APSResult {
|
|||
result.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(json.toString());
|
||||
dest.writeDouble(eventualBG);
|
||||
dest.writeDouble(snoozeBG);
|
||||
dest.writeString(mealAssist);
|
||||
}
|
||||
|
||||
public final Parcelable.Creator<DetermineBasalResult> CREATOR = new Parcelable.Creator<DetermineBasalResult>() {
|
||||
public DetermineBasalResult createFromParcel(Parcel in) {
|
||||
return new DetermineBasalResult(in);
|
||||
}
|
||||
|
||||
public DetermineBasalResult[] newArray(int size) {
|
||||
return new DetermineBasalResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
private DetermineBasalResult(Parcel in) {
|
||||
super(in);
|
||||
try {
|
||||
json = new JSONObject(in.readString());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
eventualBG = in.readDouble();
|
||||
snoozeBG = in.readDouble();
|
||||
mealAssist = in.readString();
|
||||
}
|
||||
|
||||
public DetermineBasalResult() {
|
||||
public DetermineBasalResultMA() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetermineBasalResult clone() {
|
||||
DetermineBasalResult newResult = new DetermineBasalResult();
|
||||
public DetermineBasalResultMA clone() {
|
||||
DetermineBasalResultMA newResult = new DetermineBasalResultMA();
|
||||
newResult.reason = new String(reason);
|
||||
newResult.rate = rate;
|
||||
newResult.duration = duration;
|
|
@ -1,76 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSMA;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.Round;
|
||||
|
||||
public class IobTotal {
|
||||
public Double iob;
|
||||
public Double activity;
|
||||
public Double bolussnooze;
|
||||
public Double basaliob;
|
||||
public Double netbasalinsulin;
|
||||
public Double hightempinsulin;
|
||||
|
||||
public Double netInsulin = 0d; // for calculations from temp basals only
|
||||
public Double netRatio = 0d; // for calculations from temp basals only
|
||||
|
||||
public IobTotal() {
|
||||
this.iob = 0d;
|
||||
this.activity = 0d;
|
||||
this.bolussnooze = 0d;
|
||||
this.basaliob = 0d;
|
||||
this.netbasalinsulin = 0d;
|
||||
this.hightempinsulin = 0d;
|
||||
}
|
||||
|
||||
public IobTotal plus(IobTotal other) {
|
||||
iob += other.iob;
|
||||
activity += other.activity;
|
||||
bolussnooze += other.bolussnooze;
|
||||
basaliob += other.basaliob;
|
||||
netbasalinsulin += other.netbasalinsulin;
|
||||
hightempinsulin += other.hightempinsulin;
|
||||
netInsulin += other.netInsulin;
|
||||
netRatio += other.netRatio;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static IobTotal combine(IobTotal bolusIOB, IobTotal basalIob) {
|
||||
IobTotal result = new IobTotal();
|
||||
result.iob = bolusIOB.iob + basalIob.basaliob;
|
||||
result.activity = bolusIOB.activity + basalIob.activity;
|
||||
result.bolussnooze = bolusIOB.bolussnooze;
|
||||
result.basaliob = basalIob.basaliob;
|
||||
result.netbasalinsulin = basalIob.netbasalinsulin;
|
||||
result.hightempinsulin = basalIob.hightempinsulin;
|
||||
return result;
|
||||
}
|
||||
|
||||
public IobTotal round() {
|
||||
this.iob = Round.roundTo(this.iob, 0.001);
|
||||
this.activity = Round.roundTo(this.activity, 0.0001);
|
||||
this.bolussnooze = Round.roundTo(this.bolussnooze, 0.0001);
|
||||
this.basaliob = Round.roundTo(this.basaliob, 0.001);
|
||||
this.netbasalinsulin = Round.roundTo(this.netbasalinsulin, 0.001);
|
||||
this.hightempinsulin = Round.roundTo(this.hightempinsulin, 0.001);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("iob", iob);
|
||||
json.put("basaliob", basaliob);
|
||||
json.put("activity", activity);
|
||||
json.put("time", DateUtil.toISOString(new Date()));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -17,9 +17,8 @@ import org.slf4j.LoggerFactory;
|
|||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interfaces.FragmentBase;
|
||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSMAUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSMAUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.utils.JSONFormatter;
|
||||
|
||||
public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, FragmentBase {
|
||||
|
@ -68,7 +67,7 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
|
|||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.openapsma_run:
|
||||
getPlugin().invoke();
|
||||
getPlugin().invoke("OpenAPSMA button");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -87,12 +86,12 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
|
|||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventOpenAPSMAUpdateGui ev) {
|
||||
public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
|
||||
updateGUI();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventOpenAPSMAUpdateResultGui ev) {
|
||||
public void onStatusEvent(final EventOpenAPSUpdateResultGui ev) {
|
||||
updateResultGUI(ev.text);
|
||||
}
|
||||
|
||||
|
@ -102,18 +101,18 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
|
|||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DetermineBasalResult lastAPSResult = getPlugin().lastAPSResult;
|
||||
DetermineBasalResultMA lastAPSResult = getPlugin().lastAPSResult;
|
||||
if (lastAPSResult != null) {
|
||||
resultView.setText(JSONFormatter.format(lastAPSResult.json));
|
||||
requestView.setText(lastAPSResult.toSpanned());
|
||||
}
|
||||
DetermineBasalAdapterJS determineBasalAdapterJS = getPlugin().lastDetermineBasalAdapterJS;
|
||||
if (determineBasalAdapterJS != null) {
|
||||
glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterJS.getGlucoseStatusParam()));
|
||||
currentTempView.setText(JSONFormatter.format(determineBasalAdapterJS.getCurrentTempParam()));
|
||||
iobDataView.setText(JSONFormatter.format(determineBasalAdapterJS.getIobDataParam()));
|
||||
profileView.setText(JSONFormatter.format(determineBasalAdapterJS.getProfileParam()));
|
||||
mealDataView.setText(JSONFormatter.format(determineBasalAdapterJS.getMealDataParam()));
|
||||
DetermineBasalAdapterMAJS determineBasalAdapterMAJS = getPlugin().lastDetermineBasalAdapterMAJS;
|
||||
if (determineBasalAdapterMAJS != null) {
|
||||
glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getGlucoseStatusParam()));
|
||||
currentTempView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getCurrentTempParam()));
|
||||
iobDataView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getIobDataParam()));
|
||||
profileView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getProfileParam()));
|
||||
mealDataView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getMealDataParam()));
|
||||
}
|
||||
if (getPlugin().lastAPSRun != null) {
|
||||
lastRunView.setText(getPlugin().lastAPSRun.toLocaleString());
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSMA;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -18,8 +14,10 @@ import info.nightscout.androidaps.Config;
|
|||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.Services.Intents;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
|
@ -27,10 +25,9 @@ import info.nightscout.androidaps.interfaces.TempBasalsInterface;
|
|||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSMAUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSMAUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
|
||||
import info.nightscout.client.data.DbLogger;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.TempTargetRangePlugin;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.Round;
|
||||
|
@ -44,9 +41,9 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
|
|||
private static Logger log = LoggerFactory.getLogger(OpenAPSMAPlugin.class);
|
||||
|
||||
// last values
|
||||
DetermineBasalAdapterJS lastDetermineBasalAdapterJS = null;
|
||||
DetermineBasalAdapterMAJS lastDetermineBasalAdapterMAJS = null;
|
||||
Date lastAPSRun = null;
|
||||
DetermineBasalResult lastAPSResult = null;
|
||||
DetermineBasalResultMA lastAPSResult = null;
|
||||
|
||||
boolean fragmentEnabled = false;
|
||||
boolean fragmentVisible = true;
|
||||
|
@ -102,43 +99,44 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
public void invoke(String initiator) {
|
||||
log.debug("invoke from " + initiator);
|
||||
lastAPSResult = null;
|
||||
DetermineBasalAdapterJS determineBasalAdapterJS = null;
|
||||
DetermineBasalAdapterMAJS determineBasalAdapterMAJS = null;
|
||||
try {
|
||||
determineBasalAdapterJS = new DetermineBasalAdapterJS(new ScriptReader(MainApp.instance().getBaseContext()));
|
||||
determineBasalAdapterMAJS = new DetermineBasalAdapterMAJS(new ScriptReader(MainApp.instance().getBaseContext()));
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
PumpInterface pump = MainApp.getConfigBuilder();
|
||||
|
||||
if (!isEnabled(PluginBase.APS)) {
|
||||
MainApp.bus().post(new EventOpenAPSMAUpdateResultGui(MainApp.instance().getString(R.string.openapsma_disabled)));
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_disabled)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_disabled));
|
||||
return;
|
||||
}
|
||||
|
||||
if (glucoseStatus == null) {
|
||||
MainApp.bus().post(new EventOpenAPSMAUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noglucosedata)));
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noglucosedata)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_noglucosedata));
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile == null) {
|
||||
MainApp.bus().post(new EventOpenAPSMAUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noprofile)));
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noprofile)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_noprofile));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pump == null) {
|
||||
MainApp.bus().post(new EventOpenAPSMAUpdateResultGui(MainApp.instance().getString(R.string.openapsma_nopump)));
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_nopump)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_nopump));
|
||||
return;
|
||||
|
@ -176,13 +174,24 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
|
|||
|
||||
IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
|
||||
|
||||
TreatmentsPlugin.MealData mealData = treatments.getMealData();
|
||||
MealData mealData = treatments.getMealData();
|
||||
|
||||
maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob);
|
||||
|
||||
minBg = verifyHardLimits(minBg, "minBg", 72, 180);
|
||||
maxBg = verifyHardLimits(maxBg, "maxBg", 100, 270);
|
||||
targetBg = verifyHardLimits(targetBg, "targetBg", 80, 200);
|
||||
|
||||
TempTargetRangePlugin tempTargetRangePlugin = (TempTargetRangePlugin) MainApp.getSpecificPlugin(TempTargetRangePlugin.class);
|
||||
if (tempTargetRangePlugin != null && tempTargetRangePlugin.isEnabled(PluginBase.GENERAL)) {
|
||||
TempTarget tempTarget = tempTargetRangePlugin.getTempTargetInProgress(new Date().getTime());
|
||||
if (tempTarget != null) {
|
||||
minBg = verifyHardLimits(tempTarget.low, "minBg", 72, 180);
|
||||
maxBg = verifyHardLimits(tempTarget.high, "maxBg", 72, 270);
|
||||
targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", 72, 200);
|
||||
}
|
||||
}
|
||||
|
||||
maxIob = verifyHardLimits(maxIob, "maxIob", 0, 7);
|
||||
maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, 10);
|
||||
|
||||
|
@ -193,37 +202,37 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
|
|||
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.1, 10)) return;
|
||||
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, 5)) return;
|
||||
|
||||
determineBasalAdapterJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobTotal, glucoseStatus, mealData);
|
||||
determineBasalAdapterMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobTotal, glucoseStatus, mealData);
|
||||
|
||||
|
||||
DetermineBasalResult determineBasalResult = determineBasalAdapterJS.invoke();
|
||||
DetermineBasalResultMA determineBasalResultMA = determineBasalAdapterMAJS.invoke();
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResult.rate == 0d && determineBasalResult.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
|
||||
determineBasalResult.changeRequested = false;
|
||||
if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
|
||||
determineBasalResultMA.changeRequested = false;
|
||||
// limit requests on openloop mode
|
||||
if (!MainApp.getConfigBuilder().isClosedModeEnabled()) {
|
||||
if (MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResult.rate - MainApp.getConfigBuilder().getTempBasalAbsoluteRate()) < 0.1)
|
||||
determineBasalResult.changeRequested = false;
|
||||
if (!MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResult.rate - MainApp.getConfigBuilder().getBaseBasalRate()) < 0.1)
|
||||
determineBasalResult.changeRequested = false;
|
||||
if (MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultMA.rate - MainApp.getConfigBuilder().getTempBasalAbsoluteRate()) < 0.1)
|
||||
determineBasalResultMA.changeRequested = false;
|
||||
if (!MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultMA.rate - MainApp.getConfigBuilder().getBaseBasalRate()) < 0.1)
|
||||
determineBasalResultMA.changeRequested = false;
|
||||
}
|
||||
|
||||
determineBasalResult.iob = iobTotal;
|
||||
determineBasalResultMA.iob = iobTotal;
|
||||
|
||||
determineBasalAdapterJS.release();
|
||||
determineBasalAdapterMAJS.release();
|
||||
|
||||
try {
|
||||
determineBasalResult.json.put("timestamp", DateUtil.toISOString(now));
|
||||
determineBasalResultMA.json.put("timestamp", DateUtil.toISOString(now));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
lastDetermineBasalAdapterJS = determineBasalAdapterJS;
|
||||
lastAPSResult = determineBasalResult;
|
||||
lastDetermineBasalAdapterMAJS = determineBasalAdapterMAJS;
|
||||
lastAPSResult = determineBasalResultMA;
|
||||
lastAPSRun = now;
|
||||
MainApp.bus().post(new EventOpenAPSMAUpdateGui());
|
||||
MainApp.bus().post(new EventOpenAPSUpdateGui());
|
||||
|
||||
//deviceStatus.suggested = determineBasalResult.json;
|
||||
//deviceStatus.suggested = determineBasalResultMA.json;
|
||||
}
|
||||
|
||||
// safety checks
|
||||
|
|
|
@ -3,5 +3,5 @@ package info.nightscout.androidaps.plugins.OpenAPSMA.events;
|
|||
/**
|
||||
* Created by mike on 05.08.2016.
|
||||
*/
|
||||
public class EventOpenAPSMAUpdateGui {
|
||||
public class EventOpenAPSUpdateGui {
|
||||
}
|
|
@ -3,10 +3,10 @@ package info.nightscout.androidaps.plugins.OpenAPSMA.events;
|
|||
/**
|
||||
* Created by mike on 05.08.2016.
|
||||
*/
|
||||
public class EventOpenAPSMAUpdateResultGui {
|
||||
public class EventOpenAPSUpdateResultGui {
|
||||
public String text = null;
|
||||
|
||||
public EventOpenAPSMAUpdateResultGui(String text) {
|
||||
public EventOpenAPSUpdateResultGui(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
|
@ -38,18 +38,15 @@ import info.nightscout.androidaps.MainApp;
|
|||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.interfaces.TempBasalsInterface;
|
||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.BolusWizard;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
import info.nightscout.utils.PlusMinusEditText;
|
||||
import info.nightscout.utils.Round;
|
||||
import info.nightscout.utils.SafeParse;
|
||||
import info.nightscout.utils.ToastUtils;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ public class Notification {
|
|||
public static final int PROFILE_NOT_SET_NOT_INITIALIZED = 5;
|
||||
public static final int FAILED_UDPATE_PROFILE = 6;
|
||||
public static final int BASAL_VALUE_BELOW_MINIMUM = 7;
|
||||
public static final int OLD_NSCLIENT = 8;
|
||||
|
||||
public int id;
|
||||
public Date date;
|
||||
|
|
|
@ -22,6 +22,8 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
@ -49,10 +51,12 @@ import info.nightscout.androidaps.Config;
|
|||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.db.TempBasal;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.db.Treatment;
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged;
|
||||
import info.nightscout.androidaps.events.EventNewBG;
|
||||
|
@ -69,13 +73,16 @@ import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
|||
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
|
||||
import info.nightscout.androidaps.plugins.Objectives.ObjectivesPlugin;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.DetermineBasalResultAMA;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
|
||||
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTreatmentDialog;
|
||||
import info.nightscout.androidaps.plugins.Overview.Dialogs.WizardDialog;
|
||||
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
|
||||
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
|
||||
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
|
||||
import info.nightscout.androidaps.plugins.Overview.graphExtensions.TimeAsXAxisLabelFormatter;
|
||||
import info.nightscout.androidaps.plugins.TempBasals.TempBasalsPlugin;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.TempTargetRangePlugin;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.BolusWizard;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
|
@ -105,7 +112,9 @@ public class OverviewFragment extends Fragment {
|
|||
TextView activeProfileView;
|
||||
TextView iobView;
|
||||
TextView apsModeView;
|
||||
TextView tempTargetView;
|
||||
GraphView bgGraph;
|
||||
CheckBox showPredictionView;
|
||||
|
||||
RecyclerView notificationsView;
|
||||
LinearLayoutManager llm;
|
||||
|
@ -152,6 +161,7 @@ public class OverviewFragment extends Fragment {
|
|||
|
||||
iobView = (TextView) view.findViewById(R.id.overview_iob);
|
||||
apsModeView = (TextView) view.findViewById(R.id.overview_apsmode);
|
||||
tempTargetView = (TextView) view.findViewById(R.id.overview_temptarget);
|
||||
bgGraph = (GraphView) view.findViewById(R.id.overview_bggraph);
|
||||
cancelTempButton = (Button) view.findViewById(R.id.overview_canceltemp);
|
||||
treatmentButton = (Button) view.findViewById(R.id.overview_treatment);
|
||||
|
@ -162,12 +172,25 @@ public class OverviewFragment extends Fragment {
|
|||
acceptTempLayout = (LinearLayout) view.findViewById(R.id.overview_accepttemplayout);
|
||||
quickWizardButton = (Button) view.findViewById(R.id.overview_quickwizard);
|
||||
quickWizardLayout = (LinearLayout) view.findViewById(R.id.overview_quickwizardlayout);
|
||||
showPredictionView = (CheckBox) view.findViewById(R.id.overview_showprediction);
|
||||
|
||||
notificationsView = (RecyclerView) view.findViewById(R.id.overview_notifications);
|
||||
notificationsView.setHasFixedSize(true);
|
||||
llm = new LinearLayoutManager(view.getContext());
|
||||
notificationsView.setLayoutManager(llm);
|
||||
|
||||
showPredictionView.setChecked(prefs.getBoolean("showprediction", false));
|
||||
|
||||
showPredictionView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean("showprediction", showPredictionView.isChecked());
|
||||
editor.apply();
|
||||
updateGUI();
|
||||
}
|
||||
});
|
||||
|
||||
treatmentButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
@ -214,7 +237,7 @@ public class OverviewFragment extends Fragment {
|
|||
acceptTempButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
MainApp.getConfigBuilder().getActiveLoop().invoke(false);
|
||||
MainApp.getConfigBuilder().getActiveLoop().invoke("Accept temp button", false);
|
||||
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
|
||||
if (finalLastRun != null && finalLastRun.lastAPSRun != null && finalLastRun.constraintsProcessed.changeRequested) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
|
@ -441,7 +464,7 @@ public class OverviewFragment extends Fragment {
|
|||
updateNotifications();
|
||||
BgReading actualBG = MainApp.getDbHelper().actualBg();
|
||||
BgReading lastBG = MainApp.getDbHelper().lastBg();
|
||||
if (MainApp.getConfigBuilder() == null || MainApp.getConfigBuilder().getActiveProfile() == null) // app not initialized yet
|
||||
if (MainApp.getConfigBuilder() == null || MainApp.getConfigBuilder().getActiveProfile() == null || MainApp.getConfigBuilder().getActiveProfile().getProfile() == null) // app not initialized yet
|
||||
return;
|
||||
|
||||
// Skip if not initialized yet
|
||||
|
@ -497,8 +520,20 @@ public class OverviewFragment extends Fragment {
|
|||
apsModeView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// **** Temp button ****
|
||||
// temp target
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
TempTargetRangePlugin tempTargetRangePlugin = (TempTargetRangePlugin) MainApp.getSpecificPlugin(TempTargetRangePlugin.class);
|
||||
if (tempTargetRangePlugin != null && tempTargetRangePlugin.isEnabled(PluginBase.GENERAL)) {
|
||||
TempTarget tempTarget = tempTargetRangePlugin.getTempTargetInProgress(new Date().getTime());
|
||||
if (tempTarget != null) {
|
||||
tempTargetView.setVisibility(View.VISIBLE);
|
||||
tempTargetView.setText(NSProfile.toUnitsString(tempTarget.low, NSProfile.fromMgdlToUnits(tempTarget.low, profile.getUnits()), profile.getUnits()) + " - " + NSProfile.toUnitsString(tempTarget.high, NSProfile.fromMgdlToUnits(tempTarget.high, profile.getUnits()), profile.getUnits()));
|
||||
} else {
|
||||
tempTargetView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
// **** Temp button ****
|
||||
PumpInterface pump = MainApp.getConfigBuilder();
|
||||
|
||||
boolean showAcceptButton = !MainApp.getConfigBuilder().isClosedModeEnabled(); // Open mode needed
|
||||
|
@ -513,8 +548,8 @@ public class OverviewFragment extends Fragment {
|
|||
acceptTempLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
TempBasal activeTemp = pump.getTempBasal();
|
||||
if (pump.isTempBasalInProgress()) {
|
||||
TempBasal activeTemp = pump.getTempBasal();
|
||||
cancelTempLayout.setVisibility(View.VISIBLE);
|
||||
cancelTempButton.setText(MainApp.instance().getString(R.string.cancel) + ": " + activeTemp.toString());
|
||||
runningTempView.setVisibility(View.VISIBLE);
|
||||
|
@ -539,7 +574,7 @@ public class OverviewFragment extends Fragment {
|
|||
public boolean onLongClick(View view) {
|
||||
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false, false);
|
||||
profileswitch.executeProfileSwitch = true;
|
||||
newDialog.setOptions(profileswitch);
|
||||
newDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
|
||||
|
@ -578,10 +613,11 @@ public class OverviewFragment extends Fragment {
|
|||
if (lastBG != null && bgView != null) {
|
||||
bgView.setText(lastBG.valueToUnitsToString(profile.getUnits()));
|
||||
arrowView.setText(lastBG.directionToSymbol());
|
||||
DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
if (glucoseStatus != null){
|
||||
deltaView.setText("Δ " + NSProfile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units);
|
||||
avgdeltaView.setText("øΔ " + NSProfile.toUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units) + " " + units);
|
||||
avgdeltaView.setText("øΔ15m: " + NSProfile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units) +
|
||||
" øΔ40m: " + NSProfile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units));
|
||||
}
|
||||
|
||||
BgReading.units = profile.getUnits();
|
||||
|
@ -602,16 +638,21 @@ public class OverviewFragment extends Fragment {
|
|||
// iob
|
||||
MainApp.getConfigBuilder().getActiveTreatments().updateTotalIOB();
|
||||
IobTotal bolusIob = MainApp.getConfigBuilder().getActiveTreatments().getLastCalculation().round();
|
||||
if (bolusIob == null) bolusIob = new IobTotal();
|
||||
MainApp.getConfigBuilder().getActiveTempBasals().updateTotalIOB();
|
||||
IobTotal basalIob = MainApp.getConfigBuilder().getActiveTempBasals().getLastCalculation().round();
|
||||
if (basalIob == null) basalIob = new IobTotal();
|
||||
|
||||
String iobtext = getString(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U ("
|
||||
+ getString(R.string.bolus) + ": " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
|
||||
+ getString(R.string.basal) + ": " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U)";
|
||||
iobView.setText(iobtext);
|
||||
|
||||
boolean showPrediction = showPredictionView.isChecked() && finalLastRun != null && finalLastRun.constraintsProcessed.getClass().equals(DetermineBasalResultAMA.class);
|
||||
if (MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class) != null && MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class).isEnabled(PluginBase.APS)) {
|
||||
showPredictionView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
showPredictionView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// ****** GRAPH *******
|
||||
|
||||
// allign to hours
|
||||
|
@ -622,9 +663,24 @@ public class OverviewFragment extends Fragment {
|
|||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.add(Calendar.HOUR, 1);
|
||||
|
||||
int hoursToFetch = 6;
|
||||
long toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding
|
||||
long fromTime = toTime - hoursToFetch * 60 * 60 * 1000L;
|
||||
int hoursToFetch;
|
||||
long toTime;
|
||||
long fromTime;
|
||||
long endTime;
|
||||
if (showPrediction) {
|
||||
int predHours = (int) (Math.ceil(((DetermineBasalResultAMA)finalLastRun.constraintsProcessed).getLatestPredictionsTime() - new Date().getTime()) / (60 * 60 * 1000));
|
||||
predHours = Math.min(2, predHours);
|
||||
predHours = Math.max(0, predHours);
|
||||
hoursToFetch = (int) (6 - predHours);
|
||||
toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding
|
||||
fromTime = toTime - hoursToFetch * 60 * 60 * 1000L;
|
||||
endTime = toTime + predHours * 60 * 60 * 1000L;
|
||||
} else {
|
||||
hoursToFetch = 6;
|
||||
toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding
|
||||
fromTime = toTime - hoursToFetch * 60 * 60 * 1000L;
|
||||
endTime = toTime;
|
||||
}
|
||||
|
||||
Double lowLine = SafeParse.stringToDouble(prefs.getString("low_mark", "0"));
|
||||
Double highLine = SafeParse.stringToDouble(prefs.getString("high_mark", "0"));
|
||||
|
@ -637,12 +693,14 @@ public class OverviewFragment extends Fragment {
|
|||
highLine = NSProfile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units);
|
||||
}
|
||||
|
||||
LineGraphSeries<DataPoint> basalsLineSeries = null;
|
||||
BarGraphSeries<DataPoint> basalsSeries = null;
|
||||
LineGraphSeries<DataPoint> seriesLow = null;
|
||||
LineGraphSeries<DataPoint> seriesHigh = null;
|
||||
LineGraphSeries<DataPoint> seriesNow = null;
|
||||
PointsGraphSeries<BgReading> seriesInRage = null;
|
||||
PointsGraphSeries<BgReading> seriesOutOfRange = null;
|
||||
PointsGraphSeries<BgReading> predSeries = null;
|
||||
PointsWithLabelGraphSeries<Treatment> seriesTreatments = null;
|
||||
|
||||
// remove old data from graph
|
||||
|
@ -651,11 +709,11 @@ public class OverviewFragment extends Fragment {
|
|||
// **** HIGH and LOW targets graph ****
|
||||
DataPoint[] lowDataPoints = new DataPoint[]{
|
||||
new DataPoint(fromTime, lowLine),
|
||||
new DataPoint(toTime, lowLine)
|
||||
new DataPoint(endTime, lowLine)
|
||||
};
|
||||
DataPoint[] highDataPoints = new DataPoint[]{
|
||||
new DataPoint(fromTime, highLine),
|
||||
new DataPoint(toTime, highLine)
|
||||
new DataPoint(endTime, highLine)
|
||||
};
|
||||
bgGraph.addSeries(seriesLow = new LineGraphSeries<DataPoint>(lowDataPoints));
|
||||
seriesLow.setColor(Color.RED);
|
||||
|
@ -672,19 +730,26 @@ public class OverviewFragment extends Fragment {
|
|||
public boolean isTempBasal = false;
|
||||
}
|
||||
|
||||
Double maxAllowedBasal = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalAbsoluteOnlyForCheckLimit);
|
||||
Double maxBasalValueFound = 0d;
|
||||
|
||||
long now = new Date().getTime();
|
||||
if (pump.getPumpDescription().isTempBasalCapable) {
|
||||
List<BarDataPoint> basalArray = new ArrayList<BarDataPoint>();
|
||||
List<DataPoint> basalLineArray = new ArrayList<DataPoint>();
|
||||
double lastBaseBasal = 0;
|
||||
for (long time = fromTime; time < now; time += 5 * 60 * 1000L) {
|
||||
TempBasal tb = MainApp.getConfigBuilder().getTempBasal(new Date(time));
|
||||
double basebasal = profile.getBasal(NSProfile.secondsFromMidnight(new Date(time)));
|
||||
Double basal = 0d;
|
||||
if (tb != null)
|
||||
basalArray.add(new BarDataPoint(time, basal = tb.tempBasalConvertedToAbsolute(new Date(time)), true));
|
||||
else
|
||||
basalArray.add(new BarDataPoint(time, basal = profile.getBasal(NSProfile.secondsFromMidnight(new Date(time))), false));
|
||||
else {
|
||||
basalArray.add(new BarDataPoint(time, basal = basebasal, false));
|
||||
}
|
||||
if (basebasal != lastBaseBasal)
|
||||
basalLineArray.add(new DataPoint(time, lastBaseBasal));
|
||||
basalLineArray.add(new DataPoint(time, basebasal));
|
||||
lastBaseBasal = basebasal;
|
||||
maxBasalValueFound = Math.max(maxBasalValueFound, basal);
|
||||
}
|
||||
BarDataPoint[] basal = new BarDataPoint[basalArray.size()];
|
||||
|
@ -698,17 +763,23 @@ public class OverviewFragment extends Fragment {
|
|||
else return Color.CYAN;
|
||||
}
|
||||
});
|
||||
DataPoint[] basalLine = new DataPoint[basalLineArray.size()];
|
||||
basalLine = basalLineArray.toArray(basalLine);
|
||||
bgGraph.addSeries(basalsLineSeries = new LineGraphSeries<DataPoint>(basalLine));
|
||||
basalsLineSeries.setColor(Color.CYAN);
|
||||
basalsLineSeries.setDrawDataPoints(false);
|
||||
basalsLineSeries.setThickness(2);
|
||||
}
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
bgGraph.getViewport().setMaxX(toTime);
|
||||
bgGraph.getViewport().setMaxX(endTime);
|
||||
bgGraph.getViewport().setMinX(fromTime);
|
||||
bgGraph.getViewport().setXAxisBoundsManual(true);
|
||||
bgGraph.getGridLabelRenderer().setLabelFormatter(new TimeAsXAxisLabelFormatter(getActivity(), "HH"));
|
||||
bgGraph.getGridLabelRenderer().setNumHorizontalLabels(7); // only 7 because of the space
|
||||
|
||||
// **** BG graph ****
|
||||
List<BgReading> bgReadingsArray = MainApp.getDbHelper().getDataFromTime(fromTime);
|
||||
List<BgReading> bgReadingsArray = MainApp.getDbHelper().getBgreadingsDataFromTime(fromTime, true);
|
||||
List<BgReading> inRangeArray = new ArrayList<BgReading>();
|
||||
List<BgReading> outOfRangeArray = new ArrayList<BgReading>();
|
||||
|
||||
|
@ -750,6 +821,19 @@ public class OverviewFragment extends Fragment {
|
|||
seriesOutOfRange.setColor(Color.RED);
|
||||
}
|
||||
|
||||
if (showPrediction) {
|
||||
DetermineBasalResultAMA amaResult = (DetermineBasalResultAMA) finalLastRun.constraintsProcessed;
|
||||
List<BgReading> predArray = amaResult.getPredictions();
|
||||
BgReading[] pred = new BgReading[predArray.size()];
|
||||
pred = predArray.toArray(pred);
|
||||
if (pred.length > 0) {
|
||||
bgGraph.addSeries(predSeries = new PointsGraphSeries<BgReading>(pred));
|
||||
predSeries.setShape(PointsGraphSeries.Shape.POINT);
|
||||
predSeries.setSize(4);
|
||||
predSeries.setColor(Color.MAGENTA);
|
||||
}
|
||||
}
|
||||
|
||||
// **** NOW line ****
|
||||
DataPoint[] nowPoints = new DataPoint[]{
|
||||
new DataPoint(now, 0),
|
||||
|
@ -762,8 +846,8 @@ public class OverviewFragment extends Fragment {
|
|||
// custom paint to make a dotted line
|
||||
Paint paint = new Paint();
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(1);
|
||||
paint.setPathEffect(new DashPathEffect(new float[]{4, 20}, 0));
|
||||
paint.setStrokeWidth(2);
|
||||
paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
|
||||
paint.setColor(Color.WHITE);
|
||||
seriesNow.setCustomPaint(paint);
|
||||
|
||||
|
@ -796,12 +880,11 @@ public class OverviewFragment extends Fragment {
|
|||
// set second scale
|
||||
if (pump.getPumpDescription().isTempBasalCapable) {
|
||||
bgGraph.getSecondScale().addSeries(basalsSeries);
|
||||
bgGraph.getSecondScale().addSeries(basalsLineSeries);
|
||||
bgGraph.getSecondScale().setMinY(0);
|
||||
bgGraph.getSecondScale().setMaxY(maxBgValue / lowLine * maxBasalValueFound * 1.2d);
|
||||
bgGraph.getGridLabelRenderer().setVerticalLabelsSecondScaleColor(MainApp.instance().getResources().getColor(R.color.background_material_dark)); // same color as backround = hide
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//Notifications
|
||||
|
|
|
@ -97,8 +97,8 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
|
|||
if (profile == null) return absoluteRate;
|
||||
if (absoluteRate < 0) absoluteRate = 0d;
|
||||
|
||||
Integer maxBasalMult = 4;
|
||||
Integer maxBasalFromDaily = 3;
|
||||
Integer maxBasalMult = Constants.CURRENT_BASAL_SAFETY_MULTIPLIER;
|
||||
Integer maxBasalFromDaily = Constants.MAX_DAILY_SAFETY_MULTIPLIER;
|
||||
// Check percentRate but absolute rate too, because we know real current basal in pump
|
||||
Double origRate = absoluteRate;
|
||||
if (absoluteRate > maxBasal) {
|
||||
|
@ -136,8 +136,8 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
|
|||
|
||||
if (absoluteRate < 0) absoluteRate = 0d;
|
||||
|
||||
Integer maxBasalMult = 4;
|
||||
Integer maxBasalFromDaily = 3;
|
||||
Integer maxBasalMult = Constants.CURRENT_BASAL_SAFETY_MULTIPLIER;
|
||||
Integer maxBasalFromDaily = Constants.MAX_DAILY_SAFETY_MULTIPLIER;
|
||||
// Check percentRate but absolute rate too, because we know real current basal in pump
|
||||
Double origRate = absoluteRate;
|
||||
if (absoluteRate > maxBasal) {
|
||||
|
|
|
@ -110,7 +110,7 @@ public class SimpleProfileFragment extends Fragment implements FragmentBase {
|
|||
@Override
|
||||
public void onClick(View view) {
|
||||
NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
|
||||
final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false, false);
|
||||
profileswitch.executeProfileSwitch = true;
|
||||
newDialog.setOptions(profileswitch);
|
||||
newDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
|
||||
|
|
|
@ -21,16 +21,16 @@ import info.nightscout.androidaps.Constants;
|
|||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.Services.Intents;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
|
||||
import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
|
||||
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
|
||||
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventSmsCommunicatorUpdateGui;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
|
@ -213,16 +213,14 @@ public class SmsCommunicatorPlugin implements PluginBase {
|
|||
} else if (lastBG != null) {
|
||||
reply = MainApp.sResources.getString(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(MainApp.sResources.getString(R.string.sms_minago), agoMin) + ", ";
|
||||
}
|
||||
DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
if (glucoseStatus != null)
|
||||
reply += MainApp.sResources.getString(R.string.sms_delta) + " " + NSProfile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", ";
|
||||
|
||||
MainApp.getConfigBuilder().getActiveTreatments().updateTotalIOB();
|
||||
IobTotal bolusIob = MainApp.getConfigBuilder().getActiveTreatments().getLastCalculation().round();
|
||||
if (bolusIob == null) bolusIob = new IobTotal();
|
||||
MainApp.getConfigBuilder().getActiveTempBasals().updateTotalIOB();
|
||||
IobTotal basalIob = MainApp.getConfigBuilder().getActiveTempBasals().getLastCalculation().round();
|
||||
if (basalIob == null) basalIob = new IobTotal();
|
||||
|
||||
reply += MainApp.sResources.getString(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U ("
|
||||
+ MainApp.sResources.getString(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
|
||||
|
|
|
@ -22,10 +22,10 @@ import java.util.List;
|
|||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.db.TempBasal;
|
||||
import info.nightscout.androidaps.events.EventTempBasalChange;
|
||||
import info.nightscout.androidaps.interfaces.FragmentBase;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
|
||||
|
|
|
@ -5,9 +5,6 @@ import android.preference.PreferenceManager;
|
|||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.stmt.PreparedQuery;
|
||||
import com.j256.ormlite.stmt.QueryBuilder;
|
||||
import com.j256.ormlite.stmt.Where;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -28,7 +25,7 @@ import info.nightscout.androidaps.events.EventPreferenceChange;
|
|||
import info.nightscout.androidaps.events.EventTempBasalChange;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.TempBasalsInterface;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
|
||||
/**
|
||||
* Created by mike on 05.08.2016.
|
||||
|
@ -95,44 +92,16 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
|
|||
}
|
||||
|
||||
private void initializeData() {
|
||||
try {
|
||||
Dao<TempBasal, Long> dao = MainApp.getDbHelper().getDaoTempBasals();
|
||||
/*
|
||||
// **************** TESTING CREATE FAKE RECORD *****************
|
||||
TempBasal fake = new TempBasal();
|
||||
fake.timeStart = new Date(new Date().getTime() - 45 * 40 * 1000);
|
||||
fake.timeEnd = new Date(new Date().getTime() - new Double(Math.random() * 45d * 40 * 1000).longValue());
|
||||
fake.duration = 30;
|
||||
fake.percent = 150;
|
||||
fake.isAbsolute = false;
|
||||
fake.isExtended = false;
|
||||
dao.createOrUpdate(fake);
|
||||
// **************** TESTING CREATE FAKE RECORD *****************
|
||||
*/
|
||||
QueryBuilder<TempBasal, Long> queryBuilder = dao.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", false);
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("isExtended", false);
|
||||
queryBuilder.limit(30L);
|
||||
PreparedQuery<TempBasal> preparedQuery = queryBuilder.prepare();
|
||||
tempBasals = dao.query(preparedQuery);
|
||||
double dia = 3;
|
||||
if (MainApp.getConfigBuilder().getActiveProfile() != null && MainApp.getConfigBuilder().getActiveProfile().getProfile() != null)
|
||||
dia = MainApp.getConfigBuilder().getActiveProfile().getProfile().getDia();
|
||||
long fromMills = (long) (new Date().getTime() - 60 * 60 * 1000L * (24 + dia));
|
||||
tempBasals = MainApp.getDbHelper().getTempbasalsDataFromTime(fromMills, false, false);
|
||||
extendedBoluses = MainApp.getDbHelper().getTempbasalsDataFromTime(fromMills, false, true);
|
||||
|
||||
QueryBuilder<TempBasal, Long> queryBuilderExt = dao.queryBuilder();
|
||||
queryBuilderExt.orderBy("timeIndex", false);
|
||||
Where whereExt = queryBuilderExt.where();
|
||||
whereExt.eq("isExtended", true);
|
||||
queryBuilderExt.limit(30L);
|
||||
PreparedQuery<TempBasal> preparedQueryExt = queryBuilderExt.prepare();
|
||||
extendedBoluses = dao.query(preparedQueryExt);
|
||||
|
||||
// Update ended
|
||||
checkForExpiredExtended();
|
||||
checkForExpiredTemps();
|
||||
} catch (SQLException e) {
|
||||
log.debug(e.getMessage(), e);
|
||||
tempBasals = new ArrayList<TempBasal>();
|
||||
extendedBoluses = new ArrayList<TempBasal>();
|
||||
}
|
||||
// Update ended
|
||||
checkForExpiredExtended();
|
||||
checkForExpiredTemps();
|
||||
}
|
||||
|
||||
public void checkForExpiredTemps() {
|
||||
|
@ -197,13 +166,14 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateTotalIOB() {
|
||||
public IobTotal getCalculationToTime(long time) {
|
||||
checkForExpired(tempBasals);
|
||||
checkForExpired(extendedBoluses);
|
||||
Date now = new Date();
|
||||
IobTotal total = new IobTotal();
|
||||
Date now = new Date(time);
|
||||
IobTotal total = new IobTotal(time);
|
||||
for (Integer pos = 0; pos < tempBasals.size(); pos++) {
|
||||
TempBasal t = tempBasals.get(pos);
|
||||
if (t.timeStart.getTime() > time) continue;
|
||||
IobTotal calc = t.iobCalc(now);
|
||||
total.plus(calc);
|
||||
}
|
||||
|
@ -214,6 +184,13 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
|
|||
total.plus(calc);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTotalIOB() {
|
||||
IobTotal total = getCalculationToTime(new Date().getTime());
|
||||
|
||||
lastCalculationTimestamp = new Date().getTime();
|
||||
lastCalculation = total;
|
||||
}
|
||||
|
@ -237,6 +214,17 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long oldestDataAvaialable() {
|
||||
long oldestTemp = new Date().getTime();
|
||||
if (tempBasals.size() > 0)
|
||||
oldestTemp = Math.min(oldestTemp, tempBasals.get(tempBasals.size() - 1).timeStart.getTime());
|
||||
if (extendedBoluses.size() > 0)
|
||||
oldestTemp = Math.min(oldestTemp, extendedBoluses.get(extendedBoluses.size() - 1).timeStart.getTime());
|
||||
oldestTemp -= 15 * 60 * 1000L; // allow 15 min before
|
||||
return oldestTemp;
|
||||
}
|
||||
|
||||
List<TempBasal> getMergedList() {
|
||||
if (useExtendedBoluses) {
|
||||
List<TempBasal> merged = new ArrayList<TempBasal>();
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
package info.nightscout.androidaps.plugins.TempTargetRange;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.Services.Intents;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.FragmentBase;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.events.EventTempTargetRangeChange;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
import info.nightscout.utils.ToastUtils;
|
||||
|
||||
/**
|
||||
* Created by mike on 13/01/17.
|
||||
*/
|
||||
|
||||
public class TempTargetRangeFragment extends Fragment implements View.OnClickListener, FragmentBase {
|
||||
|
||||
private static TempTargetRangePlugin tempTargetRangePlugin = new TempTargetRangePlugin();
|
||||
|
||||
public static TempTargetRangePlugin getPlugin() {
|
||||
return tempTargetRangePlugin;
|
||||
}
|
||||
|
||||
RecyclerView recyclerView;
|
||||
LinearLayoutManager llm;
|
||||
Button refreshFromNS;
|
||||
|
||||
Context context;
|
||||
|
||||
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TempTargetsViewHolder> {
|
||||
|
||||
List<TempTarget> tempTargetList;
|
||||
|
||||
RecyclerViewAdapter(List<TempTarget> TempTargetList) {
|
||||
this.tempTargetList = TempTargetList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TempTargetsViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
|
||||
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.temptargetrange_item, viewGroup, false);
|
||||
TempTargetsViewHolder TempTargetsViewHolder = new TempTargetsViewHolder(v);
|
||||
return TempTargetsViewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(TempTargetsViewHolder holder, int position) {
|
||||
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
|
||||
if (profile == null) return;
|
||||
TempTarget tempTarget = tempTargetList.get(position);
|
||||
holder.date.setText(DateUtil.dateAndTimeString(tempTarget.timeStart) + " - " + DateUtil.timeString(tempTargetList.get(position).getPlannedTimeEnd()));
|
||||
holder.duration.setText(DecimalFormatter.to0Decimal(tempTarget.duration) + " min");
|
||||
holder.low.setText(tempTarget.lowValueToUnitsToString(profile.getUnits()));
|
||||
holder.high.setText(tempTarget.highValueToUnitsToString(profile.getUnits()));
|
||||
holder.reason.setText(tempTarget.reason);
|
||||
if (tempTarget.isInProgress())
|
||||
holder.dateLinearLayout.setBackgroundColor(MainApp.instance().getResources().getColor(R.color.colorInProgress));
|
||||
else
|
||||
holder.dateLinearLayout.setBackgroundColor(MainApp.instance().getResources().getColor(R.color.cardColorBackground));
|
||||
holder.remove.setTag(tempTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return tempTargetList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
public class TempTargetsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
CardView cv;
|
||||
TextView date;
|
||||
TextView duration;
|
||||
TextView low;
|
||||
TextView high;
|
||||
TextView reason;
|
||||
TextView remove;
|
||||
LinearLayout dateLinearLayout;
|
||||
|
||||
TempTargetsViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
cv = (CardView) itemView.findViewById(R.id.temptargetrange_cardview);
|
||||
date = (TextView) itemView.findViewById(R.id.temptargetrange_date);
|
||||
duration = (TextView) itemView.findViewById(R.id.temptargetrange_duration);
|
||||
low = (TextView) itemView.findViewById(R.id.temptargetrange_low);
|
||||
high = (TextView) itemView.findViewById(R.id.temptargetrange_high);
|
||||
reason = (TextView) itemView.findViewById(R.id.temptargetrange_reason);
|
||||
remove = (TextView) itemView.findViewById(R.id.temptargetrange_remove);
|
||||
remove.setOnClickListener(this);
|
||||
remove.setPaintFlags(remove.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
dateLinearLayout = (LinearLayout) itemView.findViewById(R.id.temptargetrange_datelinearlayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final TempTarget tempTarget = (TempTarget) v.getTag();
|
||||
final Context finalContext = context;
|
||||
switch (v.getId()) {
|
||||
case R.id.temptargetrange_remove:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(MainApp.sResources.getString(R.string.confirmation));
|
||||
builder.setMessage(MainApp.sResources.getString(R.string.removerecord) + "\n" + DateUtil.dateAndTimeString(tempTarget.timeStart));
|
||||
builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
final String _id = tempTarget._id;
|
||||
if (_id != null && !_id.equals("")) {
|
||||
MainApp.getConfigBuilder().removeCareportalEntryFromNS(_id);
|
||||
}
|
||||
try {
|
||||
Dao<TempTarget, Long> daoTempTargets = MainApp.getDbHelper().getDaoTempTargets();
|
||||
daoTempTargets.delete(tempTarget);
|
||||
MainApp.bus().post(new EventTempTargetRangeChange());
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null);
|
||||
builder.show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.temptargetrange_fragment, container, false);
|
||||
|
||||
recyclerView = (RecyclerView) view.findViewById(R.id.temptargetrange_recyclerview);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
llm = new LinearLayoutManager(view.getContext());
|
||||
recyclerView.setLayoutManager(llm);
|
||||
|
||||
RecyclerViewAdapter adapter = new RecyclerViewAdapter(tempTargetRangePlugin.getList());
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
refreshFromNS = (Button) view.findViewById(R.id.temptargetrange_refreshfromnightscout);
|
||||
refreshFromNS.setOnClickListener(this);
|
||||
|
||||
context = getContext();
|
||||
|
||||
updateGUI();
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.temptargetrange_refreshfromnightscout:
|
||||
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
boolean nsUploadOnly = SP.getBoolean("ns_upload_only", false);
|
||||
if (nsUploadOnly) {
|
||||
ToastUtils.showToastInUiThread(getContext(), this.getContext().getString(R.string.ns_upload_only_enabled));
|
||||
} else {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
|
||||
builder.setTitle(this.getContext().getString(R.string.confirmation));
|
||||
builder.setMessage(this.getContext().getString(R.string.refreshtemptargetsfromnightscout));
|
||||
builder.setPositiveButton(this.getContext().getString(R.string.ok), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
MainApp.getDbHelper().resetTempTargets();
|
||||
tempTargetRangePlugin.initializeData();
|
||||
updateGUI();
|
||||
Intent restartNSClient = new Intent(Intents.ACTION_RESTART);
|
||||
MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(this.getContext().getString(R.string.cancel), null);
|
||||
builder.show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
MainApp.bus().unregister(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
MainApp.bus().register(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventTempTargetRangeChange ev) {
|
||||
updateGUI();
|
||||
}
|
||||
|
||||
void updateGUI() {
|
||||
Activity activity = getActivity();
|
||||
if (activity != null)
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
recyclerView.swapAdapter(new RecyclerViewAdapter(tempTargetRangePlugin.getList()), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package info.nightscout.androidaps.plugins.TempTargetRange;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.plugins.TempTargetRange.events.EventTempTargetRangeChange;
|
||||
|
||||
/**
|
||||
* Created by mike on 13/01/17.
|
||||
*/
|
||||
|
||||
public class TempTargetRangePlugin implements PluginBase {
|
||||
|
||||
static boolean fragmentEnabled = true;
|
||||
static boolean fragmentVisible = true;
|
||||
|
||||
private static List<TempTarget> tempTargets;
|
||||
|
||||
TempTargetRangePlugin() {
|
||||
initializeData();
|
||||
MainApp.bus().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return PluginBase.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentClass() {
|
||||
return TempTargetRangeFragment.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return MainApp.sResources.getString(R.string.temptargetrange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int type) {
|
||||
return type == GENERAL && fragmentEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisibleInTabs(int type) {
|
||||
return type == GENERAL && fragmentVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeHidden(int type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
|
||||
if (type == GENERAL) {
|
||||
this.fragmentEnabled = fragmentEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragmentVisible(int type, boolean fragmentVisible) {
|
||||
if (type == GENERAL) this.fragmentVisible = fragmentVisible;
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return fragmentEnabled;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventTempTargetRangeChange ev) {
|
||||
initializeData();
|
||||
}
|
||||
|
||||
public void initializeData() {
|
||||
long fromMills = (long) (new Date().getTime() - 60 * 60 * 1000L * 24);
|
||||
tempTargets = MainApp.getDbHelper().getTemptargetsDataFromTime(fromMills, false);
|
||||
}
|
||||
|
||||
public List<TempTarget> getList() {
|
||||
return tempTargets;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TempTarget getTempTargetInProgress(long time) {
|
||||
for (int i = tempTargets.size() - 1; i >= 0; i--) {
|
||||
if (tempTargets.get(i).timeStart.getTime() > time) continue;
|
||||
if (tempTargets.get(i).getPlannedTimeEnd().getTime() >= time) return tempTargets.get(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.TempTargetRange.events;
|
||||
|
||||
/**
|
||||
* Created by mike on 13.01.2017.
|
||||
*/
|
||||
|
||||
public class EventTempTargetRangeChange {
|
||||
}
|
|
@ -157,7 +157,7 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
|
|||
} else {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
|
||||
builder.setTitle(this.getContext().getString(R.string.confirmation));
|
||||
builder.setMessage(this.getContext().getString(R.string.refreshfromnightscout));
|
||||
builder.setMessage(this.getContext().getString(R.string.refreshtreatmentsfromnightscout));
|
||||
builder.setPositiveButton(this.getContext().getString(R.string.ok), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
MainApp.getDbHelper().resetTreatments();
|
||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.Treatments;
|
|||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.stmt.PreparedQuery;
|
||||
import com.j256.ormlite.stmt.QueryBuilder;
|
||||
import com.j256.ormlite.stmt.Where;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -13,14 +14,17 @@ import java.util.ArrayList;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.Iob;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.db.Treatment;
|
||||
import info.nightscout.androidaps.events.EventTreatmentChange;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
|
||||
/**
|
||||
|
@ -83,17 +87,11 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
|
|||
}
|
||||
|
||||
public void initializeData() {
|
||||
try {
|
||||
Dao<Treatment, Long> dao = MainApp.getDbHelper().getDaoTreatments();
|
||||
QueryBuilder<Treatment, Long> queryBuilder = dao.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", false);
|
||||
queryBuilder.limit(30l);
|
||||
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
|
||||
treatments = dao.query(preparedQuery);
|
||||
} catch (SQLException e) {
|
||||
log.debug(e.getMessage(), e);
|
||||
treatments = new ArrayList<Treatment>();
|
||||
}
|
||||
double dia = 3;
|
||||
if (MainApp.getConfigBuilder().getActiveProfile() != null && MainApp.getConfigBuilder().getActiveProfile().getProfile() != null)
|
||||
dia = MainApp.getConfigBuilder().getActiveProfile().getProfile().getDia();
|
||||
long fromMills = (long) (new Date().getTime() - 60 * 60 * 1000L * (24 + dia));
|
||||
treatments = MainApp.getDbHelper().getTreatmentDataFromTime(fromMills, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -111,57 +109,44 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateTotalIOB() {
|
||||
IobTotal total = new IobTotal();
|
||||
public IobTotal getCalculationToTime(long time) {
|
||||
IobTotal total = new IobTotal(time);
|
||||
|
||||
if (MainApp.getConfigBuilder() == null || MainApp.getConfigBuilder().getActiveProfile() == null) // app not initialized yet
|
||||
return;
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
if (profile == null) {
|
||||
lastCalculation = total;
|
||||
return;
|
||||
}
|
||||
if (MainApp.getConfigBuilder() == null || ConfigBuilderPlugin.getActiveProfile() == null) // app not initialized yet
|
||||
return total;
|
||||
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
|
||||
if (profile == null)
|
||||
return total;
|
||||
|
||||
Double dia = profile.getDia();
|
||||
|
||||
Date now = new Date();
|
||||
Date now = new Date(time);
|
||||
for (Integer pos = 0; pos < treatments.size(); pos++) {
|
||||
Treatment t = treatments.get(pos);
|
||||
if (t.created_at.getTime() > time) continue;
|
||||
Iob tIOB = t.iobCalc(now, dia);
|
||||
total.iob += tIOB.iobContrib;
|
||||
total.activity += tIOB.activityContrib;
|
||||
Iob bIOB = t.iobCalc(now, dia / 2);
|
||||
Iob bIOB = t.iobCalc(now, dia / Constants.BOLUSSNOOZE_DIA_ADVISOR);
|
||||
total.bolussnooze += bIOB.iobContrib;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTotalIOB() {
|
||||
IobTotal total = getCalculationToTime(new Date().getTime());
|
||||
|
||||
lastCalculationTimestamp = new Date().getTime();
|
||||
lastCalculation = total;
|
||||
}
|
||||
|
||||
public class MealData {
|
||||
public double boluses = 0d;
|
||||
public double carbs = 0d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MealData getMealData() {
|
||||
MealData result = new MealData();
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
if (profile == null)
|
||||
return result;
|
||||
|
||||
for (Treatment treatment : treatments) {
|
||||
long now = new Date().getTime();
|
||||
long dia_ago = now - (new Double(profile.getDia() * 60 * 60 * 1000l)).longValue();
|
||||
long t = treatment.created_at.getTime();
|
||||
if (t > dia_ago && t <= now) {
|
||||
if (treatment.carbs >= 1) {
|
||||
result.carbs += treatment.carbs;
|
||||
}
|
||||
if (treatment.insulin >= 0.1 && treatment.mealBolus) {
|
||||
result.boluses += treatment.insulin;
|
||||
}
|
||||
}
|
||||
result.addTreatment(treatment);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ import java.util.List;
|
|||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.db.TempBasal;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
|
||||
import info.nightscout.androidaps.plugins.Wear.WearPlugin;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
|
@ -144,7 +144,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
|
||||
BgReading lastBG = MainApp.getDbHelper().lastBg();
|
||||
if (lastBG != null) {
|
||||
DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
|
||||
if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); }
|
||||
if (wear_integration) {
|
||||
|
@ -160,7 +160,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
}
|
||||
}
|
||||
|
||||
private DataMap dataMapSingleBG(BgReading lastBG, DatabaseHelper.GlucoseStatus glucoseStatus) {
|
||||
private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) {
|
||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||
if(profile == null) return null;
|
||||
|
||||
|
@ -254,8 +254,8 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
|
||||
if (last_bg == null) return;
|
||||
|
||||
List<BgReading> graph_bgs = MainApp.getDbHelper().getDataFromTime(startTime);
|
||||
DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
|
||||
List<BgReading> graph_bgs = MainApp.getDbHelper().getBgreadingsDataFromTime(startTime, true);
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
|
||||
if (!graph_bgs.isEmpty()) {
|
||||
DataMap entries = dataMapSingleBG(last_bg, glucoseStatus);
|
||||
|
@ -444,10 +444,8 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
//IOB
|
||||
MainApp.getConfigBuilder().getActiveTreatments().updateTotalIOB();
|
||||
IobTotal bolusIob = MainApp.getConfigBuilder().getActiveTreatments().getLastCalculation().round();
|
||||
if (bolusIob == null) bolusIob = new IobTotal();
|
||||
MainApp.getConfigBuilder().getActiveTempBasals().updateTotalIOB();
|
||||
IobTotal basalIob = MainApp.getConfigBuilder().getActiveTempBasals().getLastCalculation().round();
|
||||
if (basalIob == null) basalIob = new IobTotal();
|
||||
status += (shortString?"":(getString(R.string.treatments_iob_label_string) + " ")) + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "("
|
||||
+ DecimalFormatter.to2Decimal(bolusIob.iob) + "|"
|
||||
+ DecimalFormatter.to2Decimal(basalIob.basaliob) + ")";
|
||||
|
|
|
@ -15,8 +15,8 @@ import info.nightscout.androidaps.Constants;
|
|||
import info.nightscout.androidaps.MainActivity;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.db.TempBasal;
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged;
|
||||
import info.nightscout.androidaps.events.EventNewBG;
|
||||
|
@ -27,8 +27,7 @@ import info.nightscout.androidaps.events.EventTempBasalChange;
|
|||
import info.nightscout.androidaps.events.EventTreatmentChange;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.plugins.Overview.Notification;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
import info.nightscout.utils.DecimalFormatter;
|
||||
|
||||
|
@ -103,7 +102,7 @@ public class PersistentNotificationPlugin implements PluginBase{
|
|||
|
||||
|
||||
BgReading lastBG = MainApp.getDbHelper().lastBg();
|
||||
DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
|
||||
if(profile != null && lastBG != null) {
|
||||
line1 = lastBG.valueToUnitsToString(profile.getUnits());
|
||||
|
@ -127,10 +126,8 @@ public class PersistentNotificationPlugin implements PluginBase{
|
|||
//IOB
|
||||
MainApp.getConfigBuilder().getActiveTreatments().updateTotalIOB();
|
||||
IobTotal bolusIob = MainApp.getConfigBuilder().getActiveTreatments().getLastCalculation().round();
|
||||
if (bolusIob == null) bolusIob = new IobTotal();
|
||||
MainApp.getConfigBuilder().getActiveTempBasals().updateTotalIOB();
|
||||
IobTotal basalIob = MainApp.getConfigBuilder().getActiveTempBasals().getLastCalculation().round();
|
||||
if (basalIob == null) basalIob = new IobTotal();
|
||||
String line2 = ctx.getString(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U ("
|
||||
+ ctx.getString(R.string.bolus) + ": " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
|
||||
+ ctx.getString(R.string.basal) + ": " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U)";
|
||||
|
|
|
@ -26,4 +26,14 @@ public class DbLogger {
|
|||
} else if (Config.logNSUpload)
|
||||
log.debug("DBADD dbAdd " + q.size() + " receivers " + data);
|
||||
}
|
||||
|
||||
public static void dbRemove(Intent intent, String data, Class sender) {
|
||||
Logger log = LoggerFactory.getLogger(sender);
|
||||
List<ResolveInfo> q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(intent, 0);
|
||||
if (q.size() < 1) {
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(),MainApp.sResources.getString(R.string.nsclientnotinstalled));
|
||||
log.error("DBREMOVE No receivers");
|
||||
} else if (Config.logNSUpload)
|
||||
log.debug("DBREMOVE dbRemove " + q.size() + " receivers " + data);
|
||||
}
|
||||
}
|
||||
|
|
15002
app/src/main/java/info/nightscout/sampleData/cgm/glucose.json
Normal file
15002
app/src/main/java/info/nightscout/sampleData/cgm/glucose.json
Normal file
File diff suppressed because it is too large
Load diff
15002
app/src/main/java/info/nightscout/sampleData/cgm/ns-glucose.json
Normal file
15002
app/src/main/java/info/nightscout/sampleData/cgm/ns-glucose.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"bg": 148,
|
||||
"temp": "absolute",
|
||||
"snoozeBG": 17,
|
||||
"recieved": true,
|
||||
"predBGs": {
|
||||
"IOB": [
|
||||
148,
|
||||
128,
|
||||
109,
|
||||
91,
|
||||
75,
|
||||
59,
|
||||
45,
|
||||
39,
|
||||
39,
|
||||
39,
|
||||
39,
|
||||
39,
|
||||
39
|
||||
]
|
||||
},
|
||||
"rate": 0.0,
|
||||
"reason": "COB: 0, Dev: -64, BGI: -8.24, ISF: 21, Target: 81; Eventual BG -34 < 81, setting -11.1U/hr",
|
||||
"COB": 0,
|
||||
"eventualBG": -34,
|
||||
"timestamp": "2017-01-04T16:37:56.113148",
|
||||
"duration": 30,
|
||||
"tick": -21,
|
||||
"IOB": 5.521
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"temp":"absolute","bg":148,"tick":-21,"eventualBG":-28,"snoozeBG":16,"predBGs":{"IOB":[148,128,109,92,75,60,46,39,39,39,39,39,39]},"COB":0,"IOB":5.248,"reason":"COB: 0, Dev: -64, BGI: -8.2, ISF: 21, Target: 81; Eventual BG -28 < 81, setting -11.3U/hr, but 28m left and 0 ~ req 0U/hr: no action required"}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"status": "normal",
|
||||
"voltage": 1.45
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
"2017-01-04T16:40:31+01:00"
|
|
@ -0,0 +1 @@
|
|||
"2017-01-04T16:40:31"
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"battery": 52,
|
||||
"batteryVoltage": 3701
|
||||
}
|
15002
app/src/main/java/info/nightscout/sampleData/monitor/glucose.json
Normal file
15002
app/src/main/java/info/nightscout/sampleData/monitor/glucose.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
{"carbs":0,"boluses":8,"mealCOB":0}
|
131
app/src/main/java/info/nightscout/sampleData/monitor/mmtune.json
Normal file
131
app/src/main/java/info/nightscout/sampleData/monitor/mmtune.json
Normal file
|
@ -0,0 +1,131 @@
|
|||
{
|
||||
"scanDetails": [
|
||||
[
|
||||
"868.300",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.312",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.324",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.336",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.348",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.360",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.372",
|
||||
4,
|
||||
-91
|
||||
],
|
||||
[
|
||||
"868.384",
|
||||
5,
|
||||
-81
|
||||
],
|
||||
[
|
||||
"868.396",
|
||||
5,
|
||||
-78
|
||||
],
|
||||
[
|
||||
"868.408",
|
||||
5,
|
||||
-77
|
||||
],
|
||||
[
|
||||
"868.420",
|
||||
5,
|
||||
-76
|
||||
],
|
||||
[
|
||||
"868.432",
|
||||
5,
|
||||
-76
|
||||
],
|
||||
[
|
||||
"868.444",
|
||||
5,
|
||||
-76
|
||||
],
|
||||
[
|
||||
"868.456",
|
||||
5,
|
||||
-76
|
||||
],
|
||||
[
|
||||
"868.468",
|
||||
5,
|
||||
-75
|
||||
],
|
||||
[
|
||||
"868.480",
|
||||
5,
|
||||
-76
|
||||
],
|
||||
[
|
||||
"868.492",
|
||||
5,
|
||||
-76
|
||||
],
|
||||
[
|
||||
"868.504",
|
||||
5,
|
||||
-77
|
||||
],
|
||||
[
|
||||
"868.516",
|
||||
5,
|
||||
-80
|
||||
],
|
||||
[
|
||||
"868.528",
|
||||
5,
|
||||
-86
|
||||
],
|
||||
[
|
||||
"868.540",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.552",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.564",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.576",
|
||||
0,
|
||||
-99
|
||||
],
|
||||
[
|
||||
"868.588",
|
||||
0,
|
||||
-99
|
||||
]
|
||||
],
|
||||
"setFreq": 868.468,
|
||||
"usedDefault": false
|
||||
}
|
|
@ -0,0 +1,936 @@
|
|||
[
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:37:57 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:37:57+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "3965104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:37:57 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:37:57+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "3965104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:28:28 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:28:28+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1c5c104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:28:28 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:28:28+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "1c5c104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:21:31 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:21:31+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1f55104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:21:31 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:21:31+01:00",
|
||||
"_body": "00",
|
||||
"_head": "337c",
|
||||
"rate": 3.1,
|
||||
"_date": "1f55104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:15:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:15:29+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1d4f104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:15:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:15:29+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3362",
|
||||
"rate": 2.45,
|
||||
"_date": "1d4f104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:08:41 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:08:41+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2948104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:08:41 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:08:41+01:00",
|
||||
"_body": "00",
|
||||
"_head": "334e",
|
||||
"rate": 1.95,
|
||||
"_date": "2948104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:06:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:06:50+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "3246104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:06:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:06:50+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3332",
|
||||
"rate": 1.25,
|
||||
"_date": "3246104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:02:03 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:02:03+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "0342104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:02:03 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:02:03+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "0342104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:01:28 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:01:28+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1c41104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:01:28 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:01:28+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3396",
|
||||
"rate": 3.75,
|
||||
"_date": "1c41104411"
|
||||
},
|
||||
{
|
||||
"_type": "Bolus",
|
||||
"_description": "Bolus 2017-01-04T15:58:37 head[4], body[0] op[0x01]",
|
||||
"timestamp": "2017-01-04T15:58:37+01:00",
|
||||
"_body": "",
|
||||
"programmed": 2.0,
|
||||
"_head": "01141400",
|
||||
"amount": 2.0,
|
||||
"duration": 0,
|
||||
"type": "normal",
|
||||
"_date": "257a4f0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T15:55:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:55:29+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1d770f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:55:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:55:29+01:00",
|
||||
"_body": "00",
|
||||
"_head": "332d",
|
||||
"rate": 1.125,
|
||||
"_date": "1d770f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T15:46:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:46:50+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "326e0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:46:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:46:50+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "326e0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "Bolus",
|
||||
"_description": "Bolus 2017-01-04T15:44:07 head[4], body[0] op[0x01]",
|
||||
"timestamp": "2017-01-04T15:44:07+01:00",
|
||||
"_body": "",
|
||||
"programmed": 2.0,
|
||||
"_head": "01141400",
|
||||
"amount": 2.0,
|
||||
"duration": 0,
|
||||
"type": "normal",
|
||||
"_date": "076c4f0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T15:43:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:43:50+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "326b0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:43:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:43:50+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3341",
|
||||
"rate": 1.625,
|
||||
"_date": "326b0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T15:41:22 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:41:22+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "16690f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:41:22 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:41:22+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "16690f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T15:28:24 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:28:24+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "185c0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:28:24 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:28:24+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "185c0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T15:22:58 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:22:58+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "3a560f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:22:58 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:22:58+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "3a560f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T15:13:01 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:13:01+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "014d0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:13:01 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:13:01+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "014d0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:50:21 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:50:21+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "15720e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:50:21 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:50:21+01:00",
|
||||
"_body": "00",
|
||||
"_head": "33fb",
|
||||
"rate": 6.275,
|
||||
"_date": "15720e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:38:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:38:50+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "32660e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:38:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:38:50+01:00",
|
||||
"_body": "00",
|
||||
"_head": "33e7",
|
||||
"rate": 5.775,
|
||||
"_date": "32660e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:34:03 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:34:03+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "03620e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:34:03 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:34:03+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3344",
|
||||
"rate": 1.7,
|
||||
"_date": "03620e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:33:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:33:29+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1d610e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:33:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:33:29+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3392",
|
||||
"rate": 3.65,
|
||||
"_date": "1d610e4411"
|
||||
},
|
||||
{
|
||||
"_type": "Bolus",
|
||||
"_description": "Bolus 2017-01-04T14:32:05 head[4], body[0] op[0x01]",
|
||||
"timestamp": "2017-01-04T14:32:05+01:00",
|
||||
"_body": "",
|
||||
"programmed": 1.0,
|
||||
"_head": "010a0a00",
|
||||
"amount": 1.0,
|
||||
"duration": 0,
|
||||
"type": "normal",
|
||||
"_date": "05604e0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:26:30 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:26:30+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1e5a0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:26:30 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:26:30+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3320",
|
||||
"rate": 0.8,
|
||||
"_date": "1e5a0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:25:47 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:25:47+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2f590e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:25:47 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:25:47+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3378",
|
||||
"rate": 3.0,
|
||||
"_date": "2f590e4411"
|
||||
},
|
||||
{
|
||||
"_type": "Bolus",
|
||||
"_description": "Bolus 2017-01-04T14:22:59 head[4], body[0] op[0x01]",
|
||||
"timestamp": "2017-01-04T14:22:59+01:00",
|
||||
"_body": "",
|
||||
"programmed": 2.0,
|
||||
"_head": "01141400",
|
||||
"amount": 2.0,
|
||||
"duration": 0,
|
||||
"type": "normal",
|
||||
"_date": "3b564e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Prime",
|
||||
"_description": "Prime 2017-01-04T14:18:15 head[5], body[0] op[0x03]",
|
||||
"timestamp": "2017-01-04T14:18:15+01:00",
|
||||
"_body": "",
|
||||
"_head": "0300000027",
|
||||
"amount": 3.9,
|
||||
"fixed": 0.0,
|
||||
"type": "manual",
|
||||
"_date": "0f522e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Rewind",
|
||||
"_description": "Rewind 2017-01-04T14:18:03 head[2], body[0] op[0x21]",
|
||||
"timestamp": "2017-01-04T14:18:03+01:00",
|
||||
"_body": "",
|
||||
"_head": "2100",
|
||||
"_date": "03520e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Prime",
|
||||
"_description": "Prime 2017-01-04T14:17:15 head[5], body[0] op[0x03]",
|
||||
"timestamp": "2017-01-04T14:17:15+01:00",
|
||||
"_body": "",
|
||||
"_head": "03000a000a",
|
||||
"amount": 1.0,
|
||||
"fixed": 1.0,
|
||||
"type": "fixed",
|
||||
"_date": "0f510e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Prime",
|
||||
"_description": "Prime 2017-01-04T14:14:56 head[5], body[0] op[0x03]",
|
||||
"timestamp": "2017-01-04T14:14:56+01:00",
|
||||
"_body": "",
|
||||
"_head": "0300190019",
|
||||
"amount": 2.5,
|
||||
"fixed": 2.5,
|
||||
"type": "fixed",
|
||||
"_date": "384e0e0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:14:32 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:14:32+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "204e0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:14:32 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:14:32+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3346",
|
||||
"rate": 1.75,
|
||||
"_date": "204e0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T14:09:45 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:09:45+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2d490e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:09:45 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:09:45+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3337",
|
||||
"rate": 1.375,
|
||||
"_date": "2d490e4411"
|
||||
},
|
||||
{
|
||||
"_type": "ClearAlarm",
|
||||
"_description": "ClearAlarm 2017-01-04T14:04:16 head[2], body[0] op[0x0c]",
|
||||
"timestamp": "2017-01-04T14:04:16+01:00",
|
||||
"_body": "",
|
||||
"_head": "0c04",
|
||||
"_date": "10440e0411"
|
||||
},
|
||||
{
|
||||
"_type": "AlarmPump",
|
||||
"_description": "AlarmPump 2017-01-04T14:04:05 head[4], body[0] op[0x06]",
|
||||
"timestamp": "2017-01-04T14:04:05+01:00",
|
||||
"_body": "",
|
||||
"_head": "06040bff",
|
||||
"_date": "05444e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:57:38 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:57:38+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "26790d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:57:38 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:57:38+01:00",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "26790d4411"
|
||||
},
|
||||
{
|
||||
"_type": "Bolus",
|
||||
"_description": "Bolus 2017-01-04T13:53:05 head[4], body[0] op[0x01]",
|
||||
"timestamp": "2017-01-04T13:53:05+01:00",
|
||||
"_body": "",
|
||||
"programmed": 1.0,
|
||||
"_head": "010a0a00",
|
||||
"amount": 1.0,
|
||||
"duration": 0,
|
||||
"type": "normal",
|
||||
"_date": "05754d0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:47:51 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:47:51+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "336f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:47:51 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:47:51+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3368",
|
||||
"rate": 2.6,
|
||||
"_date": "336f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:43:53 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:43:53+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "356b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:43:53 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:43:53+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3355",
|
||||
"rate": 2.125,
|
||||
"_date": "356b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:40:04 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:40:04+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "04680d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:40:04 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:40:04+01:00",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "04680d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:27:46 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:27:46+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2e5b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:27:46 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:27:46+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3348",
|
||||
"rate": 1.8,
|
||||
"_date": "2e5b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:27:00 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:27:00+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "005b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:27:00 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:27:00+01:00",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "005b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:20:49 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:20:49+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "31540d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:20:49 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:20:49+01:00",
|
||||
"_body": "00",
|
||||
"_head": "332d",
|
||||
"rate": 1.125,
|
||||
"_date": "31540d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:15:40 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:15:40+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "284f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:15:40 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:15:40+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3373",
|
||||
"rate": 2.875,
|
||||
"_date": "284f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:15:31 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:15:31+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1f4f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:15:31 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:15:31+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3373",
|
||||
"rate": 2.875,
|
||||
"_date": "1f4f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:08:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:08:29+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1d480d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:08:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:08:29+01:00",
|
||||
"_body": "00",
|
||||
"_head": "332c",
|
||||
"rate": 1.1,
|
||||
"_date": "1d480d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T13:03:28 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:03:28+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1c430d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:03:28 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:03:28+01:00",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "1c430d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T12:57:44 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:57:44+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2c790c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:57:44 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:57:44+01:00",
|
||||
"_body": "00",
|
||||
"_head": "332a",
|
||||
"rate": 1.05,
|
||||
"_date": "2c790c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T12:47:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:47:29+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1d6f0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:47:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:47:29+01:00",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "1d6f0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T12:35:30 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:35:30+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1e630c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:35:30 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:35:30+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "1e630c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T12:23:47 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:23:47+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2f570c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:23:47 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:23:47+01:00",
|
||||
"_body": "00",
|
||||
"_head": "33b5",
|
||||
"rate": 4.525,
|
||||
"_date": "2f570c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T12:18:48 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:18:48+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "30520c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:18:48 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:18:48+01:00",
|
||||
"_body": "00",
|
||||
"_head": "334a",
|
||||
"rate": 1.85,
|
||||
"_date": "30520c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T12:13:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:13:29+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "1d4d0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:13:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:13:29+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3337",
|
||||
"rate": 1.375,
|
||||
"_date": "1d4d0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T12:08:07 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:08:07+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "07480c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:08:07 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:08:07+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3324",
|
||||
"rate": 0.9,
|
||||
"_date": "07480c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T11:55:46 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T11:55:46+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2e770b4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T11:55:46 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T11:55:46+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "2e770b4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T11:42:44 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T11:42:44+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "2c6a0b4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T11:42:44 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T11:42:44+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "2c6a0b4411"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,936 @@
|
|||
[
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:37:57 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:37:57",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "3965104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:37:57 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:37:57",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "3965104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:28:28 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:28:28",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1c5c104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:28:28 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:28:28",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "1c5c104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:21:31 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:21:31",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1f55104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:21:31 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:21:31",
|
||||
"_body": "00",
|
||||
"_head": "337c",
|
||||
"rate": 3.1,
|
||||
"_date": "1f55104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:15:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:15:29",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1d4f104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:15:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:15:29",
|
||||
"_body": "00",
|
||||
"_head": "3362",
|
||||
"rate": 2.45,
|
||||
"_date": "1d4f104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:08:41 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:08:41",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2948104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:08:41 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:08:41",
|
||||
"_body": "00",
|
||||
"_head": "334e",
|
||||
"rate": 1.95,
|
||||
"_date": "2948104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:06:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:06:50",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "3246104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:06:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:06:50",
|
||||
"_body": "00",
|
||||
"_head": "3332",
|
||||
"rate": 1.25,
|
||||
"_date": "3246104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:02:03 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:02:03",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "0342104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:02:03 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:02:03",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "0342104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T16:01:28 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:01:28",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1c41104411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:01:28 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:01:28",
|
||||
"_body": "00",
|
||||
"_head": "3396",
|
||||
"rate": 3.75,
|
||||
"_date": "1c41104411"
|
||||
},
|
||||
{
|
||||
"programmed": 2.0,
|
||||
"_type": "Bolus",
|
||||
"type": "normal",
|
||||
"_description": "Bolus 2017-01-04T15:58:37 head[4], body[0] op[0x01]",
|
||||
"duration": 0,
|
||||
"timestamp": "2017-01-04T15:58:37",
|
||||
"_body": "",
|
||||
"_head": "01141400",
|
||||
"amount": 2.0,
|
||||
"_date": "257a4f0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T15:55:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:55:29",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1d770f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:55:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:55:29",
|
||||
"_body": "00",
|
||||
"_head": "332d",
|
||||
"rate": 1.125,
|
||||
"_date": "1d770f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T15:46:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:46:50",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "326e0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:46:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:46:50",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "326e0f4411"
|
||||
},
|
||||
{
|
||||
"programmed": 2.0,
|
||||
"_type": "Bolus",
|
||||
"type": "normal",
|
||||
"_description": "Bolus 2017-01-04T15:44:07 head[4], body[0] op[0x01]",
|
||||
"duration": 0,
|
||||
"timestamp": "2017-01-04T15:44:07",
|
||||
"_body": "",
|
||||
"_head": "01141400",
|
||||
"amount": 2.0,
|
||||
"_date": "076c4f0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T15:43:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:43:50",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "326b0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:43:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:43:50",
|
||||
"_body": "00",
|
||||
"_head": "3341",
|
||||
"rate": 1.625,
|
||||
"_date": "326b0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T15:41:22 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:41:22",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "16690f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:41:22 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:41:22",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "16690f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T15:28:24 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:28:24",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "185c0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:28:24 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:28:24",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "185c0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T15:22:58 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:22:58",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "3a560f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:22:58 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:22:58",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "3a560f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T15:13:01 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T15:13:01",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "014d0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T15:13:01 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T15:13:01",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "014d0f4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:50:21 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:50:21",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "15720e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:50:21 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:50:21",
|
||||
"_body": "00",
|
||||
"_head": "33fb",
|
||||
"rate": 6.275,
|
||||
"_date": "15720e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:38:50 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:38:50",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "32660e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:38:50 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:38:50",
|
||||
"_body": "00",
|
||||
"_head": "33e7",
|
||||
"rate": 5.775,
|
||||
"_date": "32660e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:34:03 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:34:03",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "03620e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:34:03 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:34:03",
|
||||
"_body": "00",
|
||||
"_head": "3344",
|
||||
"rate": 1.7,
|
||||
"_date": "03620e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:33:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:33:29",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1d610e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:33:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:33:29",
|
||||
"_body": "00",
|
||||
"_head": "3392",
|
||||
"rate": 3.65,
|
||||
"_date": "1d610e4411"
|
||||
},
|
||||
{
|
||||
"programmed": 1.0,
|
||||
"_type": "Bolus",
|
||||
"type": "normal",
|
||||
"_description": "Bolus 2017-01-04T14:32:05 head[4], body[0] op[0x01]",
|
||||
"duration": 0,
|
||||
"timestamp": "2017-01-04T14:32:05",
|
||||
"_body": "",
|
||||
"_head": "010a0a00",
|
||||
"amount": 1.0,
|
||||
"_date": "05604e0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:26:30 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:26:30",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1e5a0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:26:30 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:26:30",
|
||||
"_body": "00",
|
||||
"_head": "3320",
|
||||
"rate": 0.8,
|
||||
"_date": "1e5a0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:25:47 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:25:47",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2f590e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:25:47 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:25:47",
|
||||
"_body": "00",
|
||||
"_head": "3378",
|
||||
"rate": 3.0,
|
||||
"_date": "2f590e4411"
|
||||
},
|
||||
{
|
||||
"programmed": 2.0,
|
||||
"_type": "Bolus",
|
||||
"type": "normal",
|
||||
"_description": "Bolus 2017-01-04T14:22:59 head[4], body[0] op[0x01]",
|
||||
"duration": 0,
|
||||
"timestamp": "2017-01-04T14:22:59",
|
||||
"_body": "",
|
||||
"_head": "01141400",
|
||||
"amount": 2.0,
|
||||
"_date": "3b564e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Prime",
|
||||
"type": "manual",
|
||||
"_description": "Prime 2017-01-04T14:18:15 head[5], body[0] op[0x03]",
|
||||
"timestamp": "2017-01-04T14:18:15",
|
||||
"_body": "",
|
||||
"fixed": 0.0,
|
||||
"_head": "0300000027",
|
||||
"amount": 3.9,
|
||||
"_date": "0f522e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Rewind",
|
||||
"_description": "Rewind 2017-01-04T14:18:03 head[2], body[0] op[0x21]",
|
||||
"timestamp": "2017-01-04T14:18:03",
|
||||
"_body": "",
|
||||
"_head": "2100",
|
||||
"_date": "03520e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Prime",
|
||||
"type": "fixed",
|
||||
"_description": "Prime 2017-01-04T14:17:15 head[5], body[0] op[0x03]",
|
||||
"timestamp": "2017-01-04T14:17:15",
|
||||
"_body": "",
|
||||
"fixed": 1.0,
|
||||
"_head": "03000a000a",
|
||||
"amount": 1.0,
|
||||
"_date": "0f510e0411"
|
||||
},
|
||||
{
|
||||
"_type": "Prime",
|
||||
"type": "fixed",
|
||||
"_description": "Prime 2017-01-04T14:14:56 head[5], body[0] op[0x03]",
|
||||
"timestamp": "2017-01-04T14:14:56",
|
||||
"_body": "",
|
||||
"fixed": 2.5,
|
||||
"_head": "0300190019",
|
||||
"amount": 2.5,
|
||||
"_date": "384e0e0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:14:32 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:14:32",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "204e0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:14:32 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:14:32",
|
||||
"_body": "00",
|
||||
"_head": "3346",
|
||||
"rate": 1.75,
|
||||
"_date": "204e0e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T14:09:45 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T14:09:45",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2d490e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T14:09:45 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T14:09:45",
|
||||
"_body": "00",
|
||||
"_head": "3337",
|
||||
"rate": 1.375,
|
||||
"_date": "2d490e4411"
|
||||
},
|
||||
{
|
||||
"_type": "ClearAlarm",
|
||||
"_description": "ClearAlarm 2017-01-04T14:04:16 head[2], body[0] op[0x0c]",
|
||||
"timestamp": "2017-01-04T14:04:16",
|
||||
"_body": "",
|
||||
"_head": "0c04",
|
||||
"_date": "10440e0411"
|
||||
},
|
||||
{
|
||||
"_type": "AlarmPump",
|
||||
"_description": "AlarmPump 2017-01-04T14:04:05 head[4], body[0] op[0x06]",
|
||||
"timestamp": "2017-01-04T14:04:05",
|
||||
"_body": "",
|
||||
"_head": "06040bff",
|
||||
"_date": "05444e4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:57:38 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:57:38",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "26790d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:57:38 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:57:38",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "26790d4411"
|
||||
},
|
||||
{
|
||||
"programmed": 1.0,
|
||||
"_type": "Bolus",
|
||||
"type": "normal",
|
||||
"_description": "Bolus 2017-01-04T13:53:05 head[4], body[0] op[0x01]",
|
||||
"duration": 0,
|
||||
"timestamp": "2017-01-04T13:53:05",
|
||||
"_body": "",
|
||||
"_head": "010a0a00",
|
||||
"amount": 1.0,
|
||||
"_date": "05754d0411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:47:51 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:47:51",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "336f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:47:51 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:47:51",
|
||||
"_body": "00",
|
||||
"_head": "3368",
|
||||
"rate": 2.6,
|
||||
"_date": "336f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:43:53 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:43:53",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "356b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:43:53 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:43:53",
|
||||
"_body": "00",
|
||||
"_head": "3355",
|
||||
"rate": 2.125,
|
||||
"_date": "356b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:40:04 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:40:04",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "04680d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:40:04 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:40:04",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "04680d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:27:46 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:27:46",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2e5b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:27:46 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:27:46",
|
||||
"_body": "00",
|
||||
"_head": "3348",
|
||||
"rate": 1.8,
|
||||
"_date": "2e5b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:27:00 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:27:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "005b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:27:00 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:27:00",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "005b0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:20:49 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:20:49",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "31540d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:20:49 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:20:49",
|
||||
"_body": "00",
|
||||
"_head": "332d",
|
||||
"rate": 1.125,
|
||||
"_date": "31540d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:15:40 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:15:40",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "284f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:15:40 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:15:40",
|
||||
"_body": "00",
|
||||
"_head": "3373",
|
||||
"rate": 2.875,
|
||||
"_date": "284f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:15:31 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:15:31",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1f4f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:15:31 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:15:31",
|
||||
"_body": "00",
|
||||
"_head": "3373",
|
||||
"rate": 2.875,
|
||||
"_date": "1f4f0d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:08:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:08:29",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1d480d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:08:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:08:29",
|
||||
"_body": "00",
|
||||
"_head": "332c",
|
||||
"rate": 1.1,
|
||||
"_date": "1d480d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T13:03:28 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T13:03:28",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1c430d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T13:03:28 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T13:03:28",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "1c430d4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T12:57:44 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:57:44",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2c790c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:57:44 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:57:44",
|
||||
"_body": "00",
|
||||
"_head": "332a",
|
||||
"rate": 1.05,
|
||||
"_date": "2c790c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T12:47:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:47:29",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1d6f0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:47:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:47:29",
|
||||
"_body": "00",
|
||||
"_head": "331e",
|
||||
"rate": 0.75,
|
||||
"_date": "1d6f0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T12:35:30 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:35:30",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1e630c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:35:30 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:35:30",
|
||||
"_body": "00",
|
||||
"_head": "3322",
|
||||
"rate": 0.85,
|
||||
"_date": "1e630c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T12:23:47 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:23:47",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2f570c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:23:47 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:23:47",
|
||||
"_body": "00",
|
||||
"_head": "33b5",
|
||||
"rate": 4.525,
|
||||
"_date": "2f570c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T12:18:48 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:18:48",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "30520c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:18:48 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:18:48",
|
||||
"_body": "00",
|
||||
"_head": "334a",
|
||||
"rate": 1.85,
|
||||
"_date": "30520c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T12:13:29 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:13:29",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "1d4d0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:13:29 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:13:29",
|
||||
"_body": "00",
|
||||
"_head": "3337",
|
||||
"rate": 1.375,
|
||||
"_date": "1d4d0c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T12:08:07 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T12:08:07",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "07480c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T12:08:07 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T12:08:07",
|
||||
"_body": "00",
|
||||
"_head": "3324",
|
||||
"rate": 0.9,
|
||||
"_date": "07480c4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T11:55:46 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T11:55:46",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2e770b4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T11:55:46 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T11:55:46",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "2e770b4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasalDuration",
|
||||
"duration (min)": 30,
|
||||
"_description": "TempBasalDuration 2017-01-04T11:42:44 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T11:42:44",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"_date": "2c6a0b4411"
|
||||
},
|
||||
{
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T11:42:44 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T11:42:44",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0.0,
|
||||
"_date": "2c6a0b4411"
|
||||
}
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
120.5
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"status": "normal",
|
||||
"bolusing": false,
|
||||
"suspended": false
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"duration": 28,
|
||||
"rate": 0.0,
|
||||
"temp": "absolute"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"ratio":1.4}
|
|
@ -0,0 +1,140 @@
|
|||
[
|
||||
{
|
||||
"i": 0,
|
||||
"start": "00:00:00",
|
||||
"rate": 1.0,
|
||||
"minutes": 0
|
||||
},
|
||||
{
|
||||
"i": 1,
|
||||
"start": "01:00:00",
|
||||
"rate": 0.9,
|
||||
"minutes": 60
|
||||
},
|
||||
{
|
||||
"i": 2,
|
||||
"start": "02:00:00",
|
||||
"rate": 0.8,
|
||||
"minutes": 120
|
||||
},
|
||||
{
|
||||
"i": 3,
|
||||
"start": "03:00:00",
|
||||
"rate": 0.8,
|
||||
"minutes": 180
|
||||
},
|
||||
{
|
||||
"i": 4,
|
||||
"start": "04:00:00",
|
||||
"rate": 1.3,
|
||||
"minutes": 240
|
||||
},
|
||||
{
|
||||
"i": 5,
|
||||
"start": "05:00:00",
|
||||
"rate": 1.4000000000000001,
|
||||
"minutes": 300
|
||||
},
|
||||
{
|
||||
"i": 6,
|
||||
"start": "06:00:00",
|
||||
"rate": 1.8,
|
||||
"minutes": 360
|
||||
},
|
||||
{
|
||||
"i": 7,
|
||||
"start": "07:00:00",
|
||||
"rate": 1.8,
|
||||
"minutes": 420
|
||||
},
|
||||
{
|
||||
"i": 8,
|
||||
"start": "08:00:00",
|
||||
"rate": 1.8,
|
||||
"minutes": 480
|
||||
},
|
||||
{
|
||||
"i": 9,
|
||||
"start": "09:00:00",
|
||||
"rate": 1.5,
|
||||
"minutes": 540
|
||||
},
|
||||
{
|
||||
"i": 10,
|
||||
"start": "10:00:00",
|
||||
"rate": 1.0,
|
||||
"minutes": 600
|
||||
},
|
||||
{
|
||||
"i": 11,
|
||||
"start": "11:00:00",
|
||||
"rate": 0.9,
|
||||
"minutes": 660
|
||||
},
|
||||
{
|
||||
"i": 12,
|
||||
"start": "12:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 720
|
||||
},
|
||||
{
|
||||
"i": 13,
|
||||
"start": "13:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 780
|
||||
},
|
||||
{
|
||||
"i": 14,
|
||||
"start": "14:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 840
|
||||
},
|
||||
{
|
||||
"i": 15,
|
||||
"start": "15:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 900
|
||||
},
|
||||
{
|
||||
"i": 16,
|
||||
"start": "17:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 1020
|
||||
},
|
||||
{
|
||||
"i": 17,
|
||||
"start": "18:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 1080
|
||||
},
|
||||
{
|
||||
"i": 18,
|
||||
"start": "19:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 1140
|
||||
},
|
||||
{
|
||||
"i": 19,
|
||||
"start": "20:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 1200
|
||||
},
|
||||
{
|
||||
"i": 20,
|
||||
"start": "21:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 1260
|
||||
},
|
||||
{
|
||||
"i": 21,
|
||||
"start": "22:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 1320
|
||||
},
|
||||
{
|
||||
"i": 22,
|
||||
"start": "23:00:00",
|
||||
"rate": 0.6000000000000001,
|
||||
"minutes": 1380
|
||||
}
|
||||
]
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"units": "mg/dL",
|
||||
"raw": "0x01 0x00 0x5a 0x5a 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00",
|
||||
"user_preferred_units": "mg/dL",
|
||||
"targets": [
|
||||
{
|
||||
"i": 0,
|
||||
"high": 90,
|
||||
"start": "00:00:00",
|
||||
"low": 90,
|
||||
"offset": 0,
|
||||
"x": 0
|
||||
}
|
||||
],
|
||||
"first": 1
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"units": "mg/dL",
|
||||
"raw": "0x01 0x00 0x5a 0x5a 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00",
|
||||
"targets": [
|
||||
{
|
||||
"high": 90,
|
||||
"start": "00:00:00",
|
||||
"low": 90,
|
||||
"offset": 0,
|
||||
"i": 0,
|
||||
"x": 0
|
||||
}
|
||||
],
|
||||
"first": 1
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"units": "grams",
|
||||
"raw": "0x01 0x00 0x09 0x0b 0x07 0x12 0x09 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00",
|
||||
"first": 1,
|
||||
"schedule": [
|
||||
{
|
||||
"start": "00:00:00",
|
||||
"r": 9,
|
||||
"ratio": 9,
|
||||
"offset": 0,
|
||||
"i": 0,
|
||||
"x": 0
|
||||
},
|
||||
{
|
||||
"start": "05:30:00",
|
||||
"r": 7,
|
||||
"ratio": 7,
|
||||
"offset": 330,
|
||||
"i": 11,
|
||||
"x": 1
|
||||
},
|
||||
{
|
||||
"start": "09:00:00",
|
||||
"r": 9,
|
||||
"ratio": 9,
|
||||
"offset": 540,
|
||||
"i": 18,
|
||||
"x": 2
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"units": "mg/dL",
|
||||
"user_preferred_units": "mg/dL",
|
||||
"sensitivities": [
|
||||
{
|
||||
"i": 0,
|
||||
"start": "00:00:00",
|
||||
"sensitivity": 35,
|
||||
"x": 0,
|
||||
"offset": 0
|
||||
},
|
||||
{
|
||||
"i": 8,
|
||||
"start": "04:00:00",
|
||||
"sensitivity": 30,
|
||||
"x": 1,
|
||||
"offset": 240
|
||||
},
|
||||
{
|
||||
"i": 20,
|
||||
"start": "10:00:00",
|
||||
"sensitivity": 30,
|
||||
"x": 2,
|
||||
"offset": 600
|
||||
}
|
||||
],
|
||||
"first": 1
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"units": "mg/dL",
|
||||
"sensitivities": [
|
||||
{
|
||||
"i": 0,
|
||||
"start": "00:00:00",
|
||||
"sensitivity": 35,
|
||||
"offset": 0,
|
||||
"x": 0
|
||||
},
|
||||
{
|
||||
"i": 8,
|
||||
"start": "04:00:00",
|
||||
"sensitivity": 30,
|
||||
"offset": 240,
|
||||
"x": 1
|
||||
},
|
||||
{
|
||||
"i": 20,
|
||||
"start": "10:00:00",
|
||||
"sensitivity": 30,
|
||||
"offset": 600,
|
||||
"x": 2
|
||||
}
|
||||
],
|
||||
"first": 1
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
"522"
|
|
@ -0,0 +1 @@
|
|||
{"max_iob":15,"max_daily_safety_multiplier":9,"current_basal_safety_multiplier":12,"autosens_max":1.4,"autosens_min":0.6,"autosens_adjust_targets":true,"override_high_target_with_low":false,"skip_neutral_temps":false,"bolussnooze_dia_divisor":2,"min_5m_carbimpact":3,"carbratio_adjustmentratio":1,"dia":3,"model":"522","current_basal":0.6,"basalprofile":[{"i":0,"start":"00:00:00","rate":1,"minutes":0},{"i":1,"start":"01:00:00","rate":0.9,"minutes":60},{"i":2,"start":"02:00:00","rate":0.8,"minutes":120},{"i":3,"start":"03:00:00","rate":0.8,"minutes":180},{"i":4,"start":"04:00:00","rate":1.3,"minutes":240},{"i":5,"start":"05:00:00","rate":1.4000000000000001,"minutes":300},{"i":6,"start":"06:00:00","rate":1.8,"minutes":360},{"i":7,"start":"07:00:00","rate":1.8,"minutes":420},{"i":8,"start":"08:00:00","rate":1.8,"minutes":480},{"i":9,"start":"09:00:00","rate":1.5,"minutes":540},{"i":10,"start":"10:00:00","rate":1,"minutes":600},{"i":11,"start":"11:00:00","rate":0.9,"minutes":660},{"i":12,"start":"12:00:00","rate":0.6000000000000001,"minutes":720},{"i":13,"start":"13:00:00","rate":0.6000000000000001,"minutes":780},{"i":14,"start":"14:00:00","rate":0.6000000000000001,"minutes":840},{"i":15,"start":"15:00:00","rate":0.6000000000000001,"minutes":900},{"i":16,"start":"17:00:00","rate":0.6000000000000001,"minutes":1020},{"i":17,"start":"18:00:00","rate":0.6000000000000001,"minutes":1080},{"i":18,"start":"19:00:00","rate":0.6000000000000001,"minutes":1140},{"i":19,"start":"20:00:00","rate":0.6000000000000001,"minutes":1200},{"i":20,"start":"21:00:00","rate":0.6000000000000001,"minutes":1260},{"i":21,"start":"22:00:00","rate":0.6000000000000001,"minutes":1320},{"i":22,"start":"23:00:00","rate":0.6000000000000001,"minutes":1380}],"max_daily_basal":1.8,"max_basal":6.3,"out_units":"mg/dL","min_bg":90,"max_bg":90,"sens":30,"isfProfile":{"units":"mg/dL","user_preferred_units":"mg/dL","sensitivities":[{"i":0,"start":"00:00:00","sensitivity":35,"x":0,"offset":0},{"i":8,"start":"04:00:00","sensitivity":30,"x":1,"offset":240},{"i":20,"start":"10:00:00","sensitivity":30,"x":2,"offset":600,"endOffset":1440}],"first":1},"carb_ratio":9}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"low_reservoir_warn_point": 16,
|
||||
"keypad_lock_status": 0,
|
||||
"maxBasal": 6.3,
|
||||
"temp_basal": {
|
||||
"percent": 100,
|
||||
"type": "Units/hour"
|
||||
},
|
||||
"low_reservoir_warn_type": 1,
|
||||
"insulinConcentration": 100,
|
||||
"audio_bolus_enable": true,
|
||||
"variable_bolus_enable": true,
|
||||
"alarm": {
|
||||
"volume": -1,
|
||||
"mode": 1
|
||||
},
|
||||
"rf_enable": true,
|
||||
"auto_off_duration_hrs": 15,
|
||||
"block_enable": false,
|
||||
"timeformat": 1,
|
||||
"insulin_action_curve": 3,
|
||||
"audio_bolus_size": 1.0,
|
||||
"selected_pattern": 0,
|
||||
"patterns_enabled": true,
|
||||
"maxBolus": 12.0,
|
||||
"paradigm_enabled": 1
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -0,0 +1 @@
|
|||
{"content":"148-21 16:36\n5.2U->-28-16\nTmp: 28m@0.0 at 16:40\nReq: None\nCOB: 0, Dev: -64, BGI: -8.2, ISF: 21, Target: 81; Eventual BG -28 < 81, setting -11.3U/hr, but 28m left and 0 ~ req 0U/hr: no action required\nSched: 0.60U/hr\nmealCOB: 0g\neddie\n","refresh_frequency":1}
|
|
@ -0,0 +1,31 @@
|
|||
[
|
||||
{
|
||||
"duration": "30",
|
||||
"raw_duration": {
|
||||
"_type": "TempBasalDuration",
|
||||
"_description": "TempBasalDuration 2017-01-04T16:37:57 head[2], body[0] op[0x16]",
|
||||
"timestamp": "2017-01-04T16:37:57+01:00",
|
||||
"_body": "",
|
||||
"_head": "1601",
|
||||
"duration (min)": 30,
|
||||
"_date": "3965104411"
|
||||
},
|
||||
"timestamp": "2017-01-04T16:37:57+01:00",
|
||||
"absolute": "0",
|
||||
"rate": 0,
|
||||
"raw_rate": {
|
||||
"_type": "TempBasal",
|
||||
"temp": "absolute",
|
||||
"_description": "TempBasal 2017-01-04T16:37:57 head[2], body[1] op[0x33]",
|
||||
"timestamp": "2017-01-04T16:37:57+01:00",
|
||||
"_body": "00",
|
||||
"_head": "3300",
|
||||
"rate": 0,
|
||||
"_date": "3965104411"
|
||||
},
|
||||
"eventType": "Temp Basal",
|
||||
"medtronic": "mm://openaps/mm-format-ns-treatments/Temp Basal",
|
||||
"created_at": "2017-01-04T16:37:57+01:00",
|
||||
"enteredBy": "openaps://medtronic/522"
|
||||
}
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
{"device":"openaps://eddie","openaps":{"iob":{"iob":5.521,"activity":0.077,"bolussnooze":1.574,"basaliob":1.893,"netbasalinsulin":5.05,"hightempinsulin":5.1,"timestamp":"2017-01-04T15:37:36.000Z"},"suggested":{"temp":"absolute","bg":148,"tick":-21,"eventualBG":-34,"snoozeBG":17,"COB":0,"IOB":5.521,"reason":"COB: 0, Dev: -64, BGI: -8.24, ISF: 21, Target: 81; Eventual BG -34 < 81, setting -11.1U/hr","duration":30,"rate":0,"timestamp":"2017-01-04T15:37:50.000Z"},"enacted":{"bg":148,"temp":"absolute","snoozeBG":17,"recieved":true,"predBGs":{"IOB":[148,128,109,91,75,59,45,39,39,39,39,39,39]},"rate":0,"reason":"COB: 0, Dev: -64, BGI: -8.24, ISF: 21, Target: 81; Eventual BG -34 < 81, setting -11.1U/hr","COB":0,"eventualBG":-34,"timestamp":"2017-01-04T15:37:56.000Z","duration":30,"tick":-21,"IOB":5.521}},"pump":{"clock":"2017-01-04T16:37:36+01:00","battery":{"status":"normal","voltage":1.45},"reservoir":120.5,"status":{"status":"normal","bolusing":false,"suspended":false,"timestamp":"2017-01-04T15:37:43.000Z"}},"mmtune":{"scanDetails":[["868.372",4,-91],["868.384",5,-81],["868.396",5,-78],["868.408",5,-77],["868.420",5,-76],["868.432",5,-76],["868.444",5,-76],["868.456",5,-76],["868.468",5,-75],["868.480",5,-76],["868.492",5,-76],["868.504",5,-77],["868.516",5,-80],["868.528",5,-86]],"setFreq":868.468,"usedDefault":false,"timestamp":"2017-01-04T15:33:30.000Z"},"uploader":{"battery":57,"batteryVoltage":3748}}
|
|
@ -0,0 +1 @@
|
|||
{"content":"148-21 16:36\n5.2U->-28-16\nTmp: 28m@0.0 at 16:40\nReq: None\nCOB: 0, Dev: -64, BGI: -8.2, ISF: 21, Target: 81; Eventual BG -28 < 81, setting -11.3U/hr, but 28m left and 0 ~ req 0U/hr: no action required\nSched: 0.60U/hr\nmealCOB: 0g\neddie\n","refresh_frequency":1}
|
|
@ -3,10 +3,9 @@ package info.nightscout.utils;
|
|||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interfaces.TempBasalsInterface;
|
||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.client.data.NSProfile;
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,7 +17,12 @@ public class JSONFormatter {
|
|||
public static Spanned format(final String jsonString) {
|
||||
final JsonVisitor visitor = new JsonVisitor(4, ' ');
|
||||
try {
|
||||
return Html.fromHtml(visitor.visit(new JSONObject(jsonString), 0));
|
||||
if (jsonString.equals("undefined"))
|
||||
return Html.fromHtml("undefined");
|
||||
else if (jsonString.getBytes()[0] == '[')
|
||||
return Html.fromHtml(visitor.visit(new JSONArray(jsonString), 0));
|
||||
else
|
||||
return Html.fromHtml(visitor.visit(new JSONObject(jsonString), 0));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return Html.fromHtml("");
|
||||
|
|
|
@ -56,7 +56,7 @@ public class Translator {
|
|||
case "Sensor":
|
||||
return MainApp.sResources.getString(R.string.glucosetype_sensor);
|
||||
case "Manual":
|
||||
return MainApp.sResources.getString(R.string.glucosetype_manual);
|
||||
return MainApp.sResources.getString(R.string.manual);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
|
7
app/src/main/res/drawable-mdpi-v11/temptargetborder.xml
Normal file
7
app/src/main/res/drawable-mdpi-v11/temptargetborder.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
|
||||
<solid android:color="@color/colorWizardButton" />
|
||||
<stroke android:width="1dip" android:color="@android:color/white"/>
|
||||
<corners
|
||||
android:radius="2dp" >
|
||||
</corners>
|
||||
</shape>
|
|
@ -22,6 +22,19 @@
|
|||
android:text="@string/careportal_profileswitch"
|
||||
android:textColor="@color/colorProfileSwitchButton" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/actions_temptarget"
|
||||
style="?android:attr/buttonStyle"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/careportal_temptarget"
|
||||
android:textColor="@color/colorTempTargetButton" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/actions_settempbasal"
|
||||
style="?android:attr/buttonStyle"
|
||||
|
|
|
@ -197,6 +197,16 @@
|
|||
app:layout_gravity="fill"
|
||||
app:layout_row="5" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/careportal_temptarget"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="70dp"
|
||||
android:text="@string/careportal_temptarget"
|
||||
app:layout_column="0"
|
||||
app:layout_columnWeight="1"
|
||||
app:layout_gravity="fill"
|
||||
app:layout_row="6" />
|
||||
|
||||
</android.support.v7.widget.GridLayout>
|
||||
</ScrollView>
|
||||
</FrameLayout>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue