commit
ba4d70b264
|
@ -154,6 +154,7 @@ public class MainApp extends DaggerApplication {
|
|||
@Inject TreatmentsPlugin treatmentsPlugin;
|
||||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
||||
@Inject VersionCheckerPlugin versionCheckerPlugin;
|
||||
@Inject WearPlugin wearPlugin;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
|
@ -251,7 +252,7 @@ public class MainApp extends DaggerApplication {
|
|||
if (!Config.NSCLIENT) pluginsList.add(smsCommunicatorPlugin);
|
||||
pluginsList.add(FoodPlugin.getPlugin());
|
||||
|
||||
pluginsList.add(WearPlugin.initPlugin(this));
|
||||
pluginsList.add(wearPlugin);
|
||||
pluginsList.add(statusLinePlugin);
|
||||
pluginsList.add(PersistentNotificationPlugin.getPlugin());
|
||||
pluginsList.add(NSClientPlugin.getPlugin());
|
||||
|
|
|
@ -65,6 +65,7 @@ public class MyPreferenceFragment extends PreferenceFragment implements HasAndro
|
|||
@Inject StatusLinePlugin statusLinePlugin;
|
||||
@Inject TidepoolPlugin tidepoolPlugin;
|
||||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
||||
@Inject WearPlugin wearPlugin;
|
||||
|
||||
@Override
|
||||
public void setArguments(Bundle args) {
|
||||
|
@ -144,7 +145,7 @@ public class MyPreferenceFragment extends PreferenceFragment implements HasAndro
|
|||
addPreferencesFromResource(R.xml.pref_others);
|
||||
addPreferencesFromResource(R.xml.pref_datachoices);
|
||||
|
||||
addPreferencesFromResourceIfEnabled(WearPlugin.getPlugin(), PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(wearPlugin, PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(statusLinePlugin, PluginType.GENERAL);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ object L {
|
|||
const val UI = "UI"
|
||||
const val LOCATION = "LOCATION"
|
||||
const val SMS = "SMS"
|
||||
const val WEAR = "WEAR"
|
||||
|
||||
init {
|
||||
logElements.add(LogElement(APS, defaultValue = true))
|
||||
|
@ -58,6 +59,7 @@ object L {
|
|||
logElements.add(LogElement(PUMPQUEUE, true))
|
||||
logElements.add(LogElement(SMS, true))
|
||||
logElements.add(LogElement(UI, true))
|
||||
logElements.add(LogElement(WEAR, true))
|
||||
}
|
||||
|
||||
private fun findByName(name: String): LogElement {
|
||||
|
@ -145,5 +147,6 @@ enum class LTag(val tag: String) {
|
|||
CONFIGBUILDER("CONFIGBUILDER"),
|
||||
UI("UI"),
|
||||
LOCATION("LOCATION"),
|
||||
WEAR("WEAR"),
|
||||
SMS("SMS"),
|
||||
}
|
|
@ -78,6 +78,7 @@ public class LoopPlugin extends PluginBase {
|
|||
private final ConfigBuilderPlugin configBuilderPlugin;
|
||||
private final TreatmentsPlugin treatmentsPlugin;
|
||||
private final VirtualPumpPlugin virtualPumpPlugin;
|
||||
private final ActionStringHandler actionStringHandler;
|
||||
|
||||
private CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
|
@ -111,6 +112,7 @@ public class LoopPlugin extends PluginBase {
|
|||
public Date lastOpenModeAccept;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
static public LastRun lastRun = null;
|
||||
|
||||
@Inject
|
||||
|
@ -124,7 +126,8 @@ public class LoopPlugin extends PluginBase {
|
|||
MainApp mainApp,
|
||||
ConfigBuilderPlugin configBuilderPlugin,
|
||||
TreatmentsPlugin treatmentsPlugin,
|
||||
VirtualPumpPlugin virtualPumpPlugin
|
||||
VirtualPumpPlugin virtualPumpPlugin,
|
||||
ActionStringHandler actionStringHandler
|
||||
) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.LOOP)
|
||||
|
@ -145,6 +148,7 @@ public class LoopPlugin extends PluginBase {
|
|||
this.configBuilderPlugin = configBuilderPlugin;
|
||||
this.treatmentsPlugin = treatmentsPlugin;
|
||||
this.virtualPumpPlugin = virtualPumpPlugin;
|
||||
this.actionStringHandler = actionStringHandler;
|
||||
|
||||
loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L);
|
||||
isSuperBolus = sp.getBoolean("isSuperBolus", false);
|
||||
|
@ -471,13 +475,13 @@ public class LoopPlugin extends PluginBase {
|
|||
rxBus.send(new EventNewOpenLoopNotification());
|
||||
|
||||
// Send to Wear
|
||||
ActionStringHandler.handleInitiate("changeRequest");
|
||||
actionStringHandler.handleInitiate("changeRequest");
|
||||
} else if (allowNotification) {
|
||||
// dismiss notifications
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mainApp.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(Constants.notificationID);
|
||||
ActionStringHandler.handleInitiate("cancelChangeRequest");
|
||||
actionStringHandler.handleInitiate("cancelChangeRequest");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList
|
|||
@Inject TreatmentsPlugin treatmentsPlugin;
|
||||
@Inject IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||
@Inject NotificationStore notificationStore;
|
||||
@Inject ActionStringHandler actionStringHandler;
|
||||
|
||||
private CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
|
@ -967,7 +968,7 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList
|
|||
(NotificationManager) mainApp.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(Constants.notificationID);
|
||||
|
||||
ActionStringHandler.handleInitiate("cancelChangeRequest");
|
||||
actionStringHandler.handleInitiate("cancelChangeRequest");
|
||||
}
|
||||
|
||||
private void updatePumpStatus(String status) {
|
||||
|
|
|
@ -1,758 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.Config;
|
||||
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.BgReading;
|
||||
import info.nightscout.androidaps.db.CareportalEvent;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.db.ProfileSwitch;
|
||||
import info.nightscout.androidaps.db.Source;
|
||||
import info.nightscout.androidaps.db.TDD;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
||||
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.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
import info.nightscout.androidaps.plugins.general.careportal.Dialogs.NewNSTreatmentDialog;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPump;
|
||||
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin;
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
|
||||
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.BolusWizard;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter;
|
||||
import info.nightscout.androidaps.utils.HardLimits;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.utils.SafeParse;
|
||||
import info.nightscout.androidaps.utils.ToastUtils;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
*/
|
||||
|
||||
public class ActionStringHandler {
|
||||
|
||||
public static final int TIMEOUT = 65 * 1000;
|
||||
|
||||
private static long lastSentTimestamp = 0;
|
||||
private static String lastConfirmActionString = null;
|
||||
private static BolusWizard lastBolusWizard = null;
|
||||
|
||||
public synchronized static void handleInitiate(String actionstring) {
|
||||
|
||||
if (!SP.getBoolean("wearcontrol", false)) return;
|
||||
|
||||
lastBolusWizard = null;
|
||||
|
||||
String rTitle = "CONFIRM"; //TODO: i18n
|
||||
String rMessage = "";
|
||||
String rAction = "";
|
||||
|
||||
|
||||
// do the parsing and check constraints
|
||||
String[] act = actionstring.split("\\s+");
|
||||
|
||||
if ("fillpreset".equals(act[0])) {
|
||||
///////////////////////////////////// PRIME/FILL
|
||||
double amount = 0d;
|
||||
if ("1".equals(act[1])) {
|
||||
amount = SP.getDouble("fill_button1", 0.3);
|
||||
} else if ("2".equals(act[1])) {
|
||||
amount = SP.getDouble("fill_button2", 0d);
|
||||
} else if ("3".equals(act[1])) {
|
||||
amount = SP.getDouble("fill_button3", 0d);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
Double insulinAfterConstraints = ConstraintChecker.getInstance().applyBolusConstraints(new Constraint<>(amount)).value();
|
||||
rMessage += MainApp.gs(R.string.primefill) + ": " + insulinAfterConstraints + "U";
|
||||
if (insulinAfterConstraints - amount != 0)
|
||||
rMessage += "\n" + MainApp.gs(R.string.constraintapllied);
|
||||
|
||||
rAction += "fill " + insulinAfterConstraints;
|
||||
|
||||
} else if ("fill".equals(act[0])) {
|
||||
////////////////////////////////////////////// PRIME/FILL
|
||||
double amount = SafeParse.stringToDouble(act[1]);
|
||||
|
||||
Double insulinAfterConstraints = ConstraintChecker.getInstance().applyBolusConstraints(new Constraint<>(amount)).value();
|
||||
rMessage += MainApp.gs(R.string.primefill) + ": " + insulinAfterConstraints + "U";
|
||||
if (insulinAfterConstraints - amount != 0)
|
||||
rMessage += "\n" + MainApp.gs(R.string.constraintapllied);
|
||||
|
||||
rAction += "fill " + insulinAfterConstraints;
|
||||
|
||||
} else if ("bolus".equals(act[0])) {
|
||||
////////////////////////////////////////////// BOLUS
|
||||
double insulin = SafeParse.stringToDouble(act[1]);
|
||||
int carbs = SafeParse.stringToInt(act[2]);
|
||||
Double insulinAfterConstraints = ConstraintChecker.getInstance().applyBolusConstraints(new Constraint<>(insulin)).value();
|
||||
Integer carbsAfterConstraints = ConstraintChecker.getInstance().applyCarbsConstraints(new Constraint<>(carbs)).value();
|
||||
rMessage += MainApp.gs(R.string.bolus) + ": " + insulinAfterConstraints + "U\n";
|
||||
rMessage += MainApp.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g";
|
||||
|
||||
if ((insulinAfterConstraints - insulin != 0) || (carbsAfterConstraints - carbs != 0)) {
|
||||
rMessage += "\n" + MainApp.gs(R.string.constraintapllied);
|
||||
}
|
||||
rAction += "bolus " + insulinAfterConstraints + " " + carbsAfterConstraints;
|
||||
|
||||
} else if ("temptarget".equals(act[0])) {
|
||||
///////////////////////////////////////////////////////// TEMPTARGET
|
||||
boolean isMGDL = Boolean.parseBoolean(act[1]);
|
||||
|
||||
if (ProfileFunctions.getSystemUnits().equals(Constants.MGDL) != isMGDL) {
|
||||
sendError("Different units used on watch and phone!");
|
||||
return;
|
||||
}
|
||||
|
||||
int duration = SafeParse.stringToInt(act[2]);
|
||||
if (duration == 0) {
|
||||
rMessage += "Zero-Temp-Target - cancelling running Temp-Targets?";
|
||||
rAction = "temptarget true 0 0 0";
|
||||
} else {
|
||||
double low = SafeParse.stringToDouble(act[3]);
|
||||
double high = SafeParse.stringToDouble(act[4]);
|
||||
if (!isMGDL) {
|
||||
low *= Constants.MMOLL_TO_MGDL;
|
||||
high *= Constants.MMOLL_TO_MGDL;
|
||||
}
|
||||
if (low < HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
|
||||
sendError("Min-BG out of range!");
|
||||
return;
|
||||
}
|
||||
if (high < HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
|
||||
sendError("Max-BG out of range!");
|
||||
return;
|
||||
}
|
||||
rMessage += "Temptarget:\nMin: " + act[3] + "\nMax: " + act[4] + "\nDuration: " + act[2];
|
||||
rAction = actionstring;
|
||||
|
||||
}
|
||||
|
||||
} else if ("status".equals(act[0])) {
|
||||
////////////////////////////////////////////// STATUS
|
||||
rTitle = "STATUS";
|
||||
rAction = "statusmessage";
|
||||
if ("pump".equals(act[1])) {
|
||||
rTitle += " PUMP";
|
||||
rMessage = getPumpStatus();
|
||||
} else if ("loop".equals(act[1])) {
|
||||
rTitle += " LOOP";
|
||||
rMessage = "TARGETS:\n" + getTargetsStatus();
|
||||
rMessage += "\n\n" + getLoopStatus();
|
||||
rMessage += "\n\nOAPS RESULT:\n" + getOAPSResultStatus();
|
||||
}
|
||||
|
||||
} else if ("wizard".equals(act[0])) {
|
||||
sendError("Update APP on Watch!");
|
||||
return;
|
||||
} else if ("wizard2".equals(act[0])) {
|
||||
////////////////////////////////////////////// WIZARD
|
||||
Integer carbsBeforeConstraints = SafeParse.stringToInt(act[1]);
|
||||
Integer carbsAfterConstraints = ConstraintChecker.getInstance().applyCarbsConstraints(new Constraint<>(carbsBeforeConstraints)).value();
|
||||
|
||||
if (carbsAfterConstraints - carbsBeforeConstraints != 0) {
|
||||
sendError("Carb constraint violation!");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean useBG = SP.getBoolean(R.string.key_wearwizard_bg, true);
|
||||
boolean useTT = SP.getBoolean(R.string.key_wearwizard_tt, false);
|
||||
boolean useBolusIOB = SP.getBoolean(R.string.key_wearwizard_bolusiob, true);
|
||||
boolean useBasalIOB = SP.getBoolean(R.string.key_wearwizard_basaliob, true);
|
||||
boolean useCOB = SP.getBoolean(R.string.key_wearwizard_cob, true);
|
||||
boolean useTrend = SP.getBoolean(R.string.key_wearwizard_trend, false);
|
||||
int percentage = Integer.parseInt(act[2]);
|
||||
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
String profileName = ProfileFunctions.getInstance().getProfileName();
|
||||
if (profile == null) {
|
||||
sendError("No profile found!");
|
||||
return;
|
||||
}
|
||||
|
||||
BgReading bgReading = DatabaseHelper.actualBg();
|
||||
if (bgReading == null && useBG) {
|
||||
sendError("No recent BG to base calculation on!");
|
||||
return;
|
||||
}
|
||||
|
||||
CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "Wizard wear");
|
||||
if (useCOB && (cobInfo == null || cobInfo.displayCob == null)) {
|
||||
sendError("Unknown COB! BG reading missing or recent app restart?");
|
||||
return;
|
||||
}
|
||||
|
||||
DecimalFormat format = new DecimalFormat("0.00");
|
||||
DecimalFormat formatInt = new DecimalFormat("0");
|
||||
BolusWizard bolusWizard = new BolusWizard(profile, profileName, TreatmentsPlugin.getPlugin().getTempTargetFromHistory(),
|
||||
carbsAfterConstraints, cobInfo.displayCob, bgReading.valueToUnits(ProfileFunctions.getSystemUnits()),
|
||||
0d, percentage, useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend);
|
||||
|
||||
if (Math.abs(bolusWizard.getInsulinAfterConstraints() - bolusWizard.getCalculatedTotalInsulin()) >= 0.01) {
|
||||
sendError("Insulin constraint violation!" +
|
||||
"\nCannot deliver " + format.format(bolusWizard.getCalculatedTotalInsulin()) + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bolusWizard.getCalculatedTotalInsulin() <= 0 && bolusWizard.getCarbs() <= 0) {
|
||||
rAction = "info";
|
||||
rTitle = "INFO";
|
||||
} else {
|
||||
rAction = actionstring;
|
||||
}
|
||||
rMessage += "Carbs: " + bolusWizard.getCarbs() + "g";
|
||||
rMessage += "\nBolus: " + format.format(bolusWizard.getCalculatedTotalInsulin()) + "U";
|
||||
rMessage += "\n_____________";
|
||||
rMessage += "\nCalc (IC:" + DecimalFormatter.to1Decimal(bolusWizard.getIc()) + ", " + "ISF:" + DecimalFormatter.to1Decimal(bolusWizard.getSens()) + "): ";
|
||||
rMessage += "\nFrom Carbs: " + format.format(bolusWizard.getInsulinFromCarbs()) + "U";
|
||||
if (useCOB)
|
||||
rMessage += "\nFrom" + formatInt.format(cobInfo.displayCob) + "g COB : " + format.format(bolusWizard.getInsulinFromCOB()) + "U";
|
||||
if (useBG)
|
||||
rMessage += "\nFrom BG: " + format.format(bolusWizard.getInsulinFromBG()) + "U";
|
||||
if (useBolusIOB)
|
||||
rMessage += "\nBolus IOB: " + format.format(bolusWizard.getInsulinFromBolusIOB()) + "U";
|
||||
if (useBasalIOB)
|
||||
rMessage += "\nBasal IOB: " + format.format(bolusWizard.getInsulinFromBasalsIOB()) + "U";
|
||||
if (useTrend)
|
||||
rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.getInsulinFromTrend()) + "U";
|
||||
if (percentage != 100) {
|
||||
rMessage += "\nPercentage: " + format.format(bolusWizard.getTotalBeforePercentageAdjustment()) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.getCalculatedTotalInsulin()) + "U";
|
||||
}
|
||||
|
||||
lastBolusWizard = bolusWizard;
|
||||
|
||||
} else if ("opencpp".equals(act[0])) {
|
||||
ProfileSwitch activeProfileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis());
|
||||
if (activeProfileSwitch == null) {
|
||||
sendError("No active profile switch!");
|
||||
return;
|
||||
} else {
|
||||
// read CPP values
|
||||
rTitle = "opencpp";
|
||||
rMessage = "opencpp";
|
||||
rAction = "opencpp" + " " + activeProfileSwitch.percentage + " " + activeProfileSwitch.timeshift;
|
||||
}
|
||||
|
||||
} else if ("cppset".equals(act[0])) {
|
||||
ProfileSwitch activeProfileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis());
|
||||
if (activeProfileSwitch == null) {
|
||||
sendError("No active profile switch!");
|
||||
return;
|
||||
} else {
|
||||
// read CPP values
|
||||
rMessage = "CPP:" + "\n\n" +
|
||||
"Timeshift: " + act[1] + "\n" +
|
||||
"Percentage: " + act[2] + "%";
|
||||
rAction = actionstring;
|
||||
}
|
||||
|
||||
} else if ("tddstats".equals(act[0])) {
|
||||
Object activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
|
||||
if (activePump != null) {
|
||||
// check if DB up to date
|
||||
List<TDD> dummies = new LinkedList<TDD>();
|
||||
List<TDD> historyList = getTDDList(dummies);
|
||||
|
||||
if (isOldData(historyList)) {
|
||||
rTitle = "TDD";
|
||||
rAction = "statusmessage";
|
||||
rMessage = "OLD DATA - ";
|
||||
|
||||
//if pump is not busy: try to fetch data
|
||||
final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
|
||||
if (pump.isBusy()) {
|
||||
rMessage += MainApp.gs(R.string.pumpbusy);
|
||||
} else {
|
||||
rMessage += "trying to fetch data from pump.";
|
||||
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().loadTDDs(new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<TDD> dummies = new LinkedList<TDD>();
|
||||
List<TDD> historyList = getTDDList(dummies);
|
||||
if (isOldData(historyList)) {
|
||||
sendStatusmessage("TDD", "TDD: Still old data! Cannot load from pump.\n" + generateTDDMessage(historyList, dummies));
|
||||
} else {
|
||||
sendStatusmessage("TDD", generateTDDMessage(historyList, dummies));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// if up to date: prepare, send (check if CPP is activated -> add CPP stats)
|
||||
rTitle = "TDD";
|
||||
rAction = "statusmessage";
|
||||
rMessage = generateTDDMessage(historyList, dummies);
|
||||
}
|
||||
}
|
||||
|
||||
} else if ("ecarbs".equals(act[0])) {
|
||||
////////////////////////////////////////////// ECARBS
|
||||
int carbs = SafeParse.stringToInt(act[1]);
|
||||
int starttime = SafeParse.stringToInt(act[2]);
|
||||
int duration = SafeParse.stringToInt(act[3]);
|
||||
long starttimestamp = System.currentTimeMillis() + starttime * 60 * 1000;
|
||||
Integer carbsAfterConstraints = ConstraintChecker.getInstance().applyCarbsConstraints(new Constraint<>(carbs)).value();
|
||||
rMessage += MainApp.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g";
|
||||
rMessage += "\n" + MainApp.gs(R.string.time) + ": " + DateUtil.timeString(starttimestamp);
|
||||
rMessage += "\n" + MainApp.gs(R.string.duration) + ": " + duration + "h";
|
||||
|
||||
|
||||
if ((carbsAfterConstraints - carbs != 0)) {
|
||||
rMessage += "\n" + MainApp.gs(R.string.constraintapllied);
|
||||
}
|
||||
if (carbsAfterConstraints <= 0) {
|
||||
sendError("Carbs = 0! No action taken!");
|
||||
return;
|
||||
}
|
||||
rAction += "ecarbs " + carbsAfterConstraints + " " + starttimestamp + " " + duration;
|
||||
|
||||
} else if ("changeRequest".equals(act[0])) {
|
||||
////////////////////////////////////////////// CHANGE REQUEST
|
||||
rTitle = MainApp.gs(R.string.openloop_newsuggestion);
|
||||
rAction = "changeRequest";
|
||||
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
|
||||
rMessage += finalLastRun.constraintsProcessed;
|
||||
|
||||
WearPlugin.getPlugin().requestChangeConfirmation(rTitle, rMessage, rAction);
|
||||
lastSentTimestamp = System.currentTimeMillis();
|
||||
lastConfirmActionString = rAction;
|
||||
return;
|
||||
} else if ("cancelChangeRequest".equals(act[0])) {
|
||||
////////////////////////////////////////////// CANCEL CHANGE REQUEST NOTIFICATION
|
||||
rAction = "cancelChangeRequest";
|
||||
|
||||
WearPlugin.getPlugin().requestNotificationCancel(rAction);
|
||||
return;
|
||||
} else return;
|
||||
|
||||
|
||||
// send result
|
||||
WearPlugin.getPlugin().requestActionConfirmation(rTitle, rMessage, rAction);
|
||||
lastSentTimestamp = System.currentTimeMillis();
|
||||
lastConfirmActionString = rAction;
|
||||
}
|
||||
|
||||
private static String generateTDDMessage(List<TDD> historyList, List<TDD> dummies) {
|
||||
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
|
||||
if (profile == null) {
|
||||
return "No profile loaded :(";
|
||||
}
|
||||
|
||||
if (historyList.isEmpty()) {
|
||||
return "No history data!";
|
||||
}
|
||||
|
||||
DateFormat df = new SimpleDateFormat("dd.MM.");
|
||||
String message = "";
|
||||
|
||||
double refTDD = profile.baseBasalSum() * 2;
|
||||
|
||||
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
|
||||
if (df.format(new Date(historyList.get(0).date)).equals(df.format(new Date()))) {
|
||||
double tdd = historyList.get(0).getTotal();
|
||||
historyList.remove(0);
|
||||
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n";
|
||||
message += "\n";
|
||||
} else if (pump != null && pump instanceof DanaRPlugin) {
|
||||
double tdd = DanaRPump.getInstance().dailyTotalUnits;
|
||||
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n";
|
||||
message += "\n";
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
double sum = 0d;
|
||||
double weighted03 = 0d;
|
||||
double weighted05 = 0d;
|
||||
double weighted07 = 0d;
|
||||
|
||||
Collections.reverse(historyList);
|
||||
for (TDD record : historyList) {
|
||||
double tdd = record.getTotal();
|
||||
if (i == 0) {
|
||||
weighted03 = tdd;
|
||||
weighted05 = tdd;
|
||||
weighted07 = tdd;
|
||||
|
||||
} else {
|
||||
weighted07 = (weighted07 * 0.3 + tdd * 0.7);
|
||||
weighted05 = (weighted05 * 0.5 + tdd * 0.5);
|
||||
weighted03 = (weighted03 * 0.7 + tdd * 0.3);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
message += "weighted:\n";
|
||||
message += "0.3: " + DecimalFormatter.to2Decimal(weighted03) + "U " + (DecimalFormatter.to0Decimal(100 * weighted03 / refTDD) + "%") + "\n";
|
||||
message += "0.5: " + DecimalFormatter.to2Decimal(weighted05) + "U " + (DecimalFormatter.to0Decimal(100 * weighted05 / refTDD) + "%") + "\n";
|
||||
message += "0.7: " + DecimalFormatter.to2Decimal(weighted07) + "U " + (DecimalFormatter.to0Decimal(100 * weighted07 / refTDD) + "%") + "\n";
|
||||
message += "\n";
|
||||
Collections.reverse(historyList);
|
||||
|
||||
//add TDDs:
|
||||
for (TDD record : historyList) {
|
||||
double tdd = record.getTotal();
|
||||
message += df.format(new Date(record.date)) + " " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + (dummies.contains(record) ? "x" : "") + "\n";
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
public static boolean isOldData(List<TDD> historyList) {
|
||||
Object activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
|
||||
PumpInterface dana = DanaRPlugin.getPlugin();
|
||||
PumpInterface danaRS = DanaRSPlugin.getPlugin();
|
||||
PumpInterface danaV2 = DanaRv2Plugin.getPlugin();
|
||||
PumpInterface danaKorean = DanaRKoreanPlugin.getPlugin();
|
||||
PumpInterface insight = LocalInsightPlugin.getPlugin();
|
||||
|
||||
boolean startsYesterday = activePump == dana || activePump == danaRS || activePump == danaV2 || activePump == danaKorean || activePump == insight;
|
||||
|
||||
DateFormat df = new SimpleDateFormat("dd.MM.");
|
||||
return (historyList.size() < 3 || !(df.format(new Date(historyList.get(0).date)).equals(df.format(new Date(System.currentTimeMillis() - (startsYesterday ? 1000 * 60 * 60 * 24 : 0))))));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static List<TDD> getTDDList(List<TDD> returnDummies) {
|
||||
List<TDD> historyList = MainApp.getDbHelper().getTDDs();
|
||||
|
||||
historyList = historyList.subList(0, Math.min(10, historyList.size()));
|
||||
|
||||
//fill single gaps - only needed for Dana*R data
|
||||
List<TDD> dummies = (returnDummies != null) ? returnDummies : (new LinkedList());
|
||||
DateFormat df = new SimpleDateFormat("dd.MM.");
|
||||
for (int i = 0; i < historyList.size() - 1; i++) {
|
||||
TDD elem1 = historyList.get(i);
|
||||
TDD elem2 = historyList.get(i + 1);
|
||||
|
||||
if (!df.format(new Date(elem1.date)).equals(df.format(new Date(elem2.date + 25 * 60 * 60 * 1000)))) {
|
||||
TDD dummy = new TDD();
|
||||
dummy.date = elem1.date - 24 * 60 * 60 * 1000;
|
||||
dummy.basal = elem1.basal / 2;
|
||||
dummy.bolus = elem1.bolus / 2;
|
||||
dummies.add(dummy);
|
||||
elem1.basal /= 2;
|
||||
elem1.bolus /= 2;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
historyList.addAll(dummies);
|
||||
Collections.sort(historyList, new Comparator<TDD>() {
|
||||
@Override
|
||||
public int compare(TDD lhs, TDD rhs) {
|
||||
return (int) (rhs.date - lhs.date);
|
||||
}
|
||||
});
|
||||
|
||||
return historyList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String getPumpStatus() {
|
||||
return ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(false);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String getLoopStatus() {
|
||||
String ret = "";
|
||||
// decide if enabled/disabled closed/open; what Plugin as APS?
|
||||
final LoopPlugin loopPlugin = LoopPlugin.getPlugin();
|
||||
if (loopPlugin.isEnabled(loopPlugin.getType())) {
|
||||
if (ConstraintChecker.getInstance().isClosedLoopAllowed().value()) {
|
||||
ret += "CLOSED LOOP\n";
|
||||
} else {
|
||||
ret += "OPEN LOOP\n";
|
||||
}
|
||||
final APSInterface aps = ConfigBuilderPlugin.getPlugin().getActiveAPS();
|
||||
ret += "APS: " + ((aps == null) ? "NO APS SELECTED!" : ((PluginBase) aps).getName());
|
||||
if (LoopPlugin.lastRun != null) {
|
||||
if (LoopPlugin.lastRun.lastAPSRun != null)
|
||||
ret += "\nLast Run: " + DateUtil.timeString(LoopPlugin.lastRun.lastAPSRun);
|
||||
|
||||
if (LoopPlugin.lastRun.lastEnact != null)
|
||||
ret += "\nLast Enact: " + DateUtil.timeString(LoopPlugin.lastRun.lastEnact);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
ret += "LOOP DISABLED\n";
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String getTargetsStatus() {
|
||||
String ret = "";
|
||||
if (!Config.APS) {
|
||||
return "Targets only apply in APS mode!";
|
||||
}
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
if (profile == null) {
|
||||
return "No profile set :(";
|
||||
}
|
||||
|
||||
//Check for Temp-Target:
|
||||
TempTarget tempTarget = TreatmentsPlugin.getPlugin().getTempTargetFromHistory();
|
||||
if (tempTarget != null) {
|
||||
ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.low, tempTarget.low, Constants.MGDL, ProfileFunctions.getSystemUnits());
|
||||
ret += "\nuntil: " + DateUtil.timeString(tempTarget.originalEnd());
|
||||
ret += "\n\n";
|
||||
}
|
||||
|
||||
ret += "DEFAULT RANGE: ";
|
||||
ret += Profile.fromMgdlToUnits(profile.getTargetLowMgdl(), ProfileFunctions.getSystemUnits()) + " - " + Profile.fromMgdlToUnits(profile.getTargetHighMgdl(), ProfileFunctions.getSystemUnits());
|
||||
ret += " target: " + Profile.fromMgdlToUnits(profile.getTargetMgdl(), ProfileFunctions.getSystemUnits());
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static String getOAPSResultStatus() {
|
||||
String ret = "";
|
||||
if (!Config.APS) {
|
||||
return "Only apply in APS mode!";
|
||||
}
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
if (profile == null) {
|
||||
return "No profile set :(";
|
||||
}
|
||||
|
||||
APSInterface usedAPS = ConfigBuilderPlugin.getPlugin().getActiveAPS();
|
||||
if (usedAPS == null) {
|
||||
return "No active APS :(!";
|
||||
}
|
||||
|
||||
APSResult result = usedAPS.getLastAPSResult();
|
||||
if (result == null) {
|
||||
return "Last result not available!";
|
||||
}
|
||||
|
||||
if (!result.isChangeRequested()) {
|
||||
ret += MainApp.gs(R.string.nochangerequested) + "\n";
|
||||
} else if (result.rate == 0 && result.duration == 0) {
|
||||
ret += MainApp.gs(R.string.canceltemp) + "\n";
|
||||
} else {
|
||||
ret += MainApp.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(result.rate) + " U/h " +
|
||||
"(" + DecimalFormatter.to2Decimal(result.rate / ConfigBuilderPlugin.getPlugin().getActivePump().getBaseBasalRate() * 100) + "%)\n" +
|
||||
MainApp.gs(R.string.duration) + ": " + DecimalFormatter.to0Decimal(result.duration) + " min\n";
|
||||
}
|
||||
ret += "\n" + MainApp.gs(R.string.reason) + ": " + result.reason;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public synchronized static void handleConfirmation(String actionString) {
|
||||
|
||||
if (!SP.getBoolean("wearcontrol", false)) return;
|
||||
|
||||
|
||||
//Guard from old or duplicate confirmations
|
||||
if (lastConfirmActionString == null) return;
|
||||
if (!lastConfirmActionString.equals(actionString)) return;
|
||||
if (System.currentTimeMillis() - lastSentTimestamp > TIMEOUT) return;
|
||||
lastConfirmActionString = null;
|
||||
|
||||
// do the parsing, check constraints and enact!
|
||||
String[] act = actionString.split("\\s+");
|
||||
|
||||
if ("fill".equals(act[0])) {
|
||||
Double amount = SafeParse.stringToDouble(act[1]);
|
||||
Double insulinAfterConstraints = ConstraintChecker.getInstance().applyBolusConstraints(new Constraint<>(amount)).value();
|
||||
if (amount - insulinAfterConstraints != 0) {
|
||||
ToastUtils.showToastInUiThread(MainApp.instance(), "aborting: previously applied constraint changed");
|
||||
sendError("aborting: previously applied constraint changed");
|
||||
return;
|
||||
}
|
||||
doFillBolus(amount);
|
||||
} else if ("temptarget".equals(act[0])) {
|
||||
int duration = SafeParse.stringToInt(act[2]);
|
||||
double low = SafeParse.stringToDouble(act[3]);
|
||||
double high = SafeParse.stringToDouble(act[4]);
|
||||
boolean isMGDL = Boolean.parseBoolean(act[1]);
|
||||
if (!isMGDL) {
|
||||
low *= Constants.MMOLL_TO_MGDL;
|
||||
high *= Constants.MMOLL_TO_MGDL;
|
||||
}
|
||||
generateTempTarget(duration, low, high);
|
||||
} else if ("wizard2".equals(act[0])) {
|
||||
if (lastBolusWizard != null) {
|
||||
//use last calculation as confirmed string matches
|
||||
|
||||
doBolus(lastBolusWizard.getCalculatedTotalInsulin(), lastBolusWizard.getCarbs());
|
||||
lastBolusWizard = null;
|
||||
}
|
||||
} else if ("bolus".equals(act[0])) {
|
||||
double insulin = SafeParse.stringToDouble(act[1]);
|
||||
int carbs = SafeParse.stringToInt(act[2]);
|
||||
doBolus(insulin, carbs);
|
||||
} else if ("cppset".equals(act[0])) {
|
||||
int timeshift = SafeParse.stringToInt(act[1]);
|
||||
int percentage = SafeParse.stringToInt(act[2]);
|
||||
setCPP(timeshift, percentage);
|
||||
} else if ("ecarbs".equals(act[0])) {
|
||||
int carbs = SafeParse.stringToInt(act[1]);
|
||||
long starttime = SafeParse.stringToLong(act[2]);
|
||||
int duration = SafeParse.stringToInt(act[3]);
|
||||
|
||||
doECarbs(carbs, starttime, duration);
|
||||
} else if ("dismissoverviewnotification".equals(act[0])) {
|
||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(SafeParse.stringToInt(act[1])));
|
||||
} else if ("changeRequest".equals(act[0])) {
|
||||
LoopPlugin.getPlugin().acceptChangeRequest();
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) MainApp.instance().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(Constants.notificationID);
|
||||
}
|
||||
lastBolusWizard = null;
|
||||
}
|
||||
|
||||
private static void doECarbs(int carbs, long time, int duration) {
|
||||
if (carbs > 0) {
|
||||
if (duration == 0) {
|
||||
CarbsGenerator.createCarb(carbs, time, CareportalEvent.CARBCORRECTION, "watch");
|
||||
} else {
|
||||
CarbsGenerator.generateCarbs(carbs, time, duration, "watch eCarbs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setCPP(int timeshift, int percentage) {
|
||||
|
||||
String msg = "";
|
||||
|
||||
|
||||
//check for validity
|
||||
if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
|
||||
msg += String.format(MainApp.gs(R.string.valueoutofrange), "Profile-Percentage") + "\n";
|
||||
}
|
||||
if (timeshift < 0 || timeshift > 23) {
|
||||
msg += String.format(MainApp.gs(R.string.valueoutofrange), "Profile-Timeshift") + "\n";
|
||||
}
|
||||
final Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
|
||||
if (profile == null) {
|
||||
msg += MainApp.gs(R.string.notloadedplugins) + "\n";
|
||||
}
|
||||
if (!"".equals(msg)) {
|
||||
msg += MainApp.gs(R.string.valuesnotstored);
|
||||
String rTitle = "STATUS";
|
||||
String rAction = "statusmessage";
|
||||
WearPlugin.getPlugin().requestActionConfirmation(rTitle, msg, rAction);
|
||||
lastSentTimestamp = System.currentTimeMillis();
|
||||
lastConfirmActionString = rAction;
|
||||
return;
|
||||
}
|
||||
|
||||
//send profile to pumpe
|
||||
TreatmentsPlugin.getPlugin().doProfileSwitch(0, percentage, timeshift);
|
||||
}
|
||||
|
||||
private static void generateTempTarget(int duration, double low, double high) {
|
||||
TempTarget tempTarget = new TempTarget()
|
||||
.date(System.currentTimeMillis())
|
||||
.duration(duration)
|
||||
.reason("WearPlugin")
|
||||
.source(Source.USER);
|
||||
if (tempTarget.durationInMinutes != 0) {
|
||||
tempTarget.low(low).high(high);
|
||||
} else {
|
||||
tempTarget.low(0).high(0);
|
||||
}
|
||||
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
|
||||
}
|
||||
|
||||
private static void doFillBolus(final Double amount) {
|
||||
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
|
||||
detailedBolusInfo.insulin = amount;
|
||||
detailedBolusInfo.isValid = false;
|
||||
detailedBolusInfo.source = Source.USER;
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
sendError(MainApp.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void doBolus(final Double amount, final Integer carbs) {
|
||||
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
|
||||
detailedBolusInfo.insulin = amount;
|
||||
detailedBolusInfo.carbs = carbs;
|
||||
detailedBolusInfo.source = Source.USER;
|
||||
if (detailedBolusInfo.insulin > 0 || ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().storesCarbInfo) {
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
sendError(MainApp.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized static void sendError(String errormessage) {
|
||||
WearPlugin.getPlugin().requestActionConfirmation("ERROR", errormessage, "error");
|
||||
lastSentTimestamp = System.currentTimeMillis();
|
||||
lastConfirmActionString = null;
|
||||
lastBolusWizard = null;
|
||||
}
|
||||
|
||||
private synchronized static void sendStatusmessage(String title, String message) {
|
||||
WearPlugin.getPlugin().requestActionConfirmation(title, message, "statusmessage");
|
||||
lastSentTimestamp = System.currentTimeMillis();
|
||||
lastConfirmActionString = null;
|
||||
lastBolusWizard = null;
|
||||
}
|
||||
|
||||
public synchronized static void expectNotificationAction(String message, int id) {
|
||||
String actionstring = "dismissoverviewnotification " + id;
|
||||
WearPlugin.getPlugin().requestActionConfirmation("DISMISS", message, actionstring);
|
||||
lastSentTimestamp = System.currentTimeMillis();
|
||||
lastConfirmActionString = actionstring;
|
||||
lastBolusWizard = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,619 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import dagger.Lazy
|
||||
import info.nightscout.androidaps.Config
|
||||
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.CareportalEvent
|
||||
import info.nightscout.androidaps.db.DatabaseHelper
|
||||
import info.nightscout.androidaps.db.Source
|
||||
import info.nightscout.androidaps.db.TDD
|
||||
import info.nightscout.androidaps.db.TempTarget
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPump
|
||||
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ActionStringHandler @Inject constructor(
|
||||
private val sp: SP,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val resourceHelper: ResourceHelper,
|
||||
private val constraintChecker: ConstraintChecker,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val mainApp: MainApp,
|
||||
private val loopPlugin: Lazy<LoopPlugin>,
|
||||
private val wearPlugin: WearPlugin,
|
||||
private val treatmentsPlugin: TreatmentsPlugin,
|
||||
private val configBuilderPlugin: ConfigBuilderPlugin,
|
||||
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||
private val danaRPlugin: DanaRPlugin,
|
||||
private val danaRKoreanPlugin: DanaRKoreanPlugin,
|
||||
private val danaRv2Plugin: DanaRv2Plugin,
|
||||
private val danaRSPlugin: DanaRSPlugin
|
||||
) {
|
||||
|
||||
private val TIMEOUT = 65 * 1000
|
||||
private var lastSentTimestamp: Long = 0
|
||||
private var lastConfirmActionString: String? = null
|
||||
private var lastBolusWizard: BolusWizard? = null
|
||||
@Synchronized
|
||||
fun handleInitiate(actionString: String) {
|
||||
if (!sp.getBoolean("wearcontrol", false)) return
|
||||
lastBolusWizard = null
|
||||
var rTitle = "CONFIRM" //TODO: i18n
|
||||
var rMessage = ""
|
||||
var rAction = ""
|
||||
// do the parsing and check constraints
|
||||
val act = actionString.split("\\s+").toTypedArray()
|
||||
if ("fillpreset" == act[0]) { ///////////////////////////////////// PRIME/FILL
|
||||
val amount: Double = if ("1" == act[1]) {
|
||||
sp.getDouble("fill_button1", 0.3)
|
||||
} else if ("2" == act[1]) {
|
||||
sp.getDouble("fill_button2", 0.0)
|
||||
} else if ("3" == act[1]) {
|
||||
sp.getDouble("fill_button3", 0.0)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
|
||||
rMessage += resourceHelper.gs(R.string.primefill) + ": " + insulinAfterConstraints + "U"
|
||||
if (insulinAfterConstraints - amount != 0.0) rMessage += "\n" + resourceHelper.gs(R.string.constraintapllied)
|
||||
rAction += "fill $insulinAfterConstraints"
|
||||
} else if ("fill" == act[0]) { ////////////////////////////////////////////// PRIME/FILL
|
||||
val amount = SafeParse.stringToDouble(act[1])
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
|
||||
rMessage += resourceHelper.gs(R.string.primefill) + ": " + insulinAfterConstraints + "U"
|
||||
if (insulinAfterConstraints - amount != 0.0) rMessage += "\n" + resourceHelper.gs(R.string.constraintapllied)
|
||||
rAction += "fill $insulinAfterConstraints"
|
||||
} else if ("bolus" == act[0]) { ////////////////////////////////////////////// BOLUS
|
||||
val insulin = SafeParse.stringToDouble(act[1])
|
||||
val carbs = SafeParse.stringToInt(act[2])
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
||||
rMessage += resourceHelper.gs(R.string.bolus) + ": " + insulinAfterConstraints + "U\n"
|
||||
rMessage += resourceHelper.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g"
|
||||
if (insulinAfterConstraints - insulin != 0.0 || carbsAfterConstraints - carbs != 0) {
|
||||
rMessage += "\n" + resourceHelper.gs(R.string.constraintapllied)
|
||||
}
|
||||
rAction += "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||
} else if ("temptarget" == act[0]) { ///////////////////////////////////////////////////////// TEMPTARGET
|
||||
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
||||
if (profileFunction.getUnits() == Constants.MGDL != isMGDL) {
|
||||
sendError("Different units used on watch and phone!")
|
||||
return
|
||||
}
|
||||
val duration = SafeParse.stringToInt(act[2])
|
||||
if (duration == 0) {
|
||||
rMessage += "Zero-Temp-Target - cancelling running Temp-Targets?"
|
||||
rAction = "temptarget true 0 0 0"
|
||||
} else {
|
||||
var low = SafeParse.stringToDouble(act[3])
|
||||
var high = SafeParse.stringToDouble(act[4])
|
||||
if (!isMGDL) {
|
||||
low *= Constants.MMOLL_TO_MGDL
|
||||
high *= Constants.MMOLL_TO_MGDL
|
||||
}
|
||||
if (low < HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
|
||||
sendError("Min-BG out of range!")
|
||||
return
|
||||
}
|
||||
if (high < HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
|
||||
sendError("Max-BG out of range!")
|
||||
return
|
||||
}
|
||||
rMessage += "Temptarget:\nMin: " + act[3] + "\nMax: " + act[4] + "\nDuration: " + act[2]
|
||||
rAction = actionString
|
||||
}
|
||||
} else if ("status" == act[0]) { ////////////////////////////////////////////// STATUS
|
||||
rTitle = "STATUS"
|
||||
rAction = "statusmessage"
|
||||
if ("pump" == act[1]) {
|
||||
rTitle += " PUMP"
|
||||
rMessage = pumpStatus
|
||||
} else if ("loop" == act[1]) {
|
||||
rTitle += " LOOP"
|
||||
rMessage = "TARGETS:\n$targetsStatus"
|
||||
rMessage += "\n\n" + loopStatus
|
||||
rMessage += "\n\nOAPS RESULT:\n$oAPSResultStatus"
|
||||
}
|
||||
} else if ("wizard" == act[0]) {
|
||||
sendError("Update APP on Watch!")
|
||||
return
|
||||
} else if ("wizard2" == act[0]) { ////////////////////////////////////////////// WIZARD
|
||||
val carbsBeforeConstraints = SafeParse.stringToInt(act[1])
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbsBeforeConstraints)).value()
|
||||
if (carbsAfterConstraints - carbsBeforeConstraints != 0) {
|
||||
sendError("Carb constraint violation!")
|
||||
return
|
||||
}
|
||||
val useBG = sp.getBoolean(R.string.key_wearwizard_bg, true)
|
||||
val useTT = sp.getBoolean(R.string.key_wearwizard_tt, false)
|
||||
val useBolusIOB = sp.getBoolean(R.string.key_wearwizard_bolusiob, true)
|
||||
val useBasalIOB = sp.getBoolean(R.string.key_wearwizard_basaliob, true)
|
||||
val useCOB = sp.getBoolean(R.string.key_wearwizard_cob, true)
|
||||
val useTrend = sp.getBoolean(R.string.key_wearwizard_trend, false)
|
||||
val percentage = act[2].toInt()
|
||||
val profile = profileFunction.getProfile()
|
||||
val profileName = profileFunction.getProfileName()
|
||||
if (profile == null) {
|
||||
sendError("No profile found!")
|
||||
return
|
||||
}
|
||||
val bgReading = DatabaseHelper.actualBg()
|
||||
if (bgReading == null && useBG) {
|
||||
sendError("No recent BG to base calculation on!")
|
||||
return
|
||||
}
|
||||
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard wear")
|
||||
if (useCOB && (cobInfo.displayCob == null)) {
|
||||
sendError("Unknown COB! BG reading missing or recent app restart?")
|
||||
return
|
||||
}
|
||||
val format = DecimalFormat("0.00")
|
||||
val formatInt = DecimalFormat("0")
|
||||
val bolusWizard = BolusWizard(profile, profileName, treatmentsPlugin.tempTargetFromHistory,
|
||||
carbsAfterConstraints, cobInfo.displayCob!!, bgReading!!.valueToUnits(profileFunction.getUnits()),
|
||||
0.0, percentage.toDouble(), useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend)
|
||||
if (Math.abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) {
|
||||
sendError("Insulin constraint violation!" +
|
||||
"\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!")
|
||||
return
|
||||
}
|
||||
if (bolusWizard.calculatedTotalInsulin <= 0 && bolusWizard.carbs <= 0) {
|
||||
rAction = "info"
|
||||
rTitle = "INFO"
|
||||
} else {
|
||||
rAction = actionString
|
||||
}
|
||||
rMessage += "Carbs: " + bolusWizard.carbs + "g"
|
||||
rMessage += "\nBolus: " + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
||||
rMessage += "\n_____________"
|
||||
rMessage += "\nCalc (IC:" + DecimalFormatter.to1Decimal(bolusWizard.ic) + ", " + "ISF:" + DecimalFormatter.to1Decimal(bolusWizard.sens) + "): "
|
||||
rMessage += "\nFrom Carbs: " + format.format(bolusWizard.insulinFromCarbs) + "U"
|
||||
if (useCOB) rMessage += "\nFrom" + formatInt.format(cobInfo.displayCob) + "g COB : " + format.format(bolusWizard.insulinFromCOB) + "U"
|
||||
if (useBG) rMessage += "\nFrom BG: " + format.format(bolusWizard.insulinFromBG) + "U"
|
||||
if (useBolusIOB) rMessage += "\nBolus IOB: " + format.format(bolusWizard.insulinFromBolusIOB) + "U"
|
||||
if (useBasalIOB) rMessage += "\nBasal IOB: " + format.format(bolusWizard.insulinFromBasalsIOB) + "U"
|
||||
if (useTrend) rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.insulinFromTrend) + "U"
|
||||
if (percentage != 100) {
|
||||
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
||||
}
|
||||
lastBolusWizard = bolusWizard
|
||||
} else if ("opencpp" == act[0]) {
|
||||
val activeProfileSwitch = treatmentsPlugin.getProfileSwitchFromHistory(System.currentTimeMillis())
|
||||
if (activeProfileSwitch == null) {
|
||||
sendError("No active profile switch!")
|
||||
return
|
||||
} else { // read CPP values
|
||||
rTitle = "opencpp"
|
||||
rMessage = "opencpp"
|
||||
rAction = "opencpp" + " " + activeProfileSwitch.percentage + " " + activeProfileSwitch.timeshift
|
||||
}
|
||||
} else if ("cppset" == act[0]) {
|
||||
val activeProfileSwitch = treatmentsPlugin.getProfileSwitchFromHistory(System.currentTimeMillis())
|
||||
if (activeProfileSwitch == null) {
|
||||
sendError("No active profile switch!")
|
||||
return
|
||||
} else { // read CPP values
|
||||
rMessage = "CPP:" + "\n\n" +
|
||||
"Timeshift: " + act[1] + "\n" +
|
||||
"Percentage: " + act[2] + "%"
|
||||
rAction = actionString
|
||||
}
|
||||
} else if ("tddstats" == act[0]) {
|
||||
val activePump: Any? = configBuilderPlugin.activePump
|
||||
if (activePump != null) { // check if DB up to date
|
||||
val dummies: MutableList<TDD> = LinkedList()
|
||||
val historyList = getTDDList(dummies)
|
||||
if (isOldData(historyList)) {
|
||||
rTitle = "TDD"
|
||||
rAction = "statusmessage"
|
||||
rMessage = "OLD DATA - "
|
||||
//if pump is not busy: try to fetch data
|
||||
val pump = configBuilderPlugin.activePump
|
||||
if (pump!!.isBusy) {
|
||||
rMessage += resourceHelper.gs(R.string.pumpbusy)
|
||||
} else {
|
||||
rMessage += "trying to fetch data from pump."
|
||||
configBuilderPlugin.commandQueue.loadTDDs(object : Callback() {
|
||||
override fun run() {
|
||||
val dummies1: MutableList<TDD> = LinkedList()
|
||||
val historyList1 = getTDDList(dummies1)
|
||||
if (isOldData(historyList1)) {
|
||||
sendStatusMessage("TDD: Still old data! Cannot load from pump.\n" + generateTDDMessage(historyList1, dummies1))
|
||||
} else {
|
||||
sendStatusMessage(generateTDDMessage(historyList1, dummies1))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} else { // if up to date: prepare, send (check if CPP is activated -> add CPP stats)
|
||||
rTitle = "TDD"
|
||||
rAction = "statusmessage"
|
||||
rMessage = generateTDDMessage(historyList, dummies)
|
||||
}
|
||||
}
|
||||
} else if ("ecarbs" == act[0]) { ////////////////////////////////////////////// ECARBS
|
||||
val carbs = SafeParse.stringToInt(act[1])
|
||||
val starttime = SafeParse.stringToInt(act[2])
|
||||
val duration = SafeParse.stringToInt(act[3])
|
||||
val starttimestamp = System.currentTimeMillis() + starttime * 60 * 1000
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
||||
rMessage += resourceHelper.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g"
|
||||
rMessage += "\n" + resourceHelper.gs(R.string.time) + ": " + DateUtil.timeString(starttimestamp)
|
||||
rMessage += "\n" + resourceHelper.gs(R.string.duration) + ": " + duration + "h"
|
||||
if (carbsAfterConstraints - carbs != 0) {
|
||||
rMessage += "\n" + resourceHelper.gs(R.string.constraintapllied)
|
||||
}
|
||||
if (carbsAfterConstraints <= 0) {
|
||||
sendError("Carbs = 0! No action taken!")
|
||||
return
|
||||
}
|
||||
rAction += "ecarbs $carbsAfterConstraints $starttimestamp $duration"
|
||||
} else if ("changeRequest" == act[0]) { ////////////////////////////////////////////// CHANGE REQUEST
|
||||
rTitle = resourceHelper.gs(R.string.openloop_newsuggestion)
|
||||
rAction = "changeRequest"
|
||||
val finalLastRun = LoopPlugin.lastRun
|
||||
rMessage += finalLastRun.constraintsProcessed
|
||||
wearPlugin.requestChangeConfirmation(rTitle, rMessage, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = rAction
|
||||
return
|
||||
} else if ("cancelChangeRequest" == act[0]) { ////////////////////////////////////////////// CANCEL CHANGE REQUEST NOTIFICATION
|
||||
rAction = "cancelChangeRequest"
|
||||
wearPlugin.requestNotificationCancel(rAction)
|
||||
return
|
||||
} else return
|
||||
// send result
|
||||
wearPlugin.requestActionConfirmation(rTitle, rMessage, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = rAction
|
||||
}
|
||||
|
||||
private fun generateTDDMessage(historyList: MutableList<TDD>, dummies: MutableList<TDD>): String {
|
||||
val profile = profileFunction.getProfile() ?: return "No profile loaded :("
|
||||
if (historyList.isEmpty()) {
|
||||
return "No history data!"
|
||||
}
|
||||
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
|
||||
var message = ""
|
||||
val refTDD = profile.baseBasalSum() * 2
|
||||
val pump = configBuilderPlugin.activePump
|
||||
if (df.format(Date(historyList[0].date)) == df.format(Date())) {
|
||||
val tdd = historyList[0].getTotal()
|
||||
historyList.removeAt(0)
|
||||
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n"
|
||||
message += "\n"
|
||||
} else if (pump != null && pump is DanaRPlugin) {
|
||||
val tdd = DanaRPump.getInstance().dailyTotalUnits
|
||||
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n"
|
||||
message += "\n"
|
||||
}
|
||||
var i = 0
|
||||
var weighted03 = 0.0
|
||||
var weighted05 = 0.0
|
||||
var weighted07 = 0.0
|
||||
Collections.reverse(historyList)
|
||||
for (record in historyList) {
|
||||
val tdd = record.getTotal()
|
||||
if (i == 0) {
|
||||
weighted03 = tdd
|
||||
weighted05 = tdd
|
||||
weighted07 = tdd
|
||||
} else {
|
||||
weighted07 = weighted07 * 0.3 + tdd * 0.7
|
||||
weighted05 = weighted05 * 0.5 + tdd * 0.5
|
||||
weighted03 = weighted03 * 0.7 + tdd * 0.3
|
||||
}
|
||||
i++
|
||||
}
|
||||
message += "weighted:\n"
|
||||
message += "0.3: " + DecimalFormatter.to2Decimal(weighted03) + "U " + (DecimalFormatter.to0Decimal(100 * weighted03 / refTDD) + "%") + "\n"
|
||||
message += "0.5: " + DecimalFormatter.to2Decimal(weighted05) + "U " + (DecimalFormatter.to0Decimal(100 * weighted05 / refTDD) + "%") + "\n"
|
||||
message += "0.7: " + DecimalFormatter.to2Decimal(weighted07) + "U " + (DecimalFormatter.to0Decimal(100 * weighted07 / refTDD) + "%") + "\n"
|
||||
message += "\n"
|
||||
Collections.reverse(historyList)
|
||||
//add TDDs:
|
||||
for (record in historyList) {
|
||||
val tdd = record.getTotal()
|
||||
message += df.format(Date(record.date)) + " " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + (if (dummies.contains(record)) "x" else "") + "\n"
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
private fun isOldData(historyList: List<TDD>): Boolean {
|
||||
val activePump: Any? = configBuilderPlugin.activePump
|
||||
val insight: PumpInterface = LocalInsightPlugin.getPlugin()
|
||||
val startsYesterday = activePump === danaRPlugin || activePump === danaRSPlugin || activePump === danaRv2Plugin || activePump === danaRKoreanPlugin || activePump === insight
|
||||
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
|
||||
return historyList.size < 3 || df.format(Date(historyList[0].date)) != df.format(Date(System.currentTimeMillis() - if (startsYesterday) 1000 * 60 * 60 * 24 else 0))
|
||||
}
|
||||
|
||||
private fun getTDDList(returnDummies: MutableList<TDD>): MutableList<TDD> {
|
||||
var historyList = MainApp.getDbHelper().tdDs
|
||||
historyList = historyList.subList(0, Math.min(10, historyList.size))
|
||||
//fill single gaps - only needed for Dana*R data
|
||||
val dummies: MutableList<TDD> = returnDummies
|
||||
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
|
||||
for (i in 0 until historyList.size - 1) {
|
||||
val elem1 = historyList[i]
|
||||
val elem2 = historyList[i + 1]
|
||||
if (df.format(Date(elem1!!.date)) != df.format(Date(elem2!!.date + 25 * 60 * 60 * 1000))) {
|
||||
val dummy = TDD()
|
||||
dummy.date = elem1.date - 24 * 60 * 60 * 1000
|
||||
dummy.basal = elem1.basal / 2
|
||||
dummy.bolus = elem1.bolus / 2
|
||||
dummies.add(dummy)
|
||||
elem1.basal /= 2.0
|
||||
elem1.bolus /= 2.0
|
||||
}
|
||||
}
|
||||
historyList.addAll(dummies)
|
||||
Collections.sort(historyList) { lhs, rhs -> (rhs.date - lhs.date).toInt() }
|
||||
return historyList
|
||||
}
|
||||
|
||||
private val pumpStatus: String
|
||||
get() = configBuilderPlugin.activePump?.shortStatus(false) ?: ""
|
||||
|
||||
// decide if enabled/disabled closed/open; what Plugin as APS?
|
||||
private val loopStatus: String
|
||||
get() {
|
||||
var ret = ""
|
||||
// decide if enabled/disabled closed/open; what Plugin as APS?
|
||||
if (loopPlugin.get().isEnabled(loopPlugin.get().getType())) {
|
||||
ret += if (constraintChecker.isClosedLoopAllowed().value()) {
|
||||
"CLOSED LOOP\n"
|
||||
} else {
|
||||
"OPEN LOOP\n"
|
||||
}
|
||||
val aps = configBuilderPlugin.activeAPS
|
||||
ret += "APS: " + if (aps == null) "NO APS SELECTED!" else (aps as PluginBase).name
|
||||
if (LoopPlugin.lastRun != null) {
|
||||
if (LoopPlugin.lastRun.lastAPSRun != null) ret += "\nLast Run: " + DateUtil.timeString(LoopPlugin.lastRun.lastAPSRun)
|
||||
if (LoopPlugin.lastRun.lastEnact != null) ret += "\nLast Enact: " + DateUtil.timeString(LoopPlugin.lastRun.lastEnact)
|
||||
}
|
||||
} else {
|
||||
ret += "LOOP DISABLED\n"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
//Check for Temp-Target:
|
||||
private val targetsStatus: String
|
||||
get() {
|
||||
var ret = ""
|
||||
if (!Config.APS) {
|
||||
return "Targets only apply in APS mode!"
|
||||
}
|
||||
val profile = profileFunction.getProfile() ?: return "No profile set :("
|
||||
//Check for Temp-Target:
|
||||
val tempTarget = treatmentsPlugin.tempTargetFromHistory
|
||||
if (tempTarget != null) {
|
||||
ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.low, tempTarget.low, Constants.MGDL, profileFunction.getUnits())
|
||||
ret += "\nuntil: " + DateUtil.timeString(tempTarget.originalEnd())
|
||||
ret += "\n\n"
|
||||
}
|
||||
ret += "DEFAULT RANGE: "
|
||||
ret += Profile.fromMgdlToUnits(profile.targetLowMgdl, profileFunction.getUnits()).toString() + " - " + Profile.fromMgdlToUnits(profile.targetHighMgdl, profileFunction.getUnits())
|
||||
ret += " target: " + Profile.fromMgdlToUnits(profile.targetMgdl, profileFunction.getUnits())
|
||||
return ret
|
||||
}
|
||||
|
||||
private val oAPSResultStatus: String
|
||||
get() {
|
||||
var ret = ""
|
||||
if (!Config.APS) {
|
||||
return "Only apply in APS mode!"
|
||||
}
|
||||
val usedAPS = configBuilderPlugin.activeAPS ?: return "No active APS :(!"
|
||||
val result = usedAPS.lastAPSResult ?: return "Last result not available!"
|
||||
ret += if (!result.isChangeRequested) {
|
||||
resourceHelper.gs(R.string.nochangerequested) + "\n"
|
||||
} else if (result.rate == 0.0 && result.duration == 0) {
|
||||
resourceHelper.gs(R.string.canceltemp) + "\n"
|
||||
} else {
|
||||
resourceHelper.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(result.rate) + " U/h " +
|
||||
"(" + DecimalFormatter.to2Decimal(result.rate / configBuilderPlugin.activePump!!.baseBasalRate * 100) + "%)\n" +
|
||||
resourceHelper.gs(R.string.duration) + ": " + DecimalFormatter.to0Decimal(result.duration.toDouble()) + " min\n"
|
||||
}
|
||||
ret += "\n" + resourceHelper.gs(R.string.reason) + ": " + result.reason
|
||||
return ret
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun handleConfirmation(actionString: String) {
|
||||
if (!sp.getBoolean("wearcontrol", false)) return
|
||||
//Guard from old or duplicate confirmations
|
||||
if (lastConfirmActionString == null) return
|
||||
if (lastConfirmActionString != actionString) return
|
||||
if (System.currentTimeMillis() - lastSentTimestamp > TIMEOUT) return
|
||||
lastConfirmActionString = null
|
||||
// do the parsing, check constraints and enact!
|
||||
val act = actionString.split("\\s+").toTypedArray()
|
||||
if ("fill" == act[0]) {
|
||||
val amount = SafeParse.stringToDouble(act[1])
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
|
||||
if (amount - insulinAfterConstraints != 0.0) {
|
||||
ToastUtils.showToastInUiThread(mainApp, "aborting: previously applied constraint changed")
|
||||
sendError("aborting: previously applied constraint changed")
|
||||
return
|
||||
}
|
||||
doFillBolus(amount)
|
||||
} else if ("temptarget" == act[0]) {
|
||||
val duration = SafeParse.stringToInt(act[2])
|
||||
var low = SafeParse.stringToDouble(act[3])
|
||||
var high = SafeParse.stringToDouble(act[4])
|
||||
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
||||
if (!isMGDL) {
|
||||
low *= Constants.MMOLL_TO_MGDL
|
||||
high *= Constants.MMOLL_TO_MGDL
|
||||
}
|
||||
generateTempTarget(duration, low, high)
|
||||
} else if ("wizard2" == act[0]) {
|
||||
if (lastBolusWizard != null) { //use last calculation as confirmed string matches
|
||||
doBolus(lastBolusWizard!!.calculatedTotalInsulin, lastBolusWizard!!.carbs)
|
||||
lastBolusWizard = null
|
||||
}
|
||||
} else if ("bolus" == act[0]) {
|
||||
val insulin = SafeParse.stringToDouble(act[1])
|
||||
val carbs = SafeParse.stringToInt(act[2])
|
||||
doBolus(insulin, carbs)
|
||||
} else if ("cppset" == act[0]) {
|
||||
val timeshift = SafeParse.stringToInt(act[1])
|
||||
val percentage = SafeParse.stringToInt(act[2])
|
||||
setCPP(timeshift, percentage)
|
||||
} else if ("ecarbs" == act[0]) {
|
||||
val carbs = SafeParse.stringToInt(act[1])
|
||||
val starttime = SafeParse.stringToLong(act[2])
|
||||
val duration = SafeParse.stringToInt(act[3])
|
||||
doECarbs(carbs, starttime, duration)
|
||||
} else if ("dismissoverviewnotification" == act[0]) {
|
||||
rxBus.send(EventDismissNotification(SafeParse.stringToInt(act[1])))
|
||||
} else if ("changeRequest" == act[0]) {
|
||||
loopPlugin.get().acceptChangeRequest()
|
||||
val notificationManager = mainApp.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.cancel(Constants.notificationID)
|
||||
}
|
||||
lastBolusWizard = null
|
||||
}
|
||||
|
||||
private fun doECarbs(carbs: Int, time: Long, duration: Int) {
|
||||
if (carbs > 0) {
|
||||
if (duration == 0) {
|
||||
CarbsGenerator.createCarb(carbs, time, CareportalEvent.CARBCORRECTION, "watch")
|
||||
} else {
|
||||
CarbsGenerator.generateCarbs(carbs, time, duration, "watch eCarbs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCPP(timeshift: Int, percentage: Int) {
|
||||
var msg = ""
|
||||
//check for validity
|
||||
if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
|
||||
msg += String.format(resourceHelper.gs(R.string.valueoutofrange), "Profile-Percentage") + "\n"
|
||||
}
|
||||
if (timeshift < 0 || timeshift > 23) {
|
||||
msg += String.format(resourceHelper.gs(R.string.valueoutofrange), "Profile-Timeshift") + "\n"
|
||||
}
|
||||
val profile = profileFunction.getProfile()
|
||||
if (profile == null) {
|
||||
msg += resourceHelper.gs(R.string.notloadedplugins) + "\n"
|
||||
}
|
||||
if ("" != msg) {
|
||||
msg += resourceHelper.gs(R.string.valuesnotstored)
|
||||
val rTitle = "STATUS"
|
||||
val rAction = "statusmessage"
|
||||
wearPlugin.requestActionConfirmation(rTitle, msg, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = rAction
|
||||
return
|
||||
}
|
||||
//send profile to pumpe
|
||||
treatmentsPlugin.doProfileSwitch(0, percentage, timeshift)
|
||||
}
|
||||
|
||||
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
||||
val tempTarget = TempTarget()
|
||||
.date(System.currentTimeMillis())
|
||||
.duration(duration)
|
||||
.reason("WearPlugin")
|
||||
.source(Source.USER)
|
||||
if (tempTarget.durationInMinutes != 0) {
|
||||
tempTarget.low(low).high(high)
|
||||
} else {
|
||||
tempTarget.low(0.0).high(0.0)
|
||||
}
|
||||
treatmentsPlugin.addToHistoryTempTarget(tempTarget)
|
||||
}
|
||||
|
||||
private fun doFillBolus(amount: Double) {
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
detailedBolusInfo.insulin = amount
|
||||
detailedBolusInfo.isValid = false
|
||||
detailedBolusInfo.source = Source.USER
|
||||
configBuilderPlugin.commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
sendError(resourceHelper.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun doBolus(amount: Double, carbs: Int) {
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
detailedBolusInfo.insulin = amount
|
||||
detailedBolusInfo.carbs = carbs.toDouble()
|
||||
detailedBolusInfo.source = Source.USER
|
||||
if (detailedBolusInfo.insulin > 0 || configBuilderPlugin.activePump!!.pumpDescription.storesCarbInfo) {
|
||||
configBuilderPlugin.commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
sendError(resourceHelper.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized private fun sendError(errormessage: String) {
|
||||
wearPlugin.requestActionConfirmation("ERROR", errormessage, "error")
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = null
|
||||
lastBolusWizard = null
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun sendStatusMessage(message: String) {
|
||||
wearPlugin.requestActionConfirmation("TDD", message, "statusmessage")
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = null
|
||||
lastBolusWizard = null
|
||||
} /*
|
||||
public synchronized static void expectNotificationAction(String message, int id) {
|
||||
String actionstring = "dismissoverviewnotification " + id;
|
||||
WearPlugin.getPlugin().requestActionConfirmation("DISMISS", message, actionstring);
|
||||
lastSentTimestamp = System.currentTimeMillis();
|
||||
lastConfirmActionString = actionstring;
|
||||
lastBolusWizard = null;
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
|
||||
/**
|
||||
* Created by adrian on 17/11/16.
|
||||
*/
|
||||
|
||||
public class WearFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.wear_fragment, container, false);
|
||||
|
||||
view.findViewById(R.id.wear_resend).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
WearPlugin.getPlugin().resendDataToWatch();
|
||||
}
|
||||
});
|
||||
|
||||
view.findViewById(R.id.wear_opensettings).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
WearPlugin.getPlugin().openSettings();
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import kotlinx.android.synthetic.main.wear_fragment.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class WearFragment : DaggerFragment() {
|
||||
@Inject lateinit var wearPlugin: WearPlugin
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.wear_fragment, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
wear_resend.setOnClickListener { wearPlugin.resendDataToWatch() }
|
||||
wear_opensettings.setOnClickListener { wearPlugin.openSettings() }
|
||||
}
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.events.EventBolusRequested;
|
||||
import info.nightscout.androidaps.events.EventExtendedBolusChange;
|
||||
import info.nightscout.androidaps.events.EventNewBasalProfile;
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.events.EventTempBasalChange;
|
||||
import info.nightscout.androidaps.events.EventTreatmentChange;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress;
|
||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by adrian on 17/11/16.
|
||||
*/
|
||||
|
||||
public class WearPlugin extends PluginBase {
|
||||
|
||||
private static WatchUpdaterService watchUS;
|
||||
private final Context ctx;
|
||||
|
||||
private static WearPlugin wearPlugin;
|
||||
private static String TAG = "WearPlugin";
|
||||
|
||||
private CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
@Deprecated
|
||||
public static WearPlugin getPlugin() {
|
||||
return wearPlugin;
|
||||
}
|
||||
|
||||
public static WearPlugin initPlugin(Context ctx) {
|
||||
|
||||
if (wearPlugin == null) {
|
||||
wearPlugin = new WearPlugin(ctx);
|
||||
}
|
||||
|
||||
return wearPlugin;
|
||||
}
|
||||
|
||||
WearPlugin(Context ctx) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(WearFragment.class.getName())
|
||||
.pluginName(R.string.wear)
|
||||
.shortName(R.string.wear_shortname)
|
||||
.preferencesId(R.xml.pref_wear)
|
||||
.description(R.string.description_wear)
|
||||
);
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
if (watchUS != null) {
|
||||
watchUS.setSettings();
|
||||
}
|
||||
super.onStart();
|
||||
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventOpenAPSUpdateGui.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> sendDataToWatch(true, true, false),
|
||||
FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventExtendedBolusChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> sendDataToWatch(true, true, false),
|
||||
FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventTempBasalChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> sendDataToWatch(true, true, false),
|
||||
FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventTreatmentChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> sendDataToWatch(true, true, false),
|
||||
FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventNewBasalProfile.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> sendDataToWatch(false, true, false),
|
||||
FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventAutosensCalculationFinished.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> sendDataToWatch(true, true, true),
|
||||
FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventPreferenceChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> {
|
||||
// possibly new high or low mark
|
||||
resendDataToWatch();
|
||||
// status may be formated differently
|
||||
sendDataToWatch(true, false, false);
|
||||
}, FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventRefreshOverview.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> {
|
||||
if (WatchUpdaterService.shouldReportLoopStatus(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)))
|
||||
sendDataToWatch(true, false, false);
|
||||
}, FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventBolusRequested.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> {
|
||||
String status = String.format(MainApp.gs(R.string.bolusrequested), event.getAmount());
|
||||
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
|
||||
intent.putExtra("progresspercent", 0);
|
||||
intent.putExtra("progressstatus", status);
|
||||
ctx.startService(intent);
|
||||
}, FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventDismissBolusProgressIfRunning.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> {
|
||||
if (event.getResult() == null) return;
|
||||
String status;
|
||||
if (event.getResult().success) {
|
||||
status = MainApp.gs(R.string.success);
|
||||
} else {
|
||||
status = MainApp.gs(R.string.nosuccess);
|
||||
}
|
||||
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
|
||||
intent.putExtra("progresspercent", 100);
|
||||
intent.putExtra("progressstatus", status);
|
||||
ctx.startService(intent);
|
||||
}, FabricPrivacy::logException
|
||||
));
|
||||
disposable.add(RxBus.Companion.getINSTANCE()
|
||||
.toObservable(EventOverviewBolusProgress.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> {
|
||||
if (!event.isSMB() || SP.getBoolean("wear_notifySMB", true)) {
|
||||
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
|
||||
intent.putExtra("progresspercent", event.getPercent());
|
||||
intent.putExtra("progressstatus", event.getStatus());
|
||||
ctx.startService(intent);
|
||||
}
|
||||
}, FabricPrivacy::logException
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
disposable.clear();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) {
|
||||
|
||||
//Log.d(TAG, "WR: WearPlugin:sendDataToWatch (status=" + status + ",basals=" + basals + ",bgValue=" + bgValue + ")");
|
||||
|
||||
if (isEnabled(getType())) { // only start service when this plugin is enabled
|
||||
|
||||
if (bgValue) {
|
||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class));
|
||||
}
|
||||
|
||||
if (basals) {
|
||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BASALS));
|
||||
}
|
||||
|
||||
if (status) {
|
||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_STATUS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resendDataToWatch() {
|
||||
//Log.d(TAG, "WR: WearPlugin:resendDataToWatch");
|
||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_RESEND));
|
||||
}
|
||||
|
||||
void openSettings() {
|
||||
//Log.d(TAG, "WR: WearPlugin:openSettings");
|
||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS));
|
||||
}
|
||||
|
||||
void requestNotificationCancel(String actionstring) {
|
||||
//Log.d(TAG, "WR: WearPlugin:requestNotificationCancel");
|
||||
|
||||
Intent intent = new Intent(ctx, WatchUpdaterService.class)
|
||||
.setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION);
|
||||
intent.putExtra("actionstring", actionstring);
|
||||
ctx.startService(intent);
|
||||
}
|
||||
|
||||
public void requestActionConfirmation(String title, String message, String actionstring) {
|
||||
|
||||
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_ACTIONCONFIRMATIONREQUEST);
|
||||
intent.putExtra("title", title);
|
||||
intent.putExtra("message", message);
|
||||
intent.putExtra("actionstring", actionstring);
|
||||
ctx.startService(intent);
|
||||
}
|
||||
|
||||
public void requestChangeConfirmation(String title, String message, String actionstring) {
|
||||
|
||||
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_CHANGECONFIRMATIONREQUEST);
|
||||
intent.putExtra("title", title);
|
||||
intent.putExtra("message", message);
|
||||
intent.putExtra("actionstring", actionstring);
|
||||
ctx.startService(intent);
|
||||
}
|
||||
|
||||
public static void registerWatchUpdaterService(WatchUpdaterService wus) {
|
||||
watchUS = wus;
|
||||
}
|
||||
|
||||
public static void unRegisterWatchUpdaterService() {
|
||||
watchUS = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear
|
||||
|
||||
import android.content.Intent
|
||||
import dagger.Lazy
|
||||
import info.nightscout.androidaps.MainApp
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
|
||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class WearPlugin internal @Inject constructor(
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val resourceHelper: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val mainApp: MainApp,
|
||||
private val loopPlugin: Lazy<LoopPlugin>
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(WearFragment::class.java.name)
|
||||
.pluginName(R.string.wear)
|
||||
.shortName(R.string.wear_shortname)
|
||||
.preferencesId(R.xml.pref_wear)
|
||||
.description(R.string.description_wear)
|
||||
) {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventOpenAPSUpdateGui::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ sendDataToWatch(true, true, false) }) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ sendDataToWatch(true, true, false) }) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventTempBasalChange? -> sendDataToWatch(true, true, false) }) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTreatmentChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ sendDataToWatch(true, true, false) }) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNewBasalProfile::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventNewBasalProfile? -> sendDataToWatch(false, true, false) }) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventAutosensCalculationFinished? -> sendDataToWatch(true, true, true) }) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventPreferenceChange? ->
|
||||
// possibly new high or low mark
|
||||
resendDataToWatch()
|
||||
// status may be formated differently
|
||||
sendDataToWatch(true, false, false)
|
||||
}) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventRefreshOverview::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventRefreshOverview? -> if (WatchUpdaterService.shouldReportLoopStatus(loopPlugin.get().isEnabled(PluginType.LOOP))) sendDataToWatch(true, false, false) }) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventBolusRequested::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventBolusRequested ->
|
||||
val status = String.format(resourceHelper.gs(R.string.bolusrequested), event.amount)
|
||||
val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
|
||||
intent.putExtra("progresspercent", 0)
|
||||
intent.putExtra("progressstatus", status)
|
||||
mainApp.startService(intent)
|
||||
}) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventDismissBolusProgressIfRunning::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventDismissBolusProgressIfRunning ->
|
||||
if (event.result == null) return@subscribe
|
||||
val status: String = if (event.result.success) {
|
||||
resourceHelper.gs(R.string.success)
|
||||
} else {
|
||||
resourceHelper.gs(R.string.nosuccess)
|
||||
}
|
||||
val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
|
||||
intent.putExtra("progresspercent", 100)
|
||||
intent.putExtra("progressstatus", status)
|
||||
mainApp.startService(intent)
|
||||
}) { FabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventOverviewBolusProgress::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ event: EventOverviewBolusProgress ->
|
||||
if (!event.isSMB() || sp.getBoolean("wear_notifySMB", true)) {
|
||||
val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
|
||||
intent.putExtra("progresspercent", event.percent)
|
||||
intent.putExtra("progressstatus", event.status)
|
||||
mainApp.startService(intent)
|
||||
}
|
||||
}) { FabricPrivacy.logException(it) })
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
disposable.clear()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
private fun sendDataToWatch(status: Boolean, basals: Boolean, bgValue: Boolean) {
|
||||
//Log.d(TAG, "WR: WearPlugin:sendDataToWatch (status=" + status + ",basals=" + basals + ",bgValue=" + bgValue + ")");
|
||||
if (isEnabled(getType())) {
|
||||
// only start service when this plugin is enabled
|
||||
if (bgValue) {
|
||||
mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java))
|
||||
}
|
||||
if (basals) {
|
||||
mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BASALS))
|
||||
}
|
||||
if (status) {
|
||||
mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_STATUS))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resendDataToWatch() {
|
||||
//Log.d(TAG, "WR: WearPlugin:resendDataToWatch");
|
||||
mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_RESEND))
|
||||
}
|
||||
|
||||
fun openSettings() {
|
||||
//Log.d(TAG, "WR: WearPlugin:openSettings");
|
||||
mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS))
|
||||
}
|
||||
|
||||
fun requestNotificationCancel(actionstring: String?) { //Log.d(TAG, "WR: WearPlugin:requestNotificationCancel");
|
||||
val intent = Intent(mainApp, WatchUpdaterService::class.java)
|
||||
.setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION)
|
||||
intent.putExtra("actionstring", actionstring)
|
||||
mainApp.startService(intent)
|
||||
}
|
||||
|
||||
fun requestActionConfirmation(title: String, message: String, actionString: String) {
|
||||
val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_ACTIONCONFIRMATIONREQUEST)
|
||||
intent.putExtra("title", title)
|
||||
intent.putExtra("message", message)
|
||||
intent.putExtra("actionstring", actionString)
|
||||
mainApp.startService(intent)
|
||||
}
|
||||
|
||||
fun requestChangeConfirmation(title: String, message: String, actionString: String) {
|
||||
val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_CHANGECONFIRMATIONREQUEST)
|
||||
intent.putExtra("title", title)
|
||||
intent.putExtra("message", message)
|
||||
intent.putExtra("actionstring", actionString)
|
||||
mainApp.startService(intent)
|
||||
}
|
||||
}
|
|
@ -3,13 +3,11 @@ package info.nightscout.androidaps.plugins.general.wear.wearintegration;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -26,13 +24,13 @@ import com.google.android.gms.wearable.PutDataRequest;
|
|||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.wearable.WearableListenerService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
|
@ -43,9 +41,11 @@ import info.nightscout.androidaps.db.BgReading;
|
|||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
||||
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
|
||||
|
@ -56,10 +56,21 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorP
|
|||
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.utils.ToastUtils;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
@Inject public AAPSLogger aapsLogger;
|
||||
@Inject public WearPlugin wearPlugin;
|
||||
@Inject public ResourceHelper resourceHelper;
|
||||
@Inject public SP sp;
|
||||
@Inject public ConfigBuilderPlugin configBuilderPlugin;
|
||||
@Inject public ProfileFunction profileFunction;
|
||||
@Inject public LoopPlugin loopPlugin;
|
||||
@Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||
@Inject public TreatmentsPlugin treatmentsPlugin;
|
||||
@Inject public ActionStringHandler actionStringHandler;
|
||||
|
||||
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
|
||||
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
|
||||
|
@ -87,11 +98,8 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||
|
||||
|
||||
boolean wear_integration = false;
|
||||
private static boolean lastLoopStatus;
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(WatchUpdaterService.class);
|
||||
|
||||
private Handler handler;
|
||||
|
||||
// Phone
|
||||
|
@ -100,16 +108,12 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
// Wear
|
||||
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
|
||||
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
|
||||
private String mWearNodeId = null;
|
||||
private String localnode = null;
|
||||
private String logPrefix = ""; // "WR: "
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
listenForChangeInSettings();
|
||||
setSettings();
|
||||
if (wear_integration) {
|
||||
AndroidInjection.inject(this);
|
||||
if (wearIntegration()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
if (handler == null) {
|
||||
|
@ -119,19 +123,10 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
}
|
||||
}
|
||||
|
||||
public void listenForChangeInSettings() {
|
||||
WearPlugin.registerWatchUpdaterService(this);
|
||||
private boolean wearIntegration() {
|
||||
return wearPlugin.isEnabled(PluginType.GENERAL);
|
||||
}
|
||||
|
||||
public void setSettings() {
|
||||
wear_integration = WearPlugin.getPlugin().isEnabled(PluginType.GENERAL);
|
||||
// Log.d(TAG, "WR: wear_integration=" + wear_integration);
|
||||
if (wear_integration) {
|
||||
googleApiConnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void googleApiConnect() {
|
||||
if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) {
|
||||
googleApiClient.disconnect();
|
||||
|
@ -140,7 +135,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
.addOnConnectionFailedListener(this).addApi(Wearable.API).build();
|
||||
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||
if (googleApiClient.isConnected()) {
|
||||
log.debug(logPrefix + "API client is connected");
|
||||
aapsLogger.debug(LTag.WEAR, "API client is connected");
|
||||
} else {
|
||||
// Log.d("WatchUpdater", logPrefix + "API client is not connected and is trying to connect");
|
||||
googleApiClient.connect();
|
||||
|
@ -153,7 +148,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
// Log.d(TAG, logPrefix + "onStartCommand: " + action);
|
||||
|
||||
if (wear_integration) {
|
||||
if (wearIntegration()) {
|
||||
handler.post(() -> {
|
||||
if (googleApiClient.isConnected()) {
|
||||
if (ACTION_RESEND.equals(action)) {
|
||||
|
@ -193,9 +188,9 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
|
||||
private void updateWearSyncBgsCapability(CapabilityInfo capabilityInfo) {
|
||||
Log.d("WatchUpdaterService", logPrefix + "CabilityInfo: " + capabilityInfo);
|
||||
Log.d("WatchUpdaterService", "CabilityInfo: " + capabilityInfo);
|
||||
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||
mWearNodeId = pickBestNodeId(connectedNodes);
|
||||
String mWearNodeId = pickBestNodeId(connectedNodes);
|
||||
}
|
||||
|
||||
|
||||
|
@ -240,7 +235,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
String id = peer.getId();
|
||||
String name = peer.getDisplayName();
|
||||
// Log.d(TAG, logPrefix + "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
}
|
||||
|
||||
|
||||
|
@ -249,7 +243,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
// Log.d(TAG, logPrefix + "onMessageRecieved: " + event);
|
||||
|
||||
if (wear_integration) {
|
||||
if (wearIntegration()) {
|
||||
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
||||
resendData();
|
||||
}
|
||||
|
@ -260,20 +254,20 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
if (event != null && event.getPath().equals(WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
|
||||
String actionstring = new String(event.getData());
|
||||
log.debug("Wear: " + actionstring);
|
||||
ActionStringHandler.handleInitiate(actionstring);
|
||||
aapsLogger.debug(LTag.WEAR, "Wear: " + actionstring);
|
||||
actionStringHandler.handleInitiate(actionstring);
|
||||
}
|
||||
|
||||
if (event != null && event.getPath().equals(WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
|
||||
String actionstring = new String(event.getData());
|
||||
log.debug("Wear Confirm: " + actionstring);
|
||||
ActionStringHandler.handleConfirmation(actionstring);
|
||||
aapsLogger.debug(LTag.WEAR, "Wear Confirm: " + actionstring);
|
||||
actionStringHandler.handleConfirmation(actionstring);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelBolus() {
|
||||
ConfigBuilderPlugin.getPlugin().getActivePump().stopBolusDelivering();
|
||||
configBuilderPlugin.getActivePump().stopBolusDelivering();
|
||||
}
|
||||
|
||||
private void sendData() {
|
||||
|
@ -286,11 +280,11 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
if (wear_integration) {
|
||||
if (wearIntegration()) {
|
||||
|
||||
final DataMap dataMap = dataMapSingleBG(lastBG, glucoseStatus);
|
||||
if (dataMap == null) {
|
||||
ToastUtils.showToastInUiThread(this, MainApp.gs(R.string.noprofile));
|
||||
ToastUtils.showToastInUiThread(this, resourceHelper.gs(R.string.noprofile));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -356,7 +350,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
deltastring += "-";
|
||||
}
|
||||
|
||||
boolean detailed = SP.getBoolean("wear_detailed_delta", false);
|
||||
boolean detailed = sp.getBoolean(R.string.key_wear_detailed_delta, false);
|
||||
if (units.equals(Constants.MGDL)) {
|
||||
if (detailed) {
|
||||
deltastring += DecimalFormatter.to1Decimal(Math.abs(deltaMGDL));
|
||||
|
@ -407,7 +401,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
if (!graph_bgs.isEmpty()) {
|
||||
DataMap entries = dataMapSingleBG(last_bg, glucoseStatus);
|
||||
if (entries == null) {
|
||||
ToastUtils.showToastInUiThread(this, MainApp.gs(R.string.noprofile));
|
||||
ToastUtils.showToastInUiThread(this, resourceHelper.gs(R.string.noprofile));
|
||||
return;
|
||||
}
|
||||
final ArrayList<DataMap> dataMaps = new ArrayList<>(graph_bgs.size());
|
||||
|
@ -440,7 +434,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
ArrayList<DataMap> predictions = new ArrayList<>();
|
||||
|
||||
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
Profile profile = profileFunction.getProfile();
|
||||
|
||||
if (profile == null) {
|
||||
return;
|
||||
|
@ -452,8 +446,8 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
double beginBasalValue = profile.getBasal(beginBasalSegmentTime);
|
||||
double endBasalValue = beginBasalValue;
|
||||
|
||||
TemporaryBasal tb1 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(runningTime);
|
||||
TemporaryBasal tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(runningTime);
|
||||
TemporaryBasal tb1 = treatmentsPlugin.getTempBasalFromHistory(runningTime);
|
||||
TemporaryBasal tb2 = treatmentsPlugin.getTempBasalFromHistory(runningTime);
|
||||
double tb_before = beginBasalValue;
|
||||
double tb_amount = beginBasalValue;
|
||||
long tb_start = runningTime;
|
||||
|
@ -469,7 +463,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
|
||||
for (; runningTime < now; runningTime += 5 * 60 * 1000) {
|
||||
Profile profileTB = ProfileFunctions.getInstance().getProfile(runningTime);
|
||||
Profile profileTB = profileFunction.getProfile(runningTime);
|
||||
if (profileTB == null)
|
||||
return;
|
||||
//basal rate
|
||||
|
@ -484,7 +478,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
}
|
||||
|
||||
//temps
|
||||
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(runningTime);
|
||||
tb2 = treatmentsPlugin.getTempBasalFromHistory(runningTime);
|
||||
|
||||
if (tb1 == null && tb2 == null) {
|
||||
//no temp stays no temp
|
||||
|
@ -517,13 +511,13 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
|
||||
}
|
||||
if (tb1 != null) {
|
||||
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(now); //use "now" to express current situation
|
||||
tb2 = treatmentsPlugin.getTempBasalFromHistory(now); //use "now" to express current situation
|
||||
if (tb2 == null) {
|
||||
//express the cancelled temp by painting it down one minute early
|
||||
temps.add(tempDatamap(tb_start, tb_before, now - 1 * 60 * 1000, endBasalValue, tb_amount));
|
||||
} else {
|
||||
//express currently running temp by painting it a bit into the future
|
||||
Profile profileNow = ProfileFunctions.getInstance().getProfile(now);
|
||||
Profile profileNow = profileFunction.getProfile(now);
|
||||
double currentAmount = tb2.tempBasalConvertedToAbsolute(now, profileNow);
|
||||
if (currentAmount != tb_amount) {
|
||||
temps.add(tempDatamap(tb_start, tb_before, now, tb_amount, tb_amount));
|
||||
|
@ -536,13 +530,13 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(now); //use "now" to express current situation
|
||||
if (tb2 != null) {
|
||||
//onset at the end
|
||||
Profile profileTB = ProfileFunctions.getInstance().getProfile(runningTime);
|
||||
Profile profileTB = profileFunction.getProfile(runningTime);
|
||||
double currentAmount = tb2.tempBasalConvertedToAbsolute(runningTime, profileTB);
|
||||
temps.add(tempDatamap(now - 1 * 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
|
||||
}
|
||||
}
|
||||
|
||||
List<Treatment> treatments = TreatmentsPlugin.getPlugin().getTreatmentsFromHistory();
|
||||
List<Treatment> treatments = treatmentsPlugin.getTreatmentsFromHistory();
|
||||
for (Treatment treatment : treatments) {
|
||||
if (treatment.date > startTimeWindow) {
|
||||
boluses.add(treatmentMap(treatment.date, treatment.insulin, treatment.carbs, treatment.isSMB, treatment.isValid));
|
||||
|
@ -550,8 +544,8 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
}
|
||||
|
||||
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
|
||||
if (SP.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.request.hasPredictions && finalLastRun.constraintsProcessed != null) {
|
||||
final LoopPlugin.LastRun finalLastRun = loopPlugin.lastRun;
|
||||
if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.request.hasPredictions && finalLastRun.constraintsProcessed != null) {
|
||||
List<BgReading> predArray = finalLastRun.constraintsProcessed.getPredictions();
|
||||
|
||||
if (!predArray.isEmpty()) {
|
||||
|
@ -649,7 +643,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
dataMapRequest.getDataMap().putString("message", message);
|
||||
dataMapRequest.getDataMap().putString("actionstring", actionstring);
|
||||
|
||||
log.debug("Requesting confirmation from wear: " + actionstring);
|
||||
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: " + actionstring);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendActionConfirmationRequest", putDataRequest);
|
||||
|
@ -669,7 +663,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
dataMapRequest.getDataMap().putString("message", message);
|
||||
dataMapRequest.getDataMap().putString("actionstring", actionstring);
|
||||
|
||||
log.debug("Requesting confirmation from wear: " + actionstring);
|
||||
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: " + actionstring);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendChangeConfirmationRequest", putDataRequest);
|
||||
|
@ -687,7 +681,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
dataMapRequest.getDataMap().putString("cancelNotificationRequest", "cancelNotificationRequest");
|
||||
dataMapRequest.getDataMap().putString("actionstring", actionstring);
|
||||
|
||||
log.debug("Canceling notification on wear: " + actionstring);
|
||||
aapsLogger.debug(LTag.WEAR, "Canceling notification on wear: " + actionstring);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendCancelNotificationRequest", putDataRequest);
|
||||
|
@ -700,26 +694,25 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
private void sendStatus() {
|
||||
|
||||
if (googleApiClient.isConnected()) {
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
String status = MainApp.gs(R.string.noprofile);
|
||||
Profile profile = profileFunction.getProfile();
|
||||
String status = resourceHelper.gs(R.string.noprofile);
|
||||
String iobSum, iobDetail, cobString, currentBasal, bgiString;
|
||||
iobSum = iobDetail = cobString = currentBasal = bgiString = "";
|
||||
if (profile != null) {
|
||||
TreatmentsInterface treatmentsInterface = TreatmentsPlugin.getPlugin();
|
||||
treatmentsInterface.updateTotalIOBTreatments();
|
||||
IobTotal bolusIob = treatmentsInterface.getLastCalculationTreatments().round();
|
||||
treatmentsInterface.updateTotalIOBTempBasals();
|
||||
IobTotal basalIob = treatmentsInterface.getLastCalculationTempBasals().round();
|
||||
treatmentsPlugin.updateTotalIOBTreatments();
|
||||
IobTotal bolusIob = treatmentsPlugin.getLastCalculationTreatments().round();
|
||||
treatmentsPlugin.updateTotalIOBTempBasals();
|
||||
IobTotal basalIob = treatmentsPlugin.getLastCalculationTempBasals().round();
|
||||
|
||||
iobSum = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob);
|
||||
iobDetail = "(" + DecimalFormatter.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.to2Decimal(basalIob.basaliob) + ")";
|
||||
cobString = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "WatcherUpdaterService").generateCOBString();
|
||||
currentBasal = generateBasalString(treatmentsInterface);
|
||||
cobString = iobCobCalculatorPlugin.getCobInfo(false, "WatcherUpdaterService").generateCOBString();
|
||||
currentBasal = generateBasalString();
|
||||
|
||||
//bgi
|
||||
|
||||
|
||||
double bgi = -(bolusIob.activity + basalIob.activity) * 5 * Profile.fromMgdlToUnits(profile.getIsfMgdl(), ProfileFunctions.getSystemUnits());
|
||||
double bgi = -(bolusIob.activity + basalIob.activity) * 5 * Profile.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits());
|
||||
bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.to1Decimal(bgi);
|
||||
|
||||
status = generateStatusString(profile, currentBasal, iobSum, iobDetail, bgiString);
|
||||
|
@ -731,11 +724,11 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
String rigBattery = NSDeviceStatus.getInstance().getUploaderStatus().trim();
|
||||
|
||||
|
||||
long openApsStatus = -1;
|
||||
long openApsStatus;
|
||||
//OpenAPS status
|
||||
if (Config.APS) {
|
||||
//we are AndroidAPS
|
||||
openApsStatus = LoopPlugin.lastRun != null && LoopPlugin.lastRun.lastEnact != null && LoopPlugin.lastRun.lastEnact.getTime() != 0 ? LoopPlugin.lastRun.lastEnact.getTime() : -1;
|
||||
openApsStatus = loopPlugin.lastRun != null && loopPlugin.lastRun.lastEnact != null && loopPlugin.lastRun.lastEnact.getTime() != 0 ? loopPlugin.lastRun.lastEnact.getTime() : -1;
|
||||
} else {
|
||||
//NSClient or remote
|
||||
openApsStatus = NSDeviceStatus.getOpenApsTimestamp();
|
||||
|
@ -746,14 +739,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
dataMapRequest.getDataMap().putString("externalStatusString", status);
|
||||
dataMapRequest.getDataMap().putString("iobSum", iobSum);
|
||||
dataMapRequest.getDataMap().putString("iobDetail", iobDetail);
|
||||
dataMapRequest.getDataMap().putBoolean("detailedIob", SP.getBoolean(R.string.key_wear_detailediob, false));
|
||||
dataMapRequest.getDataMap().putBoolean("detailedIob", sp.getBoolean(R.string.key_wear_detailediob, false));
|
||||
dataMapRequest.getDataMap().putString("cob", cobString);
|
||||
dataMapRequest.getDataMap().putString("currentBasal", currentBasal);
|
||||
dataMapRequest.getDataMap().putString("battery", "" + phoneBattery);
|
||||
dataMapRequest.getDataMap().putString("rigBattery", rigBattery);
|
||||
dataMapRequest.getDataMap().putLong("openApsStatus", openApsStatus);
|
||||
dataMapRequest.getDataMap().putString("bgi", bgiString);
|
||||
dataMapRequest.getDataMap().putBoolean("showBgi", SP.getBoolean(R.string.key_wear_showbgi, false));
|
||||
dataMapRequest.getDataMap().putBoolean("showBgi", sp.getBoolean(R.string.key_wear_showbgi, false));
|
||||
dataMapRequest.getDataMap().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendStatus", putDataRequest);
|
||||
|
@ -766,7 +759,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
private void sendPreferences() {
|
||||
if (googleApiClient.isConnected()) {
|
||||
|
||||
boolean wearcontrol = SP.getBoolean("wearcontrol", false);
|
||||
boolean wearcontrol = sp.getBoolean("wearcontrol", false);
|
||||
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH);
|
||||
//unique content
|
||||
|
@ -785,7 +778,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
// Log.d(TAG, "WR: " + source + " " + data);
|
||||
}
|
||||
|
||||
|
||||
private void executeTask(AsyncTask task, DataMap... parameters) {
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[]) parameters);
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
|
@ -802,21 +794,19 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
String status = "";
|
||||
|
||||
if (profile == null) {
|
||||
status = MainApp.gs(R.string.noprofile);
|
||||
status = resourceHelper.gs(R.string.noprofile);
|
||||
return status;
|
||||
}
|
||||
|
||||
LoopPlugin activeloop = LoopPlugin.getPlugin();
|
||||
|
||||
if (!activeloop.isEnabled(PluginType.LOOP)) {
|
||||
status += MainApp.gs(R.string.disabledloop) + "\n";
|
||||
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
status += resourceHelper.gs(R.string.disabledloop) + "\n";
|
||||
lastLoopStatus = false;
|
||||
} else {
|
||||
lastLoopStatus = true;
|
||||
}
|
||||
|
||||
String iobString = "";
|
||||
if (SP.getBoolean(R.string.key_wear_detailediob, false)) {
|
||||
String iobString;
|
||||
if (sp.getBoolean(R.string.key_wear_detailediob, false)) {
|
||||
iobString = iobSum + " " + iobDetail;
|
||||
} else {
|
||||
iobString = iobSum + "U";
|
||||
|
@ -825,7 +815,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
status += currentBasal + " " + iobString;
|
||||
|
||||
//add BGI if shown, otherwise return
|
||||
if (SP.getBoolean(R.string.key_wear_showbgi, false)) {
|
||||
if (sp.getBoolean(R.string.key_wear_showbgi, false)) {
|
||||
status += " " + bgiString;
|
||||
}
|
||||
|
||||
|
@ -833,19 +823,19 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
}
|
||||
|
||||
@NonNull
|
||||
private String generateBasalString(TreatmentsInterface treatmentsInterface) {
|
||||
private String generateBasalString() {
|
||||
|
||||
String basalStringResult;
|
||||
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
Profile profile = profileFunction.getProfile();
|
||||
if (profile == null)
|
||||
return "";
|
||||
|
||||
TemporaryBasal activeTemp = treatmentsInterface.getTempBasalFromHistory(System.currentTimeMillis());
|
||||
TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis());
|
||||
if (activeTemp != null) {
|
||||
basalStringResult = activeTemp.toStringShort();
|
||||
} else {
|
||||
if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false)) {
|
||||
if (sp.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false)) {
|
||||
basalStringResult = "100%";
|
||||
} else {
|
||||
basalStringResult = DecimalFormatter.to2Decimal(profile.getBasal()) + "U/h";
|
||||
|
@ -859,7 +849,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
googleApiClient.disconnect();
|
||||
}
|
||||
WearPlugin.unRegisterWatchUpdaterService();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -867,7 +856,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
|
||||
}
|
||||
|
||||
public static boolean shouldReportLoopStatus(boolean enabled) {
|
||||
|
|
|
@ -1689,5 +1689,6 @@
|
|||
<string name="clearqueueconfirm">Clear queue? All data in queue will be lost!</string>
|
||||
<string name="key_xdripstatus_detailediob" translatable="false">xdripstatus_detailediob</string>
|
||||
<string name="key_xdripstatus_showbgi" translatable="false">xdripstatus_showbgi</string>
|
||||
<string name="key_wear_detailed_delta" translatable="false">wear_detailed_delta</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="wear_detailed_delta"
|
||||
android:key="@string/key_wear_detailed_delta"
|
||||
android:summary="@string/wear_detailed_delta_summary"
|
||||
android:title="@string/wear_detailed_delta_title" />
|
||||
|
||||
|
|
Loading…
Reference in a new issue