commit
b1a342ec86
|
@ -37,7 +37,7 @@
|
|||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
316
app/src/main/assets/OpenAPSMA/determine-basal.js
Normal file
316
app/src/main/assets/OpenAPSMA/determine-basal.js
Normal file
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -160,4 +160,65 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return new ArrayList<BgReading>();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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<BgReading, Long> daoBgreadings = null;
|
||||
daoBgreadings = getDaoBgReadings();
|
||||
List<BgReading> bgReadings;
|
||||
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
|
||||
queryBuilder.orderBy("timeIndex", false);
|
||||
queryBuilder.limit(4l);
|
||||
PreparedQuery<BgReading> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by mike on 09.06.2016.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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<RecyclerViewAdapter.TempBasalsViewHolder> {
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<RecyclerViewAdapter.TreatmentsViewHolder> {
|
||||
|
||||
List<Treatment> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
13
app/src/main/res/layout/lowsuspend_fragment.xml
Normal file
13
app/src/main/res/layout/lowsuspend_fragment.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.LowSuspend.LowSuspendFragment">
|
||||
|
||||
<!-- TODO: Update blank fragment layout -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/hello_blank_fragment" />
|
||||
|
||||
</FrameLayout>
|
19
app/src/main/res/layout/openapsma_fragment.xml
Normal file
19
app/src/main/res/layout/openapsma_fragment.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/openapsma_run"
|
||||
android:id="@+id/openapsma_run" />
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -31,20 +31,6 @@
|
|||
android:id="@+id/tempbasals_iobtotal"
|
||||
android:paddingLeft="10dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tempbasals_iobactivitytotal_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="10dp"
|
||||
android:text="@string/tempbasals_iobactivitytotal_label_string"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tempbasals_iobactivitytotal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="10dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
|
|
|
@ -144,26 +144,6 @@
|
|||
android:layout_marginRight="30dp"
|
||||
android:text="0.12 U" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tempbasals_activity_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:text="@string/tempbasals_activity_string"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tempbasals_activity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginRight="30dp"
|
||||
android:text="0.002 U" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -44,9 +44,7 @@
|
|||
<string name="tempbasals_netratio_label_string">Ratio:</string>
|
||||
<string name="tempbasals_netinsulin_label_string">Ins:</string>
|
||||
<string name="tempbasals_iob_label_string">IOB:</string>
|
||||
<string name="tempbasals_activity_string">Activity:</string>
|
||||
<string name="tempbasals_iobtotal_label_string">Total IOB:</string>
|
||||
<string name="tempbasals_iobactivitytotal_label_string">Total IOB activity:</string>
|
||||
<string name="treatments_newtreatment_insulinamount_label">Insulin amount</string>
|
||||
<string name="treatments_newtreatment_carbsamount_label">Carbs amount</string>
|
||||
<string name="treatments_wizard_bg_label">BG</string>
|
||||
|
@ -56,5 +54,6 @@
|
|||
<string name="treatments_wizard_iob_label">IOB</string>
|
||||
<string name="treatments_wizard_total_label">TOTAL</string>
|
||||
<string name="profileview_units_label">Units:</string>
|
||||
<string name="openapsma_run">Run now</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue