initial work on SMB
This commit is contained in:
parent
82d3289602
commit
898e162300
|
@ -44,7 +44,7 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 23
|
||||
versionCode 1500
|
||||
version "1.5g"
|
||||
version "1.5smb"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", generateGitBuild()
|
||||
}
|
||||
|
|
|
@ -194,17 +194,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedMinBG, don’t use it
|
||||
//console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG);
|
||||
if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) {
|
||||
process.stderr.write("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
||||
console.error("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
||||
min_bg = adjustedMinBG;
|
||||
} else {
|
||||
process.stderr.write("min_bg unchanged: "+min_bg+"; ");
|
||||
console.error("min_bg unchanged: "+min_bg+"; ");
|
||||
}
|
||||
// if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedTargetBG, don’t use it
|
||||
if (eventualBG > adjustedTargetBG && naive_eventualBG > adjustedTargetBG && target_bg > adjustedTargetBG) {
|
||||
process.stderr.write("target_bg from "+target_bg+" to "+adjustedTargetBG+"; ");
|
||||
console.error("target_bg from "+target_bg+" to "+adjustedTargetBG+"; ");
|
||||
target_bg = adjustedTargetBG;
|
||||
} else {
|
||||
process.stderr.write("target_bg unchanged: "+target_bg+"; ");
|
||||
console.error("target_bg unchanged: "+target_bg+"; ");
|
||||
}
|
||||
// if eventualBG, naive_eventualBG, and max_bg aren't all above adjustedMaxBG, don’t use it
|
||||
if (eventualBG > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) {
|
||||
|
|
|
@ -38,6 +38,7 @@ import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalFragm
|
|||
import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAFragment;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAFragment;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBFragment;
|
||||
import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
|
||||
import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin;
|
||||
import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPercentageProfileFragment;
|
||||
|
@ -125,6 +126,7 @@ public class MainApp extends Application {
|
|||
if (Config.LOOPENABLED) pluginsList.add(LoopFragment.getPlugin());
|
||||
if (Config.OPENAPSENABLED) pluginsList.add(OpenAPSMAFragment.getPlugin());
|
||||
if (Config.OPENAPSENABLED) pluginsList.add(OpenAPSAMAFragment.getPlugin());
|
||||
if (Config.OPENAPSENABLED) pluginsList.add(OpenAPSSMBFragment.getPlugin());
|
||||
pluginsList.add(NSProfileFragment.getPlugin());
|
||||
if (Config.OTHERPROFILES) pluginsList.add(SimpleProfileFragment.getPlugin());
|
||||
if (Config.OTHERPROFILES) pluginsList.add(LocalProfileFragment.getPlugin());
|
||||
|
|
|
@ -14,6 +14,7 @@ import android.preference.PreferenceManager;
|
|||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.events.EventRefreshGui;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
|
||||
import info.nightscout.androidaps.plugins.PumpDanaR.BluetoothDevicePreference;
|
||||
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
|
||||
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
|
||||
|
@ -112,6 +113,8 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
addPreferencesFromResource(R.xml.pref_openapsma);
|
||||
if (MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class) != null && MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class).isEnabled(PluginBase.APS))
|
||||
addPreferencesFromResource(R.xml.pref_openapsama);
|
||||
if (MainApp.getSpecificPlugin(OpenAPSSMBPlugin.class) != null && MainApp.getSpecificPlugin(OpenAPSSMBPlugin.class).isEnabled(PluginBase.APS))
|
||||
addPreferencesFromResource(R.xml.pref_openapsama);
|
||||
}
|
||||
if (MainApp.getSpecificPlugin(SensitivityAAPSPlugin.class) != null && MainApp.getSpecificPlugin(SensitivityAAPSPlugin.class).isEnabled(PluginBase.SENSITIVITY)
|
||||
|| MainApp.getSpecificPlugin(SensitivityWeightedAveragePlugin.class) != null && MainApp.getSpecificPlugin(SensitivityWeightedAveragePlugin.class).isEnabled(PluginBase.SENSITIVITY))
|
||||
|
|
|
@ -19,6 +19,7 @@ public class IobTotal {
|
|||
// oref1
|
||||
public double microBolusInsulin;
|
||||
public double microBolusIOB;
|
||||
public long lastBolusTime;
|
||||
|
||||
public double netInsulin = 0d; // for calculations from temp basals only
|
||||
public double netRatio = 0d; // net ratio at start of temp basal
|
||||
|
@ -36,6 +37,7 @@ public class IobTotal {
|
|||
this.hightempinsulin = 0d;
|
||||
this.microBolusInsulin = 0d;
|
||||
this.microBolusIOB = 0d;
|
||||
this.lastBolusTime = 0;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
|
@ -63,6 +65,7 @@ public class IobTotal {
|
|||
result.hightempinsulin = basalIob.hightempinsulin;
|
||||
result.microBolusInsulin = bolusIOB.microBolusInsulin + basalIob.microBolusInsulin;
|
||||
result.microBolusIOB = bolusIOB.microBolusIOB + basalIob.microBolusIOB;
|
||||
result.lastBolusTime = bolusIOB.lastBolusTime;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -98,6 +101,7 @@ public class IobTotal {
|
|||
json.put("basaliob", basaliob);
|
||||
json.put("bolussnooze", bolussnooze);
|
||||
json.put("activity", activity);
|
||||
json.put("lastBolusTime", lastBolusTime);
|
||||
json.put("time", DateUtil.toISOString(new Date(time)));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -7,4 +7,5 @@ public class MealData {
|
|||
public double boluses = 0d;
|
||||
public double carbs = 0d;
|
||||
public double mealCOB = 0.0d;
|
||||
public double minDeviationSlope;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ public class AutosensData {
|
|||
|
||||
public double autosensRatio = 1d;
|
||||
|
||||
public double minDeviationSlope;
|
||||
|
||||
public String log(long time) {
|
||||
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " Bgi=" + bgi + " Deviation=" + deviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio;
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
|||
private BgReading findOlder(long time) {
|
||||
BgReading lastFound = bgReadings.get(bgReadings.size() - 1);
|
||||
if (lastFound.date > time) return null;
|
||||
for (int i = bgReadings.size() - 2; i >=0 ; --i) {
|
||||
for (int i = bgReadings.size() - 2; i >= 0; --i) {
|
||||
if (bgReadings.get(i).date < time) continue;
|
||||
lastFound = bgReadings.get(i);
|
||||
if (bgReadings.get(i).date > time) break;
|
||||
|
@ -246,7 +246,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
|||
long currentTime = bgReadings.get(0).date + 5 * 60 * 1000 - bgReadings.get(0).date % (5 * 60 * 1000) - 5 * 60 * 1000L;
|
||||
//log.debug("First reading: " + new Date(currentTime).toLocaleString());
|
||||
|
||||
while (true) {
|
||||
while (true) {
|
||||
// test if current value is older than current time
|
||||
BgReading newer = findNewer(currentTime);
|
||||
BgReading older = findOlder(currentTime);
|
||||
|
@ -353,6 +353,11 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
|||
long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
|
||||
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
|
||||
AutosensData previous = autosensDataTable.get(prevDataTime);
|
||||
|
||||
double currentDeviation = 0;
|
||||
double minDeviationSlope = 0;
|
||||
double maxDeviation = 0;
|
||||
|
||||
// start from oldest to be able sub cob
|
||||
for (int i = bucketed_data.size() - 4; i >= 0; i--) {
|
||||
// check if data already exists
|
||||
|
@ -379,11 +384,13 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
|||
double bg;
|
||||
double avgDelta;
|
||||
double delta;
|
||||
|
||||
bg = bucketed_data.get(i).value;
|
||||
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
|
||||
log.error("! value < 39");
|
||||
continue;
|
||||
}
|
||||
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
|
||||
delta = (bg - bucketed_data.get(i + 1).value);
|
||||
|
||||
IobTotal iob = calculateFromTreatmentsAndTemps(bgTime);
|
||||
|
@ -391,6 +398,32 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
|||
double bgi = -iob.activity * sens * 5;
|
||||
double deviation = delta - bgi;
|
||||
|
||||
/*
|
||||
TODO: SMB: i don't undestand this part
|
||||
long ciTime = System.currentTimeMillis();
|
||||
|
||||
if (i == bucketed_data.size() - 4) {
|
||||
currentDeviation = Math.round((avgDelta - bgi) * 1000) / 1000;
|
||||
} else if (ciTime > bgTime) {
|
||||
double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000;
|
||||
double deviationSlope = (avgDeviation - currentDeviation) / (bgTime - ciTime) * 1000 * 60 * 5;
|
||||
if (avgDeviation > maxDeviation) {
|
||||
minDeviationSlope = Math.min(0, deviationSlope);
|
||||
maxDeviation = avgDeviation;
|
||||
}
|
||||
//console.error("Deviations:",bgTime, avgDeviation, deviationSlope, minDeviationSlope);
|
||||
}
|
||||
|
||||
https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
|
||||
|
||||
Scott's comment
|
||||
that stuff is used in UAM (unannounced meal) mode. what we're doing there is calculating the currentDeviation (how fast carbs are absorbing right now), and comparing that to the highest deviation we've seen in the last 45m to calculate the deviationSlope: the rate at which deviations are currently decreasing. We then project deviations to continue into the future starting at the currentDeviation rate and declining at deviationSlope until it gets back down to zero
|
||||
that gives us an independent way to estimate how long deviations (likely carb absorption) will continue, even if we don't have (or don't want to fully trust) the user's carb estimate
|
||||
the complexity comes from reusing the same COB calculation code to calculate both current and historical carb absorption rates
|
||||
|
||||
*/
|
||||
|
||||
|
||||
List<Treatment> recentTreatments = MainApp.getConfigBuilder().getTreatments5MinBackFromHistory(bgTime);
|
||||
for (int ir = 0; ir < recentTreatments.size(); ir++) {
|
||||
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
|
||||
|
@ -420,6 +453,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
|||
autosensData.deviation = deviation;
|
||||
autosensData.bgi = bgi;
|
||||
autosensData.delta = delta;
|
||||
autosensData.minDeviationSlope = minDeviationSlope;
|
||||
|
||||
// calculate autosens only without COB
|
||||
if (autosensData.cob <= 0) {
|
||||
|
@ -669,8 +703,8 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
|||
for (int index = iobTable.size() - 1; index >= 0; index--) {
|
||||
if (iobTable.keyAt(index) > time) {
|
||||
if (Config.logAutosensData)
|
||||
if (Config.logAutosensData)
|
||||
log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
|
||||
if (Config.logAutosensData)
|
||||
log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
|
||||
iobTable.removeAt(index);
|
||||
} else {
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSSMB;
|
||||
|
||||
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 java.util.Date;
|
||||
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.utils.SP;
|
||||
|
||||
public class DetermineBasalAdapterSMBJS {
|
||||
private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterSMBJS.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 final String PARAM_reservoirData = "reservoirData";
|
||||
private final String PARAM_microBolusAllowed = "microBolusAllowed";
|
||||
|
||||
|
||||
private String storedCurrentTemp = null;
|
||||
private String storedIobData = null;
|
||||
private String storedGlucoseStatus = null;
|
||||
private String storedProfile = null;
|
||||
private String storedMeal_data = null;
|
||||
private String storedAutosens_data = null;
|
||||
private String storedMicroBolusAllowed = null;
|
||||
|
||||
private String scriptDebug = "";
|
||||
|
||||
/**
|
||||
* Main code
|
||||
*/
|
||||
|
||||
public DetermineBasalAdapterSMBJS(ScriptReader scriptReader) throws IOException {
|
||||
mV8rt = V8.createV8Runtime();
|
||||
mScriptReader = scriptReader;
|
||||
|
||||
initLogCallback();
|
||||
initProcessExitCallback();
|
||||
initModuleParent();
|
||||
loadScript();
|
||||
}
|
||||
|
||||
public DetermineBasalResultSMB invoke() {
|
||||
|
||||
log.debug(">>> Invoking detemine_basal_oref1 <<<");
|
||||
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"));
|
||||
log.debug("Reservoir data: " + "undefined");
|
||||
log.debug("MicroBolusAllowed: " + (storedMicroBolusAllowed = mV8rt.executeStringScript("JSON.stringify(" + PARAM_microBolusAllowed + ");")));
|
||||
|
||||
mV8rt.executeVoidScript(
|
||||
"var rT = determine_basal(" +
|
||||
PARAM_glucoseStatus + ", " +
|
||||
PARAM_currentTemp + ", " +
|
||||
PARAM_iobData + ", " +
|
||||
PARAM_profile + ", " +
|
||||
PARAM_autosens_data + ", " +
|
||||
PARAM_meal_data + ", " +
|
||||
"tempBasalFunctions" + ", " +
|
||||
PARAM_microBolusAllowed + ", " +
|
||||
PARAM_reservoirData +
|
||||
");");
|
||||
|
||||
|
||||
String ret = mV8rt.executeStringScript("JSON.stringify(rT);");
|
||||
log.debug("Result: " + ret);
|
||||
|
||||
DetermineBasalResultSMB result = null;
|
||||
try {
|
||||
result = new DetermineBasalResultSMB(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 getMicroBolusAllowedParam() {
|
||||
return storedMicroBolusAllowed;
|
||||
}
|
||||
|
||||
String getScriptDebug() {
|
||||
return scriptDebug;
|
||||
}
|
||||
|
||||
private void loadScript() throws IOException {
|
||||
mV8rt.executeVoidScript("var round_basal = function round_basal(basal, profile) { return basal; };");
|
||||
mV8rt.executeVoidScript("require = function() {return round_basal;};");
|
||||
|
||||
mV8rt.executeVoidScript(readFile("OpenAPSSMB/basal-set-temp.js"), "OpenAPSSMB/basal-set-temp.js ", 0);
|
||||
mV8rt.executeVoidScript("var tempBasalFunctions = module.exports;");
|
||||
|
||||
mV8rt.executeVoidScript(
|
||||
readFile("OpenAPSSMB/determine-basal.js"),
|
||||
"OpenAPSSMB/determine-basal.js",
|
||||
0);
|
||||
mV8rt.executeVoidScript("var determine_basal = module.exports;");
|
||||
}
|
||||
|
||||
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(Profile profile,
|
||||
double maxIob,
|
||||
double maxBasal,
|
||||
double minBg,
|
||||
double maxBg,
|
||||
double targetBg,
|
||||
PumpInterface pump,
|
||||
IobTotal[] iobArray,
|
||||
GlucoseStatus glucoseStatus,
|
||||
MealData mealData,
|
||||
double autosensDataRatio,
|
||||
boolean tempTargetSet,
|
||||
boolean microBolusAllowed
|
||||
) {
|
||||
|
||||
String units = profile.getUnits();
|
||||
|
||||
mProfile = new V8Object(mV8rt);
|
||||
mProfile.add("max_iob", maxIob);
|
||||
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());
|
||||
mProfile.add("sens", Profile.toMgdl(profile.getIsf().doubleValue(), units));
|
||||
mProfile.add("max_daily_safety_multiplier", SP.getInt("openapsama_max_daily_safety_multiplier", 3));
|
||||
mProfile.add("current_basal_safety_multiplier", SP.getInt("openapsama_current_basal_safety_multiplier", 4));
|
||||
mProfile.add("skip_neutral_temps", true);
|
||||
mProfile.add("current_basal", pump.getBaseBasalRate());
|
||||
mProfile.add("temptargetSet", tempTargetSet);
|
||||
mProfile.add("autosens_adjust_targets", SP.getBoolean("openapsama_autosens_adjusttargets", true));
|
||||
mProfile.add("min_5m_carbimpact", SP.getDouble("openapsama_min_5m_carbimpact", 3d));
|
||||
mProfile.add("enableSMB_with_bolus", SP.getBoolean(R.string.key_use_smb, false));
|
||||
mProfile.add("enableSMB_with_COB", SP.getBoolean(R.string.key_use_smb, false));
|
||||
mProfile.add("enableSMB_with_temptarget", SP.getBoolean(R.string.key_use_smb, false));
|
||||
mProfile.add("enableUAM", SP.getBoolean(R.string.key_use_uam, false));
|
||||
mProfile.add("adv_target_adjustments", true); // lower target automatically when BG and eventualBG are high
|
||||
// create maxCOB and default it to 120 because that's the most a typical body can absorb over 4 hours.
|
||||
// (If someone enters more carbs or stacks more; OpenAPS will just truncate dosing based on 120.
|
||||
// Essentially, this just limits AMA as a safety cap against weird COB calculations)
|
||||
mProfile.add("maxCOB", 120);
|
||||
mProfile.add("autotune_isf_adjustmentFraction", 0.5); // keep autotune ISF closer to pump ISF via a weighted average of fullNewISF and pumpISF. 1.0 allows full adjustment, 0 is no adjustment from pump ISF.
|
||||
mProfile.add("remainingCarbsFraction", 1.0d); // fraction of carbs we'll assume will absorb over 4h if we don't yet see carb absorption
|
||||
mProfile.add("remainingCarbsCap", 90); // max carbs we'll assume will absorb over 4h if we don't yet see carb absorption
|
||||
mV8rt.add(PARAM_profile, mProfile);
|
||||
|
||||
mCurrentTemp = new V8Object(mV8rt);
|
||||
mCurrentTemp.add("temp", "absolute");
|
||||
mCurrentTemp.add("duration", MainApp.getConfigBuilder().getTempBasalRemainingMinutesFromHistory());
|
||||
mCurrentTemp.add("rate", MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory());
|
||||
|
||||
// as we have non default temps longer than 30 mintues
|
||||
TemporaryBasal tempBasal = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
|
||||
if (tempBasal != null) {
|
||||
mCurrentTemp.add("minutesrunning", tempBasal.getRealDuration());
|
||||
}
|
||||
|
||||
mV8rt.add(PARAM_currentTemp, mCurrentTemp);
|
||||
|
||||
mIobData = mV8rt.executeArrayScript(IobCobCalculatorPlugin.convertToJSONArray(iobArray).toString());
|
||||
mV8rt.add(PARAM_iobData, mIobData);
|
||||
|
||||
mGlucoseStatus = new V8Object(mV8rt);
|
||||
mGlucoseStatus.add("glucose", glucoseStatus.glucose);
|
||||
|
||||
if (SP.getBoolean("always_use_shortavg", false)) {
|
||||
mGlucoseStatus.add("delta", glucoseStatus.short_avgdelta);
|
||||
} else {
|
||||
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);
|
||||
mMealData.add("minDeviationSlope", mealData.minDeviationSlope);
|
||||
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);
|
||||
}
|
||||
|
||||
mV8rt.addUndefined(PARAM_reservoirData);
|
||||
mV8rt.add(PARAM_microBolusAllowed, microBolusAllowed);
|
||||
|
||||
}
|
||||
|
||||
|
||||
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,180 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSSMB;
|
||||
|
||||
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.data.IobTotal;
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
import info.nightscout.utils.DateUtil;
|
||||
|
||||
public class DetermineBasalResultSMB extends APSResult {
|
||||
public Date date;
|
||||
public JSONObject json = new JSONObject();
|
||||
public double eventualBG;
|
||||
public double snoozeBG;
|
||||
public IobTotal iob;
|
||||
public double smbValue;
|
||||
public long deliverAt;
|
||||
|
||||
public DetermineBasalResultSMB(JSONObject result) {
|
||||
date = new Date();
|
||||
json = result;
|
||||
try {
|
||||
if (result.has("error")) {
|
||||
reason = result.getString("error");
|
||||
changeRequested = false;
|
||||
rate = -1;
|
||||
duration = -1;
|
||||
} else {
|
||||
reason = result.getString("reason");
|
||||
if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG");
|
||||
if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG");
|
||||
if (result.has("rate")) {
|
||||
rate = result.getDouble("rate");
|
||||
if (rate < 0d) rate = 0d;
|
||||
changeRequested = true;
|
||||
} else {
|
||||
rate = -1;
|
||||
changeRequested = false;
|
||||
}
|
||||
if (result.has("duration")) {
|
||||
duration = result.getInt("duration");
|
||||
//changeRequested as above
|
||||
} else {
|
||||
duration = -1;
|
||||
changeRequested = false;
|
||||
}
|
||||
if (result.has("units")) {
|
||||
changeRequested = true;
|
||||
smbValue = result.getDouble("units");
|
||||
} else {
|
||||
smbValue = 0.0;
|
||||
//changeRequested as above
|
||||
}
|
||||
if (result.has("deliverAt")) {
|
||||
String date = result.getString("deliverAt");
|
||||
try {
|
||||
deliverAt = DateUtil.fromISODateString(date).getTime();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public DetermineBasalResultSMB() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetermineBasalResultSMB clone() {
|
||||
DetermineBasalResultSMB newResult = new DetermineBasalResultSMB();
|
||||
newResult.reason = new String(reason);
|
||||
newResult.rate = rate;
|
||||
newResult.duration = duration;
|
||||
newResult.changeRequested = changeRequested;
|
||||
newResult.rate = rate;
|
||||
newResult.duration = duration;
|
||||
newResult.smbValue = smbValue;
|
||||
|
||||
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.date = startTime + i * 5 * 60 * 1000L;
|
||||
bg.isPrediction = true;
|
||||
array.add(bg);
|
||||
}
|
||||
}
|
||||
if (predBGs.has("aCOB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("aCOB");
|
||||
for (int i = 1; i < iob.length(); i++) {
|
||||
BgReading bg = new BgReading();
|
||||
bg.value = iob.getInt(i);
|
||||
bg.date = startTime + i * 5 * 60 * 1000L;
|
||||
bg.isPrediction = true;
|
||||
array.add(bg);
|
||||
}
|
||||
}
|
||||
if (predBGs.has("COB")) {
|
||||
JSONArray iob = predBGs.getJSONArray("COB");
|
||||
for (int i = 1; i < iob.length(); i++) {
|
||||
BgReading bg = new BgReading();
|
||||
bg.value = iob.getInt(i);
|
||||
bg.date = startTime + i * 5 * 60 * 1000L;
|
||||
bg.isPrediction = true;
|
||||
array.add(bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
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,150 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSSMB;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.crashlytics.android.answers.Answers;
|
||||
import com.crashlytics.android.answers.CustomEvent;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.utils.JSONFormatter;
|
||||
|
||||
public class OpenAPSSMBFragment extends SubscriberFragment implements View.OnClickListener {
|
||||
private static Logger log = LoggerFactory.getLogger(OpenAPSSMBFragment.class);
|
||||
|
||||
private static OpenAPSSMBPlugin openAPSSMBPlugin;
|
||||
|
||||
public static OpenAPSSMBPlugin getPlugin() {
|
||||
if (openAPSSMBPlugin == null) {
|
||||
openAPSSMBPlugin = new OpenAPSSMBPlugin();
|
||||
}
|
||||
return openAPSSMBPlugin;
|
||||
}
|
||||
|
||||
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");
|
||||
Answers.getInstance().logCustom(new CustomEvent("OpenAPS_AMA_Run"));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
|
||||
updateGUI();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventOpenAPSUpdateResultGui ev) {
|
||||
updateResultGUI(ev.text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateGUI() {
|
||||
Activity activity = getActivity();
|
||||
if (activity != null)
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DetermineBasalResultSMB lastAPSResult = getPlugin().lastAPSResult;
|
||||
if (lastAPSResult != null) {
|
||||
resultView.setText(JSONFormatter.format(lastAPSResult.json));
|
||||
requestView.setText(lastAPSResult.toSpanned());
|
||||
}
|
||||
DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS = getPlugin().lastDetermineBasalAdapterSMBJS;
|
||||
if (determineBasalAdapterSMBJS != null) {
|
||||
glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getGlucoseStatusParam()));
|
||||
currentTempView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getCurrentTempParam()));
|
||||
try {
|
||||
JSONArray iobArray = new JSONArray(determineBasalAdapterSMBJS.getIobDataParam());
|
||||
iobDataView.setText(String.format(MainApp.sResources.getString(R.string.array_of_elements), iobArray.length()) + "\n" + JSONFormatter.format(iobArray.getString(0)));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
iobDataView.setText("JSONException");
|
||||
}
|
||||
profileView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getProfileParam()));
|
||||
mealDataView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getMealDataParam()));
|
||||
scriptdebugView.setText(determineBasalAdapterSMBJS.getScriptDebug());
|
||||
}
|
||||
if (getPlugin().lastAPSRun != null) {
|
||||
lastRunView.setText(getPlugin().lastAPSRun.toLocaleString());
|
||||
}
|
||||
if (getPlugin().lastAutosensResult != null) {
|
||||
autosensDataView.setText(JSONFormatter.format(getPlugin().lastAutosensResult.json()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateResultGUI(final String text) {
|
||||
Activity activity = getActivity();
|
||||
if (activity != null)
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultView.setText(text);
|
||||
glucoseStatusView.setText("");
|
||||
currentTempView.setText("");
|
||||
iobDataView.setText("");
|
||||
profileView.setText("");
|
||||
mealDataView.setText("");
|
||||
autosensDataView.setText("");
|
||||
scriptdebugView.setText("");
|
||||
requestView.setText("");
|
||||
lastRunView.setText("");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
package info.nightscout.androidaps.plugins.OpenAPSSMB;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
|
||||
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSSMB.DetermineBasalResultSMB;
|
||||
import info.nightscout.androidaps.plugins.OpenAPSSMB.DetermineBasalAdapterSMBJS;
|
||||
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.utils.DateUtil;
|
||||
import info.nightscout.utils.NSUpload;
|
||||
import info.nightscout.utils.Profiler;
|
||||
import info.nightscout.utils.Round;
|
||||
import info.nightscout.utils.SP;
|
||||
import info.nightscout.utils.SafeParse;
|
||||
import info.nightscout.utils.ToastUtils;
|
||||
|
||||
/**
|
||||
* Created by mike on 05.08.2016.
|
||||
*/
|
||||
public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
|
||||
private static Logger log = LoggerFactory.getLogger(OpenAPSSMBPlugin.class);
|
||||
|
||||
// last values
|
||||
DetermineBasalAdapterSMBJS lastDetermineBasalAdapterSMBJS = null;
|
||||
Date lastAPSRun = null;
|
||||
DetermineBasalResultSMB lastAPSResult = null;
|
||||
AutosensResult lastAutosensResult = null;
|
||||
|
||||
boolean fragmentEnabled = false;
|
||||
boolean fragmentVisible = true;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return MainApp.instance().getString(R.string.openapssmb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameShort() {
|
||||
String name = MainApp.sResources.getString(R.string.smb_shortname);
|
||||
if (!name.trim().isEmpty()){
|
||||
//only if translation exists
|
||||
return name;
|
||||
}
|
||||
// use long name as fallback
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int type) {
|
||||
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 boolean hasFragment() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showInList(int type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragmentVisible(int type, boolean fragmentVisible) {
|
||||
if (type == APS) this.fragmentVisible = fragmentVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
|
||||
if (type == APS) this.fragmentEnabled = fragmentEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return PluginBase.APS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentClass() {
|
||||
return OpenAPSSMBFragment.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public APSResult getLastAPSResult() {
|
||||
return lastAPSResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastAPSRun() {
|
||||
return lastAPSRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String initiator) {
|
||||
log.debug("invoke from " + initiator);
|
||||
lastAPSResult = null;
|
||||
DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS = null;
|
||||
try {
|
||||
determineBasalAdapterSMBJS = new DetermineBasalAdapterSMBJS(new ScriptReader(MainApp.instance().getBaseContext()));
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
Profile profile = MainApp.getConfigBuilder().getProfile();
|
||||
PumpInterface pump = MainApp.getConfigBuilder();
|
||||
|
||||
if (profile == null) {
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.noprofileselected)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.noprofileselected));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEnabled(PluginBase.APS)) {
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_disabled)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_disabled));
|
||||
return;
|
||||
}
|
||||
|
||||
if (glucoseStatus == null) {
|
||||
MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.instance().getString(R.string.openapsma_noglucosedata)));
|
||||
if (Config.logAPSResult)
|
||||
log.debug(MainApp.instance().getString(R.string.openapsma_noglucosedata));
|
||||
return;
|
||||
}
|
||||
|
||||
String units = profile.getUnits();
|
||||
|
||||
double maxIob = SP.getDouble("openapsma_max_iob", 1.5d);
|
||||
double maxBasal = SP.getDouble("openapsma_max_basal", 1d);
|
||||
double minBg = Profile.toMgdl(profile.getTargetLow(), units);
|
||||
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
|
||||
double targetBg = (minBg + maxBg) / 2;
|
||||
|
||||
minBg = Round.roundTo(minBg, 0.1d);
|
||||
maxBg = Round.roundTo(maxBg, 0.1d);
|
||||
|
||||
Date start = new Date();
|
||||
Date startPart = new Date();
|
||||
IobTotal[] iobArray = IobCobCalculatorPlugin.calculateIobArrayInDia();
|
||||
Profiler.log(log, "calculateIobArrayInDia()", startPart);
|
||||
|
||||
startPart = new Date();
|
||||
MealData mealData = MainApp.getConfigBuilder().getMealData();
|
||||
Profiler.log(log, "getMealData()", startPart);
|
||||
|
||||
maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob);
|
||||
|
||||
minBg = verifyHardLimits(minBg, "minBg", Constants.VERY_HARD_LIMIT_MIN_BG[0], Constants.VERY_HARD_LIMIT_MIN_BG[1]);
|
||||
maxBg = verifyHardLimits(maxBg, "maxBg", Constants.VERY_HARD_LIMIT_MAX_BG[0], Constants.VERY_HARD_LIMIT_MAX_BG[1]);
|
||||
targetBg = verifyHardLimits(targetBg, "targetBg", Constants.VERY_HARD_LIMIT_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TARGET_BG[1]);
|
||||
|
||||
boolean isTempTarget = false;
|
||||
TempTarget tempTarget = MainApp.getConfigBuilder().getTempTargetFromHistory(System.currentTimeMillis());
|
||||
if (tempTarget != null) {
|
||||
isTempTarget = true;
|
||||
minBg = verifyHardLimits(tempTarget.low, "minBg", Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[1]);
|
||||
maxBg = verifyHardLimits(tempTarget.high, "maxBg", Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[1]);
|
||||
targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]);
|
||||
}
|
||||
|
||||
|
||||
maxIob = verifyHardLimits(maxIob, "maxIob", 0, 7);
|
||||
maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, 10);
|
||||
|
||||
if (!checkOnlyHardLimits(profile.getDia(), "dia", 2, 7)) return;
|
||||
if (!checkOnlyHardLimits(profile.getIc(profile.secondsFromMidnight()), "carbratio", 2, 100))
|
||||
return;
|
||||
if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf().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;
|
||||
|
||||
startPart = new Date();
|
||||
if (MainApp.getConfigBuilder().isAMAModeEnabled()) {
|
||||
lastAutosensResult = IobCobCalculatorPlugin.detectSensitivityWithLock(IobCobCalculatorPlugin.oldestDataAvailable(), System.currentTimeMillis());
|
||||
} else {
|
||||
lastAutosensResult = new AutosensResult();
|
||||
}
|
||||
Profiler.log(log, "detectSensitivityandCarbAbsorption()", startPart);
|
||||
Profiler.log(log, "AMA data gathering", start);
|
||||
|
||||
start = new Date();
|
||||
determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobArray, glucoseStatus, mealData,
|
||||
lastAutosensResult.ratio, //autosensDataRatio
|
||||
isTempTarget,
|
||||
true //microBolusAllowed
|
||||
);
|
||||
|
||||
|
||||
DetermineBasalResultSMB determineBasalResultSMB = determineBasalAdapterSMBJS.invoke();
|
||||
Profiler.log(log, "SMB calculation", start);
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress())
|
||||
determineBasalResultSMB.changeRequested = false;
|
||||
// limit requests on openloop mode
|
||||
if (!MainApp.getConfigBuilder().isClosedModeEnabled()) {
|
||||
if (MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultSMB.rate - MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()) < 0.1)
|
||||
determineBasalResultSMB.changeRequested = false;
|
||||
if (!MainApp.getConfigBuilder().isTempBasalInProgress() && Math.abs(determineBasalResultSMB.rate - MainApp.getConfigBuilder().getBaseBasalRate()) < 0.1)
|
||||
determineBasalResultSMB.changeRequested = false;
|
||||
}
|
||||
|
||||
determineBasalResultSMB.iob = iobArray[0];
|
||||
|
||||
determineBasalAdapterSMBJS.release();
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
try {
|
||||
determineBasalResultSMB.json.put("timestamp", DateUtil.toISOString(now));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
|
||||
lastAPSResult = determineBasalResultSMB;
|
||||
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) {
|
||||
Double newvalue = value;
|
||||
if (newvalue < lowLimit || newvalue > highLimit) {
|
||||
newvalue = Math.max(newvalue, lowLimit);
|
||||
newvalue = Math.min(newvalue, highLimit);
|
||||
String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), valueName);
|
||||
msg += ".\n";
|
||||
msg += String.format(MainApp.sResources.getString(R.string.openapsma_valuelimitedto), value, newvalue);
|
||||
log.error(msg);
|
||||
NSUpload.uploadError(msg);
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
|
||||
}
|
||||
return newvalue;
|
||||
}
|
||||
|
||||
}
|
|
@ -187,6 +187,8 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
|
|||
Iob bIOB = t.iobCalc(time, dia / SP.getDouble("openapsama_bolussnooze_dia_divisor", 2.0));
|
||||
total.bolussnooze += bIOB.iobContrib;
|
||||
} else {
|
||||
if (t.date > total.lastBolusTime)
|
||||
total.lastBolusTime = t.date;
|
||||
total.basaliob += t.insulin;
|
||||
total.microBolusIOB += tIOB.iobContrib;
|
||||
}
|
||||
|
@ -236,6 +238,7 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
|
|||
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData();
|
||||
if (autosensData != null) {
|
||||
result.mealCOB = autosensData.cob;
|
||||
result.minDeviationSlope = autosensData.minDeviationSlope;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -689,5 +689,13 @@
|
|||
<string name="careportal_pump_label">PUMP</string>
|
||||
<string name="overview_newtempbasal_basalabsolute">Basal value [U/h]</string>
|
||||
<string name="careportal_newnstreatment_duration_min_label">Duration [min]</string>
|
||||
<string name="openapssmb">OpenAPS SMB</string>
|
||||
<string name="smb_shortname">SMB</string>
|
||||
<string name="key_use_smb">use_smb</string>
|
||||
<string name="key_use_uam">use_uam</string>
|
||||
<string name="enableuam">Enable UAM</string>
|
||||
<string name="enablesmb">Enable SMB</string>
|
||||
<string name="enablesmb_summary">Use Super Micro Boluses instead of temp basal for faster action</string>
|
||||
<string name="enableuam_summary">Detection of Unannounced meals</string>
|
||||
</resources>
|
||||
|
||||
|
|
|
@ -4,125 +4,130 @@
|
|||
<PreferenceCategory
|
||||
android:key="advanced"
|
||||
android:title="@string/advancedsettings_title">
|
||||
<PreferenceScreen
|
||||
android:title="@string/advancedsettings_title">
|
||||
<PreferenceCategory
|
||||
android:title="@string/nightscout">
|
||||
<PreferenceScreen android:title="@string/advancedsettings_title">
|
||||
<PreferenceCategory android:title="@string/nightscout">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_ns_upload_only"
|
||||
android:title="@string/ns_upload_only"
|
||||
android:summary="@string/ns_upload_only_summary"/>
|
||||
android:summary="@string/ns_upload_only_summary"
|
||||
android:title="@string/ns_upload_only" />
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_ns_noupload"
|
||||
android:title="@string/ns_noupload"
|
||||
android:summary="@string/ns_noupload_summary"/>
|
||||
android:summary="@string/ns_noupload_summary"
|
||||
android:title="@string/ns_noupload" />
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="ns_sync_use_absolute"
|
||||
android:title="@string/ns_sync_use_absolute_title" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="@string/superbolus">
|
||||
<PreferenceCategory android:title="@string/superbolus">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_usesuperbolus"
|
||||
android:title="@string/enablesuperbolus"
|
||||
android:summary="@string/enablesuperbolus_summary"/>
|
||||
android:summary="@string/enablesuperbolus_summary"
|
||||
android:title="@string/enablesuperbolus" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="@string/openapsma">
|
||||
<PreferenceCategory android:title="@string/openapsma">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="always_use_shortavg"
|
||||
android:title="@string/always_use_shortavg"
|
||||
android:summary="@string/always_use_shortavg_summary"/>
|
||||
android:summary="@string/always_use_shortavg_summary"
|
||||
android:title="@string/always_use_shortavg" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="OpenAPS preferences.json">
|
||||
<Preference
|
||||
android:summary="@string/openapsama_link_to_preferncejson_doc_txt" >
|
||||
<PreferenceCategory android:title="@string/openapssmb">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_use_smb"
|
||||
android:summary="@string/enablesmb_summary"
|
||||
android:title="@string/enablesmb" />
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_use_uam"
|
||||
android:summary="@string/enableuam_summary"
|
||||
android:title="@string/enableuam" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="OpenAPS preferences.json">
|
||||
<Preference android:summary="@string/openapsama_link_to_preferncejson_doc_txt">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="@string/openapsama_link_to_preferncejson_doc" />
|
||||
</Preference>
|
||||
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||
validate:testType="numericRange"
|
||||
validate:minNumber="1"
|
||||
validate:maxNumber="10"
|
||||
android:digits="0123456789.,"
|
||||
android:defaultValue="3"
|
||||
android:selectAllOnFocus="true"
|
||||
android:inputType="number"
|
||||
android:maxLines="20"
|
||||
android:title="@string/openapsama_max_daily_safety_multiplier"
|
||||
android:dialogMessage="@string/openapsama_max_daily_safety_multiplier_summary"
|
||||
android:key="openapsama_max_daily_safety_multiplier" />
|
||||
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||
validate:testType="numericRange"
|
||||
validate:minNumber="1"
|
||||
validate:maxNumber="10"
|
||||
android:digits="0123456789.,"
|
||||
android:defaultValue="4"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:inputType="number"
|
||||
android:key="openapsama_max_daily_safety_multiplier"
|
||||
android:maxLines="20"
|
||||
android:title="@string/openapsama_current_basal_safety_multiplier"
|
||||
android:selectAllOnFocus="true"
|
||||
android:title="@string/openapsama_max_daily_safety_multiplier"
|
||||
validate:maxNumber="10"
|
||||
validate:minNumber="1"
|
||||
validate:testType="numericRange" />
|
||||
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||
android:defaultValue="4"
|
||||
android:dialogMessage="@string/openapsama_current_basal_safety_multiplier_summary"
|
||||
android:key="openapsama_current_basal_safety_multiplier" />
|
||||
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||
validate:testType="floatNumericRange"
|
||||
validate:floatminNumber="0.5"
|
||||
validate:floatmaxNumber="3"
|
||||
android:digits="0123456789.,"
|
||||
android:defaultValue="1.2"
|
||||
android:inputType="number"
|
||||
android:key="openapsama_current_basal_safety_multiplier"
|
||||
android:maxLines="20"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:inputType="numberDecimal"
|
||||
android:maxLines="20"
|
||||
android:title="@string/openapsama_autosens_max"
|
||||
android:dialogMessage="@string/openapsama_autosens_max_summary"
|
||||
android:key="openapsama_autosens_max" />
|
||||
android:title="@string/openapsama_current_basal_safety_multiplier"
|
||||
validate:maxNumber="10"
|
||||
validate:minNumber="1"
|
||||
validate:testType="numericRange" />
|
||||
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||
validate:testType="floatNumericRange"
|
||||
validate:floatminNumber="0.1"
|
||||
validate:floatmaxNumber="1.0"
|
||||
android:defaultValue="0.7"
|
||||
android:defaultValue="1.2"
|
||||
android:dialogMessage="@string/openapsama_autosens_max_summary"
|
||||
android:digits="0123456789.,"
|
||||
android:inputType="numberDecimal"
|
||||
android:key="openapsama_autosens_max"
|
||||
android:maxLines="20"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:inputType="numberDecimal"
|
||||
android:maxLines="20"
|
||||
android:title="@string/openapsama_autosens_min"
|
||||
android:title="@string/openapsama_autosens_max"
|
||||
validate:floatmaxNumber="3"
|
||||
validate:floatminNumber="0.5"
|
||||
validate:testType="floatNumericRange" />
|
||||
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||
android:defaultValue="0.7"
|
||||
android:dialogMessage="@string/openapsama_autosens_min_summary"
|
||||
android:key="openapsama_autosens_min" />
|
||||
android:inputType="numberDecimal"
|
||||
android:key="openapsama_autosens_min"
|
||||
android:maxLines="20"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:title="@string/openapsama_autosens_min"
|
||||
validate:floatmaxNumber="1.0"
|
||||
validate:floatminNumber="0.1"
|
||||
validate:testType="floatNumericRange" />
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="openapsama_autosens_adjusttargets"
|
||||
android:title="@string/openapsama_autosens_adjusttargets"
|
||||
android:summary="@string/openapsama_autosens_adjusttargets_summary"/>
|
||||
android:summary="@string/openapsama_autosens_adjusttargets_summary"
|
||||
android:title="@string/openapsama_autosens_adjusttargets" />
|
||||
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||
validate:testType="floatNumericRange"
|
||||
validate:minNumber="1"
|
||||
validate:maxNumber="10"
|
||||
android:digits="0123456789.,"
|
||||
android:defaultValue="2"
|
||||
android:dialogMessage="@string/openapsama_bolussnooze_dia_divisor_summary"
|
||||
android:digits="0123456789.,"
|
||||
android:inputType="numberDecimal"
|
||||
android:key="openapsama_bolussnooze_dia_divisor"
|
||||
android:maxLines="20"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:inputType="numberDecimal"
|
||||
android:maxLines="20"
|
||||
android:title="@string/openapsama_bolussnooze_dia_divisor"
|
||||
android:dialogMessage="@string/openapsama_bolussnooze_dia_divisor_summary"
|
||||
android:key="openapsama_bolussnooze_dia_divisor" />
|
||||
validate:maxNumber="10"
|
||||
validate:minNumber="1"
|
||||
validate:testType="floatNumericRange" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="@string/profile">
|
||||
<PreferenceCategory android:title="@string/profile">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_do_not_track_profile_switch"
|
||||
android:title="@string/do_not_track_profile_switch"
|
||||
android:summary="@string/do_not_track_profile_switch_summary"/>
|
||||
android:summary="@string/do_not_track_profile_switch_summary"
|
||||
android:title="@string/do_not_track_profile_switch" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
</PreferenceCategory>
|
||||
|
|
Loading…
Reference in a new issue