Merge branch 'dev' into omnipod_eros

This commit is contained in:
Bart Sopers 2019-12-01 02:21:49 +01:00
commit b808bc3228
281 changed files with 9423 additions and 2085 deletions

48
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,48 @@
This document speciffy hints and good practices for source code contributions.
AndroidAPS is community effort and all contributions are welcome! If you wish help us improving AndroidAPS - please read and try to adhere to
this guidelines, to make the development and process of change aproval as smooth as possible :)
General rules
=============
* There are plenty of ways you can help, some of them are listed on wiki:
https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/How-can-I-help.html
* If you wish to help with documentation or translating:
https://androidaps.readthedocs.io/en/latest/EN/translations.html
Development guidelines
======================
Coding convetions
-----------------
1. Use Android Studio with default indents (4 chars, use spaces)
2. Use autoformat feature CTRL-ALT-L in every changed file before commit
Commiting Changes / Pull Requests
---------------------------------
1. Make fork of repository on github
2. Create separate branch for each feature, branch from most recent dev
3. Commit all changes to your fork
4. When ready, rebase on top of dev and make pull request to main repo
Naming Conventions for Pull Requests / Branches
-----------------------------------------------
TODO
Translations
------------
* If possible, always use Android translation mechanism (with strings.xml and @strings/id) instead of hardcoded texts
* Provide only English strings - all other languages will be crowd translated via Crowdn https://translations.androidaps.org/
Hints
-----
* Start small, it is easier to review smaller changes that affect fewer parts of code
* Take a look into Issues list (https://github.com/MilosKozak/AndroidAPS/issues) - maybe there is somthing you can fix or implement
* For new features, make sure there is Issue to track progress and have on-topic discussion
* Reach out to community, discuss idea on Gitter (https://gitter.im/MilosKozak/AndroidAPS)
* Speak with other developers to minimise merge conflicts. Find out who worked, working or plan to work on speciffic issue or part of app

View file

@ -130,7 +130,14 @@ public class MainApp extends Application {
sConstraintsChecker = new ConstraintChecker();
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> log.error("Uncaught exception crashing app", ex));
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
if (ex instanceof InternalError) {
// usually the app trying to spawn a thread while being killed
return;
}
log.error("Uncaught exception crashing app", ex);
});
try {
if (FabricPrivacy.fabricEnabled()) {
@ -207,7 +214,7 @@ public class MainApp extends Application {
pluginsList.add(SourcePoctechPlugin.getPlugin());
pluginsList.add(SourceTomatoPlugin.getPlugin());
pluginsList.add(SourceEversensePlugin.getPlugin());
if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.getPlugin());
if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.INSTANCE);
pluginsList.add(FoodPlugin.getPlugin());
pluginsList.add(WearPlugin.initPlugin(this));

View file

@ -9,27 +9,28 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.text.TextUtils;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRebuildTabs;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin;
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader;
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin;
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
@ -42,14 +43,9 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
MyPreferenceFragment myPreferenceFragment;
@ -80,7 +76,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
if (key.equals(MainApp.gs(R.string.key_openapsama_useautosens)) && SP.getBoolean(R.string.key_openapsama_useautosens, false)) {
OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning), null);
}
updatePrefSummary(myPreferenceFragment.getPreference(key));
updatePrefSummary(myPreferenceFragment.findPreference(key));
}
private static void updatePrefSummary(Preference pref) {
@ -92,13 +88,13 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
EditTextPreference editTextPref = (EditTextPreference) pref;
if (pref.getKey().contains("password") || pref.getKey().contains("secret")) {
pref.setSummary("******");
} else if (pref.getKey().equals(MainApp.gs(R.string.key_danars_name))) {
pref.setSummary(SP.getString(R.string.key_danars_name, ""));
} else if (editTextPref.getText() != null) {
((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage());
pref.setSummary(editTextPref.getText());
} else if (pref.getKey().contains("smscommunicator_allowednumbers") && (editTextPref.getText() == null || TextUtils.isEmpty(editTextPref.getText().trim()))) {
pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary));
} else {
for (PluginBase plugin : MainApp.getPluginsList()) {
plugin.updatePreferenceSummary(pref);
}
}
}
}
@ -188,7 +184,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(TidepoolPlugin.INSTANCE, PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.INSTANCE, PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(AutomationPlugin.INSTANCE, PluginType.GENERAL);
addPreferencesFromResource(R.xml.pref_others);
@ -198,26 +194,11 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginType.GENERAL);
}
if (Config.NSCLIENT) {
PreferenceScreen scrnAdvancedSettings = (PreferenceScreen) findPreference(getString(R.string.key_advancedsettings));
if (scrnAdvancedSettings != null) {
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_warning)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_critical)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_warning)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_critical)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_show_statuslights)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_show_statuslights_extended)));
}
}
initSummary(getPreferenceScreen());
final Preference tidepoolTestLogin = findPreference(MainApp.gs(R.string.key_tidepool_test_login));
if (tidepoolTestLogin != null)
tidepoolTestLogin.setOnPreferenceClickListener(preference -> {
TidepoolUploader.INSTANCE.testLogin(getActivity());
return false;
});
for (PluginBase plugin : MainApp.getPluginsList()) {
plugin.preprocessPreferences(this);
}
}
@Override
@ -225,9 +206,5 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
super.onSaveInstanceState(outState);
outState.putInt("id", id);
}
public Preference getPreference(String key) {
return findPreference(key);
}
}
}

View file

@ -100,8 +100,8 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval {
String hours = " " + MainApp.gs(R.string.hours) + " ";
if (useShortText) {
days = "d";
hours = "h";
days = MainApp.gs(R.string.shortday);
hours = MainApp.gs(R.string.shorthour);
}
return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours;

View file

@ -1,10 +1,13 @@
package info.nightscout.androidaps.interfaces;
import android.os.SystemClock;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -215,4 +218,10 @@ public abstract class PluginBase {
protected void onStateChange(PluginType type, State oldState, State newState) {
}
public void preprocessPreferences(@NotNull final PreferenceFragment preferenceFragment) {
}
public void updatePreferenceSummary(@NotNull final Preference pref) {
}
}

View file

@ -247,7 +247,7 @@ public class APSResult {
}
}
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return array;
}
@ -280,7 +280,7 @@ public class APSResult {
}
}
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return latest;

View file

@ -164,7 +164,7 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
return;
if (!HardLimits.checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return;
if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return;
if (!HardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;

View file

@ -162,7 +162,7 @@ public class OpenAPSMAPlugin extends PluginBase implements APSInterface {
return;
if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return;
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return;
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;

View file

@ -170,7 +170,7 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
return;
if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return;
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return;
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;

View file

@ -27,6 +27,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SP;
import io.reactivex.disposables.CompositeDisposable;
@ -75,35 +76,42 @@ public class ProfileFunctions {
}
public String getProfileName() {
return getProfileName(System.currentTimeMillis());
return getProfileName(System.currentTimeMillis(), true, false);
}
public String getProfileName(boolean customized) {
return getProfileName(System.currentTimeMillis(), customized);
return getProfileName(System.currentTimeMillis(), customized, false);
}
public String getProfileName(long time) {
return getProfileName(time, true);
public String getProfileNameWithDuration() {
return getProfileName(System.currentTimeMillis(), true, true);
}
public String getProfileName(long time, boolean customized) {
public String getProfileName(long time, boolean customized, boolean showRemainingTime) {
String profileName = MainApp.gs(R.string.noprofileselected);
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
ProfileInterface activeProfile = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
ProfileSwitch profileSwitch = activeTreatments.getProfileSwitchFromHistory(time);
if (profileSwitch != null) {
if (profileSwitch.profileJson != null) {
return customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName;
profileName = customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName;
} else {
ProfileStore profileStore = activeProfile.getProfile();
if (profileStore != null) {
Profile profile = profileStore.getSpecificProfile(profileSwitch.profileName);
if (profile != null)
return profileSwitch.profileName;
profileName = profileSwitch.profileName;
}
}
if (showRemainingTime && profileSwitch.durationInMinutes != 0) {
profileName += DateUtil.untilString(profileSwitch.originalEnd());
}
return profileName;
}
return MainApp.gs(R.string.noprofileselected);
return profileName;
}
public boolean isProfileValid(String from) {
@ -176,7 +184,7 @@ public class ProfileFunctions {
profileSwitch = new ProfileSwitch();
profileSwitch.date = System.currentTimeMillis();
profileSwitch.source = Source.USER;
profileSwitch.profileName = getInstance().getProfileName(System.currentTimeMillis(), false);
profileSwitch.profileName = getInstance().getProfileName(System.currentTimeMillis(), false, false);
profileSwitch.profileJson = getInstance().getProfile().getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration;

View file

@ -22,7 +22,7 @@ import info.nightscout.androidaps.plugins.general.overview.notifications.Notific
public class DstHelperPlugin extends PluginBase implements ConstraintsInterface {
public static final int DISABLE_TIMEFRAME_HOURS = -3;
public static final int WARN_PRIOR_TIMEFRAME_HOURS = 24;
public static final int WARN_PRIOR_TIMEFRAME_HOURS = 12;
private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS);
static DstHelperPlugin plugin = null;

View file

@ -4,6 +4,7 @@ import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@ -12,6 +13,7 @@ import android.widget.Button
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
@ -21,6 +23,8 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
import info.nightscout.androidaps.plugins.constraints.objectives.dialogs.NtpProgressDialog
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
@ -101,18 +105,20 @@ class ObjectivesFragment : Fragment() {
}
private fun scrollToCurrentObjective() {
for (i in 0 until ObjectivesPlugin.objectives.size) {
val objective = ObjectivesPlugin.objectives[i]
if (!objective.isStarted || !objective.isAccomplished) {
context?.let {
val smoothScroller = object : LinearSmoothScroller(it) {
override fun getVerticalSnapPreference(): Int = SNAP_TO_START
override fun calculateTimeForScrolling(dx: Int): Int = super.calculateTimeForScrolling(dx) * 4
activity?.runOnUiThread {
for (i in 0 until ObjectivesPlugin.objectives.size) {
val objective = ObjectivesPlugin.objectives[i]
if (!objective.isStarted || !objective.isAccomplished) {
context?.let {
val smoothScroller = object : LinearSmoothScroller(it) {
override fun getVerticalSnapPreference(): Int = SNAP_TO_START
override fun calculateTimeForScrolling(dx: Int): Int = super.calculateTimeForScrolling(dx) * 4
}
smoothScroller.targetPosition = i
objectives_recyclerview.layoutManager?.startSmoothScroll(smoothScroller)
}
smoothScroller.targetPosition = i
objectives_recyclerview.layoutManager?.startSmoothScroll(smoothScroller)
break
}
break
}
}
}
@ -126,7 +132,6 @@ class ObjectivesFragment : Fragment() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val objective = ObjectivesPlugin.objectives[position]
holder.title.text = MainApp.gs(R.string.nth_objective, position + 1)
holder.revert.visibility = View.GONE
if (objective.objective != 0) {
holder.objective.visibility = View.VISIBLE
holder.objective.text = MainApp.gs(objective.objective)
@ -142,6 +147,8 @@ class ObjectivesFragment : Fragment() {
holder.verify.visibility = View.GONE
holder.progress.visibility = View.GONE
holder.accomplished.visibility = View.GONE
holder.unFinish.visibility = View.GONE
holder.unStart.visibility = View.GONE
if (position == 0 || ObjectivesPlugin.objectives[position - 1].isAccomplished)
holder.start.visibility = View.VISIBLE
else
@ -152,15 +159,16 @@ class ObjectivesFragment : Fragment() {
holder.progress.visibility = View.GONE
holder.start.visibility = View.GONE
holder.accomplished.visibility = View.VISIBLE
holder.unFinish.visibility = View.VISIBLE
holder.unStart.visibility = View.GONE
} else if (objective.isStarted) {
holder.gate.setTextColor(-0x1)
holder.verify.visibility = View.VISIBLE
holder.verify.isEnabled = objective.isCompleted || objectives_fake.isChecked
holder.start.visibility = View.GONE
holder.accomplished.visibility = View.GONE
if (objective.isRevertable) {
holder.revert.visibility = View.VISIBLE
}
holder.unFinish.visibility = View.GONE
holder.unStart.visibility = View.VISIBLE
holder.progress.visibility = View.VISIBLE
holder.progress.removeAllViews()
for (task in objective.tasks) {
@ -203,76 +211,87 @@ class ObjectivesFragment : Fragment() {
holder.accomplished.text = MainApp.gs(R.string.accomplished, DateUtil.dateAndTimeString(objective.accomplishedOn))
holder.accomplished.setTextColor(-0x3e3e3f)
holder.verify.setOnClickListener {
holder.verify.visibility = View.INVISIBLE
NetworkChangeReceiver.fetch()
NetworkChangeReceiver.grabNetworkStatus(context)
if (objectives_fake.isChecked) {
objective.accomplishedOn = DateUtil.now()
scrollToCurrentObjective()
startUpdateTimer()
RxBus.send(EventObjectivesUpdateGui())
} else
SntpClient.ntpTime(object : SntpClient.Callback() {
override fun run() {
activity?.runOnUiThread {
holder.verify.visibility = View.VISIBLE
} else {
// move out of UI thread
Thread {
NtpProgressDialog().show((context as AppCompatActivity).supportFragmentManager, "NtpCheck")
RxBus.send(EventNtpStatus(MainApp.gs(R.string.timedetection), 0))
SntpClient.ntpTime(object : SntpClient.Callback() {
override fun run() {
log.debug("NTP time: $time System time: ${DateUtil.now()}")
SystemClock.sleep(300)
if (!networkConnected) {
ToastUtils.showToastInUiThread(context, R.string.notconnected)
RxBus.send(EventNtpStatus(MainApp.gs(R.string.notconnected), 99))
} else if (success) {
if (objective.isCompleted(time)) {
objective.accomplishedOn = time
scrollToCurrentObjective()
startUpdateTimer()
RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
SystemClock.sleep(1000)
RxBus.send(EventObjectivesUpdateGui())
SystemClock.sleep(100)
scrollToCurrentObjective()
} else {
ToastUtils.showToastInUiThread(context, R.string.requirementnotmet)
RxBus.send(EventNtpStatus(MainApp.gs(R.string.requirementnotmet), 99))
}
} else {
ToastUtils.showToastInUiThread(context, R.string.failedretrievetime)
RxBus.send(EventNtpStatus(MainApp.gs(R.string.failedretrievetime), 99))
}
}
}
}, NetworkChangeReceiver.isConnected())
}, NetworkChangeReceiver.isConnected())
}.start()
}
}
holder.start.setOnClickListener {
holder.start.visibility = View.INVISIBLE
NetworkChangeReceiver.fetch()
NetworkChangeReceiver.grabNetworkStatus(context)
if (objectives_fake.isChecked) {
objective.startedOn = DateUtil.now()
scrollToCurrentObjective()
startUpdateTimer()
RxBus.send(EventObjectivesUpdateGui())
} else
SntpClient.ntpTime(object : SntpClient.Callback() {
override fun run() {
activity?.runOnUiThread {
holder.start.visibility = View.VISIBLE
// move out of UI thread
Thread {
NtpProgressDialog().show((context as AppCompatActivity).supportFragmentManager, "NtpCheck")
RxBus.send(EventNtpStatus(MainApp.gs(R.string.timedetection), 0))
SntpClient.ntpTime(object : SntpClient.Callback() {
override fun run() {
log.debug("NTP time: $time System time: ${DateUtil.now()}")
SystemClock.sleep(300)
if (!networkConnected) {
ToastUtils.showToastInUiThread(context, R.string.notconnected)
RxBus.send(EventNtpStatus(MainApp.gs(R.string.notconnected), 99))
} else if (success) {
objective.startedOn = time
scrollToCurrentObjective()
startUpdateTimer()
RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
SystemClock.sleep(1000)
RxBus.send(EventObjectivesUpdateGui())
SystemClock.sleep(100)
scrollToCurrentObjective()
} else {
ToastUtils.showToastInUiThread(context, R.string.failedretrievetime)
RxBus.send(EventNtpStatus(MainApp.gs(R.string.failedretrievetime), 99))
}
}
}
}, NetworkChangeReceiver.isConnected())
}, NetworkChangeReceiver.isConnected())
}.start()
}
holder.revert.setOnClickListener {
objective.accomplishedOn = 0
objective.startedOn = 0
if (position > 0) {
val prevObj = ObjectivesPlugin.objectives[position - 1]
prevObj.accomplishedOn = 0
holder.unStart.setOnClickListener {
OKDialog.showConfirmation(activity, MainApp.gs(R.string.doyouwantresetstart)) {
objective.startedOn = 0
scrollToCurrentObjective()
RxBus.send(EventObjectivesUpdateGui())
}
}
holder.unFinish.setOnClickListener {
objective.accomplishedOn = 0
scrollToCurrentObjective()
RxBus.send(EventObjectivesUpdateGui())
}
if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted) {
if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted && objective.specialActionEnabled()) {
// generate random request code if none exists
val request = SP.getString(R.string.key_objectives_request_code, String.format("%1$05d", (Math.random() * 99999).toInt()))
SP.putString(R.string.key_objectives_request_code, request)
@ -307,7 +326,8 @@ class ObjectivesFragment : Fragment() {
val progress: LinearLayout = itemView.findViewById(R.id.objective_progress)
val verify: Button = itemView.findViewById(R.id.objective_verify)
val start: Button = itemView.findViewById(R.id.objective_start)
val revert: Button = itemView.findViewById(R.id.objective_back)
val unFinish: Button = itemView.findViewById(R.id.objective_unfinish)
val unStart: Button = itemView.findViewById(R.id.objective_unstart)
val inputHint: TextView = itemView.findViewById(R.id.objective_inputhint)
val input: EditText = itemView.findViewById(R.id.objective_input)
val enterButton: Button = itemView.findViewById(R.id.objective_enterbutton)

View file

@ -104,8 +104,8 @@ object ObjectivesPlugin : PluginBase(PluginDescription()
fun completeObjectives(activity: Activity, request: String) {
val requestCode = SP.getString(R.string.key_objectives_request_code, "")
var url = SP.getString(R.string.key_nsclientinternal_url, "").toLowerCase()
if (!url.endsWith("\"")) url = "$url/"
val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString()
if (!url.endsWith("/")) url = "$url/"
@Suppress("DEPRECATION") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString()
if (request.equals(hashNS.substring(0, 10), ignoreCase = true)) {
SP.putLong("Objectives_" + "openloop" + "_started", DateUtil.now())
SP.putLong("Objectives_" + "openloop" + "_accomplished", DateUtil.now())

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.plugins.constraints.objectives.dialogs
import android.os.Bundle
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.bus.RxBus.toObservable
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus
import info.nightscout.androidaps.utils.FabricPrivacy
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.overview_bolusprogress_dialog.*
import org.slf4j.LoggerFactory
class NtpProgressDialog : DialogFragment() {
private val log = LoggerFactory.getLogger(L.UI)
private val disposable = CompositeDisposable()
private val DEFAULT_STATE = MainApp.gs(R.string.timedetection)
private var state: String = DEFAULT_STATE
private var percent = 0
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
dialog?.setTitle(String.format(MainApp.gs(R.string.objectives)))
isCancelable = false
state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE
percent = savedInstanceState?.getInt("percent", 0) ?: 0
return inflater.inflate(R.layout.overview_bolusprogress_dialog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
overview_bolusprogress_stop.setOnClickListener { dismiss() }
overview_bolusprogress_status.setText(state)
overview_bolusprogress_progressbar.setMax(100)
overview_bolusprogress_progressbar.setProgress(percent)
overview_bolusprogress_stop.text = MainApp.gs(R.string.close)
}
override fun onResume() {
super.onResume()
if (L.isEnabled(L.UI)) log.debug("onResume")
if (percent == 100) {
dismiss()
return
} else
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
disposable.add(toObservable(EventNtpStatus::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ event: EventNtpStatus ->
if (L.isEnabled(L.UI)) log.debug("Status: " + event.status + " Percent: " + event.percent)
overview_bolusprogress_status?.text = event.status
overview_bolusprogress_progressbar?.progress = event.percent
if (event.percent == 100) {
SystemClock.sleep(100)
dismiss()
}
state = event.status
percent = event.percent
}) { FabricPrivacy.logException(it) }
)
}
override fun onPause() {
if (L.isEnabled(L.UI)) log.debug("onPause")
super.onPause()
disposable.clear()
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putString("state", state)
outState.putInt("percent", percent)
super.onSaveInstanceState(outState)
}
}

View file

@ -0,0 +1,5 @@
package info.nightscout.androidaps.plugins.constraints.objectives.events
import info.nightscout.androidaps.events.Event
class EventNtpStatus(val status: String, val percent: Int) : Event()

View file

@ -61,10 +61,6 @@ public abstract class Objective {
return true;
}
public boolean isRevertable() {
return false;
}
public boolean isAccomplished() {
return accomplishedOn != 0 && accomplishedOn < DateUtil.now();
}
@ -107,6 +103,8 @@ public abstract class Objective {
return tasks;
}
public boolean specialActionEnabled() { return true; }
public void specialAction(Activity activity, String input) {}
public abstract class Task {

View file

@ -7,6 +7,7 @@ import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
@ -38,6 +39,11 @@ public class Objective3 extends Objective {
});
}
@Override
public boolean specialActionEnabled() {
return NSClientPlugin.getPlugin().nsClientService.isConnected && NSClientPlugin.getPlugin().nsClientService.hasWriteAuth;
}
@Override
public void specialAction(Activity activity, String input) {
ObjectivesPlugin.INSTANCE.completeObjectives(activity, input);

View file

@ -25,9 +25,4 @@ public class Objective5 extends Objective {
}
});
}
@Override
public boolean isRevertable() {
return true;
}
}

View file

@ -10,8 +10,11 @@ import java.util.List;
import info.nightscout.androidaps.plugins.general.automation.actions.Action;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AutomationEvent {
private static final Logger log = LoggerFactory.getLogger(AutomationEvent.class);
private Trigger trigger = new TriggerConnector();
private List<Action> actions = new ArrayList<>();
@ -74,7 +77,7 @@ public class AutomationEvent {
}
o.put("actions", array);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -91,7 +94,7 @@ public class AutomationEvent {
actions.add(Action.instantiate(new JSONObject(array.getString(i))));
}
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -11,6 +11,8 @@ import javax.annotation.Nullable;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
import info.nightscout.androidaps.queue.Callback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
Action ideas:
@ -44,6 +46,7 @@ import info.nightscout.androidaps.queue.Callback;
public abstract class Action {
private static final Logger log = LoggerFactory.getLogger(Action.class);
public Trigger precondition = null;
@ -65,7 +68,7 @@ public abstract class Action {
try {
o.put("type", this.getClass().getName());
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -84,7 +87,7 @@ public abstract class Action {
Class clazz = Class.forName(type);
return ((Action) clazz.newInstance()).fromJSON(data != null ? data.toString() : "");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return null;
}
@ -98,7 +101,7 @@ public abstract class Action {
fromJSON(data.toString());
}
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
}
}

View file

@ -18,8 +18,12 @@ import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithE
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.JsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ActionLoopSuspend extends Action {
private static final Logger log = LoggerFactory.getLogger(ActionLoopSuspend.class);
public InputDuration minutes = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
@Override
@ -59,7 +63,7 @@ public class ActionLoopSuspend extends Action {
o.put("type", this.getClass().getName());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -70,7 +74,7 @@ public class ActionLoopSuspend extends Action {
JSONObject o = new JSONObject(data);
minutes.setMinutes(JsonHelper.safeGetInt(o, "minutes"));
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -20,8 +20,12 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.JsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ActionNotification extends Action {
private static final Logger log = LoggerFactory.getLogger(ActionNotification.class);
public InputString text = new InputString();
@Override
@ -59,7 +63,7 @@ public class ActionNotification extends Action {
o.put("type", this.getClass().getName());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -70,7 +74,7 @@ public class ActionNotification extends Action {
JSONObject o = new JSONObject(data);
text.setValue(JsonHelper.safeGetString(o, "text"));
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -92,7 +92,7 @@ public class ActionProfileSwitch extends Action {
data.put("profileToSwitchTo", inputProfileName.getValue());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -105,7 +105,7 @@ public class ActionProfileSwitch extends Action {
profileName = JsonHelper.safeGetString(d, "profileToSwitchTo");
inputProfileName.setValue(profileName);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -19,8 +19,12 @@ import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuil
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerProfilePercent;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.JsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ActionProfileSwitchPercent extends Action {
private static final Logger log = LoggerFactory.getLogger(ActionProfileSwitchPercent.class);
InputPercent pct = new InputPercent();
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
@ -71,7 +75,7 @@ public class ActionProfileSwitchPercent extends Action {
data.put("durationInMinutes", duration.getMinutes());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -83,7 +87,7 @@ public class ActionProfileSwitchPercent extends Action {
pct.setValue(JsonHelper.safeGetInt(d, "percentage"));
duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes"));
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -21,6 +21,7 @@ import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.JsonHelper;
public class ActionSendSMS extends Action {
private static final Logger log = LoggerFactory.getLogger(ActionSendSMS.class);
public InputString text = new InputString();
@ -36,7 +37,7 @@ public class ActionSendSMS extends Action {
@Override
public void doAction(Callback callback) {
boolean result = SmsCommunicatorPlugin.getPlugin().sendNotificationToAllNumbers(text.getValue());
boolean result = SmsCommunicatorPlugin.INSTANCE.sendNotificationToAllNumbers(text.getValue());
if (callback != null)
callback.result(new PumpEnactResult().success(result).comment(result ? R.string.ok : R.string.danar_error)).run();
@ -56,7 +57,7 @@ public class ActionSendSMS extends Action {
o.put("type", this.getClass().getName());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -67,7 +68,7 @@ public class ActionSendSMS extends Action {
JSONObject o = new JSONObject(data);
text.setValue(JsonHelper.safeGetString(o, "text"));
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -24,8 +24,12 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ActionStartTempTarget extends Action {
private static final Logger log = LoggerFactory.getLogger(ActionStartTempTarget.class);
String reason = "";
InputTempTarget value = new InputTempTarget();
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
@ -93,7 +97,7 @@ public class ActionStartTempTarget extends Action {
data.put("durationInMinutes", duration.getMinutes());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -107,7 +111,7 @@ public class ActionStartTempTarget extends Action {
value.setValue(JsonHelper.safeGetDouble(d, "value"));
duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes"));
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -14,8 +14,12 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ActionStopTempTarget extends Action {
private static final Logger log = LoggerFactory.getLogger(ActionStopTempTarget.class);
String reason = "";
private TempTarget tempTarget;
@ -54,7 +58,7 @@ public class ActionStopTempTarget extends Action {
data.put("reason", reason);
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -65,7 +69,7 @@ public class ActionStopTempTarget extends Action {
JSONObject d = new JSONObject(data);
reason = JsonHelper.safeGetString(d, "reason");
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -13,10 +13,13 @@ import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
public abstract class Trigger {
private static final Logger log = LoggerFactory.getLogger(Trigger.class);
TriggerConnector connector = null;
long lastRun;
@ -56,7 +59,7 @@ public abstract class Trigger {
try {
return instantiate(new JSONObject(json));
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return null;
}
@ -69,7 +72,7 @@ public abstract class Trigger {
Class clazz = Class.forName(type);
return ((Trigger) clazz.newInstance()).fromJSON(data.toString());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return null;
}

View file

@ -89,7 +89,7 @@ public class TriggerAutosensValue extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -102,7 +102,7 @@ public class TriggerAutosensValue extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -104,7 +104,7 @@ public class TriggerBg extends Trigger {
data.put("units", bg.getUnits());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -118,7 +118,7 @@ public class TriggerBg extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -86,7 +86,7 @@ public class TriggerBolusAgo extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -99,7 +99,7 @@ public class TriggerBolusAgo extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -87,7 +87,7 @@ public class TriggerCOB extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -100,7 +100,7 @@ public class TriggerCOB extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -162,7 +162,7 @@ public class TriggerConnector extends Trigger {
data.put("triggerList", array);
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -179,7 +179,7 @@ public class TriggerConnector extends Trigger {
add(newItem);
}
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -129,7 +129,7 @@ public class TriggerDelta extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -144,7 +144,7 @@ public class TriggerDelta extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -82,7 +82,7 @@ public class TriggerIob extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -95,7 +95,7 @@ public class TriggerIob extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -93,7 +93,7 @@ public class TriggerLocation extends Trigger {
data.put("lastRun", lastRun);
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -108,7 +108,7 @@ public class TriggerLocation extends Trigger {
name.setValue(JsonHelper.safeGetString(d, "name"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -88,7 +88,7 @@ public class TriggerProfilePercent extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -101,7 +101,7 @@ public class TriggerProfilePercent extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -82,7 +82,7 @@ public class TriggerPumpLastConnection extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -95,7 +95,7 @@ public class TriggerPumpLastConnection extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -163,7 +163,7 @@ public class TriggerRecurringTime extends Trigger {
object.put("type", TriggerRecurringTime.class.getName());
object.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return object.toString();
}
@ -181,7 +181,7 @@ public class TriggerRecurringTime extends Trigger {
minute = JsonHelper.safeGetInt(o, "minute");
validTo = JsonHelper.safeGetLong(o, "validTo");
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -74,7 +74,7 @@ public class TriggerTempTarget extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -86,7 +86,7 @@ public class TriggerTempTarget extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(ComparatorExists.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -65,7 +65,7 @@ public class TriggerTime extends Trigger {
object.put("type", TriggerTime.class.getName());
object.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return object.toString();
}
@ -78,7 +78,7 @@ public class TriggerTime extends Trigger {
lastRun = JsonHelper.safeGetLong(o, "lastRun");
runAt = JsonHelper.safeGetLong(o, "runAt");
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -93,7 +93,7 @@ public class TriggerTimeRange extends Trigger {
object.put("type", TriggerTimeRange.class.getName());
object.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
log.debug(object.toString());
return object.toString();
@ -108,7 +108,7 @@ public class TriggerTimeRange extends Trigger {
start = JsonHelper.safeGetInt(o, "start");
end = JsonHelper.safeGetInt(o, "end");
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -85,7 +85,7 @@ public class TriggerWifiSsid extends Trigger {
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return o.toString();
}
@ -98,7 +98,7 @@ public class TriggerWifiSsid extends Trigger {
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return this;
}

View file

@ -7,9 +7,12 @@ import android.content.ServiceConnection;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.text.Html;
import android.text.Spanned;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -89,7 +92,7 @@ public class NSClientPlugin extends PluginBase {
}
nsClientReceiverDelegate =
new NsClientReceiverDelegate(MainApp.instance().getApplicationContext());
new NsClientReceiverDelegate();
}
public boolean isAllowed() {
@ -104,7 +107,7 @@ public class NSClientPlugin extends PluginBase {
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
super.onStart();
nsClientReceiverDelegate.registerReceivers();
nsClientReceiverDelegate.grabReceiversState();
disposable.add(RxBus.INSTANCE
.toObservable(EventNSClientStatus.class)
.observeOn(Schedulers.io())
@ -129,7 +132,6 @@ public class NSClientPlugin extends PluginBase {
.subscribe(event -> {
if (nsClientService != null) {
MainApp.instance().getApplicationContext().unbindService(mConnection);
nsClientReceiverDelegate.unregisterReceivers();
}
}, FabricPrivacy::logException)
);
@ -152,11 +154,27 @@ public class NSClientPlugin extends PluginBase {
@Override
protected void onStop() {
MainApp.instance().getApplicationContext().unbindService(mConnection);
nsClientReceiverDelegate.unregisterReceivers();
disposable.clear();
super.onStop();
}
@Override
public void preprocessPreferences(@NotNull PreferenceFragment preferenceFragment) {
super.preprocessPreferences(preferenceFragment);
if (Config.NSCLIENT) {
PreferenceScreen scrnAdvancedSettings = (PreferenceScreen) preferenceFragment.findPreference(MainApp.gs(R.string.key_advancedsettings));
if (scrnAdvancedSettings != null) {
scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_res_warning)));
scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_res_critical)));
scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_bat_warning)));
scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_bat_critical)));
scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_show_statuslights)));
scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_show_statuslights_extended)));
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {

View file

@ -594,7 +594,7 @@ public class NSUpload {
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
}

View file

@ -18,44 +18,19 @@ import info.nightscout.androidaps.utils.SP;
class NsClientReceiverDelegate {
private final Context context;
private NetworkChangeReceiver networkChangeReceiver = new NetworkChangeReceiver();
private ChargingStateReceiver chargingStateReceiver = new ChargingStateReceiver();
private boolean allowedChargingState = true;
private boolean allowedNetworkState = true;
boolean allowed = true;
NsClientReceiverDelegate(Context context) {
this.context = context;
}
void registerReceivers() {
void grabReceiversState() {
Context context = MainApp.instance().getApplicationContext();
// register NetworkChangeReceiver --> https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html
// Nougat is not providing Connectivity-Action anymore ;-(
context.registerReceiver(networkChangeReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
context.registerReceiver(networkChangeReceiver,
new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
EventNetworkChange event = networkChangeReceiver.grabNetworkStatus(context);
if (event != null)
RxBus.INSTANCE.send(event);
EventNetworkChange event = NetworkChangeReceiver.grabNetworkStatus(context);
if (event != null) RxBus.INSTANCE.send(event);
context.registerReceiver(chargingStateReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
EventChargingState eventChargingState = ChargingStateReceiver.grabChargingState(context);
if (eventChargingState != null) RxBus.INSTANCE.send(eventChargingState);
EventChargingState eventChargingState = chargingStateReceiver.grabChargingState(context);
if (eventChargingState != null)
RxBus.INSTANCE.send(eventChargingState);
}
void unregisterReceivers() {
context.unregisterReceiver(networkChangeReceiver);
context.unregisterReceiver(chargingStateReceiver);
}
void onStatusEvent(EventPreferenceChange ev) {
@ -63,11 +38,11 @@ class NsClientReceiverDelegate {
ev.isChanged(R.string.key_ns_wifi_ssids) ||
ev.isChanged(R.string.key_ns_allowroaming)
) {
EventNetworkChange event = networkChangeReceiver.grabNetworkStatus(MainApp.instance().getApplicationContext());
EventNetworkChange event = NetworkChangeReceiver.grabNetworkStatus(MainApp.instance().getApplicationContext());
if (event != null)
RxBus.INSTANCE.send(event);
} else if (ev.isChanged(R.string.key_ns_chargingonly)) {
EventChargingState event = chargingStateReceiver.grabChargingState(MainApp.instance().getApplicationContext());
EventChargingState event = ChargingStateReceiver.grabChargingState(MainApp.instance().getApplicationContext());
if (event != null)
RxBus.INSTANCE.send(event);
}
@ -91,7 +66,7 @@ class NsClientReceiverDelegate {
}
}
void processStateChange() {
private void processStateChange() {
boolean newAllowedState = allowedChargingState && allowedNetworkState;
if (newAllowedState != allowed) {
allowed = newAllowedState;
@ -101,7 +76,6 @@ class NsClientReceiverDelegate {
boolean calculateStatus(final EventChargingState ev) {
boolean chargingOnly = SP.getBoolean(R.string.key_ns_chargingonly, false);
boolean newAllowedState = true;
if (!ev.isCharging() && chargingOnly) {
@ -129,8 +103,6 @@ class NsClientReceiverDelegate {
}
}
return newAllowedState;
}
}

View file

@ -1223,7 +1223,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
extendedBolusView.setVisibility(View.VISIBLE);
}
activeProfileView.setText(ProfileFunctions.getInstance().getProfileName());
activeProfileView.setText(ProfileFunctions.getInstance().getProfileNameWithDuration());
if (profile.getPercentage() != 100 || profile.getTimeshift() != 0) {
activeProfileView.setBackgroundColor(MainApp.gc(R.color.ribbonWarning));
activeProfileView.setTextColor(MainApp.gc(R.color.ribbonTextWarning));

View file

@ -1,59 +0,0 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
class AuthRequest {
private static Logger log = LoggerFactory.getLogger(L.SMS);
Sms requester;
String confirmCode;
private Runnable action;
private long date;
private boolean processed;
private SmsCommunicatorPlugin plugin;
AuthRequest(SmsCommunicatorPlugin plugin, Sms requester, String requestText, String confirmCode, SmsAction action) {
this.requester = requester;
this.confirmCode = confirmCode;
this.action = action;
this.plugin = plugin;
this.date = DateUtil.now();
plugin.sendSMS(new Sms(requester.phoneNumber, requestText));
}
void action(String codeReceived) {
if (processed) {
if (L.isEnabled(L.SMS))
log.debug("Already processed");
return;
}
if (!confirmCode.equals(codeReceived)) {
processed = true;
if (L.isEnabled(L.SMS))
log.debug("Wrong code");
plugin.sendSMS(new Sms(requester.phoneNumber, R.string.sms_wrongcode));
return;
}
if (DateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) {
processed = true;
if (L.isEnabled(L.SMS))
log.debug("Processing confirmed SMS: " + requester.text);
if (action != null)
action.run();
return;
}
if (L.isEnabled(L.SMS))
log.debug("Timed out SMS: " + requester.text);
}
}

View file

@ -0,0 +1,38 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.utils.DateUtil
import org.slf4j.LoggerFactory
class AuthRequest internal constructor(val plugin: SmsCommunicatorPlugin, var requester: Sms, requestText: String, var confirmCode: String, val action: SmsAction) {
private val log = LoggerFactory.getLogger(L.SMS)
private val date = DateUtil.now()
private var processed = false
init {
plugin.sendSMS(Sms(requester.phoneNumber, requestText))
}
fun action(codeReceived: String) {
if (processed) {
if (L.isEnabled(L.SMS)) log.debug("Already processed")
return
}
if (confirmCode != codeReceived) {
processed = true
if (L.isEnabled(L.SMS)) log.debug("Wrong code")
plugin.sendSMS(Sms(requester.phoneNumber, R.string.sms_wrongcode))
return
}
if (DateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) {
processed = true
if (L.isEnabled(L.SMS)) log.debug("Processing confirmed SMS: " + requester.text)
action.run()
return
}
if (L.isEnabled(L.SMS)) log.debug("Timed out SMS: " + requester.text)
}
}

View file

@ -1,42 +0,0 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator;
import android.telephony.SmsMessage;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.utils.DateUtil;
class Sms {
String phoneNumber;
String text;
long date;
boolean received = false;
boolean sent = false;
boolean processed = false;
boolean ignored = false;
Sms(SmsMessage message) {
phoneNumber = message.getOriginatingAddress();
text = message.getMessageBody();
date = message.getTimestampMillis();
received = true;
}
Sms(String phoneNumber, String text) {
this.phoneNumber = phoneNumber;
this.text = text;
this.date = DateUtil.now();
sent = true;
}
Sms(String phoneNumber, int textId) {
this.phoneNumber = phoneNumber;
this.text = MainApp.gs(textId);
this.date = DateUtil.now();
sent = true;
}
public String toString() {
return "SMS from " + phoneNumber + ": " + text;
}
}

View file

@ -0,0 +1,40 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
import android.telephony.SmsMessage
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.utils.DateUtil
class Sms {
var phoneNumber: String
var text: String
var date: Long
var received = false
var sent = false
var processed = false
var ignored = false
internal constructor(message: SmsMessage) {
phoneNumber = message.originatingAddress ?: ""
text = message.messageBody
date = message.timestampMillis
received = true
}
internal constructor(phoneNumber: String, text: String) {
this.phoneNumber = phoneNumber
this.text = text
date = DateUtil.now()
sent = true
}
internal constructor(phoneNumber: String, textId: Int) {
this.phoneNumber = phoneNumber
text = MainApp.gs(textId)
date = DateUtil.now()
sent = true
}
override fun toString(): String {
return "SMS from $phoneNumber: $text"
}
}

View file

@ -1,33 +0,0 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator;
abstract class SmsAction implements Runnable {
Double aDouble;
Integer anInteger;
Integer secondInteger;
String aString;
SmsAction() {}
SmsAction(Double aDouble) {
this.aDouble = aDouble;
}
SmsAction(Double aDouble, Integer secondInteger) {
this.aDouble = aDouble;
this.secondInteger = secondInteger;
}
SmsAction(String aString, Integer secondInteger) {
this.aString = aString;
this.secondInteger = secondInteger;
}
SmsAction(Integer anInteger) {
this.anInteger = anInteger;
}
SmsAction(Integer anInteger, Integer secondInteger) {
this.anInteger = anInteger;
this.secondInteger = secondInteger;
}
}

View file

@ -0,0 +1,68 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
abstract class SmsAction : Runnable {
var aDouble: Double? = null
var anInteger: Int? = null
var secondInteger: Int? = null
var secondLong: Long? = null
var aString: String? = null
internal constructor()
internal constructor(aDouble: Double) {
this.aDouble = aDouble
}
internal constructor(aDouble: Double, secondInteger: Int) {
this.aDouble = aDouble
this.secondInteger = secondInteger
}
internal constructor(aString: String, secondInteger: Int) {
this.aString = aString
this.secondInteger = secondInteger
}
internal constructor(anInteger: Int) {
this.anInteger = anInteger
}
internal constructor(anInteger: Int, secondInteger: Int) {
this.anInteger = anInteger
this.secondInteger = secondInteger
}
internal constructor(anInteger: Int, secondLong: Long) {
this.anInteger = anInteger
this.secondLong = secondLong
}
fun aDouble(): Double {
return aDouble?.let {
aDouble
} ?: throw IllegalStateException()
}
fun anInteger(): Int {
return anInteger?.let {
anInteger
} ?: throw IllegalStateException()
}
fun secondInteger(): Int {
return secondInteger?.let {
secondInteger
} ?: throw IllegalStateException()
}
fun secondLong(): Long {
return secondLong?.let {
secondLong
} ?: throw IllegalStateException()
}
fun aString(): String {
return aString?.let {
aString
} ?: throw IllegalStateException()
}
}

View file

@ -1,83 +0,0 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator;
import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import java.util.Collections;
import java.util.Comparator;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
public class SmsCommunicatorFragment extends Fragment {
private CompositeDisposable disposable = new CompositeDisposable();
TextView logView;
public SmsCommunicatorFragment() {
super();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.smscommunicator_fragment, container, false);
logView = (TextView) view.findViewById(R.id.smscommunicator_log);
return view;
}
@Override
public synchronized void onResume() {
super.onResume();
disposable.add(RxBus.INSTANCE
.toObservable(EventSmsCommunicatorUpdateGui.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(event -> updateGui(), FabricPrivacy::logException)
);
updateGui();
}
@Override
public synchronized void onPause() {
super.onPause();
disposable.clear();
}
protected void updateGui() {
class CustomComparator implements Comparator<Sms> {
public int compare(Sms object1, Sms object2) {
return (int) (object1.date - object2.date);
}
}
Collections.sort(SmsCommunicatorPlugin.getPlugin().messages, new CustomComparator());
int messagesToShow = 40;
int start = Math.max(0, SmsCommunicatorPlugin.getPlugin().messages.size() - messagesToShow);
String logText = "";
for (int x = start; x < SmsCommunicatorPlugin.getPlugin().messages.size(); x++) {
Sms sms = SmsCommunicatorPlugin.getPlugin().messages.get(x);
if (sms.ignored) {
logText += DateUtil.timeString(sms.date) + " &lt;&lt;&lt; " + "" + sms.phoneNumber + " <b>" + sms.text + "</b><br>";
} else if (sms.received) {
logText += DateUtil.timeString(sms.date) + " &lt;&lt;&lt; " + (sms.processed ? "" : "") + sms.phoneNumber + " <b>" + sms.text + "</b><br>";
} else if (sms.sent) {
logText += DateUtil.timeString(sms.date) + " &gt;&gt;&gt; " + (sms.processed ? "" : "") + sms.phoneNumber + " <b>" + sms.text + "</b><br>";
}
}
logView.setText(Html.fromHtml(logText));
}
}

View file

@ -0,0 +1,70 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.bus.RxBus.toObservable
import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.smscommunicator_fragment.*
import java.util.*
import kotlin.math.max
class SmsCommunicatorFragment : Fragment() {
private val disposable = CompositeDisposable()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.smscommunicator_fragment, container, false)
}
@Synchronized
override fun onResume() {
super.onResume()
disposable.add(toObservable(EventSmsCommunicatorUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }) { FabricPrivacy.logException(it) }
)
updateGui()
}
@Synchronized
override fun onPause() {
super.onPause()
disposable.clear()
}
fun updateGui() {
class CustomComparator : Comparator<Sms> {
override fun compare(object1: Sms, object2: Sms): Int {
return (object1.date - object2.date).toInt()
}
}
Collections.sort(SmsCommunicatorPlugin.messages, CustomComparator())
val messagesToShow = 40
val start = max(0, SmsCommunicatorPlugin.messages.size - messagesToShow)
var logText = ""
for (x in start until SmsCommunicatorPlugin.messages.size) {
val sms = SmsCommunicatorPlugin.messages[x]
when {
sms.ignored -> {
logText += DateUtil.timeString(sms.date) + " &lt;&lt;&lt; " + "" + sms.phoneNumber + " <b>" + sms.text + "</b><br>"
}
sms.received -> {
logText += DateUtil.timeString(sms.date) + " &lt;&lt;&lt; " + (if (sms.processed) "" else "") + sms.phoneNumber + " <b>" + sms.text + "</b><br>"
}
sms.sent -> {
logText += DateUtil.timeString(sms.date) + " &gt;&gt;&gt; " + (if (sms.processed) "" else "") + sms.phoneNumber + " <b>" + sms.text + "</b><br>"
}
}
}
smscommunicator_log?.text = HtmlHelper.fromHtml(logText)
}
}

View file

@ -1,812 +0,0 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.SafeParse;
import info.nightscout.androidaps.utils.XdripCalibrations;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
/**
* Created by mike on 05.08.2016.
*/
public class SmsCommunicatorPlugin extends PluginBase {
private static Logger log = LoggerFactory.getLogger(L.SMS);
private CompositeDisposable disposable = new CompositeDisposable();
private static SmsCommunicatorPlugin smsCommunicatorPlugin;
public static SmsCommunicatorPlugin getPlugin() {
if (smsCommunicatorPlugin == null) {
smsCommunicatorPlugin = new SmsCommunicatorPlugin();
}
return smsCommunicatorPlugin;
}
List<String> allowedNumbers = new ArrayList<>();
AuthRequest messageToConfirm = null;
long lastRemoteBolusTime = 0;
ArrayList<Sms> messages = new ArrayList<>();
SmsCommunicatorPlugin() {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(SmsCommunicatorFragment.class.getName())
.pluginName(R.string.smscommunicator)
.shortName(R.string.smscommunicator_shortname)
.preferencesId(R.xml.pref_smscommunicator)
.description(R.string.description_sms_communicator)
);
processSettings(null);
}
@Override
protected void onStart() {
super.onStart();
disposable.add(RxBus.INSTANCE
.toObservable(EventPreferenceChange.class)
.observeOn(Schedulers.io())
.subscribe(event -> {
processSettings(event);
}, FabricPrivacy::logException)
);
}
@Override
protected void onStop() {
disposable.clear();
super.onStop();
}
private void processSettings(final EventPreferenceChange ev) {
if (ev == null || ev.isChanged(R.string.key_smscommunicator_allowednumbers)) {
String settings = SP.getString(R.string.key_smscommunicator_allowednumbers, "");
allowedNumbers.clear();
String[] substrings = settings.split(";");
for (String number : substrings) {
String cleaned = number.replaceAll("\\s+", "");
allowedNumbers.add(cleaned);
log.debug("Found allowed number: " + cleaned);
}
}
}
boolean isCommand(String command, String number) {
switch (command.toUpperCase()) {
case "BG":
case "LOOP":
case "TREATMENTS":
case "NSCLIENT":
case "PUMP":
case "BASAL":
case "BOLUS":
case "EXTENDED":
case "CAL":
case "PROFILE":
return true;
}
if (messageToConfirm != null && messageToConfirm.requester.phoneNumber.equals(number))
return true;
return false;
}
boolean isAllowedNumber(String number) {
for (String num : allowedNumbers) {
if (num.equals(number)) return true;
}
return false;
}
public void handleNewData(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
Object[] pdus = (Object[]) bundle.get("pdus");
if (pdus != null) {
// For every SMS message received
for (Object pdu : pdus) {
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu);
processSms(new Sms(message));
}
}
}
void processSms(final Sms receivedSms) {
if (!isEnabled(PluginType.GENERAL)) {
log.debug("Ignoring SMS. Plugin disabled.");
return;
}
if (!isAllowedNumber(receivedSms.phoneNumber)) {
log.debug("Ignoring SMS from: " + receivedSms.phoneNumber + ". Sender not allowed");
receivedSms.ignored = true;
messages.add(receivedSms);
RxBus.INSTANCE.send(new EventSmsCommunicatorUpdateGui());
return;
}
messages.add(receivedSms);
log.debug(receivedSms.toString());
String[] splitted = receivedSms.text.split("\\s+");
boolean remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false);
if (splitted.length > 0 && isCommand(splitted[0].toUpperCase(), receivedSms.phoneNumber)) {
switch (splitted[0].toUpperCase()) {
case "BG":
processBG(splitted, receivedSms);
break;
case "LOOP":
if (!remoteCommandsAllowed)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed));
else if (splitted.length == 2 || splitted.length == 3)
processLOOP(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
case "TREATMENTS":
if (splitted.length == 2)
processTREATMENTS(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
case "NSCLIENT":
if (splitted.length == 2)
processNSCLIENT(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
case "PUMP":
processPUMP(splitted, receivedSms);
break;
case "PROFILE":
if (!remoteCommandsAllowed)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed));
else if (splitted.length == 2 || splitted.length == 3)
processPROFILE(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
case "BASAL":
if (!remoteCommandsAllowed)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed));
else if (splitted.length == 2 || splitted.length == 3)
processBASAL(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
case "EXTENDED":
if (!remoteCommandsAllowed)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed));
else if (splitted.length == 2 || splitted.length == 3)
processEXTENDED(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
case "BOLUS":
if (!remoteCommandsAllowed)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed));
else if (splitted.length == 2 && DateUtil.now() - lastRemoteBolusTime < Constants.remoteBolusMinDistance)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotebolusnotallowed));
else if (splitted.length == 2 && ConfigBuilderPlugin.getPlugin().getActivePump().isSuspended())
sendSMS(new Sms(receivedSms.phoneNumber, R.string.pumpsuspended));
else if (splitted.length == 2)
processBOLUS(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
case "CAL":
if (!remoteCommandsAllowed)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed));
else if (splitted.length == 2)
processCAL(splitted, receivedSms);
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
default: // expect passCode here
if (messageToConfirm != null && messageToConfirm.requester.phoneNumber.equals(receivedSms.phoneNumber)) {
messageToConfirm.action(splitted[0]);
messageToConfirm = null;
} else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand));
break;
}
}
RxBus.INSTANCE.send(new EventSmsCommunicatorUpdateGui());
}
@SuppressWarnings("unused")
private void processBG(String[] splitted, Sms receivedSms) {
BgReading actualBG = DatabaseHelper.actualBg();
BgReading lastBG = DatabaseHelper.lastBg();
String reply = "";
String units = ProfileFunctions.getInstance().getProfileUnits();
if (actualBG != null) {
reply = MainApp.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsToString(units) + ", ";
} else if (lastBG != null) {
Long agoMsec = System.currentTimeMillis() - lastBG.date;
int agoMin = (int) (agoMsec / 60d / 1000d);
reply = MainApp.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(MainApp.gs(R.string.sms_minago), agoMin) + ", ";
}
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (glucoseStatus != null)
reply += MainApp.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", ";
TreatmentsPlugin.getPlugin().updateTotalIOBTreatments();
IobTotal bolusIob = TreatmentsPlugin.getPlugin().getLastCalculationTreatments().round();
TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals();
IobTotal basalIob = TreatmentsPlugin.getPlugin().getLastCalculationTempBasals().round();
String cobText = MainApp.gs(R.string.value_unavailable_short);
CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "SMS COB");
reply += MainApp.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U ("
+ MainApp.gs(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
+ MainApp.gs(R.string.sms_basal) + " " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U), "
+ MainApp.gs(R.string.cob) + ": " + cobInfo.generateCOBString();
sendSMS(new Sms(receivedSms.phoneNumber, reply));
receivedSms.processed = true;
}
private void processLOOP(String[] splitted, Sms receivedSms) {
String reply;
switch (splitted[1].toUpperCase()) {
case "DISABLE":
case "STOP":
LoopPlugin loopPlugin = LoopPlugin.getPlugin();
if (loopPlugin.isEnabled(PluginType.LOOP)) {
loopPlugin.setPluginEnabled(PluginType.LOOP, false);
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
@Override
public void run() {
RxBus.INSTANCE.send(new EventRefreshOverview("SMS_LOOP_STOP"));
String reply = MainApp.gs(R.string.smscommunicator_loophasbeendisabled) + " " +
MainApp.gs(result.success ? R.string.smscommunicator_tempbasalcanceled : R.string.smscommunicator_tempbasalcancelfailed);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
});
} else {
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisdisabled));
}
receivedSms.processed = true;
break;
case "ENABLE":
case "START":
loopPlugin = LoopPlugin.getPlugin();
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
loopPlugin.setPluginEnabled(PluginType.LOOP, true);
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loophasbeenenabled));
RxBus.INSTANCE.send(new EventRefreshOverview("SMS_LOOP_START"));
} else {
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisenabled));
}
receivedSms.processed = true;
break;
case "STATUS":
loopPlugin = LoopPlugin.getPlugin();
if (loopPlugin.isEnabled(PluginType.LOOP)) {
if (loopPlugin.isSuspended())
reply = String.format(MainApp.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend());
else
reply = MainApp.gs(R.string.smscommunicator_loopisenabled);
} else {
reply = MainApp.gs(R.string.smscommunicator_loopisdisabled);
}
sendSMS(new Sms(receivedSms.phoneNumber, reply));
receivedSms.processed = true;
break;
case "RESUME":
LoopPlugin.getPlugin().suspendTo(0);
RxBus.INSTANCE.send(new EventRefreshOverview("SMS_LOOP_RESUME"));
NSUpload.uploadOpenAPSOffline(0);
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopresumed));
break;
case "SUSPEND":
int duration = 0;
if (splitted.length == 3)
duration = SafeParse.stringToInt(splitted[2]);
duration = Math.max(0, duration);
duration = Math.min(180, duration);
if (duration == 0) {
receivedSms.processed = true;
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_wrongduration));
return;
} else {
String passCode = generatePasscode();
reply = String.format(MainApp.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(duration) {
@Override
public void run() {
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
@Override
public void run() {
if (result.success) {
LoopPlugin.getPlugin().suspendTo(System.currentTimeMillis() + anInteger * 60L * 1000);
NSUpload.uploadOpenAPSOffline(anInteger * 60);
RxBus.INSTANCE.send(new EventRefreshOverview("SMS_LOOP_SUSPENDED"));
String reply = MainApp.gs(R.string.smscommunicator_loopsuspended) + " " +
MainApp.gs(result.success ? R.string.smscommunicator_tempbasalcanceled : R.string.smscommunicator_tempbasalcancelfailed);
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply));
} else {
String reply = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
}
});
}
break;
default:
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
break;
}
}
private void processTREATMENTS(String[] splitted, Sms receivedSms) {
if (splitted[1].toUpperCase().equals("REFRESH")) {
TreatmentsPlugin.getPlugin().getService().resetTreatments();
RxBus.INSTANCE.send(new EventNSClientRestart());
sendSMS(new Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT"));
receivedSms.processed = true;
} else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
}
private void processNSCLIENT(String[] splitted, Sms receivedSms) {
if (splitted[1].toUpperCase().equals("RESTART")) {
RxBus.INSTANCE.send(new EventNSClientRestart());
sendSMS(new Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT"));
receivedSms.processed = true;
} else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
}
@SuppressWarnings("unused")
private void processPUMP(String[] splitted, Sms receivedSms) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("SMS", new Callback() {
@Override
public void run() {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (result.success) {
if (pump != null) {
String reply = pump.shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
} else {
String reply = MainApp.gs(R.string.readstatusfailed);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
receivedSms.processed = true;
}
private void processPROFILE(String[] splitted, Sms receivedSms) {
// load profiles
ProfileInterface anInterface = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
if (anInterface == null) {
sendSMS(new Sms(receivedSms.phoneNumber, R.string.notconfigured));
receivedSms.processed = true;
return;
}
ProfileStore store = anInterface.getProfile();
if (store == null) {
sendSMS(new Sms(receivedSms.phoneNumber, R.string.notconfigured));
receivedSms.processed = true;
return;
}
final ArrayList<CharSequence> list = store.getProfileList();
if (splitted[1].toUpperCase().equals("STATUS")) {
sendSMS(new Sms(receivedSms.phoneNumber, ProfileFunctions.getInstance().getProfileName()));
} else if (splitted[1].toUpperCase().equals("LIST")) {
if (list.isEmpty())
sendSMS(new Sms(receivedSms.phoneNumber, R.string.invalidprofile));
else {
String reply = "";
for (int i = 0; i < list.size(); i++) {
if (i > 0)
reply += "\n";
reply += (i + 1) + ". ";
reply += list.get(i);
}
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
} else {
int pindex = SafeParse.stringToInt(splitted[1]);
int percentage = 100;
if (splitted.length > 2)
percentage = SafeParse.stringToInt(splitted[2]);
if (pindex > list.size())
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else if (percentage == 0)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else if (pindex == 0)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else {
final Profile profile = store.getSpecificProfile((String) list.get(pindex - 1));
if (profile == null)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.noprofile));
else {
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_profilereplywithcode), list.get(pindex - 1), percentage, passCode);
receivedSms.processed = true;
int finalPercentage = percentage;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction((String) list.get(pindex - 1), finalPercentage) {
@Override
public void run() {
ProfileFunctions.doProfileSwitch(store, (String) list.get(pindex - 1), 0, finalPercentage, 0);
sendSMS(new Sms(receivedSms.phoneNumber, R.string.profileswitchcreated));
}
});
}
}
}
receivedSms.processed = true;
}
private void processBASAL(String[] splitted, Sms receivedSms) {
if (splitted[1].toUpperCase().equals("CANCEL") || splitted[1].toUpperCase().equals("STOP")) {
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_basalstopreplywithcode), passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction() {
@Override
public void run() {
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
@Override
public void run() {
if (result.success) {
String reply = MainApp.gs(R.string.smscommunicator_tempbasalcanceled);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply));
} else {
String reply = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
}
});
} else if (splitted[1].endsWith("%")) {
int tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%"));
int duration = 30;
if (splitted.length > 2)
duration = SafeParse.stringToInt(splitted[2]);
final Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.noprofile));
else if (tempBasalPct == 0 && !splitted[1].equals("0%"))
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else if (duration == 0)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else {
tempBasalPct = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(tempBasalPct), profile).value();
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(tempBasalPct, duration) {
@Override
public void run() {
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(anInteger, secondInteger, true, profile, new Callback() {
@Override
public void run() {
if (result.success) {
String reply;
if (result.isPercent)
reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration);
else
reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply));
} else {
String reply = MainApp.gs(R.string.smscommunicator_tempbasalfailed);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
}
});
}
} else {
Double tempBasal = SafeParse.stringToDouble(splitted[1]);
int duration = 30;
if (splitted.length > 2)
duration = SafeParse.stringToInt(splitted[2]);
final Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.noprofile));
else if (tempBasal == 0 && !splitted[1].equals("0"))
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else if (duration == 0)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else {
tempBasal = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(tempBasal), profile).value();
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(tempBasal, duration) {
@Override
public void run() {
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(aDouble, secondInteger, true, profile, new Callback() {
@Override
public void run() {
if (result.success) {
String reply;
if (result.isPercent)
reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration);
else
reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply));
} else {
String reply = MainApp.gs(R.string.smscommunicator_tempbasalfailed);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
}
});
}
}
}
private void processEXTENDED(String[] splitted, Sms receivedSms) {
if (splitted[1].toUpperCase().equals("CANCEL") || splitted[1].toUpperCase().equals("STOP")) {
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction() {
@Override
public void run() {
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelExtended(new Callback() {
@Override
public void run() {
if (result.success) {
String reply = MainApp.gs(R.string.smscommunicator_extendedcanceled);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply));
} else {
String reply = MainApp.gs(R.string.smscommunicator_extendedcancelfailed);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
}
});
} else if (splitted.length != 3) {
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
} else {
Double extended = SafeParse.stringToDouble(splitted[1]);
int duration = SafeParse.stringToInt(splitted[2]);
extended = MainApp.getConstraintChecker().applyExtendedBolusConstraints(new Constraint<>(extended)).value();
if (extended == 0 || duration == 0)
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
else {
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(extended, duration) {
@Override
public void run() {
ConfigBuilderPlugin.getPlugin().getCommandQueue().extendedBolus(aDouble, secondInteger, new Callback() {
@Override
public void run() {
if (result.success) {
String reply = String.format(MainApp.gs(R.string.smscommunicator_extendedset), aDouble, duration);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply));
} else {
String reply = MainApp.gs(R.string.smscommunicator_extendedfailed);
reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
}
});
}
}
}
private void processBOLUS(String[] splitted, Sms receivedSms) {
Double bolus = SafeParse.stringToDouble(splitted[1]);
bolus = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(bolus)).value();
if (bolus > 0d) {
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(bolus) {
@Override
public void run() {
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.insulin = aDouble;
detailedBolusInfo.source = Source.USER;
ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override
public void run() {
final boolean resultSuccess = result.success;
final double resultBolusDelivered = result.bolusDelivered;
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("SMS", new Callback() {
@Override
public void run() {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (resultSuccess) {
String reply = String.format(MainApp.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered);
if (pump != null)
reply += "\n" + pump.shortStatus(true);
lastRemoteBolusTime = DateUtil.now();
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply));
} else {
String reply = MainApp.gs(R.string.smscommunicator_bolusfailed);
if (pump != null)
reply += "\n" + pump.shortStatus(true);
sendSMS(new Sms(receivedSms.phoneNumber, reply));
}
}
});
}
});
}
});
} else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
}
private void processCAL(String[] splitted, Sms receivedSms) {
Double cal = SafeParse.stringToDouble(splitted[1]);
if (cal > 0d) {
String passCode = generatePasscode();
String reply = String.format(MainApp.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode);
receivedSms.processed = true;
messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(cal) {
@Override
public void run() {
boolean result = XdripCalibrations.sendIntent(aDouble);
if (result)
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationsent));
else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationfailed));
}
});
} else
sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat));
}
public boolean sendNotificationToAllNumbers(String text) {
boolean result = true;
for (int i = 0; i < allowedNumbers.size(); i++) {
Sms sms = new Sms(allowedNumbers.get(i), text);
result = result && sendSMS(sms);
}
return result;
}
private void sendSMSToAllNumbers(Sms sms) {
for (String number : allowedNumbers) {
sms.phoneNumber = number;
sendSMS(sms);
}
}
boolean sendSMS(Sms sms) {
SmsManager smsManager = SmsManager.getDefault();
sms.text = stripAccents(sms.text);
try {
if (L.isEnabled(L.SMS))
log.debug("Sending SMS to " + sms.phoneNumber + ": " + sms.text);
if (sms.text.getBytes().length <= 140)
smsManager.sendTextMessage(sms.phoneNumber, null, sms.text, null, null);
else {
ArrayList<String> parts = smsManager.divideMessage(sms.text);
smsManager.sendMultipartTextMessage(sms.phoneNumber, null, parts,
null, null);
}
messages.add(sms);
} catch (IllegalArgumentException e) {
if (e.getMessage().equals("Invalid message body")) {
Notification notification = new Notification(Notification.INVALID_MESSAGE_BODY, MainApp.gs(R.string.smscommunicator_messagebody), Notification.NORMAL);
RxBus.INSTANCE.send(new EventNewNotification(notification));
return false;
} else {
Notification notification = new Notification(Notification.INVALID_PHONE_NUMBER, MainApp.gs(R.string.smscommunicator_invalidphonennumber), Notification.NORMAL);
RxBus.INSTANCE.send(new EventNewNotification(notification));
return false;
}
} catch (java.lang.SecurityException e) {
Notification notification = new Notification(Notification.MISSING_SMS_PERMISSION, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.NORMAL);
RxBus.INSTANCE.send(new EventNewNotification(notification));
return false;
}
RxBus.INSTANCE.send(new EventSmsCommunicatorUpdateGui());
return true;
}
private String generatePasscode() {
int startChar1 = 'A'; // on iphone 1st char is uppercase :)
String passCode = Character.toString((char) (startChar1 + Math.random() * ('z' - 'a' + 1)));
int startChar2 = Math.random() > 0.5 ? 'a' : 'A';
passCode += Character.toString((char) (startChar2 + Math.random() * ('z' - 'a' + 1)));
int startChar3 = Math.random() > 0.5 ? 'a' : 'A';
passCode += Character.toString((char) (startChar3 + Math.random() * ('z' - 'a' + 1)));
passCode = passCode.replace('l', 'k').replace('I', 'J');
return passCode;
}
private static String stripAccents(String s) {
s = Normalizer.normalize(s, Normalizer.Form.NFD);
s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}]", "");
return s;
}
}

View file

@ -0,0 +1,922 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
import android.content.Intent
import android.preference.EditTextPreference
import android.preference.Preference
import android.preference.Preference.OnPreferenceChangeListener
import android.preference.PreferenceFragment
import android.telephony.SmsManager
import android.telephony.SmsMessage
import android.text.TextUtils
import com.andreabaccega.widget.ValidatingEditTextPreference
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.DatabaseHelper
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBus.send
import info.nightscout.androidaps.plugins.bus.RxBus.toObservable
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.*
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import org.apache.commons.lang3.StringUtils
import org.slf4j.LoggerFactory
import java.text.Normalizer
import java.util.*
object SmsCommunicatorPlugin : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(SmsCommunicatorFragment::class.java.name)
.pluginName(R.string.smscommunicator)
.shortName(R.string.smscommunicator_shortname)
.preferencesId(R.xml.pref_smscommunicator)
.description(R.string.description_sms_communicator)
) {
private val log = LoggerFactory.getLogger(L.SMS)
private val disposable = CompositeDisposable()
var allowedNumbers: MutableList<String> = ArrayList()
var messageToConfirm: AuthRequest? = null
var lastRemoteBolusTime: Long = 0
var messages = ArrayList<Sms>()
val commands = mapOf(
"BG" to "BG",
"LOOP" to "LOOP STOP/DISABLE/START/ENABLE/RESUME/STATUS\nLOOP SUSPEND 20",
"TREATMENTS" to "TREATMENTS REFRESH",
"NSCLIENT" to "NSCLIENT RESTART",
"PUMP" to "PUMP",
"BASAL" to "BASAL STOP/CANCEL\nBASAL 0.3\nBASAL 0.3 20\nBASAL 30%\nBASAL 30% 20\n",
"BOLUS" to "BOLUS 1.2\nBOLUS 1.2 MEAL",
"EXTENDED" to "EXTENDED STOP/CANCEL\nEXTENDED 2 120",
"CAL" to "CAL 5.6",
"PROFILE" to "PROFILE STATUS/LIST\nPROFILE 1\nPROFILE 2 30",
"TARGET" to "TARGET MEAL/ACTIVITY/HYPO/STOP",
"SMS" to "SMS DISABLE/STOP",
"CARBS" to "CARBS 12\nCARBS 12 23:05\nCARBS 12 11:05PM",
"HELP" to "HELP\nHELP command"
)
init {
processSettings(null)
}
override fun onStart() {
super.onStart()
disposable.add(toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ event: EventPreferenceChange? -> processSettings(event) }) { throwable: Throwable? -> FabricPrivacy.logException(throwable) }
)
}
override fun onStop() {
disposable.clear()
super.onStop()
}
override fun preprocessPreferences(preferenceFragment: PreferenceFragment) {
super.preprocessPreferences(preferenceFragment)
val distance = preferenceFragment.findPreference(MainApp.gs(R.string.key_smscommunicator_remotebolusmindistance)) as ValidatingEditTextPreference?
?: return
val allowedNumbers = preferenceFragment.findPreference(MainApp.gs(R.string.key_smscommunicator_allowednumbers)) as EditTextPreference?
?: return
if (!areMoreNumbers(allowedNumbers.text)) {
distance.title = (MainApp.gs(R.string.smscommunicator_remotebolusmindistance)
+ ".\n"
+ MainApp.gs(R.string.smscommunicator_remotebolusmindistance_caveat))
distance.isEnabled = false
} else {
distance.title = MainApp.gs(R.string.smscommunicator_remotebolusmindistance)
distance.isEnabled = true
}
allowedNumbers.onPreferenceChangeListener = OnPreferenceChangeListener { _: Preference?, newValue: Any ->
if (!areMoreNumbers(newValue as String)) {
distance.text = (Constants.remoteBolusMinDistance / (60 * 1000L)).toString()
distance.title = (MainApp.gs(R.string.smscommunicator_remotebolusmindistance)
+ ".\n"
+ MainApp.gs(R.string.smscommunicator_remotebolusmindistance_caveat))
distance.isEnabled = false
} else {
distance.title = MainApp.gs(R.string.smscommunicator_remotebolusmindistance)
distance.isEnabled = true
}
true
}
}
override fun updatePreferenceSummary(pref: Preference) {
super.updatePreferenceSummary(pref)
if (pref is EditTextPreference) {
val editTextPref = pref
if (pref.getKey().contains("smscommunicator_allowednumbers") && (editTextPref.text == null || TextUtils.isEmpty(editTextPref.text.trim { it <= ' ' }))) {
pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary))
}
}
}
private fun processSettings(ev: EventPreferenceChange?) {
if (ev == null || ev.isChanged(R.string.key_smscommunicator_allowednumbers)) {
val settings = SP.getString(R.string.key_smscommunicator_allowednumbers, "")
allowedNumbers.clear()
val substrings = settings.split(";").toTypedArray()
for (number in substrings) {
val cleaned = number.replace("\\s+".toRegex(), "")
allowedNumbers.add(cleaned)
log.debug("Found allowed number: $cleaned")
}
}
}
fun isCommand(command: String, number: String): Boolean {
var found = false
commands.forEach { (k, _) ->
if (k == command) found = true
}
return found || messageToConfirm?.requester?.phoneNumber == number
}
fun isAllowedNumber(number: String): Boolean {
for (num in allowedNumbers) {
if (num == number) return true
}
return false
}
fun handleNewData(intent: Intent) {
val bundle = intent.extras ?: return
val format = bundle.getString("format") ?: return
val pdus = bundle["pdus"] as Array<*>
for (pdu in pdus) {
val message = SmsMessage.createFromPdu(pdu as ByteArray, format)
processSms(Sms(message))
}
}
fun processSms(receivedSms: Sms) {
if (!isEnabled(PluginType.GENERAL)) {
log.debug("Ignoring SMS. Plugin disabled.")
return
}
if (!isAllowedNumber(receivedSms.phoneNumber)) {
log.debug("Ignoring SMS from: " + receivedSms.phoneNumber + ". Sender not allowed")
receivedSms.ignored = true
messages.add(receivedSms)
send(EventSmsCommunicatorUpdateGui())
return
}
val pump = ConfigBuilderPlugin.getPlugin().activePump ?: return
messages.add(receivedSms)
log.debug(receivedSms.toString())
val splitted = receivedSms.text.split(Regex("\\s+")).toTypedArray()
val remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
if (splitted.isNotEmpty() && isCommand(splitted[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
when (splitted[0].toUpperCase(Locale.getDefault())) {
"BG" ->
if (splitted.size == 1) processBG(receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"LOOP" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2 || splitted.size == 3) processLOOP(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"TREATMENTS" ->
if (splitted.size == 2) processTREATMENTS(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"NSCLIENT" ->
if (splitted.size == 2) processNSCLIENT(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"PUMP" ->
if (splitted.size == 1) processPUMP(receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"PROFILE" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2 || splitted.size == 3) processPROFILE(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"BASAL" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2 || splitted.size == 3) processBASAL(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"EXTENDED" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2 || splitted.size == 3) processEXTENDED(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"BOLUS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2 && DateUtil.now() - lastRemoteBolusTime < Constants.remoteBolusMinDistance) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotebolusnotallowed))
else if (splitted.size == 2 && pump.isSuspended) sendSMS(Sms(receivedSms.phoneNumber, R.string.pumpsuspended))
else if (splitted.size == 2 || splitted.size == 3) processBOLUS(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"CARBS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2 || splitted.size == 3) processCARBS(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"CAL" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2) processCAL(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"TARGET" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2) processTARGET(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"SMS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed))
else if (splitted.size == 2) processSMS(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
"HELP" ->
if (splitted.size == 1 || splitted.size == 2) processHELP(splitted, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else ->
if (messageToConfirm?.requester?.phoneNumber == receivedSms.phoneNumber) {
messageToConfirm?.action(splitted[0])
messageToConfirm = null
} else sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand))
}
}
send(EventSmsCommunicatorUpdateGui())
}
private fun processBG(receivedSms: Sms) {
val actualBG = DatabaseHelper.actualBg()
val lastBG = DatabaseHelper.lastBg()
var reply = ""
val units = ProfileFunctions.getInstance().profileUnits
if (actualBG != null) {
reply = MainApp.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsToString(units) + ", "
} else if (lastBG != null) {
val agoMsec = System.currentTimeMillis() - lastBG.date
val agoMin = (agoMsec / 60.0 / 1000.0).toInt()
reply = MainApp.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(MainApp.gs(R.string.sms_minago), agoMin) + ", "
}
val glucoseStatus = GlucoseStatus.getGlucoseStatusData()
if (glucoseStatus != null) reply += MainApp.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "
TreatmentsPlugin.getPlugin().updateTotalIOBTreatments()
val bolusIob = TreatmentsPlugin.getPlugin().lastCalculationTreatments.round()
TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals()
val basalIob = TreatmentsPlugin.getPlugin().lastCalculationTempBasals.round()
val cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "SMS COB")
reply += (MainApp.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U ("
+ MainApp.gs(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
+ MainApp.gs(R.string.sms_basal) + " " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U), "
+ MainApp.gs(R.string.cob) + ": " + cobInfo.generateCOBString())
sendSMS(Sms(receivedSms.phoneNumber, reply))
receivedSms.processed = true
}
private fun processLOOP(splitted: Array<String>, receivedSms: Sms) {
when (splitted[1].toUpperCase(Locale.getDefault())) {
"DISABLE", "STOP" -> {
val loopPlugin = LoopPlugin.getPlugin()
if (loopPlugin.isEnabled(PluginType.LOOP)) {
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
send(EventRefreshOverview("SMS_LOOP_STOP"))
val replyText = MainApp.gs(R.string.smscommunicator_loophasbeendisabled) + " " +
MainApp.gs(if (result.success) R.string.smscommunicator_tempbasalcanceled else R.string.smscommunicator_tempbasalcancelfailed)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
})
} else
sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisdisabled))
receivedSms.processed = true
}
"ENABLE", "START" -> {
val loopPlugin = LoopPlugin.getPlugin()
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loophasbeenenabled))
send(EventRefreshOverview("SMS_LOOP_START"))
} else
sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisenabled))
receivedSms.processed = true
}
"STATUS" -> {
val loopPlugin = LoopPlugin.getPlugin()
val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) {
if (loopPlugin.isSuspended()) String.format(MainApp.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
else MainApp.gs(R.string.smscommunicator_loopisenabled)
} else
MainApp.gs(R.string.smscommunicator_loopisdisabled)
sendSMS(Sms(receivedSms.phoneNumber, reply))
receivedSms.processed = true
}
"RESUME" -> {
LoopPlugin.getPlugin().suspendTo(0)
send(EventRefreshOverview("SMS_LOOP_RESUME"))
NSUpload.uploadOpenAPSOffline(0.0)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopresumed))
}
"SUSPEND" -> {
var duration = 0
if (splitted.size == 3) duration = SafeParse.stringToInt(splitted[2])
duration = Math.max(0, duration)
duration = Math.min(180, duration)
if (duration == 0) {
receivedSms.processed = true
sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_wrongduration))
return
} else {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(duration) {
override fun run() {
ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (result.success) {
LoopPlugin.getPlugin().suspendTo(System.currentTimeMillis() + anInteger() * 60L * 1000)
NSUpload.uploadOpenAPSOffline(anInteger() * 60.toDouble())
send(EventRefreshOverview("SMS_LOOP_SUSPENDED"))
val replyText = MainApp.gs(R.string.smscommunicator_loopsuspended) + " " +
MainApp.gs(if (result.success) R.string.smscommunicator_tempbasalcanceled else R.string.smscommunicator_tempbasalcancelfailed)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
}
}
else -> sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
}
private fun processTREATMENTS(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "REFRESH") {
TreatmentsPlugin.getPlugin().service.resetTreatments()
send(EventNSClientRestart())
sendSMS(Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT"))
receivedSms.processed = true
} else
sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
private fun processNSCLIENT(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "RESTART") {
send(EventNSClientRestart())
sendSMS(Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT"))
receivedSms.processed = true
} else
sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
private fun processHELP(splitted: Array<String>, receivedSms: Sms) {
if (splitted.size == 1) {
sendSMS(Sms(receivedSms.phoneNumber, commands.keys.toString().replace("[", "").replace("]", "")))
receivedSms.processed = true
} else if (isCommand(splitted[1].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
commands[splitted[1].toUpperCase(Locale.getDefault())]?.let {
sendSMS(Sms(receivedSms.phoneNumber, it))
receivedSms.processed = true
}
} else
sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
private fun processPUMP(receivedSms: Sms) {
ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("SMS", object : Callback() {
override fun run() {
val pump = ConfigBuilderPlugin.getPlugin().activePump
if (result.success) {
if (pump != null) {
val reply = pump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, reply))
}
} else {
val reply = MainApp.gs(R.string.readstatusfailed)
sendSMS(Sms(receivedSms.phoneNumber, reply))
}
}
})
receivedSms.processed = true
}
private fun processPROFILE(splitted: Array<String>, receivedSms: Sms) { // load profiles
val anInterface = ConfigBuilderPlugin.getPlugin().activeProfileInterface
if (anInterface == null) {
sendSMS(Sms(receivedSms.phoneNumber, R.string.notconfigured))
receivedSms.processed = true
return
}
val store = anInterface.profile
if (store == null) {
sendSMS(Sms(receivedSms.phoneNumber, R.string.notconfigured))
receivedSms.processed = true
return
}
val list = store.profileList
if (splitted[1].toUpperCase(Locale.getDefault()) == "STATUS") {
sendSMS(Sms(receivedSms.phoneNumber, ProfileFunctions.getInstance().profileName))
} else if (splitted[1].toUpperCase(Locale.getDefault()) == "LIST") {
if (list.isEmpty()) sendSMS(Sms(receivedSms.phoneNumber, R.string.invalidprofile))
else {
var reply = ""
for (i in list.indices) {
if (i > 0) reply += "\n"
reply += (i + 1).toString() + ". "
reply += list[i]
}
sendSMS(Sms(receivedSms.phoneNumber, reply))
}
} else {
val pindex = SafeParse.stringToInt(splitted[1])
var percentage = 100
if (splitted.size > 2) percentage = SafeParse.stringToInt(splitted[2])
if (pindex > list.size) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else if (percentage == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else if (pindex == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else {
val profile = store.getSpecificProfile(list[pindex - 1] as String)
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile))
else {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_profilereplywithcode), list[pindex - 1], percentage, passCode)
receivedSms.processed = true
val finalPercentage = percentage
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
override fun run() {
ProfileFunctions.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0)
sendSMS(Sms(receivedSms.phoneNumber, R.string.profileswitchcreated))
}
})
}
}
}
receivedSms.processed = true
}
private fun processBASAL(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "CANCEL" || splitted[1].toUpperCase(Locale.getDefault()) == "STOP") {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (result.success) {
var replyText = MainApp.gs(R.string.smscommunicator_tempbasalcanceled)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
} else if (splitted[1].endsWith("%")) {
var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%"))
var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
val profile = ProfileFunctions.getInstance().profile
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile))
else if (tempBasalPct == 0 && splitted[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else {
tempBasalPct = MainApp.getConstraintChecker().applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value()
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
override fun run() {
ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() {
override fun run() {
if (result.success) {
var replyText: String
replyText = if (result.isPercent) String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
}
} else {
var tempBasal = SafeParse.stringToDouble(splitted[1])
var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
val profile = ProfileFunctions.getInstance().profile
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile))
else if (tempBasal == 0.0 && splitted[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else {
tempBasal = MainApp.getConstraintChecker().applyBasalConstraints(Constraint(tempBasal), profile).value()
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
override fun run() {
ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() {
override fun run() {
if (result.success) {
var replyText = if (result.isPercent) String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration)
else String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
}
}
}
private fun processEXTENDED(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "CANCEL" || splitted[1].toUpperCase(Locale.getDefault()) == "STOP") {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
ConfigBuilderPlugin.getPlugin().commandQueue.cancelExtended(object : Callback() {
override fun run() {
if (result.success) {
var replyText = MainApp.gs(R.string.smscommunicator_extendedcanceled)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_extendedcancelfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
} else if (splitted.size != 3) {
sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
} else {
var extended = SafeParse.stringToDouble(splitted[1])
val duration = SafeParse.stringToInt(splitted[2])
extended = MainApp.getConstraintChecker().applyExtendedBolusConstraints(Constraint(extended)).value()
if (extended == 0.0 || duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
override fun run() {
ConfigBuilderPlugin.getPlugin().commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
override fun run() {
if (result.success) {
var replyText = String.format(MainApp.gs(R.string.smscommunicator_extendedset), aDouble, duration)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_extendedfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
}
}
}
private fun processBOLUS(splitted: Array<String>, receivedSms: Sms) {
var bolus = SafeParse.stringToDouble(splitted[1])
val isMeal = splitted.size > 2 && splitted[2].equals("MEAL", ignoreCase = true)
bolus = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(bolus)).value()
if (splitted.size == 3 && !isMeal) {
sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
} else if (bolus > 0.0) {
val passCode = generatePasscode()
val reply = if (isMeal)
String.format(MainApp.gs(R.string.smscommunicator_mealbolusreplywithcode), bolus, passCode)
else
String.format(MainApp.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(bolus) {
override fun run() {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = aDouble()
detailedBolusInfo.source = Source.USER
ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
val resultSuccess = result.success
val resultBolusDelivered = result.bolusDelivered
ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("SMS", object : Callback() {
override fun run() {
if (resultSuccess) {
var replyText = if (isMeal)
String.format(MainApp.gs(R.string.smscommunicator_mealbolusdelivered), resultBolusDelivered)
else
String.format(MainApp.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
lastRemoteBolusTime = DateUtil.now()
if (isMeal) {
ProfileFunctions.getInstance().profile?.let { currentProfile ->
var eatingSoonTTDuration = SP.getInt(R.string.key_eatingsoon_duration, Constants.defaultEatingSoonTTDuration)
eatingSoonTTDuration =
if (eatingSoonTTDuration > 0) eatingSoonTTDuration
else Constants.defaultEatingSoonTTDuration
var eatingSoonTT = SP.getDouble(R.string.key_eatingsoon_target, if (currentProfile.units == Constants.MMOL) Constants.defaultEatingSoonTTmmol else Constants.defaultEatingSoonTTmgdl)
eatingSoonTT =
if (eatingSoonTT > 0) eatingSoonTT
else if (currentProfile.units == Constants.MMOL) Constants.defaultEatingSoonTTmmol
else Constants.defaultEatingSoonTTmgdl
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(eatingSoonTTDuration)
.reason(MainApp.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(eatingSoonTT, currentProfile.units))
.high(Profile.toMgdl(eatingSoonTT, currentProfile.units))
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
val tt = if (currentProfile.units == Constants.MMOL) {
DecimalFormatter.to1Decimal(eatingSoonTT)
} else DecimalFormatter.to0Decimal(eatingSoonTT)
replyText += "\n" + String.format(MainApp.gs(R.string.smscommunicator_mealbolusdelivered_tt), tt, eatingSoonTTDuration)
}
}
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_bolusfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
}
})
} else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
private fun processCARBS(splitted: Array<String>, receivedSms: Sms) {
var grams = SafeParse.stringToInt(splitted[1])
var time = DateUtil.now()
if (splitted.size > 2) {
val seconds = DateUtil.toSeconds(splitted[2].toUpperCase(Locale.getDefault()))
val midnight = MidnightTime.calc()
if (seconds == 0 && (!splitted[2].startsWith("00:00") || !splitted[2].startsWith("12:00"))) {
sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
return
}
time = midnight + T.secs(seconds.toLong()).msecs()
}
grams = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(grams)).value()
if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_carbsreplywithcode), grams, DateUtil.timeString(time), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(grams, time) {
override fun run() {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.carbs = anInteger().toDouble()
detailedBolusInfo.date = secondLong()
ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
if (result.success) {
var replyText = String.format(MainApp.gs(R.string.smscommunicator_carbsset), anInteger)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
var replyText = MainApp.gs(R.string.smscommunicator_carbsfailed)
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
}
})
}
}
private fun processTARGET(splitted: Array<String>, receivedSms: Sms) {
val isMeal = splitted[1].equals("MEAL", ignoreCase = true)
val isActivity = splitted[1].equals("ACTIVITY", ignoreCase = true)
val isHypo = splitted[1].equals("HYPO", ignoreCase = true)
val isStop = splitted[1].equals("STOP", ignoreCase = true) || splitted[1].equals("CANCEL", ignoreCase = true)
if (isMeal || isActivity || isHypo) {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_temptargetwithcode), splitted[1].toUpperCase(Locale.getDefault()), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
val currentProfile = ProfileFunctions.getInstance().profile
if (currentProfile != null) {
var keyDuration = 0
var defaultTargetDuration = 0
var keyTarget = 0
var defaultTargetMMOL = 0.0
var defaultTargetMGDL = 0.0
if (isMeal) {
keyDuration = R.string.key_eatingsoon_duration
defaultTargetDuration = Constants.defaultEatingSoonTTDuration
keyTarget = R.string.key_eatingsoon_target
defaultTargetMMOL = Constants.defaultEatingSoonTTmmol
defaultTargetMGDL = Constants.defaultEatingSoonTTmgdl
} else if (isActivity) {
keyDuration = R.string.key_activity_duration
defaultTargetDuration = Constants.defaultActivityTTDuration
keyTarget = R.string.key_activity_target
defaultTargetMMOL = Constants.defaultActivityTTmmol
defaultTargetMGDL = Constants.defaultActivityTTmgdl
} else if (isHypo) {
keyDuration = R.string.key_hypo_duration
defaultTargetDuration = Constants.defaultHypoTTDuration
keyTarget = R.string.key_hypo_target
defaultTargetMMOL = Constants.defaultHypoTTmmol
defaultTargetMGDL = Constants.defaultHypoTTmgdl
}
var ttDuration = SP.getInt(keyDuration, defaultTargetDuration)
ttDuration = if (ttDuration > 0) ttDuration else defaultTargetDuration
var tt = SP.getDouble(keyTarget, if (currentProfile.units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL)
tt = if (tt > 0) tt else if (currentProfile.units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(ttDuration)
.reason(MainApp.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(tt, currentProfile.units))
.high(Profile.toMgdl(tt, currentProfile.units))
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
val ttString = if (currentProfile.units == Constants.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt)
val replyText = String.format(MainApp.gs(R.string.smscommunicator_tt_set), ttString, ttDuration)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand))
}
}
})
} else if (isStop) {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_temptargetcancel), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
val currentProfile = ProfileFunctions.getInstance().profile
if (currentProfile != null) {
val tempTarget = TempTarget()
.source(Source.USER)
.date(DateUtil.now())
.duration(0)
.low(0.0)
.high(0.0)
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
val replyText = String.format(MainApp.gs(R.string.smscommunicator_tt_canceled))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand))
}
}
})
} else
sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
private fun processSMS(splitted: Array<String>, receivedSms: Sms) {
val isStop = (splitted[1].equals("STOP", ignoreCase = true)
|| splitted[1].equals("DISABLE", ignoreCase = true))
if (isStop) {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_stopsmswithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
SP.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val replyText = String.format(MainApp.gs(R.string.smscommunicator_stoppedsms))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
}
})
} else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
private fun processCAL(splitted: Array<String>, receivedSms: Sms) {
val cal = SafeParse.stringToDouble(splitted[1])
if (cal > 0.0) {
val passCode = generatePasscode()
val reply = String.format(MainApp.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(cal) {
override fun run() {
val result = XdripCalibrations.sendIntent(aDouble)
if (result) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationsent)) else sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationfailed))
}
})
} else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
}
fun sendNotificationToAllNumbers(text: String): Boolean {
var result = true
for (i in allowedNumbers.indices) {
val sms = Sms(allowedNumbers[i], text)
result = result && sendSMS(sms)
}
return result
}
private fun sendSMSToAllNumbers(sms: Sms) {
for (number in allowedNumbers) {
sms.phoneNumber = number
sendSMS(sms)
}
}
fun sendSMS(sms: Sms): Boolean {
val smsManager = SmsManager.getDefault()
sms.text = stripAccents(sms.text)
try {
if (L.isEnabled(L.SMS)) log.debug("Sending SMS to " + sms.phoneNumber + ": " + sms.text)
if (sms.text.toByteArray().size <= 140) smsManager.sendTextMessage(sms.phoneNumber, null, sms.text, null, null)
else {
val parts = smsManager.divideMessage(sms.text)
smsManager.sendMultipartTextMessage(sms.phoneNumber, null, parts,
null, null)
}
messages.add(sms)
} catch (e: IllegalArgumentException) {
return if (e.message == "Invalid message body") {
val notification = Notification(Notification.INVALID_MESSAGE_BODY, MainApp.gs(R.string.smscommunicator_messagebody), Notification.NORMAL)
send(EventNewNotification(notification))
false
} else {
val notification = Notification(Notification.INVALID_PHONE_NUMBER, MainApp.gs(R.string.smscommunicator_invalidphonennumber), Notification.NORMAL)
send(EventNewNotification(notification))
false
}
} catch (e: SecurityException) {
val notification = Notification(Notification.MISSING_SMS_PERMISSION, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.NORMAL)
send(EventNewNotification(notification))
return false
}
send(EventSmsCommunicatorUpdateGui())
return true
}
private fun generatePasscode(): String {
val startChar1 = 'A'.toInt() // on iphone 1st char is uppercase :)
var passCode = Character.toString((startChar1 + Math.random() * ('z' - 'a' + 1)).toChar())
val startChar2: Int = if (Math.random() > 0.5) 'a'.toInt() else 'A'.toInt()
passCode += Character.toString((startChar2 + Math.random() * ('z' - 'a' + 1)).toChar())
val startChar3: Int = if (Math.random() > 0.5) 'a'.toInt() else 'A'.toInt()
passCode += Character.toString((startChar3 + Math.random() * ('z' - 'a' + 1)).toChar())
passCode = passCode.replace('l', 'k').replace('I', 'J')
return passCode
}
private fun stripAccents(str: String): String {
var s = str
s = Normalizer.normalize(s, Normalizer.Form.NFD)
s = s.replace("[\\p{InCombiningDiacriticalMarks}]".toRegex(), "")
return s
}
fun areMoreNumbers(allowednumbers: String?): Boolean {
return allowednumbers?.let {
var countNumbers = 0
val substrings = it.split(";").toTypedArray()
for (number in substrings) {
var cleaned = number.replace(Regex("\\s+"), "")
if (cleaned.length < 4) continue
cleaned = cleaned.replace("+", "")
cleaned = cleaned.replace("-", "")
if (!cleaned.matches(Regex("[0-9]+"))) continue
countNumbers++
}
countNumbers > 1
} ?: false
}
}

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.general.tidepool
import android.preference.PreferenceFragment
import android.text.Spanned
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
@ -34,7 +35,6 @@ object TidepoolPlugin : PluginBase(PluginDescription()
.preferencesId(R.xml.pref_tidepool)
.description(R.string.description_tidepool)
) {
private val log = LoggerFactory.getLogger(L.TIDEPOOL)
private var disposable: CompositeDisposable = CompositeDisposable()
@ -111,6 +111,16 @@ object TidepoolPlugin : PluginBase(PluginDescription()
super.onStop()
}
override fun preprocessPreferences(preferenceFragment: PreferenceFragment) {
super.preprocessPreferences(preferenceFragment)
val tidepoolTestLogin = preferenceFragment.findPreference(MainApp.gs(R.string.key_tidepool_test_login))
tidepoolTestLogin?.setOnPreferenceClickListener {
TidepoolUploader.testLogin(preferenceFragment.getActivity())
false
}
}
private fun doUpload() =
when (TidepoolUploader.connectionStatus) {
TidepoolUploader.ConnectionStatus.FAILED -> {}

View file

@ -16,6 +16,7 @@ import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
*/
public class Encoding4b6bLoop extends Encoding4b6bAbstract {
private static final Logger log = LoggerFactory.getLogger(Encoding4b6bLoop.class);
public static final Logger LOG = LoggerFactory.getLogger(Encoding4b6bLoop.class);
public Map<Integer, Byte> codesRev = null;
@ -108,9 +109,8 @@ public class Encoding4b6bLoop extends Encoding4b6bAbstract {
int index2 = ((bitAccumulator >> (availBits - 12)) & 0b111111);
hiNibble = codesRev.get((bitAccumulator >> (availBits - 6)));
loNibble = codesRev.get(((bitAccumulator >> (availBits - 12)) & 0b111111));
} catch (Exception ex) {
System.out.println("Exception: " + ex.getMessage());
ex.printStackTrace();
} catch (Exception e) {
log.error("Unhandled exception", e);
return null;
}

View file

@ -383,7 +383,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
}
} else {

View file

@ -5,10 +5,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.preference.Preference;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
@ -110,6 +112,14 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
@Override
public void updatePreferenceSummary(@NotNull Preference pref) {
super.updatePreferenceSummary(pref);
if (pref.getKey().equals(MainApp.gs(R.string.key_danars_name)))
pref.setSummary(SP.getString(R.string.key_danars_name, ""));
}
@Override
protected void onStart() {
Context context = MainApp.instance().getApplicationContext();

View file

@ -4,11 +4,15 @@ import android.annotation.TargetApi;
import android.os.Build;
import com.cozmo.danar.util.BleCommandUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.Date;
public class DanaRS_Packet {
private static final Logger log = LoggerFactory.getLogger(DanaRS_Packet.class);
protected static final int TYPE_START = 0;
protected static final int OPCODE_START = 1;
protected static final int DATA_START = 2;
@ -73,7 +77,7 @@ public class DanaRS_Packet {
return ret;
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
return null;
}

View file

@ -551,7 +551,7 @@ public class BLEComm {
break;
}
} catch (Exception e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
startSignatureFound = false;
packetIsValid = false;
@ -635,7 +635,7 @@ public class BLEComm {
message.wait(5000);
} catch (InterruptedException e) {
log.error("sendMessage InterruptedException", e);
e.printStackTrace();
log.error("Unhandled exception", e);
}
}

View file

@ -1526,7 +1526,7 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con
data.put("notes", note);
NSUpload.uploadCareportalEntryToNS(data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
}
@ -1554,7 +1554,7 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con
data.put("eventType", event);
NSUpload.uploadCareportalEntryToNS(data);
} catch (JSONException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
}

View file

@ -3,8 +3,11 @@ package info.nightscout.androidaps.plugins.pump.insight.app_layer.history.histor
import info.nightscout.androidaps.plugins.pump.insight.ids.HistoryEventIDs;
import info.nightscout.androidaps.plugins.pump.insight.utils.BOCUtil;
import info.nightscout.androidaps.plugins.pump.insight.utils.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HistoryEvent implements Comparable<HistoryEvent> {
private static final Logger log = LoggerFactory.getLogger(HistoryEvent.class);
private int eventYear;
private int eventMonth;
@ -22,10 +25,8 @@ public class HistoryEvent implements Comparable<HistoryEvent> {
else {
try {
event = eventClass.newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException | InstantiationException e) {
log.error("Unhandled exception", e);
}
}
event.parseHeader(byteBuf);

View file

@ -48,6 +48,7 @@ import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperAc
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.pump.common.PumpPluginAbstract;
import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst;
@ -372,7 +373,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
refreshAnyStatusThatNeedsToBeRefreshed();
}
RxBus.INSTANCE.send(new EventMedtronicPumpValuesChanged());
RxBus.INSTANCE.send(new EventMedtronicPumpValuesChanged());
}
@ -386,7 +387,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
RileyLinkServiceState rileyLinkServiceState = MedtronicUtil.getServiceState();
if (rileyLinkServiceState==null) {
if (rileyLinkServiceState == null) {
LOG.error("RileyLink unreachable. RileyLinkServiceState is null.");
return false;
}
@ -744,13 +745,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
ClockDTO clock = MedtronicUtil.getPumpTime();
if (clock==null) { // retry
if (clock == null) { // retry
medtronicUIComm.executeCommand(MedtronicCommandType.GetRealTimeClock);
clock = MedtronicUtil.getPumpTime();
}
if (clock==null)
if (clock == null)
return;
int timeDiff = Math.abs(clock.timeDifference);
@ -866,6 +867,11 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}).start();
}
long now = System.currentTimeMillis();
detailedBolusInfo.date = now;
detailedBolusInfo.deliverAt = now; // not sure about that one
TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true);
// we subtract insulin, exact amount will be visible with next remainingInsulin update.
@ -877,7 +883,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// calculate time for bolus and set driver to busy for that time
int bolusTime = (int) (detailedBolusInfo.insulin * 42.0d);
long time = System.currentTimeMillis() + (bolusTime * 1000);
long time = now + (bolusTime * 1000);
this.busyTimestamps.add(time);
setEnableCustomAction(MedtronicCustomActionType.ClearBolusBlock, true);
@ -1065,10 +1071,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
if (percent==0) {
if (percent == 0) {
return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew);
} else {
double absoluteValue = profile.getBasal() * (percent /100.0d);
double absoluteValue = profile.getBasal() * (percent / 100.0d);
getMDTPumpStatus();
absoluteValue = pumpStatusLocal.pumpType.determineCorrectBasalSize(absoluteValue);
LOG.warn("setTempBasalPercent [MedtronicPumpPlugin] - You are trying to use setTempBasalPercent with percent other then 0% (%d). This will start setTempBasalAbsolute, with calculated value (%.3f). Result might not be 100% correct.", percent, absoluteValue);

View file

@ -412,25 +412,18 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder<PumpHis
rate = body[1] * 0.025f;
}
LOG.info("Basal Profile Start: offset={}, rate={}, index={}, body_raw={}", offset, rate, index,
body);
//LOG.info("Basal Profile Start: offset={}, rate={}, index={}, body_raw={}", offset, rate, index, body);
if (rate == null) {
LOG.warn("Basal Profile Start (ERROR): offset={}, rate={}, index={}, body_raw={}", offset, rate, index,
body);
return RecordDecodeStatus.Error;
} else {
// writeData(PumpBaseType.Basal, PumpBasalType.ValueChange, getFormattedFloat(rate, 3),
// entry.getATechDate());
entry.addDecodedData("Value", getFormattedFloat(rate, 3));
entry.setDisplayableValue(getFormattedFloat(rate, 3));
return RecordDecodeStatus.OK;
}
// profileIndex = asUINT8(data[1]);
// offset = asUINT8(data[7]) * 30 * 1000 * 60;
// rate = (double)(asUINT8(data[8])) / 40.0;
}

View file

@ -10,12 +10,10 @@ import java.util.List;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
/**
* Created by andy on 9/23/18.
*/
/**
* History page contains data, sorted from newest to oldest (0=newest..n=oldest)
*
* Created by andy on 9/23/18.
*/
public class PumpHistoryResult {
@ -29,8 +27,6 @@ public class PumpHistoryResult {
public List<PumpHistoryEntry> validEntries;
// private Object validValues;
public PumpHistoryResult(PumpHistoryEntry searchEntry, Long targetDate) {
if (searchEntry != null) {
/*
@ -109,9 +105,8 @@ public class PumpHistoryResult {
if (unprocessedEntry.isAfter(this.searchDate)) {
this.validEntries.add(unprocessedEntry);
} else {
LOG.debug("PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]",
DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry);
// LOG.debug("PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]",
// DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry);
if (DateTimeUtil.getYear(unprocessedEntry.atechDateTime) > 2015)
olderEntries++;
}
@ -131,14 +126,6 @@ public class PumpHistoryResult {
}
private void clearOrPrepareList() {
if (this.validEntries == null)
this.validEntries = new ArrayList<>();
else
this.validEntries.clear();
}
public String toString() {
return "PumpHistoryResult [unprocessed=" + (unprocessedEntries != null ? "" + unprocessedEntries.size() : "0") + //
", valid=" + (validEntries != null ? "" + validEntries.size() : "0") + //

View file

@ -49,6 +49,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpSta
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentService;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.SP;
@ -67,7 +68,6 @@ import info.nightscout.androidaps.utils.SP;
// All things marked with "TODO: Fix db code" needs to be updated in new 2.5 database code
public class MedtronicHistoryData {
private static final Logger LOG = LoggerFactory.getLogger(L.PUMP);
private List<PumpHistoryEntry> allHistory = null;
@ -77,6 +77,7 @@ public class MedtronicHistoryData {
private boolean isInit = false;
private Gson gson;
private Gson gsonCore;
private DatabaseHelper databaseHelper = MainApp.getDbHelper();
private ClockDTO pumpTime;
@ -94,10 +95,15 @@ public class MedtronicHistoryData {
public MedtronicHistoryData() {
this.allHistory = new ArrayList<>();
this.gson = MedtronicUtil.gsonInstance;
this.gsonCore = MedtronicUtil.getGsonInstanceCore();
if (this.gson == null) {
this.gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
}
if (this.gsonCore == null) {
this.gsonCore = new GsonBuilder().create();
}
}
@ -523,7 +529,7 @@ public class MedtronicHistoryData {
data.put("eventType", event);
NSUpload.uploadCareportalEntryToNS(data);
} catch (JSONException e) {
e.printStackTrace();
LOG.error("Unhandled exception", e);
}
}
@ -597,7 +603,7 @@ public class MedtronicHistoryData {
if (doubleBolusDebug)
LOG.debug("DoubleBolusDebug: List (before filter): {}, FromDb={}", gson.toJson(entryList),
gson.toJson(entriesFromHistory));
gsonCore.toJson(entriesFromHistory));
filterOutAlreadyAddedEntries(entryList, entriesFromHistory);
@ -609,7 +615,7 @@ public class MedtronicHistoryData {
if (doubleBolusDebug)
LOG.debug("DoubleBolusDebug: List (after filter): {}, FromDb={}", gson.toJson(entryList),
gson.toJson(entriesFromHistory));
gsonCore.toJson(entriesFromHistory));
if (isCollectionEmpty(entriesFromHistory)) {
for (PumpHistoryEntry treatment : entryList) {
@ -862,6 +868,7 @@ public class MedtronicHistoryData {
return;
List<DbObjectBase> removeTreatmentsFromHistory = new ArrayList<>();
List<PumpHistoryEntry> removeTreatmentsFromPH = new ArrayList<>();
for (DbObjectBase treatment : treatmentsFromHistory) {
@ -879,11 +886,17 @@ public class MedtronicHistoryData {
if (selectedBolus != null) {
entryList.remove(selectedBolus);
removeTreatmentsFromPH.add(selectedBolus);
removeTreatmentsFromHistory.add(treatment);
}
}
}
if (doubleBolusDebug)
LOG.debug("DoubleBolusDebug: filterOutAlreadyAddedEntries: PumpHistory={}, Treatments={}",
gson.toJson(removeTreatmentsFromPH),
gsonCore.toJson(removeTreatmentsFromHistory));
treatmentsFromHistory.removeAll(removeTreatmentsFromHistory);
}
@ -947,36 +960,23 @@ public class MedtronicHistoryData {
} else {
DetailedBolusInfo detailedBolusInfo = DetailedBolusInfoStorage.INSTANCE.findDetailedBolusInfo(treatment.date, bolusDTO.getDeliveredAmount());
if (doubleBolusDebug)
LOG.debug("DoubleBolusDebug: addBolus(OldTreatment={}): Bolus={}", treatment, bolusDTO);
treatment.source = Source.PUMP;
treatment.pumpId = bolus.getPumpId();
treatment.insulin = bolusDTO.getDeliveredAmount();
TreatmentService.UpdateReturn updateReturn = TreatmentsPlugin.getPlugin().getService().createOrUpdateMedtronic(treatment, false);
if (doubleBolusDebug)
LOG.debug("DoubleBolusDebug: addBolus(tretament={}): Bolus={}, DetailedBolusInfo={}", treatment, bolusDTO, detailedBolusInfo);
if (detailedBolusInfo == null) {
detailedBolusInfo = new DetailedBolusInfo();
if (doubleBolusDebug)
LOG.debug("DoubleBolusDebug: detailedBolusInfoCouldNotBeRetrived !");
}
detailedBolusInfo.date = treatment.date;
detailedBolusInfo.source = Source.PUMP;
detailedBolusInfo.pumpId = bolus.getPumpId();
detailedBolusInfo.insulin = bolusDTO.getDeliveredAmount();
detailedBolusInfo.carbs = treatment.carbs;
addCarbsFromEstimate(detailedBolusInfo, bolus);
if (doubleBolusDebug)
LOG.debug("DoubleBolusDebug: addBolus(tretament!=null): DetailedBolusInfo(New)={}", detailedBolusInfo);
boolean newRecord = TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false);
bolus.setLinkedObject(detailedBolusInfo);
LOG.debug("DoubleBolusDebug: addBolus(tretament!=null): NewTreatment={}, UpdateReturn={}", treatment, updateReturn);
if (isLogEnabled())
LOG.debug("editBolus - [date={},pumpId={}, insulin={}, newRecord={}]", detailedBolusInfo.date,
detailedBolusInfo.pumpId, detailedBolusInfo.insulin, newRecord);
LOG.debug("editBolus - [date={},pumpId={}, insulin={}, newRecord={}]", treatment.date,
treatment.pumpId, treatment.insulin, updateReturn.toString());
bolus.setLinkedObject(treatment);
}
}

View file

@ -61,8 +61,7 @@ public class MedtronicUtil extends RileyLinkUtil {
private static int doneBit = 1 << 7;
private static ClockDTO pumpTime;
public static Gson gsonInstance = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
public static Gson gsonInstancePretty = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting().create();
public static Gson gsonInstanceCore = new GsonBuilder().create();
private static BatteryType batteryType = BatteryType.None;
@ -70,8 +69,9 @@ public class MedtronicUtil extends RileyLinkUtil {
return gsonInstance;
}
public static Gson getGsonInstancePretty() {
return gsonInstancePretty;
public static Gson getGsonInstanceCore() {
return gsonInstanceCore;
}

View file

@ -17,6 +17,7 @@ import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.SP
import info.nightscout.androidaps.utils.T
import org.json.JSONObject
import org.slf4j.LoggerFactory
@ -51,7 +52,7 @@ object SourceDexcomPlugin : PluginBase(PluginDescription()
}
fun findDexcomPackageName(): String? {
val packageManager = MainApp.instance().packageManager;
val packageManager = MainApp.instance().packageManager
for (packageInfo in packageManager.getInstalledPackages(0)) {
if (PACKAGE_NAMES.contains(packageInfo.packageName)) return packageInfo.packageName
}
@ -64,43 +65,53 @@ object SourceDexcomPlugin : PluginBase(PluginDescription()
val sensorType = intent.getStringExtra("sensorType") ?: ""
val glucoseValues = intent.getBundleExtra("glucoseValues")
for (i in 0 until glucoseValues.size()) {
val glucoseValue = glucoseValues.getBundle(i.toString())
val bgReading = BgReading()
bgReading.value = glucoseValue!!.getInt("glucoseValue").toDouble()
bgReading.direction = glucoseValue.getString("trendArrow")
bgReading.date = glucoseValue.getLong("timestamp") * 1000
bgReading.raw = 0.0
if (MainApp.getDbHelper().createIfNotExists(bgReading, "Dexcom$sensorType")) {
if (SP.getBoolean(R.string.key_dexcomg5_nsupload, false)) {
NSUpload.uploadBg(bgReading, "AndroidAPS-Dexcom$sensorType")
}
if (SP.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
NSUpload.sendToXdrip(bgReading)
glucoseValues.getBundle(i.toString())?.let { glucoseValue ->
val bgReading = BgReading()
bgReading.value = glucoseValue.getInt("glucoseValue").toDouble()
bgReading.direction = glucoseValue.getString("trendArrow")
bgReading.date = glucoseValue.getLong("timestamp") * 1000
bgReading.raw = 0.0
if (MainApp.getDbHelper().createIfNotExists(bgReading, "Dexcom$sensorType")) {
if (SP.getBoolean(R.string.key_dexcomg5_nsupload, false)) {
NSUpload.uploadBg(bgReading, "AndroidAPS-Dexcom$sensorType")
}
if (SP.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
NSUpload.sendToXdrip(bgReading)
}
}
}
}
val meters = intent.getBundleExtra("meters")
for (i in 0 until meters.size()) {
val meter = meters.getBundle(i.toString())
val timestamp = meter!!.getLong("timestamp") * 1000
if (MainApp.getDbHelper().getCareportalEventFromTimestamp(timestamp) != null) continue
val jsonObject = JSONObject()
jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType")
jsonObject.put("created_at", DateUtil.toISOString(timestamp))
jsonObject.put("eventType", CareportalEvent.BGCHECK)
jsonObject.put("glucoseType", "Finger")
jsonObject.put("glucose", meter.getInt("meterValue"))
jsonObject.put("units", Constants.MGDL)
NSUpload.uploadCareportalEntryToNS(jsonObject)
meter?.let {
val timestamp = it.getLong("timestamp") * 1000
val now = DateUtil.now()
if (timestamp > now - T.months(1).msecs() && timestamp < now)
if (MainApp.getDbHelper().getCareportalEventFromTimestamp(timestamp) == null) {
val jsonObject = JSONObject()
jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType")
jsonObject.put("created_at", DateUtil.toISOString(timestamp))
jsonObject.put("eventType", CareportalEvent.BGCHECK)
jsonObject.put("glucoseType", "Finger")
jsonObject.put("glucose", meter.getInt("meterValue"))
jsonObject.put("units", Constants.MGDL)
NSUpload.uploadCareportalEntryToNS(jsonObject)
}
}
}
if (SP.getBoolean(R.string.key_dexcom_lognssensorchange, false) && intent.hasExtra("sensorInsertionTime")) {
val sensorInsertionTime = intent.extras!!.getLong("sensorInsertionTime") * 1000
if (MainApp.getDbHelper().getCareportalEventFromTimestamp(sensorInsertionTime) == null) {
val jsonObject = JSONObject()
jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType")
jsonObject.put("created_at", DateUtil.toISOString(sensorInsertionTime))
jsonObject.put("eventType", CareportalEvent.SENSORCHANGE)
NSUpload.uploadCareportalEntryToNS(jsonObject)
intent.extras?.let {
val sensorInsertionTime = it.getLong("sensorInsertionTime") * 1000
val now = DateUtil.now()
if (sensorInsertionTime > now - T.months(1).msecs() && sensorInsertionTime < now)
if (MainApp.getDbHelper().getCareportalEventFromTimestamp(sensorInsertionTime) == null) {
val jsonObject = JSONObject()
jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType")
jsonObject.put("created_at", DateUtil.toISOString(sensorInsertionTime))
jsonObject.put("eventType", CareportalEvent.SENSORCHANGE)
NSUpload.uploadCareportalEntryToNS(jsonObject)
}
}
}
} catch (e: Exception) {

View file

@ -133,7 +133,7 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
try {
getDao().executeRaw("ALTER TABLE `" + Treatment.TABLE_TREATMENTS + "` ADD COLUMN boluscalc STRING;");
} catch (SQLException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
} else {
if (L.isEnabled(L.DATATREATMENTS))
@ -147,7 +147,7 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
try {
getDao().executeRaw("ALTER TABLE `" + Treatment.TABLE_TREATMENTS + "` DROP COLUMN boluscalc STRING;");
} catch (SQLException e) {
e.printStackTrace();
log.error("Unhandled exception", e);
}
}
}
@ -736,6 +736,14 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
boolean newRecord;
boolean success;
@Override
public String toString() {
return "UpdateReturn [" +
"newRecord=" + newRecord +
", success=" + success +
']';
}
}
}

View file

@ -349,7 +349,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
long time = System.currentTimeMillis();
synchronized (treatments) {
if (MedtronicHistoryData.doubleBolusDebug)
log.debug("DoubleBolusDebug: AllTreatmentsInDb: {}", MedtronicUtil.getGsonInstance().toJson(treatments));
log.debug("DoubleBolusDebug: AllTreatmentsInDb: {}", MedtronicUtil.getGsonInstanceCore().toJson(treatments));
for (Treatment t : treatments) {
if (t.date <= time && t.date >= fromTimestamp)
@ -357,7 +357,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
if (MedtronicHistoryData.doubleBolusDebug)
log.debug("DoubleBolusDebug: FilteredTreatments: AfterTime={}, Items={}", fromTimestamp, MedtronicUtil.getGsonInstance().toJson(in5minback));
log.debug("DoubleBolusDebug: FilteredTreatments: AfterTime={}, Items={}", fromTimestamp, MedtronicUtil.getGsonInstanceCore().toJson(in5minback));
return in5minback;
}

View file

@ -50,7 +50,7 @@ public class CommandSetProfile extends Command {
// Send SMS notification if ProfileSwitch is comming from NS
ProfileSwitch profileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis());
if (profileSwitch != null && r.enacted && profileSwitch.source == Source.NIGHTSCOUT) {
SmsCommunicatorPlugin smsCommunicatorPlugin = SmsCommunicatorPlugin.getPlugin();
SmsCommunicatorPlugin smsCommunicatorPlugin = SmsCommunicatorPlugin.INSTANCE;
if (smsCommunicatorPlugin.isEnabled(PluginType.GENERAL)) {
smsCommunicatorPlugin.sendNotificationToAllNumbers(MainApp.gs(R.string.profile_set_ok));
}

View file

@ -21,7 +21,7 @@ public class ChargingStateReceiver extends BroadcastReceiver {
lastEvent = event;
}
public EventChargingState grabChargingState(Context context) {
public static EventChargingState grabChargingState(Context context) {
BatteryManager bm = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
if (bm == null)

View file

@ -26,11 +26,6 @@ public class NetworkChangeReceiver extends BroadcastReceiver {
public static final NetworkChangeReceiver instance = new NetworkChangeReceiver();
// TODO: Split NSClient into network state component that can be used by several plugins and logic for plugin
public static void fetch() {
new NetworkChangeReceiver().grabNetworkStatus(MainApp.instance().getApplicationContext());
}
@Override
public void onReceive(final Context context, final Intent intent) {
EventNetworkChange event = grabNetworkStatus(context);
@ -39,7 +34,7 @@ public class NetworkChangeReceiver extends BroadcastReceiver {
}
@Nullable
public EventNetworkChange grabNetworkStatus(final Context context) {
public static EventNetworkChange grabNetworkStatus(final Context context) {
EventNetworkChange event = new EventNetworkChange();
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

View file

@ -103,7 +103,7 @@ public class DataService extends IntentService {
) {
handleNewDataFromNSClient(intent);
} else if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(action)) {
SmsCommunicatorPlugin.getPlugin().handleNewData(intent);
SmsCommunicatorPlugin.INSTANCE.handleNewData(intent);
}
if (L.isEnabled(L.DATASERVICE))

View file

@ -93,15 +93,15 @@ public class DateUtil {
}
public static int toSeconds(String hh_colon_mm) {
Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM | PM|)");
Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)");
Matcher m = p.matcher(hh_colon_mm);
int retval = 0;
if (m.find()) {
retval = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60;
if ((m.group(3).equals(" a.m.") || m.group(3).equals(" AM")) && m.group(1).equals("12"))
if ((m.group(3).equals(" a.m.") || m.group(3).equals(" AM") || m.group(3).equals("AM")) && m.group(1).equals("12"))
retval -= 12 * 60 * 60;
if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM")) && !(m.group(1).equals("12")))
if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM") || m.group(3).equals("PM")) && !(m.group(1).equals("12")))
retval += 12 * 60 * 60;
}
return retval;
@ -185,7 +185,7 @@ public class DateUtil {
long remainingTimeMinutes = timeInMillis / (1000 * 60);
long remainingTimeHours = remainingTimeMinutes / 60;
remainingTimeMinutes = remainingTimeMinutes % 60;
return "(" + ((remainingTimeHours > 0) ? (remainingTimeHours + "h ") : "") + remainingTimeMinutes + "')";
return "(" + ((remainingTimeHours > 0) ? (remainingTimeHours + MainApp.gs(R.string.shorthour) + " ") : "") + remainingTimeMinutes + "')";
}
public static String sinceString(long timestamp) {

View file

@ -1,14 +1,23 @@
package info.nightscout.androidaps.utils;
import java.math.BigDecimal;
/**
* Created by mike on 20.06.2016.
*/
public class Round {
public static Double roundTo(double x, Double step) {
if (x != 0d) {
return Math.round(x / step) * step;
if (x == 0d) {
return 0d;
}
return 0d;
//Double oldCalc = Math.round(x / step) * step;
Double newCalc = BigDecimal.valueOf(Math.round(x / step)).multiply(BigDecimal.valueOf(step)).doubleValue();
// just for the tests, forcing failures
//newCalc = oldCalc;
return newCalc;
}
public static Double floorTo(Double x, Double step) {

View file

@ -16,12 +16,16 @@ package info.nightscout.androidaps.utils;
*/
import android.os.SystemClock;
import android.util.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import info.nightscout.androidaps.logging.L;
/**
* {@hide}
* <p>
@ -35,7 +39,7 @@ import java.net.InetAddress;
* </pre>
*/
public class SntpClient {
private static final String TAG = "SntpClient";
private static Logger log = LoggerFactory.getLogger(L.CORE);
//private static final int REFERENCE_TIME_OFFSET = 16;
private static final int ORIGINATE_TIME_OFFSET = 24;
@ -76,8 +80,10 @@ public class SntpClient {
}
static void doNtpTime(final Callback callback) {
log.debug("Time detection started");
callback.success = requestTime("time.google.com", 5000);
callback.time = getNtpTime() + SystemClock.elapsedRealtime() - getNtpTimeReference();
log.debug("Time detection ended: " + callback.success + " " + DateUtil.dateAndTimeString(getNtpTime()));
callback.run();
}
@ -138,7 +144,7 @@ public class SntpClient {
mNtpTimeReference = responseTicks;
mRoundTripTime = roundTripTime;
} catch (Exception e) {
Log.d(TAG, "request time failed: " + e);
log.debug("request time failed: " + e);
return false;
}

View file

@ -68,11 +68,18 @@
android:text="@string/objectives_button_start" />
<Button
android:id="@+id/objective_back"
android:id="@+id/objective_unfinish"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/objectives_button_back" />
android:text="@string/objectives_button_unfinish" />
<Button
android:id="@+id/objective_unstart"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/objectives_button_unstart" />
<TextView
android:id="@+id/objective_inputhint"

View file

@ -1138,8 +1138,6 @@
<string name="tidepool_upload_tbr">Laai tydelike basale op</string>
<string name="tidepool_upload_profile">Laai profiel veranderings, tydelike teikens op</string>
<string name="tidepool_upload_bg">Laai BG toetse op</string>
<string name="dst_in_24h_warning">Daglig spaar tyd verandering in 24 h of minder</string>
<string name="dst_loop_disabled_warning">Daglig spaar tyd het verander minder as 3 ure terug - Geslote lus afgeskakel</string>
<string name="storage">interne berging beperking</string>
<string name="diskfull">Bevry ten minste %1$d MB van intene stoorspasie! Lus gedeaktiveer!</string>
<string name="wrongformat">Verkeerde formaat</string>

View file

@ -36,11 +36,12 @@
<string name="objectives_useloop">Отворете съдържанието на Цикъл плъгина.</string>
<string name="objectives_usescale">Използвайте функцията за удължаване на периода на графиката, като задържите върху нея.</string>
<string name="objectives_button_enter">Въведи</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Въведете кода, получен от разработчиците да прескочите останалите цели</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Ако сте били потребител на OpenAPS и НС има най-малко 3 месеца цикъл на данни, можете да изпращате по електронна поща objectives@androidaps.org с адрес на НС, за да поискате код за заобикаляне на останалите цели. Въведете кода, получен от разработчици</string>
<string name="codeaccepted">Код приет!</string>
<string name="codeinvalid">Неправилен код</string>
<string name="objectives_exam_objective">Докажете знанията си</string>
<string name="objectives_exam_gate">Отговорете правилно на въпросите</string>
<string name="answerdisabledto">Изключено до: %1$s</string>
<string name="wronganswer">Грешен отговор!</string>
<string name="unfinshed_button">Следващия неотговорен</string>
<string name="requestcode">Код (request code): %1$s</string>

View file

@ -98,6 +98,7 @@
<string name="openapsma_profile_label">Профил</string>
<string name="openapsma_mealdata_label">Данни за хранене</string>
<string name="result">Резултат</string>
<string name="result_insulin_carbs">Резултат: %1$s %2$s</string>
<string name="openapsma_noglucosedata">Няма данни за КЗ</string>
<string name="nochangerequested">Не се изисква промяна</string>
<string name="openapsma_request_label">Искане</string>
@ -215,6 +216,7 @@
<string name="overview_tempbasal_button">Временен базал</string>
<string name="overview_extendedbolus_button">Удължен болус</string>
<string name="configbuilder_nightscoutversion_label">Nightscout версия:</string>
<string name="missing_carbs">Нужни %1$dг</string>
<string name="exported">Настройките са експортирани</string>
<string name="export_to">Експортирай настройките в </string>
<string name="import_from">Импорт на настройки от</string>
@ -258,11 +260,23 @@
<string name="smscommunicator_allowednumbers">Разрешени телефонни номера</string>
<string name="smscommunicator_allowednumbers_summary">+XXXXXXXXXX;+YYYYYYYYYY</string>
<string name="smscommunicator_bolusreplywithcode">За да доставите болус от %1$.2fЕ отговорете с код %2$s</string>
<string name="smscommunicator_mealbolusreplywithcode">За да стартирате болус от %1$.2fЕ отговорете с код %2$s</string>
<string name="smscommunicator_temptargetwithcode">Зa zадаване на временна цел %1$s отговорете с код %2$s</string>
<string name="smscommunicator_temptargetcancel">За да спрете временната цел отговорете с код %1$s</string>
<string name="smscommunicator_stopsmswithcode">За да изключите услугата за отдалечен SMS контрол отговорете с код %1$s.\n\nИмайте предвид, че можете да го активирате само от AAPS смартфона.</string>
<string name="smscommunicator_stoppedsms">Отдалечен SMS контрол е изключен. Можете да го включите от AndroidAPS телефона.</string>
<string name="smscommunicator_calibrationreplywithcode">За да изпратите калибрация %1$.2f отговорете с код %2$s</string>
<string name="smscommunicator_bolusfailed">Болус отказан</string>
<string name="smscommunicator_remotebolusmindistance_summary">Минимален брой минути, в които трябва да мине между един отдалечен болус и следващия</string>
<string name="smscommunicator_remotebolusmindistance">Колко най-малко минути трябва да минат два болуса</string>
<string name="smscommunicator_remotebolusmindistance_caveat">За вашата сигурност, променете тази настройка, трябва да добавите най-малко 2 телефонни номера.</string>
<string name="bolusdelivered">Болус от %1$.2fЕ доставен успешно</string>
<string name="bolusrequested">Ще стартира %1$.2fЕ болус</string>
<string name="smscommunicator_bolusdelivered">Болус от %1$.2fЕ доставен успешно</string>
<string name="smscommunicator_mealbolusdelivered">Болус от %1$.2fЕ доставен успешно</string>
<string name="smscommunicator_mealbolusdelivered_tt">Временна цел от %1$s за %2$d минути</string>
<string name="smscommunicator_tt_set">Временна цел от %1$s за %2$d минути стартирана успешно</string>
<string name="smscommunicator_tt_canceled">Временна цел успешно спряна</string>
<string name="bolusdelivering">Стартирам %1$.2fЕ</string>
<string name="smscommunicator_remotecommandsallowed">Позволи отдалечени команди чрез SMS</string>
<string name="glucosetype_finger">Пръст</string>
@ -322,10 +336,13 @@
<string name="smscommunicator_basalreplywithcode">За да стартирате базал от %1$.2fЕ/ч за %2$d мин отговорете с код %3$s</string>
<string name="smscommunicator_profilereplywithcode">За да превключите профила към %1$s %2$d%% отговорете с код %3$s</string>
<string name="smscommunicator_extendedreplywithcode">За да започнете удължен болус %1$.2fЕ за %2$d мин отговорете с код %3$s</string>
<string name="smscommunicator_carbsreplywithcode">За да въведете %1$dг в %2$s отговорете с код %3$s</string>
<string name="smscommunicator_basalpctreplywithcode">За да стартирате базал от %1$d%Е/ч за %2$d мин отговорете с код %3$s</string>
<string name="smscommunicator_suspendreplywithcode">За да спрете APS за %1$d минути отговорете с код %2$s</string>
<string name="smscommunicator_tempbasalset">Временен базал от %1$.2fЕ/ч за %2$d мин стартиран успешно</string>
<string name="smscommunicator_extendedset">Удължен болус %1$.2fU за %2$d мин стартиран успешно</string>
<string name="smscommunicator_carbsset">Въглехидрати %1$dг въведени</string>
<string name="smscommunicator_carbsfailed">Въвеждане на%1$dг въглехидрати - НЕУСПЕШНО</string>
<string name="smscommunicator_tempbasalset_percent">Временен базал от %1$d%Е/ч за %2$d мин стартиран успешно</string>
<string name="smscommunicator_tempbasalfailed">Неуспешно стартиране на временен базал</string>
<string name="smscommunicator_extendedfailed">Неуспешно стартиране на удължен болус</string>
@ -546,6 +563,8 @@
<string name="show_statuslights_extended_summary">Показвай подробни статус светлини за канула, инсулин, сензор, резервоар и батерията на началния екран.</string>
<string name="statuslights_res_warning">Ниво за аларма за останал инсулин в резервоара [Е]</string>
<string name="statuslights_res_critical">Критично ниво на останал инсулин в резервоар [Е]</string>
<string name="statuslights_bat_warning">Аларма при заряд на батерия под [%]</string>
<string name="statuslights_bat_critical">Критично ниво на батерията под [%]</string>
<string name="iob">IOB</string>
<string name="cob">СОВ</string>
<string name="virtualpump_firmware_label">Фърмуер</string>
@ -676,6 +695,7 @@
<string name="shortgramm">гр.</string>
<string name="shortminute">мин.</string>
<string name="shorthour">ч.</string>
<string name="shortday">д</string>
<string name="none"><![CDATA[<празно>]]></string>
<string name="shortkilojoul">килодж.</string>
<string name="shortenergy">Ен</string>
@ -704,6 +724,7 @@
<string name="bgsource_upload">Настройки при качване на КЗ към Nightscout</string>
<string name="wear_detailed_delta_title">Показвай подробна делта</string>
<string name="wear_detailed_delta_summary">Показвай делта с още един десетичен знак</string>
<string name="smbmaxminutes">Максимум минути СМБ</string>
<string name="smbmaxminutes_summary">Максимални минути за ограничаване на базала от SMB</string>
<string name="unsupportedfirmware">Неподдържан фърмуер на помпата</string>
<string name="dexcomg5_xdripupload_title">Изпращай данни за КЗ към xDrip+</string>
@ -1232,6 +1253,8 @@
<string name="medtronic_pump_battery_no">Не е избрано (общ)</string>
<string name="medtronic_pump_battery_alkaline">Алкални</string>
<string name="medtronic_pump_battery_lithium">Литиева</string>
<string name="medtronic_pump_battery_nizn">NiZn батерия</string>
<string name="medtronic_bolus_debugging">Болус/Корекция подробно</string>
<!-- RL BLE Scanning -->
<string name="rileylink_scanner_scan_scan">СКАНИРАЙ</string>
<string name="rileylink_scanner_scan_stop">СТОП</string>
@ -1343,6 +1366,7 @@
<string name="profilename">Смени профила на</string>
<string name="changengetoprofilename">Смени профила на %1$s</string>
<string name="automation_trigger_pump_last_connection_label">Последно свързване към помпа</string>
<string name="automation_trigger_pump_last_connection_description">Последнa връзкa с помпата [минути]</string>
<string name="automation_trigger_pump_last_connection_compared">Последна връзка с помпата е %1$s %2$s минути преди</string>
<string name="sendsmsactionlabel">Изпращане на SMS с текст %1$s</string>
<string name="sendsmsactiondescription">Изпрати SMS до всички телефони от настройките</string>
@ -1367,4 +1391,7 @@
<string name="format_percent">%1$d %%</string>
<string name="boluswizard">Болус калкулатор</string>
<string name="unit_minute_short">мин</string>
<string name="format_carbs">%1$dг</string>
<string name="common_on">Вкл</string>
<string name="common_off">Изкл</string>
</resources>

View file

@ -36,7 +36,7 @@
<string name="objectives_useloop">Zobrazte obsah modulu Smyčka</string>
<string name="objectives_usescale">Přepněte režim zobrazení dlouhým stisknutím grafu glykémie</string>
<string name="objectives_button_enter">Zadat</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Zadejte kód, který jste získali od vývojářů, abyste obešli zbývající cíle</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Pokud jste byli dříve uživateli OpenAPS a váš NS má alespoň 3 měsíce dat z používání smyčky, můžete poslat e-mail na adresu objectives@androidaps.org s adresou svého NS a požádat o kód, pomocí něhož budete moci obejít zbývající cíle. Zadejte kód získaný od vývojářů.</string>
<string name="codeaccepted">Kód přijat</string>
<string name="codeinvalid">Neplatný kód</string>
<string name="objectives_exam_objective">Prokažte své znalosti</string>

View file

@ -260,11 +260,23 @@
<string name="smscommunicator_allowednumbers">Povolená tel. čísla</string>
<string name="smscommunicator_allowednumbers_summary">+XXXXXXXXXX;+YYYYYYYYYY</string>
<string name="smscommunicator_bolusreplywithcode">K potvrzení bolusu %1$.2fU odpověz SMS s kódem %2$s</string>
<string name="smscommunicator_mealbolusreplywithcode">Pro potvrzení bolusu na jídlo %1$.2fU odpovězte pomocí SMS s kódem %2$s</string>
<string name="smscommunicator_temptargetwithcode">Pro nastavení dočasného cíle %1$s odpovězte pomocí SMS s kódem %2$s</string>
<string name="smscommunicator_temptargetcancel">Pro zrušení dočasného cíle odpovězte pomocí SMS s kódem %1$s</string>
<string name="smscommunicator_stopsmswithcode">Chcete-li deaktivovat Vzdálené řízení přes SMS, odpovězte pomocí SMS s kódem %1$s.\n\nUpozornění: tuto funkci budete moci znovu aktivovat pouze z telefonu s hlavní verzí AAPS.</string>
<string name="smscommunicator_stoppedsms">Služba Vzdáleného řízení přes SMS zastavena. Chcete-li ji znovu aktivovat, použijte telefon s hlavní verzí AAPS.</string>
<string name="smscommunicator_calibrationreplywithcode">Odeslání kalibrace %1$.2f potvrďte kódem %2$s</string>
<string name="smscommunicator_bolusfailed">Chyba při aplikování bolusu</string>
<string name="smscommunicator_remotebolusmindistance_summary">Minimální počet minut, které musí uplynout mezi dvěma bolusy podanými přes vzdálené řízení</string>
<string name="smscommunicator_remotebolusmindistance">Kolik minut (minimálně) musí uplynout mezi dvěma bolusy</string>
<string name="smscommunicator_remotebolusmindistance_caveat">Úprava tohoto nastavení v zájmu vaší bezpečnosti vyžaduje, abyste zadali alespoň 2 telefonní čísla.</string>
<string name="bolusdelivered">Bolus %1$.2fU aplikován úspěšně</string>
<string name="bolusrequested">Podávání %1$.2fU inzulínu</string>
<string name="smscommunicator_bolusdelivered">Bolus %1$.2fU aplikován úspěšně</string>
<string name="smscommunicator_mealbolusdelivered">Bolus na jídlo %1$.2fU byl úspěšně aplikován</string>
<string name="smscommunicator_mealbolusdelivered_tt">Cíl %1$s na %2$d minut</string>
<string name="smscommunicator_tt_set">Cíl %1$s na %2$d minut byl úspěšně nastaven</string>
<string name="smscommunicator_tt_canceled">Dočasný cíl byl úspěšně zrušen</string>
<string name="bolusdelivering">Aplikováno %1$.2fU</string>
<string name="smscommunicator_remotecommandsallowed">Povolit posílání příkazů přes SMS</string>
<string name="glucosetype_finger">Glukoměr</string>
@ -324,10 +336,13 @@
<string name="smscommunicator_basalreplywithcode">Pro spuštění bazálu %1$.2fU/h na %2$d min odpovězte SMS s kódem %3$s</string>
<string name="smscommunicator_profilereplywithcode">Pro přepnutí profilu na %1$s %2$d%% odpovězte SMS s kódem %3$s</string>
<string name="smscommunicator_extendedreplywithcode">Pro spuštění prodlouženého bolusu %1$.2fU na %2$d min odpovězte SMS s kódem %3$s</string>
<string name="smscommunicator_carbsreplywithcode">Pro zadání %1$dg na %2$s odpovězte pomocí SMS s kódem %3$s</string>
<string name="smscommunicator_basalpctreplywithcode">Pro spuštění bazálu %1$d%% na %2$d min odpovězte SMS s kódem %3$s</string>
<string name="smscommunicator_suspendreplywithcode">K pozastavení smyčky na %1$d minut odpověz SMS s kódem %2$s</string>
<string name="smscommunicator_tempbasalset">Dočasný bazál %1$.2fU/h na %2$d minut spuštěn</string>
<string name="smscommunicator_extendedset">Prodloužený bolus %1$.2fU na %2$d min úspěšně spuštěn</string>
<string name="smscommunicator_carbsset">Sacharidy %1$dg byly úspěšně zadány</string>
<string name="smscommunicator_carbsfailed">Zadání %1$dg sacharidů se nezdařilo</string>
<string name="smscommunicator_tempbasalset_percent">Dočasný bazál %1$d%% na %2$d minut úspěšně spuštěn</string>
<string name="smscommunicator_tempbasalfailed">Spuštění dočasného bazálu selhalo</string>
<string name="smscommunicator_extendedfailed">Spuštění prodlouženého bolusu selhalo</string>
@ -680,6 +695,7 @@
<string name="shortgramm">g</string>
<string name="shortminute">m</string>
<string name="shorthour">h</string>
<string name="shortday">d</string>
<string name="none"><![CDATA[<prázdný>]]></string>
<string name="shortkilojoul">kJ</string>
<string name="shortenergy">En</string>
@ -708,6 +724,7 @@
<string name="bgsource_upload">Nastavení nahrávání glykémií</string>
<string name="wear_detailed_delta_title">Zobrazovat detailní změny</string>
<string name="wear_detailed_delta_summary">Zobrazovat rozdíl s jedním desetinným místem navíc</string>
<string name="smbmaxminutes">Max. minut SMB</string>
<string name="smbmaxminutes_summary">Maximální počet minut bazálu, ke kterým se limituje SMB</string>
<string name="unsupportedfirmware">Nepodporovaný firmware v pumpě</string>
<string name="dexcomg5_xdripupload_title">Odesílat data do xDrip+</string>
@ -1148,7 +1165,7 @@
<string name="tidepool_upload_profile">Nahrávat přepnutí profilu, dočasné cíle</string>
<string name="tidepool_upload_bg">Nahrávat měření z prstu</string>
<string name="dst_in_24h_warning">Změna letního času za méně než 24 hodin</string>
<string name="dst_loop_disabled_warning">Změna letního času za méně než 3 hodiny - Uzavřená smyčka zastavena</string>
<string name="dst_loop_disabled_warning">Změna letního času za méně než 3 hodiny Uzavřená smyčka zastavena</string>
<string name="storage">omezení vnitřního úložiště</string>
<string name="diskfull">Uvolněte alespoň %1$d MB z vnitřního úložiště! Smyčka zakázána!</string>
<string name="wrongformat">Chybný formát</string>

View file

@ -37,7 +37,7 @@ die Formel maxIOB = durchschnittlicher Essensbolus + 3 x höchste Basalrate</str
<string name="objectives_useloop">Zeige den Inhalt des Loop-Plugins an</string>
<string name="objectives_usescale">Nutze die Skalierfunktion. Drücke dazu lange auf das BZ-Diagramm</string>
<string name="objectives_button_enter">OK</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Gib den Code ein, den Du von den Entwicklern erhalten hast, um die restlichen Objectives zu überspringen.</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Wenn Du früher bereits OpenAPS genutzt hast und auf Deiner Nightscout-Seite mindestens drei Monate Closed-Loop-Daten ersichtlich sind, kannst Du eine E-Mail an objectives@androidaps.org mit Deiner NS-URL und Deinem Anforderungscode senden, um die restlichen Ziele zu überspringen. Code eingeben, der von den Entwicklern übermittelt wurde:</string>
<string name="codeaccepted">Code akzeptiert</string>
<string name="codeinvalid">Code ungültig</string>
<string name="objectives_exam_objective">Prüfe Dein Wissen</string>

View file

@ -260,11 +260,23 @@
<string name="smscommunicator_allowednumbers">Erlaubte Telefonnummern</string>
<string name="smscommunicator_allowednumbers_summary">+XXXXXXXXXX;+YYYYYYYYYY</string>
<string name="smscommunicator_bolusreplywithcode">Um einen Bolus von %1$.2f IE abzugeben, antworte mit dem Code %2$s.</string>
<string name="smscommunicator_mealbolusreplywithcode">Um einen Mahlzeitenbolus von %1$.2f IE abzugeben, antworte mit dem Code %2$s.</string>
<string name="smscommunicator_temptargetwithcode">Um ein Temp Target von %1$s zu setzen, antworte mit dem Code %2$s</string>
<string name="smscommunicator_temptargetcancel">Um das temporäre Ziel zu stoppen, antworte mit dem Code %1$s</string>
<string name="smscommunicator_stopsmswithcode">Um den SMS Remote Service zu deaktivieren, antworte mit dem Code %1$s.\n\nBeachte, dass Du diesen nur am AAPS Master Smartphone wieder aktivieren kannst.</string>
<string name="smscommunicator_stoppedsms">SMS Remote Service gestoppt. Verwende das AAPS Master, um ihn wieder zu aktivieren.</string>
<string name="smscommunicator_calibrationreplywithcode">Um die Kalibrierung %1$.2f zu senden, antworte mit dem Code %2$s.</string>
<string name="smscommunicator_bolusfailed">Bolus fehlgeschlagen</string>
<string name="smscommunicator_remotebolusmindistance_summary">Minimale Dauer in Minuten, die nach einem Remote Bolus verstrichen sein muss, bevor ein neuer abgegeben werden kann.</string>
<string name="smscommunicator_remotebolusmindistance">Anzahl Minuten, die mindestens zwischen zwei Bolusgaben liegen müssen.</string>
<string name="smscommunicator_remotebolusmindistance_caveat">Aus Sicherheitsgründen musst Du mindestens zwei Telefonnummern eintragen, um diese Voreinstellung zu ändern.</string>
<string name="bolusdelivered">Bolus %1$.2fIE erfolgreich abgegeben</string>
<string name="bolusrequested">Werde %1$.2fIE abgeben</string>
<string name="smscommunicator_bolusdelivered">Bolus %1$.2fIE erfolgreich abgegeben</string>
<string name="smscommunicator_mealbolusdelivered">Mahlzeiten-Bolus %1$.2f IE erfolgreich abgegeben.</string>
<string name="smscommunicator_mealbolusdelivered_tt">Ziel %1$s für %2$d Minuten</string>
<string name="smscommunicator_tt_set">Ziel %1$s für %2$d Minuten erfolgreich gesetzt.</string>
<string name="smscommunicator_tt_canceled">Temporäres Ziel wurde erfolgreich abgebrochen</string>
<string name="bolusdelivering">Gebe %1$.2fIE ab</string>
<string name="smscommunicator_remotecommandsallowed">Erlaube externe Befehle per SMS</string>
<string name="glucosetype_finger">Finger</string>
@ -314,7 +326,7 @@
<string name="youareonallowedlimit">Limit erreicht</string>
<string name="noprofileselected">Kein Profil ausgewählt</string>
<string name="smscommunicator_loophasbeendisabled">Loop wurde deaktiviert.</string>
<string name="smscommunicator_loophasbeenenabled">Lopp wurde aktiviert</string>
<string name="smscommunicator_loophasbeenenabled">Loop wurde aktiviert</string>
<string name="smscommunicator_loopisdisabled">Loop ist deaktiviert.</string>
<string name="smscommunicator_loopisenabled">Loop ist aktiviert.</string>
<string name="valuelimitedto">%1$.2f limitiert auf %2$.2f</string>
@ -324,10 +336,13 @@
<string name="smscommunicator_basalreplywithcode">Um eine Basalrate von %1$.2fIE/h für %2$d Minuten zu setzen, antworte mit dem Code %3$s</string>
<string name="smscommunicator_profilereplywithcode">Um das Profil auf %1$s %2$d%% zu setzen, antworte mit dem Code %3$s</string>
<string name="smscommunicator_extendedreplywithcode">Um den erweiterten Bolus %1$.2fIE für %2$d Minuten abzugeben, antworte mit dem Code %3$s</string>
<string name="smscommunicator_carbsreplywithcode">Um %1$dg Kohlenhydrate um %2$s einzugeben, antworte mit dem Code %3$s</string>
<string name="smscommunicator_basalpctreplywithcode">Um die Basalrate von %1$d%% für %2$d Minuten zu setzen, antworte mit dem Code %3$s</string>
<string name="smscommunicator_suspendreplywithcode">Um das Loopen für %1$d Minuten zu pausieren, antworte mit dem Code %2$s.</string>
<string name="smscommunicator_tempbasalset">TBR mit %1$.2f IE/h für %2$d min wurde erfolgreich gestartet.</string>
<string name="smscommunicator_extendedset">Der erweiterte Bolus %1$.2f IE/h für %2$d Minuten wurde erfolgreich gestartet</string>
<string name="smscommunicator_carbsset">%1$dg Kohlenhydrate erfolgreich erfasst</string>
<string name="smscommunicator_carbsfailed">Eingabe von %1$dg Kohlenhydraten ist fehlgeschlagen.</string>
<string name="smscommunicator_tempbasalset_percent">Die temporäre Basalrate wurde erfolgreich für %2$d Minuten auf %1$d%% gesetzt</string>
<string name="smscommunicator_tempbasalfailed">Das Starten der TBR ist fehlgeschlagen.</string>
<string name="smscommunicator_extendedfailed">Die Abgabe des erweiterten Bolus ist fehlgeschlagen</string>
@ -680,6 +695,7 @@
<string name="shortgramm">g</string>
<string name="shortminute">min</string>
<string name="shorthour">h</string>
<string name="shortday">T</string>
<string name="none"><![CDATA[<nichts>]]></string>
<string name="shortkilojoul">kJ</string>
<string name="shortenergy">En</string>
@ -708,6 +724,7 @@
<string name="bgsource_upload">BZ Upload Einstellungen</string>
<string name="wear_detailed_delta_title">Zeige detailliertes Delta</string>
<string name="wear_detailed_delta_summary">Delta wird mit Dezimalstelle angezeigt.</string>
<string name="smbmaxminutes">SMB max. Minuten</string>
<string name="smbmaxminutes_summary">SMB Basal-Limit in Minuten</string>
<string name="unsupportedfirmware">Nicht unterstützte Pumpen-Firmware</string>
<string name="dexcomg5_xdripupload_title">Sende BZ-Werte zu xDrip+</string>

View file

@ -36,7 +36,6 @@
<string name="objectives_useloop">Εμφάνιση περιεχομένου της προσθήκης Κύκλωμα</string>
<string name="objectives_usescale">Χρησιμοποιήστε τη λειτουργία κλίμακας πατώντας παρατεταμένα το διάγραμμα BG</string>
<string name="objectives_button_enter">Εισαγωγή</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Εισαγάγετε τον κωδικό που λαμβάνετε από τους προγραμματιστές για να παρακάμψετε τους υπόλοιπους στόχους</string>
<string name="codeaccepted">Κωδικός αποδεκτός</string>
<string name="codeinvalid">Μη έγκυρος κωδικός</string>
<string name="objectives_exam_objective">Αποδείξτε τις γνώσεις σας</string>

View file

@ -1147,8 +1147,6 @@
<string name="tidepool_upload_tbr">Αποστολή προσωρινών ρυθμών</string>
<string name="tidepool_upload_profile">Αποστολή αλλαγών προφίλ, προσωρινών στόχων</string>
<string name="tidepool_upload_bg">Αποστολή BG βαθμονομήσεων</string>
<string name="dst_in_24h_warning">Αλλαγή σε Θερινή ώρα σε 24h ή λιγότερο</string>
<string name="dst_loop_disabled_warning">Η Θερινή ώρα αλλάζει σε λιγότερο από 3 ώρες - Απενεργοποιήθηκε το κλειστό κύκλωμα</string>
<string name="storage">περιορισμός εσωτερικής μνήμης</string>
<string name="diskfull">Ελευθερώστε τουλάχιστον %1$d MB από εσωτερική μνήμη! Κύκλωμα απενεργοποιήθηκε!</string>
<string name="wrongformat">Λάθος μορφή αρχείου</string>

View file

@ -8,9 +8,9 @@
<string name="dia_hint1">https://androidaps.readthedocs.io/en/latest/EN/Configuration/Config-Builder.html?#insulin</string>
<string name="dia_meaningisequaltodiapump">El significado es igual al parámetro DIA utilizado en su bomba.</string>
<string name="dia_valuemustbedetermined">Debes determinar tu valor individual (pero no menos de 5 horas).</string>
<string name="hypott_label">Tema: Hypo Temp-Objetivo</string>
<string name="hypott_whenhypott">¿Cuál es la razón principal para establecer un hipo TT?</string>
<string name="hypott_goinglow">Para evitar que BG caiga si ya hay basal temporal a cero corriendo.</string>
<string name="hypott_label">Tema: Objetivo Temporal por Hipoglucemia</string>
<string name="hypott_whenhypott">¿Cuál es la razón principal para establecer un objetivo temporal por hipoglucemia?</string>
<string name="hypott_goinglow">Para evitar que la glucemia caiga si ya hay una basal temporal a cero activada.</string>
<string name="hypott_preventoversmb">Para evitar que AAPS inyecte demasiada insulina después de una subida causada por los carbohidratos de acción rápida utilizados para tratar una bajada en las lecturas de glucosa.</string>
<string name="hypott_hint1">https://androidaps.readthedocs.io/en/latest/EN/Usage/temptarget.html</string>
<string name="offlineprofile_whatprofile">¿Qué perfil puede ser usado y configurado estando desconectado?</string>
@ -163,4 +163,7 @@
<string name="basalhelp_diabetesteam">Tu equipo de diabetes</string>
<string name="basalhelp_google">Google</string>
<string name="basalhelp_facebook">Facebook</string>
<string name="other_medication_label">Otra medicación</string>
<string name="other_medication_text">La AAPS reduce el BR para aumentar la glucosa en la sangre. Los inhibidores del grupo de las SGLT2 (gliflozinas) pueden prevenir el aumento esperado de BG y, por lo tanto, pueden producir una deficiencia de insulina peligrosa (DKA).
\nLos nombres comunes de marca son: Invokana ®, Forxiga ®, Steglatro ®, Suglat ®, Apleway ®, Synjardy ®, Vokanamet ®, Xigduo ®.\n\nI prometo que no tomaré este tipo de medicamentos cuando use AAPS o desactivará el lazo cerrado antes de usar estas drogas.</string>
</resources>

View file

@ -10,7 +10,7 @@
<string name="alert_w32_title">Pila baja</string>
<string name="alert_w33_title">Fecha/hora no válida</string>
<string name="alert_w34_title">Fin de la garantía</string>
<string name="alert_w36_title">TBR cancelada</string>
<string name="alert_w36_title">Basal Temporal cancelada</string>
<string name="alert_w38_title">Bolo cancelado</string>
<string name="alert_w39_title">Aviso de préstamo de infusora</string>
<string name="alert_m20_title">Reservorio no insertado</string>

View file

@ -36,7 +36,6 @@
<string name="objectives_useloop">Mostrar contenido del plugin Loop</string>
<string name="objectives_usescale">Usar función de escala mediante un gráfico BG pulsado largo</string>
<string name="objectives_button_enter">Intro</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Introduzca el código obtenido de los desarrolladores para eludir el resto de objetivos</string>
<string name="codeaccepted">Código aceptado</string>
<string name="codeinvalid">Código no válido</string>
<string name="objectives_exam_objective">Compruebe su conocimiento</string>

View file

@ -1147,8 +1147,8 @@
<string name="tidepool_upload_tbr">Subir basales temporales</string>
<string name="tidepool_upload_profile">Subir conmutaciones de perfil, objetivos temps</string>
<string name="tidepool_upload_bg">Subir pruebas BG</string>
<string name="dst_in_24h_warning">Cambio al horario de verano/invierno en menos de 24 horas</string>
<string name="dst_loop_disabled_warning">Cambio al horario de verano/invierno hace menos de 3 horas - Lazo cerrado deshabilitado</string>
<string name="dst_in_24h_warning">Cambio al horario de verano en menos de 24 horas</string>
<string name="dst_loop_disabled_warning">Cambio al horario de verano hace menos de 3 horas - Lazo cerrado deshabilitado</string>
<string name="storage">restricción de almacenamiento interno</string>
<string name="diskfull">Libera al menos %1$d MB de almacenamiento interno. ¡Loop desactivado!</string>
<string name="wrongformat">Formato incorrecto</string>
@ -1236,6 +1236,8 @@
<string name="medtronic_pump_battery_no">No seleccionado (Vista simple)</string>
<string name="medtronic_pump_battery_alkaline">Alcalina (vista extendida)</string>
<string name="medtronic_pump_battery_lithium">Litio (vista extendida)</string>
<string name="medtronic_pump_battery_nizn">NiZn (vista ampliada)</string>
<string name="medtronic_bolus_debugging">Bolos/Depuración de Tratamientos</string>
<!-- RL BLE Scanning -->
<string name="rileylink_scanner_scan_scan">ESCANEAR</string>
<string name="rileylink_scanner_scan_stop">DETENER</string>
@ -1373,4 +1375,6 @@
<string name="boluswizard">Asistente Bolus</string>
<string name="unit_minute_short">min</string>
<string name="format_carbs">%1$dg</string>
<string name="common_on">Activado</string>
<string name="common_off">Desactivado</string>
</resources>

View file

@ -36,7 +36,7 @@
<string name="objectives_useloop">Affichage du contenu du plugin Boucle</string>
<string name="objectives_usescale">Modification de l\'échelle du graphique par un appui long sur la courbe de glycémie</string>
<string name="objectives_button_enter">Entrer</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Entrez le code obtenu auprès des développeurs pour contourner le reste des objectifs</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Si vous étiez avant un utilisateur d\'OpenAPS et que votre NS a au moins 3 mois de données de bouclage, vous pouvez envoyer un e-mail à objectives@androidaps.org avec votre adresse NS et demander un code pour contourner le reste des objectifs. Entrez le code obtenu auprès des développeurs</string>
<string name="codeaccepted">Code accepté</string>
<string name="codeinvalid">Code invalide</string>
<string name="objectives_exam_objective">Prouver ses connaissances</string>

View file

@ -155,9 +155,9 @@
<string name="confirmation">Confirmation</string>
<string name="entertreatmentquestion">Entrez le nouveau traitement :</string>
<string name="bolus">Bolus</string>
<string name="sms_bolus">Bolus :</string>
<string name="sms_bolus">Bolus:</string>
<string name="basal">Basal</string>
<string name="sms_basal">Basal :</string>
<string name="sms_basal">Basal:</string>
<string name="carbs">Glucides</string>
<string name="changeyourinput">Changez vos entrées !</string>
<string name="setextendedbolusquestion">Définir un nouveau bolus étendu</string>
@ -314,7 +314,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="overview_bolusprogress_goingtodeliver">%1$.2fU vont être injectées</string>
<string name="youareonallowedlimit">Vous avez atteint la limite maximale</string>
<string name="noprofileselected">Aucun profil séléctionné</string>
<string name="smscommunicator_loophasbeendisabled">La Boucle été désactivée</string>
<string name="smscommunicator_loophasbeendisabled">La Boucle a été désactivée</string>
<string name="smscommunicator_loophasbeenenabled">La Boucle a été activée</string>
<string name="smscommunicator_loopisdisabled">La Boucle est désactivée</string>
<string name="smscommunicator_loopisenabled">La Boucle est activée</string>
@ -322,17 +322,17 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="valueoutofrange">La valeur %1$s est en dehors des limites</string>
<string name="smscommunicator_remotecommandnotallowed">La commande à distance n\'est pas autorisée</string>
<string name="smscommunicator_remotebolusnotallowed">Bolus à distance non disponible. Réessayez plus tard.</string>
<string name="smscommunicator_basalreplywithcode">Pour démarrer Basal %1$.2fU/h pendant %2$d min, renvoyer le code %3$s</string>
<string name="smscommunicator_basalreplywithcode">Pour démarrer la Basal %1$.2fU/h pendant %2$d min, renvoyer le code %3$s</string>
<string name="smscommunicator_profilereplywithcode">Pour changer le profil vers %1$s %2$d%%, renvoyer le code %3$s</string>
<string name="smscommunicator_extendedreplywithcode">Pour démarrer le Bolus étendu %1$.2fU pendant %2$d min, renvoyer le code %3$s</string>
<string name="smscommunicator_basalpctreplywithcode">Pour démarrer le Basal %1$d%% pendant %2$d min, renvoyer le code %3$s</string>
<string name="smscommunicator_basalpctreplywithcode">Pour démarrer la Basal %1$d%% pendant %2$d min, renvoyer le code %3$s</string>
<string name="smscommunicator_suspendreplywithcode">Envoyer le code %2$s pour suspendre la Boucle pour %1$d minutes</string>
<string name="smscommunicator_tempbasalset">Démarrage réussi pour %1$.2fU/h de basal temporaire pour %2$d min</string>
<string name="smscommunicator_extendedset">Le Bolus étendu %1$.2fU pendant %2$d min a commencé avec succès</string>
<string name="smscommunicator_tempbasalset_percent">Démarrage réussi pour %1$d%% de Basal temporaire pour %2$d min</string>
<string name="smscommunicator_tempbasalfailed">Le démarrage du basal temporaire a échoué</string>
<string name="smscommunicator_extendedfailed">Le départ du Bolus étendu a échoué</string>
<string name="smscommunicator_basalstopreplywithcode">Envoyer le code %1$s pour arrêter le Basal temporaire</string>
<string name="smscommunicator_basalstopreplywithcode">Envoyer le code %1$s pour arrêter la Basal temporaire</string>
<string name="smscommunicator_extendedstopreplywithcode">Pour arrêter le Bolus étendu, renvoyer le code %1$s</string>
<string name="smscommunicator_tempbasalcanceled">Basal temporaire annulé</string>
<string name="smscommunicator_extendedcanceled">Bolus étendu annulé</string>
@ -393,7 +393,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="ongoingnotificaction">Notification en cours</string>
<string name="old_data">DONNÉES ANCIENNES</string>
<string name="minago">%1$d min passées</string>
<string name="sms_minago">%1$dmin passées</string>
<string name="sms_minago">il y a %1$d min</string>
<string name="localprofile">Profil Local</string>
<string name="openapsama">OpenAPS AMA</string>
<string name="short_avgdelta">Delta basé sur une courte moyenne</string>
@ -533,7 +533,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="treatments_wizard_bgtrend_label">Delta 15 min</string>
<string name="treatments_wizard_cob_label">GA</string>
<string name="superbolus">Superbolus</string>
<string name="ns_logappstartedevent">Démarrage de l\'app journaux vers NS</string>
<string name="ns_logappstartedevent">Démarrage AAPS entré dans NS</string>
<string name="restartingapp">Sortie de lapplication pour appliquer de nouveaux paramètres.</string>
<string name="danarv2pump">DanaRv2</string>
<string name="configbuilder_insulin">Insuline</string>
@ -544,9 +544,9 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="insulin_shortname">INS</string>
<string name="enablesuperbolus">Activer les Superbolus dans lAssistant</string>
<string name="enablesuperbolus_summary">Activer la fonctionnalité SuperBolus dans lAssistant. Ne pas lactiver avant de bien comprendre comment cela fonctionne réellement. IL PEUT PROVOQUER UNE OVERDOSE DINSULINE SI UTILISÉ AVEUGLÉMENT !</string>
<string name="show_statuslights">Afficher les lumières d\'état sur l\'écran d\'accueil</string>
<string name="show_statuslights_extended">Afficher les lumières d\'état prolongées sur l\'écran d\'accueil</string>
<string name="show_statuslights_extended_summary">Activer les lumières d\'état prolongées pour AgeC, AgeI, AgeS, niveaux du réservoir et de batterie sur l\'écran d\'accueil.</string>
<string name="show_statuslights">Afficher les voyants d\'état sur l\'écran d\'accueil</string>
<string name="show_statuslights_extended">Afficher les voyants d\'état prolongés sur l\'écran d\'accueil</string>
<string name="show_statuslights_extended_summary">Activer les voyants d\'état prolongés pour AgeC, AgeI, AgeS, niveaux du réservoir et de batterie sur l\'écran d\'accueil.</string>
<string name="statuslights_res_warning">Seuil d\'avertissement de niveau du réservoir [U]</string>
<string name="statuslights_res_critical">Seuil critique de niveau du réservoir [U]</string>
<string name="statuslights_bat_warning">Seuil davertissement du niveau de batterie [%]</string>
@ -681,6 +681,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="shortgramm">g</string>
<string name="shortminute">m</string>
<string name="shorthour">h</string>
<string name="shortday">j</string>
<string name="none"><![CDATA[<aucune>]]></string>
<string name="shortkilojoul">kJ</string>
<string name="shortenergy">En</string>
@ -705,13 +706,14 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="btwatchdog_title">BT Watchdog</string>
<string name="btwatchdog_summary">Ceci va arrêter le Bluetooth du téléphone pour une seconde si la connexion pompe nest pas possible. Cela peut assister certains téléphones dont la connexion Bluetooth se bloque.</string>
<string name="eversense">App Eversense (patché)</string>
<string name="dexcomg5_nsupload_title">Remonter les données glycémiques vers NS</string>
<string name="dexcomg5_nsupload_title">Remonter les Gly vers NS</string>
<string name="bgsource_upload">Paramètres de téléchargement des glycémies</string>
<string name="wear_detailed_delta_title">Afficher le delta détaillé</string>
<string name="wear_detailed_delta_summary">Afficher delta avec une décimale supplémentaire</string>
<string name="smbmaxminutes">SMB minutes max</string>
<string name="smbmaxminutes_summary">Max. minutes de basal pour limiter le SMB</string>
<string name="unsupportedfirmware">Firmware pompe incompatible </string>
<string name="dexcomg5_xdripupload_title">Transmettre les données G vers xDrip+</string>
<string name="dexcomg5_xdripupload_title">Transmettre les Gly vers xDrip+</string>
<string name="dexcomg5_xdripupload_summary">Dans xDrip+ veuillez séléctionner 640g/Eversense comme source de données</string>
<string name="nsclientbg">Glycémie NSClient</string>
<string name="minimalbasalvaluereplaced">Valeur de basal remplacée par la valeur minimale autorisée : %1$s</string>
@ -869,7 +871,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="unsafeusage">utilisation dangereuse</string>
<string name="readstatusfailed">La lecture du statut a échoué</string>
<string name="record_pump_site_change">Enregistrer changement de site de cathéter</string>
<string name="record_insulin_cartridge_change">Enregistrer changement de réservoir</string>
<string name="record_insulin_cartridge_change">Enreg. changement de réservoir</string>
<string name="smbalwaysdisabled">SMB toujours et post-ingestion de glucides désactivé car la source de glycémies actuelle ne supporte pas de filtrage avancé</string>
<string name="smbnotallowedinopenloopmode">SMB non autorisé en mode Boucle Ouverte</string>
<string name="food_short">Aliments</string>
@ -1148,8 +1150,8 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="tidepool_upload_tbr">Transférer les Basal temporaires</string>
<string name="tidepool_upload_profile">Transférer les changements de profils, les objectifs temporaires</string>
<string name="tidepool_upload_bg">Transférer les tests de glycémies</string>
<string name="dst_in_24h_warning">Changement d\'heure d\'été dans moins de 24 heures</string>
<string name="dst_loop_disabled_warning">Changement d\'heure d\'été dans moins de 3 heures - Boucle fermée désactivée</string>
<string name="dst_in_24h_warning">Changement d\'heure dans moins de 24 heures</string>
<string name="dst_loop_disabled_warning">Changement d\'heure dans moins de 3 heures - Boucle fermée désactivée</string>
<string name="storage">stockage interne limité</string>
<string name="diskfull">Boucle désactivée ! Libérez au moins %1$d Mo du stockage interne !</string>
<string name="wrongformat">Format incorrect</string>

View file

@ -28,8 +28,8 @@
<string name="objectives_exportsettings">Esportarle localmente dal menu Manutenzione.</string>
<string name="objectives_storeelsewhere">Salvare il file esportato in un altro posto come l\'email, Dropbox, Google drive…</string>
<string name="objectives_doexportonstart">Esportarle subito dopo l\'installazione di AAPS.</string>
<string name="objectives_doexportafterchange">Esportarli dopo aver fatto modifiche d\'impostazione.</string>
<string name="objectives_doexportafterobjective">Esportarli dopo il completamento di un obiettivo.</string>
<string name="objectives_doexportafterchange">Esportarle dopo aver fatto modifiche d\'impostazione.</string>
<string name="objectives_doexportafterobjective">Esportarle dopo il completamento di un obiettivo.</string>
<string name="objectives_doexportafterfirtssettings">Esportarle quando termini le configurazioni iniziali.</string>
<string name="objectives_hint1">https://androidaps.readthedocs.io/en/latest/EN/Usage/ExportImportSettings.html</string>
<string name="objectives_hint2">https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#what-emergency-equipment-is-recommended-to-take-with-me</string>

View file

@ -32,18 +32,18 @@
<string name="objectives_usedisconnectpump">Simula la doccia. Disconnetti il micro per 1h (premi a lungo su Loop aperto)</string>
<string name="objectives_usereconnectpump">... e riconnetti allo stesso modo</string>
<string name="objectives_usetemptarget">Crea un target temporaneo personalizzato con una durata di 10 min (premi a lungo sul tuo target corrente)</string>
<string name="objectives_useactions">Nel Configuratore attiva il plugin Azioni, rendilo visibile e visualizzane i contenuti tramite il menu in alto</string>
<string name="objectives_useactions">Nel Configuratore strutturale attiva il plugin Azioni, rendilo visibile e visualizzane i contenuti tramite il menu in alto</string>
<string name="objectives_useloop">Visualizza il contenuto del plugin Loop</string>
<string name="objectives_usescale">Usa la funzione di ridimensionamento premendo a lungo sul grafico delle glicemie</string>
<string name="objectives_button_enter">Entra</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Inserisci il codice ottenuto dagli sviluppatori per aggirare il resto degli obiettivi</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Se prima eri un utente OpenAPS e il tuo NS ha almeno 3 mesi di dati in loop, puoi inviare un\'e-mail a objectives@androidaps.org con il tuo indirizzo NS e richiedere il codice per ignorare il resto degli obiettivi. Inserisci il codice ottenuto dagli sviluppatori</string>
<string name="codeaccepted">Codice accettato</string>
<string name="codeinvalid">Codice non valido</string>
<string name="objectives_exam_objective">Dai prova della tua conoscenza</string>
<string name="objectives_exam_gate">Studia e rispondi correttamente alle domande</string>
<string name="answerdisabledto">Risposta disabilitata per: %1$s</string>
<string name="wronganswer">Risposta sbagliata!</string>
<string name="unfinshed_button">Prossimo non completato</string>
<string name="unfinshed_button">Prossimo N.C.</string>
<string name="requestcode">Codice richiesta: %1$s</string>
<string name="objectives_hint">(segna tutte le risposte corrette)</string>
<string name="disconnectpump_hint">https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#what-to-do-when-taking-a-shower-or-bath</string>

View file

@ -7,7 +7,7 @@
<!-- <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>
<string name="treatmentssafety_maxcarbs_title">Max carboidrati consentiti [g]</string>
<string name="treatmentssafety_maxcarbs_title">Max CHO consentiti [g]</string>
<string name="nav_preferences">Preferenze</string>
<string name="nav_refreshtreatments">Ricarica trattamenti da NS</string>
<string name="nav_resetdb">Resetta database</string>
@ -18,7 +18,7 @@
<string name="ns_sync_use_absolute_title">Utilizza sempre valori basali assoluti</string>
<string name="alert_dialog_storage_permission_text">Per favore riavvia il tuo telefono oppure fai ripartire AndroidAPS dalle impostazioni di sistema \naltrimenti Android APS non farà il log (è importante monitorare e verificare che gli algoritmi stiano funzionando correttamente)!</string>
<string name="alert_dialog_permission_battery_optimization_failed">Questo dispositivo non sembra supportare la whitelist dell\'ottimizzazione della batteria: potrebbero verificarsi problemi di prestazioni.</string>
<string name="description_actions">Alcuni pulsanti per accedere rapidamente alle funzioni comuni</string>
<string name="description_actions">Alcuni tasti per accedere rapidamente alle funzioni comuni</string>
<string name="description_careportal">Inserisci voci di registro avanzate.</string>
<string name="description_config_builder">Utilizzato per configurare i plugin attivi</string>
<string name="description_objectives">Programma di apprendimento</string>
@ -31,7 +31,7 @@
<string name="description_ma">Stato dell\'algoritmo nel 2016</string>
<string name="description_ama">Stato dell\'algoritmo nel 2017</string>
<string name="description_smb">Algoritmo più recente per gli utenti avanzati</string>
<string name="description_overview">Visualizza lo stato corrente del tuo loop e i pulsanti per le azioni più comuni</string>
<string name="description_overview">Visualizza lo stato corrente del tuo loop e i tasti per le azioni più comuni</string>
<string name="description_persistent_notification">Mostra una notifica con una breve panoramica di ciò che sta facendo il tuo loop</string>
<string name="description_profile_local">Definisci un profilo disponibile offline.</string>
<string name="description_profile_nightscout">Fornisce il profilo definito in Nightscout</string>
@ -43,15 +43,15 @@
<string name="description_pump_dana_rs">Integrazione del microinfusore DANA Diabecare RS</string>
<string name="description_pump_mdi">Per le persone in terapia multi-iniettiva</string>
<string name="description_pump_virtual">Per microinfusori che non hanno ancora alcun driver (Loop Aperto)</string>
<string name="description_sensitivity_aaps">La sensibilità è calcolata allo stesso modo di Oref0, ma puoi specificare l\'intervallo di tempo al passato. L\'assorbimento minimo dei carboidrati è calcolato da \'max tempo assorbimento carboidrati\' nelle preferenze.</string>
<string name="description_sensitivity_aaps">La sensibilità è calcolata allo stesso modo di Oref0, ma puoi specificare l\'intervallo di tempo al passato. L\'assorbimento minimo dei carboidrati è calcolato da \'max tempo assorbimento pasto\' nelle preferenze.</string>
<string name="description_sensitivity_oref0">La sensibilità è calcolata dai dati delle ultime 24h e i carboidrati (se non assorbiti) vengono tagliati fuori dopo il tempo specificato nelle preferenze.</string>
<string name="description_sensitivity_oref1">La sensibilità è calcolata dai dati delle ultime 8h e i carboidrati (se non assorbiti) vengono tagliati fuori dopo il tempo specificato nelle preferenze. Il Plugin calcola anche UAM.</string>
<string name="description_sensitivity_weighted_average">La sensibilità è calcolata come media ponderata dalle deviazioni. Le deviazioni più recenti hanno peso maggiore. L\'assorbimento minimo dei carboidrati è calcolato da \'max tempo assorbimento carboidrati\' nelle preferenze. Questo algoritmo è il più veloce nel seguire i cambiamenti di sensibilità.</string>
<string name="description_source_eversense">Ricevi valori Glicemia dall\'app Eversense modificata.</string>
<string name="description_source_glimp">Ricevi valori Glicemia da Glimp.</string>
<string name="description_source_mm640g">Ricevi valori Glicemia da 600SeriesAndroidUploader.</string>
<string name="description_source_ns_client">Scarica dati Glicemia da Nightscout</string>
<string name="description_source_xdrip">Ricevi dati Glicemia da xDrip.</string>
<string name="description_sensitivity_weighted_average">La sensibilità è calcolata come media ponderata dalle deviazioni. Le deviazioni più recenti hanno peso maggiore. L\'assorbimento minimo dei carboidrati è calcolato da \'max tempo assorbimento pasto\' nelle preferenze. Questo algoritmo è il più veloce nel seguire i cambiamenti di sensibilità.</string>
<string name="description_source_eversense">Ricevi valori glicemia dall\'app Eversense modificata.</string>
<string name="description_source_glimp">Ricevi valori glicemia da Glimp.</string>
<string name="description_source_mm640g">Ricevi valori glicemia da 600SeriesAndroidUploader.</string>
<string name="description_source_ns_client">Scarica dati glicemia da Nightscout</string>
<string name="description_source_xdrip">Ricevi dati glicemia da xDrip.</string>
<string name="description_treatments">Salva tutti i trattamenti che sono stati fatti</string>
<string name="description_wear">Monitora e controlla AndroidAPS usando il tuo smartwatch WearOS.</string>
<string name="description_xdrip_status_line">Mostra le informazioni del loop sulla watchface di xDrip+.</string>
@ -64,7 +64,7 @@
<string name="nsprofileview_target_label">Target</string>
<string name="noprofileset">NESSUN PROFILO IMPOSTATO</string>
<string name="treatments_insulin_label_string">Insulina:</string>
<string name="treatments_carbs_label_string">Carboidrati:</string>
<string name="treatments_carbs_label_string">CHO:</string>
<string name="treatments_iob_label_string">IOB:</string>
<string name="sms_iob">IOB:</string>
<string name="treatments_iobtotal_label_string">IOB totale:</string>
@ -75,15 +75,15 @@
<string name="tempbasals_iob_label_string">IOB:</string>
<string name="tempbasals_iobtotal_label_string">IOB totale:</string>
<string name="treatments_newtreatment_insulinamount_label">Insulina</string>
<string name="treatments_newtreatment_carbsamount_label">Carbs</string>
<string name="treatments_newtreatment_carbsamount_label">CHO</string>
<string name="treatments_wizard_bg_label">BG</string>
<string name="treatments_wizard_tt_label">TT</string>
<string name="treatments_wizard_carbs_label">Carbs</string>
<string name="treatments_wizard_correction_label">Corr</string>
<string name="treatments_wizard_carbs_label">CHO</string>
<string name="treatments_wizard_correction_label">Correzione</string>
<string name="insulin_unit_shortname">U</string>
<string name="treatments_wizard_bolusiob_label">IOB da bolo</string>
<string name="openapsma_run">Esegui ora</string>
<string name="vitualpump_label">MICROINFUSORE VIRTUALE</string>
<string name="vitualpump_label">MICRO VIRTUALE</string>
<string name="pump_basebasalrate_label">Velocità basale originale</string>
<string name="pump_tempbasal_label">Basale temporanea</string>
<string name="virtualpump_extendedbolus_label">Bolo esteso</string>
@ -108,7 +108,7 @@
<string name="glucose">Glicemia</string>
<string name="delta">Delta</string>
<string name="sms_delta">Delta:</string>
<string name="configbuilder">Configurazione strutturale</string>
<string name="configbuilder">Configuratore strutturale</string>
<string name="objectives">Obiettivi</string>
<string name="openapsma">OpenAPS MA</string>
<string name="overview">Panoramica</string>
@ -116,7 +116,7 @@
<string name="simpleprofile">Profilo semplice</string>
<string name="tempbasal">Basale temporanea</string>
<string name="treatments">Trattamenti</string>
<string name="virtualpump">Microinfusore Virtuale</string>
<string name="virtualpump">Micro Virtuale</string>
<string name="careportal">Portale</string>
<string name="configbuilder_pump">Micro</string>
<string name="configbuilder_pump_description">Quale microinfusore desideri utilizzare con AndroidAPS?</string>
@ -158,10 +158,10 @@
<string name="sms_bolus">Bolo:</string>
<string name="basal">Basale</string>
<string name="sms_basal">Basale</string>
<string name="carbs">Carbs</string>
<string name="carbs">CHO</string>
<string name="changeyourinput">Cambia il tuo input!</string>
<string name="setextendedbolusquestion">Imposta nuovo bolo esteso:</string>
<string name="configbuilder_bgsource">Origine Glicemia</string>
<string name="configbuilder_bgsource">Origine glicemia</string>
<string name="configbuilder_bgsource_description">Da dove AndroidAPS dovrebbe ottenere i suoi dati?</string>
<string name="xdrip">xDrip</string>
<string name="apsmode_title">Modalità APS</string>
@ -177,8 +177,8 @@
<string name="loopdisabled">LOOP DISABILITATO DAI VINCOLI</string>
<string name="treatments_wizard_basaliob_label">IOB da basale</string>
<string name="bolusconstraintapplied">Vincolo bolo applicato</string>
<string name="carbsconstraintapplied">Vincolo carboidrati applicato</string>
<string name="careportal_bgcheck">Controllo BG</string>
<string name="carbsconstraintapplied">Vincolo CHO applicato</string>
<string name="careportal_bgcheck">Controllo glicemia</string>
<string name="careportal_announcement">Annuncio</string>
<string name="careportal_note">Nota</string>
<string name="careportal_question">Domanda</string>
@ -194,16 +194,16 @@
<string name="careportal_combobolus">Bolo combo</string>
<string name="careportal_tempbasalstart">Inizio basale temporanea</string>
<string name="careportal_tempbasalend">Fine basale temporanea</string>
<string name="careportal_carbscorrection">Correzione con carboidrati</string>
<string name="careportal_carbscorrection">Correzione con CHO</string>
<string name="careportal_openapsoffline">OpenAPS Offline</string>
<string name="careportal_newnstreatment_eventtype">Tipo di evento</string>
<string name="careportal_newnstreatment_other">Altro</string>
<string name="careportal_newnstreatment_meter">Glucometro</string>
<string name="careportal_newnstreatment_sensor">Sensore</string>
<string name="careportal_newnstreatment_carbs_label">Carbs</string>
<string name="careportal_newnstreatment_carbs_label">CHO</string>
<string name="careportal_newnstreatment_insulin_label">Insulina</string>
<string name="careportal_newnstreatment_carbtime_label">Tempo carboidrati</string>
<string name="careportal_newnstreatment_split_label">Fraziona</string>
<string name="careportal_newnstreatment_carbtime_label">Tempo CHO</string>
<string name="careportal_newnstreatment_split_label">Frazione</string>
<string name="careportal_newnstreatment_duration_label">Durata</string>
<string name="careportal_newnstreatment_percent_label">Percentuale</string>
<string name="careportal_newnstreatment_absolute_label">Assoluto</string>
@ -224,11 +224,11 @@
<string name="filenotfound">File non trovato</string>
<string name="nav_export">Esporta impostazioni</string>
<string name="nav_import">Importa impostazioni</string>
<string name="openapsma_maxbasal_title">Max U/h che una basale temporanea può impostare</string>
<string name="openapsma_maxbasal_title">Max U/h a cui limitare una basale temporanea</string>
<string name="openapsma_maxbasal_summary">Questo valore è chiamato max basale nel contesto OpenAPS</string>
<string name="openapsma_maxiob_title">Max IOB da basale che OpenAPS può erogare [U]</string>
<string name="openapsma_maxiob_summary">Questo valore è chiamato Max IOB nel contesto OpenAPS\nIndica l\'insulina massima in [U] che APS può erogare contemporaneamente.</string>
<string name="dismiss">RESPINGI</string>
<string name="openapsma_maxiob_title">Max IOB da basale a cui limitare OpenAPS [U]</string>
<string name="openapsma_maxiob_summary">Questo valore è chiamato Max IOB nel contesto OpenAPS\nIndica l\'insulina massima in [U] che APS può erogare in contemporanea.</string>
<string name="dismiss">RIMUOVI</string>
<string name="danarpump">DanaR</string>
<string name="connecting">Connessione</string>
<string name="connected">Connesso</string>
@ -260,11 +260,23 @@
<string name="smscommunicator_allowednumbers">Numeri di telefono consentiti</string>
<string name="smscommunicator_allowednumbers_summary">+XXXXXXXXXX;+YYYYYYYYYY</string>
<string name="smscommunicator_bolusreplywithcode">Per erogare il bolo di %1$.2fU rispondi col codice %2$s</string>
<string name="smscommunicator_mealbolusreplywithcode">Per erogare il bolo pasto di %1$.2fU rispondi col codice %2$s</string>
<string name="smscommunicator_temptargetwithcode">Per impostare il Temp-Target %1$s rispondi con il codice %2$s</string>
<string name="smscommunicator_temptargetcancel">Per cancellare il Temp-Target rispondi col codice %1$s</string>
<string name="smscommunicator_stopsmswithcode">Per disabilitare il Servizio di Controllo Remoto tramite SMS rispondi col codice %1$s.\n\nRicorda che potrai riattivarlo solo in maniera diretta dallo smartphone master in cui è installato AAPS.</string>
<string name="smscommunicator_stoppedsms">Servizio di Controllo Remoto tramite SMS stoppato. Per riattivarlo, usa lo smartphone master in cui è installato AAPS.</string>
<string name="smscommunicator_calibrationreplywithcode">Per inviare la calibrazione %1$.2f rispondi col codice %2$s</string>
<string name="smscommunicator_bolusfailed">Bolo fallito</string>
<string name="smscommunicator_remotebolusmindistance_summary">Numero minimo di minuti che devono trascorrere tra un bolo remoto e il successivo</string>
<string name="smscommunicator_remotebolusmindistance">Quanti minuti devono trascorrere, almeno, tra un bolo e il successivo</string>
<string name="smscommunicator_remotebolusmindistance_caveat">Per la tua sicurezza, per modificare questa preferenza hai bisogno di aggiungere almeno 2 numeri di telefono.</string>
<string name="bolusdelivered">Bolo di %1$.2fU erogato con successo</string>
<string name="bolusrequested">Sto per erogare %1$.2fU</string>
<string name="smscommunicator_bolusdelivered">Bolo di %1$.2fU erogato con successo</string>
<string name="smscommunicator_mealbolusdelivered">Bolo pasto di %1$.2fU erogato con successo</string>
<string name="smscommunicator_mealbolusdelivered_tt">Target %1$s per %2$d minuti</string>
<string name="smscommunicator_tt_set">Target %1$s per %2$d minuti impostato con successo</string>
<string name="smscommunicator_tt_canceled">Temp-Target cancellato con successo</string>
<string name="bolusdelivering">Erogazione di %1$.2fU</string>
<string name="smscommunicator_remotecommandsallowed">Consenti comandi remoti tramite SMS</string>
<string name="glucosetype_finger">Dito</string>
@ -324,10 +336,13 @@
<string name="smscommunicator_basalreplywithcode">Per avviare la basale %1$.2fU/h per %2$d min rispondi col codice %3$s</string>
<string name="smscommunicator_profilereplywithcode">Per passare al profilo %1$s %2$d%% rispondi col codice %3$s</string>
<string name="smscommunicator_extendedreplywithcode">Per avviare il bolo esteso %1$.2fU/h per %2$d min rispondi col codice %3$s</string>
<string name="smscommunicator_carbsreplywithcode">Per inserire %1$dg a %2$s rispondi col codice %3$s</string>
<string name="smscommunicator_basalpctreplywithcode">Per avviare la basale %1$d%% per %2$d min rispondi col codice %3$s</string>
<string name="smscommunicator_suspendreplywithcode">Per sospendere il loop per %1$d minuti rispondi col codice %2$s</string>
<string name="smscommunicator_tempbasalset">Basale temporanea %1$.2fU/h per %2$d min avviata con successo</string>
<string name="smscommunicator_extendedset">Bolo esteso %1$.2fU/h per %2$d min avviato con successo</string>
<string name="smscommunicator_carbsset">CHO %1$dg inseriti con successo</string>
<string name="smscommunicator_carbsfailed">Inserimento di %1$dg di CHO fallito</string>
<string name="smscommunicator_tempbasalset_percent">Basale temporanea %1$d%% per %2$d min avviata con successo</string>
<string name="smscommunicator_tempbasalfailed">Avvio basale temporanea fallito</string>
<string name="smscommunicator_extendedfailed">Avvio bolo esteso fallito</string>
@ -338,26 +353,26 @@
<string name="smscommunicator_tempbasalcancelfailed">Cancellazione basale temporanea fallita</string>
<string name="smscommunicator_extendedcancelfailed">Cancellazione bolo esteso fallita</string>
<string name="smscommunicator_unknowncommand">Comando sconosciuto o risposta errata</string>
<string name="quickwizard">QuickWizard</string>
<string name="quickwizardsettings">Impostazioni QuickWizard</string>
<string name="overview_editquickwizard_buttontext">Testo pulsante:</string>
<string name="overview_editquickwizard_carbs">Carboidrati:</string>
<string name="quickwizard">Calcolatore Rapido</string>
<string name="quickwizardsettings">Impostazioni Calcolatore Rapido</string>
<string name="overview_editquickwizard_buttontext">Testo:</string>
<string name="overview_editquickwizard_carbs">CHO:</string>
<string name="overview_editquickwizard_valid">Valido:</string>
<string name="overview_editquickwizardlistactivity_add">Aggiungi</string>
<string name="overview_quickwizard_item_edit_button">Modifica</string>
<string name="overview_quickwizard_item_remove_button">Rimuovi</string>
<string name="mealbolus">Pasto</string>
<string name="correctionbous">Corr</string>
<string name="correctionbous">Correzione</string>
<string name="actions">Azioni</string>
<string name="androidaps_start">AndroidAPS avviato</string>
<string name="ns_upload_only">NS: solo upload (sincronizzazione disabilitata)</string>
<string name="ns_upload_only">NS: solo upload (sincron. disabilitata)</string>
<string name="ns_upload_only_summary">NS: solo upload. Non ha effetto su SGV a meno che non sia selezionata una fonte locale come xDrip. Non ha effetto sui Profili durante l\'utilizzo dei profili NS.</string>
<string name="pumpNotInitialized">Micro non inizializzato!</string>
<string name="pumpNotInitializedProfileNotSet">Micro non inizializzato, profilo non impostato!</string>
<string name="primefill">Carica/Riempi</string>
<string name="fillwarning">Assicurati che la quantità corrisponda alla specifica del tuo set di infusione!</string>
<string name="othersettings_title">Altro</string>
<string name="fillbolus_title">Quantità standard di insulina per la funzione Carica/Riempi.</string>
<string name="fillbolus_title">Quantità standard di insulina per Carica/Riempi.</string>
<string name="button1">Tasto 1</string>
<string name="button2">Tasto 2</string>
<string name="button3">Tasto 3</string>
@ -370,7 +385,7 @@
<string name="prefs_range_summary">Limite alto e basso per i grafici nella sezione Panoramica e sullo Smartwatch</string>
<string name="low_mark">Limite BASSO</string>
<string name="high_mark">Limite ALTO</string>
<string name="wear">Wear</string>
<string name="wear">Smartwatch</string>
<string name="resend_all_data">Invia di nuovo tutti i dati</string>
<string name="open_settings_on_wear">Apri impostazioni sullo smartwatch</string>
<string name="pumperror">Errore micro</string>
@ -385,8 +400,8 @@
<string name="danar_enableextendedbolus">Abilita bolo esteso sul micro</string>
<string name="danar_switchtouhmode">Cambia la modalità da U/d a U/h nel micro</string>
<string name="basalvaluebelowminimum">Valore basale inferiore al minimo. Profilo non impostato!</string>
<string name="sms_actualbg">BG:</string>
<string name="sms_lastbg">Ultimo BG:</string>
<string name="sms_actualbg">Glicemia:</string>
<string name="sms_lastbg">Ultima glicemia:</string>
<string name="mdi">MDI</string>
<string name="MM640g">MM640g</string>
<string name="ongoingnotificaction">Notifica in corso</string>
@ -404,7 +419,7 @@
<string name="refresheventsfromnightscout">Ricarica eventi da NS</string>
<string name="deletefuturetreatments">Elimina trattamenti nel futuro</string>
<string name="eatingsoon">Pasto a breve</string>
<string name="hypo">Ipo</string>
<string name="hypo">Ipoglicemia</string>
<string name="activity">Attività</string>
<string name="removerecord">Rimuovi record:</string>
<string name="danar_stats">Statistiche DanaR</string>
@ -435,10 +450,10 @@
<string name="treatments_shortname">TRATT</string>
<string name="careportal_shortname">PT</string>
<string name="objectives_shortname">OBT</string>
<string name="wear_shortname">WEAR</string>
<string name="wear_shortname">SMWA</string>
<string name="smscommunicator_shortname">SMS</string>
<string name="short_tabtitles">Abbrevia i titoli delle schede</string>
<string name="always_use_shortavg">Utilizza sempre il delta medio ridotto anziché il delta semplice</string>
<string name="always_use_shortavg">Utilizza sempre il delta medio ridotto</string>
<string name="always_use_shortavg_summary">Utile quando i dati provenienti da sorgenti non filtrate come xDrip diventano \"rumorosi\" (instabili).</string>
<string name="advancedsettings_title">Impostazioni avanzate</string>
<string name="danar_model">Modello:%1$02X Protocollo:%2$02X Codice:%3$02X</string>
@ -451,7 +466,7 @@
<string name="openapsama_autosens_adjusttargets_summary">[Valore predefinito: vero]\nViene utilizzato per consentire ad autosens di regolare i target glicemici, in aggiunta a ISF e basali.</string>
<string name="openapsama_bolussnooze_dia_divisor_summary">[Valore predefinito: 2]\nBolus snooze è attivato dopo un bolo pasto per fare in modo che il loop non imposti basali temporanee basse quando hai appena mangiato. AndroidAPS non imposterà velocità basali troppo basse nel periodo corrispondente a DIA diviso il parametro bolus snooze - divisore DIA. Con DIA di 3 ore \"bolus snooze\" durerà 1.5 ore (3/2).</string>
<string name="openapsama_min_5m_carbimpact_summary">[Valore predefinito: 3.0 (AMA) o 8.0 (SMB)]. Questa è un\'impostazione per l\'impatto di assorbimento predefinito dei carboidrati in 5 minuti. L\'impostazione predefinita è una previsione di 3mg/dl/5min. Ha effetto sulla velocità di decadimento dei COB (carboidrati attivi) e su quanto il loro assorbimento incide nella previsione dellandamento glicemico, quando la glicemia sta scendendo più del previsto o non sta salendo quanto previsto.</string>
<string name="openapsama_link_to_preferncejson_doc_txt">Attenzione!\nNormalmente non dovresti modificare questi valori. FAI CLICK QUI e leggi il testo e assicuratevi di AVERLO CAPITO prima di cambiare uno di questi valori.</string>
<string name="openapsama_link_to_preferncejson_doc_txt">Attenzione!\nNormalmente non dovresti modificare questi valori. FAI CLICK QUI e leggi il testo e assicurati di AVERLO CAPITO prima di cambiare uno di questi valori.</string>
<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_field_must_not_be_empty">Il campo non deve essere vuoto</string>
@ -489,17 +504,17 @@
<string name="nsclientinternal_secret_title">API secret di NS</string>
<string name="nsclientinternal_secret_dialogtitle">API secret di NS</string>
<string name="nsclientinternal_secret_dialogmessage">Inserisci l\'API secret di NS (minimo 12 caratteri)</string>
<string name="deliver_now">Invia adesso</string>
<string name="deliver_now">Invia ora</string>
<string name="clear_queue">Cancella coda</string>
<string name="show_queue">Mostra coda</string>
<string name="queue">Coda:</string>
<string name="status">Stato:</string>
<string name="paused">In pausa</string>
<string name="clearlog">Cancella il log</string>
<string name="clearlog">Cancella log</string>
<string name="nowritepermission">NSCLIENT non ha il permesso di scrittura. API secret errato?</string>
<string name="wear_settings">Impostazioni smartwatch</string>
<string name="wear_detailedIOB_title">Mostra IOB dettagliato</string>
<string name="wear_detailedIOB_summary">Dividi IOB tra boli e IOB da basale sulla watchface</string>
<string name="wear_detailedIOB_summary">Dividi IOB in bolo e basale sulla watchface</string>
<string name="nosuccess">non riuscito - controlla il telefono</string>
<string name="notavailable">Non disponibile</string>
<string name="patientage">Età del paziente</string>
@ -541,21 +556,21 @@
<string name="fastactinginsulincomment">Novorapid, Novolog, Humalog</string>
<string name="ultrafastactinginsulincomment">Fiasp</string>
<string name="insulin_shortname">INS</string>
<string name="enablesuperbolus">Abilita superbolo nel wizard</string>
<string name="enablesuperbolus_summary">Abilita la funzionalità superbolo nel wizard. Non abilitare fino a quando non impari ciò che realmente fa. PUÒ CAUSARE SOVRADOSAGGIO DI INSULINA SE USATO IMPROPRIAMENTE!</string>
<string name="show_statuslights">Mostra \"indicatori di stato\" sulla schermata iniziale</string>
<string name="show_statuslights_extended">Mostra \"indicatori di stato\" estesi sulla schermata iniziale</string>
<string name="enablesuperbolus">Abilita superbolo nel calcolatore</string>
<string name="enablesuperbolus_summary">Abilita la funzionalità superbolo nel calcolatore. Non abilitare fino a quando non impari ciò che realmente fa. PUÒ CAUSARE SOVRADOSAGGIO DI INSULINA SE USATO IMPROPRIAMENTE!</string>
<string name="show_statuslights">Mostra indicatori di stato sulla home</string>
<string name="show_statuslights_extended">Mostra indicatori estesi sulla home</string>
<string name="show_statuslights_extended_summary">Abilita indicatori di stato estesi per \"età\" cannula, insulina, sensore, serbatoio e livello batteria sulla schermata iniziale.</string>
<string name="statuslights_res_warning">Soglia di avviso livello serbatoio [U]</string>
<string name="statuslights_res_critical">Soglia critica livello serbatoio [U]</string>
<string name="statuslights_bat_warning">Soglia livello batteria a cui prestare attenzione [%]</string>
<string name="statuslights_res_critical">Soglia livello serbatoio critico [U]</string>
<string name="statuslights_bat_warning">Soglia di avviso livello batteria [%]</string>
<string name="statuslights_bat_critical">Soglia livello batteria critico [%]</string>
<string name="iob">IOB</string>
<string name="cob">COB</string>
<string name="virtualpump_firmware_label">Firmware</string>
<string name="pump_lastconnection_label">Ultima connessione</string>
<string name="danar_bluetooth_status">Stato bluetooth</string>
<string name="nav_about">Riguardo a</string>
<string name="nav_about">Informazioni su</string>
<string name="smscommunicator_missingsmspermission">Autorizzazione SMS mancante</string>
<string name="smscommunicator_missingphonestatepermission">Autorizzazione stato telefono mancante</string>
<string name="xdripstatus_settings">Stato xDrip (smartwatch)</string>
@ -606,7 +621,7 @@
<string name="careportal_sensorage_label_short">SAGE</string>
<string name="careportal_insulinage_label_short">IAGE</string>
<string name="careportal_canulaage_label_short">CAGE</string>
<string name="careportal_pbage_label_short">PBAGE</string>
<string name="careportal_pbage_label_short">MBAGE</string>
<string name="openaps_short">OAPS</string>
<string name="uploader_short">UPLD</string>
<string name="basal_short">BAS</string>
@ -622,7 +637,7 @@
<string name="ns_localbroadcasts">Abilita le trasmissioni ad altre app (come xDrip). Non abilitare se hai installato più di un\'istanza di AAPS o NSClient!</string>
<string name="ns_localbroadcasts_title">Abilita le trasmissioni locali.</string>
<string name="careportal_activity_label">ATTIVITÀ &amp; FEEDBACK</string>
<string name="careportal_carbsandbolus_label">CARBOIDRATI &amp; BOLO</string>
<string name="careportal_carbsandbolus_label">CHO &amp; BOLO</string>
<string name="careportal_cgm_label">CGM &amp; OPENAPS</string>
<string name="careportal_pump_label">MICRO</string>
<string name="overview_newtempbasal_basalabsolute">Valore basale [U/h]</string>
@ -680,6 +695,7 @@
<string name="shortgramm">g</string>
<string name="shortminute">m</string>
<string name="shorthour">h</string>
<string name="shortday">g</string>
<string name="none"><![CDATA[<none>]]></string>
<string name="shortkilojoul">kJ</string>
<string name="shortenergy">Enr</string>
@ -693,9 +709,9 @@
<string name="pumpdrivercorrected">Driver del micro corretto</string>
<string name="pump_unreachable">Micro irraggiungibile</string>
<string name="missed_bg_readings">Letture glicemia mancanti</string>
<string name="raise_notifications_as_android_notifications">Utilizza le notifiche di sistema per avvisi e notifiche</string>
<string name="raise_notifications_as_android_notifications">Usa le notifiche di sistema per gli avvisi</string>
<string name="localalertsettings_title">Allarmi locali</string>
<string name="enable_missed_bg_readings_alert">Allarme se non si ricevono dati Glicemia</string>
<string name="enable_missed_bg_readings_alert">Allarme se non si ricevono dati glicemia</string>
<string name="enable_pump_unreachable_alert">Allarme se il micro non è raggiungibile</string>
<string name="pump_unreachable_threshold">Soglia micro irraggiungibile [min]</string>
<string name="urgent_alarm">Allarme urgente</string>
@ -708,6 +724,7 @@
<string name="bgsource_upload">Impostazioni caricamento glicemia</string>
<string name="wear_detailed_delta_title">Mostra delta dettagliato</string>
<string name="wear_detailed_delta_summary">Mostra delta con una cifra decimale in più</string>
<string name="smbmaxminutes">Max minuti SMB</string>
<string name="smbmaxminutes_summary">Max minuti di basale a cui limitare SMB</string>
<string name="unsupportedfirmware">Firmware del micro non supportato</string>
<string name="dexcomg5_xdripupload_title">Invia dati glicemia a xDrip+</string>
@ -741,7 +758,7 @@
<string name="combo_no_pump_connection">Nessuna connessione per %1$d min</string>
<string name="combo_tbr_remaining">%1$d%% (%2$d min restanti)</string>
<string name="combo_pump_state_initializing">Inizializzazione</string>
<string name="combo_pump_state_suspended_due_to_error">Sospeso a causa di errore</string>
<string name="combo_pump_state_suspended_due_to_error">Sospeso a causa di un errore</string>
<string name="combo_pump_state_suspended_by_user">Sospeso dall\'utente</string>
<string name="combo_pump_state_running">In esecuzione</string>
<string name="combo_pump_action_cancelling_tbr">Cancellazione TBR</string>
@ -775,9 +792,9 @@
<string name="ago">fa</string>
<string name="format_hours">%1$.2f h</string>
<string name="enablesmbalways">Abilita SMB sempre</string>
<string name="enablesmbalways_summary">Abilita SMB sempre, indipendentemente dai boli. Possibile solo con sorgente glicemie con un buon filtraggio dei dati, come G5</string>
<string name="enablesmbaftercarbs">Abilita SMB dopo i carboidrati</string>
<string name="enablesmbaftercarbs_summary">Abilita SMB per 6h dopo i carboidrati, anche con 0 COB. Possibile solo con sorgente glicemie con un buon filtraggio dei dati, come G5</string>
<string name="enablesmbalways_summary">Abilita SMB sempre, indipendentemente dai boli. Possibile solo con sorgente glicemia con un buon filtraggio dei dati, come G5</string>
<string name="enablesmbaftercarbs">Abilita SMB dopo i CHO</string>
<string name="enablesmbaftercarbs_summary">Abilita SMB per 6h dopo i carboidrati, anche con 0 COB. Possibile solo con sorgente glicemia con un buon filtraggio dei dati, come G5</string>
<string name="enablesmbwithcob">Abilita SMB con COB</string>
<string name="enablesmbwithcob_summary">Abilita SMB quando COB è attivo (ci sono carboidrati non assorbiti).</string>
<string name="enablesmbwithtemptarget">Abilita SMB con target temporanei</string>
@ -787,7 +804,7 @@
<string name="let_temp_basal_run">Lascia eseguire la basale temporanea</string>
<string name="mute">Muto</string>
<string name="overview_insulin_label">Insulina</string>
<string name="overview_carbs_label">Carbs</string>
<string name="overview_carbs_label">CHO</string>
<string name="overview_buttons_selection">Tasti</string>
<string name="show_calibration_button_summary">Invia una calibrazione a xDrip+ o apre la finestra di calibrazione del G5</string>
<string name="show_cgm_button_summary">Apre xDrip+, il tasto indietro torna ad AAPS</string>
@ -819,8 +836,8 @@
<string name="overview_show_activity">Attività</string>
<string name="overview_show_sensitivity">Sensibilità</string>
<string name="overview_show_deviations">Deviazioni</string>
<string name="overview_show_cob">Carboidrato attivi (COB)</string>
<string name="overview_show_iob">Insulina attiva (IOB)</string>
<string name="overview_show_cob">CHO attivi</string>
<string name="overview_show_iob">Insulina attiva</string>
<string name="overview_show_basals">Basali</string>
<string name="no_action_selected">Nessuna azione selezionata, non succederà nulla</string>
<string name="start_hypo_tt">Avvia TT Ipoglicemia</string>
@ -853,8 +870,8 @@
<string name="limitingbasalratio">Limitazione max velocità basale a %1$.2f U/h a causa di: %2$s</string>
<string name="pumplimit">limite micro</string>
<string name="itmustbepositivevalue">deve essere un valore positivo</string>
<string name="maxbasalmultiplier">moltiplicatore - max basale</string>
<string name="maxdailybasalmultiplier">moltiplicatore - max basale giornaliera</string>
<string name="maxbasalmultiplier">moltiplicatore max basale</string>
<string name="maxdailybasalmultiplier">moltiplicatore max basale giornaliera</string>
<string name="smb_frequency_exceeded">Un bolo è stato erogato negli ultimi 3 minuti, SMB ignorato</string>
<string name="basal_set_correctly">Basale impostata correttamente</string>
<string name="limitingpercentrate">Limitazione max tasso percentuale a %1$d%% a causa di: %2$s</string>
@ -869,13 +886,13 @@
<string name="readstatusfailed">Lettura stato fallita</string>
<string name="record_pump_site_change">Registra cambio posizione cannula</string>
<string name="record_insulin_cartridge_change">Registra cambio serbatoio insulina</string>
<string name="smbalwaysdisabled">Le funzioni \"SMB sempre\" e \"SMB dopo i carboidrati\" sono disabilitate perché la sorgente delle glicemie non supporta il filtraggio avanzato</string>
<string name="smbalwaysdisabled">Le funzioni \"SMB sempre\" e \"SMB dopo i CHO\" sono disabilitate perché l\'attuale sorgente delle glicemie non supporta il filtraggio avanzato</string>
<string name="smbnotallowedinopenloopmode">SMB non consentito in modalità loop aperto</string>
<string name="food_short">Cibo</string>
<string name="reset">reset</string>
<string name="waitingfortimesynchronization">In attesa della sincronizzazione dell\'ora (%1$d sec)</string>
<string name="loopdisconnectedfor">Disconnesso (%1$d m)</string>
<string name="openapssmb_maxiob_title">Max IOB totale oltre la quale OpenAPS non può andare [U]</string>
<string name="openapssmb_maxiob_title">Max IOB totale a cui limitare OpenAPS [U]</string>
<string name="openapssmb_maxiob_summary">Questo valore è chiamato Max IOB nel contesto OpenAPS\nOpenAPS non aggiungerà ulteriore insulina se IOB corrente è maggiore di questo valore</string>
<string name="pump_stopped">Micro stoppato</string>
<string name="pump_started">Micro avviato</string>
@ -883,7 +900,7 @@
<string name="absorption_cutoff_title">Max tempo assorbimento pasto [h]</string>
<string name="absorption_cutoff_summary">Tempo entro il quale ogni pasto si considera assorbito. Eventuali carboidrati rimanenti verranno tagliati fuori.</string>
<string name="time">Tempo</string>
<string name="overview_show_notes_field_in_dialogs_title">Mostra campo note nelle finestre trattamento</string>
<string name="overview_show_notes_field_in_dialogs_title">Finestre tratt.nto: mostra campo note</string>
<string name="next_button">Avanti</string>
<string name="previous_button">Indietro</string>
<string name="nav_setupwizard">Configurazione guidata</string>
@ -893,9 +910,9 @@
<string name="firstinsulinincrement">Primo incremento di insulina</string>
<string name="secondinsulinincrement">Secondo incremento di insulina</string>
<string name="thirdinsulinincrement">Terzo incremento di insulina</string>
<string name="firstcarbsincrement">Primo incremento di carboidrati</string>
<string name="secondcarbsincrement">Secondo incremento di carboidrati</string>
<string name="thirdcarbsincrement">Terzo incremento di carboidrati</string>
<string name="firstcarbsincrement">Primo incremento di CHO</string>
<string name="secondcarbsincrement">Secondo incremento di CHO</string>
<string name="thirdcarbsincrement">Terzo incremento di CHO</string>
<string name="cgm">CGM</string>
<string name="ns_wifionly">Usa solo connessione WiFi</string>
<string name="ns_wifi_ssids">WiFi SSID</string>
@ -913,9 +930,9 @@
<string name="virtualpump_definition">Definizione micro</string>
<string name="virtualpump_pump_def">Bolo: Step=%1$s\nBolo Esteso: [Step=%2$s, Durata=%3$smin-%4$sh]\nBasale: Step=%5$s\nTBR: %6$s (di %7$s), Durata=%8$smin-%9$sh\n%10$s</string>
<string name="virtualpump_pump_def_extended_note">* Sono supportati solo valori discreti, non intervalli di valori, come incrementi per basale/bolo nel micro virtuale.</string>
<string name="ns_autobackfill_title">Riempimento automatico BG</string>
<string name="wear_wizard_settings">Impostazioni Wizard</string>
<string name="wear_wizard_settings_summary">Calcoli inclusi nel risultato di Wizard:</string>
<string name="ns_autobackfill_title">Riempimento automatico glicemie</string>
<string name="wear_wizard_settings">Impostazioni Calcolatore</string>
<string name="wear_wizard_settings_summary">Calcoli inclusi nel risultato del Calcolatore:</string>
<string name="wear_display_settings">Impostazioni di visualizzazione</string>
<string name="wear_general_settings">Impostazioni generali</string>
<string name="enable_nsclient">Abilita NSClient</string>
@ -924,14 +941,14 @@
<string name="readstatus">Lettura stato</string>
<string name="adjustprofileinns">Le modifiche devono essere fatte in NS</string>
<string name="exitwizard">Salta configurazione guidata</string>
<string name="setupwizard_loop_description">Premi il pulsante in basso per permettere ad AndroidAPS di suggerire/fare modifiche alla basale</string>
<string name="setupwizard_loop_description">Premi il tasto in basso per permettere ad AndroidAPS di suggerire/fare modifiche alla basale</string>
<string name="apssetup">Configura il plugin APS</string>
<string name="sensitivitysetup">Configura il plugin di Sensibilità</string>
<string name="setupwizard_sensitivity_description">Il plugin di Sensibilità è utilizzato per il rilevamento della sensibilità all\'insulina e il calcolo di COB. Per ulteriori informazioni visita:</string>
<string name="setupwizard_sensitivity_url">https://github.com/MilosKozak/AndroidAPS/wiki/Sensitivity-detection-and-COB</string>
<string name="nsclientinfotext">NSClient gestisce la connessione a Nightscout. Puoi saltare questa parte ora, ma non sarai in grado di superare gli obiettivi fino a quando non ne porterai a termine la configurazione.</string>
<string name="diawarning">Ricorda: i nuovi profili di insulina richiedono una DIA di almeno 5h. DIA di 5 - 6h sui nuovi profili sono uguali a DIA di 3h sui vecchi profili di insulina.</string>
<string name="bgsourcesetup">Configura sorgente glicemie</string>
<string name="bgsourcesetup">Configura sorgente glicemia</string>
<string name="setupwizard_profile_description">Seleziona il tipo di profilo. Se il paziente è un bambino dovresti utilizzare il profilo di NS. Se non c\'è nessuno a seguirti su Nightscout probabilmente preferirai il profilo locale. Ricorda che stai solo selezionando la sorgente del profilo. Per utilizzarlo devi attivarlo tramite l\'esecuzione del comando \"Cambio profilo\"</string>
<string name="setupwizard_aps_description">Seleziona uno degli algoritmi disponibili. Sono ordinati dal più vecchio al più recente. L\'algoritmo più recente è solitamente più potente e più aggressivo. Pertanto, se sei un nuovo utente, probabilmente dovresti iniziare con AMA e non con l\'ultimo. Non dimenticare di leggere la documentazione di OpenAPS e di configurarlo prima dell\'uso.</string>
<string name="startobjective">Avvia il tuo primo obiettivo</string>
@ -981,12 +998,12 @@
<string name="error_adding_treatment_title">Dati trattamento incompleti</string>
<string name="maintenance_settings">Impostazioni manutenzione</string>
<string name="maintenance_email">Email</string>
<string name="maintenance_amount">Nessun log da inviare</string>
<string name="maintenance_amount">Numero di log da inviare</string>
<string name="maintenance">Manutenzione</string>
<string name="maintenance_shortname">MANUT</string>
<string name="description_maintenance">Fornisce numerose funzioni per la manutenzione (ad es. invio log, eliminazione log).</string>
<string name="send_all_logs">Invia i log via Email</string>
<string name="delete_logs">Elimina i log</string>
<string name="send_all_logs">Invia log via Email</string>
<string name="delete_logs">Elimina log</string>
<string name="error_adding_treatment_message">Un trattamento (insulina: %1$.2f, carboidrati: %2$d, a: %3$s) non può essere aggiunto ai trattamenti. Controlla e aggiungi il record necessario.</string>
<string name="generated_ecarbs_note">eCarbs: %1$d g (%2$d h), ritardo: %3$d m</string>
<string name="openaps_noasdata">Nessun dato autosens disponibile</string>
@ -995,7 +1012,7 @@
<string name="nsmalfunction">Malfunzionamento NSClient. Considera il riavvio di NS e NSClient.</string>
<string name="as">AS</string>
<string name="versionavailable">Versione %1$s disponibile</string>
<string name="time_offset">Offset temporale</string>
<string name="time_offset">Offset</string>
<string name="setupwizard_preferred_aps_mode">Modalità APS preferita</string>
<string name="treatments_wizard_total_label">Totale</string>
<string name="calculation_short">Calc</string>
@ -1061,7 +1078,7 @@
<string name="enable_tbr_over_notification">Abilita notifica di fine TBR\n(impostazione micro)</string>
<string name="disable_tbr_over_notification">Disabilita notifica di fine TBR\n(impostazione micro)</string>
<string name="refresh">Ricarica</string>
<string name="description_pump_insight_local">Integrazione micro Accu-Chek Insight</string>
<string name="description_pump_insight_local">Integrazione microinfusore Accu-Chek Insight</string>
<string name="not_inserted">Non inserito</string>
<string name="short_status_last_connected">Ultima conn: %1$d min fa</string>
<string name="short_status_tbr">TBR: %1$d%% per %2$d / %3$d min</string>
@ -1358,10 +1375,10 @@
<string name="bolusconstraintappliedwarning"><![CDATA[<font color=\'%1$s\'>Vincolo Bolo applicato: %2$.2fU a %3$.2fU</font>]]></string>
<string name="slowabsorptiondetected"><![CDATA[<font color=\'%1$s\'>!!!!! Rilevato assorbimento lento dei carboidrati: %2$d%% del tempo. Ricontrolla il tuo calcolo. COB potrebbero essere sovrastimati e potrebbe essere somministrata più insulina !!!!!</font>]]></string>
<string name="reservoirvalue">%1$.0f / %2$d U</string>
<string name="partialboluswizard">Eroga questa parte del risultato del bolus wizard [%]</string>
<string name="deliverpartofboluswizard">Bolus wizard esegue il calcolo, ma solo questa parte dell\'insulina calcolata è erogata. Utile con algoritmo SMB.</string>
<string name="partialboluswizard">Eroga parte del risultato del calcolatore [%]</string>
<string name="deliverpartofboluswizard">Il calcolatore esegue il calcolo, ma solo questa parte dell\'insulina calcolata è erogata. Utile con algoritmo SMB.</string>
<string name="loading">Caricamento ...</string>
<string name="snooze">Snooze</string>
<string name="snooze">Posticipa</string>
<string name="time_range">Intervallo di tempo</string>
<string name="timerange_value">Il tempo è compreso tra %1$s e %2$s</string>
<string name="between">Tra </string>
@ -1372,7 +1389,7 @@
<string name="format_carbs_ic">%1$.0fg IC: %2$.1f</string>
<string name="format_cob_ic">%1$.1fg IC: %2$.1f</string>
<string name="format_percent">%1$d%%</string>
<string name="boluswizard">Bolus wizard</string>
<string name="boluswizard">Calcolatore</string>
<string name="unit_minute_short">min</string>
<string name="format_carbs">%1$dg</string>
<string name="common_on">On</string>

View file

@ -1140,8 +1140,6 @@
<string name="tidepool_upload_tbr">임시 Basal 업로드</string>
<string name="tidepool_upload_profile">프로파일변경, 임시목표 업로드</string>
<string name="tidepool_upload_bg">혈당 테스트 업로드</string>
<string name="dst_in_24h_warning">24시간 이내 썸머타임 변경</string>
<string name="dst_loop_disabled_warning">썸머타임 변경이 3시간 미만입니다 - Closed Loop 비활성됨</string>
<string name="storage">내부 저장 용량 제한</string>
<string name="diskfull">내부 저장 공간을 최소 %1$d MB 이상 비우세요! Loop가 비활성화되었습니다!</string>
<string name="wrongformat">잘못된 형식</string>

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