Merge remote-tracking branch 'ns/dev' into dev

This commit is contained in:
Milos Kozak 2021-02-28 11:18:37 +01:00
commit cb2d623923
283 changed files with 4346 additions and 1254 deletions

View file

@ -100,6 +100,7 @@ def allCommitted = { ->
tasks.matching { it instanceof Test }.all {
testLogging.events = ["failed", "skipped", "started"]
// testLogging.events = ["failed", "skipped", "started", "standard_out"] use to display stdout in travis
testLogging.exceptionFormat = "full"
}

View file

@ -1,220 +0,0 @@
package info.nightscout.androidaps.plugins.sensitivity;
import androidx.annotation.NonNull;
import androidx.collection.LongSparseArray;
import androidx.annotation.NonNull;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
/**
* Created by mike on 24.06.2017.
*/
@Singleton
public class SensitivityAAPSPlugin extends AbstractSensitivityPlugin {
private final ProfileFunction profileFunction;
private final DateUtil dateUtil;
@Inject
public SensitivityAAPSPlugin(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
ResourceHelper resourceHelper,
SP sp,
ProfileFunction profileFunction,
DateUtil dateUtil
) {
super(new PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityaaps)
.shortName(R.string.sensitivity_shortname)
.preferencesId(R.xml.pref_absorption_aaps)
.description(R.string.description_sensitivity_aaps),
injector, aapsLogger, resourceHelper, sp
);
this.profileFunction = profileFunction;
this.dateUtil = dateUtil;
}
@NonNull @Override
public AutosensResult detectSensitivity(IobCobCalculatorInterface iobCobCalculatorPlugin, long fromTime, long toTime) {
LongSparseArray<AutosensData> autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
String age = getSp().getString(R.string.key_age, "");
int defaultHours = 24;
if (age.equals(getResourceHelper().gs(R.string.key_adult))) defaultHours = 24;
if (age.equals(getResourceHelper().gs(R.string.key_teenage))) defaultHours = 4;
if (age.equals(getResourceHelper().gs(R.string.key_child))) defaultHours = 4;
int hoursForDetection = getSp().getInt(R.string.key_openapsama_autosens_period, defaultHours);
Profile profile = profileFunction.getProfile();
if (profile == null) {
getAapsLogger().error("No profile");
return new AutosensResult();
}
if (autosensDataTable == null || autosensDataTable.size() < 4) {
getAapsLogger().debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + iobCobCalculatorPlugin.lastDataTime());
return new AutosensResult();
}
AutosensData current = iobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
if (current == null) {
getAapsLogger().debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + iobCobCalculatorPlugin.lastDataTime());
return new AutosensResult();
}
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<ProfileSwitch> profileSwitches = MainApp.getDbHelper().getProfileSwitchEventsFromTime(fromTime, true);
List<Double> deviationsArray = new ArrayList<>();
String pastSensitivity = "";
int index = 0;
while (index < autosensDataTable.size()) {
AutosensData autosensData = autosensDataTable.valueAt(index);
if (autosensData.time < fromTime) {
index++;
continue;
}
if (autosensData.time > toTime) {
index++;
continue;
}
// reset deviations after site change
if (new CareportalEvent(getInjector()).isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
// reset deviations after profile switch
if (new ProfileSwitch(getInjector()).isEvent5minBack(profileSwitches, autosensData.time, true)) {
deviationsArray.clear();
pastSensitivity += "(PROFILESWITCH)";
}
double deviation = autosensData.deviation;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
if (autosensData.validDeviation)
if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L)
deviationsArray.add(deviation);
if (deviationsArray.size() > hoursForDetection * 60 / 5)
deviationsArray.remove(0);
pastSensitivity += autosensData.pastSensitivity;
int secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time);
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")";
}
index++;
}
Double[] deviations = new Double[deviationsArray.size()];
deviations = deviationsArray.toArray(deviations);
double sens = profile.getIsfMgdl();
String ratioLimit = "";
String sensResult = "";
getAapsLogger().debug(LTag.AUTOSENS, "Records: " + index + " " + pastSensitivity);
Arrays.sort(deviations);
double percentile = IobCobCalculatorPlugin.Companion.percentile(deviations, 0.50);
double basalOff = percentile * (60.0 / 5.0) / sens;
double ratio = 1 + (basalOff / profile.getMaxDailyBasal());
if (percentile < 0) { // sensitive
sensResult = "Excess insulin sensitivity detected";
} else if (percentile > 0) { // resistant
sensResult = "Excess insulin resistance detected";
} else {
sensResult = "Sensitivity normal";
}
getAapsLogger().debug(LTag.AUTOSENS, sensResult);
AutosensResult output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, deviationsArray.size());
getAapsLogger().debug(LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob);
getAapsLogger().debug(LTag.AUTOSENS, "Sensitivity to: deviations " + Arrays.toString(deviations));
return output;
}
@NonNull @Override public SensitivityType getId() {
return SensitivityType.SENSITIVITY_AAPS;
}
@NonNull @Override public JSONObject configuration() {
JSONObject c = new JSONObject();
try {
c.put(getResourceHelper().gs(R.string.key_absorption_maxtime), getSp().getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_period), getSp().getInt(R.string.key_openapsama_autosens_period, 24));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_max), getSp().getDouble(R.string.key_openapsama_autosens_max, 1.2));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_min), getSp().getDouble(R.string.key_openapsama_autosens_min, 0.7));
} catch (JSONException e) {
e.printStackTrace();
}
return c;
}
@Override public void applyConfiguration(@NonNull JSONObject configuration) {
try {
if (configuration.has(getResourceHelper().gs(R.string.key_absorption_maxtime)))
getSp().putDouble(R.string.key_absorption_maxtime, configuration.getDouble(getResourceHelper().gs(R.string.key_absorption_maxtime)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_period)))
getSp().putDouble(R.string.key_openapsama_autosens_period, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_period)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_max)))
getSp().getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_max)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_min)))
getSp().getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_min)));
} catch (JSONException e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,161 @@
package info.nightscout.androidaps.plugins.sensitivity
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.SensitivityInterface.SensitivityType
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.roundToInt
@Singleton
open class SensitivityAAPSPlugin @Inject constructor(
injector: HasAndroidInjector?,
aapsLogger: AAPSLogger?,
resourceHelper: ResourceHelper?,
sp: SP?,
private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil
) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityaaps)
.shortName(R.string.sensitivity_shortname)
.preferencesId(R.xml.pref_absorption_aaps)
.description(R.string.description_sensitivity_aaps),
injector!!, aapsLogger!!, resourceHelper!!, sp!!
) {
override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult {
val autosensDataTable = plugin.getAutosensDataTable()
val age = sp.getString(R.string.key_age, "")
var defaultHours = 24
if (age == resourceHelper.gs(R.string.key_adult)) defaultHours = 24
if (age == resourceHelper.gs(R.string.key_teenage)) defaultHours = 4
if (age == resourceHelper.gs(R.string.key_child)) defaultHours = 4
val hoursForDetection = sp.getInt(R.string.key_openapsama_autosens_period, defaultHours)
val profile = profileFunction.getProfile()
if (profile == null) {
aapsLogger.error("No profile")
return AutosensResult()
}
if (autosensDataTable.size() < 4) {
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + plugin.lastDataTime())
return AutosensResult()
}
val current = plugin.getAutosensData(toTime) // this is running inside lock already
if (current == null) {
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime())
return AutosensResult()
}
val siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true)
val profileSwitches = MainApp.getDbHelper().getProfileSwitchEventsFromTime(fromTime, true)
val deviationsArray: MutableList<Double> = ArrayList()
var pastSensitivity = ""
var index = 0
while (index < autosensDataTable.size()) {
val autosensData = autosensDataTable.valueAt(index)
if (autosensData.time < fromTime) {
index++
continue
}
if (autosensData.time > toTime) {
index++
continue
}
// reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear()
pastSensitivity += "(SITECHANGE)"
}
// reset deviations after profile switch
if (ProfileSwitch(injector).isEvent5minBack(profileSwitches, autosensData.time, true)) {
deviationsArray.clear()
pastSensitivity += "(PROFILESWITCH)"
}
var deviation = autosensData.deviation
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0) deviation = 0.0
if (autosensData.validDeviation) if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L) deviationsArray.add(deviation)
if (deviationsArray.size > hoursForDetection * 60 / 5) deviationsArray.removeAt(0)
pastSensitivity += autosensData.pastSensitivity
val secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time)
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
pastSensitivity += "(" + (secondsFromMidnight / 3600.0).roundToInt() + ")"
}
index++
}
val deviations = Array(deviationsArray.size) { i -> deviationsArray[i] }
val sens = profile.isfMgdl
val ratioLimit = ""
val sensResult: String
aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity")
Arrays.sort(deviations)
val percentile = percentile(deviations, 0.50)
val basalOff = percentile * (60.0 / 5.0) / sens
val ratio = 1 + basalOff / profile.maxDailyBasal
sensResult = when {
percentile < 0 -> "Excess insulin sensitivity detected"
percentile > 0 -> "Excess insulin resistance detected"
else -> "Sensitivity normal"
}
aapsLogger.debug(LTag.AUTOSENS, sensResult)
val output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, deviationsArray.size)
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob)
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity to: deviations " + deviations.contentToString())
return output
}
override val id: SensitivityType
get() = SensitivityType.SENSITIVITY_AAPS
override fun configuration(): JSONObject {
val c = JSONObject()
try {
c.put(resourceHelper.gs(R.string.key_absorption_maxtime), sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_period), sp.getInt(R.string.key_openapsama_autosens_period, 24))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_max), sp.getDouble(R.string.key_openapsama_autosens_max, 1.2))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_min), sp.getDouble(R.string.key_openapsama_autosens_min, 0.7))
} catch (e: JSONException) {
e.printStackTrace()
}
return c
}
override fun applyConfiguration(configuration: JSONObject) {
try {
if (configuration.has(resourceHelper.gs(R.string.key_absorption_maxtime))) sp.putDouble(R.string.key_absorption_maxtime, configuration.getDouble(resourceHelper.gs(R.string.key_absorption_maxtime)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_period))) sp.putDouble(R.string.key_openapsama_autosens_period, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_period)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_max)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_min)))
} catch (e: JSONException) {
e.printStackTrace()
}
}
}

View file

@ -1,286 +0,0 @@
package info.nightscout.androidaps.plugins.sensitivity;
import androidx.collection.LongSparseArray;
import androidx.annotation.NonNull;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
/**
* Created by mike on 19.06.2018.
*/
@Singleton
public class SensitivityOref1Plugin extends AbstractSensitivityPlugin {
private final ProfileFunction profileFunction;
private final DateUtil dateUtil;
@Inject
public SensitivityOref1Plugin(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
ResourceHelper resourceHelper,
SP sp,
ProfileFunction profileFunction,
DateUtil dateUtil
) {
super(new PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityoref1)
.shortName(R.string.sensitivity_shortname)
.enableByDefault(true)
.preferencesId(R.xml.pref_absorption_oref1)
.description(R.string.description_sensitivity_oref1)
.setDefault(),
injector, aapsLogger, resourceHelper, sp
);
this.profileFunction = profileFunction;
this.dateUtil = dateUtil;
}
@NonNull @Override
public AutosensResult detectSensitivity(IobCobCalculatorInterface iobCobCalculatorPlugin, long fromTime, long toTime) {
// todo this method is called from the IobCobCalculatorPlugin, which leads to a circular
// dependency, this should be avoided
LongSparseArray<AutosensData> autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
Profile profile = profileFunction.getProfile();
if (profile == null) {
getAapsLogger().error("No profile");
return new AutosensResult();
}
if (autosensDataTable == null || autosensDataTable.size() < 4) {
getAapsLogger().debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + iobCobCalculatorPlugin.lastDataTime());
return new AutosensResult();
}
// the current
AutosensData current = iobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
if (current == null) {
getAapsLogger().debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + iobCobCalculatorPlugin.lastDataTime());
return new AutosensResult();
}
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<ProfileSwitch> profileSwitches = MainApp.getDbHelper().getProfileSwitchEventsFromTime(fromTime, true);
//[0] = 8 hour
//[1] = 24 hour
//Deviationshour has DeviationsArray
List<ArrayList<Double>> deviationsHour = Arrays.asList(new ArrayList<>(), new ArrayList<>());
List<String> pastSensitivityArray = Arrays.asList("", "");
List<String> sensResultArray = Arrays.asList("", "");
List<Double> ratioArray = Arrays.asList(0d, 0d);
List<Double> deviationCategory = Arrays.asList(96d, 288d);
List<String> ratioLimitArray = Arrays.asList("", "");
List<Double> hoursDetection = Arrays.asList(8d, 24d);
int index = 0;
while (index < autosensDataTable.size()) {
AutosensData autosensData = autosensDataTable.valueAt(index);
if (autosensData.time < fromTime) {
index++;
continue;
}
if (autosensData.time > toTime) {
index++;
continue;
}
int hoursegment = 0;
//hoursegment = 0 = 8 hour
//hoursegment = 1 = 24 hour
while (hoursegment < deviationsHour.size()) {
ArrayList<Double> deviationsArray = deviationsHour.get(hoursegment);
String pastSensitivity = pastSensitivityArray.get(hoursegment);
// reset deviations after site change
if (new CareportalEvent(getInjector()).isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
// reset deviations after profile switch
if (new ProfileSwitch(getInjector()).isEvent5minBack(profileSwitches, autosensData.time, true)) {
deviationsArray.clear();
pastSensitivity += "(PROFILESWITCH)";
}
double deviation = autosensData.deviation;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
if (autosensData.validDeviation)
if (autosensData.time > toTime - hoursDetection.get(hoursegment) * 60 * 60 * 1000L)
deviationsArray.add(deviation);
deviationsArray.addAll(autosensData.extraDeviation);
if (deviationsArray.size() > deviationCategory.get(hoursegment)) {
deviationsArray.remove(0);
}
pastSensitivity += autosensData.pastSensitivity;
int secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time);
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")";
}
//Update the data back to the parent
deviationsHour.set(hoursegment, deviationsArray);
pastSensitivityArray.set(hoursegment, pastSensitivity);
hoursegment++;
}
index++;
}
// when we have less than 8h/24 worth of deviation data, add up to 90m of zero deviations
// this dampens any large sensitivity changes detected based on too little data, without ignoring them completely
for (int i = 0; i < deviationsHour.size(); i++) {
ArrayList<Double> deviations = deviationsHour.get(i);
getAapsLogger().debug(LTag.AUTOSENS, "Using most recent " + deviations.size() + " deviations");
if (deviations.size() < deviationCategory.get(i)) {
int pad = (int) Math.round((1 - (double) deviations.size() / deviationCategory.get(i)) * 18);
getAapsLogger().debug(LTag.AUTOSENS, "Adding " + pad + " more zero deviations");
for (int d = 0; d < pad; d++) {
deviations.add(0d);
}
}
//Update the data back to the parent
deviationsHour.set(i, deviations);
}
int hourused = 0;
while (hourused < deviationsHour.size()) {
ArrayList deviationsArray = deviationsHour.get(hourused);
String pastSensitivity = pastSensitivityArray.get(hourused);
String sensResult = "(8 hours) ";
if (hourused == 1) sensResult = "(24 hours) ";
String ratioLimit = "";
Double[] deviations = new Double[deviationsArray.size()];
deviations = (Double[]) deviationsArray.toArray(deviations);
double sens = profile.getIsfMgdl();
getAapsLogger().debug(LTag.AUTOSENS, "Records: " + index + " " + pastSensitivity);
Arrays.sort(deviations);
double pSensitive = IobCobCalculatorPlugin.Companion.percentile(deviations, 0.50);
double pResistant = IobCobCalculatorPlugin.Companion.percentile(deviations, 0.50);
double basalOff = 0;
if (pSensitive < 0) { // sensitive
basalOff = pSensitive * (60.0 / 5) / sens;
sensResult += "Excess insulin sensitivity detected";
} else if (pResistant > 0) { // resistant
basalOff = pResistant * (60.0 / 5) / sens;
sensResult += "Excess insulin resistance detected";
} else {
sensResult += "Sensitivity normal";
}
getAapsLogger().debug(LTag.AUTOSENS, sensResult);
double ratio = 1 + (basalOff / profile.getMaxDailyBasal());
//Update the data back to the parent
sensResultArray.set(hourused, sensResult);
ratioArray.set(hourused, ratio);
ratioLimitArray.set(hourused, ratioLimit);
hourused++;
}
int key = 1;
String comparison = " 8 h ratio " + ratioArray.get(0) + " vs 24h ratio " + ratioArray.get(1);
//use 24 hour ratio by default
//if the 8 hour ratio is less than the 24 hour ratio, the 8 hour ratio is used
if (ratioArray.get(0) < ratioArray.get(1)) {
key = 0;
}
//String message = hoursDetection.get(key) + " of sensitivity used";
AutosensResult output = fillResult(ratioArray.get(key), current.cob, pastSensitivityArray.get(key), ratioLimitArray.get(key),
sensResultArray.get(key) + comparison, deviationsHour.get(key).size());
getAapsLogger().debug(LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob);
return output;
}
@NonNull @Override public JSONObject configuration() {
JSONObject c = new JSONObject();
try {
c.put(getResourceHelper().gs(R.string.key_openapsama_min_5m_carbimpact), getSp().getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
c.put(getResourceHelper().gs(R.string.key_absorption_cutoff), getSp().getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_max), getSp().getDouble(R.string.key_openapsama_autosens_max, 1.2));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_min), getSp().getDouble(R.string.key_openapsama_autosens_min, 0.7));
} catch (JSONException e) {
e.printStackTrace();
}
return c;
}
@Override public void applyConfiguration(@NonNull JSONObject configuration) {
try {
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_min_5m_carbimpact)))
getSp().putDouble(R.string.key_openapsama_min_5m_carbimpact, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_min_5m_carbimpact)));
if (configuration.has(getResourceHelper().gs(R.string.key_absorption_cutoff)))
getSp().putDouble(R.string.key_absorption_cutoff, configuration.getDouble(getResourceHelper().gs(R.string.key_absorption_cutoff)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_max)))
getSp().getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_max)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_min)))
getSp().getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_min)));
} catch (JSONException e) {
e.printStackTrace();
}
}
@NonNull @Override public SensitivityType getId() {
return SensitivityType.SENSITIVITY_OREF1;
}
}

View file

@ -0,0 +1,228 @@
package info.nightscout.androidaps.plugins.sensitivity
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.SensitivityInterface.SensitivityType
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.roundToInt
@Singleton
open class SensitivityOref1Plugin @Inject constructor(
injector: HasAndroidInjector?,
aapsLogger: AAPSLogger?,
resourceHelper: ResourceHelper?,
sp: SP?,
private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil
) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityoref1)
.shortName(R.string.sensitivity_shortname)
.enableByDefault(true)
.preferencesId(R.xml.pref_absorption_oref1)
.description(R.string.description_sensitivity_oref1)
.setDefault(),
injector!!, aapsLogger!!, resourceHelper!!, sp!!
) {
override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult {
// todo this method is called from the IobCobCalculatorPlugin, which leads to a circular
// dependency, this should be avoided
val autosensDataTable = plugin.getAutosensDataTable()
val profile = profileFunction.getProfile()
if (profile == null) {
aapsLogger.error("No profile")
return AutosensResult()
}
if (autosensDataTable.size() < 4) {
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + plugin.lastDataTime())
return AutosensResult()
}
// the current
val current = plugin.getAutosensData(toTime) // this is running inside lock already
if (current == null) {
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime())
return AutosensResult()
}
val siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true)
val profileSwitches = MainApp.getDbHelper().getProfileSwitchEventsFromTime(fromTime, true)
//[0] = 8 hour
//[1] = 24 hour
//deviationsHour has DeviationsArray
val deviationsHour = mutableListOf(ArrayList<Double>(), ArrayList<Double>())
val pastSensitivityArray = mutableListOf("", "")
val sensResultArray = mutableListOf("", "")
val ratioArray = mutableListOf(0.0, 0.0)
val deviationCategory = listOf(96.0, 288.0)
val ratioLimitArray = mutableListOf("", "")
val hoursDetection = listOf(8.0, 24.0)
var index = 0
while (index < autosensDataTable.size()) {
val autosensData = autosensDataTable.valueAt(index)
if (autosensData.time < fromTime) {
index++
continue
}
if (autosensData.time > toTime) {
index++
continue
}
var hourSegment = 0
//hourSegment = 0 = 8 hour
//hourSegment = 1 = 24 hour
while (hourSegment < deviationsHour.size) {
val deviationsArray = deviationsHour[hourSegment]
var pastSensitivity = pastSensitivityArray[hourSegment]
// reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear()
pastSensitivity += "(SITECHANGE)"
}
// reset deviations after profile switch
if (ProfileSwitch(injector).isEvent5minBack(profileSwitches, autosensData.time, true)) {
deviationsArray.clear()
pastSensitivity += "(PROFILESWITCH)"
}
var deviation = autosensData.deviation
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0) deviation = 0.0
if (autosensData.validDeviation) if (autosensData.time > toTime - hoursDetection[hourSegment] * 60 * 60 * 1000L) deviationsArray.add(deviation)
deviationsArray.addAll(autosensData.extraDeviation)
if (deviationsArray.size > deviationCategory[hourSegment]) {
deviationsArray.removeAt(0)
}
pastSensitivity += autosensData.pastSensitivity
val secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time)
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
pastSensitivity += "(" + (secondsFromMidnight / 3600.0).roundToInt() + ")"
}
//Update the data back to the parent
deviationsHour[hourSegment] = deviationsArray
pastSensitivityArray[hourSegment] = pastSensitivity
hourSegment++
}
index++
}
// when we have less than 8h/24 worth of deviation data, add up to 90m of zero deviations
// this dampens any large sensitivity changes detected based on too little data, without ignoring them completely
for (i in deviationsHour.indices) {
val deviations = deviationsHour[i]
aapsLogger.debug(LTag.AUTOSENS, "Using most recent " + deviations.size + " deviations")
if (deviations.size < deviationCategory[i]) {
val pad = ((1 - deviations.size.toDouble() / deviationCategory[i]) * 18).roundToInt()
aapsLogger.debug(LTag.AUTOSENS, "Adding $pad more zero deviations")
for (d in 0 until pad) {
deviations.add(0.0)
}
}
//Update the data back to the parent
deviationsHour[i] = deviations
}
var hourUsed = 0
while (hourUsed < deviationsHour.size) {
val deviationsArray: ArrayList<Double> = deviationsHour[hourUsed]
val pastSensitivity = pastSensitivityArray[hourUsed]
var sensResult = "(8 hours) "
if (hourUsed == 1) sensResult = "(24 hours) "
val ratioLimit = ""
val deviations: Array<Double> = Array(deviationsArray.size) { i -> deviationsArray[i] }
val sens = profile.isfMgdl
aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity")
Arrays.sort(deviations)
val pSensitive = percentile(deviations, 0.50)
val pResistant = percentile(deviations, 0.50)
var basalOff = 0.0
when {
pSensitive < 0 -> { // sensitive
basalOff = pSensitive * (60.0 / 5) / sens
sensResult += "Excess insulin sensitivity detected"
}
pResistant > 0 -> { // resistant
basalOff = pResistant * (60.0 / 5) / sens
sensResult += "Excess insulin resistance detected"
}
else -> sensResult += "Sensitivity normal"
}
aapsLogger.debug(LTag.AUTOSENS, sensResult)
val ratio = 1 + basalOff / profile.maxDailyBasal
//Update the data back to the parent
sensResultArray[hourUsed] = sensResult
ratioArray[hourUsed] = ratio
ratioLimitArray[hourUsed] = ratioLimit
hourUsed++
}
var key = 1
val comparison = " 8 h ratio " + ratioArray[0] + " vs 24h ratio " + ratioArray[1]
//use 24 hour ratio by default
//if the 8 hour ratio is less than the 24 hour ratio, the 8 hour ratio is used
if (ratioArray[0] < ratioArray[1]) {
key = 0
}
//String message = hoursDetection.get(key) + " of sensitivity used";
val output = fillResult(ratioArray[key], current.cob, pastSensitivityArray[key], ratioLimitArray[key], sensResultArray[key] + comparison, deviationsHour[key].size)
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob)
return output
}
override fun configuration(): JSONObject {
val c = JSONObject()
try {
c.put(resourceHelper.gs(R.string.key_openapsama_min_5m_carbimpact), sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact))
c.put(resourceHelper.gs(R.string.key_absorption_cutoff), sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_max), sp.getDouble(R.string.key_openapsama_autosens_max, 1.2))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_min), sp.getDouble(R.string.key_openapsama_autosens_min, 0.7))
} catch (e: JSONException) {
e.printStackTrace()
}
return c
}
override fun applyConfiguration(configuration: JSONObject) {
try {
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_min_5m_carbimpact))) sp.putDouble(R.string.key_openapsama_min_5m_carbimpact, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_min_5m_carbimpact)))
if (configuration.has(resourceHelper.gs(R.string.key_absorption_cutoff))) sp.putDouble(R.string.key_absorption_cutoff, configuration.getDouble(resourceHelper.gs(R.string.key_absorption_cutoff)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_max)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_min)))
} catch (e: JSONException) {
e.printStackTrace()
}
}
override val id: SensitivityType
get() = SensitivityType.SENSITIVITY_OREF1
}

View file

@ -1,240 +0,0 @@
package info.nightscout.androidaps.plugins.sensitivity;
import androidx.collection.LongSparseArray;
import androidx.annotation.NonNull;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
/**
* Created by mike on 24.06.2017.
*/
@Singleton
public class SensitivityWeightedAveragePlugin extends AbstractSensitivityPlugin {
private final SP sp;
private final DateUtil dateUtil;
private final ProfileFunction profileFunction;
@Inject
public SensitivityWeightedAveragePlugin(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
ResourceHelper resourceHelper,
SP sp,
ProfileFunction profileFunction,
DateUtil dateUtil
) {
super(new PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityweightedaverage)
.shortName(R.string.sensitivity_shortname)
.preferencesId(R.xml.pref_absorption_aaps)
.description(R.string.description_sensitivity_weighted_average),
injector, aapsLogger, resourceHelper, sp
);
this.sp = sp;
this.dateUtil = dateUtil;
this.profileFunction = profileFunction;
}
@Override
public AutosensResult detectSensitivity(IobCobCalculatorInterface iobCobCalculatorPlugin, long fromTime, long toTime) {
LongSparseArray<AutosensData> autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
String age = sp.getString(R.string.key_age, "");
int defaultHours = 24;
if (age.equals(getResourceHelper().gs(R.string.key_adult))) defaultHours = 24;
if (age.equals(getResourceHelper().gs(R.string.key_teenage))) defaultHours = 4;
if (age.equals(getResourceHelper().gs(R.string.key_child))) defaultHours = 4;
int hoursForDetection = sp.getInt(R.string.key_openapsama_autosens_period, defaultHours);
if (autosensDataTable == null || autosensDataTable.size() < 4) {
getAapsLogger().debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + iobCobCalculatorPlugin.lastDataTime());
return new AutosensResult();
}
AutosensData current = iobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
if (current == null) {
getAapsLogger().debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + iobCobCalculatorPlugin.lastDataTime());
return new AutosensResult();
}
Profile profile = profileFunction.getProfile();
if (profile == null) {
getAapsLogger().debug(LTag.AUTOSENS, "No profile available");
return new AutosensResult();
}
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<ProfileSwitch> profileSwitches = MainApp.getDbHelper().getProfileSwitchEventsFromTime(fromTime, true);
String pastSensitivity = "";
int index = 0;
LongSparseArray<Double> data = new LongSparseArray<>();
while (index < autosensDataTable.size()) {
AutosensData autosensData = autosensDataTable.valueAt(index);
if (autosensData.time < fromTime) {
index++;
continue;
}
if (autosensData.time > toTime) {
index++;
continue;
}
if (autosensData.time < toTime - hoursForDetection * 60 * 60 * 1000L) {
index++;
continue;
}
// reset deviations after site change
if (new CareportalEvent(getInjector()).isEvent5minBack(siteChanges, autosensData.time)) {
data.clear();
pastSensitivity += "(SITECHANGE)";
}
// reset deviations after profile switch
if (new ProfileSwitch(getInjector()).isEvent5minBack(profileSwitches, autosensData.time, true)) {
data.clear();
pastSensitivity += "(PROFILESWITCH)";
}
double deviation = autosensData.deviation;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
//data.append(autosensData.time);
long reverseWeight = (toTime - autosensData.time) / (5 * 60 * 1000L);
if (autosensData.validDeviation)
data.append(reverseWeight, deviation);
//weights += reverseWeight;
//weightedsum += reverseWeight * (autosensData.validDeviation ? autosensData.deviation : 0d);
pastSensitivity += autosensData.pastSensitivity;
int secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time);
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")";
}
index++;
}
if (data.size() == 0) {
getAapsLogger().debug(LTag.AUTOSENS, "Data size: " + data.size() + " fromTime: " + dateUtil.dateAndTimeString(fromTime) + " toTime: " + dateUtil.dateAndTimeString(toTime));
return new AutosensResult();
} else {
getAapsLogger().debug(LTag.AUTOSENS, "Data size: " + data.size() + " fromTime: " + dateUtil.dateAndTimeString(fromTime) + " toTime: " + dateUtil.dateAndTimeString(toTime));
}
double weightedsum = 0;
double weights = 0;
long hightestWeight = data.keyAt(data.size() - 1);
for (int i = 0; i < data.size(); i++) {
long reversedWeigth = data.keyAt(i);
double value = data.valueAt(i);
double weight = (hightestWeight - reversedWeigth) / 2.0;
weights += weight;
weightedsum += weight * value;
}
if (weights == 0) {
return new AutosensResult();
}
double sens = profile.getIsfMgdl();
String ratioLimit = "";
String sensResult;
getAapsLogger().debug(LTag.AUTOSENS, "Records: " + index + " " + pastSensitivity);
double average = weightedsum / weights;
double basalOff = average * (60 / 5.0) / sens;
double ratio = 1 + (basalOff / profile.getMaxDailyBasal());
if (average < 0) { // sensitive
sensResult = "Excess insulin sensitivity detected";
} else if (average > 0) { // resistant
sensResult = "Excess insulin resistance detected";
} else {
sensResult = "Sensitivity normal";
}
getAapsLogger().debug(LTag.AUTOSENS, sensResult);
AutosensResult output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, data.size());
getAapsLogger().debug(LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob);
return output;
}
@NonNull @Override public SensitivityType getId() {
return SensitivityType.SENSITIVITY_WEIGHTED;
}
@NonNull @Override public JSONObject configuration() {
JSONObject c = new JSONObject();
try {
c.put(getResourceHelper().gs(R.string.key_absorption_maxtime), getSp().getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_period), getSp().getInt(R.string.key_openapsama_autosens_period, 24));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_max), getSp().getDouble(R.string.key_openapsama_autosens_max, 1.2));
c.put(getResourceHelper().gs(R.string.key_openapsama_autosens_min), getSp().getDouble(R.string.key_openapsama_autosens_min, 0.7));
} catch (JSONException e) {
e.printStackTrace();
}
return c;
}
@Override public void applyConfiguration(@NonNull JSONObject configuration) {
try {
if (configuration.has(getResourceHelper().gs(R.string.key_absorption_maxtime)))
getSp().putDouble(R.string.key_absorption_maxtime, configuration.getDouble(getResourceHelper().gs(R.string.key_absorption_maxtime)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_period)))
getSp().putDouble(R.string.key_openapsama_autosens_period, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_period)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_max)))
getSp().getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_max)));
if (configuration.has(getResourceHelper().gs(R.string.key_openapsama_autosens_min)))
getSp().getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(getResourceHelper().gs(R.string.key_openapsama_autosens_min)));
} catch (JSONException e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,181 @@
package info.nightscout.androidaps.plugins.sensitivity
import androidx.collection.LongSparseArray
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.SensitivityInterface.SensitivityType
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.roundToInt
@Singleton
open class SensitivityWeightedAveragePlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
sp: SP,
private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil
) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityweightedaverage)
.shortName(R.string.sensitivity_shortname)
.preferencesId(R.xml.pref_absorption_aaps)
.description(R.string.description_sensitivity_weighted_average),
injector, aapsLogger, resourceHelper, sp
) {
override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult {
val autosensDataTable = plugin.getAutosensDataTable()
val age = sp.getString(R.string.key_age, "")
var defaultHours = 24
if (age == resourceHelper.gs(R.string.key_adult)) defaultHours = 24
if (age == resourceHelper.gs(R.string.key_teenage)) defaultHours = 4
if (age == resourceHelper.gs(R.string.key_child)) defaultHours = 4
val hoursForDetection = sp.getInt(R.string.key_openapsama_autosens_period, defaultHours)
if (autosensDataTable.size() < 4) {
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + plugin.lastDataTime())
return AutosensResult()
}
val current = plugin.getAutosensData(toTime) // this is running inside lock already
if (current == null) {
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime())
return AutosensResult()
}
val profile = profileFunction.getProfile()
if (profile == null) {
aapsLogger.debug(LTag.AUTOSENS, "No profile available")
return AutosensResult()
}
val siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true)
val profileSwitches = MainApp.getDbHelper().getProfileSwitchEventsFromTime(fromTime, true)
var pastSensitivity = ""
var index = 0
val data = LongSparseArray<Double>()
while (index < autosensDataTable.size()) {
val autosensData = autosensDataTable.valueAt(index)
if (autosensData.time < fromTime) {
index++
continue
}
if (autosensData.time > toTime) {
index++
continue
}
if (autosensData.time < toTime - hoursForDetection * 60 * 60 * 1000L) {
index++
continue
}
// reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) {
data.clear()
pastSensitivity += "(SITECHANGE)"
}
// reset deviations after profile switch
if (ProfileSwitch(injector).isEvent5minBack(profileSwitches, autosensData.time, true)) {
data.clear()
pastSensitivity += "(PROFILESWITCH)"
}
var deviation = autosensData.deviation
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0) deviation = 0.0
//data.append(autosensData.time);
val reverseWeight = (toTime - autosensData.time) / (5 * 60 * 1000L)
if (autosensData.validDeviation) data.append(reverseWeight, deviation)
pastSensitivity += autosensData.pastSensitivity
val secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time)
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
pastSensitivity += "(" + (secondsFromMidnight / 3600.0).roundToInt() + ")"
}
index++
}
if (data.size() == 0) {
aapsLogger.debug(LTag.AUTOSENS, "Data size: " + data.size() + " fromTime: " + dateUtil.dateAndTimeString(fromTime) + " toTime: " + dateUtil.dateAndTimeString(toTime))
return AutosensResult()
} else {
aapsLogger.debug(LTag.AUTOSENS, "Data size: " + data.size() + " fromTime: " + dateUtil.dateAndTimeString(fromTime) + " toTime: " + dateUtil.dateAndTimeString(toTime))
}
var weightedSum = 0.0
var weights = 0.0
val highestWeight = data.keyAt(data.size() - 1)
for (i in 0 until data.size()) {
val reversedWeight = data.keyAt(i)
val value = data.valueAt(i)
val weight = (highestWeight - reversedWeight) / 2.0
weights += weight
weightedSum += weight * value
}
if (weights == 0.0) {
return AutosensResult()
}
val sens = profile.isfMgdl
val ratioLimit = ""
val sensResult: String
aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity")
val average = weightedSum / weights
val basalOff = average * (60 / 5.0) / sens
val ratio = 1 + basalOff / profile.maxDailyBasal
sensResult = when {
average < 0 -> "Excess insulin sensitivity detected"
average > 0 -> "Excess insulin resistance detected"
else -> "Sensitivity normal"
}
aapsLogger.debug(LTag.AUTOSENS, sensResult)
val output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, data.size())
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob)
return output
}
override val id: SensitivityType
get() = SensitivityType.SENSITIVITY_WEIGHTED
override fun configuration(): JSONObject {
val c = JSONObject()
try {
c.put(resourceHelper.gs(R.string.key_absorption_maxtime), sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_period), sp.getInt(R.string.key_openapsama_autosens_period, 24))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_max), sp.getDouble(R.string.key_openapsama_autosens_max, 1.2))
c.put(resourceHelper.gs(R.string.key_openapsama_autosens_min), sp.getDouble(R.string.key_openapsama_autosens_min, 0.7))
} catch (e: JSONException) {
e.printStackTrace()
}
return c
}
override fun applyConfiguration(configuration: JSONObject) {
try {
if (configuration.has(resourceHelper.gs(R.string.key_absorption_maxtime))) sp.putDouble(R.string.key_absorption_maxtime, configuration.getDouble(resourceHelper.gs(R.string.key_absorption_maxtime)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_period))) sp.putDouble(R.string.key_openapsama_autosens_period, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_period)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_max)))
if (configuration.has(resourceHelper.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(resourceHelper.gs(R.string.key_openapsama_autosens_min)))
} catch (e: JSONException) {
e.printStackTrace()
}
}
}

View file

@ -1,40 +0,0 @@
package info.nightscout.androidaps.services;
public interface Intents {
// NSClient -> App
String ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT";
String ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT";
String ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT";
String ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE";
String ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV";
String ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG";
String ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL";
// xDrip -> App
String ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate";
String EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate";
String EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope";
String EXTRA_BG_SLOPE_NAME = "com.eveningoutpost.dexdrip.Extras.BgSlopeName";
String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw";
String XDRIP_DATA_SOURCE_DESCRIPTION = "com.eveningoutpost.dexdrip.Extras.SourceDesc";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";
String NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR";
String ACTION_REMOTE_CALIBRATION = "com.eveningoutpost.dexdrip.NewCalibration";
String GLIMP_BG = "it.ct.glicemia.ACTION_GLUCOSE_MEASURED";
String DEXCOM_BG = "com.dexcom.cgm.EXTERNAL_BROADCAST";
String EVERSENSE_BG = "com.senseonics.AndroidAPSEventSubscriber.BROADCAST";
String POCTECH_BG = "com.china.poctech.data";
String TOMATO_BG = "com.fanqies.tomatofn.BgEstimate";
// Broadcast status
String AAPS_BROADCAST = "info.nightscout.androidaps.status";
}

View file

@ -0,0 +1,38 @@
package info.nightscout.androidaps.services
@Suppress("unused")
interface Intents {
companion object {
// NSClient -> App
const val ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT"
const val ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT"
const val ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT"
const val ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE"
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
const val ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG"
const val ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL"
// xDrip -> App
const val ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate"
const val EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate"
const val EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope"
const val EXTRA_BG_SLOPE_NAME = "com.eveningoutpost.dexdrip.Extras.BgSlopeName"
const val EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery"
const val EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time"
const val EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw"
const val XDRIP_DATA_SOURCE_DESCRIPTION = "com.eveningoutpost.dexdrip.Extras.SourceDesc"
const val ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData"
const val NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR"
const val ACTION_REMOTE_CALIBRATION = "com.eveningoutpost.dexdrip.NewCalibration"
const val GLIMP_BG = "it.ct.glicemia.ACTION_GLUCOSE_MEASURED"
const val DEXCOM_BG = "com.dexcom.cgm.EXTERNAL_BROADCAST"
const val EVERSENSE_BG = "com.senseonics.AndroidAPSEventSubscriber.BROADCAST"
const val POCTECH_BG = "com.china.poctech.data"
const val TOMATO_BG = "com.fanqies.tomatofn.BgEstimate"
// Broadcast status
const val AAPS_BROADCAST = "info.nightscout.androidaps.status"
}
}

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.setupwizard;
// keep in java, it's easier
public interface SWNumberValidator {
boolean isValid(double value);
}

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.setupwizard;
// keep in java, it's easier
public interface SWTextValidator {
boolean isValid(String text);
}

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.setupwizard;
// keep in java, it's easier
public interface SWValidator {
boolean isValid();
}

View file

@ -1,248 +0,0 @@
package info.nightscout.androidaps.utils;
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.os.SystemClock;
import org.slf4j.Logger;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import javax.inject.Inject;
import javax.inject.Singleton;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
/**
* {@hide}
* <p>
* Simple SNTP client class for retrieving network time.
* <p>
* Sample usage:
* <pre>SntpClient client = new SntpClient();
* if (client.requestTime("time.foo.com")) {
* long now = client.getNtpTime() + SystemClock.elapsedRealtime() - client.getNtpTimeReference();
* }
* </pre>
*/
@Singleton
public class SntpClient {
private final AAPSLogger aapsLogger;
private final DateUtil dateUtil;
//private final int REFERENCE_TIME_OFFSET = 16;
private final int ORIGINATE_TIME_OFFSET = 24;
private final int RECEIVE_TIME_OFFSET = 32;
private final int TRANSMIT_TIME_OFFSET = 40;
private final int NTP_PACKET_SIZE = 48;
private final int NTP_PORT = 123;
private final int NTP_MODE_CLIENT = 3;
private final int NTP_VERSION = 3;
@Inject
public SntpClient(
AAPSLogger aapsLogger,
DateUtil dateUtil
) {
this.aapsLogger = aapsLogger;
this.dateUtil = dateUtil;
}
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
// system time computed from NTP server response
private long mNtpTime;
// value of SystemClock.elapsedRealtime() corresponding to mNtpTime
private long mNtpTimeReference;
// round trip time in milliseconds
private long mRoundTripTime;
public static abstract class Callback implements Runnable {
public boolean networkConnected = false;
public boolean success = false;
public long time = 0;
}
public synchronized void ntpTime(final Callback callback, boolean isConnected) {
callback.networkConnected = isConnected;
if (callback.networkConnected) {
new Thread(() -> doNtpTime(callback)).start();
} else {
callback.run();
}
}
void doNtpTime(final Callback callback) {
aapsLogger.debug("Time detection started");
callback.success = requestTime("time.google.com", 5000);
callback.time = getNtpTime() + SystemClock.elapsedRealtime() - getNtpTimeReference();
aapsLogger.debug("Time detection ended: " + callback.success + " " + dateUtil.dateAndTimeString(getNtpTime()));
callback.run();
}
/**
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
* @param timeout network timeout in milliseconds.
* @return true if the transaction was successful.
*/
private synchronized boolean requestTime(String host, int timeout) {
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
// set mode = 3 (client) and version = 3
// mode is in low 3 bits of first byte
// version is in bits 3-5 of first byte
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
// get current time and write it to the request packet
long requestTime = System.currentTimeMillis();
long requestTicks = SystemClock.elapsedRealtime();
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);
socket.send(request);
// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
long responseTicks = SystemClock.elapsedRealtime();
long responseTime = requestTime + (responseTicks - requestTicks);
socket.close();
// extract the results
long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
// receiveTime = originateTime + transit + skew
// responseTime = transmitTime + transit - skew
// clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2
// = ((originateTime + transit + skew - originateTime) +
// (transmitTime - (transmitTime + transit - skew)))/2
// = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2
// = (transit + skew - transit + skew)/2
// = (2 * skew)/2 = skew
long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2;
// if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime + " ms");
// if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset + " ms");
// save our results - use the times on this side of the network latency
// (response rather than request time)
mNtpTime = responseTime + clockOffset;
mNtpTimeReference = responseTicks;
mRoundTripTime = roundTripTime;
} catch (Exception e) {
aapsLogger.debug("request time failed: " + e);
return false;
}
return true;
}
/**
* Returns the time computed from the NTP transaction.
*
* @return time value computed from NTP server response.
*/
private long getNtpTime() {
return mNtpTime;
}
/**
* Returns the reference clock value (value of SystemClock.elapsedRealtime())
* corresponding to the NTP time.
*
* @return reference clock corresponding to the NTP time.
*/
private long getNtpTimeReference() {
return mNtpTimeReference;
}
/**
* Returns the round trip time of the NTP transaction
*
* @return round trip time in milliseconds.
*/
public long getRoundTripTime() {
return mRoundTripTime;
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset];
byte b1 = buffer[offset + 1];
byte b2 = buffer[offset + 2];
byte b3 = buffer[offset + 3];
// convert signed bytes to unsigned values
int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << 8) + (long) i3;
}
/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/
private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset);
long fraction = read32(buffer, offset + 4);
return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
}
/**
* Writes system time (milliseconds since January 1, 1970) as an NTP time stamp
* at the given offset in the buffer.
*/
private void writeTimeStamp(byte[] buffer, int offset, long time) {
long seconds = time / 1000L;
long milliseconds = time - seconds * 1000L;
seconds += OFFSET_1900_TO_1970;
// write seconds in big endian format
buffer[offset++] = (byte) (seconds >> 24);
buffer[offset++] = (byte) (seconds >> 16);
buffer[offset++] = (byte) (seconds >> 8);
buffer[offset++] = (byte) (seconds >> 0);
long fraction = milliseconds * 0x100000000L / 1000L;
// write fraction in big endian format
buffer[offset++] = (byte) (fraction >> 24);
buffer[offset++] = (byte) (fraction >> 16);
buffer[offset++] = (byte) (fraction >> 8);
// low order bits should be random data
buffer[offset++] = (byte) (Math.random() * 255.0);
}
}

View file

@ -0,0 +1,214 @@
package info.nightscout.androidaps.utils
import android.os.SystemClock
import javax.inject.Singleton
import javax.inject.Inject
import info.nightscout.androidaps.logging.AAPSLogger
import java.lang.Exception
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ /**
* {@hide}
*
*
* Simple SNTP client class for retrieving network time.
*
*
* Sample usage:
* <pre>SntpClient client = new SntpClient();
* if (client.requestTime("time.foo.com")) {
* long now = client.getNtpTime() + SystemClock.elapsedRealtime() - client.getNtpTimeReference();
* }
</pre> *
*/
@Singleton
class SntpClient @Inject constructor(
private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil
) {
companion object {
//private final int REFERENCE_TIME_OFFSET = 16;
private const val ORIGINATE_TIME_OFFSET = 24
private const val RECEIVE_TIME_OFFSET = 32
private const val TRANSMIT_TIME_OFFSET = 40
private const val NTP_PACKET_SIZE = 48
private const val NTP_PORT = 123
private const val NTP_MODE_CLIENT = 3
private const val NTP_VERSION = 3
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private const val OFFSET_1900_TO_1970 = (365L * 70L + 17L) * 24L * 60L * 60L
}
/**
* Returns the time computed from the NTP transaction.
*
* @return time value computed from NTP server response.
*/
// system time computed from NTP server response
private var ntpTime: Long = 0
/**
* Returns the reference clock value (value of SystemClock.elapsedRealtime())
* corresponding to the NTP time.
*
* @return reference clock corresponding to the NTP time.
*/
// value of SystemClock.elapsedRealtime() corresponding to mNtpTime
private var ntpTimeReference: Long = 0
/**
* Returns the round trip time of the NTP transaction
*
* @return round trip time in milliseconds.
*/
// round trip time in milliseconds
private var roundTripTime: Long = 0
abstract class Callback : Runnable {
var networkConnected = false
var success = false
var time: Long = 0
}
@Synchronized fun ntpTime(callback: Callback, isConnected: Boolean) {
callback.networkConnected = isConnected
if (callback.networkConnected) {
Thread { doNtpTime(callback) }.start()
} else {
callback.run()
}
}
fun doNtpTime(callback: Callback) {
aapsLogger.debug("Time detection started")
callback.success = requestTime("time.google.com", 5000)
callback.time = ntpTime + SystemClock.elapsedRealtime() - ntpTimeReference
aapsLogger.debug("Time detection ended: " + callback.success + " " + dateUtil.dateAndTimeString(ntpTime))
callback.run()
}
/**
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
* @param timeout network timeout in milliseconds.
* @return true if the transaction was successful.
*/
@Suppress("SameParameterValue")
@Synchronized private fun requestTime(host: String, timeout: Int): Boolean {
try {
val socket = DatagramSocket()
socket.soTimeout = timeout
val address = InetAddress.getByName(host)
val buffer = ByteArray(NTP_PACKET_SIZE)
val request = DatagramPacket(buffer, buffer.size, address, NTP_PORT)
// set mode = 3 (client) and version = 3
// mode is in low 3 bits of first byte
// version is in bits 3-5 of first byte
buffer[0] = (NTP_MODE_CLIENT or (NTP_VERSION shl 3)).toByte()
// get current time and write it to the request packet
val requestTime = System.currentTimeMillis()
val requestTicks = SystemClock.elapsedRealtime()
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime)
socket.send(request)
// read the response
val response = DatagramPacket(buffer, buffer.size)
socket.receive(response)
val responseTicks = SystemClock.elapsedRealtime()
val responseTime = requestTime + (responseTicks - requestTicks)
socket.close()
// extract the results
val originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET)
val receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET)
val transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET)
val roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime)
val clockOffset = (receiveTime - originateTime + (transmitTime - responseTime)) / 2
// save our results - use the times on this side of the network latency
// (response rather than request time)
ntpTime = responseTime + clockOffset
ntpTimeReference = responseTicks
this.roundTripTime = roundTripTime
} catch (e: Exception) {
aapsLogger.debug("request time failed: $e")
return false
}
return true
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
private fun read32(buffer: ByteArray, offset: Int): Long {
val b0 = buffer[offset]
val b1 = buffer[offset + 1]
val b2 = buffer[offset + 2]
val b3 = buffer[offset + 3]
// convert signed bytes to unsigned values
val i0 = if (b0.toInt() and 0x80 == 0x80) (b0.toInt() and 0x7F) + 0x80 else b0.toInt()
val i1 = if (b1.toInt() and 0x80 == 0x80) (b1.toInt() and 0x7F) + 0x80 else b1.toInt()
val i2 = if (b2.toInt() and 0x80 == 0x80) (b2.toInt() and 0x7F) + 0x80 else b2.toInt()
val i3 = if (b3.toInt() and 0x80 == 0x80) (b3.toInt() and 0x7F) + 0x80 else b3.toInt()
return (i0.toLong() shl 24) + (i1.toLong() shl 16) + (i2.toLong() shl 8) + i3.toLong()
}
/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/
private fun readTimeStamp(buffer: ByteArray, offset: Int): Long {
val seconds = read32(buffer, offset)
val fraction = read32(buffer, offset + 4)
return (seconds - OFFSET_1900_TO_1970) * 1000 + fraction * 1000L / 0x100000000L
}
/**
* Writes system time (milliseconds since January 1, 1970) as an NTP time stamp
* at the given offset in the buffer.
*/
@Suppress("SameParameterValue")
private fun writeTimeStamp(buffer: ByteArray, offsetParam: Int, time: Long) {
var offset = offsetParam
var seconds = time / 1000L
val milliseconds = time - seconds * 1000L
seconds += OFFSET_1900_TO_1970
// write seconds in big endian format
buffer[offset++] = (seconds shr 24).toByte()
buffer[offset++] = (seconds shr 16).toByte()
buffer[offset++] = (seconds shr 8).toByte()
buffer[offset++] = (seconds shr 0).toByte()
val fraction = milliseconds * 0x100000000L / 1000L
// write fraction in big endian format
buffer[offset++] = (fraction shr 24).toByte()
buffer[offset++] = (fraction shr 16).toByte()
buffer[offset++] = (fraction shr 8).toByte()
// low order bits should be random data
buffer[offset] = (Math.random() * 255.0).toInt().toByte()
}
}

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Behandelings veiligheid</string>
<string name="treatmentssafety_maxbolus_title">Maks toelaatbare Bolus [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Настройки на сигурността</string>
<string name="treatmentssafety_maxbolus_title">Максимален инсулин при болус [единици]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<!-- SMS Communicator & OTP Authenticator -->
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Bezpečnost zadání ošetřeni</string>
<string name="treatmentssafety_maxbolus_title">Maximální povolený bolus [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<!-- SMS Communicator & OTP Authenticator -->
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Sicherheitseinstellungen der Behandlungen</string>
<string name="treatmentssafety_maxbolus_title">Max. erlaubter Bolus [IE]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Ασφάλεια Θεραπειών</string>
<string name="treatmentssafety_maxbolus_title">Μέγιστο Επιτρεπτό bolus[U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Seguridad tratamientos</string>
<string name="treatmentssafety_maxbolus_title">Máximo Bolo permitido [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Traitements de sécurité</string>
<string name="treatmentssafety_maxbolus_title">Maximum Bolus autorisé [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="nav_preferences_plugin">%1$s Sainroghanna</string>
<string name="nav_preferences">Sainroghanna</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<!-- SMS Communicator & OTP Authenticator -->
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Sicurezza trattamenti</string>
<string name="treatmentssafety_maxbolus_title">Max bolo consentito [U]</string>

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="alert_r7_description"><![CDATA[כמות: <b>%1$d%%</b>\nמשך: <b>%2$s ש\'</b>]]></string>
<string name="alert_w31_description"><![CDATA[תכולת מיכל: <b>%1$s U</b>]]></string>
<string name="alert_w32_description">החלף סוללה.</string>
<string name="alert_w33_description">קבע זמן/תאריך.</string>
<string name="alert_w34_description">צור קשר עם תמיכת Accu-Chek.</string>
<string name="alert_w36_description"><![CDATA[<b>%1$d%%</b><br/>משך: <b>%2$s שעות</b>]]></string>
<string name="alert_w38_description"><![CDATA[כמות מתוכננת: <b>%1$s U</b><br/>כמות שניתנה: <b>%2$s U</b>]]></string>
<string name="alert_m20_description">הכנס מיכל.</string>
<string name="alert_m21_description">החלף מיכל.</string>
<string name="alert_m22_description">החלף סוללה.</string>
<string name="alert_m23_description">בדוק סטטוס משאבה.</string>
<string name="alert_m24_description">החלף פרפרית.</string>
<string name="alert_m25_description">צור קשר עם תמיכת Accu-Chek.</string>
<string name="alert_m26_description">החלף מיכל.</string>
<string name="alert_m27_description">הפעילו מחדש את הורדת הנתונים.</string>
<string name="alert_m28_description">בדוק סטטוס משאבה.</string>
<string name="alert_m29_description">קבע סוג סוללה.</string>
<string name="alert_m30_description">קבע סוג מיכל.</string>
<string name="alert_e6_description">החלף סוללה ומיכל.</string>
<string name="alert_e10_description">החלף מיכל.</string>
<string name="alert_e13_description">שנה שפה.</string>
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">בטיחות טיפולים</string>
<string name="treatmentssafety_maxbolus_title">בולוס מקסימלי מותר [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">관리 안전설정</string>
<string name="treatmentssafety_maxbolus_title">최대 허용 Bolus [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Terapijos saugumas</string>
<string name="treatmentssafety_maxbolus_title">Maksimalus leistinas bolusas [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Behandelingen veiligheid</string>
<string name="treatmentssafety_maxbolus_title">Max toegestane bolus [E]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Sikkerhet ved behandlinger</string>
<string name="treatmentssafety_maxbolus_title">Maks tillat bolus [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Bezpieczeństwo leczenia</string>
<string name="treatmentssafety_maxbolus_title">Maks. dopuszczalny bolus [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Segurança do Tratamento</string>
<string name="treatmentssafety_maxbolus_title">Máximo bolus permitido [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Segurança de Tratamentos</string>
<string name="treatmentssafety_maxbolus_title">Max bolus permitido [U]</string>
@ -538,7 +537,7 @@
<string name="overview_buttons_selection">Botões</string>
<string name="show_calibration_button_summary">Enviar calibrações para o xDrip+ ou abrir sistema de calibração do G5</string>
<string name="show_cgm_button_summary">Abre xDrip+, botão retorcer volta ao AAPS</string>
<string name="carb_increment_button_message">Número de carboidratos a adicionar quando o botão é premido</string>
<string name="carb_increment_button_message">Número de hidratos de carbono a adicionar quando o botão é premido</string>
<string name="insulin_increment_button_message">Unidades de insulina a adicionar quando o botão é premido</string>
<string name="error_starting_cgm">Não foi possível lançar aplicação de monitorização contínua. Por favor verifique que está instalada.</string>
<string name="overview_cgm">CGM</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Setări siguranță tratament</string>
<string name="treatmentssafety_maxbolus_title">Bolus maxim admis [U]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Безопасность терапии</string>
<string name="treatmentssafety_maxbolus_title">Макс разрешенный болюс [U] ед.</string>
@ -903,4 +902,8 @@ Context | Edit Context</string>
<string name="cannula">Катетер помпы</string>
<string name="userentry">Запись пользователя</string>
<string name="common_values">Введите максимальные значения вашего приема пищи \n</string>
<string name="summary_email_for_crash_report">Этот адрес электронной почты будет привязан к отчетам о сбоях, чтобы мы могли связаться с вами в экстренных случаях. Это опция.</string>
<string name="email_address">Адрес электронной почты</string>
<string name="privacy_settings">Настройки конфиденцальности</string>
<string name="privacy_summary">Вы можете указать дополнительно адрес электронной почты, если хотите получать уведомления о сбоях приложения; что является не автоматизированной рассылкой, а способом связи с разработчиками в опасных ситуациях.</string>
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Bezpečnosť zadania ošetrenia</string>
<string name="treatmentssafety_maxbolus_title">Maximálny povolený bolus [JI]</string>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<!-- SMS Communicator & OTP Authenticator -->
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Säkerhetsbegränsningar</string>
<string name="treatmentssafety_maxbolus_title">Max tillåten bolus [U]</string>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="alert_r7_description"><![CDATA[Miktar: <b>%1$d%%</b>\nSüre: </b>%2$s st.</b>]]></string>
<string name="alert_w36_description"><![CDATA[Miktar: <b>%1$d%%</b><br/>Süre: <b>%2$s st.</b>]]></string>
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">Tedavilerin güvenlik ayarları</string>
<string name="treatmentssafety_maxbolus_title">Max izin verilen bolus [U]</string>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="alert_r7_description"><![CDATA[总数: <b>%1$d%%</b>\nDuration: <b>%2$s h</b>]]></string>
<string name="alert_w36_description"><![CDATA[总数: <b>%1$d%%</b><br/>Duration: <b>%2$s h</b>]]></string>
</resources>

View file

@ -2,7 +2,6 @@
<resources>
<!-- <string name="fi_lang" translatable="false">Finnish</string> -->
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="treatmentssafety_title">治疗安全</string>
<string name="treatmentssafety_maxbolus_title">允许的最大大剂量值[U]</string>

View file

@ -32,6 +32,7 @@
<item>@string/nl_lang</item>
<item>@string/es_lang</item>
<item>@string/el_lang</item>
<item>@string/ga_lang</item>
<item>@string/it_lang</item>
<item>@string/ko_lang</item>
<item>@string/lt_lang</item>
@ -46,6 +47,7 @@
<item>@string/tr_lang</item>
<item>@string/zh_lang</item>
</string-array>
<string-array name="languagesValues" translatable="false">
<item>default</item>
<item>en</item>
@ -57,6 +59,7 @@
<item>nl</item>
<item>es</item>
<item>el</item>
<item>ga</item>
<item>it</item>
<item>ko</item>
<item>lt</item>

View file

@ -11,7 +11,7 @@
<string name="el_lang" translatable="false">Greek</string>
<!-- <string name="he_lang" translatable="false">Hebrew</string> -->
<string name="zh_lang" translatable="false">Chinese</string>
<!-- <string name="ga_lang" translatable="false">Irish</string> -->
<string name="ga_lang" translatable="false">Irish</string>
<string name="it_lang" translatable="false">Italian</string>
<!-- <string name="ja_lang" translatable="false">Japanese</string> -->
<string name="ko_lang" translatable="false">Korean</string>
@ -28,6 +28,11 @@
<string name="tr_lang" translatable="false">Turkish</string>
<string name="key_email_for_crash_report" translatable="false">email_for_crash_report</string>
<string name="key_smscommunicator_settings" translatable="false">smscommunicator</string>
<string name="key_open_humans_settings" translatable="false">open_humans</string>
<string name="key_protection_settings" translatable="false">protection</string>
<string name="key_absorption_category_settings" translatable="false">absorption_category_settings</string>
<string name="key_insulin_oref_peak_settings" translatable="false">insulin_oref_peak_settings</string>
<string name="treatmentssafety_title">Treatments safety</string>
<string name="treatmentssafety_maxbolus_title">Max allowed bolus [U]</string>

View file

@ -5,6 +5,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_absorption_settings"
android:title="@string/absorptionsettings_title"
app:initialExpandedChildrenCount="0">

View file

@ -5,6 +5,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_absorption_category_settings"
android:title="@string/absorptionsettings_title"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_localalert_settings"
android:title="@string/localalertsettings_title"
app:initialExpandedChildrenCount="0">

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_bgsource_upload_settings"
android:title="@string/bgsource_upload"
app:initialExpandedChildrenCount="0">

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_dexcom_settings"
android:title="@string/bgsource_upload"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_data_choices_settings"
android:title="@string/data_choices"
app:initialExpandedChildrenCount="0">

View file

@ -3,8 +3,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:initialExpandedChildrenCount="0"
android:title="@string/configbuilder_general">
android:key="@string/key_configbuilder_general_settings"
android:title="@string/configbuilder_general"
app:initialExpandedChildrenCount="0">
<ListPreference
android:defaultValue="mg/dl"
@ -27,7 +28,9 @@
android:summary="@string/patient_name_summary"
/>
<PreferenceCategory android:title="@string/protection">
<PreferenceCategory
android:key="@string/key_protection_settings"
android:title="@string/protection">
<Preference
android:inputType="textPassword"

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_insulin_oref_peak_settings"
android:title="@string/insulin_oref_peak"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_loop_settings"
app:initialExpandedChildrenCount="0"
android:title="@string/loop">

View file

@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="maintenance"
android:key="@string/key_maintenance_settings"
android:title="@string/maintenance_settings"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_nsclientinternal_settings"
android:title="@string/nsclientinternal_title"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_openapsma_settings"
android:title="@string/openapsama"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_openapssmb_settings"
android:title="@string/openapssmb"
app:initialExpandedChildrenCount="0">

View file

@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory android:title="@string/open_humans">
<PreferenceCategory
android:key="@string/key_open_humans_settings"
android:title="@string/open_humans">
<CheckBoxPreference
android:defaultValue="true"
@ -15,4 +19,4 @@
</PreferenceCategory>
</PreferenceScreen>
</androidx.preference.PreferenceScreen>

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_overview_settings"
android:title="@string/overview"
app:initialExpandedChildrenCount="0">

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_pump_settings"
android:title="@string/pump"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_treatmentssafety_settings"
android:title="@string/treatmentssafety_title"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_smscommunicator_settings"
android:title="@string/smscommunicator"
app:initialExpandedChildrenCount="0">

View file

@ -4,6 +4,7 @@
xmlns:validate="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_tidepool_settings"
android:title="@string/tidepool"
app:initialExpandedChildrenCount="0">

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_virtualpump_settings"
android:title="@string/virtualpump_settings"
app:initialExpandedChildrenCount="0">

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_wear_settings"
android:title="@string/wear_settings"
app:initialExpandedChildrenCount="0">

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_xdripstatus_settings"
android:title="@string/xdripstatus_settings"
app:initialExpandedChildrenCount="0">

View file

@ -7,6 +7,7 @@
<string name="automation_missing_trigger">Merci de spécifier au moins un déclencheur.</string>
<string name="automation_missing_action">Merci de spécifier au moins une action.</string>
<string name="alarm_message">Alarme: %1$s</string>
<string name="alarm_short">Alarme:</string>
<string name="message_short">Mess :</string>
<string name="alreadyenabled">Déjà activé</string>
<string name="alreadydisabled">Déjà désactivé</string>
@ -88,6 +89,7 @@
<string name="glucose_u">Glycémie [%1$s] :</string>
<string name="lastboluslabel">Lors du dernier Bolus</string>
<string name="lastboluscompared">Heure du dernier bolus %1$s il y a %2$s min</string>
<string name="triggercoblabel">GA</string>
<string name="cobcompared">GA %1$s %2$.0f</string>
<string name="iob_u">IA [U]:</string>
<string name="distance_short">Dist [m]:</string>

View file

@ -7,6 +7,7 @@
<string name="automation_missing_trigger">Specifica almeno un trigger.</string>
<string name="automation_missing_action">Specifica almeno un\'azione.</string>
<string name="alarm_message">Allarme: %1$s</string>
<string name="alarm_short">Allarme:</string>
<string name="message_short">Msg:</string>
<string name="alreadyenabled">Già abilitato</string>
<string name="alreadydisabled">Già disabilitato</string>
@ -88,6 +89,7 @@
<string name="glucose_u">Glicemia [%1$s]:</string>
<string name="lastboluslabel">Ultimo bolo</string>
<string name="lastboluscompared">Ora ultimo bolo %1$s %2$s min fa</string>
<string name="triggercoblabel">COB</string>
<string name="cobcompared">COB %1$s %2$.0f</string>
<string name="iob_u">IOB [U]:</string>
<string name="distance_short">Dist [m]:</string>

View file

@ -7,6 +7,7 @@
<string name="automation_missing_trigger">Oppgi minst en trigger.</string>
<string name="automation_missing_action">Oppgi minst en aksjon.</string>
<string name="alarm_message">Alarm: %1$s</string>
<string name="alarm_short">Alarm:</string>
<string name="message_short">Meld:</string>
<string name="alreadyenabled">Allerede aktivert</string>
<string name="alreadydisabled">Allerede avslått</string>
@ -88,6 +89,7 @@
<string name="glucose_u">Glukose [%1$s]:</string>
<string name="lastboluslabel">Siste bolus</string>
<string name="lastboluscompared">Siste bolus for %1$s %2$s min siden</string>
<string name="triggercoblabel">COB</string>
<string name="cobcompared">COB %1$s %2$.0f</string>
<string name="iob_u">IOB [U]:</string>
<string name="distance_short">Dist [m]:</string>

View file

@ -7,6 +7,7 @@
<string name="automation_missing_trigger">Especifique pelo menos um gatilho.</string>
<string name="automation_missing_action">Especifique pelo menos uma acção.</string>
<string name="alarm_message">Alarme: %1$s</string>
<string name="alarm_short">Alarme:</string>
<string name="message_short">Mnsg:</string>
<string name="alreadyenabled">Já activado</string>
<string name="alreadydisabled">Já desativado</string>
@ -88,6 +89,7 @@
<string name="glucose_u">Glicose [%1$s]:</string>
<string name="lastboluslabel">Último bolus atrás</string>
<string name="lastboluscompared">Última vez do bolus %1$s %2$s atrás</string>
<string name="triggercoblabel">COB</string>
<string name="cobcompared">COB %1$s %2$.0f</string>
<string name="iob_u">IOB [U]:</string>
<string name="distance_short">Dist [m]:</string>

View file

@ -109,6 +109,7 @@
<string name="preconditions">Preconditions:</string>
<string name="automation_event">Automation event</string>
<string name="reorder_label">Reorder</string>
<string name="key_automation_settings" translatable="false">automation_settings</string>
</resources>

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="@string/key_automation_settings"
android:title="@string/automation"
app:initialExpandedChildrenCount="0">

View file

@ -2,14 +2,14 @@
buildscript {
ext {
kotlin_version = '1.4.30'
kotlin_version = '1.4.31'
coreVersion = '1.3.2'
rxjava_version = '2.2.21'
rxandroid_version = '2.1.1'
rxkotlin_version = '2.4.0'
room_version = '2.2.6'
lifecycle_version = '2.3.0'
dagger_version = '2.32'
dagger_version = '2.33'
coroutinesVersion = '1.4.1'
activityVersion = '1.2.0'
fragmentktx_version = '1.3.0'
@ -25,7 +25,7 @@ buildscript {
work_version = '2.5.0'
junit_version = '4.13.2'
mockitoVersion = '3.7.7'
mockitoVersion = '3.8.0'
powermockVersion = '2.0.9'
dexmakerVersion = "1.2"
retrofit2Version = '2.9.0'

View file

@ -3,6 +3,7 @@
<string name="description_pump_combo">Integração para bombas Accu-Chek Combo, requer ter o ruffy instalado</string>
<string name="combo_programming_bolus">A programar bomba para administrar bólus</string>
<string name="combo_pump_state_label">Estado</string>
<string name="combo_pump_activity_label">Actividade</string>
<string name="combo_no_pump_connection">Sem conexão há %1$d min</string>
<string name="combo_tbr_remaining">%1$d%% (%2$d min restantes)</string>
<string name="combo_pump_state_initializing">A iniciar</string>

View file

@ -3,6 +3,7 @@
<string name="description_pump_combo">Интеграция с помпой Accu-Chek Combo, требует наличия утилиты Ruffy</string>
<string name="combo_programming_bolus">Помпа программируется для болюса</string>
<string name="combo_pump_state_label">Состояние</string>
<string name="combo_pump_activity_label">Нагрузка</string>
<string name="combo_no_pump_connection">Нет связи в течение %1$d мин</string>
<string name="combo_tbr_remaining">%1$d%% (%2$d мин осталось)</string>
<string name="combo_pump_state_initializing">Инициализация</string>

View file

@ -1,9 +0,0 @@
package info.nightscout.androidaps.db;
public interface DbObjectBase {
long getDate();
long getPumpId();
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.db
interface DbObjectBase {
val date: Long
val pumpId: Long
}

View file

@ -1,13 +0,0 @@
package info.nightscout.androidaps.interfaces;
import info.nightscout.androidaps.data.PumpEnactResult;
/**
* Created by mike on 12.06.2017.
*/
public interface DanaRInterface {
PumpEnactResult loadHistory(byte type); // for history browser
PumpEnactResult loadEvents(); // events history to build treatments from
PumpEnactResult setUserOptions(); // like AnyDana does
}

View file

@ -0,0 +1,10 @@
package info.nightscout.androidaps.interfaces
import info.nightscout.androidaps.data.PumpEnactResult
interface DanaRInterface {
fun loadHistory(type: Byte): PumpEnactResult // for history browser
fun loadEvents(): PumpEnactResult // events history to build treatments from
fun setUserOptions(): PumpEnactResult // like AnyDana does
}

View file

@ -139,12 +139,12 @@ public class DateUtil {
hours -= 12;
if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM") || m.group(3).equals("PM")) && !(m.group(1).equals("12")))
hours += 12;
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, hours);
c.set(Calendar.MINUTE, minutes);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
retval = c.getTimeInMillis();
DateTime t = new DateTime()
.withHourOfDay(hours)
.withMinuteOfHour(minutes)
.withSecondOfMinute(0)
.withMillisOfSecond(0);
retval = t.getMillis();
}
return retval;
}

View file

@ -69,6 +69,40 @@
<string name="pairing">Сдвояване</string>
<string name="yes">Да</string>
<string name="no">Не</string>
<string name="loopdisabled">LOOP Е СПРЯН ОТ ОГРАНИЧЕНИЯТА</string>
<string name="bolusdelivered">Болус от %1$.2fЕ доставен успешно</string>
<string name="virtualpump_resultok">ОК</string>
<string name="novalidbasalrate">Няма валиден базал в помпата</string>
<string name="limitingmaxiob">Ограничаване на макс. IOB до %1$.1f Е поради %2$s</string>
<string name="unsafeusage">опасно използване</string>
<string name="pump_unreachable">Помпата е недостъпна</string>
<string name="extended_bolus">Удължен болус</string>
<string name="pump_time_updated">Актуализирано време на помпата</string>
<string name="exit">Изход</string>
<string name="serial_number">Сериен номер</string>
<string name="removerecord">Премахни</string>
<string name="loopisdisabled">APS е изключен</string>
<string name="alarm">Аларма</string>
<string name="disableloop">Изключи Loop</string>
<string name="enableloop">Включи Loop</string>
<string name="resumeloop">Възстанови loop</string>
<string name="suspendloop">Изключи APS</string>
<string name="duration_min_label">Продължителност [мин.]</string>
<string name="notification">Известие</string>
<string name="noprofile">Още не е зареден профила от NS</string>
<string name="exists">съществува</string>
<string name="notexists">не съществува</string>
<string name="glucose">Кръвна захар</string>
<string name="iob">IOB</string>
<string name="cob">СОВ</string>
<string name="name_short">Име:</string>
<string name="time">Време</string>
<string name="ns_wifi_ssids">WiFi име</string>
<string name="loading">Зареждане…</string>
<string name="event_time_label">Време</string>
<string name="notes_label">Бележки</string>
<string name="remove_button">Изтрий</string>
<string name="addnew">Добави нов</string>
<!-- Constraints-->
<string name="limitingbasalratio">Ограничаване на макс. базална стойност до %1$.2f Е/ч поради %2$s</string>
<string name="pumplimit">лимит на помпата</string>
@ -258,6 +292,13 @@
<!-- Permissions -->
<string name="alert_dialog_storage_permission_text">Рестартирайте телефона или AndroidAPS от системните настройки \nили Android APS няма да записва проблемите (което е важно за работата на алгоритъма)!</string>
<!-- WeekdayPicker -->
<string name="monday_short">П</string>
<string name="tuesday_short">Вт</string>
<string name="wednesday_short">Ср</string>
<string name="thursday_short">Ч</string>
<string name="friday_short">П</string>
<string name="saturday_short">С</string>
<string name="sunday_short">Н</string>
<plurals name="minutes">
<item quantity="one">%1$d минутa</item>
<item quantity="other">%1$d минути</item>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="error_only_numeric_digits_allowed">Позволени са само числа.</string>
<string name="error_only_numeric_digits_range_allowed">Позволени са числа между %1$s - %2$s.</string>
<string name="error_this_field_cannot_contain_special_character">Полето не може да съдържа никакви специални символи</string>
<string name="error_only_standard_letters_are_allowed">Разрешени са само стандартни букви</string>
<string name="error_field_must_not_be_empty">Полето не може да бъде празно</string>
<string name="error_email_address_not_valid">Имейл адресът не е валиден</string>
<string name="error_creditcard_number_not_valid">Номер на кредитна карта е невалиден</string>
<string name="error_phone_not_valid">Телефонният номер не е валиден</string>
<string name="error_domain_not_valid">Името на домейн не е валидно</string>
<string name="error_ip_not_valid">IP адресът е невалиден</string>
<string name="error_url_not_valid">Url адресът не е валиден</string>
<string name="error_notvalid_personname">Не е валидно първото или последното име.</string>
<string name="error_notvalid_personfullname">Невалидно име.</string>
<string name="error_date_not_valid">Невалиден формат</string>
<string name="error_mustbe4digitnumber">Трябва да е 4 цифрено число</string>
<string name="error_mustbe6digitnumber">Трябва да е 6 цифрено число</string>
<string name="error_mustbe12hexadidits">Трябва да са 12 символа между ABCDEF0123456789</string>
<string name="error_mustbe8hexadidits">Трябва да са 8 символа между ABCDEF0123456789</string>
<string name="error_mustbe4hexadidits">Трябва да са 4 символа между ABCDEF0123456789</string>
<string name="error_not_a_minimum_length">Не е с минималната дължина</string>
<string name="error_pin_not_valid">Пин трябва да бъде 3 до 6 цифри, не същите или в серия</string>
</resources>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="error_only_numeric_digits_allowed">Jsou povoleny pouze číslice.</string>
<string name="error_only_numeric_digits_range_allowed">Povolena jsou pouze čísla v rozsahu %1$s - %2$s.</string>
<string name="error_this_field_cannot_contain_special_character">Toto pole nesmí obsahovat speciální znaky</string>
<string name="error_only_standard_letters_are_allowed">Jsou povolena pouze standardní písmena</string>
<string name="error_field_must_not_be_empty">Toto pole nesmí být prázdné</string>
<string name="error_email_address_not_valid">E-mailová adresa je neplatná</string>
<string name="error_creditcard_number_not_valid">Číslo kreditní karty není platné</string>
<string name="error_phone_not_valid">Neplatné telefonní číslo</string>
<string name="error_domain_not_valid">Název domény není platný</string>
<string name="error_ip_not_valid">IP adresa není platná</string>
<string name="error_url_not_valid">Adresa Url není platná</string>
<string name="error_notvalid_personname">Neplatné jméno nebo příjmení.</string>
<string name="error_notvalid_personfullname">Není platné celé jméno.</string>
<string name="error_date_not_valid">Formát není platný</string>
<string name="error_mustbe4digitnumber">Musí být čtyřmístné číslo</string>
<string name="error_mustbe6digitnumber">Musí být šestimístné číslo</string>
<string name="error_mustbe12hexadidits">Musí být 12 znaků ABCDEF0123456789</string>
<string name="error_mustbe8hexadidits">Musí být 8 znaků ABCDEF0123456789</string>
<string name="error_mustbe4hexadidits">Musí obsahovat 4 znaky ABCDEF0123456789</string>
<string name="error_not_a_minimum_length">Není splněna minimální délka</string>
<string name="error_pin_not_valid">Pin by měl být 3 až 6 číslic, které nesmí být stejné nebo v sériích</string>
</resources>

View file

@ -80,6 +80,29 @@
<string name="pump_time_updated">Mise à jour de l\'heure de la pompe</string>
<string name="exit">Quitter</string>
<string name="serial_number">Numéro de série</string>
<string name="removerecord">Supprimer l\'enregistrement</string>
<string name="loopisdisabled">La Boucle est désactivée</string>
<string name="alarm">Alarme</string>
<string name="disableloop">Désactiver la Boucle</string>
<string name="enableloop">Activer la Boucle</string>
<string name="resumeloop">Reprendre la boucle</string>
<string name="suspendloop">Suspendre la boucle</string>
<string name="duration_min_label">Durée [min]</string>
<string name="notification">Notification</string>
<string name="noprofile">Pas encore de profil téléchargé depuis NS</string>
<string name="exists">existe</string>
<string name="notexists">n\'existe pas</string>
<string name="glucose">Glycémie</string>
<string name="iob">IA</string>
<string name="cob">GA</string>
<string name="name_short">Nom :</string>
<string name="time">Heure</string>
<string name="ns_wifi_ssids">SSID WiFi</string>
<string name="loading">Chargement…</string>
<string name="event_time_label">Heure événement</string>
<string name="notes_label">Notes</string>
<string name="remove_button">Supprimer</string>
<string name="addnew">Ajouter</string>
<!-- Constraints-->
<string name="limitingbasalratio">Limiter le débit de basal max à %1$.2f U/h à cause de %2$s</string>
<string name="pumplimit">Limite de la pompe</string>

View file

@ -80,6 +80,29 @@
<string name="pump_time_updated">Ora del micro aggiornata</string>
<string name="exit">Esci</string>
<string name="serial_number">Numero seriale</string>
<string name="removerecord">Rimuovi record</string>
<string name="loopisdisabled">Il loop è disabilitato</string>
<string name="alarm">Allarme</string>
<string name="disableloop">Disabilita loop</string>
<string name="enableloop">Abilita loop</string>
<string name="resumeloop">Riprendi loop</string>
<string name="suspendloop">Sospendi loop</string>
<string name="duration_min_label">Durata [min]</string>
<string name="notification">Notifica</string>
<string name="noprofile">Nessun profilo ancora caricato da NS</string>
<string name="exists">esiste</string>
<string name="notexists">non esiste</string>
<string name="glucose">Glicemia</string>
<string name="iob">IOB</string>
<string name="cob">COB</string>
<string name="name_short">Nome:</string>
<string name="time">Tempo</string>
<string name="ns_wifi_ssids">WiFi SSID</string>
<string name="loading">Caricamento…</string>
<string name="event_time_label">Ora evento</string>
<string name="notes_label">Note</string>
<string name="remove_button">Rimuovi</string>
<string name="addnew">Aggiungi nuovo</string>
<!-- Constraints-->
<string name="limitingbasalratio">Limitazione max velocità basale a %1$.2f U/h a causa di: %2$s</string>
<string name="pumplimit">limite micro</string>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="error_only_numeric_digits_allowed">Sono consentite solo cifre numeriche.</string>
<string name="error_only_numeric_digits_range_allowed">Sono consentite solo cifre numeriche nel range %1$s - %2$s.</string>
<string name="error_this_field_cannot_contain_special_character">Questo campo non può contenere alcun carattere speciale</string>
<string name="error_only_standard_letters_are_allowed">Sono consentite solo lettere standard</string>
<string name="error_field_must_not_be_empty">Il campo non deve essere vuoto</string>
<string name="error_email_address_not_valid">Indirizzo email non valido</string>
<string name="error_creditcard_number_not_valid">Il numero della carta di credito non è valido</string>
<string name="error_phone_not_valid">Numero di telefono non valido</string>
<string name="error_domain_not_valid">Nome dominio non valido</string>
<string name="error_ip_not_valid">Indirizzo IP non valido</string>
<string name="error_url_not_valid">L\'URL non è valido</string>
<string name="error_notvalid_personname">Nome o Cognome non valido.</string>
<string name="error_notvalid_personfullname">Nome completo non valido.</string>
<string name="error_date_not_valid">Formato non valido</string>
<string name="error_mustbe4digitnumber">Deve essere un numero di 4 cifre</string>
<string name="error_mustbe6digitnumber">Deve essere un numero di 6 cifre</string>
<string name="error_mustbe12hexadidits">Devono essere 12 caratteri tra ABCDEF0123456789</string>
<string name="error_mustbe8hexadidits">Devono essere 8 caratteri tra ABCDEF0123456789</string>
<string name="error_mustbe4hexadidits">Devono essere 4 caratteri tra ABCDEF0123456789</string>
<string name="error_not_a_minimum_length">Lunghezza minima non soddisfatta</string>
<string name="error_pin_not_valid">Il PIN deve contenere da 3 a 6 cifre, non uguali o in serie</string>
</resources>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="error_only_numeric_digits_allowed">ניתן להשתמש רק בתוים מספריים.</string>
<string name="error_only_numeric_digits_range_allowed">מותר להשתמש רק בתוים מספריים בטווח %1$s עד %2$s. </string>
<string name="error_this_field_cannot_contain_special_character">שדה זה לא יכול להכיל תוים מיוחדים</string>
<string name="error_only_standard_letters_are_allowed">ניתן להשתמש רק באותיות אנגליות רגילות</string>
<string name="error_field_must_not_be_empty">שדה זה לא יכול להיות ריק</string>
<string name="error_email_address_not_valid">כתובת הדוא\"ל אינה תקינה</string>
<string name="error_creditcard_number_not_valid">מספר כרטיס האשראי לא תקין</string>
<string name="error_phone_not_valid">מספר הטלפון אינו תקין</string>
<string name="error_domain_not_valid">שם הדומיין לא תקין</string>
<string name="error_ip_not_valid">כתובת ה-IP אינה תקינה</string>
<string name="error_url_not_valid">כתובת ה-URL אינה תקינה</string>
<string name="error_notvalid_personname">השם הפרטי או שם המשפחה לא תקינים.</string>
<string name="error_notvalid_personfullname">השם המלא אינו תקין.</string>
<string name="error_date_not_valid">הפורמט אינו תקין</string>
<string name="error_mustbe4digitnumber">חייב להיות מספר ארבע ספרתי</string>
<string name="error_mustbe6digitnumber">חייב להיות מספר שש ספרתי</string>
<string name="error_mustbe12hexadidits">חייב להיות באורך 12 תוים, מהתוים הבאים: ABCDEF0123456789</string>
<string name="error_mustbe8hexadidits">חייב להיות באורך 8 תוים, מהתוים הבאים: ABCDEF0123456789</string>
<string name="error_mustbe4hexadidits">חייב להיות באורך 4 תוים, מהתוים הבאים: ABCDEF0123456789</string>
<string name="error_not_a_minimum_length">לא באורך המינימלי</string>
<string name="error_pin_not_valid">קוד ה-PIN חייב להיות באורך 3 עד 6 תוים, לא זהים ולא בסדר</string>
</resources>

Some files were not shown because too many files have changed in this diff Show more