AutoISF -> separate plugin
This commit is contained in:
parent
e32515a369
commit
8a19267a39
17 changed files with 1809 additions and 218 deletions
|
@ -277,56 +277,16 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
|
|
||||||
var profile_sens = round(profile.sens,1)
|
var profile_sens = round(profile.sens,1)
|
||||||
var sens = profile.sens;
|
var sens = profile.sens;
|
||||||
|
if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||||
var now = new Date().getHours();
|
sens = profile.sens / sensitivityRatio;
|
||||||
if (now < 1){
|
|
||||||
now = 1;}
|
|
||||||
else {
|
|
||||||
console.error("Time now is "+now+"; ");
|
|
||||||
}
|
|
||||||
if (meal_data.TDDAIMI7){
|
|
||||||
var tdd7 = meal_data.TDDAIMI7;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
var tdd7 = ((basal * 12)*100)/21;
|
|
||||||
}
|
|
||||||
var tdd_pump_now = meal_data.TDDPUMP;
|
|
||||||
var tdd_pump = ( tdd_pump_now / (now / 24));
|
|
||||||
var TDD = (tdd7 * 0.4) + (tdd_pump * 0.6);
|
|
||||||
console.error("Pump extrapolated TDD = "+tdd_pump+"; ");
|
|
||||||
//if (tdd7 > 0){
|
|
||||||
if ( tdd_pump > tdd7 && now < 5 || now < 7 && TDD < ( 0.8 * tdd7 ) ){
|
|
||||||
TDD = ( 0.8 * tdd7 );
|
|
||||||
console.log("Excess or too low insulin from pump so TDD set to "+TDD+" based on 75% of TDD7; ");
|
|
||||||
rT.reason += "TDD: " +TDD+ " due to low or high tdd from pump; ";
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (tdd_pump < (0.33 * tdd7)){
|
|
||||||
TDD = (tdd7 * 0.25) + (tdd_pump * 0.75);
|
|
||||||
console.error("TDD weighted to pump due to low insulin usage. TDD = "+TDD+"; ");
|
|
||||||
rT.reason += "TDD weighted to pump due to low insulin usage. TDD = "+TDD+"; ";
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
console.log("TDD 7 ="+tdd7+", TDD Pump ="+tdd_pump+" and TDD = "+TDD+";");
|
|
||||||
rT.reason += "TDD: " +TDD+ " based on standard pump 60/tdd7 40 split; ";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var variable_sens = (277700 / (TDD * bg));
|
|
||||||
variable_sens = round(variable_sens,1);
|
|
||||||
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
|
|
||||||
|
|
||||||
sens = variable_sens;
|
|
||||||
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
|
|
||||||
sens = sens / sensitivityRatio ;
|
|
||||||
sens = round(sens, 1);
|
|
||||||
console.log("ISF from "+variable_sens+" to "+sens+ "due to temp target; ");
|
|
||||||
} else {
|
|
||||||
sens = sens;
|
|
||||||
sens = round(sens, 1);
|
sens = round(sens, 1);
|
||||||
|
if (sens !== profile_sens) {
|
||||||
|
console.log("ISF from "+profile_sens+" to "+sens);
|
||||||
|
} else {
|
||||||
|
console.log("ISF unchanged: "+sens);
|
||||||
|
}
|
||||||
|
//console.log(" (autosens ratio "+sensitivityRatio+")");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error("; CR:",profile.carb_ratio);
|
console.error("; CR:",profile.carb_ratio);
|
||||||
|
|
||||||
// compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
|
// compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
|
||||||
|
@ -740,20 +700,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
|
|
||||||
console.error("UAM Impact:",uci,"mg/dL per 5m; UAM Duration:",UAMduration,"hours");
|
console.error("UAM Impact:",uci,"mg/dL per 5m; UAM Duration:",UAMduration,"hours");
|
||||||
|
|
||||||
console.log("EventualBG is" +eventualBG+" ;");
|
|
||||||
|
|
||||||
if( glucose_status.delta >= 0 || bg > 60 && glucose_status.delta < 2 && glucose_status.delta > -2 && glucose_status.short_avgdelta > -2 && glucose_status.short_avgdelta < 2 || eventualBG > target_bg && glucose_status.delta < 0 ) {
|
|
||||||
var future_sens = ( 277700 / (TDD * bg) );
|
|
||||||
console.log("Future state sensitivity is " +future_sens+" using current bg due to no COB & small delta or variation");
|
|
||||||
rT.reason += "Dosing sensitivity: " +future_sens+" using current BG;";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var future_sens = ( 277700 / (TDD * eventualBG));
|
|
||||||
console.log("Future state sensitivity is " +future_sens+" based on eventual bg due to -ve delta");
|
|
||||||
rT.reason += "Dosing sensitivity: " +future_sens+" using eventual BG;";
|
|
||||||
}
|
|
||||||
var future_sens = round(future_sens,1);
|
|
||||||
|
|
||||||
|
|
||||||
minIOBPredBG = Math.max(39,minIOBPredBG);
|
minIOBPredBG = Math.max(39,minIOBPredBG);
|
||||||
minCOBPredBG = Math.max(39,minCOBPredBG);
|
minCOBPredBG = Math.max(39,minCOBPredBG);
|
||||||
|
@ -974,33 +920,30 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
rT.reason += ", but Min. Delta " + minDelta.toFixed(2) + " > Exp. Delta " + convert_bg(expectedDelta, profile);
|
rT.reason += ", but Min. Delta " + minDelta.toFixed(2) + " > Exp. Delta " + convert_bg(expectedDelta, profile);
|
||||||
}
|
}
|
||||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. ";
|
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
|
||||||
return rT;
|
return rT;
|
||||||
} else {
|
} else {
|
||||||
rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. ";
|
rT.reason += "; setting current basal of " + basal + " as temp. ";
|
||||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculate 30m low-temp required to get projected BG up to target
|
||||||
|
// multiply by 2 to low-temp faster for increased hypo safety
|
||||||
// calculate 30m low-temp required to get projected BG up to target
|
var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / sens);
|
||||||
// multiply by 2 to low-temp faster for increased hypo safety
|
insulinReq = round( insulinReq , 2);
|
||||||
|
// calculate naiveInsulinReq based on naive_eventualBG
|
||||||
var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / future_sens);
|
var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens);
|
||||||
insulinReq = round( insulinReq , 2);
|
naiveInsulinReq = round( naiveInsulinReq , 2);
|
||||||
// calculate naiveInsulinReq based on naive_eventualBG
|
if (minDelta < 0 && minDelta > expectedDelta) {
|
||||||
var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens);
|
// if we're barely falling, newinsulinReq should be barely negative
|
||||||
naiveInsulinReq = round( naiveInsulinReq , 2);
|
var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2);
|
||||||
if (minDelta < 0 && minDelta > expectedDelta) {
|
//console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
||||||
// if we're barely falling, newinsulinReq should be barely negative
|
insulinReq = newinsulinReq;
|
||||||
var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2);
|
}
|
||||||
//console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
// rate required to deliver insulinReq less insulin over 30m:
|
||||||
insulinReq = newinsulinReq;
|
var rate = basal + (2 * insulinReq);
|
||||||
}
|
rate = round_basal(rate, profile);
|
||||||
// rate required to deliver insulinReq less insulin over 30m:
|
|
||||||
var rate = basal + (2 * insulinReq);
|
|
||||||
rate = round_basal(rate, profile);
|
|
||||||
|
|
||||||
// if required temp < existing temp basal
|
// if required temp < existing temp basal
|
||||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||||
|
@ -1049,10 +992,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Min. Delta " + minDelta.toFixed(2) + " < Exp. Delta " + convert_bg(expectedDelta, profile);
|
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Min. Delta " + minDelta.toFixed(2) + " < Exp. Delta " + convert_bg(expectedDelta, profile);
|
||||||
}
|
}
|
||||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. ";
|
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
|
||||||
return rT;
|
return rT;
|
||||||
} else {
|
} else {
|
||||||
rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. ";
|
rT.reason += "; setting current basal of " + basal + " as temp. ";
|
||||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,10 +1006,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
if (! (microBolusAllowed && enableSMB )) {
|
if (! (microBolusAllowed && enableSMB )) {
|
||||||
rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(minPredBG, profile)+" in range: no temp required";
|
rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(minPredBG, profile)+" in range: no temp required";
|
||||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. ";
|
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
|
||||||
return rT;
|
return rT;
|
||||||
} else {
|
} else {
|
||||||
rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. ";
|
rT.reason += "; setting current basal of " + basal + " as temp. ";
|
||||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1080,22 +1023,22 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
if (iob_data.iob > max_iob) {
|
if (iob_data.iob > max_iob) {
|
||||||
rT.reason += "IOB " + round(iob_data.iob,2) + " > max_iob " + max_iob;
|
rT.reason += "IOB " + round(iob_data.iob,2) + " > max_iob " + max_iob;
|
||||||
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) {
|
||||||
rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. ";
|
rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. ";
|
||||||
return rT;
|
return rT;
|
||||||
} else {
|
} else {
|
||||||
rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. ";
|
rT.reason += "; setting current basal of " + basal + " as temp. ";
|
||||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||||
}
|
}
|
||||||
} else { // otherwise, calculate 30m high-temp required to get projected BG down to target
|
} else { // otherwise, calculate 30m high-temp required to get projected BG down to target
|
||||||
|
|
||||||
// insulinReq is the additional insulin required to get minPredBG down to target_bg
|
// insulinReq is the additional insulin required to get minPredBG down to target_bg
|
||||||
//console.error(minPredBG,eventualBG);
|
//console.error(minPredBG,eventualBG);
|
||||||
insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / future_sens, 2);
|
insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
||||||
// if that would put us over max_iob, then reduce accordingly
|
// if that would put us over max_iob, then reduce accordingly
|
||||||
if (insulinReq > max_iob-iob_data.iob) {
|
if (insulinReq > max_iob-iob_data.iob) {
|
||||||
rT.reason += "max_iob " + max_iob + ", ";
|
rT.reason += "max_iob " + max_iob + ", ";
|
||||||
insulinReq = max_iob-iob_data.iob;
|
insulinReq = max_iob-iob_data.iob;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rate required to deliver insulinReq more insulin over 30m:
|
// rate required to deliver insulinReq more insulin over 30m:
|
||||||
rate = basal + (2 * insulinReq);
|
rate = basal + (2 * insulinReq);
|
||||||
|
|
1224
app/src/main/assets/OpenAPSSMBAutoISF/determine-basal.js
Normal file
1224
app/src/main/assets/OpenAPSSMBAutoISF/determine-basal.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@ import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalAdapterAM
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMBAutoISF.DetermineBasalAdapterSMBAutoISFJS
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ abstract class APSModule {
|
||||||
@ContributesAndroidInjector abstract fun determineBasalResultAMAInjector(): DetermineBasalResultAMA
|
@ContributesAndroidInjector abstract fun determineBasalResultAMAInjector(): DetermineBasalResultAMA
|
||||||
@ContributesAndroidInjector abstract fun determineBasalAdapterAMAJSInjector(): DetermineBasalAdapterAMAJS
|
@ContributesAndroidInjector abstract fun determineBasalAdapterAMAJSInjector(): DetermineBasalAdapterAMAJS
|
||||||
@ContributesAndroidInjector abstract fun determineBasalAdapterSMBJSInjector(): DetermineBasalAdapterSMBJS
|
@ContributesAndroidInjector abstract fun determineBasalAdapterSMBJSInjector(): DetermineBasalAdapterSMBJS
|
||||||
|
@ContributesAndroidInjector abstract fun determineBasalAdapterSMBAutoISFJSInjector(): DetermineBasalAdapterSMBAutoISFJS
|
||||||
@ContributesAndroidInjector abstract fun iobCobThreadInjector(): IobCobThread
|
@ContributesAndroidInjector abstract fun iobCobThreadInjector(): IobCobThread
|
||||||
@ContributesAndroidInjector abstract fun iobCobOref1ThreadInjector(): IobCobOref1Thread
|
@ContributesAndroidInjector abstract fun iobCobOref1ThreadInjector(): IobCobOref1Thread
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@ import info.nightscout.androidaps.plugin.general.openhumans.OpenHumansUploader
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMBAutoISF.OpenAPSSMBAutoISFPlugin
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||||
import info.nightscout.androidaps.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
|
import info.nightscout.androidaps.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
|
||||||
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
|
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
|
||||||
|
@ -212,6 +213,12 @@ abstract class PluginsModule {
|
||||||
@IntKey(220)
|
@IntKey(220)
|
||||||
abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase
|
abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(222)
|
||||||
|
abstract fun bindOpenAPSSMBAutoISFPlugin(plugin: OpenAPSSMBAutoISFPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
|
|
@ -7,6 +7,7 @@ import info.nightscout.androidaps.data.MealData
|
||||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||||
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
||||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||||
|
import info.nightscout.androidaps.interfaces.DetermineBasalAdapterInterface
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
|
@ -14,6 +15,7 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
import info.nightscout.shared.logging.LTag
|
import info.nightscout.shared.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
@ -30,7 +32,7 @@ import java.nio.charset.StandardCharsets
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader, injector: HasAndroidInjector) {
|
class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader, injector: HasAndroidInjector) : DetermineBasalAdapterInterface {
|
||||||
|
|
||||||
private val injector: HasAndroidInjector
|
private val injector: HasAndroidInjector
|
||||||
|
|
||||||
|
@ -48,21 +50,15 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
||||||
private var currentTemp = JSONObject()
|
private var currentTemp = JSONObject()
|
||||||
private var autosensData = JSONObject()
|
private var autosensData = JSONObject()
|
||||||
|
|
||||||
var currentTempParam: String? = null
|
override var currentTempParam: String? = null
|
||||||
private set
|
override var iobDataParam: String? = null
|
||||||
var iobDataParam: String? = null
|
override var glucoseStatusParam: String? = null
|
||||||
private set
|
override var profileParam: String? = null
|
||||||
var glucoseStatusParam: String? = null
|
override var mealDataParam: String? = null
|
||||||
private set
|
override var scriptDebug = ""
|
||||||
var profileParam: String? = null
|
|
||||||
private set
|
|
||||||
var mealDataParam: String? = null
|
|
||||||
private set
|
|
||||||
var scriptDebug = ""
|
|
||||||
private set
|
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
operator fun invoke(): DetermineBasalResultAMA? {
|
override operator fun invoke(): APSResult? {
|
||||||
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||||
aapsLogger.debug(LTag.APS, "Glucose status: " + glucoseStatus.toString().also { glucoseStatusParam = it })
|
aapsLogger.debug(LTag.APS, "Glucose status: " + glucoseStatus.toString().also { glucoseStatusParam = it })
|
||||||
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||||
|
@ -143,18 +139,25 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
@Throws(JSONException::class) fun setData(profile: Profile,
|
@Throws(JSONException::class)
|
||||||
maxIob: Double,
|
override fun setData(
|
||||||
maxBasal: Double,
|
profile: Profile,
|
||||||
minBg: Double,
|
maxIob: Double,
|
||||||
maxBg: Double,
|
maxBasal: Double,
|
||||||
targetBg: Double,
|
minBg: Double,
|
||||||
basalRate: Double,
|
maxBg: Double,
|
||||||
iobArray: Array<IobTotal>,
|
targetBg: Double,
|
||||||
glucoseStatus: GlucoseStatus,
|
basalRate: Double,
|
||||||
mealData: MealData,
|
iobArray: Array<IobTotal>,
|
||||||
autosensDataRatio: Double,
|
glucoseStatus: GlucoseStatus,
|
||||||
tempTargetSet: Boolean) {
|
mealData: MealData,
|
||||||
|
autosensDataRatio: Double,
|
||||||
|
tempTargetSet: Boolean,
|
||||||
|
microBolusAllowed: Boolean,
|
||||||
|
uamAllowed: Boolean,
|
||||||
|
advancedFiltering: Boolean,
|
||||||
|
isSaveCgmSource: Boolean
|
||||||
|
) {
|
||||||
this.profile = JSONObject()
|
this.profile = JSONObject()
|
||||||
this.profile.put("max_iob", maxIob)
|
this.profile.put("max_iob", maxIob)
|
||||||
this.profile.put("dia", min(profile.dia, 3.0))
|
this.profile.put("dia", min(profile.dia, 3.0))
|
||||||
|
|
|
@ -96,7 +96,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
||||||
binding.result.text = jsonFormatter.format(lastAPSResult.json)
|
binding.result.text = jsonFormatter.format(lastAPSResult.json)
|
||||||
binding.request.text = lastAPSResult.toSpanned()
|
binding.request.text = lastAPSResult.toSpanned()
|
||||||
}
|
}
|
||||||
openAPSAMAPlugin.lastDetermineBasalAdapterAMAJS?.let { determineBasalAdapterAMAJS ->
|
openAPSAMAPlugin.lastDetermineBasalAdapter?.let { determineBasalAdapterAMAJS ->
|
||||||
binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam)
|
binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam)
|
||||||
binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterAMAJS.currentTempParam)
|
binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterAMAJS.currentTempParam)
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -60,8 +60,8 @@ class OpenAPSAMAPlugin @Inject constructor(
|
||||||
// last values
|
// last values
|
||||||
override var lastAPSRun: Long = 0
|
override var lastAPSRun: Long = 0
|
||||||
override var lastAPSResult: DetermineBasalResultAMA? = null
|
override var lastAPSResult: DetermineBasalResultAMA? = null
|
||||||
var lastDetermineBasalAdapterAMAJS: DetermineBasalAdapterAMAJS? = null
|
override var lastDetermineBasalAdapter: DetermineBasalAdapterInterface? = null
|
||||||
var lastAutosensResult: AutosensResult = AutosensResult()
|
override var lastAutosensResult: AutosensResult = AutosensResult()
|
||||||
|
|
||||||
override fun specialEnableCondition(): Boolean {
|
override fun specialEnableCondition(): Boolean {
|
||||||
return try {
|
return try {
|
||||||
|
@ -158,7 +158,7 @@ class OpenAPSAMAPlugin @Inject constructor(
|
||||||
// Fix bug determine basal
|
// Fix bug determine basal
|
||||||
if (determineBasalResultAMA == null) {
|
if (determineBasalResultAMA == null) {
|
||||||
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||||
lastDetermineBasalAdapterAMAJS = null
|
lastDetermineBasalAdapter = null
|
||||||
lastAPSResult = null
|
lastAPSResult = null
|
||||||
lastAPSRun = 0
|
lastAPSRun = 0
|
||||||
} else {
|
} else {
|
||||||
|
@ -167,8 +167,8 @@ class OpenAPSAMAPlugin @Inject constructor(
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
determineBasalResultAMA.json?.put("timestamp", dateUtil.toISOString(now))
|
determineBasalResultAMA.json?.put("timestamp", dateUtil.toISOString(now))
|
||||||
determineBasalResultAMA.inputConstraints = inputConstraints
|
determineBasalResultAMA.inputConstraints = inputConstraints
|
||||||
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS
|
lastDetermineBasalAdapter = determineBasalAdapterAMAJS
|
||||||
lastAPSResult = determineBasalResultAMA
|
lastAPSResult = determineBasalResultAMA as DetermineBasalResultAMA
|
||||||
lastAPSRun = now
|
lastAPSRun = now
|
||||||
}
|
}
|
||||||
rxBus.send(EventOpenAPSUpdateGui())
|
rxBus.send(EventOpenAPSUpdateGui())
|
||||||
|
|
|
@ -4,27 +4,19 @@ import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.IobTotal
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
import info.nightscout.androidaps.data.MealData
|
import info.nightscout.androidaps.data.MealData
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
|
||||||
import info.nightscout.androidaps.database.entities.Bolus
|
|
||||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||||
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
||||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
|
||||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
import info.nightscout.shared.logging.LTag
|
import info.nightscout.shared.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
|
||||||
import info.nightscout.shared.SafeParse
|
import info.nightscout.shared.SafeParse
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.stats.TddCalculator
|
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
|
@ -36,7 +28,7 @@ import java.lang.reflect.InvocationTargetException
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) {
|
class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapterInterface {
|
||||||
|
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
|
@ -45,10 +37,6 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var repository: AppRepository
|
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
|
||||||
//@Inject lateinit var danaPump: DanaPump
|
|
||||||
|
|
||||||
|
|
||||||
private var profile = JSONObject()
|
private var profile = JSONObject()
|
||||||
private var mGlucoseStatus = JSONObject()
|
private var mGlucoseStatus = JSONObject()
|
||||||
|
@ -60,26 +48,16 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
private var smbAlwaysAllowed = false
|
private var smbAlwaysAllowed = false
|
||||||
private var currentTime: Long = 0
|
private var currentTime: Long = 0
|
||||||
private var saveCgmSource = false
|
private var saveCgmSource = false
|
||||||
private var lastBolusNormalTime: Long = 0
|
|
||||||
private val millsToThePast = T.hours(4).msecs()
|
|
||||||
private var tddAIMI: TddCalculator? = null
|
|
||||||
|
|
||||||
|
override var currentTempParam: String? = null
|
||||||
var currentTempParam: String? = null
|
override var iobDataParam: String? = null
|
||||||
private set
|
override var glucoseStatusParam: String? = null
|
||||||
var iobDataParam: String? = null
|
override var profileParam: String? = null
|
||||||
private set
|
override var mealDataParam: String? = null
|
||||||
var glucoseStatusParam: String? = null
|
override var scriptDebug = ""
|
||||||
private set
|
|
||||||
var profileParam: String? = null
|
|
||||||
private set
|
|
||||||
var mealDataParam: String? = null
|
|
||||||
private set
|
|
||||||
var scriptDebug = ""
|
|
||||||
private set
|
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
operator fun invoke(): DetermineBasalResultSMB? {
|
override operator fun invoke(): APSResult? {
|
||||||
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||||
aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
|
aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
|
||||||
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||||
|
@ -169,22 +147,24 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
return determineBasalResultSMB
|
return determineBasalResultSMB
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection") fun setData(profile: Profile,
|
@Suppress("SpellCheckingInspection")
|
||||||
maxIob: Double,
|
override fun setData(
|
||||||
maxBasal: Double,
|
profile: Profile,
|
||||||
minBg: Double,
|
maxIob: Double,
|
||||||
maxBg: Double,
|
maxBasal: Double,
|
||||||
targetBg: Double,
|
minBg: Double,
|
||||||
basalRate: Double,
|
maxBg: Double,
|
||||||
iobArray: Array<IobTotal>,
|
targetBg: Double,
|
||||||
glucoseStatus: GlucoseStatus,
|
basalRate: Double,
|
||||||
mealData: MealData,
|
iobArray: Array<IobTotal>,
|
||||||
autosensDataRatio: Double,
|
glucoseStatus: GlucoseStatus,
|
||||||
tempTargetSet: Boolean,
|
mealData: MealData,
|
||||||
microBolusAllowed: Boolean,
|
autosensDataRatio: Double,
|
||||||
uamAllowed: Boolean,
|
tempTargetSet: Boolean,
|
||||||
advancedFiltering: Boolean,
|
microBolusAllowed: Boolean,
|
||||||
isSaveCgmSource: Boolean
|
uamAllowed: Boolean,
|
||||||
|
advancedFiltering: Boolean,
|
||||||
|
isSaveCgmSource: Boolean
|
||||||
) {
|
) {
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||||
|
@ -255,7 +235,6 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
} else {
|
} else {
|
||||||
mGlucoseStatus.put("delta", glucoseStatus.delta)
|
mGlucoseStatus.put("delta", glucoseStatus.delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
mGlucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
|
mGlucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
|
||||||
mGlucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
|
mGlucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
|
||||||
mGlucoseStatus.put("date", glucoseStatus.date)
|
mGlucoseStatus.put("date", glucoseStatus.date)
|
||||||
|
@ -264,13 +243,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation)
|
this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation)
|
||||||
this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation)
|
this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation)
|
||||||
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
|
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
|
||||||
this.mealData.put("lastBolusNormalTime", lastBolusNormalTime)
|
|
||||||
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
|
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
|
||||||
|
|
||||||
tddAIMI = TddCalculator(aapsLogger,rh,activePlugin,profileFunction,dateUtil,iobCobCalculator, repository)
|
|
||||||
this.mealData.put("TDDAIMI7", tddAIMI!!.averageTDD(tddAIMI!!.calculate(7)).totalAmount)
|
|
||||||
this.mealData.put("TDDPUMP", tddAIMI!!.calculateDaily().totalAmount)
|
|
||||||
|
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
autosensData.put("ratio", autosensDataRatio)
|
autosensData.put("ratio", autosensDataRatio)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,8 +9,7 @@ import android.view.ViewGroup
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.databinding.OpenapsamaFragmentBinding
|
import info.nightscout.androidaps.databinding.OpenapsamaFragmentBinding
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.shared.logging.LTag
|
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
@ -19,6 +18,8 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.JSONFormatter
|
import info.nightscout.androidaps.utils.JSONFormatter
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
|
@ -34,7 +35,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
@Inject lateinit var rxBus: RxBus
|
@Inject lateinit var rxBus: RxBus
|
||||||
@Inject lateinit var rh: ResourceHelper
|
@Inject lateinit var rh: ResourceHelper
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var jsonFormatter: JSONFormatter
|
@Inject lateinit var jsonFormatter: JSONFormatter
|
||||||
|
|
||||||
|
@ -44,8 +45,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
savedInstanceState: Bundle?): View {
|
|
||||||
_binding = OpenapsamaFragmentBinding.inflate(inflater, container, false)
|
_binding = OpenapsamaFragmentBinding.inflate(inflater, container, false)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
binding.run.setOnClickListener {
|
binding.run.setOnClickListener {
|
||||||
openAPSSMBPlugin.invoke("OpenAPSSMB button", false)
|
activePlugin.activeAPS.invoke("OpenAPSSMB button", false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,11 +92,12 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun updateGUI() {
|
fun updateGUI() {
|
||||||
if (_binding == null) return
|
if (_binding == null) return
|
||||||
|
val openAPSSMBPlugin = activePlugin.activeAPS
|
||||||
openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult ->
|
openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult ->
|
||||||
binding.result.text = jsonFormatter.format(lastAPSResult.json)
|
binding.result.text = jsonFormatter.format(lastAPSResult.json)
|
||||||
binding.request.text = lastAPSResult.toSpanned()
|
binding.request.text = lastAPSResult.toSpanned()
|
||||||
}
|
}
|
||||||
openAPSSMBPlugin.lastDetermineBasalAdapterSMBJS?.let { determineBasalAdapterSMBJS ->
|
openAPSSMBPlugin.lastDetermineBasalAdapter?.let { determineBasalAdapterSMBJS ->
|
||||||
binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam)
|
binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam)
|
||||||
binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterSMBJS.currentTempParam)
|
binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterSMBJS.currentTempParam)
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -10,8 +10,6 @@ import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.extensions.target
|
import info.nightscout.androidaps.extensions.target
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
|
||||||
import info.nightscout.shared.logging.LTag
|
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
|
@ -24,6 +22,8 @@ import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.Profiler
|
import info.nightscout.androidaps.utils.Profiler
|
||||||
import info.nightscout.androidaps.utils.Round
|
import info.nightscout.androidaps.utils.Round
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -37,7 +37,7 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
private val constraintChecker: ConstraintChecker,
|
private val constraintChecker: ConstraintChecker,
|
||||||
rh: ResourceHelper,
|
rh: ResourceHelper,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val context: Context,
|
val context: Context,
|
||||||
private val activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private val iobCobCalculator: IobCobCalculator,
|
private val iobCobCalculator: IobCobCalculator,
|
||||||
private val hardLimits: HardLimits,
|
private val hardLimits: HardLimits,
|
||||||
|
@ -46,23 +46,24 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
private val dateUtil: DateUtil,
|
private val dateUtil: DateUtil,
|
||||||
private val repository: AppRepository,
|
private val repository: AppRepository,
|
||||||
private val glucoseStatusProvider: GlucoseStatusProvider
|
private val glucoseStatusProvider: GlucoseStatusProvider
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(
|
||||||
.mainType(PluginType.APS)
|
PluginDescription()
|
||||||
.fragmentClass(OpenAPSSMBFragment::class.java.name)
|
.mainType(PluginType.APS)
|
||||||
.pluginIcon(R.drawable.ic_generic_icon)
|
.fragmentClass(OpenAPSSMBFragment::class.java.name)
|
||||||
.pluginName(R.string.openapssmb)
|
.pluginIcon(R.drawable.ic_generic_icon)
|
||||||
.shortName(R.string.smb_shortname)
|
.pluginName(R.string.openapssmb)
|
||||||
.preferencesId(R.xml.pref_openapssmb)
|
.shortName(R.string.smb_shortname)
|
||||||
.description(R.string.description_smb)
|
.preferencesId(R.xml.pref_openapssmb)
|
||||||
.setDefault(),
|
.description(R.string.description_smb)
|
||||||
|
.setDefault(),
|
||||||
aapsLogger, rh, injector
|
aapsLogger, rh, injector
|
||||||
), APS, Constraints {
|
), APS, Constraints {
|
||||||
|
|
||||||
// last values
|
// last values
|
||||||
override var lastAPSRun: Long = 0
|
override var lastAPSRun: Long = 0
|
||||||
override var lastAPSResult: DetermineBasalResultSMB? = null
|
override var lastAPSResult: DetermineBasalResultSMB? = null
|
||||||
var lastDetermineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS? = null
|
override var lastDetermineBasalAdapter: DetermineBasalAdapterInterface? = null
|
||||||
var lastAutosensResult = AutosensResult()
|
override var lastAutosensResult = AutosensResult()
|
||||||
|
|
||||||
override fun specialEnableCondition(): Boolean {
|
override fun specialEnableCondition(): Boolean {
|
||||||
return try {
|
return try {
|
||||||
|
@ -120,15 +121,34 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
}.value()
|
}.value()
|
||||||
|
|
||||||
var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetLowMgdl(), 0.1), R.string.profile_low_target, HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1])
|
var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetLowMgdl(), 0.1), R.string.profile_low_target, HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1])
|
||||||
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetHighMgdl(), 0.1), R.string.profile_high_target, HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1])
|
var maxBg =
|
||||||
|
hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetHighMgdl(), 0.1), R.string.profile_high_target, HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1])
|
||||||
var targetBg = hardLimits.verifyHardLimits(profile.getTargetMgdl(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TARGET_BG[1])
|
var targetBg = hardLimits.verifyHardLimits(profile.getTargetMgdl(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TARGET_BG[1])
|
||||||
var isTempTarget = false
|
var isTempTarget = false
|
||||||
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||||
if (tempTarget is ValueWrapper.Existing) {
|
if (tempTarget is ValueWrapper.Existing) {
|
||||||
isTempTarget = true
|
isTempTarget = true
|
||||||
minBg = hardLimits.verifyHardLimits(tempTarget.value.lowTarget, R.string.temp_target_low_target, HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
|
minBg =
|
||||||
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
hardLimits.verifyHardLimits(
|
||||||
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
tempTarget.value.lowTarget,
|
||||||
|
R.string.temp_target_low_target,
|
||||||
|
HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(),
|
||||||
|
HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble()
|
||||||
|
)
|
||||||
|
maxBg =
|
||||||
|
hardLimits.verifyHardLimits(
|
||||||
|
tempTarget.value.highTarget,
|
||||||
|
R.string.temp_target_high_target,
|
||||||
|
HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(),
|
||||||
|
HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble()
|
||||||
|
)
|
||||||
|
targetBg =
|
||||||
|
hardLimits.verifyHardLimits(
|
||||||
|
tempTarget.value.target(),
|
||||||
|
R.string.temp_target_value,
|
||||||
|
HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(),
|
||||||
|
HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (!hardLimits.checkHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
if (!hardLimits.checkHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||||
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||||
|
@ -165,8 +185,9 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
profiler.log(LTag.APS, "SMB data gathering", start)
|
profiler.log(LTag.APS, "SMB data gathering", start)
|
||||||
start = System.currentTimeMillis()
|
start = System.currentTimeMillis()
|
||||||
|
|
||||||
DetermineBasalAdapterSMBJS(ScriptReader(context), injector).also { determineBasalAdapterSMBJS ->
|
provideDetermineBasalAdapter().also { determineBasalAdapterSMBJS ->
|
||||||
determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg,
|
determineBasalAdapterSMBJS.setData(
|
||||||
|
profile, maxIob, maxBasal, minBg, maxBg, targetBg,
|
||||||
activePlugin.activePump.baseBasalRate,
|
activePlugin.activePump.baseBasalRate,
|
||||||
iobArray,
|
iobArray,
|
||||||
glucoseStatus,
|
glucoseStatus,
|
||||||
|
@ -176,24 +197,26 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
smbAllowed.value(),
|
smbAllowed.value(),
|
||||||
uam.value(),
|
uam.value(),
|
||||||
advancedFiltering.value(),
|
advancedFiltering.value(),
|
||||||
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin")
|
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin"
|
||||||
|
)
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
||||||
profiler.log(LTag.APS, "SMB calculation", start)
|
profiler.log(LTag.APS, "SMB calculation", start)
|
||||||
if (determineBasalResultSMB == null) {
|
if (determineBasalResultSMB == null) {
|
||||||
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||||
lastDetermineBasalAdapterSMBJS = null
|
lastDetermineBasalAdapter = null
|
||||||
lastAPSResult = null
|
lastAPSResult = null
|
||||||
lastAPSRun = 0
|
lastAPSRun = 0
|
||||||
} else {
|
} else {
|
||||||
// TODO still needed with oref1?
|
// TODO still needed with oref1?
|
||||||
// Fix bug determine basal
|
// Fix bug determine basal
|
||||||
if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) == null) determineBasalResultSMB.tempBasalRequested = false
|
if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) == null) determineBasalResultSMB.tempBasalRequested =
|
||||||
|
false
|
||||||
determineBasalResultSMB.iob = iobArray[0]
|
determineBasalResultSMB.iob = iobArray[0]
|
||||||
determineBasalResultSMB.json?.put("timestamp", dateUtil.toISOString(now))
|
determineBasalResultSMB.json?.put("timestamp", dateUtil.toISOString(now))
|
||||||
determineBasalResultSMB.inputConstraints = inputConstraints
|
determineBasalResultSMB.inputConstraints = inputConstraints
|
||||||
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS
|
lastDetermineBasalAdapter = determineBasalAdapterSMBJS
|
||||||
lastAPSResult = determineBasalResultSMB
|
lastAPSResult = determineBasalResultSMB as DetermineBasalResultSMB
|
||||||
lastAPSRun = now
|
lastAPSRun = now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,4 +227,6 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
value.set(aapsLogger, false)
|
value.set(aapsLogger, false)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun provideDetermineBasalAdapter(): DetermineBasalAdapterInterface = DetermineBasalAdapterSMBJS(ScriptReader(context), injector)
|
||||||
}
|
}
|
|
@ -0,0 +1,298 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.openAPSSMBAutoISF
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
|
import info.nightscout.androidaps.data.MealData
|
||||||
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||||
|
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
||||||
|
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
|
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||||
|
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||||
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
|
import info.nightscout.androidaps.interfaces.DetermineBasalAdapterInterface
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.stats.TddCalculator
|
||||||
|
import info.nightscout.shared.SafeParse
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.mozilla.javascript.*
|
||||||
|
import org.mozilla.javascript.Function
|
||||||
|
import java.io.IOException
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DetermineBasalAdapterSMBAutoISFJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapterInterface {
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var rh: ResourceHelper
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var tddCalculator: TddCalculator
|
||||||
|
|
||||||
|
private var profile = JSONObject()
|
||||||
|
private var mGlucoseStatus = JSONObject()
|
||||||
|
private var iobData: JSONArray? = null
|
||||||
|
private var mealData = JSONObject()
|
||||||
|
private var currentTemp = JSONObject()
|
||||||
|
private var autosensData = JSONObject()
|
||||||
|
private var microBolusAllowed = false
|
||||||
|
private var smbAlwaysAllowed = false
|
||||||
|
private var currentTime: Long = 0
|
||||||
|
private var saveCgmSource = false
|
||||||
|
private var lastBolusNormalTime: Long = 0
|
||||||
|
|
||||||
|
override var currentTempParam: String? = null
|
||||||
|
override var iobDataParam: String? = null
|
||||||
|
override var glucoseStatusParam: String? = null
|
||||||
|
override var profileParam: String? = null
|
||||||
|
override var mealDataParam: String? = null
|
||||||
|
override var scriptDebug = ""
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
override operator fun invoke(): DetermineBasalResultSMB? {
|
||||||
|
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||||
|
aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
|
||||||
|
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined")
|
||||||
|
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
||||||
|
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||||
|
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||||
|
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
||||||
|
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||||
|
val rhino = Context.enter()
|
||||||
|
val scope: Scriptable = rhino.initStandardObjects()
|
||||||
|
// Turn off optimization to make Rhino Android compatible
|
||||||
|
rhino.optimizationLevel = -1
|
||||||
|
try {
|
||||||
|
|
||||||
|
//register logger callback for console.log and console.error
|
||||||
|
ScriptableObject.defineClass(scope, LoggerCallback::class.java)
|
||||||
|
val myLogger = rhino.newObject(scope, "LoggerCallback", null)
|
||||||
|
scope.put("console2", scope, myLogger)
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
|
||||||
|
|
||||||
|
//set module parent
|
||||||
|
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
|
||||||
|
|
||||||
|
//generate functions "determine_basal" and "setTempBasal"
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSSMBAutoISF/determine-basal.js"), "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null)
|
||||||
|
val determineBasalObj = scope["determine_basal", scope]
|
||||||
|
val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
|
||||||
|
|
||||||
|
//call determine-basal
|
||||||
|
if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
|
||||||
|
|
||||||
|
//prepare parameters
|
||||||
|
val params = arrayOf(
|
||||||
|
makeParam(mGlucoseStatus, rhino, scope),
|
||||||
|
makeParam(currentTemp, rhino, scope),
|
||||||
|
makeParamArray(iobData, rhino, scope),
|
||||||
|
makeParam(profile, rhino, scope),
|
||||||
|
makeParam(autosensData, rhino, scope),
|
||||||
|
makeParam(mealData, rhino, scope),
|
||||||
|
setTempBasalFunctionsObj,
|
||||||
|
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||||
|
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||||
|
java.lang.Long.valueOf(currentTime),
|
||||||
|
java.lang.Boolean.valueOf(saveCgmSource)
|
||||||
|
)
|
||||||
|
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||||
|
scriptDebug = LoggerCallback.scriptDebug
|
||||||
|
|
||||||
|
// Parse the jsResult object to a JSON-String
|
||||||
|
val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
|
||||||
|
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||||
|
try {
|
||||||
|
val resultJson = JSONObject(result)
|
||||||
|
determineBasalResultSMB = DetermineBasalResultSMB(injector, resultJson)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aapsLogger.error(LTag.APS, "Problem loading JS Functions")
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
aapsLogger.error(LTag.APS, "IOException")
|
||||||
|
} catch (e: RhinoException) {
|
||||||
|
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
|
||||||
|
} catch (e: IllegalAccessException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} catch (e: InstantiationException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} catch (e: InvocationTargetException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} finally {
|
||||||
|
Context.exit()
|
||||||
|
}
|
||||||
|
glucoseStatusParam = mGlucoseStatus.toString()
|
||||||
|
iobDataParam = iobData.toString()
|
||||||
|
currentTempParam = currentTemp.toString()
|
||||||
|
profileParam = profile.toString()
|
||||||
|
mealDataParam = mealData.toString()
|
||||||
|
return determineBasalResultSMB
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
override fun setData(
|
||||||
|
profile: Profile,
|
||||||
|
maxIob: Double,
|
||||||
|
maxBasal: Double,
|
||||||
|
minBg: Double,
|
||||||
|
maxBg: Double,
|
||||||
|
targetBg: Double,
|
||||||
|
basalRate: Double,
|
||||||
|
iobArray: Array<IobTotal>,
|
||||||
|
glucoseStatus: GlucoseStatus,
|
||||||
|
mealData: MealData,
|
||||||
|
autosensDataRatio: Double,
|
||||||
|
tempTargetSet: Boolean,
|
||||||
|
microBolusAllowed: Boolean,
|
||||||
|
uamAllowed: Boolean,
|
||||||
|
advancedFiltering: Boolean,
|
||||||
|
isSaveCgmSource: Boolean
|
||||||
|
) {
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||||
|
this.profile.put("max_iob", maxIob)
|
||||||
|
//mProfile.put("dia", profile.getDia());
|
||||||
|
this.profile.put("type", "current")
|
||||||
|
this.profile.put("max_daily_basal", profile.getMaxDailyBasal())
|
||||||
|
this.profile.put("max_basal", maxBasal)
|
||||||
|
this.profile.put("min_bg", minBg)
|
||||||
|
this.profile.put("max_bg", maxBg)
|
||||||
|
this.profile.put("target_bg", targetBg)
|
||||||
|
this.profile.put("carb_ratio", profile.getIc())
|
||||||
|
this.profile.put("sens", profile.getIsfMgdl())
|
||||||
|
this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
|
||||||
|
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
|
||||||
|
|
||||||
|
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
||||||
|
this.profile.put("high_temptarget_raises_sensitivity", false)
|
||||||
|
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||||
|
this.profile.put("low_temptarget_lowers_sensitivity", false)
|
||||||
|
this.profile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target))
|
||||||
|
this.profile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target))
|
||||||
|
this.profile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments)
|
||||||
|
this.profile.put("exercise_mode", SMBDefaults.exercise_mode)
|
||||||
|
this.profile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target)
|
||||||
|
this.profile.put("maxCOB", SMBDefaults.maxCOB)
|
||||||
|
this.profile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour())
|
||||||
|
// min_5m_carbimpact is not used within SMB determinebasal
|
||||||
|
//if (mealData.usedMinCarbsImpact > 0) {
|
||||||
|
// mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
||||||
|
//} else {
|
||||||
|
// mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
||||||
|
//}
|
||||||
|
this.profile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap)
|
||||||
|
this.profile.put("enableUAM", uamAllowed)
|
||||||
|
this.profile.put("A52_risk_enable", SMBDefaults.A52_risk_enable)
|
||||||
|
val smbEnabled = sp.getBoolean(R.string.key_use_smb, false)
|
||||||
|
this.profile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval))
|
||||||
|
this.profile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false))
|
||||||
|
this.profile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false))
|
||||||
|
this.profile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false))
|
||||||
|
this.profile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering)
|
||||||
|
this.profile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering)
|
||||||
|
this.profile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes))
|
||||||
|
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
|
||||||
|
//set the min SMB amount to be the amount set by the pump.
|
||||||
|
this.profile.put("bolus_increment", pumpBolusStep)
|
||||||
|
this.profile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold))
|
||||||
|
this.profile.put("current_basal", basalRate)
|
||||||
|
this.profile.put("temptargetSet", tempTargetSet)
|
||||||
|
this.profile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")))
|
||||||
|
if (profileFunction.getUnits() == GlucoseUnit.MMOL) {
|
||||||
|
this.profile.put("out_units", "mmol/L")
|
||||||
|
}
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val tb = iobCobCalculator.getTempBasalIncludingConvertedExtended(now)
|
||||||
|
currentTemp.put("temp", "absolute")
|
||||||
|
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
|
||||||
|
currentTemp.put("rate", tb?.convertedToAbsolute(now, profile) ?: 0.0)
|
||||||
|
// as we have non default temps longer than 30 mintues
|
||||||
|
if (tb != null) currentTemp.put("minutesrunning", tb.getPassedDurationToTimeInMinutes(now))
|
||||||
|
|
||||||
|
iobData = iobCobCalculator.convertToJSONArray(iobArray)
|
||||||
|
mGlucoseStatus.put("glucose", glucoseStatus.glucose)
|
||||||
|
mGlucoseStatus.put("noise", glucoseStatus.noise)
|
||||||
|
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||||
|
mGlucoseStatus.put("delta", glucoseStatus.shortAvgDelta)
|
||||||
|
} else {
|
||||||
|
mGlucoseStatus.put("delta", glucoseStatus.delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
mGlucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
|
||||||
|
mGlucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
|
||||||
|
mGlucoseStatus.put("date", glucoseStatus.date)
|
||||||
|
this.mealData.put("carbs", mealData.carbs)
|
||||||
|
this.mealData.put("mealCOB", mealData.mealCOB)
|
||||||
|
this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation)
|
||||||
|
this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation)
|
||||||
|
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
|
||||||
|
this.mealData.put("lastBolusNormalTime", lastBolusNormalTime)
|
||||||
|
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
|
||||||
|
|
||||||
|
this.mealData.put("TDDAIMI7", tddCalculator.averageTDD(tddCalculator.calculate(7)).totalAmount)
|
||||||
|
this.mealData.put("TDDPUMP", tddCalculator.calculateDaily().totalAmount)
|
||||||
|
|
||||||
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
|
autosensData.put("ratio", autosensDataRatio)
|
||||||
|
} else {
|
||||||
|
autosensData.put("ratio", 1.0)
|
||||||
|
}
|
||||||
|
this.microBolusAllowed = microBolusAllowed
|
||||||
|
smbAlwaysAllowed = advancedFiltering
|
||||||
|
currentTime = now
|
||||||
|
saveCgmSource = isSaveCgmSource
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
return if (jsonObject == null) Undefined.instance
|
||||||
|
else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class) private fun readFile(filename: String): String {
|
||||||
|
val bytes = scriptReader.readFile(filename)
|
||||||
|
var string = String(bytes, StandardCharsets.UTF_8)
|
||||||
|
if (string.startsWith("#!/usr/bin/env node")) {
|
||||||
|
string = string.substring(20)
|
||||||
|
}
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
injector.androidInjector().inject(this)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.openAPSSMBAutoISF
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
|
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||||
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
|
import info.nightscout.androidaps.interfaces.DetermineBasalAdapterInterface
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
|
import info.nightscout.androidaps.utils.Profiler
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
|
@Singleton
|
||||||
|
class OpenAPSSMBAutoISFPlugin @Inject constructor(
|
||||||
|
injector: HasAndroidInjector,
|
||||||
|
aapsLogger: AAPSLogger,
|
||||||
|
rxBus: RxBus,
|
||||||
|
constraintChecker: ConstraintChecker,
|
||||||
|
rh: ResourceHelper,
|
||||||
|
profileFunction: ProfileFunction,
|
||||||
|
context: Context,
|
||||||
|
activePlugin: ActivePlugin,
|
||||||
|
iobCobCalculator: IobCobCalculator,
|
||||||
|
hardLimits: HardLimits,
|
||||||
|
profiler: Profiler,
|
||||||
|
sp: SP,
|
||||||
|
dateUtil: DateUtil,
|
||||||
|
repository: AppRepository,
|
||||||
|
glucoseStatusProvider: GlucoseStatusProvider,
|
||||||
|
private val buildHelper: BuildHelper
|
||||||
|
) : OpenAPSSMBPlugin(
|
||||||
|
injector,
|
||||||
|
aapsLogger,
|
||||||
|
rxBus,
|
||||||
|
constraintChecker,
|
||||||
|
rh,
|
||||||
|
profileFunction,
|
||||||
|
context,
|
||||||
|
activePlugin,
|
||||||
|
iobCobCalculator,
|
||||||
|
hardLimits,
|
||||||
|
profiler,
|
||||||
|
sp,
|
||||||
|
dateUtil,
|
||||||
|
repository,
|
||||||
|
glucoseStatusProvider
|
||||||
|
) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
pluginDescription
|
||||||
|
.pluginName(R.string.openapssmbautoisf)
|
||||||
|
.description(R.string.description_smb_auto_isf)
|
||||||
|
.setDefault(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun specialEnableCondition(): Boolean = buildHelper.isEngineeringMode() && buildHelper.isDev()
|
||||||
|
|
||||||
|
override fun provideDetermineBasalAdapter(): DetermineBasalAdapterInterface = DetermineBasalAdapterSMBAutoISFJS(ScriptReader(context), injector)
|
||||||
|
}
|
|
@ -96,7 +96,6 @@ class TddCalculator @Inject constructor(
|
||||||
//result.put(midnight, tdd)
|
//result.put(midnight, tdd)
|
||||||
}
|
}
|
||||||
val calculationStep = T.mins(5).msecs()
|
val calculationStep = T.mins(5).msecs()
|
||||||
val tempBasals = iobCobCalculator.getTempBasalIncludingConvertedExtendedForRange(startTime, endTime, calculationStep)
|
|
||||||
for (t in startTime until endTime step calculationStep) {
|
for (t in startTime until endTime step calculationStep) {
|
||||||
|
|
||||||
//val midnight = MidnightTime.calc(t)
|
//val midnight = MidnightTime.calc(t)
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
<string name="description_ns_client">Synchronizes your data with Nightscout</string>
|
<string name="description_ns_client">Synchronizes your data with Nightscout</string>
|
||||||
<string name="description_ama">State of the algorithm in 2017</string>
|
<string name="description_ama">State of the algorithm in 2017</string>
|
||||||
<string name="description_smb">Most recent algorithm for advanced users</string>
|
<string name="description_smb">Most recent algorithm for advanced users</string>
|
||||||
|
<string name="description_smb_auto_isf">Most recent algorithm for advanced users with automatic ISF</string>
|
||||||
<string name="description_overview">Displays the current state of your loop and buttons for most common actions</string>
|
<string name="description_overview">Displays the current state of your loop and buttons for most common actions</string>
|
||||||
<string name="description_persistent_notification">Shows an ongoing notification with a short overview of what your loop is doing</string>
|
<string name="description_persistent_notification">Shows an ongoing notification with a short overview of what your loop is doing</string>
|
||||||
<string name="description_profile_local">Define a profile which is available offline.</string>
|
<string name="description_profile_local">Define a profile which is available offline.</string>
|
||||||
|
@ -535,6 +536,7 @@
|
||||||
<string name="ns_localbroadcasts">Enable broadcasts to other apps (like xDrip+). Do not enable if you have more than one instance of AAPS or NSClient installed!</string>
|
<string name="ns_localbroadcasts">Enable broadcasts to other apps (like xDrip+). Do not enable if you have more than one instance of AAPS or NSClient installed!</string>
|
||||||
<string name="ns_localbroadcasts_title">Enable local Broadcasts.</string>
|
<string name="ns_localbroadcasts_title">Enable local Broadcasts.</string>
|
||||||
<string name="openapssmb">OpenAPS SMB</string>
|
<string name="openapssmb">OpenAPS SMB</string>
|
||||||
|
<string name="openapssmbautoisf">OpenAPS SMB Auto ISF</string>
|
||||||
<string name="key_use_smb" translatable="false">use_smb</string>
|
<string name="key_use_smb" translatable="false">use_smb</string>
|
||||||
<string name="key_use_uam" translatable="false">use_uam</string>
|
<string name="key_use_uam" translatable="false">use_uam</string>
|
||||||
<string name="key_smb_enable_carbs_suggestions_threshold" translatable="false">smb_enable_carbs_suggestions_threshold</string>
|
<string name="key_smb_enable_carbs_suggestions_threshold" translatable="false">smb_enable_carbs_suggestions_threshold</string>
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package info.nightscout.androidaps.interfaces
|
package info.nightscout.androidaps.interfaces
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||||
|
|
||||||
interface APS {
|
interface APS {
|
||||||
|
|
||||||
val lastAPSResult: APSResult?
|
val lastAPSResult: APSResult?
|
||||||
val lastAPSRun: Long
|
val lastAPSRun: Long
|
||||||
|
var lastDetermineBasalAdapter: DetermineBasalAdapterInterface?
|
||||||
|
var lastAutosensResult: AutosensResult
|
||||||
|
|
||||||
operator fun invoke(initiator: String, tempBasalFallback: Boolean)
|
operator fun invoke(initiator: String, tempBasalFallback: Boolean)
|
||||||
}
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package info.nightscout.androidaps.interfaces
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
|
import info.nightscout.androidaps.data.MealData
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
|
|
||||||
|
interface DetermineBasalAdapterInterface {
|
||||||
|
|
||||||
|
var currentTempParam: String?
|
||||||
|
var iobDataParam: String?
|
||||||
|
var glucoseStatusParam: String?
|
||||||
|
var profileParam: String?
|
||||||
|
var mealDataParam: String?
|
||||||
|
var scriptDebug: String
|
||||||
|
|
||||||
|
fun setData(profile: Profile,
|
||||||
|
maxIob: Double,
|
||||||
|
maxBasal: Double,
|
||||||
|
minBg: Double,
|
||||||
|
maxBg: Double,
|
||||||
|
targetBg: Double,
|
||||||
|
basalRate: Double,
|
||||||
|
iobArray: Array<IobTotal>,
|
||||||
|
glucoseStatus: GlucoseStatus,
|
||||||
|
mealData: MealData,
|
||||||
|
autosensDataRatio: Double,
|
||||||
|
tempTargetSet: Boolean,
|
||||||
|
microBolusAllowed: Boolean = false,
|
||||||
|
uamAllowed: Boolean = false,
|
||||||
|
advancedFiltering: Boolean = false,
|
||||||
|
isSaveCgmSource: Boolean = false
|
||||||
|
) {}
|
||||||
|
|
||||||
|
operator fun invoke(): APSResult?
|
||||||
|
}
|
|
@ -35,5 +35,5 @@ class PluginDescription {
|
||||||
fun enableByDefault(enableByDefault: Boolean): PluginDescription = this.also { it.enableByDefault = enableByDefault }
|
fun enableByDefault(enableByDefault: Boolean): PluginDescription = this.also { it.enableByDefault = enableByDefault }
|
||||||
fun visibleByDefault(visibleByDefault: Boolean): PluginDescription = this.also { it.visibleByDefault = visibleByDefault }
|
fun visibleByDefault(visibleByDefault: Boolean): PluginDescription = this.also { it.visibleByDefault = visibleByDefault }
|
||||||
fun description(description: Int): PluginDescription = this.also { it.description = description }
|
fun description(description: Int): PluginDescription = this.also { it.description = description }
|
||||||
fun setDefault(): PluginDescription = this.also { it.defaultPlugin = true }
|
fun setDefault(value: Boolean = true): PluginDescription = this.also { it.defaultPlugin = value }
|
||||||
}
|
}
|
Loading…
Reference in a new issue