Merge remote-tracking branch 'origin/dev' into combo-scripter-v2

This commit is contained in:
Johannes Mockenhaupt 2018-01-25 02:48:08 +01:00
commit c469edb5a3
No known key found for this signature in database
GPG key ID: 9E1EA6AF7BBBB0D1
8 changed files with 354 additions and 275 deletions

View file

@ -15,20 +15,22 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.events.EventNSProfileUpdateGUI;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync; import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS; import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin;
@ -37,7 +39,6 @@ import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin; import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin;
import info.nightscout.androidaps.receivers.DataReceiver; import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
import info.nightscout.utils.BundleLogger; import info.nightscout.utils.BundleLogger;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -365,8 +366,10 @@ public class DataService extends IntentService {
String profile = bundles.getString("profile"); String profile = bundles.getString("profile");
ProfileStore profileStore = new ProfileStore(new JSONObject(profile)); ProfileStore profileStore = new ProfileStore(new JSONObject(profile));
NSProfilePlugin.storeNewProfile(profileStore); NSProfilePlugin.storeNewProfile(profileStore);
MainApp.bus().post(new EventNewBasalProfile()); MainApp.bus().post(new EventNSProfileUpdateGUI());
// if there are no profile switches this should lead to profile update
if (MainApp.getConfigBuilder().getProfileSwitchesFromHistory().size() == 0)
MainApp.bus().post(new EventNewBasalProfile());
if (Config.logIncommingData) if (Config.logIncommingData)
log.debug("Received profileStore: " + activeProfile + " " + profile); log.debug("Received profileStore: " + activeProfile + " " + profile);
} catch (JSONException e) { } catch (JSONException e) {

View file

@ -0,0 +1,8 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 23.01.2018.
*/
public class EventAppInitialized extends Event {
}

View file

@ -28,6 +28,7 @@ import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.BgSourceInterface; import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
@ -144,6 +145,7 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
public void initialize() { public void initialize() {
pluginList = MainApp.getPluginsList(); pluginList = MainApp.getPluginsList();
loadSettings(); loadSettings();
MainApp.bus().post(new EventAppInitialized());
} }
public void storeSettings() { public void storeSettings() {

View file

@ -1,8 +1,6 @@
package info.nightscout.androidaps.plugins.IobCobCalculator; package info.nightscout.androidaps.plugins.IobCobCalculator;
import android.os.Handler; import android.os.SystemClock;
import android.os.HandlerThread;
import android.os.Process;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
@ -24,14 +22,13 @@ import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventConfigBuilderChange;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
@ -51,10 +48,10 @@ public class IobCobCalculatorPlugin implements PluginBase {
private static double dia = Constants.defaultDIA; private static double dia = Constants.defaultDIA;
private static Handler sHandler = null; static final Object dataLock = new Object();
private static HandlerThread sHandlerThread = null;
private static final Object dataLock = new Object(); boolean stopCalculationTrigger = false;
IobCobThread thread = null;
private static IobCobCalculatorPlugin plugin = null; private static IobCobCalculatorPlugin plugin = null;
@ -134,12 +131,6 @@ public class IobCobCalculatorPlugin implements PluginBase {
IobCobCalculatorPlugin() { IobCobCalculatorPlugin() {
MainApp.bus().register(this); MainApp.bus().register(this);
if (sHandlerThread == null) {
sHandlerThread = new HandlerThread(IobCobCalculatorPlugin.class.getSimpleName(), Process.THREAD_PRIORITY_LOWEST);
sHandlerThread.start();
sHandler = new Handler(sHandlerThread.getLooper());
}
onNewBg(new EventNewBG());
} }
@Nullable @Nullable
@ -176,14 +167,9 @@ public class IobCobCalculatorPlugin implements PluginBase {
return rouded; return rouded;
} }
private void loadBgData() { void loadBgData() {
//log.debug("Locking loadBgData"); bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)), false);
synchronized (dataLock) { log.debug("BG data loaded. Size: " + bgReadings.size());
onNewProfile(null);
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)), false);
log.debug("BG data loaded. Size: " + bgReadings.size());
}
//log.debug("Releasing loadBgData");
} }
private boolean isAbout5minData() { private boolean isAbout5minData() {
@ -210,7 +196,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
} }
private void createBucketedData() { void createBucketedData() {
if (isAbout5minData()) if (isAbout5minData())
createBucketedData5min(); createBucketedData5min();
else else
@ -242,223 +228,97 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
private void createBucketedDataRecalculated() { private void createBucketedDataRecalculated() {
synchronized (dataLock) { if (bgReadings == null || bgReadings.size() < 3) {
if (bgReadings == null || bgReadings.size() < 3) { bucketed_data = null;
bucketed_data = null; return;
return; }
}
bucketed_data = new ArrayList<>(); bucketed_data = new ArrayList<>();
long currentTime = bgReadings.get(0).date + 5 * 60 * 1000 - bgReadings.get(0).date % (5 * 60 * 1000) - 5 * 60 * 1000L; 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()); //log.debug("First reading: " + new Date(currentTime).toLocaleString());
while (true) { while (true) {
// test if current value is older than current time // test if current value is older than current time
BgReading newer = findNewer(currentTime); BgReading newer = findNewer(currentTime);
BgReading older = findOlder(currentTime); BgReading older = findOlder(currentTime);
if (newer == null || older == null) if (newer == null || older == null)
break; break;
double bgDelta = newer.value - older.value; double bgDelta = newer.value - older.value;
long timeDiffToNew = newer.date - currentTime; long timeDiffToNew = newer.date - currentTime;
double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta; double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta;
BgReading newBgreading = new BgReading(); BgReading newBgreading = new BgReading();
newBgreading.date = currentTime; newBgreading.date = currentTime;
newBgreading.value = Math.round(currentBg); newBgreading.value = Math.round(currentBg);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")"); //log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
currentTime -= 5 * 60 * 1000L; currentTime -= 5 * 60 * 1000L;
}
} }
} }
public void createBucketedData5min() { public void createBucketedData5min() {
//log.debug("Locking createBucketedData"); if (bgReadings == null || bgReadings.size() < 3) {
synchronized (dataLock) { bucketed_data = null;
if (bgReadings == null || bgReadings.size() < 3) { return;
bucketed_data = null; }
return;
bucketed_data = new ArrayList<>();
bucketed_data.add(bgReadings.get(0));
int j = 0;
for (int i = 1; i < bgReadings.size(); ++i) {
long bgTime = bgReadings.get(i).date;
long lastbgTime = bgReadings.get(i - 1).date;
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
continue;
} }
bucketed_data = new ArrayList<>(); long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
bucketed_data.add(bgReadings.get(0)); if (Math.abs(elapsed_minutes) > 8) {
int j = 0; // interpolate missing data points
for (int i = 1; i < bgReadings.size(); ++i) { double lastbg = bgReadings.get(i - 1).value;
long bgTime = bgReadings.get(i).date; elapsed_minutes = Math.abs(elapsed_minutes);
long lastbgTime = bgReadings.get(i - 1).date; //console.error(elapsed_minutes);
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value); long nextbgTime;
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) { while (elapsed_minutes > 5) {
continue; nextbgTime = lastbgTime - 5 * 60 * 1000;
}
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
if (Math.abs(elapsed_minutes) > 8) {
// interpolate missing data points
double lastbg = bgReadings.get(i - 1).value;
elapsed_minutes = Math.abs(elapsed_minutes);
//console.error(elapsed_minutes);
long nextbgTime;
while (elapsed_minutes > 5) {
nextbgTime = lastbgTime - 5 * 60 * 1000;
j++;
BgReading newBgreading = new BgReading();
newBgreading.date = nextbgTime;
double gapDelta = bgReadings.get(i).value - lastbg;
//console.error(gapDelta, lastbg, elapsed_minutes);
double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
newBgreading.value = Math.round(nextbg);
//console.error("Interpolated", bucketed_data[j]);
bucketed_data.add(newBgreading);
//log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
elapsed_minutes = elapsed_minutes - 5;
lastbg = nextbg;
lastbgTime = nextbgTime;
}
j++; j++;
BgReading newBgreading = new BgReading(); BgReading newBgreading = new BgReading();
newBgreading.value = bgReadings.get(i).value; newBgreading.date = nextbgTime;
newBgreading.date = bgTime; double gapDelta = bgReadings.get(i).value - lastbg;
//console.error(gapDelta, lastbg, elapsed_minutes);
double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
newBgreading.value = Math.round(nextbg);
//console.error("Interpolated", bucketed_data[j]);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value); //log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
} else if (Math.abs(elapsed_minutes) > 2) {
j++; elapsed_minutes = elapsed_minutes - 5;
BgReading newBgreading = new BgReading(); lastbg = nextbg;
newBgreading.value = bgReadings.get(i).value; lastbgTime = nextbgTime;
newBgreading.date = bgTime;
bucketed_data.add(newBgreading);
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
} else {
bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2;
//log.error("***** Average");
} }
} j++;
log.debug("Bucketed data created. Size: " + bucketed_data.size()); BgReading newBgreading = new BgReading();
} newBgreading.value = bgReadings.get(i).value;
//log.debug("Releasing createBucketedData"); newBgreading.date = bgTime;
} bucketed_data.add(newBgreading);
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
private void calculateSensitivityData() { } else if (Math.abs(elapsed_minutes) > 2) {
if (MainApp.getConfigBuilder() == null) j++;
return; // app still initializing BgReading newBgreading = new BgReading();
if (MainApp.getConfigBuilder().getProfile() == null) newBgreading.value = bgReadings.get(i).value;
return; // app still initializing newBgreading.date = bgTime;
//log.debug("Locking calculateSensitivityData"); bucketed_data.add(newBgreading);
long oldestTimeWithData = oldestDataAvailable(); //log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value);
} else {
synchronized (dataLock) { bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2;
//log.error("***** Average");
if (bucketed_data == null || bucketed_data.size() < 3) {
log.debug("calculateSensitivityData: No bucketed data available");
return;
}
long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
AutosensData previous = autosensDataTable.get(prevDataTime);
// start from oldest to be able sub cob
for (int i = bucketed_data.size() - 4; i >= 0; i--) {
// check if data already exists
long bgTime = bucketed_data.get(i).date;
bgTime = roundUpTime(bgTime);
if (bgTime > System.currentTimeMillis())
continue;
Profile profile = MainApp.getConfigBuilder().getProfile(bgTime);
AutosensData existing;
if ((existing = autosensDataTable.get(bgTime)) != null) {
previous = existing;
continue;
}
if (profile.getIsf(bgTime) == null)
return; // profile not set yet
double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits());
AutosensData autosensData = new AutosensData();
autosensData.time = bgTime;
if (previous != null)
autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList);
else
autosensData.activeCarbsList = new ArrayList<>();
//console.error(bgTime , bucketed_data[i].glucose);
double bg;
double avgDelta;
double delta;
bg = bucketed_data.get(i).value;
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
log.error("! value < 39");
continue;
}
delta = (bg - bucketed_data.get(i + 1).value);
IobTotal iob = calculateFromTreatmentsAndTemps(bgTime);
double bgi = -iob.activity * sens * 5;
double deviation = delta - bgi;
List<Treatment> recentTreatments = MainApp.getConfigBuilder().getTreatments5MinBackFromHistory(bgTime);
for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
}
// if we are absorbing carbs
if (previous != null && previous.cob > 0) {
// calculate sum of min carb impact from all active treatments
double totalMinCarbsImpact = 0d;
for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
totalMinCarbsImpact += c.min5minCarbImpact;
}
// figure out how many carbs that represents
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
double ci = Math.max(deviation, totalMinCarbsImpact);
autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
// and add that to the running total carbsAbsorbed
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
autosensData.substractAbosorbedCarbs();
}
autosensData.removeOldCarbs(bgTime);
autosensData.cob += autosensData.carbsFromBolus;
autosensData.deviation = deviation;
autosensData.bgi = bgi;
autosensData.delta = delta;
// calculate autosens only without COB
if (autosensData.cob <= 0) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity += "=";
autosensData.nonEqualDeviation = true;
} else if (deviation > 0) {
autosensData.pastSensitivity += "+";
autosensData.nonEqualDeviation = true;
} else {
autosensData.pastSensitivity += "-";
autosensData.nonEqualDeviation = true;
}
autosensData.nonCarbsDeviation = true;
} else {
autosensData.pastSensitivity += "C";
}
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
previous = autosensData;
autosensDataTable.put(bgTime, autosensData);
autosensData.autosensRatio = detectSensitivity(oldestTimeWithData, bgTime).ratio;
if (Config.logAutosensData)
log.debug(autosensData.log(bgTime));
} }
} }
MainApp.bus().post(new EventAutosensCalculationFinished()); log.debug("Bucketed data created. Size: " + bucketed_data.size());
//log.debug("Releasing calculateSensitivityData");
} }
public static long oldestDataAvailable() { public static long oldestDataAvailable() {
@ -613,7 +473,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
} }
private static AutosensResult detectSensitivity(long fromTime, long toTime) { static AutosensResult detectSensitivity(long fromTime, long toTime) {
return ConfigBuilderPlugin.getActiveSensitivity().detectSensitivity(fromTime, toTime); return ConfigBuilderPlugin.getActiveSensitivity().detectSensitivity(fromTime, toTime);
} }
@ -626,15 +486,33 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
@Subscribe @Subscribe
public void onNewBg(EventNewBG ev) { public void onEventAppInitialized(EventAppInitialized ev) {
sHandler.post(new Runnable() { runCalculation("onEventAppInitialized", true);
@Override }
public void run() {
loadBgData(); @Subscribe
createBucketedData(); public void onEventNewBG(EventNewBG ev) {
calculateSensitivityData(); stopCalculation("onEventNewBG");
runCalculation("onEventNewBG", true);
}
private void stopCalculation(String from) {
if (thread != null && thread.getState() != Thread.State.TERMINATED) {
stopCalculationTrigger = true;
log.debug("Stopping calculation thread: " + from);
while (thread.getState() != Thread.State.TERMINATED) {
SystemClock.sleep(100);
} }
}); log.debug("Calculation thread stopped: " + from);
}
}
private void runCalculation(String from, boolean bgDataReload) {
log.debug("Starting calculation thread: " + from);
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new IobCobThread(this, from, bgDataReload);
thread.start();
}
} }
@Subscribe @Subscribe
@ -648,66 +526,55 @@ public class IobCobCalculatorPlugin implements PluginBase {
if (ev == null) { // on init no need of reset if (ev == null) { // on init no need of reset
return; return;
} }
stopCalculation("onNewProfile");
synchronized (dataLock) { synchronized (dataLock) {
log.debug("Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); log.debug("Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
sHandler.post(new Runnable() { runCalculation("onNewProfile", false);
@Override
public void run() {
calculateSensitivityData();
}
});
} }
@Subscribe @Subscribe
public void onStatusEvent(EventPreferenceChange ev) { public void onEventPreferenceChange(EventPreferenceChange ev) {
if (ev.isChanged(R.string.key_openapsama_autosens_period) || if (ev.isChanged(R.string.key_openapsama_autosens_period) ||
ev.isChanged(R.string.key_age) || ev.isChanged(R.string.key_age) ||
ev.isChanged(R.string.key_absorption_maxtime) ev.isChanged(R.string.key_absorption_maxtime)
) { ) {
stopCalculation("onEventPreferenceChange");
synchronized (dataLock) { synchronized (dataLock) {
log.debug("Invalidating cached data because of preference change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); log.debug("Invalidating cached data because of preference change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
sHandler.post(new Runnable() { runCalculation("onEventPreferenceChange", false);
@Override
public void run() {
calculateSensitivityData();
}
});
} }
} }
@Subscribe @Subscribe
public void onStatusEvent(EventConfigBuilderChange ev) { public void onEventConfigBuilderChange(EventConfigBuilderChange ev) {
stopCalculation("onEventConfigBuilderChange");
synchronized (dataLock) { synchronized (dataLock) {
log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
sHandler.post(new Runnable() { runCalculation("onEventConfigBuilderChange", false);
@Override
public void run() {
calculateSensitivityData();
}
});
} }
// When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated // When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
@Subscribe @Subscribe
public void onNewHistoryData(EventNewHistoryData ev) { public void onEventNewHistoryData(EventNewHistoryData ev) {
//log.debug("Locking onNewHistoryData"); //log.debug("Locking onNewHistoryData");
stopCalculation("onEventNewHistoryData");
synchronized (dataLock) { synchronized (dataLock) {
long time = ev.time; // clear up 5 min back for proper COB calculation
long time = ev.time - 5 * 60 * 1000L;
log.debug("Invalidating cached data to: " + new Date(time).toLocaleString()); log.debug("Invalidating cached data to: " + new Date(time).toLocaleString());
for (int index = iobTable.size() - 1; index >= 0; index--) { for (int index = iobTable.size() - 1; index >= 0; index--) {
if (iobTable.keyAt(index) > time) { if (iobTable.keyAt(index) > time) {
if (Config.logAutosensData) if (Config.logAutosensData)
if (Config.logAutosensData) log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
iobTable.removeAt(index); iobTable.removeAt(index);
} else { } else {
break; break;
@ -732,12 +599,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
} }
} }
} }
sHandler.post(new Runnable() { runCalculation("onEventNewHistoryData", false);
@Override
public void run() {
calculateSensitivityData();
}
});
//log.debug("Releasing onNewHistoryData"); //log.debug("Releasing onNewHistoryData");
} }

View file

@ -0,0 +1,201 @@
package info.nightscout.androidaps.plugins.IobCobCalculator;
import android.content.Context;
import android.os.PowerManager;
import android.support.v4.util.LongSparseArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.queue.QueueThread;
import static info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin.getBucketedData;
import static info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin.oldestDataAvailable;
import static info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin.roundUpTime;
/**
* Created by mike on 23.01.2018.
*/
public class IobCobThread extends Thread {
private static Logger log = LoggerFactory.getLogger(QueueThread.class);
private IobCobCalculatorPlugin iobCobCalculatorPlugin;
private boolean bgDataReload;
private String from;
private PowerManager.WakeLock mWakeLock;
public IobCobThread(IobCobCalculatorPlugin plugin, String from, boolean bgDataReload) {
super();
this.iobCobCalculatorPlugin = plugin;
this.bgDataReload = bgDataReload;
this.from = from;
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread");
}
@Override
public final void run() {
mWakeLock.acquire();
try {
if (MainApp.getConfigBuilder() == null) {
log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from);
return; // app still initializing
}
if (MainApp.getConfigBuilder().getProfile() == null) {
log.debug("Aborting calculation thread (No profile): " + from);
return; // app still initializing
}
//log.debug("Locking calculateSensitivityData");
Object dataLock = iobCobCalculatorPlugin.dataLock;
long oldestTimeWithData = oldestDataAvailable();
synchronized (dataLock) {
if (bgDataReload) {
iobCobCalculatorPlugin.loadBgData();
iobCobCalculatorPlugin.createBucketedData();
}
List<BgReading> bucketed_data = getBucketedData();
LongSparseArray<AutosensData> autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
if (bucketed_data == null || bucketed_data.size() < 3) {
log.debug("Aborting calculation thread (No bucketed data available): " + from);
return;
}
long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
AutosensData previous = autosensDataTable.get(prevDataTime);
// start from oldest to be able sub cob
for (int i = bucketed_data.size() - 4; i >= 0; i--) {
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
iobCobCalculatorPlugin.stopCalculationTrigger = false;
log.debug("Aborting calculation thread (trigger): " + from);
return;
}
// check if data already exists
long bgTime = bucketed_data.get(i).date;
bgTime = roundUpTime(bgTime);
if (bgTime > System.currentTimeMillis())
continue;
Profile profile = MainApp.getConfigBuilder().getProfile(bgTime);
AutosensData existing;
if ((existing = autosensDataTable.get(bgTime)) != null) {
previous = existing;
continue;
}
if (profile.getIsf(bgTime) == null) {
log.debug("Aborting calculation thread (no ISF): " + from);
return; // profile not set yet
}
if (Config.logAutosensData)
log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits());
AutosensData autosensData = new AutosensData();
autosensData.time = bgTime;
if (previous != null)
autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList);
else
autosensData.activeCarbsList = new ArrayList<>();
//console.error(bgTime , bucketed_data[i].glucose);
double bg;
double avgDelta;
double delta;
bg = bucketed_data.get(i).value;
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
log.error("! value < 39");
continue;
}
delta = (bg - bucketed_data.get(i + 1).value);
IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime);
double bgi = -iob.activity * sens * 5;
double deviation = delta - bgi;
List<Treatment> recentTreatments = MainApp.getConfigBuilder().getTreatments5MinBackFromHistory(bgTime);
for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
}
// if we are absorbing carbs
if (previous != null && previous.cob > 0) {
// calculate sum of min carb impact from all active treatments
double totalMinCarbsImpact = 0d;
for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
totalMinCarbsImpact += c.min5minCarbImpact;
}
// figure out how many carbs that represents
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
double ci = Math.max(deviation, totalMinCarbsImpact);
autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
// and add that to the running total carbsAbsorbed
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
autosensData.substractAbosorbedCarbs();
}
autosensData.removeOldCarbs(bgTime);
autosensData.cob += autosensData.carbsFromBolus;
autosensData.deviation = deviation;
autosensData.bgi = bgi;
autosensData.delta = delta;
// calculate autosens only without COB
if (autosensData.cob <= 0) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity += "=";
autosensData.nonEqualDeviation = true;
} else if (deviation > 0) {
autosensData.pastSensitivity += "+";
autosensData.nonEqualDeviation = true;
} else {
autosensData.pastSensitivity += "-";
autosensData.nonEqualDeviation = true;
}
autosensData.nonCarbsDeviation = true;
} else {
autosensData.pastSensitivity += "C";
}
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
previous = autosensData;
autosensDataTable.put(bgTime, autosensData);
autosensData.autosensRatio = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime).ratio;
if (Config.logAutosensData)
log.debug(autosensData.log(bgTime));
}
}
MainApp.bus().post(new EventAutosensCalculationFinished());
log.debug("Finishing calculation thread: " + from);
} finally {
mWakeLock.release();
}
}
}

View file

@ -11,6 +11,7 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
@ -191,8 +192,10 @@ public class SensitivityAAPSPlugin implements PluginBase, SensitivityInterface{
log.debug(ratioLimit); log.debug(ratioLimit);
} }
log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " percentile: " + percentile + " ratio: " + ratio); if (Config.logAutosensData) {
log.debug("Sensitivity to: deviations " + Arrays.toString(deviations)); log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " percentile: " + percentile + " ratio: " + ratio + " mealCOB: " + current.cob);
log.debug("Sensitivity to: deviations " + Arrays.toString(deviations));
}
AutosensResult output = new AutosensResult(); AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01); output.ratio = Round.roundTo(ratio, 0.01);

View file

@ -7,8 +7,10 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
@ -118,7 +120,7 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
return new AutosensResult(); return new AutosensResult();
} }
AutosensData current = IobCobCalculatorPlugin.getLastAutosensData("SensitivityOref0"); // this is running inside lock already AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
if (current == null) { if (current == null) {
log.debug("No current autosens data available"); log.debug("No current autosens data available");
return new AutosensResult(); return new AutosensResult();
@ -199,10 +201,8 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
log.debug(ratioLimit); log.debug(ratioLimit);
} }
double newisf = Math.round(Profile.toMgdl(sens, profile.getUnits()) / ratio); if (Config.logAutosensData)
if (ratio != 1) { log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " ratio: " + ratio + " mealCOB: " + current.cob);
log.debug("ISF adjusted from " + Profile.toMgdl(sens, profile.getUnits()) + " to " + newisf);
}
AutosensResult output = new AutosensResult(); AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01); output.ratio = Round.roundTo(ratio, 0.01);

View file

@ -217,7 +217,7 @@ public class SensitivityWeightedAveragePlugin implements PluginBase, Sensitivity
} }
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " weightedaverage: " + average + " ratio: " + ratio); log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " weightedaverage: " + average + " ratio: " + ratio + " mealCOB: " + current.cob);
AutosensResult output = new AutosensResult(); AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01); output.ratio = Round.roundTo(ratio, 0.01);