diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5d19981032..fbb68289f4 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -37,7 +37,7 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 797ac55410..0ec3e3453f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -32,4 +32,5 @@ dependencies {
compile 'com.github.tony19:logback-android-classic:1.1.1-4'
compile 'org.slf4j:slf4j-api:1.7.12'
compile 'com.jjoe64:graphview:4.0.1'
+ compile 'com.eclipsesource.j2v8:j2v8:3.1.6@aar'
}
diff --git a/app/src/main/assets/OpenAPSMA/determine-basal.js b/app/src/main/assets/OpenAPSMA/determine-basal.js
new file mode 100644
index 0000000000..1492caf3de
--- /dev/null
+++ b/app/src/main/assets/OpenAPSMA/determine-basal.js
@@ -0,0 +1,316 @@
+/*
+ Determine Basal
+
+ Released under MIT license. See the accompanying LICENSE.txt file for
+ full terms and conditions
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, offline, meal_data, setTempBasal) {
+ var rT = { //short for requestedTemp
+ };
+
+ if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
+ rT.error ='Error: could not get current basal rate';
+ return rT;
+ }
+
+ var bg = glucose_status.glucose;
+ if (bg < 30) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose
+ rT.error = "CGM is calibrating or in ??? state";
+ return rT;
+ }
+
+ var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver
+
+ // if target_bg is set, great. otherwise, if min and max are set, then set target to their average
+ var target_bg;
+ if (typeof profile.target_bg !== 'undefined') {
+ target_bg = profile.target_bg;
+ } else {
+ if (typeof profile.min_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') {
+ target_bg = (profile.min_bg + profile.max_bg) / 2;
+ } else {
+ rT.error ='Error: could not determine target_bg';
+ return rT;
+ }
+ }
+
+
+ if (typeof iob_data === 'undefined' ) {
+ rT.error ='Error: iob_data undefined';
+ return rT;
+ }
+
+ if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' || typeof iob_data.activity === 'undefined') {
+ rT.error ='Error: iob_data missing some property';
+ return rT;
+ }
+
+ var tick;
+
+ if (glucose_status.delta >= 0) {
+ tick = "+" + glucose_status.delta;
+ } else {
+ tick = glucose_status.delta;
+ }
+ var minDelta = Math.min(glucose_status.delta, glucose_status.avgdelta);
+ //var maxDelta = Math.max(glucose_status.delta, glucose_status.avgdelta);
+
+
+ //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone
+ var bgi = Math.round(( -iob_data.activity * profile.sens * 5 )*100)/100;
+ // project positive deviations for 15 minutes
+ var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) );
+ // project negative deviations for 30 minutes
+ if (deviation < 0) {
+ deviation = Math.round( 30 / 5 * ( glucose_status.avgdelta - bgi ) );
+ }
+ //console.log("Avg.Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1) + " 15m activity projection: " + deviation.toFixed(0));
+
+ // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity
+ var naive_eventualBG = Math.round( bg - (iob_data.iob * profile.sens) );
+ // and adjust it for the deviation above
+ var eventualBG = naive_eventualBG + deviation;
+ // calculate what portion of that is due to bolussnooze
+ var bolusContrib = iob_data.bolussnooze * profile.sens;
+ // and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime
+ var naive_snoozeBG = Math.round( naive_eventualBG + 1.5 * bolusContrib );
+ // adjust that for deviation like we did eventualBG
+ var snoozeBG = naive_snoozeBG + deviation;
+
+ //console.log("BG: " + bg +"(" + tick + ","+glucose_status.avgdelta.toFixed(1)+")"+ " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + "), BGI: " + bgi);
+
+ var expectedDelta = Math.round(( bgi + ( target_bg - eventualBG ) / ( profile.dia * 60 / 5 ) )*10)/10;
+ //console.log("expectedDelta: " + expectedDelta);
+
+ if (typeof eventualBG === 'undefined' || isNaN(eventualBG)) {
+ rT.error ='Error: could not calculate eventualBG';
+ return rT;
+ }
+
+ // min_bg of 90 -> threshold of 70, 110 -> 80, and 130 -> 90
+ var threshold = profile.min_bg - 0.5*(profile.min_bg-50);
+
+ rT = {
+ 'temp': 'absolute'
+ , 'bg': bg
+ , 'tick': tick
+ , 'eventualBG': eventualBG
+ , 'snoozeBG': snoozeBG
+ };
+
+ var basaliob;
+ if (iob_data.basaliob) { basaliob = iob_data.basaliob; }
+ else { basaliob = iob_data.iob - iob_data.bolussnooze; }
+ // allow meal assist to run when carbs are just barely covered
+ if (minDelta > Math.max(3, bgi) && ( (meal_data.carbs > 0 && (1.1 * meal_data.carbs/profile.carb_ratio > meal_data.boluses + basaliob)) || ( deviation > 25 && minDelta > 7 ) ) ) {
+ // ignore all covered IOB, and just set eventualBG to the current bg
+ eventualBG = Math.max(bg,eventualBG) + deviation;
+ rT.eventualBG = eventualBG;
+ profile.min_bg = 80;
+ target_bg = (profile.min_bg + profile.max_bg) / 2;
+ expectedDelta = Math.round(( bgi + ( target_bg - eventualBG ) / ( profile.dia * 60 / 5 ) )*10)/10;
+ rT.mealAssist = "On: Carbs: " + meal_data.carbs + " Boluses: " + meal_data.boluses + " Target: " + target_bg + " Deviation: " + deviation + " BGI: " + bgi;
+ } else {
+ rT.mealAssist = "Off: Carbs: " + meal_data.carbs + " Boluses: " + meal_data.boluses + " Target: " + target_bg + " Deviation: " + deviation + " BGI: " + bgi;
+ }
+ if (bg < threshold) { // low glucose suspend mode: BG is < ~80
+ rT.reason = "BG " + bg + "<" + threshold;
+ if ((glucose_status.delta <= 0 && glucose_status.avgdelta <= 0) || (glucose_status.delta < expectedDelta && glucose_status.avgdelta < expectedDelta)) {
+ // BG is still falling / rising slower than predicted
+ return setTempBasal(0, 30, profile, rT, offline);
+ }
+ if (glucose_status.delta > glucose_status.avgdelta) {
+ rT.reason += ", delta " + glucose_status.delta + ">0";
+ } else {
+ rT.reason += ", avg delta " + glucose_status.avgdelta.toFixed(2) + ">0";
+ }
+ if (currenttemp.rate > profile.current_basal) { // if a high-temp is running
+ rT.reason += ", cancel high temp";
+ return setTempBasal(0, 0, profile, rT, offline); // cancel high temp
+ } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB
+ rT.reason += ", cancel low temp";
+ return setTempBasal(0, 0, profile, rT, offline); // cancel low temp
+ }
+ rT.reason += "; no high-temp to cancel";
+ return rT;
+ }
+ if (eventualBG < profile.min_bg) { // if eventual BG is below target:
+ if (rT.mealAssist.indexOf("On") == 0) {
+ rT.reason = "Meal assist: " + meal_data.carbs + "g, " + meal_data.boluses + "U";
+ } else {
+ rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg;
+ // if 5m or 15m avg BG is rising faster than expected delta
+ if (minDelta > expectedDelta && minDelta > 0) {
+ if (glucose_status.delta > glucose_status.avgdelta) {
+ rT.reason += ", but Delta " + tick + " > Exp. Delta " + expectedDelta;
+ } else {
+ rT.reason += ", but Avg. Delta " + glucose_status.avgdelta.toFixed(2) + " > Exp. Delta " + expectedDelta;
+ }
+ if (currenttemp.duration > 0) { // if there is currently any temp basal running
+ rT.reason = rT.reason += "; cancel";
+ return setTempBasal(0, 0, profile, rT, offline); // cancel temp
+ } else {
+ rT.reason = rT.reason += "; no temp to cancel";
+ return rT;
+ }
+ }
+ }
+
+ if (eventualBG < profile.min_bg) {
+ // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed)
+ if (snoozeBG > profile.min_bg) { // if adding back in the bolus contribution BG would be above min
+ // if BG is falling and high-temped, or rising and low-temped, cancel
+ // compare against zero here, not BGI, because BGI will be highly negative from boluses and no carbs
+ if (glucose_status.delta < 0 && currenttemp.duration > 0 && currenttemp.rate > profile.current_basal) {
+ rT.reason += tick + ", and temp " + currenttemp.rate + " > basal " + profile.current_basal;
+ return setTempBasal(0, 0, profile, rT, offline); // cancel temp
+ } else if (glucose_status.delta > 0 && currenttemp.duration > 0 && currenttemp.rate < profile.current_basal) {
+ rT.reason += tick + ", and temp " + currenttemp.rate + " < basal " + profile.current_basal;
+ return setTempBasal(0, 0, profile, rT, offline); // cancel temp
+ }
+
+ rT.reason += ", bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG;
+ return rT;
+ } else {
+ // calculate 30m low-temp required to get projected BG up to target
+ // use snoozeBG to more gradually ramp in any counteraction of the user's boluses
+ // multiply by 2 to low-temp faster for increased hypo safety
+ var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / profile.sens);
+ if (minDelta < 0 && minDelta > expectedDelta) {
+ // if we're barely falling, newinsulinReq should be barely negative
+ rT.reason += ", Snooze BG " + snoozeBG;
+ var newinsulinReq = Math.round(( insulinReq * (minDelta / expectedDelta) ) * 100)/100;
+ //console.log("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
+ insulinReq = newinsulinReq;
+ }
+ // rate required to deliver insulinReq less insulin over 30m:
+ var rate = profile.current_basal + (2 * insulinReq);
+ rate = Math.round( rate * 1000 ) / 1000;
+ // if required temp < existing temp basal
+ var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60;
+ if (insulinScheduled < insulinReq - 0.2) { // if current temp would deliver >0.2U less than the required insulin, raise the rate
+ rT.reason = currenttemp.duration + "m@" + (currenttemp.rate - profile.current_basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " < req " + insulinReq + "-0.2U";
+ return setTempBasal(rate, 30, profile, rT, offline);
+ }
+ if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate > currenttemp.rate - 0.1)) {
+ rT.reason += ", temp " + currenttemp.rate + " ~< req " + rate + "U/hr";
+ return rT;
+ } else {
+ rT.reason += ", setting " + rate + "U/hr";
+ return setTempBasal(rate, 30, profile, rT, offline);
+ }
+ }
+ }
+ }
+
+ // if eventual BG is above min but BG is falling faster than expected Delta
+ if (minDelta < expectedDelta) {
+ if (glucose_status.delta < glucose_status.avgdelta) {
+ rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < Exp. Delta " + expectedDelta;
+ } else {
+ rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Avg. Delta " + glucose_status.avgdelta.toFixed(2) + " < Exp. Delta " + expectedDelta;
+ }
+ if (currenttemp.duration > 0) { // if there is currently any temp basal running
+ rT.reason = rT.reason += "; cancel";
+ return setTempBasal(0, 0, profile, rT, offline); // cancel temp
+ } else {
+ rT.reason = rT.reason += "; no temp to cancel";
+ return rT;
+ }
+ }
+
+ if (eventualBG < profile.max_bg) {
+ rT.reason = eventualBG + " is in range. No temp required";
+ if (currenttemp.duration > 0) { // if there is currently any temp basal running
+ rT.reason = rT.reason += "; cancel";
+ return setTempBasal(0, 0, profile, rT, offline); // cancel temp
+ }
+ if (offline == 'Offline') {
+ // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working
+ if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !rT.duration) {
+ rT.reason = rT.reason + "; setting current basal of " + profile.current_basal + " as temp";
+ return setTempBasal(profile.current_basal, 30, profile, rT, offline);
+ }
+ }
+ return rT;
+ }
+
+ if (snoozeBG < profile.max_bg) {
+ rT.reason = snoozeBG + " < " + profile.max_bg;
+ if (currenttemp.duration > 0) { // if there is currently any temp basal running
+ rT.reason = rT.reason += "; cancel";
+ return setTempBasal(0, 0, profile, rT, offline); // cancel temp
+ } else {
+ rT.reason = rT.reason += "; no temp to cancel";
+ return rT;
+ }
+ }
+
+
+ // eventual BG is at/above target:
+ // if iob is over max, just cancel any temps
+ var basaliob;
+ if (iob_data.basaliob) { basaliob = iob_data.basaliob; }
+ else { basaliob = iob_data.iob - iob_data.bolussnooze; }
+ rT.reason = "Eventual BG " + eventualBG + ">=" + profile.max_bg + ", ";
+ if (basaliob > max_iob) {
+ rT.reason = "basaliob " + basaliob + " > max_iob " + max_iob;
+ return setTempBasal(0, 0, profile, rT, offline);
+ } else { // otherwise, calculate 30m high-temp required to get projected BG down to target
+
+ // insulinReq is the additional insulin required to get down to max bg:
+ // if in meal assist mode, check if snoozeBG is lower, as eventualBG is not dependent on IOB
+ var insulinReq = (Math.min(snoozeBG,eventualBG) - target_bg) / profile.sens;
+ if (minDelta < 0 && minDelta > expectedDelta) {
+ var newinsulinReq = Math.round(( insulinReq * (1 - (minDelta / expectedDelta)) ) * 100)/100;
+ //console.log("Reducing insulinReq from " + insulinReq + " to " + newinsulinReq);
+ insulinReq = newinsulinReq;
+ }
+ // if that would put us over max_iob, then reduce accordingly
+ if (insulinReq > max_iob-basaliob) {
+ rT.reason = "max_iob " + max_iob + ", ";
+ insulinReq = max_iob-basaliob;
+ }
+
+ // rate required to deliver insulinReq more insulin over 30m:
+ var rate = profile.current_basal + (2 * insulinReq);
+ rate = Math.round( rate * 1000 ) / 1000;
+
+ var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal);
+ if (rate > maxSafeBasal) {
+ rT.reason += "adj. req. rate:"+rate.toFixed(1) +" to maxSafeBasal:"+maxSafeBasal.toFixed(1)+", ";
+ rate = maxSafeBasal;
+ }
+
+ var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60;
+ if (insulinScheduled > insulinReq + 0.2) { // if current temp would deliver >0.2U more than the required insulin, lower the rate
+ rT.reason = currenttemp.duration + "m@" + (currenttemp.rate - profile.current_basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " > req " + insulinReq + "+0.2U";
+ return setTempBasal(rate, 30, profile, rT, offline);
+ }
+
+ if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set
+ rT.reason += "no temp, setting " + rate + "U/hr";
+ return setTempBasal(rate, 30, profile, rT, offline);
+ }
+
+ if (currenttemp.duration > 5 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal
+ rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr";
+ return rT;
+ }
+
+ // required temp > existing temp basal
+ rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr";
+ return setTempBasal(rate, 30, profile, rT, offline);
+ }
+
+};
+
+module.exports = determine_basal;
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java
index b4f54dae85..5e0f2b84e2 100644
--- a/app/src/main/java/info/nightscout/androidaps/Config.java
+++ b/app/src/main/java/info/nightscout/androidaps/Config.java
@@ -8,4 +8,5 @@ public class Config {
public static final boolean logFunctionCalls = true;
public static final boolean logIncommingBG = true;
public static final boolean logIncommingData = true;
+ public static final boolean logAPSResult = true;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
index 4ee183a2bf..1c02076fb1 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
@@ -10,6 +10,8 @@ import android.view.MenuItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import info.nightscout.androidaps.plugins.LowSuspend.LowSuspendFragment;
+import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAFragment;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.androidaps.plugins.ProfileViewer.ProfileViewerFragment;
import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment;
@@ -37,6 +39,8 @@ public class MainActivity extends AppCompatActivity {
// Register all tabs in app here
mAdapter = new TabPageAdapter(getSupportFragmentManager());
mAdapter.registerNewFragment("Overview", OverviewFragment.newInstance());
+ mAdapter.registerNewFragment("LowSuspend", LowSuspendFragment.newInstance());
+ mAdapter.registerNewFragment("OpenAPS MA", OpenAPSMAFragment.newInstance());
mAdapter.registerNewFragment("Treatments", treatmentsFragment = TreatmentsFragment.newInstance());
mAdapter.registerNewFragment("TempBasals", tempBasalsFragment = TempBasalsFragment.newInstance());
mAdapter.registerNewFragment("Profile", ProfileViewerFragment.newInstance());
diff --git a/app/src/main/java/info/nightscout/androidaps/data/Iob.java b/app/src/main/java/info/nightscout/androidaps/data/Iob.java
index 92fdae4f7c..ee70699604 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/Iob.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/Iob.java
@@ -6,14 +6,10 @@ package info.nightscout.androidaps.data;
public class Iob {
public double iobContrib = 0d;
public double activityContrib = 0d;
- public double netInsulin = 0d; // for calculations from temp basals only
- public double netRatio = 0d; // for calculations from temp basals only
public Iob plus(Iob iob) {
iobContrib += iob.iobContrib;
activityContrib += iob.activityContrib;
- netInsulin += iob.netInsulin;
- netRatio += iob.netRatio;
return this;
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/Pump.java b/app/src/main/java/info/nightscout/androidaps/data/Pump.java
index b17739e1fa..5c2cc10619 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/Pump.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/Pump.java
@@ -5,6 +5,12 @@ package info.nightscout.androidaps.data;
*/
public abstract class Pump {
+ boolean tempBasalInProgress = false;
+
// Upload to pump new basal profile from MainApp.getNSProfile()
public abstract void setNewBasalProfile();
+
+ public abstract double getBaseBasalRate(); // base basal rate, not temp basal
+ public abstract double getTempBasalAbsoluteRate();
+ public abstract double getTempBasalRemainingMinutes();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
index c3003ac9fd..0b7f7a944c 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
@@ -160,4 +160,65 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList();
}
+ /*
+ * Returns glucose_status for openAPS or null if no actual data available
+ */
+ public class GlucoseStatus {
+ public double glucose = 0d;
+ public double delta = 0d;
+ public double avgdelta = 0d;
+ }
+
+ public GlucoseStatus getGlucoseStatusData() {
+ GlucoseStatus result = new GlucoseStatus();
+ try {
+
+ Dao daoBgreadings = null;
+ daoBgreadings = getDaoBgReadings();
+ List bgReadings;
+ QueryBuilder queryBuilder = daoBgreadings.queryBuilder();
+ queryBuilder.orderBy("timeIndex", false);
+ queryBuilder.limit(4l);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ bgReadings = daoBgreadings.query(preparedQuery);
+
+ int sizeRecords = bgReadings.size();
+
+ if (sizeRecords < 4 || bgReadings.get(sizeRecords - 1).timestamp > new Date().getTime() - 7 * 60 * 1000l)
+ return null;
+
+ int minutes = 5;
+ double change;
+ double avg;
+
+ if (bgReadings.size() > 3) {
+ BgReading now = bgReadings.get(sizeRecords - 1);
+ BgReading last = bgReadings.get(sizeRecords - 2);
+ BgReading last1 = bgReadings.get(sizeRecords - 3);
+ BgReading last2 = bgReadings.get(sizeRecords - 4);
+ if (last2.value > 30) {
+ minutes = 3 * 5;
+ change = now.value - last2.value;
+ } else if (last1.value > 30) {
+ minutes = 2 * 5;
+ change = now.value - last1.value;
+ } else if (last.value > 30) {
+ minutes = 5;
+ change = now.value - last.value;
+ } else {
+ change = 0;
+ }
+ //multiply by 5 to get the same unit as delta, i.e. mg/dL/5m
+ avg = change / minutes * 5;
+
+ result.glucose = now.value;
+ result.delta = change;
+ result.avgdelta = avg;
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return null;
+ }
+ return result;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java b/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java
index 755e94e6fb..e9ca5fad42 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java
@@ -12,6 +12,7 @@ import java.util.TimeZone;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Iob;
+import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.client.data.NSProfile;
@DatabaseTable(tableName = "TempBasals")
@@ -52,8 +53,8 @@ public class TempBasal {
public boolean isAbsolute; // true if if set as absolute value in U
- public Iob iobCalc(Date time) {
- Iob result = new Iob();
+ public IobTotal iobCalc(Date time) {
+ IobTotal result = new IobTotal();
NSProfile profile = MainApp.getNSProfile();
if (profile == null)
@@ -89,8 +90,16 @@ public class TempBasal {
tempBolusPart.insulin = tempBolusSize;
Long date = this.timeStart.getTime() + j * tempBolusSpacing * 60 * 1000;
tempBolusPart.created_at = new Date(date);
- Iob iob = tempBolusPart.iobCalc(time);
- result.plus(iob);
+
+ Iob aIOB = tempBolusPart.iobCalc(time, profile.getDia());
+ result.basaliob += aIOB.iobContrib;
+ Double dia_ago = time.getTime() - profile.getDia() * 60 * 60 * 1000;
+ if (date > dia_ago && date <= time.getTime()) {
+ result.netbasalinsulin += tempBolusPart.insulin;
+ if (tempBolusPart.insulin > 0) {
+ result.hightempinsulin += tempBolusPart.insulin;
+ }
+ }
}
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/Treatment.java b/app/src/main/java/info/nightscout/androidaps/db/Treatment.java
index 59bb255062..56ce9a8a3f 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/Treatment.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/Treatment.java
@@ -56,24 +56,8 @@ public class Treatment {
this.carbs = t.carbs;
}
- public Iob iobCalc(Date time) {
- Iob resultNow = doIobCalc(time);
- Iob resultIn5min = doIobCalc(new Date(time.getTime() + 5 * 60 * 1000));
- resultNow.activityContrib = resultNow.iobContrib - resultIn5min.iobContrib;
- return resultNow;
- }
-
- public Iob doIobCalc(Date time) {
-
+ public Iob iobCalc(Date time, Double dia) {
Iob result = new Iob();
- NSProfile profile = MainApp.getNSProfile();
-
- if (profile == null) {
- return result;
- }
-
- Double dia = profile.getDia();
- Double sens = profile.getIsf(profile.secondsFromMidnight(time));
Double scaleFactor = 3.0 / dia;
Double peak = 75d;
@@ -98,22 +82,6 @@ public class Treatment {
return result;
}
-/*
- public Iob calcIobOpenAPS() {
- IobCalc calc = new IobCalc(created_at,insulin,new Date());
- calc.setBolusDiaTimesTwo();
- Iob iob = calc.invoke();
-
- return iob;
- }
- public Iob calcIob() {
- IobCalc calc = new IobCalc(created_at,insulin,new Date());
- Iob iob = calc.invoke();
-
- return iob;
- }
-*/
-
public long getMillisecondsFromStart() {
return new Date().getTime() - created_at.getTime();
}
@@ -180,6 +148,4 @@ public class Treatment {
log.error("DBUPDATE No receivers");
} else log.debug("DBUPDATE dbUpdate " + q.size() + " receivers " + _id + " " + data.toString());
}
-
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/APSBase.java b/app/src/main/java/info/nightscout/androidaps/plugins/APSBase.java
new file mode 100644
index 0000000000..b1fd2e9510
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/APSBase.java
@@ -0,0 +1,13 @@
+package info.nightscout.androidaps.plugins;
+
+import java.util.Date;
+
+/**
+ * Created by mike on 10.06.2016.
+ */
+public interface APSBase {
+ public APSResult getLastAPSResult();
+ public Date getLastAPSRun();
+
+ public void run();
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/APSResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/APSResult.java
new file mode 100644
index 0000000000..b5d2b42724
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/APSResult.java
@@ -0,0 +1,11 @@
+package info.nightscout.androidaps.plugins;
+
+/**
+ * Created by mike on 09.06.2016.
+ */
+public class APSResult {
+ public String reason;
+ public double rate;
+ public int duration;
+ public boolean changeRequested = false;
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendFragment.java
new file mode 100644
index 0000000000..492ca5e397
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendFragment.java
@@ -0,0 +1,53 @@
+package info.nightscout.androidaps.plugins.LowSuspend;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.PluginBase;
+
+public class LowSuspendFragment extends Fragment implements PluginBase {
+
+ @Override
+ public int getType() {
+ return PluginBase.APS;
+ }
+
+ @Override
+ public boolean isFragmentVisible() {
+ return true;
+ }
+
+ public static LowSuspendFragment newInstance() {
+ LowSuspendFragment fragment = new LowSuspendFragment();
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ registerBus();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.lowsuspend_fragment, container, false);
+ }
+
+ private void registerBus() {
+ try {
+ MainApp.bus().unregister(this);
+ } catch (RuntimeException x) {
+ // Ignore
+ }
+ MainApp.bus().register(this);
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendResult.java
new file mode 100644
index 0000000000..d301b735e1
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendResult.java
@@ -0,0 +1,25 @@
+package info.nightscout.androidaps.plugins.LowSuspend;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class LowSuspendResult {
+ public boolean lowProjected;
+ public boolean low;
+ public String reason;
+
+ public int percent;
+
+ public JSONObject json() {
+ JSONObject json = new JSONObject();
+ try {
+ json.put("low", low);
+ json.put("lowProjected", lowProjected);
+ json.put("reason", reason);
+ json.put("percent", percent);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return json;
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalAdapterJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalAdapterJS.java
new file mode 100644
index 0000000000..bcc7d62593
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalAdapterJS.java
@@ -0,0 +1,244 @@
+package info.nightscout.androidaps.plugins.OpenAPSMA;
+
+import com.eclipsesource.v8.JavaVoidCallback;
+import com.eclipsesource.v8.V8;
+import com.eclipsesource.v8.V8Array;
+import com.eclipsesource.v8.V8Object;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.data.Pump;
+import info.nightscout.androidaps.db.DatabaseHelper;
+import info.nightscout.androidaps.plugins.ScriptReader;
+import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
+import info.nightscout.client.data.NSProfile;
+
+public class DetermineBasalAdapterJS {
+ private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterJS.class);
+
+
+ private final ScriptReader mScriptReader;
+ V8 mV8rt;
+ private V8Object mProfile;
+ private V8Object mGlucoseStatus;
+ private V8Object mIobData;
+ private V8Object mMealData;
+ private V8Object mCurrentTemp;
+
+ 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";
+
+ public DetermineBasalAdapterJS(ScriptReader scriptReader) throws IOException {
+ mV8rt = V8.createV8Runtime();
+ mScriptReader = scriptReader;
+
+ init();
+ initLogCallback();
+ initProcessExitCallback();
+ initModuleParent();
+ loadScript();
+ }
+
+ public void init() {
+ // Profile
+ mProfile = new V8Object(mV8rt);
+ mProfile.add("max_iob", 0);
+ mProfile.add("carbs_hr", 0);
+ mProfile.add("dia", 0);
+ mProfile.add("type", "current");
+ mProfile.add("max_daily_basal", 0);
+ mProfile.add("max_basal", 0);
+ mProfile.add("max_bg", 0);
+ mProfile.add("min_bg", 0);
+ mProfile.add("carbratio", 0);
+ mProfile.add("sens", 0);
+ mProfile.add("current_basal", 0);
+ mV8rt.add(PARAM_profile, mProfile);
+ // Current temp
+ mCurrentTemp = new V8Object(mV8rt);
+ mCurrentTemp.add("temp", "absolute");
+ mCurrentTemp.add("duration", 0);
+ mCurrentTemp.add("rate", 0);
+ mV8rt.add(PARAM_currentTemp, mCurrentTemp);
+ // IOB data
+ mIobData = new V8Object(mV8rt);
+ mIobData.add("iob", 0); //netIob
+ mIobData.add("activity", 0); //netActivity
+ mIobData.add("bolusiob", 0); // backward compatibility with master
+ mIobData.add("bolussnooze", 0); //bolusIob
+ mIobData.add("basaliob", 0);
+ mIobData.add("netbasalinsulin", 0);
+ mIobData.add("hightempinsulin", 0);
+ mV8rt.add(PARAM_iobData, mIobData);
+ // Glucose status
+ mGlucoseStatus = new V8Object(mV8rt);
+ mGlucoseStatus.add("delta", 0);
+ mGlucoseStatus.add("glucose", 0);
+ mGlucoseStatus.add("avgdelta", 0);
+ mV8rt.add(PARAM_glucoseStatus, mGlucoseStatus);
+ // Meal data
+ mMealData = new V8Object(mV8rt);
+ mMealData.add("carbs", 0);
+ mMealData.add("boluses", 0);
+ mV8rt.add(PARAM_meal_data, mMealData);
+ }
+
+ public DetermineBasalResult invoke() {
+ mV8rt.executeVoidScript(
+ "console.error(\"determine_basal(\"+\n" +
+ "JSON.stringify(" + PARAM_glucoseStatus + ")+ \", \" +\n" +
+ "JSON.stringify(" + PARAM_currentTemp + ")+ \", \" + \n" +
+ "JSON.stringify(" + PARAM_iobData + ")+ \", \" +\n" +
+ "JSON.stringify(" + PARAM_meal_data + ")+ \", \" +\n" +
+ "JSON.stringify(" + PARAM_profile + ")+ \") \");");
+ mV8rt.executeVoidScript(
+ "var rT = determine_basal(" +
+ PARAM_glucoseStatus + ", " +
+ PARAM_currentTemp + ", " +
+ PARAM_iobData + ", " +
+ PARAM_profile + ", " +
+ "undefined, " +
+ PARAM_meal_data + ", " +
+ "setTempBasal" +
+ ");");
+
+
+ String ret = mV8rt.executeStringScript("JSON.stringify(rT);");
+ if (Config.logAPSResult)
+ log.debug(ret);
+
+ V8Object v8ObjectReuslt = mV8rt.getObject("rT");
+
+ DetermineBasalResult result = null;
+ try {
+ result = new DetermineBasalResult(v8ObjectReuslt, new JSONObject(ret));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ private void loadScript() throws IOException {
+ mV8rt.executeVoidScript(
+ readFile("OpenAPSMA/determine-basal.js"),
+ "OpenAPSMA/bin/oref0-determine-basal.js",
+ 0);
+ mV8rt.executeVoidScript("var determine_basal = module.exports;");
+ // TODO: convert to variable too
+ mV8rt.executeVoidScript(
+ "var setTempBasal = function (rate, duration, profile, rT, offline) {" +
+ "rT.duration = duration;\n" +
+ " rT.rate = rate;" +
+ "return rT;" +
+ "};",
+ "setTempBasal.js",
+ 0
+ );
+ }
+
+ private void initModuleParent() {
+ mV8rt.executeVoidScript("var module = {\"parent\":Boolean(1)};");
+ }
+
+ private void initProcessExitCallback() {
+ JavaVoidCallback callbackProccessExit = new JavaVoidCallback() {
+ @Override
+ public void invoke(V8Object arg0, V8Array parameters) {
+ if (parameters.length() > 0) {
+ Object arg1 = parameters.get(0);
+ log.error("ProccessExit " + arg1);
+ }
+ }
+ };
+ mV8rt.registerJavaMethod(callbackProccessExit, "proccessExit");
+ mV8rt.executeVoidScript("var process = {\"exit\": function () { proccessExit(); } };");
+ }
+
+ private void initLogCallback() {
+ JavaVoidCallback callbackLog = new JavaVoidCallback() {
+ @Override
+ public void invoke(V8Object arg0, V8Array parameters) {
+ if (parameters.length() > 0) {
+ Object arg1 = parameters.get(0);
+ if (Config.logAPSResult)
+ log.debug("JSLOG " + arg1);
+ }
+ }
+ };
+ mV8rt.registerJavaMethod(callbackLog, "log");
+ mV8rt.executeVoidScript("var console = {\"log\":log, \"error\":log};");
+ }
+
+
+ public void setData(NSProfile profile,
+ double maxIob,
+ double maxBasal,
+ double minBg,
+ double maxBg,
+ Pump pump,
+ IobTotal iobData,
+ DatabaseHelper.GlucoseStatus glucoseStatus,
+ TreatmentsFragment.MealData mealData) {
+
+ String units = profile.getUnits();
+
+ mProfile.add("max_iob", maxIob);
+ mProfile.add("carbs_hr", profile.getCarbAbsorbtionRate());
+ mProfile.add("dia", profile.getDia());
+ mProfile.add("type", "current");
+ mProfile.add("max_daily_basal", profile.getMaxDailyBasal());
+ mProfile.add("max_basal", maxBasal);
+ mProfile.add("min_bg", minBg);
+ mProfile.add("max_bg", maxBg);
+ mProfile.add("carbratio", profile.getIc(profile.secondsFromMidnight()));
+ mProfile.add("sens", NSProfile.toMgdl(profile.getIsf(profile.secondsFromMidnight()).doubleValue(), units));
+
+ mProfile.add("current_basal", pump.getBaseBasalRate());
+ mCurrentTemp.add("duration", pump.getTempBasalRemainingMinutes());
+ mCurrentTemp.add("rate", pump.getTempBasalAbsoluteRate());
+
+ mIobData.add("iob", iobData.iob); //netIob
+ mIobData.add("activity", iobData.activity); //netActivity
+ mIobData.add("bolusiob", iobData.bolussnooze); // backward compatibility with master
+ mIobData.add("bolussnooze", iobData.bolussnooze); //bolusIob
+ mIobData.add("basaliob", iobData.basaliob);
+ mIobData.add("netbasalinsulin", iobData.netbasalinsulin);
+ mIobData.add("hightempinsulin", iobData.hightempinsulin);
+
+ mGlucoseStatus.add("glucose", glucoseStatus.glucose);
+ mGlucoseStatus.add("delta", glucoseStatus.delta);
+ mGlucoseStatus.add("avgdelta", glucoseStatus.avgdelta);
+
+ mMealData.add("carbs", mealData.carbs);
+ mMealData.add("boluses", mealData.boluses);
+ }
+
+
+ public void release() {
+ mProfile.release();
+ mCurrentTemp.release();
+ mIobData.release();
+ mMealData.release();
+ mGlucoseStatus.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;
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResult.java
new file mode 100644
index 0000000000..c45a69be8d
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResult.java
@@ -0,0 +1,41 @@
+package info.nightscout.androidaps.plugins.OpenAPSMA;
+
+import com.eclipsesource.v8.V8Object;
+
+import org.json.JSONObject;
+
+import info.nightscout.androidaps.plugins.APSResult;
+
+public class DetermineBasalResult extends APSResult {
+
+ public JSONObject json = new JSONObject();
+ public final double eventualBG;
+ public final double snoozeBG;
+ public final String mealAssist;
+
+ public DetermineBasalResult(V8Object result, JSONObject j) {
+ json = j;
+ reason = result.getString("reason");
+ eventualBG = result.getDouble("eventualBG");
+ snoozeBG = result.getDouble("snoozeBG");
+ if(result.contains("rate")) {
+ rate = result.getDouble("rate");
+ changeRequested = true;
+ } else {
+ rate = -1;
+ changeRequested = false;
+ }
+ if(result.contains("duration")) {
+ duration = result.getInteger("duration");
+ changeRequested = changeRequested & true;
+ } else {
+ duration = -1;
+ changeRequested = false;
+ }
+ if(result.contains("mealAssist")) {
+ mealAssist = result.getString("mealAssist");
+ } else mealAssist = "";
+
+ result.release();
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/IobTotal.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/IobTotal.java
new file mode 100644
index 0000000000..0b167b8a94
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/IobTotal.java
@@ -0,0 +1,77 @@
+package info.nightscout.androidaps.plugins.OpenAPSMA;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Date;
+
+import info.nightscout.utils.DateUtil;
+
+public class IobTotal {
+ public Double iob;
+ public Double activity;
+ public Double bolussnooze;
+ public Double basaliob;
+ public Double netbasalinsulin;
+ public Double hightempinsulin;
+
+ public Double netInsulin = 0d; // for calculations from temp basals only
+ public Double netRatio = 0d; // for calculations from temp basals only
+
+ public IobTotal() {
+ this.iob = 0d;
+ this.activity = 0d;
+ this.bolussnooze = 0d;
+ this.basaliob = 0d;
+ this.netbasalinsulin = 0d;
+ this.hightempinsulin = 0d;
+ }
+
+ public IobTotal plus(IobTotal other) {
+ iob += other.iob;
+ activity = other.activity;
+ bolussnooze = other.bolussnooze;
+ basaliob = other.iob;
+ netbasalinsulin = other.netbasalinsulin;
+ hightempinsulin = other.hightempinsulin;
+ netInsulin += other.netInsulin;
+ netRatio += other.netRatio;
+ return this;
+ }
+
+ public static IobTotal combine(IobTotal bolusIOB, IobTotal basalIob) {
+ IobTotal result = new IobTotal();
+ result.iob = bolusIOB.iob;
+ result.activity = bolusIOB.activity;
+ result.bolussnooze = bolusIOB.bolussnooze;
+ result.basaliob = basalIob.iob;
+ result.netbasalinsulin = basalIob.netbasalinsulin;
+ result.hightempinsulin = basalIob.hightempinsulin;
+ return result;
+ }
+
+ public JSONObject json() {
+ JSONObject json = new JSONObject();
+ try {
+ json.put("iob", iob);
+ json.put("activity", activity);
+ json.put("bolusIob", bolussnooze);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return json;
+ }
+
+ public JSONObject nsJson() {
+ JSONObject json = new JSONObject();
+ try {
+ json.put("iob", bolussnooze);
+ json.put("basaliob", iob);
+ json.put("activity", activity);
+ json.put("timestamp", DateUtil.toISOString(new Date()));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return json;
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java
new file mode 100644
index 0000000000..b12829c986
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java
@@ -0,0 +1,209 @@
+package info.nightscout.androidaps.plugins.OpenAPSMA;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import com.squareup.otto.Subscribe;
+
+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.MainActivity;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.Iob;
+import info.nightscout.androidaps.data.Pump;
+import info.nightscout.androidaps.db.DatabaseHelper;
+import info.nightscout.androidaps.events.EventNewBG;
+import info.nightscout.androidaps.events.EventTreatmentChange;
+import info.nightscout.androidaps.plugins.APSBase;
+import info.nightscout.androidaps.plugins.APSResult;
+import info.nightscout.androidaps.plugins.PluginBase;
+import info.nightscout.androidaps.plugins.ScriptReader;
+import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
+import info.nightscout.client.data.NSProfile;
+import info.nightscout.utils.DateUtil;
+
+public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, PluginBase, APSBase {
+ private static Logger log = LoggerFactory.getLogger(OpenAPSMAFragment.class);
+
+ Button run;
+
+ Date lastAPSRun = null;
+ APSResult lastAPSResult = null;
+
+ @Override
+ public int getType() {
+ return PluginBase.APS;
+ }
+
+ @Override
+ public boolean isFragmentVisible() {
+ return true;
+ }
+
+ @Override
+ public APSResult getLastAPSResult() {
+ return lastAPSResult;
+ }
+
+ @Override
+ public Date getLastAPSRun() {
+ return lastAPSRun;
+ }
+
+ public static OpenAPSMAFragment newInstance() {
+ OpenAPSMAFragment fragment = new OpenAPSMAFragment();
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ registerBus();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.openapsma_fragment, container, false);
+
+ run = (Button) view.findViewById(R.id.openapsma_run);
+ run.setOnClickListener(this);
+
+ return view;
+ }
+
+ private void registerBus() {
+ try {
+ MainApp.bus().unregister(this);
+ } catch (RuntimeException x) {
+ // Ignore
+ }
+ MainApp.bus().register(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.openapsma_run:
+ run();
+ break;
+ }
+
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventTreatmentChange ev) {
+ Activity activity = getActivity();
+ if (activity != null)
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ run();
+ }
+ });
+ else
+ log.debug("EventTreatmentChange: Activity is null");
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventNewBG ev) {
+ Activity activity = getActivity();
+ if (activity != null)
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ run();
+ }
+ });
+ else
+ log.debug("EventNewBG: Activity is null");
+ }
+
+ @Override
+ public void run() {
+
+ // private DatermineBasalResult openAps(int glucoseValue, int delta, double deltaAvg15min, StatusEvent status, LowSuspendStatus lowSuspendStatus, IobTotal iobTotal, CarbCalc.Meal mealdata) {
+ DetermineBasalAdapterJS determineBasalAdapterJS = null;
+ try {
+ determineBasalAdapterJS = new DetermineBasalAdapterJS(new ScriptReader(MainApp.instance().getBaseContext()));
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ return;
+ }
+
+ DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
+ NSProfile profile = MainApp.getNSProfile();
+ Pump pump = MainApp.getActivePump();
+
+ if (glucoseStatus == null) {
+ if (Config.logAPSResult) log.debug("No glucose data available");
+ return;
+ }
+
+ if (profile == null) {
+ if (Config.logAPSResult) log.debug("No profile available");
+ return;
+ }
+
+ if (pump == null) {
+ if (Config.logAPSResult) log.debug("No pump available");
+ return;
+ }
+
+ SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+ String units = profile.getUnits();
+
+ String maxBgDefault = "180";
+ String minBgDefault = "100";
+ if (!units.equals(Constants.MGDL)) {
+ maxBgDefault = "10";
+ minBgDefault = "5";
+ }
+
+ // TODO: objectives limits
+ double maxIob = Double.parseDouble(SP.getString("max_iob", "1.5").replace(",", "."));
+ double maxBasal = Double.parseDouble(SP.getString("max_basal", "1").replace(",", "."));
+ // TODO: min_bg, max_bg in prefs
+ double minBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("min_bg", minBgDefault).replace(",", ".")), units);
+ double maxBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("max_bg", maxBgDefault).replace(",", ".")), units);
+
+ MainActivity.treatmentsFragment.updateTotalIOBIfNeeded();
+ MainActivity.tempBasalsFragment.updateTotalIOBIfNeeded();
+ IobTotal bolusIob = MainActivity.treatmentsFragment.lastCalculation;
+ IobTotal basalIob = MainActivity.tempBasalsFragment.lastCalculation;
+
+ IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob);
+
+ TreatmentsFragment.MealData mealData = MainActivity.treatmentsFragment.getMealData();
+
+ determineBasalAdapterJS.setData(profile, maxIob, maxBasal, minBg, maxBg, pump, iobTotal, glucoseStatus, mealData);
+ DetermineBasalResult determineBasalResult = determineBasalAdapterJS.invoke();
+ determineBasalAdapterJS.release();
+
+ try {
+ determineBasalResult.json.put("timestamp", DateUtil.toISOString(new Date()));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ lastAPSResult = determineBasalResult;
+ lastAPSRun = new Date();
+
+ //deviceStatus.suggested = determineBasalResult.json;
+
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
index 77422dfedd..7d79cc72fa 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
@@ -4,14 +4,12 @@ import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
-import android.support.v4.app.ShareCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.jjoe64.graphview.GraphView;
-import com.jjoe64.graphview.helper.DateAsXAxisLabelFormatter;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import com.jjoe64.graphview.series.PointsGraphSeries;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PluginBase.java b/app/src/main/java/info/nightscout/androidaps/plugins/PluginBase.java
index 307cd03476..5a9abee63d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/PluginBase.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/PluginBase.java
@@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins;
+import java.util.Date;
+
/**
* Created by mike on 09.06.2016.
*/
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ScriptReader.java b/app/src/main/java/info/nightscout/androidaps/plugins/ScriptReader.java
new file mode 100644
index 0000000000..ea90cf60b9
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/ScriptReader.java
@@ -0,0 +1,41 @@
+package info.nightscout.androidaps.plugins;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ScriptReader {
+
+ private final Context mContext;
+
+ public ScriptReader(Context context) {
+ mContext = context;
+ }
+
+ public byte[] readFile(String fileName) throws IOException {
+
+ AssetManager assetManager = mContext.getAssets();
+ InputStream is = assetManager.open(fileName);
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ int nRead;
+ byte[] data = new byte[16384];
+
+ while ((nRead = is.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, nRead);
+ }
+
+ buffer.flush();
+
+ byte[] bytes = buffer.toByteArray();
+ is.close();
+ buffer.close();
+
+
+ return bytes;
+
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java
index b7b9fe64d2..4e77987ff5 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java
@@ -35,6 +35,7 @@ import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventTempBasalChange;
+import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.androidaps.plugins.PluginBase;
@@ -45,10 +46,9 @@ public class TempBasalsFragment extends Fragment implements PluginBase {
LinearLayoutManager llm;
TextView iobTotal;
- TextView activityTotal;
public long lastCalculationTimestamp = 0;
- public Iob lastCalculation;
+ public IobTotal lastCalculation;
private static DecimalFormat formatNumber0decimalplaces = new DecimalFormat("0");
private static DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00");
@@ -107,15 +107,14 @@ public class TempBasalsFragment extends Fragment implements PluginBase {
}
private void updateTotalIOB() {
- Iob total = new Iob();
+ Date now = new Date();
+ IobTotal total = new IobTotal();
for (Integer pos = 0; pos < tempBasals.size(); pos++) {
TempBasal t = tempBasals.get(pos);
- total.plus(t.iobCalc(new Date()));
+ total.plus(t.iobCalc(now));
}
if (iobTotal != null)
- iobTotal.setText(formatNumber2decimalplaces.format(total.iobContrib));
- if (activityTotal != null)
- activityTotal.setText(formatNumber3decimalplaces.format(total.activityContrib));
+ iobTotal.setText(formatNumber2decimalplaces.format(total.basaliob));
}
public static class RecyclerViewAdapter extends RecyclerView.Adapter {
@@ -152,9 +151,8 @@ public class TempBasalsFragment extends Fragment implements PluginBase {
holder.percent.setText(formatNumber0decimalplaces.format(tempBasals.get(position).percent) + "%");
}
holder.realDuration.setText(formatNumber0decimalplaces.format(tempBasals.get(position).getRealDuration()) + " min");
- Iob iob = tempBasals.get(position).iobCalc(new Date());
- holder.iob.setText(formatNumber2decimalplaces.format(iob.iobContrib) + " U");
- holder.activity.setText(formatNumber3decimalplaces.format(iob.activityContrib) + " U");
+ IobTotal iob = tempBasals.get(position).iobCalc(new Date());
+ holder.iob.setText(formatNumber2decimalplaces.format(iob.basaliob) + " U");
holder.netInsulin.setText(formatNumber2decimalplaces.format(iob.netInsulin) + " U");
holder.netRatio.setText(formatNumber2decimalplaces.format(iob.netRatio) + " U/h");
}
@@ -179,7 +177,6 @@ public class TempBasalsFragment extends Fragment implements PluginBase {
TextView netRatio;
TextView netInsulin;
TextView iob;
- TextView activity;
TempBasalsViewHolder(View itemView) {
super(itemView);
@@ -192,7 +189,6 @@ public class TempBasalsFragment extends Fragment implements PluginBase {
netRatio = (TextView) itemView.findViewById(R.id.tempbasals_netratio);
netInsulin = (TextView) itemView.findViewById(R.id.tempbasals_netinsulin);
iob = (TextView) itemView.findViewById(R.id.tempbasals_iob);
- activity = (TextView) itemView.findViewById(R.id.tempbasals_activity);
}
}
}
@@ -227,7 +223,6 @@ public class TempBasalsFragment extends Fragment implements PluginBase {
recyclerView.setAdapter(adapter);
iobTotal = (TextView) view.findViewById(R.id.tempbasals_iobtotal);
- activityTotal = (TextView) view.findViewById(R.id.tempbasals_iobactivitytotal);
return view;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/NewTreatmentDialogFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/NewTreatmentDialogFragment.java
index 44beab6bd2..f39577891c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/NewTreatmentDialogFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/NewTreatmentDialogFragment.java
@@ -60,8 +60,8 @@ public class NewTreatmentDialogFragment extends DialogFragment implements OnClic
Double maxcarbs = Double.parseDouble(SP.getString("safety_maxcarbs", "48"));
- String insulinText = this.insulin.getText().toString();
- String carbsText = this.carbs.getText().toString();
+ String insulinText = this.insulin.getText().toString().replace(",", ".");
+ String carbsText = this.carbs.getText().toString().replace(",", ".");
Double insulin = Double.parseDouble(!insulinText.equals("") ? this.insulin.getText().toString() : "0");
Double carbs = Double.parseDouble(!carbsText.equals("") ? this.carbs.getText().toString() : "0");
if (insulin > maxbolus) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java
index 0e137c7a04..64cb5e3bd4 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java
@@ -24,6 +24,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.*;
@@ -175,10 +176,10 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe
MainActivity.treatmentsFragment.updateTotalIOBIfNeeded();
MainActivity.tempBasalsFragment.updateTotalIOBIfNeeded();
- Iob bolusIob = MainActivity.treatmentsFragment.lastCalculation;
- Iob basalIob = MainActivity.tempBasalsFragment.lastCalculation;
- bolusIob.plus(basalIob);
- iobInsulin.setText("-" + numberFormat.format(bolusIob.iobContrib) + "U");
+ IobTotal bolusIob = MainActivity.treatmentsFragment.lastCalculation;
+ IobTotal basalIob = MainActivity.tempBasalsFragment.lastCalculation;
+ Double iobTotal = bolusIob.iob + basalIob.iob;
+ iobInsulin.setText("-" + numberFormat.format(iobTotal) + "U");
totalInsulin.setText("");
wizardDialogDeliverButton.setVisibility(Button.GONE);
@@ -194,9 +195,9 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe
NSProfile profile = MainApp.instance().getNSProfile();
// Entered values
- String i_bg = this.bgInput.getText().toString();
- String i_carbs = this.carbsInput.getText().toString();
- String i_correction = this.correctionInput.getText().toString();
+ String i_bg = this.bgInput.getText().toString().replace("," , ".");
+ String i_carbs = this.carbsInput.getText().toString().replace(",", ".");
+ String i_correction = this.correctionInput.getText().toString().replace(",", ".");
Double c_bg = 0d;
try { c_bg = Double.parseDouble(i_bg.equals("") ? "0" : i_bg); } catch (Exception e) {}
Double c_carbs = 0d;
@@ -240,10 +241,10 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe
MainActivity.treatmentsFragment.updateTotalIOBIfNeeded();
MainActivity.tempBasalsFragment.updateTotalIOBIfNeeded();
- Iob bolusIob = MainActivity.treatmentsFragment.lastCalculation;
- Iob basalIob = MainActivity.tempBasalsFragment.lastCalculation;
- bolusIob.plus(basalIob);
- Double insulingFromIOB = iobCheckbox.isChecked() ? bolusIob.iobContrib : 0d;
+ IobTotal bolusIob = MainActivity.treatmentsFragment.lastCalculation;
+ IobTotal basalIob = MainActivity.tempBasalsFragment.lastCalculation;
+ Double iobTotal = bolusIob.iob + basalIob.iob;
+ Double insulingFromIOB = iobCheckbox.isChecked() ? iobTotal : 0d;
iobInsulin.setText("-" + numberFormat.format(insulingFromIOB) + "U");
// Insulin from correction
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java
index be08746349..abbc2e642b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java
@@ -39,9 +39,11 @@ import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventTreatmentChange;
+import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.androidaps.plugins.PluginBase;
import info.nightscout.androidaps.plugins.Treatments.Dialogs.NewTreatmentDialogFragment;
import info.nightscout.androidaps.Services.Intents;
+import info.nightscout.client.data.NSProfile;
public class TreatmentsFragment extends Fragment implements View.OnClickListener, NewTreatmentDialogFragment.Communicator, PluginBase {
private static Logger log = LoggerFactory.getLogger(TreatmentsFragment.class);
@@ -54,7 +56,7 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
Button refreshFromNS;
public long lastCalculationTimestamp = 0;
- public Iob lastCalculation;
+ public IobTotal lastCalculation;
private static DecimalFormat formatNumber0decimalplaces = new DecimalFormat("0");
private static DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00");
@@ -101,20 +103,61 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
}
private void updateTotalIOB() {
- Iob total = new Iob();
+ IobTotal total = new IobTotal();
+
+ NSProfile profile = MainApp.getNSProfile();
+ if (profile == null) {
+ lastCalculation = total;
+ return;
+ }
+
+ Double dia = profile.getDia();
+
+ Date now = new Date();
for (Integer pos = 0; pos < treatments.size(); pos++) {
Treatment t = treatments.get(pos);
- total.plus(t.iobCalc(new Date()));
+ Iob tIOB = t.iobCalc(now, dia);
+ total.iob += tIOB.iobContrib;
+ total.activity += tIOB.activityContrib;
+ Iob bIOB = t.iobCalc(now, dia / 2);
+ total.bolussnooze += bIOB.iobContrib;
}
if (iobTotal != null)
- iobTotal.setText(formatNumber2decimalplaces.format(total.iobContrib));
+ iobTotal.setText(formatNumber2decimalplaces.format(total.iob));
if (activityTotal != null)
- activityTotal.setText(formatNumber3decimalplaces.format(total.activityContrib));
+ activityTotal.setText(formatNumber3decimalplaces.format(total.activity));
lastCalculationTimestamp = new Date().getTime();
lastCalculation = total;
}
+ public class MealData {
+ public double boluses = 0d;
+ public double carbs = 0d;
+ }
+
+ public MealData getMealData() {
+ MealData result = new MealData();
+ NSProfile profile = MainApp.getNSProfile();
+ if (profile == null)
+ return result;
+
+ for (Treatment treatment : treatments) {
+ long now = new Date().getTime();
+ long dia_ago = now - (new Double(profile.getDia() * 60 * 60 * 1000l)).longValue();
+ long t = treatment.created_at.getTime();
+ if (t > dia_ago && t <= now) {
+ if (treatment.carbs >= 1) {
+ result.carbs += treatment.carbs;
+ }
+ if (treatment.insulin >= 0.1) {
+ result.boluses += treatment.insulin;
+ }
+ }
+ }
+ return result;
+ }
+
public static class RecyclerViewAdapter extends RecyclerView.Adapter {
List treatments;
@@ -132,12 +175,15 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
@Override
public void onBindViewHolder(TreatmentsViewHolder holder, int position) {
+ NSProfile profile = MainApp.getNSProfile();
+ if (profile == null)
+ return;
// TODO: implement locales
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, new Locale("cs", "CZ"));
holder.date.setText(df.format(treatments.get(position).created_at));
holder.insulin.setText(formatNumber2decimalplaces.format(treatments.get(position).insulin) + " U");
holder.carbs.setText(formatNumber0decimalplaces.format(treatments.get(position).carbs) + " g");
- Iob iob = treatments.get(position).iobCalc(new Date());
+ Iob iob = treatments.get(position).iobCalc(new Date(), profile.getDia());
holder.iob.setText(formatNumber2decimalplaces.format(iob.iobContrib) + " U");
holder.activity.setText(formatNumber3decimalplaces.format(iob.activityContrib) + " U");
}
@@ -205,8 +251,8 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
activityTotal = (TextView) view.findViewById(R.id.treatments_iobactivitytotal);
refreshFromNS = (Button) view.findViewById(R.id.treatments_reshreshfromnightscout);
-
refreshFromNS.setOnClickListener(this);
+
return view;
}
diff --git a/app/src/main/java/info/nightscout/client/data/NSProfile.java b/app/src/main/java/info/nightscout/client/data/NSProfile.java
index 9965d1db4e..c85545abf3 100644
--- a/app/src/main/java/info/nightscout/client/data/NSProfile.java
+++ b/app/src/main/java/info/nightscout/client/data/NSProfile.java
@@ -9,6 +9,8 @@ import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
+import info.nightscout.androidaps.Constants;
+
public class NSProfile {
private JSONObject json = null;
private String activeProfile = null;
@@ -292,4 +294,9 @@ public class NSProfile {
long passed = now - c.getTimeInMillis();
return (int) (passed / 1000);
}
+
+ public static Double toMgdl(Double value, String units) {
+ if (units.equals(Constants.MGDL)) return value;
+ else return value * Constants.MMOLL_TO_MGDL;
+ }
}
diff --git a/app/src/main/res/layout/lowsuspend_fragment.xml b/app/src/main/res/layout/lowsuspend_fragment.xml
new file mode 100644
index 0000000000..b145b8b546
--- /dev/null
+++ b/app/src/main/res/layout/lowsuspend_fragment.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/openapsma_fragment.xml b/app/src/main/res/layout/openapsma_fragment.xml
new file mode 100644
index 0000000000..f663518f55
--- /dev/null
+++ b/app/src/main/res/layout/openapsma_fragment.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/tempbasals_fragment.xml b/app/src/main/res/layout/tempbasals_fragment.xml
index 404f4ed404..8486bfbf32 100644
--- a/app/src/main/res/layout/tempbasals_fragment.xml
+++ b/app/src/main/res/layout/tempbasals_fragment.xml
@@ -31,20 +31,6 @@
android:id="@+id/tempbasals_iobtotal"
android:paddingLeft="10dp" />
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6e4a4a175b..9fba211406 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -44,9 +44,7 @@
Ratio:
Ins:
IOB:
- Activity:
Total IOB:
- Total IOB activity:
Insulin amount
Carbs amount
BG
@@ -56,5 +54,6 @@
IOB
TOTAL
Units:
+ Run now