actionStringHandler, // TODO Adrian use RxBus instead of Lazy
- IobCobCalculatorPlugin iobCobCalculatorPlugin,
- ReceiverStatusStore receiverStatusStore,
- FabricPrivacy fabricPrivacy,
- NSUpload nsUpload,
- HardLimits hardLimits
- ) {
- super(new PluginDescription()
- .mainType(PluginType.LOOP)
- .fragmentClass(LoopFragment.class.getName())
- .pluginIcon(R.drawable.ic_loop_closed_white)
- .pluginName(R.string.loop)
- .shortName(R.string.loop_shortname)
- .preferencesId(R.xml.pref_loop)
- .enableByDefault(config.getAPS())
- .description(R.string.description_loop),
- aapsLogger, resourceHelper, injector
- );
- this.injector = injector;
- this.aapsSchedulers = aapsSchedulers;
- this.sp = sp;
- this.rxBus = rxBus;
- this.constraintChecker = constraintChecker;
- this.resourceHelper = resourceHelper;
- this.profileFunction = profileFunction;
- this.context = context;
- this.activePlugin = activePlugin;
- this.commandQueue = commandQueue;
- this.treatmentsPlugin = treatmentsPlugin;
- this.virtualPumpPlugin = virtualPumpPlugin;
- this.actionStringHandler = actionStringHandler;
- this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
- this.receiverStatusStore = receiverStatusStore;
- this.fabricPrivacy = fabricPrivacy;
- this.nsUpload = nsUpload;
- this.hardLimits = hardLimits;
-
- loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L);
- isSuperBolus = sp.getBoolean("isSuperBolus", false);
- isDisconnected = sp.getBoolean("isDisconnected", false);
- }
-
- @Override
- protected void onStart() {
- createNotificationChannel();
- super.onStart();
- disposable.add(rxBus
- .toObservable(EventTempTargetChange.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> invoke("EventTempTargetChange", true), fabricPrivacy::logException)
- );
- /*
- This method is triggered once autosens calculation has completed, so the LoopPlugin
- has current data to work with. However, autosens calculation can be triggered by multiple
- sources and currently only a new BG should trigger a loop run. Hence we return early if
- the event causing the calculation is not EventNewBg.
-
- */
- disposable.add(rxBus
- .toObservable(EventAutosensCalculationFinished.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> {
- // Autosens calculation not triggered by a new BG
- if (!(event.getCause() instanceof EventNewBG)) return;
-
- GlucoseValue glucoseValue = iobCobCalculatorPlugin.actualBg();
- // BG outdated
- if (glucoseValue == null) return;
- // already looped with that value
- if (glucoseValue.getTimestamp() <= lastBgTriggeredRun) return;
-
- lastBgTriggeredRun = glucoseValue.getTimestamp();
- invoke("AutosenseCalculation for " + glucoseValue, true);
- }, fabricPrivacy::logException)
- );
- }
-
- private void createNotificationChannel() {
- NotificationManager mNotificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- @SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
- CHANNEL_ID,
- NotificationManager.IMPORTANCE_HIGH);
- mNotificationManager.createNotificationChannel(channel);
- }
-
- @Override
- protected void onStop() {
- disposable.clear();
- super.onStop();
- }
-
- @Override
- public boolean specialEnableCondition() {
- try {
- PumpInterface pump = activePlugin.getActivePump();
- return pump.getPumpDescription().isTempBasalCapable;
- } catch (Exception ignored) {
- // may fail during initialization
- return true;
- }
- }
-
- public void suspendTo(long endTime) {
- loopSuspendedTill = endTime;
- isSuperBolus = false;
- isDisconnected = false;
- sp.putLong("loopSuspendedTill", loopSuspendedTill);
- sp.putBoolean("isSuperBolus", isSuperBolus);
- sp.putBoolean("isDisconnected", isDisconnected);
- }
-
- public void superBolusTo(long endTime) {
- loopSuspendedTill = endTime;
- isSuperBolus = true;
- isDisconnected = false;
- sp.putLong("loopSuspendedTill", loopSuspendedTill);
- sp.putBoolean("isSuperBolus", isSuperBolus);
- sp.putBoolean("isDisconnected", isDisconnected);
- }
-
- private void disconnectTo(long endTime) {
- loopSuspendedTill = endTime;
- isSuperBolus = false;
- isDisconnected = true;
- sp.putLong("loopSuspendedTill", loopSuspendedTill);
- sp.putBoolean("isSuperBolus", isSuperBolus);
- sp.putBoolean("isDisconnected", isDisconnected);
- }
-
- public int minutesToEndOfSuspend() {
- if (loopSuspendedTill == 0)
- return 0;
-
- long now = System.currentTimeMillis();
- long msecDiff = loopSuspendedTill - now;
-
- if (loopSuspendedTill <= now) { // time exceeded
- suspendTo(0L);
- return 0;
- }
-
- return (int) (msecDiff / 60d / 1000d);
- }
-
- public boolean isSuspended() {
- if (loopSuspendedTill == 0)
- return false;
-
- long now = System.currentTimeMillis();
-
- if (loopSuspendedTill <= now) { // time exceeded
- suspendTo(0L);
- return false;
- }
-
- return true;
- }
-
- public boolean isLGS() {
- Constraint closedLoopEnabled = constraintChecker.isClosedLoopAllowed();
- Double MaxIOBallowed = constraintChecker.getMaxIOBAllowed().value();
- String APSmode = sp.getString(R.string.key_aps_mode, "open");
- PumpInterface pump = activePlugin.getActivePump();
- boolean isLGS = false;
-
- if (!isSuspended() && !pump.isSuspended())
- if (closedLoopEnabled.value())
- if ((MaxIOBallowed.equals(hardLimits.getMAXIOB_LGS())) || (APSmode.equals("lgs")))
- isLGS = true;
-
- return isLGS;
- }
-
- public boolean isSuperBolus() {
- if (loopSuspendedTill == 0)
- return false;
-
- long now = System.currentTimeMillis();
-
- if (loopSuspendedTill <= now) { // time exceeded
- suspendTo(0L);
- return false;
- }
-
- return isSuperBolus;
- }
-
- public boolean isDisconnected() {
- if (loopSuspendedTill == 0)
- return false;
-
- long now = System.currentTimeMillis();
-
- if (loopSuspendedTill <= now) { // time exceeded
- suspendTo(0L);
- return false;
- }
- return isDisconnected;
- }
-
- public boolean treatmentTimethreshold(int duartionMinutes) {
- long threshold = System.currentTimeMillis() + (duartionMinutes * 60 * 1000);
- boolean bool = false;
- if (treatmentsPlugin.getLastBolusTime() > threshold || treatmentsPlugin.getLastCarbTime() > threshold)
- bool = true;
-
- return bool;
- }
-
- public synchronized void invoke(String initiator, boolean allowNotification) {
- invoke(initiator, allowNotification, false);
- }
-
- public synchronized void invoke(String initiator, boolean allowNotification, boolean tempBasalFallback) {
- try {
- getAapsLogger().debug(LTag.APS, "invoke from " + initiator);
- Constraint loopEnabled = constraintChecker.isLoopInvocationAllowed();
-
- if (!loopEnabled.value()) {
- String message = resourceHelper.gs(R.string.loopdisabled) + "\n" + loopEnabled.getReasons(getAapsLogger());
- getAapsLogger().debug(LTag.APS, message);
- rxBus.send(new EventLoopSetLastRunGui(message));
- return;
- }
- final PumpInterface pump = activePlugin.getActivePump();
- APSResult result = null;
-
- if (!isEnabled(PluginType.LOOP))
- return;
-
- Profile profile = profileFunction.getProfile();
-
- if (profile == null || !profileFunction.isProfileValid("Loop")) {
- getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
- rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)));
- return;
- }
-
- // Check if pump info is loaded
- if (pump.getBaseBasalRate() < 0.01d) return;
-
- APSInterface usedAPS = activePlugin.getActiveAPS();
- if (((PluginBase) usedAPS).isEnabled(PluginType.APS)) {
- usedAPS.invoke(initiator, tempBasalFallback);
- result = usedAPS.getLastAPSResult();
- }
-
- // Check if we have any result
- if (result == null) {
- rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)));
- return;
- }
-
- // Prepare for pumps using % basals
- if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
- result.setUsePercent(true);
- }
- result.setPercent((int) (result.getRate() / profile.getBasal() * 100));
-
- // check rate for constraints
- final APSResult resultAfterConstraints = result.newAndClone(injector);
- resultAfterConstraints.setRateConstraint(new Constraint<>(resultAfterConstraints.getRate()));
- resultAfterConstraints.setRate(constraintChecker.applyBasalConstraints(resultAfterConstraints.getRateConstraint(), profile).value());
-
- resultAfterConstraints.setPercentConstraint(new Constraint<>(resultAfterConstraints.getPercent()));
- resultAfterConstraints.setPercent(constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.getPercentConstraint(), profile).value());
-
- resultAfterConstraints.setSmbConstraint(new Constraint<>(resultAfterConstraints.getSmb()));
- resultAfterConstraints.setSmb(constraintChecker.applyBolusConstraints(resultAfterConstraints.getSmbConstraint()).value());
-
- // safety check for multiple SMBs
- long lastBolusTime = treatmentsPlugin.getLastBolusTime();
- if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
- getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
- resultAfterConstraints.setSmb(0);
- }
-
- if (lastRun != null && lastRun.getConstraintsProcessed() != null) {
- prevCarbsreq = lastRun.getConstraintsProcessed().getCarbsReq();
- }
-
- if (lastRun == null) lastRun = new LastRun();
- lastRun.setRequest(result);
- lastRun.setConstraintsProcessed(resultAfterConstraints);
- lastRun.setLastAPSRun(DateUtil.now());
- lastRun.setSource(((PluginBase) usedAPS).getName());
- lastRun.setTbrSetByPump(null);
- lastRun.setSmbSetByPump(null);
- lastRun.setLastTBREnact(0);
- lastRun.setLastTBRRequest(0);
- lastRun.setLastSMBEnact(0);
- lastRun.setLastSMBRequest(0);
-
- nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump(), receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
-
- if (isSuspended()) {
- getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended));
- rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)));
- return;
- }
-
- if (pump.isSuspended()) {
- getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended));
- rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended)));
- return;
- }
-
- Constraint closedLoopEnabled = constraintChecker.isClosedLoopAllowed();
-
- if (closedLoopEnabled.value()) {
- if (allowNotification) {
- if (resultAfterConstraints.isCarbsRequired()
- && resultAfterConstraints.getCarbsReq() >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0)
- && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) {
-
- if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
- Notification carbreqlocal = new Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.getCarbsRequiredText(), Notification.NORMAL);
- rxBus.send(new EventNewNotification(carbreqlocal));
- }
- if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) {
- nsUpload.uploadError(resultAfterConstraints.getCarbsRequiredText());
- }
- if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
- Intent intentAction5m = new Intent(context, CarbSuggestionReceiver.class);
- intentAction5m.putExtra("ignoreDuration", 5);
- PendingIntent pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT);
- NotificationCompat.Action actionIgnore5m = new
- NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m);
-
- Intent intentAction15m = new Intent(context, CarbSuggestionReceiver.class);
- intentAction15m.putExtra("ignoreDuration", 15);
- PendingIntent pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT);
- NotificationCompat.Action actionIgnore15m = new
- NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m);
-
- Intent intentAction30m = new Intent(context, CarbSuggestionReceiver.class);
- intentAction30m.putExtra("ignoreDuration", 30);
- PendingIntent pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT);
- NotificationCompat.Action actionIgnore30m = new
- NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m);
-
- NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
- builder.setSmallIcon(R.drawable.notif_icon)
- .setContentTitle(resourceHelper.gs(R.string.carbssuggestion))
- .setContentText(resultAfterConstraints.getCarbsRequiredText())
- .setAutoCancel(true)
- .setPriority(Notification.IMPORTANCE_HIGH)
- .setCategory(Notification.CATEGORY_ALARM)
- .addAction(actionIgnore5m)
- .addAction(actionIgnore15m)
- .addAction(actionIgnore30m)
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
-
- NotificationManager mNotificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
- // mId allows you to update the notification later on.
- mNotificationManager.notify(Constants.notificationID, builder.build());
- rxBus.send(new EventNewOpenLoopNotification());
-
- //only send to wear if Native notifications are turned off
- if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
- // Send to Wear
- actionStringHandler.get().handleInitiate("changeRequest");
- }
- }
-
- } else {
- //If carbs were required previously, but are no longer needed, dismiss notifications
- if (prevCarbsreq > 0) {
- dismissSuggestion();
- rxBus.send(new EventDismissNotification(Notification.CARBS_REQUIRED));
- }
- }
- }
-
- if (resultAfterConstraints.isChangeRequested()
- && !commandQueue.bolusInQueue()
- && !commandQueue.isRunning(Command.CommandType.BOLUS)) {
- final PumpEnactResult waiting = new PumpEnactResult(getInjector());
- waiting.queued = true;
- if (resultAfterConstraints.getTempBasalRequested())
- lastRun.setTbrSetByPump(waiting);
- if (resultAfterConstraints.getBolusRequested())
- lastRun.setSmbSetByPump(waiting);
- rxBus.send(new EventLoopUpdateGui());
- fabricPrivacy.logCustom("APSRequest");
- applyTBRRequest(resultAfterConstraints, profile, new Callback() {
- @Override
- public void run() {
- if (result.enacted || result.success) {
- lastRun.setTbrSetByPump(result);
- lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
- lastRun.setLastTBREnact(DateUtil.now());
- rxBus.send(new EventLoopUpdateGui());
- applySMBRequest(resultAfterConstraints, new Callback() {
- @Override
- public void run() {
- // Callback is only called if a bolus was actually requested
- if (result.enacted || result.success) {
- lastRun.setSmbSetByPump(result);
- lastRun.setLastSMBRequest(lastRun.getLastAPSRun());
- lastRun.setLastSMBEnact(DateUtil.now());
- } else {
- new Thread(() -> {
- SystemClock.sleep(1000);
- invoke("tempBasalFallback", allowNotification, true);
- }).start();
- }
- rxBus.send(new EventLoopUpdateGui());
- }
- });
- } else {
- lastRun.setTbrSetByPump(result);
- lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
- }
- rxBus.send(new EventLoopUpdateGui());
- }
- });
- } else {
- lastRun.setTbrSetByPump(null);
- lastRun.setSmbSetByPump(null);
- }
- } else {
- if (resultAfterConstraints.isChangeRequested() && allowNotification) {
- NotificationCompat.Builder builder =
- new NotificationCompat.Builder(context, CHANNEL_ID);
- builder.setSmallIcon(R.drawable.notif_icon)
- .setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion))
- .setContentText(resultAfterConstraints.toString())
- .setAutoCancel(true)
- .setPriority(Notification.IMPORTANCE_HIGH)
- .setCategory(Notification.CATEGORY_ALARM)
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
- if (sp.getBoolean("wearcontrol", false)) {
- builder.setLocalOnly(true);
- }
- presentSuggestion(builder);
- } else if (allowNotification) {
- dismissSuggestion();
- }
- }
-
- rxBus.send(new EventLoopUpdateGui());
- } finally {
- getAapsLogger().debug(LTag.APS, "invoke end");
- }
- }
-
- public void disableCarbSuggestions(int durationMinutes) {
- carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + (durationMinutes * 60 * 1000);
- dismissSuggestion();
- }
-
- private void presentSuggestion(NotificationCompat.Builder builder) {
- // Creates an explicit intent for an Activity in your app
- Intent resultIntent = new Intent(context, MainActivity.class);
-
- // The stack builder object will contain an artificial back stack for the
- // started Activity.
- // This ensures that navigating backward from the Activity leads out of
- // your application to the Home screen.
- TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
- stackBuilder.addParentStack(MainActivity.class);
- // Adds the Intent that starts the Activity to the top of the stack
- stackBuilder.addNextIntent(resultIntent);
- PendingIntent resultPendingIntent =
- stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
- builder.setContentIntent(resultPendingIntent);
- builder.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
- NotificationManager mNotificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- // mId allows you to update the notification later on.
- mNotificationManager.notify(Constants.notificationID, builder.build());
- rxBus.send(new EventNewOpenLoopNotification());
-
- // Send to Wear
- actionStringHandler.get().handleInitiate("changeRequest");
- }
-
- private void dismissSuggestion() {
- // dismiss notifications
- NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(Constants.notificationID);
- actionStringHandler.get().handleInitiate("cancelChangeRequest");
- }
-
- public void acceptChangeRequest() {
- Profile profile = profileFunction.getProfile();
- final LoopPlugin lp = this;
- applyTBRRequest(lastRun.getConstraintsProcessed(), profile, new Callback() {
- @Override
- public void run() {
- if (result.enacted) {
- lastRun.setTbrSetByPump(result);
- lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
- lastRun.setLastTBREnact(DateUtil.now());
- lastRun.setLastOpenModeAccept(DateUtil.now());
- nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump(), receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
- sp.incInt(R.string.key_ObjectivesmanualEnacts);
- }
- rxBus.send(new EventAcceptOpenLoopChange());
- }
- });
- fabricPrivacy.logCustom("AcceptTemp");
- }
-
- /**
- * expect absolute request and allow both absolute and percent response based on pump capabilities
- * TODO: update pump drivers to support APS request in %
- */
-
- private void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
-
- if (!request.getTempBasalRequested()) {
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested))).run();
- }
- return;
- }
-
- PumpInterface pump = activePlugin.getActivePump();
-
- if (!pump.isInitialized()) {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpNotInitialized));
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
- }
- return;
- }
-
- if (pump.isSuspended()) {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpsuspended));
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
- }
- return;
- }
-
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + request.toString());
-
- long now = System.currentTimeMillis();
- TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(now);
- if (request.getUsePercent() && allowPercentage()) {
- if (request.getPercent() == 100 && request.getDuration() == 0) {
- if (activeTemp != null) {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
- commandQueue.cancelTempBasal(false, callback);
- } else {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent()).duration(0)
- .enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
- }
- }
- } else if (activeTemp != null
- && activeTemp.getPlannedRemainingMinutes() > 5
- && request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
- && request.getPercent() == activeTemp.percentRate) {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent())
- .enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
- .comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
- }
- } else {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: tempBasalPercent()");
- commandQueue.tempBasalPercent(request.getPercent(), request.getDuration(), false, profile, callback);
- }
- } else {
- if ((request.getRate() == 0 && request.getDuration() == 0) || Math.abs(request.getRate() - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
- if (activeTemp != null) {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
- commandQueue.cancelTempBasal(false, callback);
- } else {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).absolute(request.getRate()).duration(0)
- .enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
- }
- }
- } else if (activeTemp != null
- && activeTemp.getPlannedRemainingMinutes() > 5
- && request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
- && Math.abs(request.getRate() - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
- .enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
- .comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
- }
- } else {
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()");
- commandQueue.tempBasalAbsolute(request.getRate(), request.getDuration(), false, profile, callback);
- }
- }
- }
-
- private void applySMBRequest(APSResult request, Callback callback) {
- if (!request.getBolusRequested()) {
- return;
- }
-
- PumpInterface pump = activePlugin.getActivePump();
-
- long lastBolusTime = treatmentsPlugin.getLastBolusTime();
- if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
- getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector())
- .comment(resourceHelper.gs(R.string.smb_frequency_exceeded))
- .enacted(false).success(false)).run();
- }
- return;
- }
-
- if (!pump.isInitialized()) {
- getAapsLogger().debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpNotInitialized));
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
- }
- return;
- }
-
- if (pump.isSuspended()) {
- getAapsLogger().debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpsuspended));
- if (callback != null) {
- callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
- }
- return;
- }
-
- getAapsLogger().debug(LTag.APS, "applySMBRequest: " + request.toString());
-
- // deliver SMB
- DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
- detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.getLastBolusTime();
- detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
- detailedBolusInfo.insulin = request.getSmb();
- detailedBolusInfo.isSMB = true;
- detailedBolusInfo.source = Source.USER;
- detailedBolusInfo.deliverAt = request.getDeliverAt();
- getAapsLogger().debug(LTag.APS, "applyAPSRequest: bolus()");
- commandQueue.bolus(detailedBolusInfo, callback);
- }
-
- private boolean allowPercentage() {
- return virtualPumpPlugin.isEnabled(PluginType.PUMP);
- }
-
- public void disconnectPump(int durationInMinutes, Profile profile) {
- PumpInterface pump = activePlugin.getActivePump();
-
- disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L);
-
- if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
- commandQueue.tempBasalAbsolute(0, durationInMinutes, true, profile, new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(context, ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(i);
- }
- }
- });
- } else {
- commandQueue.tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(context, ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(i);
- }
- }
- });
- }
-
- if (pump.getPumpDescription().isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBoluslInProgress()) {
- commandQueue.cancelExtended(new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(context, ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(i);
- }
- }
- });
- }
- createOfflineEvent(durationInMinutes);
- }
-
- public void suspendLoop(int durationInMinutes) {
- suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000);
- commandQueue.cancelTempBasal(true, new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(context, ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(i);
- }
- }
- });
- createOfflineEvent(durationInMinutes);
- }
-
- public void createOfflineEvent(int durationInMinutes) {
- JSONObject data = new JSONObject();
- try {
- data.put("eventType", CareportalEvent.OPENAPSOFFLINE);
- data.put("duration", durationInMinutes);
- } catch (JSONException e) {
- getAapsLogger().error("Unhandled exception", e);
- }
- CareportalEvent event = new CareportalEvent(getInjector());
- event.date = DateUtil.now();
- event.source = Source.USER;
- event.eventType = CareportalEvent.OPENAPSOFFLINE;
- event.json = data.toString();
- MainApp.getDbHelper().createOrUpdate(event);
- nsUpload.uploadOpenAPSOffline(event);
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt
new file mode 100644
index 0000000000..74ca108a37
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt
@@ -0,0 +1,674 @@
+package info.nightscout.androidaps.plugins.aps.loop
+
+import android.annotation.SuppressLint
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.TaskStackBuilder
+import android.content.Context
+import android.content.Intent
+import android.os.SystemClock
+import androidx.core.app.NotificationCompat
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.*
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.data.DetailedBolusInfo
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.data.PumpEnactResult
+import info.nightscout.androidaps.db.CareportalEvent
+import info.nightscout.androidaps.db.Source
+import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
+import info.nightscout.androidaps.events.EventNewBG
+import info.nightscout.androidaps.events.EventTempTargetChange
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.interfaces.LoopInterface.LastRun
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui
+import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
+import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
+import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
+import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
+import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
+import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.queue.commands.Command
+import info.nightscout.androidaps.receivers.ReceiverStatusStore
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.HardLimits
+import info.nightscout.androidaps.utils.T
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.rx.AapsSchedulers
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import io.reactivex.disposables.CompositeDisposable
+import org.json.JSONException
+import org.json.JSONObject
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.math.abs
+
+@Singleton
+open class LoopPlugin @Inject constructor(
+ injector: HasAndroidInjector,
+ aapsLogger: AAPSLogger?,
+ private val aapsSchedulers: AapsSchedulers,
+ private val rxBus: RxBusWrapper,
+ private val sp: SP,
+ config: Config,
+ private val constraintChecker: ConstraintChecker,
+ resourceHelper: ResourceHelper,
+ private val profileFunction: ProfileFunction,
+ private val context: Context,
+ private val commandQueue: CommandQueueProvider,
+ private val activePlugin: ActivePluginProvider,
+ private val treatmentsPlugin: TreatmentsPlugin,
+ private val virtualPumpPlugin: VirtualPumpPlugin,
+ private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
+ private val receiverStatusStore: ReceiverStatusStore,
+ private val fabricPrivacy: FabricPrivacy,
+ private val nsUpload: NSUpload,
+ private val hardLimits: HardLimits
+) : PluginBase(PluginDescription()
+ .mainType(PluginType.LOOP)
+ .fragmentClass(LoopFragment::class.java.name)
+ .pluginIcon(R.drawable.ic_loop_closed_white)
+ .pluginName(R.string.loop)
+ .shortName(R.string.loop_shortname)
+ .preferencesId(R.xml.pref_loop)
+ .enableByDefault(config.APS)
+ .description(R.string.description_loop),
+ aapsLogger!!, resourceHelper, injector
+), LoopInterface {
+
+ private val disposable = CompositeDisposable()
+ private var lastBgTriggeredRun: Long = 0
+ private var carbsSuggestionsSuspendedUntil: Long = 0
+ private var prevCarbsreq = 0
+ override var lastRun: LastRun? = null
+ override fun onStart() {
+ createNotificationChannel()
+ super.onStart()
+ disposable.add(rxBus
+ .toObservable(EventTempTargetChange::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ invoke("EventTempTargetChange", true) }, fabricPrivacy::logException)
+ )
+ /*
+ This method is triggered once autosens calculation has completed, so the LoopPlugin
+ has current data to work with. However, autosens calculation can be triggered by multiple
+ sources and currently only a new BG should trigger a loop run. Hence we return early if
+ the event causing the calculation is not EventNewBg.
+
+ */
+ disposable.add(rxBus
+ .toObservable(EventAutosensCalculationFinished::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event: EventAutosensCalculationFinished ->
+ // Autosens calculation not triggered by a new BG
+ if (event.cause !is EventNewBG) return@subscribe
+ val glucoseValue = iobCobCalculatorPlugin.actualBg() ?: return@subscribe
+ // BG outdated
+ // already looped with that value
+ if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe
+ lastBgTriggeredRun = glucoseValue.timestamp
+ invoke("AutosenseCalculation for $glucoseValue", true)
+ }, fabricPrivacy::logException)
+ )
+ }
+
+ private fun createNotificationChannel() {
+ val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ @SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID,
+ CHANNEL_ID,
+ NotificationManager.IMPORTANCE_HIGH)
+ mNotificationManager.createNotificationChannel(channel)
+ }
+
+ override fun onStop() {
+ disposable.clear()
+ super.onStop()
+ }
+
+ override fun specialEnableCondition(): Boolean {
+ return try {
+ val pump = activePlugin.activePump
+ pump.pumpDescription.isTempBasalCapable
+ } catch (ignored: Exception) {
+ // may fail during initialization
+ true
+ }
+ }
+
+ fun suspendTo(endTime: Long) {
+ sp.putLong("loopSuspendedTill", endTime)
+ sp.putBoolean("isSuperBolus", false)
+ sp.putBoolean("isDisconnected", false)
+ }
+
+ fun superBolusTo(endTime: Long) {
+ sp.putLong("loopSuspendedTill", endTime)
+ sp.putBoolean("isSuperBolus", true)
+ sp.putBoolean("isDisconnected", false)
+ }
+
+ private fun disconnectTo(endTime: Long) {
+ sp.putLong("loopSuspendedTill", endTime)
+ sp.putBoolean("isSuperBolus", false)
+ sp.putBoolean("isDisconnected", true)
+ }
+
+ fun minutesToEndOfSuspend(): Int {
+ val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
+ if (loopSuspendedTill == 0L) return 0
+ val now = System.currentTimeMillis()
+ val millisDiff = loopSuspendedTill - now
+ if (loopSuspendedTill <= now) { // time exceeded
+ suspendTo(0L)
+ return 0
+ }
+ return (millisDiff / 60.0 / 1000.0).toInt()
+ }
+
+ // time exceeded
+ val isSuspended: Boolean
+ get() {
+ val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
+ if (loopSuspendedTill == 0L) return false
+ val now = System.currentTimeMillis()
+ if (loopSuspendedTill <= now) { // time exceeded
+ suspendTo(0L)
+ return false
+ }
+ return true
+ }
+ val isLGS: Boolean
+ get() {
+ val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
+ val maxIobAllowed = constraintChecker.getMaxIOBAllowed().value()
+ val apsMode = sp.getString(R.string.key_aps_mode, "open")
+ val pump = activePlugin.activePump
+ var isLGS = false
+ if (!isSuspended && !pump.isSuspended()) if (closedLoopEnabled.value()) if (maxIobAllowed == hardLimits.MAXIOB_LGS || apsMode == "lgs") isLGS = true
+ return isLGS
+ }
+
+ // time exceeded
+ val isSuperBolus: Boolean
+ get() {
+ val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
+ if (loopSuspendedTill == 0L) return false
+ val now = System.currentTimeMillis()
+ if (loopSuspendedTill <= now) { // time exceeded
+ suspendTo(0L)
+ return false
+ }
+ return sp.getBoolean("isSuperBolus", false)
+ }
+
+ // time exceeded
+ val isDisconnected: Boolean
+ get() {
+ val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
+ if (loopSuspendedTill == 0L) return false
+ val now = System.currentTimeMillis()
+ if (loopSuspendedTill <= now) { // time exceeded
+ suspendTo(0L)
+ return false
+ }
+ return sp.getBoolean("isDisconnected", false)
+ }
+
+ @Suppress("SameParameterValue")
+ private fun treatmentTimeThreshold(durationMinutes: Int): Boolean {
+ val threshold = System.currentTimeMillis() + durationMinutes * 60 * 1000
+ var bool = false
+ if (treatmentsPlugin.lastBolusTime > threshold || treatmentsPlugin.lastCarbTime > threshold) bool = true
+ return bool
+ }
+
+ @Synchronized operator fun invoke(initiator: String, allowNotification: Boolean) {
+ invoke(initiator, allowNotification, false)
+ }
+
+ @Synchronized
+ operator fun invoke(initiator: String, allowNotification: Boolean, tempBasalFallback: Boolean) {
+ try {
+ aapsLogger.debug(LTag.APS, "invoke from $initiator")
+ val loopEnabled = constraintChecker.isLoopInvocationAllowed()
+ if (!loopEnabled.value()) {
+ val message = """
+ ${resourceHelper.gs(R.string.loopdisabled)}
+ ${loopEnabled.getReasons(aapsLogger)}
+ """.trimIndent()
+ aapsLogger.debug(LTag.APS, message)
+ rxBus.send(EventLoopSetLastRunGui(message))
+ return
+ }
+ val pump = activePlugin.activePump
+ var apsResult: APSResult? = null
+ if (!isEnabled(PluginType.LOOP)) return
+ val profile = profileFunction.getProfile()
+ if (profile == null || !profileFunction.isProfileValid("Loop")) {
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
+ rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)))
+ return
+ }
+
+ // Check if pump info is loaded
+ if (pump.baseBasalRate < 0.01) return
+ val usedAPS = activePlugin.activeAPS
+ if ((usedAPS as PluginBase).isEnabled(PluginType.APS)) {
+ usedAPS.invoke(initiator, tempBasalFallback)
+ apsResult = usedAPS.lastAPSResult
+ }
+
+ // Check if we have any result
+ if (apsResult == null) {
+ rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)))
+ return
+ }
+
+ // Prepare for pumps using % basals
+ if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
+ apsResult.usePercent = true
+ }
+ apsResult.percent = (apsResult.rate / profile.basal * 100).toInt()
+
+ // check rate for constraints
+ val resultAfterConstraints = apsResult.newAndClone(injector)
+ resultAfterConstraints.rateConstraint = Constraint(resultAfterConstraints.rate)
+ resultAfterConstraints.rate = constraintChecker.applyBasalConstraints(resultAfterConstraints.rateConstraint!!, profile).value()
+ resultAfterConstraints.percentConstraint = Constraint(resultAfterConstraints.percent)
+ resultAfterConstraints.percent = constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.percentConstraint!!, profile).value()
+ resultAfterConstraints.smbConstraint = Constraint(resultAfterConstraints.smb)
+ resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint!!).value()
+
+ // safety check for multiple SMBs
+ val lastBolusTime = treatmentsPlugin.lastBolusTime
+ if (lastBolusTime != 0L && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
+ aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
+ resultAfterConstraints.smb = 0.0
+ }
+ if (lastRun != null && lastRun!!.constraintsProcessed != null) {
+ prevCarbsreq = lastRun!!.constraintsProcessed!!.carbsReq
+ }
+ if (lastRun == null) lastRun = LastRun()
+ lastRun!!.request = apsResult
+ lastRun!!.constraintsProcessed = resultAfterConstraints
+ lastRun!!.lastAPSRun = DateUtil.now()
+ lastRun!!.source = (usedAPS as PluginBase).name
+ lastRun!!.tbrSetByPump = null
+ lastRun!!.smbSetByPump = null
+ lastRun!!.lastTBREnact = 0
+ lastRun!!.lastTBRRequest = 0
+ lastRun!!.lastSMBEnact = 0
+ lastRun!!.lastSMBRequest = 0
+ nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)
+ if (isSuspended) {
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended))
+ rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)))
+ return
+ }
+ if (pump.isSuspended()) {
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended))
+ rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended)))
+ return
+ }
+ val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
+ if (closedLoopEnabled.value()) {
+ if (allowNotification) {
+ if (resultAfterConstraints.isCarbsRequired
+ && resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)) {
+ if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
+ val carbReqLocal = Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.carbsRequiredText, Notification.NORMAL)
+ rxBus.send(EventNewNotification(carbReqLocal))
+ }
+ if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) {
+ nsUpload.uploadError(resultAfterConstraints.carbsRequiredText)
+ }
+ if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
+ val intentAction5m = Intent(context, CarbSuggestionReceiver::class.java)
+ intentAction5m.putExtra("ignoreDuration", 5)
+ val pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT)
+ val actionIgnore5m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m)
+ val intentAction15m = Intent(context, CarbSuggestionReceiver::class.java)
+ intentAction15m.putExtra("ignoreDuration", 15)
+ val pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT)
+ val actionIgnore15m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m)
+ val intentAction30m = Intent(context, CarbSuggestionReceiver::class.java)
+ intentAction30m.putExtra("ignoreDuration", 30)
+ val pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT)
+ val actionIgnore30m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m)
+ val builder = NotificationCompat.Builder(context, CHANNEL_ID)
+ builder.setSmallIcon(R.drawable.notif_icon)
+ .setContentTitle(resourceHelper.gs(R.string.carbssuggestion))
+ .setContentText(resultAfterConstraints.carbsRequiredText)
+ .setAutoCancel(true)
+ .setPriority(Notification.IMPORTANCE_HIGH)
+ .setCategory(Notification.CATEGORY_ALARM)
+ .addAction(actionIgnore5m)
+ .addAction(actionIgnore15m)
+ .addAction(actionIgnore30m)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
+ val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+ // mId allows you to update the notification later on.
+ mNotificationManager.notify(Constants.notificationID, builder.build())
+ rxBus.send(EventNewOpenLoopNotification())
+
+ //only send to wear if Native notifications are turned off
+ if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
+ // Send to Wear
+ rxBus.send(EventWearDoAction("changeRequest"))
+ }
+ }
+ } else {
+ //If carbs were required previously, but are no longer needed, dismiss notifications
+ if (prevCarbsreq > 0) {
+ dismissSuggestion()
+ rxBus.send(EventDismissNotification(Notification.CARBS_REQUIRED))
+ }
+ }
+ }
+ if (resultAfterConstraints.isChangeRequested
+ && !commandQueue.bolusInQueue()
+ && !commandQueue.isRunning(Command.CommandType.BOLUS)) {
+ val waiting = PumpEnactResult(injector)
+ waiting.queued = true
+ if (resultAfterConstraints.tempBasalRequested) lastRun!!.tbrSetByPump = waiting
+ if (resultAfterConstraints.bolusRequested) lastRun!!.smbSetByPump = waiting
+ rxBus.send(EventLoopUpdateGui())
+ fabricPrivacy.logCustom("APSRequest")
+ applyTBRRequest(resultAfterConstraints, profile, object : Callback() {
+ override fun run() {
+ if (result.enacted || result.success) {
+ lastRun!!.tbrSetByPump = result
+ lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
+ lastRun!!.lastTBREnact = DateUtil.now()
+ rxBus.send(EventLoopUpdateGui())
+ applySMBRequest(resultAfterConstraints, object : Callback() {
+ override fun run() {
+ // Callback is only called if a bolus was actually requested
+ if (result.enacted || result.success) {
+ lastRun!!.smbSetByPump = result
+ lastRun!!.lastSMBRequest = lastRun!!.lastAPSRun
+ lastRun!!.lastSMBEnact = DateUtil.now()
+ } else {
+ Thread {
+ SystemClock.sleep(1000)
+ invoke("tempBasalFallback", allowNotification, true)
+ }.start()
+ }
+ rxBus.send(EventLoopUpdateGui())
+ }
+ })
+ } else {
+ lastRun!!.tbrSetByPump = result
+ lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
+ }
+ rxBus.send(EventLoopUpdateGui())
+ }
+ })
+ } else {
+ lastRun!!.tbrSetByPump = null
+ lastRun!!.smbSetByPump = null
+ }
+ } else {
+ if (resultAfterConstraints.isChangeRequested && allowNotification) {
+ val builder = NotificationCompat.Builder(context, CHANNEL_ID)
+ builder.setSmallIcon(R.drawable.notif_icon)
+ .setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion))
+ .setContentText(resultAfterConstraints.toString())
+ .setAutoCancel(true)
+ .setPriority(Notification.IMPORTANCE_HIGH)
+ .setCategory(Notification.CATEGORY_ALARM)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ if (sp.getBoolean(R.string.key_wear_control, false)) {
+ builder.setLocalOnly(true)
+ }
+ presentSuggestion(builder)
+ } else if (allowNotification) {
+ dismissSuggestion()
+ }
+ }
+ rxBus.send(EventLoopUpdateGui())
+ } finally {
+ aapsLogger.debug(LTag.APS, "invoke end")
+ }
+ }
+
+ fun disableCarbSuggestions(durationMinutes: Int) {
+ carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + durationMinutes * 60 * 1000
+ dismissSuggestion()
+ }
+
+ private fun presentSuggestion(builder: NotificationCompat.Builder) {
+ // Creates an explicit intent for an Activity in your app
+ val resultIntent = Intent(context, MainActivity::class.java)
+
+ // The stack builder object will contain an artificial back stack for the
+ // started Activity.
+ // This ensures that navigating backward from the Activity leads out of
+ // your application to the Home screen.
+ val stackBuilder = TaskStackBuilder.create(context)
+ stackBuilder.addParentStack(MainActivity::class.java)
+ // Adds the Intent that starts the Activity to the top of the stack
+ stackBuilder.addNextIntent(resultIntent)
+ val resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
+ builder.setContentIntent(resultPendingIntent)
+ builder.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
+ val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ // mId allows you to update the notification later on.
+ mNotificationManager.notify(Constants.notificationID, builder.build())
+ rxBus.send(EventNewOpenLoopNotification())
+
+ // Send to Wear
+ rxBus.send(EventWearDoAction("changeRequest"))
+ }
+
+ private fun dismissSuggestion() {
+ // dismiss notifications
+ val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.cancel(Constants.notificationID)
+ rxBus.send(EventWearDoAction("cancelChangeRequest"))
+ }
+
+ fun acceptChangeRequest() {
+ val profile = profileFunction.getProfile()
+ val lp = this
+ applyTBRRequest(lastRun!!.constraintsProcessed, profile, object : Callback() {
+ override fun run() {
+ if (result.enacted) {
+ lastRun!!.tbrSetByPump = result
+ lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
+ lastRun!!.lastTBREnact = DateUtil.now()
+ lastRun!!.lastOpenModeAccept = DateUtil.now()
+ nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)
+ sp.incInt(R.string.key_ObjectivesmanualEnacts)
+ }
+ rxBus.send(EventAcceptOpenLoopChange())
+ }
+ })
+ fabricPrivacy.logCustom("AcceptTemp")
+ }
+
+ /**
+ * expect absolute request and allow both absolute and percent response based on pump capabilities
+ * TODO: update pump drivers to support APS request in %
+ */
+ private fun applyTBRRequest(request: APSResult?, profile: Profile?, callback: Callback?) {
+ if (!request!!.tempBasalRequested) {
+ callback?.result(PumpEnactResult(injector).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested)))?.run()
+ return
+ }
+ val pump = activePlugin.activePump
+ if (!pump.isInitialized()) {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
+ callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
+ return
+ }
+ if (pump.isSuspended()) {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpsuspended))
+ callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
+ return
+ }
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: $request")
+ val now = System.currentTimeMillis()
+ val activeTemp = treatmentsPlugin.getTempBasalFromHistory(now)
+ if (request.usePercent && allowPercentage()) {
+ if (request.percent == 100 && request.duration == 0) {
+ if (activeTemp != null) {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
+ commandQueue.cancelTempBasal(false, callback)
+ } else {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
+ callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0)
+ .enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly)))?.run()
+ }
+ } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.percentRate) {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
+ callback?.result(PumpEnactResult(injector).percent(request.percent)
+ .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
+ .comment(resourceHelper.gs(R.string.let_temp_basal_run)))?.run()
+ } else {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: tempBasalPercent()")
+ commandQueue.tempBasalPercent(request.percent, request.duration, false, profile!!, callback)
+ }
+ } else {
+ if (request.rate == 0.0 && request.duration == 0 || abs(request.rate - pump.baseBasalRate) < pump.pumpDescription.basalStep) {
+ if (activeTemp != null) {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
+ commandQueue.cancelTempBasal(false, callback)
+ } else {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
+ callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0)
+ .enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly)))?.run()
+ }
+ } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
+ callback?.result(PumpEnactResult(injector).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
+ .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
+ .comment(resourceHelper.gs(R.string.let_temp_basal_run)))?.run()
+ } else {
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()")
+ commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile!!, callback)
+ }
+ }
+ }
+
+ private fun applySMBRequest(request: APSResult, callback: Callback?) {
+ if (!request.bolusRequested) {
+ return
+ }
+ val pump = activePlugin.activePump
+ val lastBolusTime = treatmentsPlugin.lastBolusTime
+ if (lastBolusTime != 0L && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
+ aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
+ callback?.result(PumpEnactResult(injector)
+ .comment(resourceHelper.gs(R.string.smb_frequency_exceeded))
+ .enacted(false).success(false))?.run()
+ return
+ }
+ if (!pump.isInitialized()) {
+ aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
+ callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
+ return
+ }
+ if (pump.isSuspended()) {
+ aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpsuspended))
+ callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
+ return
+ }
+ aapsLogger.debug(LTag.APS, "applySMBRequest: $request")
+
+ // deliver SMB
+ val detailedBolusInfo = DetailedBolusInfo()
+ detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.lastBolusTime
+ detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
+ detailedBolusInfo.insulin = request.smb
+ detailedBolusInfo.isSMB = true
+ detailedBolusInfo.source = Source.USER
+ detailedBolusInfo.deliverAt = request.deliverAt
+ aapsLogger.debug(LTag.APS, "applyAPSRequest: bolus()")
+ commandQueue.bolus(detailedBolusInfo, callback)
+ }
+
+ private fun allowPercentage(): Boolean {
+ return virtualPumpPlugin.isEnabled(PluginType.PUMP)
+ }
+
+ fun disconnectPump(durationInMinutes: Int, profile: Profile?) {
+ val pump = activePlugin.activePump
+ disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L)
+ if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
+ commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile!!, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
+ }
+ }
+ })
+ } else {
+ commandQueue.tempBasalPercent(0, durationInMinutes, true, profile!!, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
+ }
+ }
+ })
+ }
+ if (pump.pumpDescription.isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
+ commandQueue.cancelExtended(object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
+ }
+ }
+ })
+ }
+ createOfflineEvent(durationInMinutes)
+ }
+
+ fun suspendLoop(durationInMinutes: Int) {
+ suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000)
+ commandQueue.cancelTempBasal(true, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
+ }
+ }
+ })
+ createOfflineEvent(durationInMinutes)
+ }
+
+ fun createOfflineEvent(durationInMinutes: Int) {
+ val data = JSONObject()
+ try {
+ data.put("eventType", CareportalEvent.OPENAPSOFFLINE)
+ data.put("duration", durationInMinutes)
+ } catch (e: JSONException) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ val event = CareportalEvent(injector)
+ event.date = DateUtil.now()
+ event.source = Source.USER
+ event.eventType = CareportalEvent.OPENAPSOFFLINE
+ event.json = data.toString()
+ MainApp.getDbHelper().createOrUpdate(event)
+ nsUpload.uploadOpenAPSOffline(event)
+ }
+
+ companion object {
+
+ private const val CHANNEL_ID = "AndroidAPS-OpenLoop"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/ScriptReader.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/ScriptReader.java
deleted file mode 100644
index e3a64dbece..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/ScriptReader.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.loop;
-
-import android.content.Context;
-import android.content.res.AssetManager;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-public class ScriptReader {
-
- private final Context mContext;
-
- public ScriptReader(Context context) {
- mContext = context;
- }
-
- public byte[] readFile(String fileName) throws IOException {
-
- AssetManager assetManager = mContext.getAssets();
- InputStream is = assetManager.open(fileName);
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-
- int nRead;
- byte[] data = new byte[16384];
-
- while ((nRead = is.read(data, 0, data.length)) != -1) {
- buffer.write(data, 0, nRead);
- }
-
- buffer.flush();
-
- byte[] bytes = buffer.toByteArray();
- is.close();
- buffer.close();
-
-
- return bytes;
-
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/ScriptReader.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/ScriptReader.kt
new file mode 100644
index 0000000000..000cd55900
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/ScriptReader.kt
@@ -0,0 +1,25 @@
+package info.nightscout.androidaps.plugins.aps.loop
+
+import android.content.Context
+import java.io.ByteArrayOutputStream
+import java.io.IOException
+
+class ScriptReader(private val context: Context) {
+
+ @Throws(IOException::class)
+ fun readFile(fileName: String): ByteArray {
+ val assetManager = context.assets
+ val `is` = assetManager.open(fileName)
+ val buffer = ByteArrayOutputStream()
+ var nRead: Int
+ val data = ByteArray(16384)
+ while (`is`.read(data, 0, data.size).also { nRead = it } != -1) {
+ buffer.write(data, 0, nRead)
+ }
+ buffer.flush()
+ val bytes = buffer.toByteArray()
+ `is`.close()
+ buffer.close()
+ return bytes
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java
deleted file mode 100644
index a6876a3144..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java
+++ /dev/null
@@ -1,299 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSAMA;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.javascript.Context;
-import org.mozilla.javascript.Function;
-import org.mozilla.javascript.NativeJSON;
-import org.mozilla.javascript.NativeObject;
-import org.mozilla.javascript.RhinoException;
-import org.mozilla.javascript.Scriptable;
-import org.mozilla.javascript.ScriptableObject;
-import org.mozilla.javascript.Undefined;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.nio.charset.StandardCharsets;
-
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-
-import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.IobTotal;
-import info.nightscout.androidaps.data.MealData;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.db.TemporaryBasal;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
-import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
-import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
-import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-public class DetermineBasalAdapterAMAJS {
- private final HasAndroidInjector injector;
- @Inject AAPSLogger aapsLogger;
- @Inject ConstraintChecker constraintChecker;
- @Inject SP sp;
- @Inject ProfileFunction profileFunction;
- @Inject TreatmentsPlugin treatmentsPlugin;
- @Inject OpenHumansUploader openHumansUploader;
-
- private final ScriptReader mScriptReader;
-
- private JSONObject mProfile;
- private JSONObject mGlucoseStatus;
- private JSONArray mIobData;
- private JSONObject mMealData;
- private JSONObject mCurrentTemp;
- private JSONObject mAutosensData = null;
-
- private String storedCurrentTemp = null;
- private String storedIobData = null;
- private String storedGlucoseStatus = null;
- private String storedProfile = null;
- private String storedMeal_data = null;
- private String storedAutosens_data = null;
-
- private String scriptDebug = "";
-
- DetermineBasalAdapterAMAJS(ScriptReader scriptReader, HasAndroidInjector injector) {
- injector.androidInjector().inject(this);
- mScriptReader = scriptReader;
- this.injector = injector;
- }
-
- @Nullable
- public DetermineBasalResultAMA invoke() {
-
- aapsLogger.debug(LTag.APS, ">>> Invoking detemine_basal <<<");
- aapsLogger.debug(LTag.APS, "Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString()));
- aapsLogger.debug(LTag.APS, "IOB data: " + (storedIobData = mIobData.toString()));
- aapsLogger.debug(LTag.APS, "Current temp: " + (storedCurrentTemp = mCurrentTemp.toString()));
- aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString()));
- aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString()));
- if (mAutosensData != null)
- aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = mAutosensData.toString()));
- else
- aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = "undefined"));
-
-
- DetermineBasalResultAMA determineBasalResultAMA = null;
-
- Context rhino = Context.enter();
- Scriptable scope = rhino.initStandardObjects();
- // Turn off optimization to make Rhino Android compatible
- rhino.setOptimizationLevel(-1);
-
- try {
-
- //register logger callback for console.log and console.error
- ScriptableObject.defineClass(scope, LoggerCallback.class);
- Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null);
- scope.put("console2", scope, myLogger);
- rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null);
-
- //set module parent
- rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null);
- rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null);
- rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null);
-
- //generate functions "determine_basal" and "setTempBasal"
- rhino.evaluateString(scope, readFile("OpenAPSAMA/determine-basal.js"), "JavaScript", 0, null);
- rhino.evaluateString(scope, readFile("OpenAPSAMA/basal-set-temp.js"), "setTempBasal.js", 0, null);
- Object determineBasalObj = scope.get("determine_basal", scope);
- Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope);
-
- //call determine-basal
- if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) {
- Function determineBasalJS = (Function) determineBasalObj;
-
- //prepare parameters
- Object[] params = new Object[]{
- makeParam(mGlucoseStatus, rhino, scope),
- makeParam(mCurrentTemp, rhino, scope),
- makeParamArray(mIobData, rhino, scope),
- makeParam(mProfile, rhino, scope),
- makeParam(mAutosensData, rhino, scope),
- makeParam(mMealData, rhino, scope),
- setTempBasalFunctionsObj};
-
- NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params);
- scriptDebug = LoggerCallback.getScriptDebug();
-
- // Parse the jsResult object to a JSON-String
- String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
- aapsLogger.debug(LTag.APS, "Result: " + result);
- try {
- JSONObject resultJson = new JSONObject(result);
- openHumansUploader.enqueueAMAData(mProfile, mGlucoseStatus, mIobData, mMealData, mCurrentTemp, mAutosensData, resultJson);
- determineBasalResultAMA = new DetermineBasalResultAMA(injector, jsResult, resultJson);
- } catch (JSONException e) {
- aapsLogger.error(LTag.APS, "Unhandled exception", e);
- }
- } else {
- aapsLogger.error(LTag.APS, "Problem loading JS Functions");
- }
- } catch (IOException e) {
- aapsLogger.error(LTag.APS, "IOException");
- } catch (RhinoException e) {
- aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString());
- } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
- aapsLogger.error(LTag.APS, e.toString());
- } finally {
- Context.exit();
- }
-
- storedGlucoseStatus = mGlucoseStatus.toString();
- storedIobData = mIobData.toString();
- storedCurrentTemp = mCurrentTemp.toString();
- storedProfile = mProfile.toString();
- storedMeal_data = mMealData.toString();
-
- return determineBasalResultAMA;
-
- }
-
- String getGlucoseStatusParam() {
- return storedGlucoseStatus;
- }
-
- String getCurrentTempParam() {
- return storedCurrentTemp;
- }
-
- String getIobDataParam() {
- return storedIobData;
- }
-
- String getProfileParam() {
- return storedProfile;
- }
-
- String getMealDataParam() {
- return storedMeal_data;
- }
-
- String getAutosensDataParam() {
- return storedAutosens_data;
- }
-
- String getScriptDebug() {
- return scriptDebug;
- }
-
- public void setData(Profile profile,
- double maxIob,
- double maxBasal,
- double minBg,
- double maxBg,
- double targetBg,
- double basalrate,
- IobTotal[] iobArray,
- GlucoseStatus glucoseStatus,
- MealData mealData,
- double autosensDataRatio,
- boolean tempTargetSet) throws JSONException {
-
- mProfile = new JSONObject();
- mProfile.put("max_iob", maxIob);
- mProfile.put("dia", Math.min(profile.getDia(), 3d));
- mProfile.put("type", "current");
- mProfile.put("max_daily_basal", profile.getMaxDailyBasal());
- mProfile.put("max_basal", maxBasal);
- mProfile.put("min_bg", minBg);
- mProfile.put("max_bg", maxBg);
- mProfile.put("target_bg", targetBg);
- mProfile.put("carb_ratio", profile.getIc());
- mProfile.put("sens", profile.getIsfMgdl());
- mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
- mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
- mProfile.put("skip_neutral_temps", true);
- mProfile.put("current_basal", basalrate);
- mProfile.put("temptargetSet", tempTargetSet);
- mProfile.put("autosens_adjust_targets", sp.getBoolean(R.string.key_openapsama_autosens_adjusttargets, true));
- //align with max-absorption model in AMA sensitivity
- if (mealData.usedMinCarbsImpact > 0) {
- mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
- } else {
- mProfile.put("min_5m_carbimpact", sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
- }
-
- if (profileFunction.getUnits().equals(Constants.MMOL)) {
- mProfile.put("out_units", "mmol/L");
- }
-
- long now = System.currentTimeMillis();
- TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now);
-
- mCurrentTemp = new JSONObject();
- mCurrentTemp.put("temp", "absolute");
- mCurrentTemp.put("duration", tb != null ? tb.getPlannedRemainingMinutes() : 0);
- mCurrentTemp.put("rate", tb != null ? tb.tempBasalConvertedToAbsolute(now, profile) : 0d);
-
- // as we have non default temps longer than 30 mintues
- TemporaryBasal tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis());
- if (tempBasal != null) {
- mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration());
- }
-
- mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray);
-
- mGlucoseStatus = new JSONObject();
- mGlucoseStatus.put("glucose", glucoseStatus.glucose);
-
- if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
- mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
- } else {
- mGlucoseStatus.put("delta", glucoseStatus.delta);
- }
- mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta);
- mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta);
-
- mMealData = new JSONObject();
- mMealData.put("carbs", mealData.carbs);
- mMealData.put("boluses", mealData.boluses);
- mMealData.put("mealCOB", mealData.mealCOB);
-
- if (constraintChecker.isAutosensModeEnabled().value()) {
- mAutosensData = new JSONObject();
- mAutosensData.put("ratio", autosensDataRatio);
- } else {
- mAutosensData = null;
- }
- }
-
-
- private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
-
- if (jsonObject == null) return Undefined.instance;
-
- Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
- return param;
- }
-
- private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
- //Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
- Object param = NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
- return param;
- }
-
- private String readFile(String filename) throws IOException {
- byte[] bytes = mScriptReader.readFile(filename);
- String string = new String(bytes, StandardCharsets.UTF_8);
- if (string.startsWith("#!/usr/bin/env node")) {
- string = string.substring(20);
- }
- return string;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt
new file mode 100644
index 0000000000..a2334030ea
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt
@@ -0,0 +1,240 @@
+package info.nightscout.androidaps.plugins.aps.openAPSAMA
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.IobTotal
+import info.nightscout.androidaps.data.MealData
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
+import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
+import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
+import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import org.mozilla.javascript.*
+import org.mozilla.javascript.Function
+import java.io.IOException
+import java.lang.reflect.InvocationTargetException
+import java.nio.charset.StandardCharsets
+import javax.inject.Inject
+import kotlin.math.min
+
+class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader, injector: HasAndroidInjector) {
+
+ private val injector: HasAndroidInjector
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var constraintChecker: ConstraintChecker
+ @Inject lateinit var sp: SP
+ @Inject lateinit var profileFunction: ProfileFunction
+ @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
+ @Inject lateinit var openHumansUploader: OpenHumansUploader
+
+ private val mScriptReader: ScriptReader
+ private var profile = JSONObject()
+ private var glucoseStatus = JSONObject()
+ private var iobData: JSONArray? = null
+ private var mealData = JSONObject()
+ private var currentTemp = JSONObject()
+ private var autosensData = JSONObject()
+
+ var currentTempParam: String? = null
+ private set
+ var iobDataParam: String? = null
+ private set
+ var glucoseStatusParam: String? = null
+ private set
+ var profileParam: String? = null
+ private set
+ var mealDataParam: String? = null
+ private set
+ var scriptDebug = ""
+ private set
+
+ @Suppress("SpellCheckingInspection")
+ operator fun invoke(): DetermineBasalResultAMA? {
+ aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
+ aapsLogger.debug(LTag.APS, "Glucose status: " + glucoseStatus.toString().also { glucoseStatusParam = it })
+ aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
+ aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
+ aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
+ aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
+ aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
+ var determineBasalResultAMA: DetermineBasalResultAMA? = null
+ val rhino = Context.enter()
+ val scope: Scriptable = rhino.initStandardObjects()
+ // Turn off optimization to make Rhino Android compatible
+ rhino.optimizationLevel = -1
+ try {
+
+ //register logger callback for console.log and console.error
+ ScriptableObject.defineClass(scope, LoggerCallback::class.java)
+ val myLogger = rhino.newObject(scope, "LoggerCallback", null)
+ scope.put("console2", scope, myLogger)
+ rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
+
+ //set module parent
+ rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
+ rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
+ rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
+
+ //generate functions "determine_basal" and "setTempBasal"
+ rhino.evaluateString(scope, readFile("OpenAPSAMA/determine-basal.js"), "JavaScript", 0, null)
+ rhino.evaluateString(scope, readFile("OpenAPSAMA/basal-set-temp.js"), "setTempBasal.js", 0, null)
+ val determineBasalObj = scope["determine_basal", scope]
+ val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
+
+ //call determine-basal
+ if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
+
+ //prepare parameters
+ val params = arrayOf(
+ makeParam(glucoseStatus, rhino, scope),
+ makeParam(currentTemp, rhino, scope),
+ makeParamArray(iobData, rhino, scope),
+ makeParam(profile, rhino, scope),
+ makeParam(autosensData, rhino, scope),
+ makeParam(mealData, rhino, scope),
+ setTempBasalFunctionsObj)
+ val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
+ scriptDebug = LoggerCallback.scriptDebug
+
+ // Parse the jsResult object to a JSON-String
+ val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
+ aapsLogger.debug(LTag.APS, "Result: $result")
+ try {
+ val resultJson = JSONObject(result)
+ openHumansUploader.enqueueAMAData(profile, glucoseStatus, iobData, mealData, currentTemp, autosensData, resultJson)
+ determineBasalResultAMA = DetermineBasalResultAMA(injector, jsResult, resultJson)
+ } catch (e: JSONException) {
+ aapsLogger.error(LTag.APS, "Unhandled exception", e)
+ }
+ } else {
+ aapsLogger.error(LTag.APS, "Problem loading JS Functions")
+ }
+ } catch (e: IOException) {
+ aapsLogger.error(LTag.APS, "IOException")
+ } catch (e: RhinoException) {
+ aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
+ } catch (e: IllegalAccessException) {
+ aapsLogger.error(LTag.APS, e.toString())
+ } catch (e: InstantiationException) {
+ aapsLogger.error(LTag.APS, e.toString())
+ } catch (e: InvocationTargetException) {
+ aapsLogger.error(LTag.APS, e.toString())
+ } finally {
+ Context.exit()
+ }
+ glucoseStatusParam = glucoseStatus.toString()
+ iobDataParam = iobData.toString()
+ currentTempParam = currentTemp.toString()
+ profileParam = profile.toString()
+ mealDataParam = mealData.toString()
+ return determineBasalResultAMA
+ }
+
+ @Suppress("SpellCheckingInspection")
+ @Throws(JSONException::class) fun setData(profile: Profile,
+ maxIob: Double,
+ maxBasal: Double,
+ minBg: Double,
+ maxBg: Double,
+ targetBg: Double,
+ basalRate: Double,
+ iobArray: Array,
+ glucoseStatus: GlucoseStatus,
+ mealData: MealData,
+ autosensDataRatio: Double,
+ tempTargetSet: Boolean) {
+ this.profile = JSONObject()
+ this.profile.put("max_iob", maxIob)
+ this.profile.put("dia", min(profile.dia, 3.0))
+ this.profile.put("type", "current")
+ this.profile.put("max_daily_basal", profile.maxDailyBasal)
+ this.profile.put("max_basal", maxBasal)
+ this.profile.put("min_bg", minBg)
+ this.profile.put("max_bg", maxBg)
+ this.profile.put("target_bg", targetBg)
+ this.profile.put("carb_ratio", profile.ic)
+ this.profile.put("sens", profile.isfMgdl)
+ this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
+ this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
+ this.profile.put("skip_neutral_temps", true)
+ this.profile.put("current_basal", basalRate)
+ this.profile.put("temptargetSet", tempTargetSet)
+ this.profile.put("autosens_adjust_targets", sp.getBoolean(R.string.key_openapsama_autosens_adjusttargets, true))
+ //align with max-absorption model in AMA sensitivity
+ if (mealData.usedMinCarbsImpact > 0) {
+ this.profile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact)
+ } else {
+ this.profile.put("min_5m_carbimpact", sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact))
+ }
+ if (profileFunction.getUnits() == Constants.MMOL) {
+ this.profile.put("out_units", "mmol/L")
+ }
+ val now = System.currentTimeMillis()
+ val tb = treatmentsPlugin.getTempBasalFromHistory(now)
+ currentTemp = JSONObject()
+ currentTemp.put("temp", "absolute")
+ currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
+ currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0)
+
+ // as we have non default temps longer than 30 minutes
+ val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
+ if (tempBasal != null) {
+ currentTemp.put("minutesrunning", tempBasal.realDuration)
+ }
+ iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
+ this.glucoseStatus = JSONObject()
+ this.glucoseStatus.put("glucose", glucoseStatus.glucose)
+ if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
+ this.glucoseStatus.put("delta", glucoseStatus.shortAvgDelta)
+ } else {
+ this.glucoseStatus.put("delta", glucoseStatus.delta)
+ }
+ this.glucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
+ this.glucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
+ this.mealData = JSONObject()
+ this.mealData.put("carbs", mealData.carbs)
+ this.mealData.put("boluses", mealData.boluses)
+ this.mealData.put("mealCOB", mealData.mealCOB)
+ if (constraintChecker.isAutosensModeEnabled().value()) {
+ autosensData.put("ratio", autosensDataRatio)
+ } else {
+ autosensData.put("ratio", 1.0)
+ }
+ }
+
+ private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
+ return if (jsonObject == null) Undefined.instance else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array -> objects[1] }
+ }
+
+ private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
+ return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array -> objects[1] }
+ }
+
+ @Throws(IOException::class) private fun readFile(filename: String): String {
+ val bytes = mScriptReader.readFile(filename)
+ var string = String(bytes, StandardCharsets.UTF_8)
+ if (string.startsWith("#!/usr/bin/env node")) {
+ string = string.substring(20)
+ }
+ return string
+ }
+
+ init {
+ injector.androidInjector().inject(this)
+ mScriptReader = scriptReader
+ this.injector = injector
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt
index a9a171b46a..84bc71daf7 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt
@@ -16,10 +16,10 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.JSONFormatter
-import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import org.json.JSONArray
import org.json.JSONException
import javax.inject.Inject
@@ -114,7 +114,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
if (openAPSAMAPlugin.lastAPSRun != 0L) {
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun)
}
- openAPSAMAPlugin.lastAutosensResult?.let {
+ openAPSAMAPlugin.lastAutosensResult.let {
binding.autosensdata.text = JSONFormatter.format(it.json())
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java
deleted file mode 100644
index 76e546b88d..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java
+++ /dev/null
@@ -1,263 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSAMA;
-
-import android.content.Context;
-
-import org.json.JSONException;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.IobTotal;
-import info.nightscout.androidaps.data.MealData;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.db.TempTarget;
-import info.nightscout.androidaps.interfaces.APSInterface;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginDescription;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
-import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
-import info.nightscout.androidaps.plugins.aps.loop.APSResult;
-import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.HardLimits;
-import info.nightscout.androidaps.utils.Profiler;
-import info.nightscout.androidaps.utils.Round;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-
-@Singleton
-public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
- private final AAPSLogger aapsLogger;
- private final RxBusWrapper rxBus;
- private final ConstraintChecker constraintChecker;
- private final ResourceHelper resourceHelper;
- private final ProfileFunction profileFunction;
- private final Context context;
- private final ActivePluginProvider activePlugin;
- private final TreatmentsPlugin treatmentsPlugin;
- private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
- private final HardLimits hardLimits;
- private final Profiler profiler;
- private final FabricPrivacy fabricPrivacy;
-
- // last values
- DetermineBasalAdapterAMAJS lastDetermineBasalAdapterAMAJS = null;
- long lastAPSRun = 0;
- DetermineBasalResultAMA lastAPSResult = null;
- AutosensResult lastAutosensResult = null;
-
- @Inject
- public OpenAPSAMAPlugin(
- HasAndroidInjector injector,
- AAPSLogger aapsLogger,
- RxBusWrapper rxBus,
- ConstraintChecker constraintChecker,
- ResourceHelper resourceHelper,
- ProfileFunction profileFunction,
- Context context,
- ActivePluginProvider activePlugin,
- TreatmentsPlugin treatmentsPlugin,
- IobCobCalculatorPlugin iobCobCalculatorPlugin,
- HardLimits hardLimits,
- Profiler profiler,
- FabricPrivacy fabricPrivacy
- ) {
- super(new PluginDescription()
- .mainType(PluginType.APS)
- .fragmentClass(OpenAPSAMAFragment.class.getName())
- .pluginIcon(R.drawable.ic_generic_icon)
- .pluginName(R.string.openapsama)
- .shortName(R.string.oaps_shortname)
- .preferencesId(R.xml.pref_openapsama)
- .description(R.string.description_ama),
- aapsLogger, resourceHelper, injector
- );
- this.aapsLogger = aapsLogger;
- this.rxBus = rxBus;
- this.constraintChecker = constraintChecker;
- this.resourceHelper = resourceHelper;
- this.profileFunction = profileFunction;
- this.context = context;
- this.activePlugin = activePlugin;
- this.treatmentsPlugin = treatmentsPlugin;
- this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
- this.hardLimits = hardLimits;
- this.profiler = profiler;
- this.fabricPrivacy = fabricPrivacy;
- }
-
- @Override
- public boolean specialEnableCondition() {
- try {
- PumpInterface pump = activePlugin.getActivePump();
- return pump.getPumpDescription().isTempBasalCapable;
- } catch (Exception ignored) {
- // may fail during initialization
- return true;
- }
- }
-
- @Override
- public boolean specialShowInListCondition() {
- PumpInterface pump = activePlugin.getActivePump();
- return pump.getPumpDescription().isTempBasalCapable;
- }
-
- @Override
- public APSResult getLastAPSResult() {
- return lastAPSResult;
- }
-
- @Override
- public long getLastAPSRun() {
- return lastAPSRun;
- }
-
- @Override
- public void invoke(String initiator, boolean tempBasalFallback) {
- aapsLogger.debug(LTag.APS, "invoke from " + initiator + " tempBasalFallback: " + tempBasalFallback);
- lastAPSResult = null;
- DetermineBasalAdapterAMAJS determineBasalAdapterAMAJS;
- determineBasalAdapterAMAJS = new DetermineBasalAdapterAMAJS(new ScriptReader(context), getInjector());
-
- GlucoseStatus glucoseStatus = new GlucoseStatus(getInjector()).getGlucoseStatusData();
- Profile profile = profileFunction.getProfile();
- PumpInterface pump = activePlugin.getActivePump();
-
- if (profile == null) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)));
- aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
- return;
- }
-
- if (!isEnabled(PluginType.APS)) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)));
- aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled));
- return;
- }
-
- if (glucoseStatus == null) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)));
- aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata));
- return;
- }
-
- double maxBasal = constraintChecker.getMaxBasalAllowed(profile).value();
- double minBg = profile.getTargetLowMgdl();
- double maxBg = profile.getTargetHighMgdl();
- double targetBg = profile.getTargetMgdl();
-
- minBg = Round.roundTo(minBg, 0.1d);
- maxBg = Round.roundTo(maxBg, 0.1d);
-
- long start = System.currentTimeMillis();
- long startPart = System.currentTimeMillis();
- IobTotal[] iobArray = iobCobCalculatorPlugin.calculateIobArrayInDia(profile);
- profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart);
-
- startPart = System.currentTimeMillis();
- MealData mealData = iobCobCalculatorPlugin.getMealData();
- profiler.log(LTag.APS, "getMealData()", startPart);
-
- double maxIob = constraintChecker.getMaxIOBAllowed().value();
-
- minBg = hardLimits.verifyHardLimits(minBg, "minBg", hardLimits.getVERY_HARD_LIMIT_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_MIN_BG()[1]);
- maxBg = hardLimits.verifyHardLimits(maxBg, "maxBg", hardLimits.getVERY_HARD_LIMIT_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_MAX_BG()[1]);
- targetBg = hardLimits.verifyHardLimits(targetBg, "targetBg", hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[1]);
-
- boolean isTempTarget = false;
- TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis());
- if (tempTarget != null) {
- isTempTarget = true;
- minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[1]);
- maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[1]);
- targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[1]);
- }
-
-
- if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
- return;
- if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
- return;
- if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
- return;
- if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, hardLimits.maxBasal()))
- return;
- if (!hardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, hardLimits.maxBasal()))
- return;
-
- startPart = System.currentTimeMillis();
- if (constraintChecker.isAutosensModeEnabled().value()) {
- AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin");
- if (autosensData == null) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)));
- return;
- }
- lastAutosensResult = autosensData.autosensResult;
- } else {
- lastAutosensResult = new AutosensResult();
- lastAutosensResult.sensResult = "autosens disabled";
- }
- profiler.log(LTag.APS, "detectSensitivityandCarbAbsorption()", startPart);
- profiler.log(LTag.APS, "AMA data gathering", start);
-
- start = System.currentTimeMillis();
-
- try {
- determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
- lastAutosensResult.ratio, //autosensDataRatio
- isTempTarget
- );
- } catch (JSONException e) {
- fabricPrivacy.logException(e);
- return;
- }
-
-
- DetermineBasalResultAMA determineBasalResultAMA = determineBasalAdapterAMAJS.invoke();
- profiler.log(LTag.APS, "AMA calculation", start);
- // Fix bug determine basal
- if (determineBasalResultAMA == null) {
- aapsLogger.error(LTag.APS, "SMB calculation returned null");
- lastDetermineBasalAdapterAMAJS = null;
- lastAPSResult = null;
- lastAPSRun = 0;
- } else {
- if (determineBasalResultAMA.getRate() == 0d && determineBasalResultAMA.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
- determineBasalResultAMA.setTempBasalRequested(false);
-
- determineBasalResultAMA.setIob(iobArray[0]);
-
- long now = System.currentTimeMillis();
-
- try {
- determineBasalResultAMA.getJson().put("timestamp", DateUtil.toISOString(now));
- } catch (JSONException e) {
- aapsLogger.error(LTag.APS, "Unhandled exception", e);
- }
-
- lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS;
- lastAPSResult = determineBasalResultAMA;
- lastAPSRun = now;
- }
- rxBus.send(new EventOpenAPSUpdateGui());
-
- //deviceStatus.suggested = determineBasalResultAMA.json;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt
new file mode 100644
index 0000000000..fe15677807
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt
@@ -0,0 +1,171 @@
+package info.nightscout.androidaps.plugins.aps.openAPSAMA
+
+import android.content.Context
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
+import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
+import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.HardLimits
+import info.nightscout.androidaps.utils.Profiler
+import info.nightscout.androidaps.utils.Round
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import org.json.JSONException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+open class OpenAPSAMAPlugin @Inject constructor(
+ injector: HasAndroidInjector,
+ aapsLogger: AAPSLogger,
+ private val rxBus: RxBusWrapper,
+ private val constraintChecker: ConstraintChecker,
+ resourceHelper: ResourceHelper,
+ private val profileFunction: ProfileFunction,
+ private val context: Context,
+ private val activePlugin: ActivePluginProvider,
+ private val treatmentsPlugin: TreatmentsInterface,
+ private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
+ private val hardLimits: HardLimits,
+ private val profiler: Profiler,
+ private val fabricPrivacy: FabricPrivacy
+) : PluginBase(PluginDescription()
+ .mainType(PluginType.APS)
+ .fragmentClass(OpenAPSAMAFragment::class.java.name)
+ .pluginIcon(R.drawable.ic_generic_icon)
+ .pluginName(R.string.openapsama)
+ .shortName(R.string.oaps_shortname)
+ .preferencesId(R.xml.pref_openapsama)
+ .description(R.string.description_ama),
+ aapsLogger, resourceHelper, injector
+), APSInterface {
+
+ // last values
+ override var lastAPSRun: Long = 0
+ override var lastAPSResult: DetermineBasalResultAMA? = null
+ var lastDetermineBasalAdapterAMAJS: DetermineBasalAdapterAMAJS? = null
+ var lastAutosensResult: AutosensResult = AutosensResult()
+
+ override fun specialEnableCondition(): Boolean {
+ return try {
+ val pump = activePlugin.activePump
+ pump.pumpDescription.isTempBasalCapable
+ } catch (ignored: Exception) {
+ // may fail during initialization
+ true
+ }
+ }
+
+ override fun specialShowInListCondition(): Boolean {
+ val pump = activePlugin.activePump
+ return pump.pumpDescription.isTempBasalCapable
+ }
+
+ override fun invoke(initiator: String, tempBasalFallback: Boolean) {
+ aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback")
+ lastAPSResult = null
+ val determineBasalAdapterAMAJS = DetermineBasalAdapterAMAJS(ScriptReader(context), injector)
+ val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
+ val profile = profileFunction.getProfile()
+ val pump = activePlugin.activePump
+ if (profile == null) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)))
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
+ return
+ }
+ if (!isEnabled(PluginType.APS)) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)))
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled))
+ return
+ }
+ if (glucoseStatus == null) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)))
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata))
+ return
+ }
+ val inputConstraints = Constraint(0.0) // fake. only for collecting all results
+ val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
+ inputConstraints.copyReasons(it)
+ }.value()
+ var start = System.currentTimeMillis()
+ var startPart = System.currentTimeMillis()
+ val iobArray = iobCobCalculatorPlugin.calculateIobArrayInDia(profile)
+ profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
+ startPart = System.currentTimeMillis()
+ val mealData = iobCobCalculatorPlugin.mealData
+ profiler.log(LTag.APS, "getMealData()", startPart)
+ val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
+ inputConstraints.copyReasons(maxIOBAllowedConstraint)
+ }.value()
+ var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetLowMgdl, 0.1), "minBg", hardLimits.VERY_HARD_LIMIT_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MIN_BG[1].toDouble())
+ var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
+ var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
+ var isTempTarget = false
+ treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
+ isTempTarget = true
+ minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
+ maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
+ targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
+ }
+ if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
+ if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return
+ if (!hardLimits.checkOnlyHardLimits(profile.isfMgdl, "sens", hardLimits.MINISF, hardLimits.MAXISF)) return
+ if (!hardLimits.checkOnlyHardLimits(profile.maxDailyBasal, "max_daily_basal", 0.02, hardLimits.maxBasal())) return
+ if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, "current_basal", 0.01, hardLimits.maxBasal())) return
+ startPart = System.currentTimeMillis()
+ if (constraintChecker.isAutosensModeEnabled().value()) {
+ val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin")
+ if (autosensData == null) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
+ return
+ }
+ lastAutosensResult = autosensData.autosensResult
+ } else {
+ lastAutosensResult.sensResult = "autosens disabled"
+ }
+ profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
+ profiler.log(LTag.APS, "AMA data gathering", start)
+ start = System.currentTimeMillis()
+ try {
+ determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.activePump.baseBasalRate, iobArray, glucoseStatus, mealData,
+ lastAutosensResult.ratio,
+ isTempTarget
+ )
+ } catch (e: JSONException) {
+ fabricPrivacy.logException(e)
+ return
+ }
+ val determineBasalResultAMA = determineBasalAdapterAMAJS.invoke()
+ profiler.log(LTag.APS, "AMA calculation", start)
+ // Fix bug determine basal
+ if (determineBasalResultAMA == null) {
+ aapsLogger.error(LTag.APS, "SMB calculation returned null")
+ lastDetermineBasalAdapterAMAJS = null
+ lastAPSResult = null
+ lastAPSRun = 0
+ } else {
+ if (determineBasalResultAMA.rate == 0.0 && determineBasalResultAMA.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultAMA.tempBasalRequested = false
+ determineBasalResultAMA.iob = iobArray[0]
+ val now = System.currentTimeMillis()
+ determineBasalResultAMA.json?.put("timestamp", DateUtil.toISOString(now))
+ determineBasalResultAMA.inputConstraints = inputConstraints
+ lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS
+ lastAPSResult = determineBasalResultAMA
+ lastAPSRun = now
+ }
+ rxBus.send(EventOpenAPSUpdateGui())
+
+ //deviceStatus.suggested = determineBasalResultAMA.json;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java
deleted file mode 100644
index e42b139f3e..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java
+++ /dev/null
@@ -1,372 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSSMB;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.javascript.Context;
-import org.mozilla.javascript.Function;
-import org.mozilla.javascript.NativeJSON;
-import org.mozilla.javascript.NativeObject;
-import org.mozilla.javascript.RhinoException;
-import org.mozilla.javascript.Scriptable;
-import org.mozilla.javascript.ScriptableObject;
-import org.mozilla.javascript.Undefined;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.nio.charset.StandardCharsets;
-
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.IobTotal;
-import info.nightscout.androidaps.data.MealData;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.db.TemporaryBasal;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
-import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
-import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
-import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.SafeParse;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-
-public class DetermineBasalAdapterSMBJS {
- private final HasAndroidInjector injector;
- @Inject AAPSLogger aapsLogger;
- @Inject ConstraintChecker constraintChecker;
- @Inject SP sp;
- @Inject ResourceHelper resourceHelper;
- @Inject ProfileFunction profileFunction;
- @Inject TreatmentsPlugin treatmentsPlugin;
- @Inject ActivePluginProvider activePluginProvider;
- @Inject OpenHumansUploader openHumansUploader;
-
-
- private final ScriptReader mScriptReader;
- private JSONObject mProfile;
- private JSONObject mGlucoseStatus;
- private JSONArray mIobData;
- private JSONObject mMealData;
- private JSONObject mCurrentTemp;
- private JSONObject mAutosensData = null;
- private boolean mMicrobolusAllowed;
- private boolean mSMBAlwaysAllowed;
- private long mCurrentTime;
- private boolean mIsSaveCgmSource;
-
- private String storedCurrentTemp = null;
- private String storedIobData = null;
-
- private String storedGlucoseStatus = null;
- private String storedProfile = null;
- private String storedMeal_data = null;
-
- private String scriptDebug = "";
-
- /**
- * Main code
- */
-
- DetermineBasalAdapterSMBJS(ScriptReader scriptReader, HasAndroidInjector injector) {
- mScriptReader = scriptReader;
- this.injector = injector;
- injector.androidInjector().inject(this);
- }
-
-
- @Nullable
- public DetermineBasalResultSMB invoke() {
-
-
- aapsLogger.debug(LTag.APS, ">>> Invoking detemine_basal <<<");
- aapsLogger.debug(LTag.APS, "Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString()));
- aapsLogger.debug(LTag.APS, "IOB data: " + (storedIobData = mIobData.toString()));
- aapsLogger.debug(LTag.APS, "Current temp: " + (storedCurrentTemp = mCurrentTemp.toString()));
- aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString()));
- aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString()));
- if (mAutosensData != null)
- aapsLogger.debug(LTag.APS, "Autosens data: " + mAutosensData.toString());
- else
- aapsLogger.debug(LTag.APS, "Autosens data: " + "undefined");
- aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined");
- aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + mMicrobolusAllowed);
- aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + mSMBAlwaysAllowed);
- aapsLogger.debug(LTag.APS, "CurrentTime: " + mCurrentTime);
- aapsLogger.debug(LTag.APS, "isSaveCgmSource: " + mIsSaveCgmSource);
-
-
- DetermineBasalResultSMB determineBasalResultSMB = null;
-
- Context rhino = Context.enter();
- Scriptable scope = rhino.initStandardObjects();
- // Turn off optimization to make Rhino Android compatible
- rhino.setOptimizationLevel(-1);
-
- try {
-
- //register logger callback for console.log and console.error
- ScriptableObject.defineClass(scope, LoggerCallback.class);
- Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null);
- scope.put("console2", scope, myLogger);
- rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null);
-
- //set module parent
- rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null);
- rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null);
- rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null);
-
- //generate functions "determine_basal" and "setTempBasal"
- rhino.evaluateString(scope, readFile("OpenAPSSMB/determine-basal.js"), "JavaScript", 0, null);
- rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null);
- Object determineBasalObj = scope.get("determine_basal", scope);
- Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope);
-
- //call determine-basal
- if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) {
- Function determineBasalJS = (Function) determineBasalObj;
-
- //prepare parameters
- Object[] params = new Object[]{
- makeParam(mGlucoseStatus, rhino, scope),
- makeParam(mCurrentTemp, rhino, scope),
- makeParamArray(mIobData, rhino, scope),
- makeParam(mProfile, rhino, scope),
- makeParam(mAutosensData, rhino, scope),
- makeParam(mMealData, rhino, scope),
- setTempBasalFunctionsObj,
- Boolean.valueOf(mMicrobolusAllowed),
- makeParam(null, rhino, scope), // reservoir data as undefined
- Long.valueOf(mCurrentTime),
- Boolean.valueOf(mIsSaveCgmSource)
- };
-
-
- NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params);
- scriptDebug = LoggerCallback.getScriptDebug();
-
- // Parse the jsResult object to a JSON-String
- String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
- aapsLogger.debug(LTag.APS, "Result: " + result);
- try {
- JSONObject resultJson = new JSONObject(result);
- openHumansUploader.enqueueSMBData(mProfile, mGlucoseStatus, mIobData, mMealData, mCurrentTemp, mAutosensData, mMicrobolusAllowed, mSMBAlwaysAllowed, resultJson);
- determineBasalResultSMB = new DetermineBasalResultSMB(injector, resultJson);
- } catch (JSONException e) {
- aapsLogger.error(LTag.APS, "Unhandled exception", e);
- }
- } else {
- aapsLogger.error(LTag.APS, "Problem loading JS Functions");
- }
- } catch (IOException e) {
- aapsLogger.error(LTag.APS, "IOException");
- } catch (RhinoException e) {
- aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString());
- } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
- aapsLogger.error(LTag.APS, e.toString());
- } finally {
- Context.exit();
- }
-
- storedGlucoseStatus = mGlucoseStatus.toString();
- storedIobData = mIobData.toString();
- storedCurrentTemp = mCurrentTemp.toString();
- storedProfile = mProfile.toString();
- storedMeal_data = mMealData.toString();
-
- return determineBasalResultSMB;
-
- }
-
- String getGlucoseStatusParam() {
- return storedGlucoseStatus;
- }
-
- String getCurrentTempParam() {
- return storedCurrentTemp;
- }
-
- String getIobDataParam() {
- return storedIobData;
- }
-
- String getProfileParam() {
- return storedProfile;
- }
-
- String getMealDataParam() {
- return storedMeal_data;
- }
-
- String getScriptDebug() {
- return scriptDebug;
- }
-
- public void setData(Profile profile,
- double maxIob,
- double maxBasal,
- double minBg,
- double maxBg,
- double targetBg,
- double basalrate,
- IobTotal[] iobArray,
- GlucoseStatus glucoseStatus,
- MealData mealData,
- double autosensDataRatio,
- boolean tempTargetSet,
- boolean microBolusAllowed,
- boolean uamAllowed,
- boolean advancedFiltering,
- boolean isSaveCgmSource
- ) throws JSONException {
-
- PumpInterface pump = activePluginProvider.getActivePump();
- Double pumpbolusstep = pump.getPumpDescription().bolusStep;
- mProfile = new JSONObject();
-
- mProfile.put("max_iob", maxIob);
- //mProfile.put("dia", profile.getDia());
- mProfile.put("type", "current");
- mProfile.put("max_daily_basal", profile.getMaxDailyBasal());
- mProfile.put("max_basal", maxBasal);
- mProfile.put("min_bg", minBg);
- mProfile.put("max_bg", maxBg);
- mProfile.put("target_bg", targetBg);
- mProfile.put("carb_ratio", profile.getIc());
- mProfile.put("sens", profile.getIsfMgdl());
- mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
- mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
-
- //mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
- mProfile.put("high_temptarget_raises_sensitivity", false);
- //mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
- mProfile.put("low_temptarget_lowers_sensitivity", false);
-
-
- mProfile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target));
- mProfile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target));
- mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments);
- mProfile.put("exercise_mode", SMBDefaults.exercise_mode);
- mProfile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target);
- mProfile.put("maxCOB", SMBDefaults.maxCOB);
- mProfile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour());
- // min_5m_carbimpact is not used within SMB determinebasal
- //if (mealData.usedMinCarbsImpact > 0) {
- // mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
- //} else {
- // mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
- //}
- mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap);
- mProfile.put("enableUAM", uamAllowed);
- mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
-
- boolean smbEnabled = sp.getBoolean(R.string.key_use_smb, false);
- mProfile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval));
- mProfile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false));
- mProfile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false));
- mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
- mProfile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering);
- mProfile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering);
- mProfile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes));
- mProfile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes));
- //set the min SMB amount to be the amount set by the pump.
- mProfile.put("bolus_increment", pumpbolusstep);
- mProfile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold));
-
- mProfile.put("current_basal", basalrate);
- mProfile.put("temptargetSet", tempTargetSet);
- mProfile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")));
-
- if (profileFunction.getUnits().equals(Constants.MMOL)) {
- mProfile.put("out_units", "mmol/L");
- }
-
-
- long now = System.currentTimeMillis();
- TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now);
-
- mCurrentTemp = new JSONObject();
- mCurrentTemp.put("temp", "absolute");
- mCurrentTemp.put("duration", tb != null ? tb.getPlannedRemainingMinutes() : 0);
- mCurrentTemp.put("rate", tb != null ? tb.tempBasalConvertedToAbsolute(now, profile) : 0d);
-
- // as we have non default temps longer than 30 mintues
- TemporaryBasal tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis());
- if (tempBasal != null) {
- mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration());
- }
-
- mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray);
-
- mGlucoseStatus = new JSONObject();
- mGlucoseStatus.put("glucose", glucoseStatus.glucose);
- mGlucoseStatus.put("noise", glucoseStatus.noise);
-
- if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
- mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
- } else {
- mGlucoseStatus.put("delta", glucoseStatus.delta);
- }
- mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta);
- mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta);
- mGlucoseStatus.put("date", glucoseStatus.date);
-
- mMealData = new JSONObject();
- mMealData.put("carbs", mealData.carbs);
- mMealData.put("boluses", mealData.boluses);
- mMealData.put("mealCOB", mealData.mealCOB);
- mMealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation);
- mMealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation);
- mMealData.put("lastBolusTime", mealData.lastBolusTime);
- mMealData.put("lastCarbTime", mealData.lastCarbTime);
-
-
- if (constraintChecker.isAutosensModeEnabled().value()) {
- mAutosensData = new JSONObject();
- mAutosensData.put("ratio", autosensDataRatio);
- } else {
- mAutosensData = new JSONObject();
- mAutosensData.put("ratio", 1.0);
- }
- mMicrobolusAllowed = microBolusAllowed;
- mSMBAlwaysAllowed = advancedFiltering;
-
- mCurrentTime = now;
-
- mIsSaveCgmSource = isSaveCgmSource;
- }
-
- private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
-
- if (jsonObject == null) return Undefined.instance;
-
- return NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
- }
-
- private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
- //Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
- return NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
- }
-
- private String readFile(String filename) throws IOException {
- byte[] bytes = mScriptReader.readFile(filename);
- String string = new String(bytes, StandardCharsets.UTF_8);
- if (string.startsWith("#!/usr/bin/env node")) {
- string = string.substring(20);
- }
- return string;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.kt
new file mode 100644
index 0000000000..a980bb1bd4
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.kt
@@ -0,0 +1,290 @@
+package info.nightscout.androidaps.plugins.aps.openAPSSMB
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.IobTotal
+import info.nightscout.androidaps.data.MealData
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.interfaces.ActivePluginProvider
+import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
+import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
+import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
+import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.SafeParse
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import org.mozilla.javascript.*
+import org.mozilla.javascript.Function
+import java.io.IOException
+import java.lang.reflect.InvocationTargetException
+import java.nio.charset.StandardCharsets
+import javax.inject.Inject
+
+class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var constraintChecker: ConstraintChecker
+ @Inject lateinit var sp: SP
+ @Inject lateinit var resourceHelper: ResourceHelper
+ @Inject lateinit var profileFunction: ProfileFunction
+ @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
+ @Inject lateinit var activePluginProvider: ActivePluginProvider
+ @Inject lateinit var openHumansUploader: OpenHumansUploader
+
+ private var profile = JSONObject()
+ private var mGlucoseStatus = JSONObject()
+ private var iobData: JSONArray? = null
+ private var mealData = JSONObject()
+ private var currentTemp = JSONObject()
+ private var autosensData = JSONObject()
+ private var microBolusAllowed = false
+ private var smbAlwaysAllowed = false
+ private var currentTime: Long = 0
+ private var saveCgmSource = false
+ var currentTempParam: String? = null
+ private set
+ var iobDataParam: String? = null
+ private set
+ var glucoseStatusParam: String? = null
+ private set
+ var profileParam: String? = null
+ private set
+ var mealDataParam: String? = null
+ private set
+ var scriptDebug = ""
+ private set
+
+ @Suppress("SpellCheckingInspection")
+ operator fun invoke(): DetermineBasalResultSMB? {
+ aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
+ aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
+ aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
+ aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
+ aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
+ aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
+ aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
+ aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined")
+ aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
+ aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
+ aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
+ aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
+ var determineBasalResultSMB: DetermineBasalResultSMB? = null
+ val rhino = Context.enter()
+ val scope: Scriptable = rhino.initStandardObjects()
+ // Turn off optimization to make Rhino Android compatible
+ rhino.optimizationLevel = -1
+ try {
+
+ //register logger callback for console.log and console.error
+ ScriptableObject.defineClass(scope, LoggerCallback::class.java)
+ val myLogger = rhino.newObject(scope, "LoggerCallback", null)
+ scope.put("console2", scope, myLogger)
+ rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
+
+ //set module parent
+ rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
+ rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
+ rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
+
+ //generate functions "determine_basal" and "setTempBasal"
+ rhino.evaluateString(scope, readFile("OpenAPSSMB/determine-basal.js"), "JavaScript", 0, null)
+ rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null)
+ val determineBasalObj = scope["determine_basal", scope]
+ val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
+
+ //call determine-basal
+ if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
+
+ //prepare parameters
+ val params = arrayOf(
+ makeParam(mGlucoseStatus, rhino, scope),
+ makeParam(currentTemp, rhino, scope),
+ makeParamArray(iobData, rhino, scope),
+ makeParam(profile, rhino, scope),
+ makeParam(autosensData, rhino, scope),
+ makeParam(mealData, rhino, scope),
+ setTempBasalFunctionsObj,
+ java.lang.Boolean.valueOf(microBolusAllowed),
+ makeParam(null, rhino, scope), // reservoir data as undefined
+ java.lang.Long.valueOf(currentTime),
+ java.lang.Boolean.valueOf(saveCgmSource)
+ )
+ val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
+ scriptDebug = LoggerCallback.scriptDebug
+
+ // Parse the jsResult object to a JSON-String
+ val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
+ aapsLogger.debug(LTag.APS, "Result: $result")
+ try {
+ val resultJson = JSONObject(result)
+ openHumansUploader.enqueueSMBData(profile, mGlucoseStatus, iobData, mealData, currentTemp, autosensData, microBolusAllowed, smbAlwaysAllowed, resultJson)
+ determineBasalResultSMB = DetermineBasalResultSMB(injector, resultJson)
+ } catch (e: JSONException) {
+ aapsLogger.error(LTag.APS, "Unhandled exception", e)
+ }
+ } else {
+ aapsLogger.error(LTag.APS, "Problem loading JS Functions")
+ }
+ } catch (e: IOException) {
+ aapsLogger.error(LTag.APS, "IOException")
+ } catch (e: RhinoException) {
+ aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
+ } catch (e: IllegalAccessException) {
+ aapsLogger.error(LTag.APS, e.toString())
+ } catch (e: InstantiationException) {
+ aapsLogger.error(LTag.APS, e.toString())
+ } catch (e: InvocationTargetException) {
+ aapsLogger.error(LTag.APS, e.toString())
+ } finally {
+ Context.exit()
+ }
+ glucoseStatusParam = mGlucoseStatus.toString()
+ iobDataParam = iobData.toString()
+ currentTempParam = currentTemp.toString()
+ profileParam = profile.toString()
+ mealDataParam = mealData.toString()
+ return determineBasalResultSMB
+ }
+
+ @Suppress("SpellCheckingInspection") fun setData(profile: Profile,
+ maxIob: Double,
+ maxBasal: Double,
+ minBg: Double,
+ maxBg: Double,
+ targetBg: Double,
+ basalRate: Double,
+ iobArray: Array,
+ glucoseStatus: GlucoseStatus,
+ mealData: MealData,
+ autosensDataRatio: Double,
+ tempTargetSet: Boolean,
+ microBolusAllowed: Boolean,
+ uamAllowed: Boolean,
+ advancedFiltering: Boolean,
+ isSaveCgmSource: Boolean
+ ) {
+ val pump = activePluginProvider.activePump
+ val pumpBolusStep = pump.pumpDescription.bolusStep
+ this.profile.put("max_iob", maxIob)
+ //mProfile.put("dia", profile.getDia());
+ this.profile.put("type", "current")
+ this.profile.put("max_daily_basal", profile.maxDailyBasal)
+ this.profile.put("max_basal", maxBasal)
+ this.profile.put("min_bg", minBg)
+ this.profile.put("max_bg", maxBg)
+ this.profile.put("target_bg", targetBg)
+ this.profile.put("carb_ratio", profile.ic)
+ this.profile.put("sens", profile.isfMgdl)
+ this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
+ this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
+
+ //mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
+ this.profile.put("high_temptarget_raises_sensitivity", false)
+ //mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
+ this.profile.put("low_temptarget_lowers_sensitivity", false)
+ this.profile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target))
+ this.profile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target))
+ this.profile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments)
+ this.profile.put("exercise_mode", SMBDefaults.exercise_mode)
+ this.profile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target)
+ this.profile.put("maxCOB", SMBDefaults.maxCOB)
+ this.profile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour())
+ // min_5m_carbimpact is not used within SMB determinebasal
+ //if (mealData.usedMinCarbsImpact > 0) {
+ // mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
+ //} else {
+ // mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
+ //}
+ this.profile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap)
+ this.profile.put("enableUAM", uamAllowed)
+ this.profile.put("A52_risk_enable", SMBDefaults.A52_risk_enable)
+ val smbEnabled = sp.getBoolean(R.string.key_use_smb, false)
+ this.profile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval))
+ this.profile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false))
+ this.profile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false))
+ this.profile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false))
+ this.profile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering)
+ this.profile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering)
+ this.profile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes))
+ this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
+ //set the min SMB amount to be the amount set by the pump.
+ this.profile.put("bolus_increment", pumpBolusStep)
+ this.profile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold))
+ this.profile.put("current_basal", basalRate)
+ this.profile.put("temptargetSet", tempTargetSet)
+ this.profile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")))
+ if (profileFunction.getUnits() == Constants.MMOL) {
+ this.profile.put("out_units", "mmol/L")
+ }
+ val now = System.currentTimeMillis()
+ val tb = treatmentsPlugin.getTempBasalFromHistory(now)
+ currentTemp.put("temp", "absolute")
+ currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
+ currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0)
+
+ // as we have non default temps longer than 30 mintues
+ val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
+ if (tempBasal != null) {
+ currentTemp.put("minutesrunning", tempBasal.realDuration)
+ }
+ iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
+ mGlucoseStatus.put("glucose", glucoseStatus.glucose)
+ mGlucoseStatus.put("noise", glucoseStatus.noise)
+ if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
+ mGlucoseStatus.put("delta", glucoseStatus.shortAvgDelta)
+ } else {
+ mGlucoseStatus.put("delta", glucoseStatus.delta)
+ }
+ mGlucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
+ mGlucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
+ mGlucoseStatus.put("date", glucoseStatus.date)
+ this.mealData.put("carbs", mealData.carbs)
+ this.mealData.put("boluses", mealData.boluses)
+ this.mealData.put("mealCOB", mealData.mealCOB)
+ this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation)
+ this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation)
+ this.mealData.put("lastBolusTime", mealData.lastBolusTime)
+ this.mealData.put("lastCarbTime", mealData.lastCarbTime)
+ if (constraintChecker.isAutosensModeEnabled().value()) {
+ autosensData.put("ratio", autosensDataRatio)
+ } else {
+ autosensData.put("ratio", 1.0)
+ }
+ this.microBolusAllowed = microBolusAllowed
+ smbAlwaysAllowed = advancedFiltering
+ currentTime = now
+ saveCgmSource = isSaveCgmSource
+ }
+
+ private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
+ return if (jsonObject == null) Undefined.instance
+ else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array -> objects[1] }
+ }
+
+ private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
+ return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array -> objects[1] }
+ }
+
+ @Throws(IOException::class) private fun readFile(filename: String): String {
+ val bytes = scriptReader.readFile(filename)
+ var string = String(bytes, StandardCharsets.UTF_8)
+ if (string.startsWith("#!/usr/bin/env node")) {
+ string = string.substring(20)
+ }
+ return string
+ }
+
+ init {
+ injector.androidInjector().inject(this)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt
index b27c9fd1c4..be4e1015fa 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt
@@ -17,10 +17,10 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.JSONFormatter
-import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import org.json.JSONArray
import org.json.JSONException
import javax.inject.Inject
@@ -117,7 +117,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
if (openAPSSMBPlugin.lastAPSRun != 0L) {
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun)
}
- openAPSSMBPlugin.lastAutosensResult?.let {
+ openAPSSMBPlugin.lastAutosensResult.let {
binding.autosensdata.text = JSONFormatter.format(it.json())
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java
deleted file mode 100644
index 4ddbcdca76..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java
+++ /dev/null
@@ -1,323 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSSMB;
-
-import android.content.Context;
-
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.SwitchPreference;
-
-import org.jetbrains.annotations.NotNull;
-import org.json.JSONException;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.IobTotal;
-import info.nightscout.androidaps.data.MealData;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.db.TempTarget;
-import info.nightscout.androidaps.interfaces.APSInterface;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.interfaces.ConstraintsInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginDescription;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
-import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
-import info.nightscout.androidaps.plugins.aps.loop.APSResult;
-import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.HardLimits;
-import info.nightscout.androidaps.utils.Profiler;
-import info.nightscout.androidaps.utils.Round;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-@Singleton
-public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, ConstraintsInterface {
- private final ConstraintChecker constraintChecker;
- private final ResourceHelper resourceHelper;
- private final ProfileFunction profileFunction;
- private final Context context;
- private final RxBusWrapper rxBus;
- private final ActivePluginProvider activePlugin;
- private final TreatmentsPlugin treatmentsPlugin;
- private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
- private final HardLimits hardLimits;
- private final Profiler profiler;
- private final FabricPrivacy fabricPrivacy;
- private final SP sp;
-
- // last values
- DetermineBasalAdapterSMBJS lastDetermineBasalAdapterSMBJS = null;
- long lastAPSRun = 0;
- DetermineBasalResultSMB lastAPSResult = null;
- AutosensResult lastAutosensResult = null;
-
- @Inject
- public OpenAPSSMBPlugin(
- HasAndroidInjector injector,
- AAPSLogger aapsLogger,
- RxBusWrapper rxBus,
- ConstraintChecker constraintChecker,
- ResourceHelper resourceHelper,
- ProfileFunction profileFunction,
- Context context,
- ActivePluginProvider activePlugin,
- TreatmentsPlugin treatmentsPlugin,
- IobCobCalculatorPlugin iobCobCalculatorPlugin,
- HardLimits hardLimits,
- Profiler profiler,
- FabricPrivacy fabricPrivacy,
- SP sp
- ) {
- super(new PluginDescription()
- .mainType(PluginType.APS)
- .fragmentClass(OpenAPSSMBFragment.class.getName())
- .pluginIcon(R.drawable.ic_generic_icon)
- .pluginName(R.string.openapssmb)
- .shortName(R.string.smb_shortname)
- .preferencesId(R.xml.pref_openapssmb)
- .description(R.string.description_smb)
- .setDefault(),
- aapsLogger, resourceHelper, injector
- );
- this.constraintChecker = constraintChecker;
- this.resourceHelper = resourceHelper;
- this.profileFunction = profileFunction;
- this.rxBus = rxBus;
- this.context = context;
- this.activePlugin = activePlugin;
- this.treatmentsPlugin = treatmentsPlugin;
- this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
- this.hardLimits = hardLimits;
- this.profiler = profiler;
- this.fabricPrivacy = fabricPrivacy;
- this.sp = sp;
- }
-
- @Override
- public boolean specialEnableCondition() {
- try {
- PumpInterface pump = activePlugin.getActivePump();
- return pump.getPumpDescription().isTempBasalCapable;
- } catch (Exception ignored) {
- // may fail during initialization
- return true;
- }
- }
-
- @Override
- public boolean specialShowInListCondition() {
- PumpInterface pump = activePlugin.getActivePump();
- return pump.getPumpDescription().isTempBasalCapable;
- }
-
- @Override
- public void preprocessPreferences(@NotNull PreferenceFragmentCompat preferenceFragment) {
- super.preprocessPreferences(preferenceFragment);
- boolean smbAlwaysEnabled = sp.getBoolean(R.string.key_enableSMB_always, false);
-
- SwitchPreference withCOB = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_COB));
- if (withCOB != null) {
- withCOB.setVisible(!smbAlwaysEnabled);
- }
- SwitchPreference withTempTarget = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_temptarget));
- if (withTempTarget != null) {
- withTempTarget.setVisible(!smbAlwaysEnabled);
- }
- SwitchPreference afterCarbs = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_after_carbs));
- if (afterCarbs != null) {
- afterCarbs.setVisible(!smbAlwaysEnabled);
- }
- }
-
- @Override
- public APSResult getLastAPSResult() {
- return lastAPSResult;
- }
-
- @Override
- public long getLastAPSRun() {
- return lastAPSRun;
- }
-
- @Override
- public void invoke(String initiator, boolean tempBasalFallback) {
- getAapsLogger().debug(LTag.APS, "invoke from " + initiator + " tempBasalFallback: " + tempBasalFallback);
- lastAPSResult = null;
- DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS;
- determineBasalAdapterSMBJS = new DetermineBasalAdapterSMBJS(new ScriptReader(context), getInjector());
-
- GlucoseStatus glucoseStatus = new GlucoseStatus(getInjector()).getGlucoseStatusData();
- Profile profile = profileFunction.getProfile();
- PumpInterface pump = activePlugin.getActivePump();
-
- if (profile == null) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)));
- getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
- return;
- }
-
- if (!isEnabled(PluginType.APS)) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)));
- getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled));
- return;
- }
-
- if (glucoseStatus == null) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)));
- getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata));
- return;
- }
-
- Constraint inputConstraints = new Constraint<>(0d); // fake. only for collecting all results
-
- Constraint maxBasalConstraint = constraintChecker.getMaxBasalAllowed(profile);
- inputConstraints.copyReasons(maxBasalConstraint);
- double maxBasal = maxBasalConstraint.value();
- double minBg = profile.getTargetLowMgdl();
- double maxBg = profile.getTargetHighMgdl();
- double targetBg = profile.getTargetMgdl();
-
- minBg = Round.roundTo(minBg, 0.1d);
- maxBg = Round.roundTo(maxBg, 0.1d);
-
- long start = System.currentTimeMillis();
- long startPart = System.currentTimeMillis();
-
- MealData mealData = iobCobCalculatorPlugin.getMealData();
- profiler.log(LTag.APS, "getMealData()", startPart);
-
- Constraint maxIOBAllowedConstraint = constraintChecker.getMaxIOBAllowed();
- inputConstraints.copyReasons(maxIOBAllowedConstraint);
- double maxIob = maxIOBAllowedConstraint.value();
-
- minBg = hardLimits.verifyHardLimits(minBg, "minBg", hardLimits.getVERY_HARD_LIMIT_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_MIN_BG()[1]);
- maxBg = hardLimits.verifyHardLimits(maxBg, "maxBg", hardLimits.getVERY_HARD_LIMIT_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_MAX_BG()[1]);
- targetBg = hardLimits.verifyHardLimits(targetBg, "targetBg", hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[1]);
-
- boolean isTempTarget = false;
- TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis());
- if (tempTarget != null) {
- isTempTarget = true;
- minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[1]);
- maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[1]);
- targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[1]);
- }
-
-
- if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
- return;
- if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
- return;
- if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
- return;
- if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, hardLimits.maxBasal()))
- return;
- if (!hardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, hardLimits.maxBasal()))
- return;
-
- startPart = System.currentTimeMillis();
- if (constraintChecker.isAutosensModeEnabled().value()) {
- AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin");
- if (autosensData == null) {
- rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)));
- return;
- }
- lastAutosensResult = autosensData.autosensResult;
- } else {
- lastAutosensResult = new AutosensResult();
- lastAutosensResult.sensResult = "autosens disabled";
- }
-
- IobTotal[] iobArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget);
- profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart);
-
- startPart = System.currentTimeMillis();
- Constraint smbAllowed = new Constraint<>(!tempBasalFallback);
- constraintChecker.isSMBModeEnabled(smbAllowed);
- inputConstraints.copyReasons(smbAllowed);
-
- Constraint advancedFiltering = new Constraint<>(!tempBasalFallback);
- constraintChecker.isAdvancedFilteringEnabled(advancedFiltering);
- inputConstraints.copyReasons(advancedFiltering);
-
- Constraint uam = new Constraint<>(true);
- constraintChecker.isUAMEnabled(uam);
- inputConstraints.copyReasons(uam);
-
- profiler.log(LTag.APS, "detectSensitivityandCarbAbsorption()", startPart);
- profiler.log(LTag.APS, "SMB data gathering", start);
-
- start = System.currentTimeMillis();
- try {
- determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
- lastAutosensResult.ratio, //autosensDataRatio
- isTempTarget,
- smbAllowed.value(),
- uam.value(),
- advancedFiltering.value(),
- activePlugin.getActiveBgSource().getClass().getSimpleName().equals("DexcomPlugin")
- );
- } catch (JSONException e) {
- fabricPrivacy.logException(e);
- return;
- }
-
- long now = System.currentTimeMillis();
-
- DetermineBasalResultSMB determineBasalResultSMB = determineBasalAdapterSMBJS.invoke();
- profiler.log(LTag.APS, "SMB calculation", start);
- if (determineBasalResultSMB == null) {
- getAapsLogger().error(LTag.APS, "SMB calculation returned null");
- lastDetermineBasalAdapterSMBJS = null;
- lastAPSResult = null;
- lastAPSRun = 0;
- } else {
- // TODO still needed with oref1?
- // Fix bug determine basal
- if (determineBasalResultSMB.getRate() == 0d && determineBasalResultSMB.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
- determineBasalResultSMB.setTempBasalRequested(false);
-
- determineBasalResultSMB.setIob(iobArray[0]);
-
- try {
- determineBasalResultSMB.getJson().put("timestamp", DateUtil.toISOString(now));
- } catch (JSONException e) {
- getAapsLogger().error(LTag.APS, "Unhandled exception", e);
- }
-
- determineBasalResultSMB.setInputConstraints(inputConstraints);
-
- lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
- lastAPSResult = determineBasalResultSMB;
- lastAPSRun = now;
- }
- rxBus.send(new EventOpenAPSUpdateGui());
-
- //deviceStatus.suggested = determineBasalResultAMA.json;
- }
-
- @NotNull
- @Override
- public Constraint isSuperBolusEnabled(Constraint value) {
- value.set(getAapsLogger(), false);
- return value;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt
new file mode 100644
index 0000000000..c57e427194
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt
@@ -0,0 +1,201 @@
+package info.nightscout.androidaps.plugins.aps.openAPSSMB
+
+import android.content.Context
+import androidx.preference.PreferenceFragmentCompat
+import androidx.preference.SwitchPreference
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
+import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
+import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.HardLimits
+import info.nightscout.androidaps.utils.Profiler
+import info.nightscout.androidaps.utils.Round
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+open class OpenAPSSMBPlugin @Inject constructor(
+ injector: HasAndroidInjector,
+ aapsLogger: AAPSLogger,
+ private val rxBus: RxBusWrapper,
+ private val constraintChecker: ConstraintChecker,
+ resourceHelper: ResourceHelper,
+ private val profileFunction: ProfileFunction,
+ private val context: Context,
+ private val activePlugin: ActivePluginProvider,
+ private val treatmentsPlugin: TreatmentsInterface,
+ private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
+ private val hardLimits: HardLimits,
+ private val profiler: Profiler,
+ private val sp: SP
+) : PluginBase(PluginDescription()
+ .mainType(PluginType.APS)
+ .fragmentClass(OpenAPSSMBFragment::class.java.name)
+ .pluginIcon(R.drawable.ic_generic_icon)
+ .pluginName(R.string.openapssmb)
+ .shortName(R.string.smb_shortname)
+ .preferencesId(R.xml.pref_openapssmb)
+ .description(R.string.description_smb)
+ .setDefault(),
+ aapsLogger, resourceHelper, injector
+), APSInterface, ConstraintsInterface {
+
+ // last values
+ override var lastAPSRun: Long = 0
+ override var lastAPSResult: DetermineBasalResultSMB? = null
+ var lastDetermineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS? = null
+ var lastAutosensResult = AutosensResult()
+
+ override fun specialEnableCondition(): Boolean {
+ return try {
+ activePlugin.activePump.pumpDescription.isTempBasalCapable
+ } catch (ignored: Exception) {
+ // may fail during initialization
+ true
+ }
+ }
+
+ override fun specialShowInListCondition(): Boolean {
+ val pump = activePlugin.activePump
+ return pump.pumpDescription.isTempBasalCapable
+ }
+
+ override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
+ super.preprocessPreferences(preferenceFragment)
+ val smbAlwaysEnabled = sp.getBoolean(R.string.key_enableSMB_always, false)
+ preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_COB))?.isVisible = !smbAlwaysEnabled
+ preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_temptarget))?.isVisible = !smbAlwaysEnabled
+ preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_after_carbs))?.isVisible = !smbAlwaysEnabled
+ }
+
+ override fun invoke(initiator: String, tempBasalFallback: Boolean) {
+ aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback")
+ lastAPSResult = null
+ val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
+ val profile = profileFunction.getProfile()
+ val pump = activePlugin.activePump
+ if (profile == null) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)))
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
+ return
+ }
+ if (!isEnabled(PluginType.APS)) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)))
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled))
+ return
+ }
+ if (glucoseStatus == null) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)))
+ aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata))
+ return
+ }
+
+ val inputConstraints = Constraint(0.0) // fake. only for collecting all results
+ val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
+ inputConstraints.copyReasons(it)
+ }.value()
+ var start = System.currentTimeMillis()
+ var startPart = System.currentTimeMillis()
+ profiler.log(LTag.APS, "getMealData()", startPart)
+ val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
+ inputConstraints.copyReasons(maxIOBAllowedConstraint)
+ }.value()
+
+ var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetLowMgdl, 0.1), "minBg", hardLimits.VERY_HARD_LIMIT_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MIN_BG[1].toDouble())
+ var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
+ var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
+ var isTempTarget = false
+ treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
+ isTempTarget = true
+ minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
+ maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
+ targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
+ }
+ if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
+ if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return
+ if (!hardLimits.checkOnlyHardLimits(profile.isfMgdl, "sens", hardLimits.MINISF, hardLimits.MAXISF)) return
+ if (!hardLimits.checkOnlyHardLimits(profile.maxDailyBasal, "max_daily_basal", 0.02, hardLimits.maxBasal())) return
+ if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, "current_basal", 0.01, hardLimits.maxBasal())) return
+ startPart = System.currentTimeMillis()
+ if (constraintChecker.isAutosensModeEnabled().value()) {
+ val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin")
+ if (autosensData == null) {
+ rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
+ return
+ }
+ lastAutosensResult = autosensData.autosensResult
+ } else {
+ lastAutosensResult.sensResult = "autosens disabled"
+ }
+ val iobArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
+ profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
+ startPart = System.currentTimeMillis()
+ val smbAllowed = Constraint(!tempBasalFallback).also {
+ constraintChecker.isSMBModeEnabled(it)
+ inputConstraints.copyReasons(it)
+ }
+ val advancedFiltering = Constraint(!tempBasalFallback).also {
+ constraintChecker.isAdvancedFilteringEnabled(it)
+ inputConstraints.copyReasons(it)
+ }
+ val uam = Constraint(true).also {
+ constraintChecker.isUAMEnabled(it)
+ inputConstraints.copyReasons(it)
+ }
+ profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
+ profiler.log(LTag.APS, "SMB data gathering", start)
+ start = System.currentTimeMillis()
+
+ DetermineBasalAdapterSMBJS(ScriptReader(context), injector).also { determineBasalAdapterSMBJS ->
+ determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg,
+ activePlugin.activePump.baseBasalRate,
+ iobArray,
+ glucoseStatus,
+ iobCobCalculatorPlugin.mealData,
+ lastAutosensResult.ratio,
+ isTempTarget,
+ smbAllowed.value(),
+ uam.value(),
+ advancedFiltering.value(),
+ activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin")
+ val now = System.currentTimeMillis()
+ val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
+ profiler.log(LTag.APS, "SMB calculation", start)
+ if (determineBasalResultSMB == null) {
+ aapsLogger.error(LTag.APS, "SMB calculation returned null")
+ lastDetermineBasalAdapterSMBJS = null
+ lastAPSResult = null
+ lastAPSRun = 0
+ } else {
+ // TODO still needed with oref1?
+ // Fix bug determine basal
+ if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultSMB.tempBasalRequested = false
+ determineBasalResultSMB.iob = iobArray[0]
+ determineBasalResultSMB.json?.put("timestamp", DateUtil.toISOString(now))
+ determineBasalResultSMB.inputConstraints = inputConstraints
+ lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS
+ lastAPSResult = determineBasalResultSMB
+ lastAPSRun = now
+ }
+ }
+ rxBus.send(EventOpenAPSUpdateGui())
+ }
+
+ override fun isSuperBolusEnabled(value: Constraint): Constraint {
+ value[aapsLogger] = false
+ return value
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt
index 5bd7e72a60..8a19808833 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt
@@ -18,7 +18,7 @@ import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt
index 4fb140d55a..3f54b6e616 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt
@@ -9,9 +9,10 @@ import info.nightscout.androidaps.events.EventRebuildTabs
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.util.*
@@ -25,7 +26,8 @@ class ConfigBuilderPlugin @Inject constructor(
resourceHelper: ResourceHelper,
private val sp: SP,
private val rxBus: RxBusWrapper,
- private val activePlugin: ActivePluginProvider
+ private val activePlugin: ActivePluginProvider,
+ private val uel: UserEntryLogger
) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(ConfigBuilderFragment::class.java.name)
@@ -137,9 +139,10 @@ class ConfigBuilderPlugin @Inject constructor(
if (allowHardwarePump || activity == null) {
performPluginSwitch(changedPlugin, newState, type)
} else {
- showConfirmation(activity, resourceHelper.gs(R.string.allow_hardware_pump_text), Runnable {
+ OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.allow_hardware_pump_text), Runnable {
performPluginSwitch(changedPlugin, newState, type)
sp.putBoolean("allow_hardware_pump", true)
+ uel.log("HW PUMP ALLOWED")
aapsLogger.debug(LTag.PUMP, "First time HW pump allowed!")
}, Runnable {
rxBus.send(EventConfigBuilderUpdateGui())
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
index f12c4b5b93..63c1719a45 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
@@ -22,6 +22,7 @@ import info.nightscout.androidaps.databinding.ObjectivesItemBinding
import info.nightscout.androidaps.dialogs.NtpProgressDialog
import info.nightscout.androidaps.events.EventNtpStatus
import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
@@ -33,7 +34,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.SntpClient
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
@@ -52,6 +53,7 @@ class ObjectivesFragment : DaggerFragment() {
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var sntpClient: SntpClient
+ @Inject lateinit var uel: UserEntryLogger
private val objectivesAdapter = ObjectivesAdapter()
private val handler = Handler(Looper.getMainLooper())
@@ -194,19 +196,19 @@ class ObjectivesFragment : DaggerFragment() {
if (task.shouldBeIgnored()) continue
// name
val name = TextView(holder.binding.progress.context)
- name.text = resourceHelper.gs(task.task) + ":"
+ name.text = "${resourceHelper.gs(task.task)}:"
name.setTextColor(-0x1)
holder.binding.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
// hint
task.hints.forEach { h ->
- if (!task.isCompleted)
- holder.binding.progress.addView(h.generate(context))
+ if (!task.isCompleted())
+ context?.let { holder.binding.progress.addView(h.generate(it)) }
}
// state
val state = TextView(holder.binding.progress.context)
state.setTextColor(-0x1)
val basicHTML = "%2\$s "
- val formattedHTML = String.format(basicHTML, if (task.isCompleted) "#4CAF50" else "#FF9800", task.progress)
+ val formattedHTML = String.format(basicHTML, if (task.isCompleted()) "#4CAF50" else "#FF9800", task.progress)
state.text = HtmlHelper.fromHtml(formattedHTML)
state.gravity = Gravity.END
holder.binding.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
@@ -305,6 +307,7 @@ class ObjectivesFragment : DaggerFragment() {
holder.binding.unstart.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable {
+ uel.log("OBJECTIVE UNSTARTED", i1 = position + 1)
objective.startedOn = 0
scrollToCurrentObjective()
rxBus.send(EventObjectivesUpdateGui())
@@ -329,7 +332,7 @@ class ObjectivesFragment : DaggerFragment() {
holder.binding.inputhint.visibility = View.VISIBLE
holder.binding.enterbutton.setOnClickListener {
val input = holder.binding.input.text.toString()
- objective.specialAction(activity, input)
+ activity?.let { activity -> objective.specialAction(activity, input) }
rxBus.send(EventObjectivesUpdateGui())
}
} else {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt
index 009812a1f2..561760abe7 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt
@@ -9,6 +9,7 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
@@ -25,8 +26,8 @@ class ObjectivesPlugin @Inject constructor(
resourceHelper: ResourceHelper,
private val activePlugin: ActivePluginProvider,
private val sp: SP,
- private val config: Config
-
+ config: Config,
+ private val uel: UserEntryLogger
) : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.fragmentClass(ObjectivesFragment::class.qualifiedName)
@@ -141,6 +142,7 @@ class ObjectivesPlugin @Inject constructor(
sp.putLong("Objectives_" + "auto" + "_accomplished", DateUtil.now())
setupObjectives()
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeaccepted))
+ uel.log("OBJECTIVES SKIPPED")
} else {
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeinvalid))
}
@@ -163,7 +165,7 @@ class ObjectivesPlugin @Inject constructor(
return value
}
- fun isLgsAllowed(value: Constraint): Constraint {
+ override fun isLgsAllowed(value: Constraint): Constraint {
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXBASAL_OBJECTIVE + 1), this)
return value
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt
index 97da62bbac..c45d61bfd4 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt
@@ -80,28 +80,30 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
// Options
binding.examOptions.removeAllViews()
task.options.forEach {
- val cb = it.generate(context)
- if (task.answered) {
- cb.isEnabled = false
- if (it.isCorrect)
- cb.isChecked = true
+ context?.let { context ->
+ val cb = it.generate(context)
+ if (task.answered) {
+ cb.isEnabled = false
+ if (it.isCorrect)
+ cb.isChecked = true
+ }
+ binding.examOptions.addView(cb)
}
- binding.examOptions.addView(cb)
}
// Hints
binding.examHints.removeAllViews()
for (h in task.hints) {
- binding.examHints.addView(h.generate(context))
+ context?.let { binding.examHints.addView(h.generate(it)) }
}
// Disabled to
binding.examDisabledto.text = resourceHelper.gs(R.string.answerdisabledto, dateUtil.timeString(task.disabledTo))
- binding.examDisabledto.visibility = if (task.isEnabledAnswer) View.GONE else View.VISIBLE
+ binding.examDisabledto.visibility = if (task.isEnabledAnswer()) View.GONE else View.VISIBLE
// Buttons
- binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer
+ binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer()
binding.examVerify.setOnClickListener {
var result = true
for (o in task.options) {
- val option: Option = o as Option
+ val option: Option = o
result = result && option.evaluate()
}
task.answered = result
@@ -133,14 +135,14 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
binding.nextUnansweredButton.isEnabled = !objective.isCompleted
binding.nextUnansweredButton.setOnClickListener {
for (i in (currentTask + 1) until objective.tasks.size) {
- if (!objective.tasks[i].isCompleted) {
+ if (!objective.tasks[i].isCompleted()) {
currentTask = i
updateGui()
return@setOnClickListener
}
}
for (i in 0..currentTask) {
- if (!objective.tasks[i].isCompleted) {
+ if (!objective.tasks[i].isCompleted()) {
currentTask = i
updateGui()
return@setOnClickListener
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java
deleted file mode 100644
index 95942c4ed2..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java
+++ /dev/null
@@ -1,295 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.text.util.Linkify;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import androidx.annotation.StringRes;
-import androidx.fragment.app.FragmentActivity;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.T;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-public abstract class Objective {
- @Inject public SP sp;
- @Inject public ResourceHelper resourceHelper;
-
- private final String spName;
- @StringRes private final int objective;
- @StringRes private final int gate;
- private long startedOn;
- private long accomplishedOn;
- List tasks = new ArrayList<>();
- public boolean hasSpecialInput = false;
-
- public Objective(HasAndroidInjector injector, String spName, @StringRes int objective, @StringRes int gate) {
- injector.androidInjector().inject(this);
- this.spName = spName;
- this.objective = objective;
- this.gate = gate;
- startedOn = sp.getLong("Objectives_" + spName + "_started", 0L);
- accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 0L);
- if ((accomplishedOn - DateUtil.now()) > T.hours(3).msecs() || (startedOn - DateUtil.now()) > T.hours(3).msecs()) { // more than 3 hours in the future
- startedOn = 0;
- accomplishedOn = 0;
- }
- setupTasks(tasks);
- for (Task task : tasks) task.objective = this;
- }
-
- public boolean isCompleted() {
- for (Task task : tasks) {
- if (!task.shouldBeIgnored() && !task.isCompleted())
- return false;
- }
- return true;
- }
-
- public boolean isCompleted(long trueTime) {
- for (Task task : tasks) {
- if (!task.shouldBeIgnored() && !task.isCompleted(trueTime))
- return false;
- }
- return true;
- }
-
- public boolean isAccomplished() {
- return accomplishedOn != 0 && accomplishedOn < DateUtil.now();
- }
-
- public boolean isStarted() {
- return startedOn != 0;
- }
-
- public long getStartedOn() {
- return startedOn;
- }
-
- public int getObjective() {
- return objective;
- }
-
- public int getGate() {
- return gate;
- }
-
- public void setStartedOn(long startedOn) {
- this.startedOn = startedOn;
- sp.putLong("Objectives_" + spName + "_started", startedOn);
- }
-
- public void setAccomplishedOn(long accomplishedOn) {
- this.accomplishedOn = accomplishedOn;
- sp.putLong("Objectives_" + spName + "_accomplished", accomplishedOn);
- }
-
- public long getAccomplishedOn() {
- return accomplishedOn;
- }
-
- protected void setupTasks(List tasks) {
-
- }
-
- public List getTasks() {
- return tasks;
- }
-
- public boolean specialActionEnabled() {
- return true;
- }
-
- public void specialAction(FragmentActivity activity, String input) {
- }
-
- public abstract class Task {
- @StringRes
- private final int task;
- private Objective objective;
- ArrayList hints = new ArrayList<>();
-
- public Task(@StringRes int task) {
- this.task = task;
- }
-
- public @StringRes int getTask() {
- return task;
- }
-
- protected Objective getObjective() {
- return objective;
- }
-
- public abstract boolean isCompleted();
-
- public boolean isCompleted(long trueTime) {
- return isCompleted();
- }
-
- public String getProgress() {
- return resourceHelper.gs(isCompleted() ? R.string.completed_well_done : R.string.not_completed_yet);
- }
-
- Task hint(Hint hint) {
- hints.add(hint);
- return this;
- }
-
- public ArrayList getHints() {
- return hints;
- }
-
- public boolean shouldBeIgnored() {
- return false;
- }
- }
-
- public class MinimumDurationTask extends Task {
-
- private final long minimumDuration;
-
- MinimumDurationTask(long minimumDuration) {
- super(R.string.time_elapsed);
- this.minimumDuration = minimumDuration;
- }
-
- @Override
- public boolean isCompleted() {
- return getObjective().isStarted() && System.currentTimeMillis() - getObjective().getStartedOn() >= minimumDuration;
- }
-
- @Override
- public boolean isCompleted(long trueTime) {
- return getObjective().isStarted() && trueTime - getObjective().getStartedOn() >= minimumDuration;
- }
-
- @Override
- public String getProgress() {
- return getDurationText(System.currentTimeMillis() - getObjective().getStartedOn())
- + " / " + getDurationText(minimumDuration);
- }
-
- private String getDurationText(long duration) {
- int days = (int) Math.floor((double) duration / T.days(1).msecs());
- int hours = (int) Math.floor((double) duration / T.hours(1).msecs());
- int minutes = (int) Math.floor((double) duration / T.mins(1).msecs());
- if (days > 0) return resourceHelper.gq(R.plurals.days, days, days);
- else if (hours > 0) return resourceHelper.gq(R.plurals.hours, hours, hours);
- else return resourceHelper.gq(R.plurals.minutes, minutes, minutes);
- }
- }
-
- public class ExamTask extends Task {
- @StringRes
- int question;
- ArrayList options = new ArrayList<>();
- private final String spIdentifier;
- private boolean answered;
- private long disabledTo;
-
- ExamTask(@StringRes int task, @StringRes int question, String spIdentifier) {
- super(task);
- this.question = question;
- this.spIdentifier = spIdentifier;
- answered = sp.getBoolean("ExamTask_" + spIdentifier, false);
- disabledTo = sp.getLong("DisabledTo_" + spIdentifier, 0L);
- }
-
- public void setDisabledTo(long newState) {
- disabledTo = newState;
- sp.putLong("DisabledTo_" + spIdentifier, disabledTo);
- }
-
- public long getDisabledTo() {
- return disabledTo;
- }
-
- public boolean isEnabledAnswer() {
- return disabledTo < DateUtil.now();
- }
-
- public void setAnswered(boolean newState) {
- answered = newState;
- sp.putBoolean("ExamTask_" + spIdentifier, answered);
- }
-
- public boolean getAnswered() {
- return answered;
- }
-
- ExamTask option(Option option) {
- options.add(option);
- return this;
- }
-
- public @StringRes int getQuestion() {
- return question;
- }
-
- public List getOptions() {
- return options;
- }
-
- @Override
- public boolean isCompleted() {
- return answered;
- }
- }
-
- public class Option {
- @StringRes int option;
- boolean isCorrect;
-
- CheckBox cb; // TODO: change it, this will block releasing memeory
-
- Option(@StringRes int option, boolean isCorrect) {
- this.option = option;
- this.isCorrect = isCorrect;
- }
-
- public boolean isCorrect() {
- return isCorrect;
- }
-
- public CheckBox generate(Context context) {
- cb = new CheckBox(context);
- cb.setText(option);
- return cb;
- }
-
- public boolean evaluate() {
- boolean selection = cb.isChecked();
- if (selection && isCorrect) return true;
- return !selection && !isCorrect;
- }
- }
-
- public class Hint {
- @StringRes int hint;
-
- Hint(@StringRes int hint) {
- this.hint = hint;
- }
-
- public TextView generate(Context context) {
- TextView textView = new TextView(context);
- textView.setText(hint);
- textView.setAutoLinkMask(Linkify.WEB_URLS);
- textView.setLinksClickable(true);
- textView.setLinkTextColor(Color.YELLOW);
- Linkify.addLinks(textView, Linkify.WEB_URLS);
- return textView;
- }
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.kt
new file mode 100644
index 0000000000..876fb881db
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.kt
@@ -0,0 +1,183 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import android.content.Context
+import android.graphics.Color
+import android.text.util.Linkify
+import android.widget.CheckBox
+import android.widget.TextView
+import androidx.annotation.StringRes
+import androidx.fragment.app.FragmentActivity
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.T
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import java.util.*
+import javax.inject.Inject
+import kotlin.math.floor
+
+abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRes objective: Int, @StringRes gate: Int) {
+
+ @Inject lateinit var sp: SP
+ @Inject lateinit var resourceHelper: ResourceHelper
+
+ private val spName: String
+ @StringRes val objective: Int
+ @StringRes val gate: Int
+ var startedOn: Long = 0
+ set(value) {
+ field = value
+ sp.putLong("Objectives_" + spName + "_started", startedOn)
+ }
+ var accomplishedOn: Long = 0
+ set(value) {
+ field = value
+ sp.putLong("Objectives_" + spName + "_accomplished", value)
+ }
+
+ var tasks: MutableList = ArrayList()
+
+ var hasSpecialInput = false
+
+ val isCompleted: Boolean
+ get() {
+ for (task in tasks) {
+ if (!task.shouldBeIgnored() && !task.isCompleted()) return false
+ }
+ return true
+ }
+
+ init {
+ injector.androidInjector().inject(this)
+ this.spName = spName
+ this.objective = objective
+ this.gate = gate
+ startedOn = sp.getLong("Objectives_" + spName + "_started", 0L)
+ accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 0L)
+ if (accomplishedOn - DateUtil.now() > T.hours(3).msecs() || startedOn - DateUtil.now() > T.hours(3).msecs()) { // more than 3 hours in the future
+ startedOn = 0
+ accomplishedOn = 0
+ }
+ }
+
+ fun isCompleted(trueTime: Long): Boolean {
+ for (task in tasks) {
+ if (!task.shouldBeIgnored() && !task.isCompleted(trueTime)) return false
+ }
+ return true
+ }
+
+ val isAccomplished: Boolean
+ get() = accomplishedOn != 0L && accomplishedOn < DateUtil.now()
+ val isStarted: Boolean
+ get() = startedOn != 0L
+
+ open fun specialActionEnabled(): Boolean {
+ return true
+ }
+
+ open fun specialAction(activity: FragmentActivity, input: String) {}
+
+ abstract inner class Task(var objective: Objective, @StringRes val task: Int) {
+
+ var hints = ArrayList()
+
+ abstract fun isCompleted(): Boolean
+
+ open fun isCompleted(trueTime: Long): Boolean = isCompleted
+
+ open val progress: String
+ get() = resourceHelper.gs(if (isCompleted) R.string.completed_well_done else R.string.not_completed_yet)
+
+ fun hint(hint: Hint): Task {
+ hints.add(hint)
+ return this
+ }
+
+ open fun shouldBeIgnored(): Boolean = false
+ }
+
+ inner class MinimumDurationTask internal constructor(objective: Objective, private val minimumDuration: Long) : Task(objective, R.string.time_elapsed) {
+
+ override fun isCompleted(): Boolean =
+ objective.isStarted && System.currentTimeMillis() - objective.startedOn >= minimumDuration
+
+ override fun isCompleted(trueTime: Long): Boolean {
+ return objective.isStarted && trueTime - objective.startedOn >= minimumDuration
+ }
+
+ override val progress: String
+ get() = (getDurationText(System.currentTimeMillis() - objective.startedOn)
+ + " / " + getDurationText(minimumDuration))
+
+ private fun getDurationText(duration: Long): String {
+ val days = floor(duration.toDouble() / T.days(1).msecs()).toInt()
+ val hours = floor(duration.toDouble() / T.hours(1).msecs()).toInt()
+ val minutes = floor(duration.toDouble() / T.mins(1).msecs()).toInt()
+ return when {
+ days > 0 -> resourceHelper.gq(R.plurals.days, days, days)
+ hours > 0 -> resourceHelper.gq(R.plurals.hours, hours, hours)
+ else -> resourceHelper.gq(R.plurals.minutes, minutes, minutes)
+ }
+ }
+ }
+
+ inner class ExamTask internal constructor(objective: Objective, @StringRes task: Int, @StringRes val question: Int, private val spIdentifier: String) : Task(objective, task) {
+
+ var options = ArrayList()
+ var answered: Boolean = false
+ set(value) {
+ field = value
+ sp.putBoolean("ExamTask_$spIdentifier", value)
+ }
+ var disabledTo: Long = 0
+ set(value) {
+ field = value
+ sp.putLong("DisabledTo_$spIdentifier", value)
+ }
+
+ init {
+ answered = sp.getBoolean("ExamTask_$spIdentifier", false)
+ disabledTo = sp.getLong("DisabledTo_$spIdentifier", 0L)
+ }
+
+ override fun isCompleted(): Boolean = answered
+
+ fun isEnabledAnswer(): Boolean = disabledTo < DateUtil.now()
+
+ fun option(option: Option): ExamTask {
+ options.add(option)
+ return this
+ }
+ }
+
+ inner class Option internal constructor(@StringRes var option: Int, var isCorrect: Boolean) {
+
+ var cb: CheckBox? = null // TODO: change it, this will block releasing memory
+
+ fun generate(context: Context): CheckBox {
+ cb = CheckBox(context)
+ cb?.setText(option)
+ return cb!!
+ }
+
+ fun evaluate(): Boolean {
+ val selection = cb!!.isChecked
+ return if (selection && isCorrect) true else !selection && !isCorrect
+ }
+ }
+
+ inner class Hint internal constructor(@StringRes var hint: Int) {
+
+ fun generate(context: Context): TextView {
+ val textView = TextView(context)
+ textView.setText(hint)
+ textView.autoLinkMask = Linkify.WEB_URLS
+ textView.linksClickable = true
+ textView.setLinkTextColor(Color.YELLOW)
+ Linkify.addLinks(textView, Linkify.WEB_URLS)
+ return textView
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.java
deleted file mode 100644
index 95242b6e73..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.APSInterface;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
-import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
-import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-public class Objective0 extends Objective {
- @Inject SP sp;
- @Inject ActivePluginProvider activePlugin;
- @Inject VirtualPumpPlugin virtualPumpPlugin;
- @Inject TreatmentsPlugin treatmentsPlugin;
- @Inject LoopPlugin loopPlugin;
- @Inject NSClientPlugin nsClientPlugin;
- @Inject IobCobCalculatorPlugin iobCobCalculatorPlugin;
-
- public Objective0(HasAndroidInjector injector) {
- super(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new Task(R.string.objectives_bgavailableinns) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false);
- }
- });
- tasks.add(new Task(R.string.nsclienthaswritepermission) {
- @Override
- public boolean isCompleted() {
- return nsClientPlugin.hasWritePermission();
- }
- });
- tasks.add(new Task(R.string.virtualpump_uploadstatus_title) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_virtualpump_uploadstatus, false);
- }
-
- @Override
- public boolean shouldBeIgnored() {
- return !virtualPumpPlugin.isEnabled(PluginType.PUMP);
- }
- });
- tasks.add(new Task(R.string.objectives_pumpstatusavailableinns) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false);
- }
- });
- tasks.add(new Task(R.string.hasbgdata) {
- @Override
- public boolean isCompleted() {
- return iobCobCalculatorPlugin.lastBg() != null;
- }
- });
- tasks.add(new Task(R.string.loopenabled) {
- @Override
- public boolean isCompleted() {
- return loopPlugin.isEnabled(PluginType.LOOP);
- }
- });
- tasks.add(new Task(R.string.apsselected) {
- @Override
- public boolean isCompleted() {
- APSInterface usedAPS = activePlugin.getActiveAPS();
- return ((PluginBase) usedAPS).isEnabled(PluginType.APS);
- }
- });
- tasks.add(new Task(R.string.activate_profile) {
- @Override
- public boolean isCompleted() {
- return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null;
- }
- });
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt
new file mode 100644
index 0000000000..63eaa326fc
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt
@@ -0,0 +1,72 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.ActivePluginProvider
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
+import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import javax.inject.Inject
+
+class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate) {
+
+ @Inject lateinit var activePlugin: ActivePluginProvider
+ @Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
+ @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
+ @Inject lateinit var loopPlugin: LoopPlugin
+ @Inject lateinit var nsClientPlugin: NSClientPlugin
+ @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
+
+ init {
+ tasks.add(object : Task(this, R.string.objectives_bgavailableinns) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false)
+ }
+ })
+ tasks.add(object : Task(this, R.string.nsclienthaswritepermission) {
+ override fun isCompleted(): Boolean {
+ return nsClientPlugin.hasWritePermission()
+ }
+ })
+ tasks.add(object : Task(this, R.string.virtualpump_uploadstatus_title) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_virtualpump_uploadstatus, false)
+ }
+
+ override fun shouldBeIgnored(): Boolean {
+ return !virtualPumpPlugin.isEnabled(PluginType.PUMP)
+ }
+ })
+ tasks.add(object : Task(this, R.string.objectives_pumpstatusavailableinns) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false)
+ }
+ })
+ tasks.add(object : Task(this, R.string.hasbgdata) {
+ override fun isCompleted(): Boolean {
+ return iobCobCalculatorPlugin.lastBg() != null
+ }
+ })
+ tasks.add(object : Task(this, R.string.loopenabled) {
+ override fun isCompleted(): Boolean {
+ return loopPlugin.isEnabled(PluginType.LOOP)
+ }
+ })
+ tasks.add(object : Task(this, R.string.apsselected) {
+ override fun isCompleted(): Boolean {
+ val usedAPS = activePlugin.activeAPS
+ return (usedAPS as PluginBase).isEnabled(PluginType.APS)
+ }
+ })
+ tasks.add(object : Task(this, R.string.activate_profile) {
+ override fun isCompleted(): Boolean {
+ return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.java
deleted file mode 100644
index 057a5ef556..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-public class Objective1 extends Objective {
- @Inject SP sp;
- @Inject ActionsPlugin actionsPlugin;
-
- @Inject
- public Objective1(HasAndroidInjector injector) {
- super(injector, "usage", R.string.objectives_usage_objective, R.string.objectives_usage_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new Task(R.string.objectives_useprofileswitch) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_objectiveuseprofileswitch, false);
- }
- });
- tasks.add(new Task(R.string.objectives_usedisconnectpump) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_objectiveusedisconnect, false);
- }
- }.hint(new Hint(R.string.disconnectpump_hint)));
- tasks.add(new Task(R.string.objectives_usereconnectpump) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_objectiveusereconnect, false);
- }
- }.hint(new Hint(R.string.disconnectpump_hint)));
- tasks.add(new Task(R.string.objectives_usetemptarget) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_objectiveusetemptarget, false);
- }
- }.hint(new Hint(R.string.usetemptarget_hint)));
- tasks.add(new Task(R.string.objectives_useactions) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_objectiveuseactions, false) && actionsPlugin.isEnabled(PluginType.GENERAL) && actionsPlugin.isFragmentVisible();
- }
- }.hint(new Hint(R.string.useaction_hint)));
- tasks.add(new Task(R.string.objectives_useloop) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_objectiveuseloop, false);
- }
- }.hint(new Hint(R.string.useaction_hint)));
- tasks.add(new Task(R.string.objectives_usescale) {
- @Override
- public boolean isCompleted() {
- return sp.getBoolean(R.string.key_objectiveusescale, false);
- }
- }.hint(new Hint(R.string.usescale_hint)));
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.kt
new file mode 100644
index 0000000000..91fb901033
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.kt
@@ -0,0 +1,50 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
+import javax.inject.Inject
+
+class Objective1 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "usage", R.string.objectives_usage_objective, R.string.objectives_usage_gate) {
+
+ @Inject lateinit var actionsPlugin: ActionsPlugin
+
+ init {
+ tasks.add(object : Task(this, R.string.objectives_useprofileswitch) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_objectiveuseprofileswitch, false)
+ }
+ })
+ tasks.add(object : Task(this, R.string.objectives_usedisconnectpump) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_objectiveusedisconnect, false)
+ }
+ }.hint(Hint(R.string.disconnectpump_hint)))
+ tasks.add(object : Task(this, R.string.objectives_usereconnectpump) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_objectiveusereconnect, false)
+ }
+ }.hint(Hint(R.string.disconnectpump_hint)))
+ tasks.add(object : Task(this, R.string.objectives_usetemptarget) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_objectiveusetemptarget, false)
+ }
+ }.hint(Hint(R.string.usetemptarget_hint)))
+ tasks.add(object : Task(this, R.string.objectives_useactions) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_objectiveuseactions, false) && actionsPlugin.isEnabled(PluginType.GENERAL) && actionsPlugin.isFragmentVisible()
+ }
+ }.hint(Hint(R.string.useaction_hint)))
+ tasks.add(object : Task(this, R.string.objectives_useloop) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_objectiveuseloop, false)
+ }
+ }.hint(Hint(R.string.useaction_hint)))
+ tasks.add(object : Task(this, R.string.objectives_usescale) {
+ override fun isCompleted(): Boolean {
+ return sp.getBoolean(R.string.key_objectiveusescale, false)
+ }
+ }.hint(Hint(R.string.usescale_hint)))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective10.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective10.java
deleted file mode 100644
index a9257f15a2..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective10.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.utils.T;
-
-public class Objective10 extends Objective {
-
- public Objective10(HasAndroidInjector injector) {
- super(injector, "auto", R.string.objectives_auto_objective, R.string.objectives_auto_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(28).msecs()));
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective10.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective10.kt
new file mode 100644
index 0000000000..2a41557913
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective10.kt
@@ -0,0 +1,12 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.T
+
+class Objective10(injector: HasAndroidInjector) : Objective(injector, "auto", R.string.objectives_auto_objective, R.string.objectives_auto_gate) {
+
+ init {
+ tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.java
deleted file mode 100644
index a4e9142063..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.Collections;
-import java.util.List;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-
-public class Objective2 extends Objective {
-
-
- public Objective2(HasAndroidInjector injector) {
- super(injector, "exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate);
- for (Task task : tasks) {
- if (!task.isCompleted()) setAccomplishedOn(0);
- }
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new ExamTask(R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
- .option(new Option(R.string.prerequisites_nightscout, true))
- .option(new Option(R.string.prerequisites_computer, true))
- .option(new Option(R.string.prerequisites_pump, true))
- .option(new Option(R.string.prerequisites_beanandroiddeveloper, false))
- .hint(new Hint(R.string.prerequisites_hint1))
- );
- tasks.add(new ExamTask(R.string.prerequisites2_label, R.string.prerequisites2_what, "prerequisites2")
- .option(new Option(R.string.prerequisites2_profile, true))
- .option(new Option(R.string.prerequisites2_device, true))
- .option(new Option(R.string.prerequisites2_internet, false))
- .option(new Option(R.string.prerequisites2_supportedcgm, true))
- .hint(new Hint(R.string.prerequisites2_hint1))
- );
- tasks.add(new ExamTask(R.string.basaltest_label, R.string.basaltest_when,"basaltest")
- .option(new Option(R.string.basaltest_fixed, false))
- .option(new Option(R.string.basaltest_havingregularhighlow, true))
- .option(new Option(R.string.basaltest_weekly, false))
- .option(new Option(R.string.basaltest_beforeloop, true))
- .hint(new Hint(R.string.basaltest_hint1))
- );
- tasks.add(new ExamTask(R.string.dia_label_exam, R.string.dia_whatmeansdia,"dia")
- .option(new Option(R.string.dia_profile, true))
- .option(new Option(R.string.dia_minimumis5h, true))
- .option(new Option(R.string.dia_meaningisequaltodiapump, false))
- .option(new Option(R.string.dia_valuemustbedetermined, true))
- .hint(new Hint(R.string.dia_hint1))
- );
- tasks.add(new ExamTask(R.string.isf_label_exam, R.string.blank,"isf")
- .option(new Option(R.string.isf_decreasingvalue, true))
- .option(new Option(R.string.isf_preferences, false))
- .option(new Option(R.string.isf_increasingvalue, false))
- .option(new Option(R.string.isf_noeffect, false))
- .hint(new Hint(R.string.isf_hint1))
- .hint(new Hint(R.string.isf_hint2))
- );
- tasks.add(new ExamTask(R.string.ic_label_exam, R.string.blank,"ic")
- .option(new Option(R.string.ic_increasingvalue, true))
- .option(new Option(R.string.ic_decreasingvalue, false))
- .option(new Option(R.string.ic_multiple, true))
- .option(new Option(R.string.ic_isf, false))
- .hint(new Hint(R.string.ic_hint1))
- );
- tasks.add(new ExamTask(R.string.hypott_label, R.string.hypott_whenhypott,"hypott")
- .option(new Option(R.string.hypott_preventoversmb, true))
- .option(new Option(R.string.hypott_exercise, false))
- .option(new Option(R.string.hypott_wrongbasal, false))
- .option(new Option(R.string.hypott_0basal, false))
- .hint(new Hint(R.string.hypott_hint1))
- );
- tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitch_pctwillchange,"profileswitch")
- .option(new Option(R.string.profileswitch_basallower, true))
- .option(new Option(R.string.profileswitch_isfhigher, true))
- .option(new Option(R.string.profileswitch_iclower, false))
- .option(new Option(R.string.profileswitch_unchanged, false))
- .hint(new Hint(R.string.profileswitch_hint1))
- );
- tasks.add(new ExamTask(R.string.profileswitch2_label, R.string.profileswitch2_pctwillchange,"profileswitch2")
- .option(new Option(R.string.profileswitch2_bghigher, false))
- .option(new Option(R.string.profileswitch2_basalhigher, true))
- .option(new Option(R.string.profileswitch2_bgunchanged, true))
- .option(new Option(R.string.profileswitch2_isfhigher, false))
- .hint(new Hint(R.string.profileswitch_hint1))
- );
- tasks.add(new ExamTask(R.string.profileswitchtime_label, R.string.profileswitchtime_iwant,"profileswitchtime")
- .option(new Option(R.string.profileswitchtime_2, false))
- .option(new Option(R.string.profileswitchtime__2, true))
- .option(new Option(R.string.profileswitchtime_tt, false))
- .option(new Option(R.string.profileswitchtime_100, false))
- .hint(new Hint(R.string.profileswitchtime_hint1))
- );
- tasks.add(new ExamTask(R.string.profileswitch4_label, R.string.blank,"profileswitch4")
- .option(new Option(R.string.profileswitch4_rates, true))
- .option(new Option(R.string.profileswitch4_internet, true))
- .option(new Option(R.string.profileswitch4_sufficient, false))
- .option(new Option(R.string.profileswitch4_multi, true))
- .hint(new Hint(R.string.profileswitch_hint1))
- );
- tasks.add(new ExamTask(R.string.exerciseprofile_label, R.string.exerciseprofile_whattodo,"exercise")
- .option(new Option(R.string.exerciseprofile_switchprofileabove100, false))
- .option(new Option(R.string.exerciseprofile_switchprofilebelow100, true))
- .option(new Option(R.string.exerciseprofile_suspendloop, false))
- .option(new Option(R.string.exerciseprofile_leaveat100, false))
- .hint(new Hint(R.string.exerciseprofile_hint1))
- );
- tasks.add(new ExamTask(R.string.exercise_label, R.string.exercise_whattodo,"exercise2")
- .option(new Option(R.string.exercise_settt, true))
- .option(new Option(R.string.exercise_setfinished, false))
- .option(new Option(R.string.exercise_setunchanged, false))
- .option(new Option(R.string.exercise_15g, false))
- .hint(new Hint(R.string.exercise_hint1))
- );
- tasks.add(new ExamTask(R.string.noisycgm_label, R.string.noisycgm_whattodo,"noisycgm")
- .option(new Option(R.string.noisycgm_nothing, false))
- .option(new Option(R.string.noisycgm_pause, true))
- .option(new Option(R.string.noisycgm_replacesensor, true))
- .option(new Option(R.string.noisycgm_checksmoothing, true))
- .hint(new Hint(R.string.noisycgm_hint1))
- );
- tasks.add(new ExamTask(R.string.pumpdisconnect_label, R.string.blank,"pumpdisconnect")
- .option(new Option(R.string.pumpdisconnect_unnecessary, false))
- .option(new Option(R.string.pumpdisconnect_missinginsulin, true))
- .option(new Option(R.string.pumpdisconnect_notstop, false))
- .option(new Option(R.string.pumpdisconnect_openloop, false))
- .hint(new Hint(R.string.pumpdisconnect_hint1))
- );
- tasks.add(new ExamTask(R.string.insulin_label, R.string.insulin_ultrarapid,"insulin")
- .option(new Option(R.string.insulin_novorapid, false))
- .option(new Option(R.string.insulin_humalog, false))
- .option(new Option(R.string.insulin_actrapid, false))
- .option(new Option(R.string.insulin_fiasp, true))
- .hint(new Hint(R.string.insulin_hint1))
- );
- tasks.add(new ExamTask(R.string.sensitivity_label, R.string.blank,"sensitivity")
- .option(new Option(R.string.sensitivity_adjust, true))
- .option(new Option(R.string.sensitivity_edit, false))
- .option(new Option(R.string.sensitivity_cannula, true))
- .option(new Option(R.string.sensitivity_time, true))
- .hint(new Hint(R.string.sensitivity_hint1))
- );
- tasks.add(new ExamTask(R.string.objectives_label, R.string.objectives_howtosave,"objectives")
- .option(new Option(R.string.objectives_notesettings, false))
- .option(new Option(R.string.objectives_afterobjective, true))
- .option(new Option(R.string.objectives_afterchange, true))
- .option(new Option(R.string.objectives_afterinitialsetup, true))
- .hint(new Hint(R.string.objectives_hint1))
- .hint(new Hint(R.string.objectives_hint2))
- );
- tasks.add(new ExamTask(R.string.objectives2_label, R.string.objectives_howtosave,"objectives2")
- .option(new Option(R.string.objectives2_maintenance, true))
- .option(new Option(R.string.objectives2_internalstorage, true))
- .option(new Option(R.string.objectives2_cloud, true))
- .option(new Option(R.string.objectives2_easyrestore, false))
- .hint(new Hint(R.string.objectives_hint1))
- .hint(new Hint(R.string.objectives_hint2))
- );
- tasks.add(new ExamTask(R.string.update_label, R.string.blank,"update")
- .option(new Option(R.string.update_git, true))
- .option(new Option(R.string.update_askfriend, false))
- .option(new Option(R.string.update_keys, true))
- .option(new Option(R.string.update_asap, true))
- .hint(new Hint(R.string.update_hint1))
- );
- tasks.add(new ExamTask(R.string.troubleshooting_label, R.string.troubleshooting_wheretoask,"troubleshooting")
- .option(new Option(R.string.troubleshooting_fb, true))
- .option(new Option(R.string.troubleshooting_wiki, true))
- .option(new Option(R.string.troubleshooting_gitter, true))
- .option(new Option(R.string.troubleshooting_yourendo, false))
- .hint(new Hint(R.string.troubleshooting_hint1))
- .hint(new Hint(R.string.troubleshooting_hint2))
- .hint(new Hint(R.string.troubleshooting_hint3))
- );
- tasks.add(new ExamTask(R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo,"wrongcarbs")
- .option(new Option(R.string.wrongcarbs_addinsulin, false))
- .option(new Option(R.string.wrongcarbs_treatmentstab, true))
- .option(new Option(R.string.wrongcarbs_donothing, false))
- .option(new Option(R.string.wrongcarbs_bolus, false))
- );
- tasks.add(new ExamTask(R.string.wronginsulin_label, R.string.wronginsulin_whattodo,"wronginsulin")
- .option(new Option(R.string.wronginsulin_careportal, false))
- .option(new Option(R.string.wronginsulin_compare, true))
- .option(new Option(R.string.wronginsulin_prime, true))
- .option(new Option(R.string.wrongcarbs_donothing, false))
- );
- tasks.add(new ExamTask(R.string.iob_label, R.string.blank,"iob")
- .option(new Option(R.string.iob_value, true))
- .option(new Option(R.string.iob_hightemp, false))
- .option(new Option(R.string.iob_negiob, true))
- .option(new Option(R.string.iob_posiob, true))
- );
- tasks.add(new ExamTask(R.string.breadgrams_label, R.string.blank,"breadgrams")
- .option(new Option(R.string.breadgrams_grams, true))
- .option(new Option(R.string.breadgrams_exchange, false))
- .option(new Option(R.string.breadgrams_decay, true))
- .option(new Option(R.string.breadgrams_calc, true))
- .hint(new Hint(R.string.breadgrams_hint1))
- );
- tasks.add(new ExamTask(R.string.extendedcarbs_label, R.string.extendedcarbs_handling,"extendedcarbs")
- .option(new Option(R.string.extendedcarbs_future, true))
- .option(new Option(R.string.extendedcarbs_free, false))
- .option(new Option(R.string.extendedcarbs_fat, true))
- .option(new Option(R.string.extendedcarbs_rescue, false))
- .hint(new Hint(R.string.extendedcarbs_hint1))
- );
- tasks.add(new ExamTask(R.string.nsclient_label, R.string.nsclient_howcanyou,"nsclient")
- .option(new Option(R.string.nsclient_nightscout, true))
- .option(new Option(R.string.nsclient_dexcomfollow, true))
- .option(new Option(R.string.nsclient_data, true))
- .option(new Option(R.string.nsclient_fullcontrol, false))
- .hint(new Hint(R.string.nsclient_hint1))
- );
- tasks.add(new ExamTask(R.string.other_medication_label, R.string.other_medication_text,"otherMedicationWarning")
- .option(new Option(R.string.yes, true))
- .option(new Option(R.string.no, false))
- );
-
- for (Task task : tasks)
- Collections.shuffle(((ExamTask)task).options);
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.kt
new file mode 100644
index 0000000000..34b1f7a3b9
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.kt
@@ -0,0 +1,211 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+
+@Suppress("SpellCheckingInspection")
+class Objective2(injector: HasAndroidInjector) : Objective(injector, "exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate) {
+
+ init {
+ tasks.add(ExamTask(this, R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
+ .option(Option(R.string.prerequisites_nightscout, true))
+ .option(Option(R.string.prerequisites_computer, true))
+ .option(Option(R.string.prerequisites_pump, true))
+ .option(Option(R.string.prerequisites_beanandroiddeveloper, false))
+ .hint(Hint(R.string.prerequisites_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.prerequisites2_label, R.string.prerequisites2_what, "prerequisites2")
+ .option(Option(R.string.prerequisites2_profile, true))
+ .option(Option(R.string.prerequisites2_device, true))
+ .option(Option(R.string.prerequisites2_internet, false))
+ .option(Option(R.string.prerequisites2_supportedcgm, true))
+ .hint(Hint(R.string.prerequisites2_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.basaltest_label, R.string.basaltest_when, "basaltest")
+ .option(Option(R.string.basaltest_fixed, false))
+ .option(Option(R.string.basaltest_havingregularhighlow, true))
+ .option(Option(R.string.basaltest_weekly, false))
+ .option(Option(R.string.basaltest_beforeloop, true))
+ .hint(Hint(R.string.basaltest_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.dia_label_exam, R.string.dia_whatmeansdia, "dia")
+ .option(Option(R.string.dia_profile, true))
+ .option(Option(R.string.dia_minimumis5h, true))
+ .option(Option(R.string.dia_meaningisequaltodiapump, false))
+ .option(Option(R.string.dia_valuemustbedetermined, true))
+ .hint(Hint(R.string.dia_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.isf_label_exam, R.string.blank, "isf")
+ .option(Option(R.string.isf_decreasingvalue, true))
+ .option(Option(R.string.isf_preferences, false))
+ .option(Option(R.string.isf_increasingvalue, false))
+ .option(Option(R.string.isf_noeffect, false))
+ .hint(Hint(R.string.isf_hint1))
+ .hint(Hint(R.string.isf_hint2))
+ )
+ tasks.add(ExamTask(this, R.string.ic_label_exam, R.string.blank, "ic")
+ .option(Option(R.string.ic_increasingvalue, true))
+ .option(Option(R.string.ic_decreasingvalue, false))
+ .option(Option(R.string.ic_multiple, true))
+ .option(Option(R.string.ic_isf, false))
+ .hint(Hint(R.string.ic_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.hypott_label, R.string.hypott_whenhypott, "hypott")
+ .option(Option(R.string.hypott_preventoversmb, true))
+ .option(Option(R.string.hypott_exercise, false))
+ .option(Option(R.string.hypott_wrongbasal, false))
+ .option(Option(R.string.hypott_0basal, false))
+ .hint(Hint(R.string.hypott_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.profileswitch_label, R.string.profileswitch_pctwillchange, "profileswitch")
+ .option(Option(R.string.profileswitch_basallower, true))
+ .option(Option(R.string.profileswitch_isfhigher, true))
+ .option(Option(R.string.profileswitch_iclower, false))
+ .option(Option(R.string.profileswitch_unchanged, false))
+ .hint(Hint(R.string.profileswitch_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.profileswitch2_label, R.string.profileswitch2_pctwillchange, "profileswitch2")
+ .option(Option(R.string.profileswitch2_bghigher, false))
+ .option(Option(R.string.profileswitch2_basalhigher, true))
+ .option(Option(R.string.profileswitch2_bgunchanged, true))
+ .option(Option(R.string.profileswitch2_isfhigher, false))
+ .hint(Hint(R.string.profileswitch_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.profileswitchtime_label, R.string.profileswitchtime_iwant, "profileswitchtime")
+ .option(Option(R.string.profileswitchtime_2, false))
+ .option(Option(R.string.profileswitchtime__2, true))
+ .option(Option(R.string.profileswitchtime_tt, false))
+ .option(Option(R.string.profileswitchtime_100, false))
+ .hint(Hint(R.string.profileswitchtime_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.profileswitch4_label, R.string.blank, "profileswitch4")
+ .option(Option(R.string.profileswitch4_rates, true))
+ .option(Option(R.string.profileswitch4_internet, true))
+ .option(Option(R.string.profileswitch4_sufficient, false))
+ .option(Option(R.string.profileswitch4_multi, true))
+ .hint(Hint(R.string.profileswitch_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.exerciseprofile_label, R.string.exerciseprofile_whattodo, "exercise")
+ .option(Option(R.string.exerciseprofile_switchprofileabove100, false))
+ .option(Option(R.string.exerciseprofile_switchprofilebelow100, true))
+ .option(Option(R.string.exerciseprofile_suspendloop, false))
+ .option(Option(R.string.exerciseprofile_leaveat100, false))
+ .hint(Hint(R.string.exerciseprofile_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.exercise_label, R.string.exercise_whattodo, "exercise2")
+ .option(Option(R.string.exercise_settt, true))
+ .option(Option(R.string.exercise_setfinished, false))
+ .option(Option(R.string.exercise_setunchanged, false))
+ .option(Option(R.string.exercise_15g, false))
+ .hint(Hint(R.string.exercise_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.noisycgm_label, R.string.noisycgm_whattodo, "noisycgm")
+ .option(Option(R.string.noisycgm_nothing, false))
+ .option(Option(R.string.noisycgm_pause, true))
+ .option(Option(R.string.noisycgm_replacesensor, true))
+ .option(Option(R.string.noisycgm_checksmoothing, true))
+ .hint(Hint(R.string.noisycgm_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.pumpdisconnect_label, R.string.blank, "pumpdisconnect")
+ .option(Option(R.string.pumpdisconnect_unnecessary, false))
+ .option(Option(R.string.pumpdisconnect_missinginsulin, true))
+ .option(Option(R.string.pumpdisconnect_notstop, false))
+ .option(Option(R.string.pumpdisconnect_openloop, false))
+ .hint(Hint(R.string.pumpdisconnect_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.insulin_label, R.string.insulin_ultrarapid, "insulin")
+ .option(Option(R.string.insulin_novorapid, false))
+ .option(Option(R.string.insulin_humalog, false))
+ .option(Option(R.string.insulin_actrapid, false))
+ .option(Option(R.string.insulin_fiasp, true))
+ .hint(Hint(R.string.insulin_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.sensitivity_label, R.string.blank, "sensitivity")
+ .option(Option(R.string.sensitivity_adjust, true))
+ .option(Option(R.string.sensitivity_edit, false))
+ .option(Option(R.string.sensitivity_cannula, true))
+ .option(Option(R.string.sensitivity_time, true))
+ .hint(Hint(R.string.sensitivity_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.objectives_label, R.string.objectives_howtosave, "objectives")
+ .option(Option(R.string.objectives_notesettings, false))
+ .option(Option(R.string.objectives_afterobjective, true))
+ .option(Option(R.string.objectives_afterchange, true))
+ .option(Option(R.string.objectives_afterinitialsetup, true))
+ .hint(Hint(R.string.objectives_hint1))
+ .hint(Hint(R.string.objectives_hint2))
+ )
+ tasks.add(ExamTask(this, R.string.objectives2_label, R.string.objectives_howtosave, "objectives2")
+ .option(Option(R.string.objectives2_maintenance, true))
+ .option(Option(R.string.objectives2_internalstorage, true))
+ .option(Option(R.string.objectives2_cloud, true))
+ .option(Option(R.string.objectives2_easyrestore, false))
+ .hint(Hint(R.string.objectives_hint1))
+ .hint(Hint(R.string.objectives_hint2))
+ )
+ tasks.add(ExamTask(this, R.string.update_label, R.string.blank, "update")
+ .option(Option(R.string.update_git, true))
+ .option(Option(R.string.update_askfriend, false))
+ .option(Option(R.string.update_keys, true))
+ .option(Option(R.string.update_asap, true))
+ .hint(Hint(R.string.update_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.troubleshooting_label, R.string.troubleshooting_wheretoask, "troubleshooting")
+ .option(Option(R.string.troubleshooting_fb, true))
+ .option(Option(R.string.troubleshooting_wiki, true))
+ .option(Option(R.string.troubleshooting_gitter, true))
+ .option(Option(R.string.troubleshooting_yourendo, false))
+ .hint(Hint(R.string.troubleshooting_hint1))
+ .hint(Hint(R.string.troubleshooting_hint2))
+ .hint(Hint(R.string.troubleshooting_hint3))
+ )
+ tasks.add(ExamTask(this, R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo, "wrongcarbs")
+ .option(Option(R.string.wrongcarbs_addinsulin, false))
+ .option(Option(R.string.wrongcarbs_treatmentstab, true))
+ .option(Option(R.string.wrongcarbs_donothing, false))
+ .option(Option(R.string.wrongcarbs_bolus, false))
+ )
+ tasks.add(ExamTask(this, R.string.wronginsulin_label, R.string.wronginsulin_whattodo, "wronginsulin")
+ .option(Option(R.string.wronginsulin_careportal, false))
+ .option(Option(R.string.wronginsulin_compare, true))
+ .option(Option(R.string.wronginsulin_prime, true))
+ .option(Option(R.string.wrongcarbs_donothing, false))
+ )
+ tasks.add(ExamTask(this, R.string.iob_label, R.string.blank, "iob")
+ .option(Option(R.string.iob_value, true))
+ .option(Option(R.string.iob_hightemp, false))
+ .option(Option(R.string.iob_negiob, true))
+ .option(Option(R.string.iob_posiob, true))
+ )
+ tasks.add(ExamTask(this, R.string.breadgrams_label, R.string.blank, "breadgrams")
+ .option(Option(R.string.breadgrams_grams, true))
+ .option(Option(R.string.breadgrams_exchange, false))
+ .option(Option(R.string.breadgrams_decay, true))
+ .option(Option(R.string.breadgrams_calc, true))
+ .hint(Hint(R.string.breadgrams_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.extendedcarbs_label, R.string.extendedcarbs_handling, "extendedcarbs")
+ .option(Option(R.string.extendedcarbs_future, true))
+ .option(Option(R.string.extendedcarbs_free, false))
+ .option(Option(R.string.extendedcarbs_fat, true))
+ .option(Option(R.string.extendedcarbs_rescue, false))
+ .hint(Hint(R.string.extendedcarbs_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.nsclient_label, R.string.nsclient_howcanyou, "nsclient")
+ .option(Option(R.string.nsclient_nightscout, true))
+ .option(Option(R.string.nsclient_dexcomfollow, true))
+ .option(Option(R.string.nsclient_data, true))
+ .option(Option(R.string.nsclient_fullcontrol, false))
+ .hint(Hint(R.string.nsclient_hint1))
+ )
+ tasks.add(ExamTask(this, R.string.other_medication_label, R.string.other_medication_text, "otherMedicationWarning")
+ .option(Option(R.string.yes, true))
+ .option(Option(R.string.no, false))
+ )
+ for (task in tasks) (task as ExamTask).options.shuffle()
+
+ for (task in tasks) {
+ if (!task.isCompleted()) accomplishedOn = 0
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java
deleted file mode 100644
index 2a9c1ad008..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import androidx.fragment.app.FragmentActivity;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
-import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
-import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
-import info.nightscout.androidaps.utils.T;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-public class Objective3 extends Objective {
- @Inject SP sp;
- @Inject ObjectivesPlugin objectivesPlugin;
- @Inject ResourceHelper resourceHelper;
- @Inject NSClientPlugin nsClientPlugin;
-
- private final int MANUAL_ENACTS_NEEDED = 20;
-
- @Inject
- public Objective3(HasAndroidInjector injector) {
- super(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate);
- // disable option for skipping objectives for now
- // hasSpecialInput = true;
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(7).msecs()));
- tasks.add(new Task(R.string.objectives_manualenacts) {
- @Override
- public boolean isCompleted() {
- return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED;
- }
-
- @Override
- public String getProgress() {
- if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED)
- return resourceHelper.gs(R.string.completed_well_done);
- else
- return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) + " / " + MANUAL_ENACTS_NEEDED;
- }
- });
- }
-
- @Override
- public boolean specialActionEnabled() {
- return NSClientService.isConnected && NSClientService.hasWriteAuth;
- }
-
- @Override
- public void specialAction(FragmentActivity activity, String input) {
- objectivesPlugin.completeObjectives(activity, input);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.kt
new file mode 100644
index 0000000000..da4fb503a1
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.kt
@@ -0,0 +1,41 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import androidx.fragment.app.FragmentActivity
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
+import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
+import info.nightscout.androidaps.utils.T
+import javax.inject.Inject
+
+@Suppress("SpellCheckingInspection")
+class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate) {
+
+ @Inject lateinit var objectivesPlugin: ObjectivesPlugin
+ @Inject lateinit var nsClientPlugin: NSClientPlugin
+
+ init {
+ tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
+ tasks.add(object : Task(this, R.string.objectives_manualenacts) {
+ override fun isCompleted(): Boolean {
+ return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED
+ }
+
+ override val progress: String
+ get() = if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED) resourceHelper.gs(R.string.completed_well_done) else sp.getInt(R.string.key_ObjectivesmanualEnacts, 0).toString() + " / " + MANUAL_ENACTS_NEEDED
+ })
+ }
+
+ override fun specialActionEnabled(): Boolean =
+ NSClientService.isConnected && NSClientService.hasWriteAuth
+
+ override fun specialAction(activity: FragmentActivity, input: String) {
+ objectivesPlugin.completeObjectives(activity, input)
+ }
+
+ companion object {
+
+ private const val MANUAL_ENACTS_NEEDED = 20
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java
deleted file mode 100644
index 4ae475d099..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-
-public class Objective4 extends Objective {
-
- public Objective4(HasAndroidInjector injector) {
- super(injector, "maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.kt
new file mode 100644
index 0000000000..6ba5721ca8
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.kt
@@ -0,0 +1,7 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+
+@Suppress("SpellCheckingInspection")
+class Objective4(injector: HasAndroidInjector) : Objective(injector, "maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate)
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java
deleted file mode 100644
index 2410b3ae4f..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
-import info.nightscout.androidaps.utils.T;
-
-public class Objective5 extends Objective {
- @Inject SafetyPlugin safetyPlugin;
-
- public Objective5(HasAndroidInjector injector) {
- super(injector, "maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(5).msecs()));
- tasks.add(new Task(R.string.closedmodeenabled) {
- @Override
- public boolean isCompleted() {
- Constraint closedLoopEnabled = new Constraint<>(true);
- safetyPlugin.isClosedLoopAllowed(closedLoopEnabled);
- return closedLoopEnabled.value();
- }
- });
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.kt
new file mode 100644
index 0000000000..8a5393fd5a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.kt
@@ -0,0 +1,25 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
+import info.nightscout.androidaps.utils.T
+import javax.inject.Inject
+
+@Suppress("SpellCheckingInspection")
+class Objective5(injector: HasAndroidInjector) : Objective(injector, "maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate) {
+
+ @Inject lateinit var safetyPlugin: SafetyPlugin
+
+ init {
+ tasks.add(MinimumDurationTask(this, T.days(5).msecs()))
+ tasks.add(object : Task(this, R.string.closedmodeenabled) {
+ override fun isCompleted(): Boolean {
+ val closedLoopEnabled = Constraint(true)
+ safetyPlugin.isClosedLoopAllowed(closedLoopEnabled)
+ return closedLoopEnabled.value()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.java
deleted file mode 100644
index e05cb272d4..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
-import info.nightscout.androidaps.utils.T;
-
-public class Objective6 extends Objective {
- @Inject ConstraintChecker constraintChecker;
-
- public Objective6(HasAndroidInjector injector) {
- super(injector, "maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(1).msecs()));
- tasks.add(new Task(R.string.maxiobset) {
- @Override
- public boolean isCompleted() {
- double maxIOB = constraintChecker.getMaxIOBAllowed().value();
- return maxIOB > 0;
- }
- });
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.kt
new file mode 100644
index 0000000000..edcdf54bd5
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.kt
@@ -0,0 +1,23 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
+import info.nightscout.androidaps.utils.T
+import javax.inject.Inject
+
+@Suppress("SpellCheckingInspection")
+class Objective6(injector: HasAndroidInjector) : Objective(injector, "maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate) {
+
+ @Inject lateinit var constraintChecker: ConstraintChecker
+
+ init {
+ tasks.add(MinimumDurationTask(this, T.days(1).msecs()))
+ tasks.add(object : Task(this, R.string.maxiobset) {
+ override fun isCompleted(): Boolean {
+ val maxIOB = constraintChecker.getMaxIOBAllowed().value()
+ return maxIOB > 0
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.java
deleted file mode 100644
index 3a1a2d05f6..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.utils.T;
-
-public class Objective7 extends Objective {
-
- public Objective7(HasAndroidInjector injector) {
- super(injector, "autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(7).msecs()));
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.kt
new file mode 100644
index 0000000000..1f99b50164
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.kt
@@ -0,0 +1,12 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.T
+
+class Objective7(injector: HasAndroidInjector) : Objective(injector, "autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate) {
+
+ init {
+ tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.java
deleted file mode 100644
index 01e89fb415..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.utils.T;
-
-public class Objective8 extends Objective {
-
- public Objective8(HasAndroidInjector injector) {
- super(injector, "ama", R.string.objectives_ama_objective, 0);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(28).msecs()));
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.kt
new file mode 100644
index 0000000000..27b2f8b4d2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.kt
@@ -0,0 +1,12 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.T
+
+class Objective8(injector: HasAndroidInjector) : Objective(injector, "ama", R.string.objectives_ama_objective, 0) {
+
+ init {
+ tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.java
deleted file mode 100644
index 9db81bacdb..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-
-import java.util.List;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.utils.T;
-
-public class Objective9 extends Objective {
-
- public Objective9(HasAndroidInjector injector) {
- super(injector, "smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(28).msecs()));
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.kt
new file mode 100644
index 0000000000..df9bbccafe
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.kt
@@ -0,0 +1,12 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.T
+
+class Objective9(injector: HasAndroidInjector) : Objective(injector, "smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate) {
+
+ init {
+ tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java
deleted file mode 100644
index f0cb07061f..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java
+++ /dev/null
@@ -1,289 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.safety;
-
-import androidx.annotation.NonNull;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Config;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
-import info.nightscout.androidaps.interfaces.BgSourceInterface;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.interfaces.ConstraintsInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginDescription;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.PumpDescription;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
-import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
-import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
-import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DecimalFormatter;
-import info.nightscout.androidaps.utils.HardLimits;
-import info.nightscout.androidaps.utils.Round;
-import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-@Singleton
-public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
-
- private final SP sp;
- private final RxBusWrapper rxBus;
- private final ConstraintChecker constraintChecker;
- private final OpenAPSAMAPlugin openAPSAMAPlugin;
- private final OpenAPSSMBPlugin openAPSSMBPlugin;
- private final SensitivityOref1Plugin sensitivityOref1Plugin;
- private final ActivePluginProvider activePlugin;
- private final HardLimits hardLimits;
- private final BuildHelper buildHelper;
- private final TreatmentsPlugin treatmentsPlugin;
- private final Config config;
-
- @Inject
- public SafetyPlugin(
- HasAndroidInjector injector,
- AAPSLogger aapsLogger,
- ResourceHelper resourceHelper,
- SP sp,
- RxBusWrapper rxBus,
- ConstraintChecker constraintChecker,
- OpenAPSAMAPlugin openAPSAMAPlugin,
- OpenAPSSMBPlugin openAPSSMBPlugin,
- SensitivityOref1Plugin sensitivityOref1Plugin,
- ActivePluginProvider activePlugin,
- HardLimits hardLimits,
- BuildHelper buildHelper,
- TreatmentsPlugin treatmentsPlugin,
- Config config
- ) {
- super(new PluginDescription()
- .mainType(PluginType.CONSTRAINTS)
- .neverVisible(true)
- .alwaysEnabled(true)
- .showInList(false)
- .pluginName(R.string.safety)
- .preferencesId(R.xml.pref_safety),
- aapsLogger, resourceHelper, injector
- );
- this.sp = sp;
- this.rxBus = rxBus;
- this.constraintChecker = constraintChecker;
- this.openAPSAMAPlugin = openAPSAMAPlugin;
- this.openAPSSMBPlugin = openAPSSMBPlugin;
- this.sensitivityOref1Plugin = sensitivityOref1Plugin;
- this.activePlugin = activePlugin;
- this.hardLimits = hardLimits;
- this.buildHelper = buildHelper;
- this.treatmentsPlugin = treatmentsPlugin;
- this.config = config;
- }
-
- /**
- * Constraints interface
- **/
- @NonNull @Override
- public Constraint isLoopInvocationAllowed(@NonNull Constraint value) {
- if (!activePlugin.getActivePump().getPumpDescription().isTempBasalCapable)
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.pumpisnottempbasalcapable), this);
- return value;
- }
-
- @NonNull @Override
- public Constraint isClosedLoopAllowed(@NonNull Constraint value) {
- String mode = sp.getString(R.string.key_aps_mode, "open");
- if ((mode.equals("open")))
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closedmodedisabledinpreferences), this);
-
- if (!buildHelper.isEngineeringModeOrRelease()) {
- if (value.value()) {
- Notification n = new Notification(Notification.TOAST_ALARM, getResourceHelper().gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL);
- rxBus.send(new EventNewNotification(n));
- }
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closed_loop_disabled_on_dev_branch), this);
- }
- PumpInterface pump = activePlugin.getActivePump();
- if (!pump.isFakingTempsByExtendedBoluses() && treatmentsPlugin.isInHistoryExtendedBoluslInProgress()) {
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closed_loop_disabled_with_eb), this);
- }
- return value;
- }
-
- @NonNull @Override
- public Constraint isAutosensModeEnabled(@NonNull Constraint value) {
- boolean enabled = sp.getBoolean(R.string.key_openapsama_useautosens, false);
- if (!enabled)
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.autosensdisabledinpreferences), this);
- return value;
- }
-
- @NonNull @Override
- public Constraint isSMBModeEnabled(@NonNull Constraint value) {
- boolean enabled = sp.getBoolean(R.string.key_use_smb, false);
- if (!enabled)
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbdisabledinpreferences), this);
- Constraint closedLoop = constraintChecker.isClosedLoopAllowed();
- if (!closedLoop.value())
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbnotallowedinopenloopmode), this);
- return value;
- }
-
- @NonNull @Override
- public Constraint isUAMEnabled(@NonNull Constraint value) {
- boolean enabled = sp.getBoolean(R.string.key_use_uam, false);
- if (!enabled)
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.uamdisabledinpreferences), this);
- boolean oref1Enabled = sensitivityOref1Plugin.isEnabled(PluginType.SENSITIVITY);
- if (!oref1Enabled)
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.uamdisabledoref1notselected), this);
- return value;
- }
-
- @NonNull @Override
- public Constraint isAdvancedFilteringEnabled(@NonNull Constraint value) {
- BgSourceInterface bgSource = activePlugin.getActiveBgSource();
-
- if (!bgSource.advancedFilteringSupported())
- value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbalwaysdisabled), this);
- return value;
- }
-
- @NonNull @Override
- public Constraint applyBasalConstraints(Constraint absoluteRate, @NonNull Profile profile) {
-
- absoluteRate.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingbasalratio), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
-
- if (config.getAPS()) {
- double maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1d);
- if (maxBasal < profile.getMaxDailyBasal()) {
- maxBasal = profile.getMaxDailyBasal();
- absoluteRate.addReason(getResourceHelper().gs(R.string.increasingmaxbasal), this);
- }
- absoluteRate.setIfSmaller(getAapsLogger(), maxBasal, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxBasal, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
-
- // Check percentRate but absolute rate too, because we know real current basal in pump
- double maxBasalMult = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
- double maxFromBasalMult = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
- absoluteRate.setIfSmaller(getAapsLogger(), maxFromBasalMult, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxFromBasalMult, getResourceHelper().gs(R.string.maxbasalmultiplier)), this);
-
- double maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d);
- double maxFromDaily = Math.floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100;
- absoluteRate.setIfSmaller(getAapsLogger(), maxFromDaily, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxFromDaily, getResourceHelper().gs(R.string.maxdailybasalmultiplier)), this);
- }
-
- absoluteRate.setIfSmaller(getAapsLogger(), hardLimits.maxBasal(), String.format(getResourceHelper().gs(R.string.limitingbasalratio), hardLimits.maxBasal(), getResourceHelper().gs(R.string.hardlimit)), this);
-
- PumpInterface pump = activePlugin.getActivePump();
- // check for pump max
- if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
- double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
- absoluteRate.setIfSmaller(getAapsLogger(), pumpLimit, String.format(getResourceHelper().gs(R.string.limitingbasalratio), pumpLimit, getResourceHelper().gs(R.string.pumplimit)), this);
- }
-
- // do rounding
- if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
- absoluteRate.set(getAapsLogger(), Round.roundTo(absoluteRate.value(), pump.getPumpDescription().tempAbsoluteStep));
- }
- return absoluteRate;
- }
-
- @NonNull @Override
- public Constraint applyBasalPercentConstraints(Constraint percentRate, Profile profile) {
-
- Double currentBasal = profile.getBasal();
- double absoluteRate = currentBasal * ((double) percentRate.originalValue() / 100);
-
- percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this);
-
- Constraint absoluteConstraint = new Constraint<>(absoluteRate);
- applyBasalConstraints(absoluteConstraint, profile);
- percentRate.copyReasons(absoluteConstraint);
-
- PumpInterface pump = activePlugin.getActivePump();
-
- int percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue();
- if (percentRateAfterConst < 100)
- percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
- else
- percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
-
- percentRate.set(getAapsLogger(), percentRateAfterConst, String.format(getResourceHelper().gs(R.string.limitingpercentrate), percentRateAfterConst, getResourceHelper().gs(R.string.pumplimit)), this);
-
- if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT) {
- double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
- percentRate.setIfSmaller(getAapsLogger(), (int) pumpLimit, String.format(getResourceHelper().gs(R.string.limitingbasalratio), pumpLimit, getResourceHelper().gs(R.string.pumplimit)), this);
- }
-
- return percentRate;
- }
-
- @NonNull @Override
- public Constraint applyBolusConstraints(Constraint insulin) {
- insulin.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingbolus), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
-
- Double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
- insulin.setIfSmaller(getAapsLogger(), maxBolus, String.format(getResourceHelper().gs(R.string.limitingbolus), maxBolus, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
-
- insulin.setIfSmaller(getAapsLogger(), hardLimits.maxBolus(), String.format(getResourceHelper().gs(R.string.limitingbolus), hardLimits.maxBolus(), getResourceHelper().gs(R.string.hardlimit)), this);
-
- PumpInterface pump = activePlugin.getActivePump();
- double rounded = pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value());
- insulin.setIfDifferent(getAapsLogger(), rounded, getResourceHelper().gs(R.string.pumplimit), this);
- return insulin;
- }
-
- @NonNull @Override
- public Constraint applyExtendedBolusConstraints(Constraint insulin) {
- insulin.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingextendedbolus), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
-
- Double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
- insulin.setIfSmaller(getAapsLogger(), maxBolus, String.format(getResourceHelper().gs(R.string.limitingextendedbolus), maxBolus, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
-
- insulin.setIfSmaller(getAapsLogger(), hardLimits.maxBolus(), String.format(getResourceHelper().gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), getResourceHelper().gs(R.string.hardlimit)), this);
-
- PumpInterface pump = activePlugin.getActivePump();
- double rounded = pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value());
- insulin.setIfDifferent(getAapsLogger(), rounded, getResourceHelper().gs(R.string.pumplimit), this);
- return insulin;
- }
-
- @NonNull @Override
- public Constraint applyCarbsConstraints(Constraint carbs) {
- carbs.setIfGreater(getAapsLogger(), 0, String.format(getResourceHelper().gs(R.string.limitingcarbs), 0, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
-
- Integer maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
- carbs.setIfSmaller(getAapsLogger(), maxCarbs, String.format(getResourceHelper().gs(R.string.limitingcarbs), maxCarbs, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
-
- return carbs;
- }
-
- @NonNull @Override
- public Constraint applyMaxIOBConstraints(@NonNull Constraint maxIob) {
- double maxIobPref;
- String apsmode = sp.getString(R.string.key_aps_mode, "open");
- if (openAPSSMBPlugin.isEnabled(PluginType.APS))
- maxIobPref = sp.getDouble(R.string.key_openapssmb_max_iob, 3d);
- else
- maxIobPref = sp.getDouble(R.string.key_openapsma_max_iob, 1.5d);
- maxIob.setIfSmaller(getAapsLogger(), maxIobPref, String.format(getResourceHelper().gs(R.string.limitingiob), maxIobPref, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
-
- if (openAPSAMAPlugin.isEnabled(PluginType.APS))
- maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this);
- if (openAPSSMBPlugin.isEnabled(PluginType.APS))
- maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobSMB(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobSMB(), getResourceHelper().gs(R.string.hardlimit)), this);
- if ((apsmode.equals("lgs")))
- maxIob.setIfSmaller(getAapsLogger(), hardLimits.getMAXIOB_LGS(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.getMAXIOB_LGS(), getResourceHelper().gs(R.string.lowglucosesuspend)), this);
-
- return maxIob;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.kt
new file mode 100644
index 0000000000..c2cbe83ff7
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.kt
@@ -0,0 +1,194 @@
+package info.nightscout.androidaps.plugins.constraints.safety
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
+import info.nightscout.androidaps.utils.DecimalFormatter
+import info.nightscout.androidaps.utils.HardLimits
+import info.nightscout.androidaps.utils.Round
+import info.nightscout.androidaps.utils.buildHelper.BuildHelper
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.math.floor
+
+@Singleton
+class SafetyPlugin @Inject constructor(
+ injector: HasAndroidInjector,
+ aapsLogger: AAPSLogger,
+ resourceHelper: ResourceHelper,
+ private val sp: SP,
+ private val rxBus: RxBusWrapper,
+ private val constraintChecker: ConstraintChecker,
+ private val openAPSAMAPlugin: OpenAPSAMAPlugin,
+ private val openAPSSMBPlugin: OpenAPSSMBPlugin,
+ private val sensitivityOref1Plugin: SensitivityOref1Plugin,
+ private val activePlugin: ActivePluginProvider,
+ private val hardLimits: HardLimits,
+ private val buildHelper: BuildHelper,
+ private val treatmentsPlugin: TreatmentsInterface,
+ private val config: Config
+) : PluginBase(PluginDescription()
+ .mainType(PluginType.CONSTRAINTS)
+ .neverVisible(true)
+ .alwaysEnabled(true)
+ .showInList(false)
+ .pluginName(R.string.safety)
+ .preferencesId(R.xml.pref_safety),
+ aapsLogger, resourceHelper, injector
+), ConstraintsInterface {
+
+ /**
+ * Constraints interface
+ */
+ override fun isLoopInvocationAllowed(value: Constraint): Constraint {
+ if (!activePlugin.activePump.pumpDescription.isTempBasalCapable) value[aapsLogger, false, resourceHelper.gs(R.string.pumpisnottempbasalcapable)] = this
+ return value
+ }
+
+ override fun isClosedLoopAllowed(value: Constraint): Constraint {
+ val mode = sp.getString(R.string.key_aps_mode, "open")
+ if (mode == "open") value[aapsLogger, false, resourceHelper.gs(R.string.closedmodedisabledinpreferences)] = this
+ if (!buildHelper.isEngineeringModeOrRelease()) {
+ if (value.value()) {
+ val n = Notification(Notification.TOAST_ALARM, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL)
+ rxBus.send(EventNewNotification(n))
+ }
+ value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)] = this
+ }
+ val pump = activePlugin.activePump
+ if (!pump.isFakingTempsByExtendedBoluses && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
+ value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_with_eb)] = this
+ }
+ return value
+ }
+
+ override fun isAutosensModeEnabled(value: Constraint): Constraint {
+ val enabled = sp.getBoolean(R.string.key_openapsama_useautosens, false)
+ if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.autosensdisabledinpreferences)] = this
+ return value
+ }
+
+ override fun isSMBModeEnabled(value: Constraint): Constraint {
+ val enabled = sp.getBoolean(R.string.key_use_smb, false)
+ if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.smbdisabledinpreferences)] = this
+ val closedLoop = constraintChecker.isClosedLoopAllowed()
+ if (!closedLoop.value()) value[aapsLogger, false, resourceHelper.gs(R.string.smbnotallowedinopenloopmode)] = this
+ return value
+ }
+
+ override fun isUAMEnabled(value: Constraint): Constraint {
+ val enabled = sp.getBoolean(R.string.key_use_uam, false)
+ if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.uamdisabledinpreferences)] = this
+ val oref1Enabled = sensitivityOref1Plugin.isEnabled(PluginType.SENSITIVITY)
+ if (!oref1Enabled) value[aapsLogger, false, resourceHelper.gs(R.string.uamdisabledoref1notselected)] = this
+ return value
+ }
+
+ override fun isAdvancedFilteringEnabled(value: Constraint): Constraint {
+ val bgSource = activePlugin.activeBgSource
+ if (!bgSource.advancedFilteringSupported()) value[aapsLogger, false, resourceHelper.gs(R.string.smbalwaysdisabled)] = this
+ return value
+ }
+
+ override fun applyBasalConstraints(absoluteRate: Constraint, profile: Profile): Constraint {
+ absoluteRate.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingbasalratio), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
+ if (config.APS) {
+ var maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1.0)
+ if (maxBasal < profile.maxDailyBasal) {
+ maxBasal = profile.maxDailyBasal
+ absoluteRate.addReason(resourceHelper.gs(R.string.increasingmaxbasal), this)
+ }
+ absoluteRate.setIfSmaller(aapsLogger, maxBasal, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxBasal, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
+
+ // Check percentRate but absolute rate too, because we know real current basal in pump
+ val maxBasalMultiplier = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)
+ val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.basal * 100) / 100
+ absoluteRate.setIfSmaller(aapsLogger, maxFromBasalMultiplier, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxFromBasalMultiplier, resourceHelper.gs(R.string.maxbasalmultiplier)), this)
+ val maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)
+ val maxFromDaily = floor(profile.maxDailyBasal * maxBasalFromDaily * 100) / 100
+ absoluteRate.setIfSmaller(aapsLogger, maxFromDaily, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxFromDaily, resourceHelper.gs(R.string.maxdailybasalmultiplier)), this)
+ }
+ absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(), String.format(resourceHelper.gs(R.string.limitingbasalratio), hardLimits.maxBasal(), resourceHelper.gs(R.string.hardlimit)), this)
+ val pump = activePlugin.activePump
+ // check for pump max
+ if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
+ val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
+ absoluteRate.setIfSmaller(aapsLogger, pumpLimit, String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this)
+ }
+
+ // do rounding
+ if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
+ absoluteRate[aapsLogger] = Round.roundTo(absoluteRate.value(), pump.pumpDescription.tempAbsoluteStep)
+ }
+ return absoluteRate
+ }
+
+ override fun applyBasalPercentConstraints(percentRate: Constraint, profile: Profile): Constraint {
+ val currentBasal = profile.basal
+ val absoluteRate = currentBasal * (percentRate.originalValue().toDouble() / 100)
+ percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this)
+ val absoluteConstraint = Constraint(absoluteRate)
+ applyBasalConstraints(absoluteConstraint, profile)
+ percentRate.copyReasons(absoluteConstraint)
+ val pump = activePlugin.activePump
+ var percentRateAfterConst = java.lang.Double.valueOf(absoluteConstraint.value() / currentBasal * 100).toInt()
+ percentRateAfterConst = if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt()
+ percentRate[aapsLogger, percentRateAfterConst, String.format(resourceHelper.gs(R.string.limitingpercentrate), percentRateAfterConst, resourceHelper.gs(R.string.pumplimit))] = this
+ if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
+ val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
+ percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this)
+ }
+ return percentRate
+ }
+
+ override fun applyBolusConstraints(insulin: Constraint): Constraint {
+ insulin.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingbolus), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
+ val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
+ insulin.setIfSmaller(aapsLogger, maxBolus, String.format(resourceHelper.gs(R.string.limitingbolus), maxBolus, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
+ insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(resourceHelper.gs(R.string.limitingbolus), hardLimits.maxBolus(), resourceHelper.gs(R.string.hardlimit)), this)
+ val pump = activePlugin.activePump
+ val rounded = pump.pumpDescription.pumpType.determineCorrectBolusSize(insulin.value())
+ insulin.setIfDifferent(aapsLogger, rounded, resourceHelper.gs(R.string.pumplimit), this)
+ return insulin
+ }
+
+ override fun applyExtendedBolusConstraints(insulin: Constraint): Constraint {
+ insulin.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingextendedbolus), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
+ val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
+ insulin.setIfSmaller(aapsLogger, maxBolus, String.format(resourceHelper.gs(R.string.limitingextendedbolus), maxBolus, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
+ insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(resourceHelper.gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), resourceHelper.gs(R.string.hardlimit)), this)
+ val pump = activePlugin.activePump
+ val rounded = pump.pumpDescription.pumpType.determineCorrectExtendedBolusSize(insulin.value())
+ insulin.setIfDifferent(aapsLogger, rounded, resourceHelper.gs(R.string.pumplimit), this)
+ return insulin
+ }
+
+ override fun applyCarbsConstraints(carbs: Constraint): Constraint {
+ carbs.setIfGreater(aapsLogger, 0, String.format(resourceHelper.gs(R.string.limitingcarbs), 0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
+ val maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48)
+ carbs.setIfSmaller(aapsLogger, maxCarbs, String.format(resourceHelper.gs(R.string.limitingcarbs), maxCarbs, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
+ return carbs
+ }
+
+ override fun applyMaxIOBConstraints(maxIob: Constraint): Constraint {
+ val apsMode = sp.getString(R.string.key_aps_mode, "open")
+ val maxIobPref: Double = if (openAPSSMBPlugin.isEnabled(PluginType.APS)) sp.getDouble(R.string.key_openapssmb_max_iob, 3.0) else sp.getDouble(R.string.key_openapsma_max_iob, 1.5)
+ maxIob.setIfSmaller(aapsLogger, maxIobPref, String.format(resourceHelper.gs(R.string.limitingiob), maxIobPref, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
+ if (openAPSAMAPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobAMA(), resourceHelper.gs(R.string.hardlimit)), this)
+ if (openAPSSMBPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobSMB(), resourceHelper.gs(R.string.hardlimit)), this)
+ if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, hardLimits.MAXIOB_LGS, String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.MAXIOB_LGS, resourceHelper.gs(R.string.lowglucosesuspend)), this)
+ return maxIob
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
index 13f7b5bd27..b0a28f92b2 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
@@ -23,6 +23,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler
@@ -32,7 +33,6 @@ import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
-import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
@@ -41,6 +41,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.ui.SingleClickButton
import info.nightscout.androidaps.utils.ui.UIRunnable
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import java.util.*
import javax.inject.Inject
@@ -61,6 +62,7 @@ class ActionsFragment : DaggerFragment() {
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var skinProvider: SkinProvider
@Inject lateinit var config: Config
+ @Inject lateinit var uel: UserEntryLogger
private var disposable: CompositeDisposable = CompositeDisposable()
@@ -152,16 +154,11 @@ class ActionsFragment : DaggerFragment() {
}
extendedBolusCancel?.setOnClickListener {
if (activePlugin.activeTreatments.isInHistoryExtendedBoluslInProgress) {
- aapsLogger.debug("USER ENTRY: CANCEL EXTENDED BOLUS")
+ uel.log("CANCEL EXTENDED BOLUS")
commandQueue.cancelExtended(object : Callback() {
override fun run() {
if (!result.success) {
- val i = Intent(ctx, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- ctx.startActivity(i)
+ ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), R.raw.boluserror)
}
}
})
@@ -172,16 +169,11 @@ class ActionsFragment : DaggerFragment() {
}
cancelTempBasal?.setOnClickListener {
if (activePlugin.activeTreatments.isTempBasalInProgress) {
- aapsLogger.debug("USER ENTRY: CANCEL TEMP BASAL")
+ uel.log("CANCEL TEMP BASAL")
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success) {
- val i = Intent(ctx, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- ctx.startActivity(i)
+ ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
}
}
})
@@ -264,10 +256,10 @@ class ActionsFragment : DaggerFragment() {
profileSwitch?.visibility = (
activePlugin.activeProfileInterface.profile != null &&
pump.pumpDescription.isSetBasalProfileCapable &&
- pump.isInitialized &&
- !pump.isSuspended).toVisibility()
+ pump.isInitialized() &&
+ !pump.isSuspended()).toVisibility()
- if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized || pump.isSuspended || pump.isFakingTempsByExtendedBoluses) {
+ if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses) {
extendedBolus?.visibility = View.GONE
extendedBolusCancel?.visibility = View.GONE
} else {
@@ -283,7 +275,7 @@ class ActionsFragment : DaggerFragment() {
}
}
- if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized || pump.isSuspended) {
+ if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized() || pump.isSuspended()) {
setTempBasal?.visibility = View.GONE
cancelTempBasal?.visibility = View.GONE
} else {
@@ -300,7 +292,7 @@ class ActionsFragment : DaggerFragment() {
}
val activeBgSource = activePlugin.activeBgSource
historyBrowser?.visibility = (profile != null).toVisibility()
- fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized && !pump.isSuspended).toVisibility()
+ fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility()
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
@@ -320,7 +312,7 @@ class ActionsFragment : DaggerFragment() {
private fun checkPumpCustomActions() {
val activePump = activePlugin.activePump
- val customActions = activePump.customActions ?: return
+ val customActions = activePump.getCustomActions() ?: return
val currentContext = context ?: return
removePumpCustomActions()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt
index ca70fd8046..4c4b43ba18 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt
@@ -18,7 +18,7 @@ class AutomationEvent(private val injector: HasAndroidInjector) {
@Inject lateinit var aapsLogger: AAPSLogger
- var title: String? = null
+ var title: String = ""
var isEnabled = true
var systemAction: Boolean = false // true = generated by AAPS, false = entered by user
var readOnly: Boolean = false // removing, editing disabled
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
index e599fe8797..31819ac0bb 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
@@ -20,6 +20,7 @@ import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.AutomationEventItemBinding
import info.nightscout.androidaps.databinding.AutomationFragmentBinding
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter
@@ -31,8 +32,8 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventAutomat
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
@@ -48,6 +49,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var injector: HasAndroidInjector
+ @Inject lateinit var uel: UserEntryLogger
private var disposable: CompositeDisposable = CompositeDisposable()
private lateinit var eventListAdapter: EventListAdapter
@@ -212,11 +214,12 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
}
// remove event
holder.binding.iconTrash.setOnClickListener {
- showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
- Runnable {
+ OKDialog.showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
+ {
+ uel.log("AUTOM REMOVED", automationPlugin.at(position).title)
automationPlugin.removeAt(position)
notifyItemRemoved(position)
- }, Runnable {
+ }, {
rxBus.send(EventAutomationUpdateGui())
})
}
@@ -234,8 +237,9 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
override fun onItemDismiss(position: Int) {
activity?.let { activity ->
- showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
+ OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
Runnable {
+ uel.log("AUTOM REMOVED", automationPlugin.at(position).title)
automationPlugin.removeAt(position)
notifyItemRemoved(position)
rxBus.send(EventAutomationDataChanged())
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt
index e67906b101..480ef913cf 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt
@@ -30,7 +30,7 @@ import info.nightscout.androidaps.services.LocationServiceHelper
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt
index 47520412a4..93411a1275 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt
@@ -1,25 +1,20 @@
package info.nightscout.androidaps.plugins.general.automation.actions
import android.content.Context
-import android.content.Intent
import android.widget.LinearLayout
import androidx.annotation.DrawableRes
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
-import info.nightscout.androidaps.activities.ErrorHelperActivity
-import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.data.PumpEnactResult
-import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
-import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
-import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
-import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationUserMessage
import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
-import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
+import info.nightscout.androidaps.utils.T
+import info.nightscout.androidaps.utils.TimerUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONObject
import javax.inject.Inject
@@ -28,28 +23,24 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var rxBus: RxBusWrapper
- @Inject lateinit var nsUpload: NSUpload
@Inject lateinit var context: Context
+ @Inject lateinit var timerUtil: TimerUtil
var text = InputString(injector)
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
this.text = InputString(injector, text)
}
+
override fun friendlyName(): Int = R.string.alarm
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
- override fun isValid(): Boolean = text.value.isNotEmpty()
+ override fun isValid(): Boolean = true // empty alarm will show app name
override fun doAction(callback: Callback) {
- val i = Intent(context, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.modern_alarm)
- i.putExtra("status", text.value)
- i.putExtra("title", resourceHelper.gs(R.string.alarm))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- context.startActivity(i)
-
+ timerUtil.scheduleReminder(DateUtil.now() + T.secs(10L).msecs(), text.value.takeIf { it.isNotBlank() }
+ ?: resourceHelper.gs(R.string.app_name))
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt
index 2ce260102f..68f56a8f98 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt
@@ -25,7 +25,7 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventAutomat
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt
index 2a73b4bc24..bb2dc1e2e0 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt
@@ -16,7 +16,7 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import org.json.JSONObject
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt
index 1f2531d95b..53733acfc8 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt
@@ -1,12 +1,10 @@
package info.nightscout.androidaps.plugins.general.automation.elements
-import android.view.View
-import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.annotation.StringRes
-import com.dpro.widgets.WeekdaysPicker
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.ui.WeekdayPicker
import java.util.*
class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
@@ -56,7 +54,7 @@ class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
for (day in DayOfWeek.values()) set(day, false)
}
- fun setAll(value:Boolean) {
+ fun setAll(value: Boolean) {
for (day in DayOfWeek.values()) set(day, value)
}
@@ -78,13 +76,10 @@ class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
}
override fun addToLayout(root: LinearLayout) {
- val weekdaysPicker = WeekdaysPicker(root.context)
- weekdaysPicker.setEditable(true)
- weekdaysPicker.selectedDays = getSelectedDays()
- weekdaysPicker.setOnWeekdaysChangeListener { _: View?, i: Int, list: List -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)) }
- weekdaysPicker.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
- weekdaysPicker.sundayFirstDay = Calendar.getInstance().firstDayOfWeek == Calendar.SUNDAY
- weekdaysPicker.redrawDays()
- root.addView(weekdaysPicker)
+ WeekdayPicker(root.context).apply {
+ setSelectedDays(getSelectedDays())
+ setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) }
+ root.addView(this)
+ }
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt
index fce6bb41c4..def0d59a6c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt
@@ -11,15 +11,15 @@ import com.google.common.base.Optional
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ActivePluginProvider
+import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.interfaces.TreatmentsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
-import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerChanged
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerClone
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerRemove
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.services.LastLocationDataContainer
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
@@ -29,13 +29,14 @@ import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor
abstract class Trigger(val injector: HasAndroidInjector) {
+
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var sp: SP
@Inject lateinit var locationDataContainer: LastLocationDataContainer
- @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
+ @Inject lateinit var treatmentsInterface: TreatmentsInterface
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@@ -53,12 +54,13 @@ abstract class Trigger(val injector: HasAndroidInjector) {
abstract fun duplicate(): Trigger
companion object {
+
@JvmStatic
fun scanForActivity(cont: Context?): AppCompatActivity? {
when (cont) {
- null -> return null
+ null -> return null
is AppCompatActivity -> return cont
- is ContextWrapper -> return scanForActivity(cont.baseContext)
+ is ContextWrapper -> return scanForActivity(cont.baseContext)
else -> return null
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt
index 27f736cf9a..5ff50b561c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt
@@ -35,7 +35,7 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) {
}
override fun shouldRun(): Boolean {
- val lastBolusTime = treatmentsPlugin.getLastBolusTime(true)
+ val lastBolusTime = treatmentsInterface.getLastBolusTime(true)
if (lastBolusTime == 0L)
return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt
index 1fa82bd68f..ce553cb1a3 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt
@@ -73,8 +73,8 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) {
false
}
val calculatedDelta = when (delta.deltaType) {
- DeltaType.SHORT_AVERAGE -> glucoseStatus.short_avgdelta
- DeltaType.LONG_AVERAGE -> glucoseStatus.long_avgdelta
+ DeltaType.SHORT_AVERAGE -> glucoseStatus.shortAvgDelta
+ DeltaType.LONG_AVERAGE -> glucoseStatus.longAvgDelta
else -> glucoseStatus.delta
}
if (comparator.value.check(calculatedDelta, Profile.toMgdl(delta.value, units))) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt
index 26aa0c81b7..25ef553816 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt
@@ -28,7 +28,7 @@ class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) {
}
override fun shouldRun(): Boolean {
- val tt = treatmentsPlugin.tempTargetFromHistory
+ val tt = treatmentsInterface.tempTargetFromHistory
if (tt == null && comparator.value == ComparatorExists.Compare.NOT_EXISTS) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt
index c6b15b432f..85b557b925 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt
@@ -130,7 +130,7 @@ class DataBroadcastPlugin @Inject constructor(
bundle.putString("units", profileFunction.getUnits()) // units used in AAPS "mg/dl" or "mmol"
bundle.putString("slopeArrow", lastBG.trendArrow.text) // direction arrow as string
bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl
- bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgdelta) // average bg delta
+ bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgDelta) // average bg delta
bundle.putDouble("high", defaultValueHelper.determineHighLine()) // predefined top value of in range (green area)
bundle.putDouble("low", defaultValueHelper.determineLowLine()) // predefined bottom value of in range
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt
index b9acd8aaf2..fe08c9a3ab 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt
@@ -18,11 +18,12 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.FoodFragmentBinding
import info.nightscout.androidaps.databinding.FoodItemBinding
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
@@ -38,6 +39,7 @@ class FoodFragment : DaggerFragment() {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var foodPlugin: FoodPlugin
@Inject lateinit var nsUpload: NSUpload
+ @Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable()
private lateinit var unfiltered: List
@@ -213,7 +215,8 @@ class FoodFragment : DaggerFragment() {
binding.remove.setOnClickListener { v: View ->
val food = v.tag as Food
activity?.let { activity ->
- showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int ->
+ OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int ->
+ uel.log("FOOD REMOVED", food.name)
if (food._id != null && food._id != "") {
nsUpload.removeFoodFromNS(food._id)
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
index d1edbbca20..98fc711d25 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
@@ -20,13 +20,13 @@ import info.nightscout.androidaps.interfaces.ConfigInterface
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
import info.nightscout.androidaps.utils.AndroidPermission
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
import info.nightscout.androidaps.utils.alertDialogs.PrefImportSummaryDialog
import info.nightscout.androidaps.utils.alertDialogs.TwoMessagesAlertDialog
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
@@ -58,7 +58,8 @@ class ImportExportPrefs @Inject constructor(
private val androidPermission: AndroidPermission,
private val classicPrefsFormat: ClassicPrefsFormat,
private val encryptedPrefsFormat: EncryptedPrefsFormat,
- private val prefFileList: PrefFileListProvider
+ private val prefFileList: PrefFileListProvider,
+ private val uel: UserEntryLogger
) : ImportExportPrefsInterface {
override fun prefsFileExists(): Boolean {
@@ -342,7 +343,8 @@ class ImportExportPrefs @Inject constructor(
private fun restartAppAfterImport(context: Context) {
sp.putBoolean(R.string.key_setupwizard_processed, true)
- show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
+ OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
+ uel.log("IMPORT")
log.debug(LTag.CORE, "Exiting")
rxBus.send(EventAppExit())
if (context is AppCompatActivity) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/LoggerUtils.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/LoggerUtils.java
deleted file mode 100644
index 2d1dcb19b8..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/LoggerUtils.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package info.nightscout.androidaps.plugins.general.maintenance;
-
-import org.slf4j.LoggerFactory;
-
-import ch.qos.logback.classic.LoggerContext;
-
-/**
- * This class provides serveral methods for log-handling (eg. sending logs as emails).
- */
-public class LoggerUtils {
-
- public static String SUFFIX = ".log.zip";
-
- /**
- * Returns the directory, in which the logs are stored on the system. This is configured in the
- * logback.xml file.
- *
- * @return
- */
- public static String getLogDirectory() {
- LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
- return lc.getProperty("EXT_FILES_DIR");
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/LoggerUtils.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/LoggerUtils.kt
new file mode 100644
index 0000000000..e6ce7fb821
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/LoggerUtils.kt
@@ -0,0 +1,27 @@
+package info.nightscout.androidaps.plugins.general.maintenance
+
+import ch.qos.logback.classic.LoggerContext
+import org.slf4j.LoggerFactory
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * This class provides several methods for log-handling (eg. sending logs as emails).
+ */
+@Singleton
+class LoggerUtils @Inject constructor() {
+
+ var suffix = ".log.zip"
+
+ /**
+ * Returns the directory, in which the logs are stored on the system. This is configured in the
+ * logback.xml file.
+ *
+ * @return
+ */
+ val logDirectory: String
+ get() {
+ val lc = LoggerFactory.getILoggerFactory() as LoggerContext
+ return lc.getProperty("EXT_FILES_DIR")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt
index e2c20aa0e6..7f44689ebc 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt
@@ -13,6 +13,7 @@ import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
@@ -36,6 +37,7 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var repository: AppRepository
+ @Inject lateinit var uel: UserEntryLogger
private val compositeDisposable = CompositeDisposable()
@@ -54,13 +56,13 @@ class MaintenanceFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState)
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
binding.logDelete.setOnClickListener {
- aapsLogger.debug("USER ENTRY: DELETE LOGS")
+ uel.log("DELETE LOGS")
maintenancePlugin.deleteLogs()
}
binding.navResetdb.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
- aapsLogger.debug("USER ENTRY: RESET DATABASES")
+ uel.log("RESET DATABASES")
compositeDisposable.add(
fromAction {
MainApp.getDbHelper().resetDatabases()
@@ -81,14 +83,14 @@ class MaintenanceFragment : DaggerFragment() {
}
}
binding.navExport.setOnClickListener {
- aapsLogger.debug("USER ENTRY: EXPORT SETTINGS")
+ uel.log("EXPORT SETTINGS")
// start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.exportSharedPreferences(this)
}
}
binding.navImport.setOnClickListener {
- aapsLogger.debug("USER ENTRY: IMPORT SETTINGS")
+ uel.log("IMPORT SETTINGS")
// start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.importSharedPreferences(this)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt
index 6f7cd7401e..e50b19b0ec 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt
@@ -34,7 +34,8 @@ class MaintenancePlugin @Inject constructor(
private val nsSettingsStatus: NSSettingsStatus,
aapsLogger: AAPSLogger,
private val buildHelper: BuildHelper,
- private val config: Config
+ private val config: Config,
+ private val loggerUtils: LoggerUtils
) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(MaintenanceFragment::class.java.name)
@@ -51,8 +52,7 @@ class MaintenancePlugin @Inject constructor(
fun sendLogs() {
val recipient = sp.getString(R.string.key_maintenance_logs_email, "logs@androidaps.org")
val amount = sp.getInt(R.string.key_maintenance_logs_amount, 2)
- val logDirectory = LoggerUtils.getLogDirectory()
- val logs = getLogFiles(logDirectory, amount)
+ val logs = getLogFiles(amount)
val zipDir = context.getExternalFilesDir("exports")
val zipFile = File(zipDir, constructName())
aapsLogger.debug("zipFile: ${zipFile.absolutePath}")
@@ -66,29 +66,27 @@ class MaintenancePlugin @Inject constructor(
//todo replace this with a call on startup of the application, specifically to remove
// unnecessary garbage from the log exports
fun deleteLogs() {
- LoggerUtils.getLogDirectory()?.let { logDirectory ->
- val logDir = File(logDirectory)
- val files = logDir.listFiles { _: File?, name: String ->
- (name.startsWith("AndroidAPS") && name.endsWith(".zip"))
+ val logDir = File(loggerUtils.logDirectory)
+ val files = logDir.listFiles { _: File?, name: String ->
+ (name.startsWith("AndroidAPS") && name.endsWith(".zip"))
+ }
+ Arrays.sort(files) { f1: File, f2: File -> f1.name.compareTo(f2.name) }
+ var delFiles = listOf(*files)
+ val amount = sp.getInt(R.string.key_logshipper_amount, 2)
+ val keepIndex = amount - 1
+ if (keepIndex < delFiles.size) {
+ delFiles = delFiles.subList(keepIndex, delFiles.size)
+ for (file in delFiles) {
+ file.delete()
}
- Arrays.sort(files) { f1: File, f2: File -> f1.name.compareTo(f2.name) }
- var delFiles = listOf(*files)
- val amount = sp.getInt(R.string.key_logshipper_amount, 2)
- val keepIndex = amount - 1
- if (keepIndex < delFiles.size) {
- delFiles = delFiles.subList(keepIndex, delFiles.size)
- for (file in delFiles) {
- file.delete()
- }
- }
- val exportDir = File(logDirectory, "exports")
- if (exportDir.exists()) {
- val expFiles = exportDir.listFiles()
- for (file in expFiles) {
- file.delete()
- }
- exportDir.delete()
+ }
+ val exportDir = File(loggerUtils.logDirectory, "exports")
+ if (exportDir.exists()) {
+ val expFiles = exportDir.listFiles()
+ for (file in expFiles) {
+ file.delete()
}
+ exportDir.delete()
}
}
@@ -98,17 +96,16 @@ class MaintenancePlugin @Inject constructor(
*
* The log files are sorted by the name descending.
*
- * @param directory
* @param amount
* @return
*/
- fun getLogFiles(directory: String, amount: Int): List {
- aapsLogger.debug("getting $amount logs from directory $directory")
- val logDir = File(directory)
+ fun getLogFiles(amount: Int): List {
+ aapsLogger.debug("getting $amount logs from directory ${loggerUtils.logDirectory}")
+ val logDir = File(loggerUtils.logDirectory)
val files = logDir.listFiles { _: File?, name: String ->
(name.startsWith("AndroidAPS")
&& (name.endsWith(".log")
- || name.endsWith(".zip") && !name.endsWith(LoggerUtils.SUFFIX)))
+ || name.endsWith(".zip") && !name.endsWith(loggerUtils.suffix)))
}
Arrays.sort(files) { f1: File, f2: File -> f2.name.compareTo(f1.name) }
val result = listOf(*files)
@@ -139,7 +136,7 @@ class MaintenancePlugin @Inject constructor(
* @return
*/
private fun constructName(): String {
- return "AndroidAPS_LOG_" + Date().time + LoggerUtils.SUFFIX
+ return "AndroidAPS_LOG_" + Date().time + loggerUtils.suffix
}
private fun zip(zipFile: File?, files: List) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java
index 37de04a623..58bacbbf4c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java
@@ -16,6 +16,7 @@ import javax.inject.Inject;
import dagger.android.support.DaggerFragment;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.logging.UserEntryLogger;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
@@ -36,6 +37,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
@Inject UploadQueue uploadQueue;
@Inject FabricPrivacy fabricPrivacy;
@Inject AapsSchedulers aapsSchedulers;
+ @Inject UserEntryLogger uel;
private final CompositeDisposable disposable = new CompositeDisposable();
@@ -121,6 +123,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
break;
case R.id.nsclientinternal_clearqueue:
OKDialog.showConfirmation(getContext(), resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), () -> {
+ uel.log("NS QUEUE CLEARED", "", 0.0, 0.0, 0, 0);
uploadQueue.clearQueue();
updateGui();
fabricPrivacy.logCustom("NSClientClearQueue");
@@ -136,6 +139,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch (buttonView.getId()) {
case R.id.nsclientinternal_paused:
+ uel.log("NS PAUSED", "", 0.0, 0.0, isChecked ? 1 : 0, 0);
nsClientPlugin.pause(isChecked);
updateGui();
fabricPrivacy.logCustom("NSClientPause");
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt
index 06c853185a..fe53640252 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt
@@ -5,6 +5,7 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
@@ -116,7 +117,8 @@ class NSSettingsStatus @Inject constructor(
private val rxBus: RxBusWrapper,
private val defaultValueHelper: DefaultValueHelper,
private val sp: SP,
- private val config: Config
+ private val config: Config,
+ private val uel: UserEntryLogger
) {
var nightscoutVersionName = ""
@@ -127,7 +129,7 @@ class NSSettingsStatus @Inject constructor(
fun handleNewData(nightscoutVersionName: String, nightscoutVersionCode: Int, status: JSONObject) {
this.nightscoutVersionName = nightscoutVersionName
aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: $nightscoutVersionName")
- if (nightscoutVersionCode < config.SUPPORTEDNSVERSION) {
+ if (nightscoutVersionCode != 0 && nightscoutVersionCode < config.SUPPORTEDNSVERSION) {
val notification = Notification(Notification.OLD_NS, resourceHelper.gs(R.string.unsupportednsversion), Notification.NORMAL)
rxBus.send(EventNewNotification(notification))
} else {
@@ -233,6 +235,7 @@ class NSSettingsStatus @Inject constructor(
getExtendedWarnValue("sage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_sage_critical, it) }
getExtendedWarnValue("bage", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) }
getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, it) }
+ uel.log("NS SETTINGS COPIED")
}
if (context != null) OKDialog.showConfirmation(context, resourceHelper.gs(R.string.statuslights), resourceHelper.gs(R.string.copyexistingvalues), action)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt
index fb8faa1bcb..07bbea6753 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt
@@ -16,7 +16,7 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.BackpressureStrategy
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt
index 81c8c9c23e..31aa345d65 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt
@@ -27,7 +27,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
@@ -363,7 +363,7 @@ class OpenHumansUploader @Inject constructor(
copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
.andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows + treatmentsPlugin.service.count()) })
.doOnSuccess { maxProgress = it }
- .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } }
+ .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } }
.map { enqueueTreatment(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
index ac9ce8438c..e791cb6a73 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
@@ -33,6 +33,7 @@ import info.nightscout.androidaps.dialogs.*
import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@@ -42,7 +43,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
-import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler
+import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
@@ -98,7 +99,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
@Inject lateinit var xdripPlugin: XdripPlugin
@Inject lateinit var notificationStore: NotificationStore
- @Inject lateinit var actionStringHandler: ActionStringHandler
@Inject lateinit var quickWizard: QuickWizard
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var commandQueue: CommandQueue
@@ -109,6 +109,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var config: Config
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var databaseHelper: DatabaseHelperInterface
+ @Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable()
@@ -341,10 +342,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
?: "".toSpanned(), {
- aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL")
+ uel.log("ACCEPT TEMP BASAL")
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
- actionStringHandler.handleInitiate("cancelChangeRequest")
+ rxBus.send(EventWearDoAction("cancelChangeRequest"))
loopPlugin.acceptChangeRequest()
})
})
@@ -445,7 +446,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// QuickWizard button
val quickWizardEntry = quickWizard.getActive()
- if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized && !pump.isSuspended) {
+ if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized() && !pump.isSuspended()) {
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false)
binding.buttonsLayout.quickWizardButton.text = quickWizardEntry.buttonText() + "\n" + resourceHelper.gs(R.string.format_carbs, quickWizardEntry.carbs()) +
@@ -462,7 +463,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
(lastRun.lastOpenModeAccept == 0L || lastRun.lastOpenModeAccept < lastRun.lastAPSRun) &&// never accepted or before last result
lastRun.constraintsProcessed?.isChangeRequested == true // change is requested
- if (showAcceptButton && pump.isInitialized && !pump.isSuspended && loopPlugin.isEnabled(PluginType.LOOP)) {
+ if (showAcceptButton && pump.isInitialized() && !pump.isSuspended() && loopPlugin.isEnabled(PluginType.LOOP)) {
binding.buttonsLayout.acceptTempButton.visibility = View.VISIBLE
binding.buttonsLayout.acceptTempButton.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
} else {
@@ -470,10 +471,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
// **** Various treatment buttons ****
- binding.buttonsLayout.carbsButton.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized && !pump.isSuspended) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
- binding.buttonsLayout.treatmentButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
- binding.buttonsLayout.wizardButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
- binding.buttonsLayout.insulinButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
+ binding.buttonsLayout.carbsButton.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized() && !pump.isSuspended()) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
+ binding.buttonsLayout.treatmentButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
+ binding.buttonsLayout.wizardButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
+ binding.buttonsLayout.insulinButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
// **** Calibration & CGM buttons ****
val xDripIsBgSource = xdripPlugin.isEnabled(PluginType.BGSOURCE)
@@ -587,8 +588,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.infoLayout.deltaLarge.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
binding.infoLayout.deltaLarge.setTextColor(color)
binding.infoLayout.delta.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
- binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)
- binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)
+ binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units)
+ binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)
} else {
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
binding.infoLayout.avgDelta.text = ""
@@ -632,7 +633,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
- pump.isSuspended -> {
+ pump.isSuspended() -> {
binding.infoLayout.apsMode.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Omnipod_Eros) {
// For Omnipod, indicate the pump as disconnected when it's suspended.
// The only way to 'reconnect' it, is through the Omnipod tab
@@ -860,7 +861,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
graphData.addTreatments(fromTime, endTime)
// set manual x bounds to have nice steps
- graphData.setNumVerticalLables()
+ graphData.setNumVerticalLabels()
graphData.formatAxis(fromTime, endTime)
@@ -887,23 +888,25 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
var useDevForScale = false
var useRatioForScale = false
var useDSForScale = false
- var useIAForScale = false
+ var useBGIForScale = false
when {
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
- menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
+ menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
}
+ val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
+ val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, now, useABSForScale, 1.0)
- if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal])
+ if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
- if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0)
+ if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0, alignDevBgiScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
- if (menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8)
+ if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, endTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
// set manual x bounds to have nice steps
@@ -924,7 +927,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
- menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
+ menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
).toVisibility()
secondaryGraphsData[g].performUpdate()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt
index af10d60f85..fe9f14bb81 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt
@@ -40,7 +40,8 @@ class OverviewMenus @Inject constructor(
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true,shortnameId = R.string.cob),
DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true,shortnameId = R.string.deviation_shortname),
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true,shortnameId = R.string.sensitivity_shortname),
- ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = true,shortnameId = R.string.activity_shortname),
+ ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = false,shortnameId = R.string.activity_shortname),
+ BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.bgi_shortname),
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true,shortnameId = R.string.devslope_shortname)
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt
index d010dea773..d8308f346e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt
@@ -21,6 +21,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt
index 0256647221..d79d3f51f4 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt
@@ -17,7 +17,7 @@ import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWiza
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.wizard.QuickWizard
import io.reactivex.disposables.CompositeDisposable
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt
index 5b18eb80d5..b0f526b2c7 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt
@@ -66,7 +66,7 @@ class GraphData(
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
if (bgReadingsArray?.isEmpty() != false) {
aapsLogger.debug("No BG data.")
- maxY = 10.0
+ maxY = if (units == Constants.MGDL) 180.0 else 10.0
minY = 0.0
return
}
@@ -88,7 +88,7 @@ class GraphData(
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
}
- internal fun setNumVerticalLables() {
+ internal fun setNumVerticalLabels() {
graph.gridLabelRenderer.numVerticalLabels = if (units == Constants.MGDL) (maxY / 40 + 1).toInt() else (maxY / 2 + 1).toInt()
}
@@ -291,7 +291,7 @@ class GraphData(
fun addActivity(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
val actArrayHist: MutableList = ArrayList()
- val actArrayPred: MutableList = ArrayList()
+ val actArrayPrediction: MutableList = ArrayList()
val now = System.currentTimeMillis().toDouble()
val actScale = Scale()
var total: IobTotal
@@ -305,7 +305,7 @@ class GraphData(
}
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
val act: Double = total.activity
- if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPred.add(ScaledDataPoint(time, act, actScale))
+ if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPrediction.add(ScaledDataPoint(time, act, actScale))
maxIAValue = max(maxIAValue, abs(act))
time += 5 * 60 * 1000L
}
@@ -314,7 +314,7 @@ class GraphData(
it.color = resourceHelper.gc(R.color.activity)
it.thickness = 3
})
- addSeries(FixedLineGraphSeries(Array(actArrayPred.size) { i -> actArrayPred[i] }).also {
+ addSeries(FixedLineGraphSeries(Array(actArrayPrediction.size) { i -> actArrayPrediction[i] }).also {
it.setCustomPaint(Paint().also { paint ->
paint.style = Paint.Style.STROKE
paint.strokeWidth = 3f
@@ -329,8 +329,51 @@ class GraphData(
actScale.setMultiplier(maxY * scale / maxIAValue)
}
+ //Function below show -BGI to be able to compare curves with deviations
+ fun addMinusBGI(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
+ val bgiArrayHist: MutableList = ArrayList()
+ val bgiArrayPrediction: MutableList = ArrayList()
+ val now = System.currentTimeMillis().toDouble()
+ val bgiScale = Scale()
+ var total: IobTotal
+ var maxBGIValue = 0.0
+ var time = fromTime
+ while (time <= toTime) {
+ val profile = profileFunction.getProfile(time)
+ if (profile == null) {
+ time += 5 * 60 * 1000L
+ continue
+ }
+ val deviation = if (devBgiScale) iobCobCalculatorPlugin.getAutosensData(time)?.deviation ?:0.0 else 0.0
+
+ total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
+ val bgi: Double = total.activity * profile.getIsfMgdl(time) * 5.0
+ if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale)) else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, bgiScale))
+ maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation))
+ time += 5 * 60 * 1000L
+ }
+ addSeries(FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also {
+ it.isDrawBackground = false
+ it.color = resourceHelper.gc(R.color.bgi)
+ it.thickness = 3
+ })
+ addSeries(FixedLineGraphSeries(Array(bgiArrayPrediction.size) { i -> bgiArrayPrediction[i] }).also {
+ it.setCustomPaint(Paint().also { paint ->
+ paint.style = Paint.Style.STROKE
+ paint.strokeWidth = 3f
+ paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
+ paint.color = resourceHelper.gc(R.color.bgi)
+ })
+ })
+ if (useForScale) {
+ maxY = maxBGIValue
+ minY = -maxBGIValue
+ }
+ bgiScale.setMultiplier(maxY * scale / maxBGIValue)
+ }
+
// scale in % of vertical size (like 0.3)
- fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean) {
+ fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean, absScale: Boolean) {
val iobSeries: FixedLineGraphSeries
val iobArray: MutableList = ArrayList()
var maxIobValueFound = Double.MIN_VALUE
@@ -340,11 +383,15 @@ class GraphData(
while (time <= toTime) {
val profile = profileFunction.getProfile(time)
var iob = 0.0
- if (profile != null) iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
+ var absIob = 0.0
+ if (profile != null) {
+ iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
+ if (absScale) absIob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob
+ }
if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
iobArray.add(ScaledDataPoint(time, iob, iobScale))
- maxIobValueFound = max(maxIobValueFound, abs(iob))
+ maxIobValueFound = if (absScale) max(maxIobValueFound, abs(absIob)) else max(maxIobValueFound, abs(iob))
lastIob = iob
}
time += 5 * 60 * 1000L
@@ -359,22 +406,22 @@ class GraphData(
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData")
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
val isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null
- val iobPred: MutableList = ArrayList()
- val iobPredArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
- for (i in iobPredArray) {
- iobPred.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
+ val iobPrediction: MutableList = ArrayList()
+ val iobPredictionArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
+ for (i in iobPredictionArray) {
+ iobPrediction.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
}
- addSeries(PointsWithLabelGraphSeries(Array(iobPred.size) { i -> iobPred[i] }))
- val iobPred2: MutableList = ArrayList()
- val iobPredArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
- for (i in iobPredArray2) {
- iobPred2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
+ addSeries(PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }))
+ val iobPrediction2: MutableList = ArrayList()
+ val iobPredictionArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
+ for (i in iobPredictionArray2) {
+ iobPrediction2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
}
- addSeries(PointsWithLabelGraphSeries(Array(iobPred2.size) { i -> iobPred2[i] }))
- aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray))
- aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray2))
+ addSeries(PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] }))
+ aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray))
+ aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray2))
}
if (useForScale) {
maxY = maxIobValueFound
@@ -395,7 +442,7 @@ class GraphData(
while (time <= toTime) {
val profile = profileFunction.getProfile(time)
var iob = 0.0
- if (profile != null) iob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time, profile).iob
+ if (profile != null) iob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob
if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
iobArray.add(ScaledDataPoint(time, iob, iobScale))
@@ -460,14 +507,23 @@ class GraphData(
}
// scale in % of vertical size (like 0.3)
- fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
+ fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
class DeviationDataPoint(x: Double, y: Double, var color: Int, scale: Scale) : ScaledDataPoint(x, y, scale)
val devArray: MutableList = ArrayList()
var maxDevValueFound = 0.0
val devScale = Scale()
var time = fromTime
+ var total: IobTotal
+
while (time <= toTime) {
+ // if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0
+ val bgi: Double = if (devBgiScale) {
+ val profile = profileFunction.getProfile(time)
+ total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
+ total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0
+ } else 0.0
+
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
var color = resourceHelper.gc(R.color.deviationblack) // "="
if (autosensData.type == "" || autosensData.type == "non-meal") {
@@ -480,7 +536,7 @@ class GraphData(
color = resourceHelper.gc(R.color.deviationgrey)
}
devArray.add(DeviationDataPoint(time.toDouble(), autosensData.deviation, color, devScale))
- maxDevValueFound = max(maxDevValueFound, abs(autosensData.deviation))
+ maxDevValueFound = max(maxDevValueFound, max(abs(autosensData.deviation), abs(bgi)))
}
time += 5 * 60 * 1000L
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt
index af7813dba8..0d6defc736 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt
@@ -140,7 +140,7 @@ class PersistentNotificationPlugin @Inject constructor(
line1 = line1aa
if (glucoseStatus != null) {
line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
- + " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units))
+ + " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgDelta, glucoseStatus.avgDelta * Constants.MGDL_TO_MMOLL, units))
line1aa += " " + lastBG.trendArrow.symbol
} else {
line1 += " " +
@@ -207,7 +207,7 @@ class PersistentNotificationPlugin @Inject constructor(
builder.setCategory(NotificationCompat.CATEGORY_STATUS)
builder.setSmallIcon(iconsProvider.getNotificationIcon())
builder.setLargeIcon(resourceHelper.decodeResource(iconsProvider.getIcon()))
- if (line1 != null) builder.setContentTitle(line1)
+ builder.setContentTitle(line1)
if (line2 != null) builder.setContentText(line2)
if (line3 != null) builder.setSubText(line3)
/// Android Auto
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.kt
index 0f61f217f2..b1bee8dca8 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.kt
@@ -11,7 +11,7 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSm
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import java.util.*
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt
index 5988927460..c44460c604 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt
@@ -22,6 +22,7 @@ import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
@@ -32,17 +33,16 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSm
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.receivers.BundleStore
import info.nightscout.androidaps.receivers.DataReceiver
import info.nightscout.androidaps.utils.*
-import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import org.apache.commons.lang3.StringUtils
import java.text.Normalizer
import java.util.*
@@ -69,7 +69,8 @@ class SmsCommunicatorPlugin @Inject constructor(
private val xdripCalibrations: XdripCalibrations,
private var otp: OneTimePassword,
private val config: Config,
- private val dateUtil: DateUtil
+ private val dateUtil: DateUtil,
+ private val uel: UserEntryLogger
) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(SmsCommunicatorFragment::class.java.name)
@@ -268,7 +269,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"BOLUS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 && DateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed)))
- else if (divided.size == 2 && pump.isSuspended) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
+ else if (divided.size == 2 && pump.isSuspended()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"CARBS" ->
@@ -336,7 +337,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS LOOP DISABLE")
+ uel.log("SMS LOOP DISABLE")
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
@@ -360,7 +361,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS LOOP ENABLE")
+ uel.log("SMS LOOP ENABLE")
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)))
rxBus.send(EventRefreshOverview("SMS_LOOP_START"))
@@ -387,7 +388,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS LOOP RESUME")
+ uel.log("SMS LOOP RESUME")
loopPlugin.suspendTo(0L)
rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME"))
commandQueue.cancelTempBasal(true, object : Callback() {
@@ -420,7 +421,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS LOOP SUSPEND")
+ uel.log("SMS LOOP SUSPEND")
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (result.success) {
@@ -448,7 +449,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private fun processTREATMENTS(divided: Array, receivedSms: Sms) {
if (divided[1].toUpperCase(Locale.getDefault()) == "REFRESH") {
- (activePlugin.activeTreatments as TreatmentsPlugin).service.resetTreatments()
+ activePlugin.activeTreatments.service.resetTreatments()
rxBus.send(EventNSClientRestart())
sendSMS(Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT"))
receivedSms.processed = true
@@ -504,7 +505,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS PUMP CONNECT")
+ uel.log("SMS PUMP CONNECT")
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success) {
@@ -533,7 +534,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS PUMP DISCONNECT")
+ uel.log("SMS PUMP DISCONNECT")
val profile = profileFunction.getProfile()
loopPlugin.disconnectPump(duration, profile)
rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT"))
@@ -587,9 +588,10 @@ class SmsCommunicatorPlugin @Inject constructor(
val finalPercentage = percentage
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS PROFILE $reply")
activePlugin.activeTreatments.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
- sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.profileswitchcreated)))
+ val replyText = resourceHelper.gs(R.string.profileswitchcreated)
+ sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS PROFILE", replyText)
}
})
}
@@ -605,17 +607,18 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS BASAL $reply")
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (result.success) {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BASAL", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcancelfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BASAL", replyText)
}
}
})
@@ -637,17 +640,18 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS BASAL $reply")
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() {
override fun run() {
if (result.success) {
var replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BASAL", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BASAL", replyText)
}
}
})
@@ -670,7 +674,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS BASAL $reply")
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() {
override fun run() {
if (result.success) {
@@ -678,10 +681,12 @@ class SmsCommunicatorPlugin @Inject constructor(
else String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BASAL", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BASAL", replyText)
}
}
})
@@ -698,7 +703,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS EXTENDED $reply")
commandQueue.cancelExtended(object : Callback() {
override fun run() {
if (result.success) {
@@ -709,6 +713,7 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = resourceHelper.gs(R.string.smscommunicator_extendedcancelfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS EXTENDED", replyText)
}
}
})
@@ -727,7 +732,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS EXTENDED $reply")
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
override fun run() {
if (result.success) {
@@ -735,10 +739,12 @@ class SmsCommunicatorPlugin @Inject constructor(
if (config.APS) replyText += "\n" + resourceHelper.gs(R.string.loopsuspended)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS EXTENDED", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_extendedfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS EXTENDED", replyText)
}
}
})
@@ -763,7 +769,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(bolus) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS BOLUS $reply")
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = aDouble()
detailedBolusInfo.source = Source.USER
@@ -808,10 +813,12 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BOLUS", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_bolusfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS BOLUS", replyText)
}
}
})
@@ -840,7 +847,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(grams, time) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS CARBS $reply")
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.carbs = anInteger().toDouble()
detailedBolusInfo.source = Source.USER
@@ -852,10 +858,12 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS CARBS", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_carbsfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS CARBS", replyText)
}
}
})
@@ -864,6 +872,7 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS CARBS", replyText)
}
}
})
@@ -881,7 +890,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS TARGET $reply")
val units = profileFunction.getUnits()
var keyDuration = 0
var defaultTargetDuration = 0
@@ -929,6 +937,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val ttString = if (units == Constants.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_set), ttString, ttDuration)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS TARGET", replyText)
}
})
} else if (isStop) {
@@ -937,7 +946,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS TARGET $reply")
val tempTarget = TempTarget()
.source(Source.USER)
.date(DateUtil.now())
@@ -947,6 +955,7 @@ class SmsCommunicatorPlugin @Inject constructor(
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_canceled))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS TARGET", reply)
}
})
} else
@@ -962,10 +971,10 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS SMS $reply")
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS SMS", replyText)
}
})
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
@@ -979,9 +988,11 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(cal) {
override fun run() {
- aapsLogger.debug("USER ENTRY: SMS CAL $reply")
val result = xdripCalibrations.sendIntent(aDouble!!)
- if (result) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationsent))) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationfailed)))
+ val replyText =
+ if (result) resourceHelper.gs(R.string.smscommunicator_calibrationsent) else resourceHelper.gs(R.string.smscommunicator_calibrationfailed)
+ sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
+ uel.log("SMS CAL", replyText)
}
})
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt
index d11ee90f70..162c128c58 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt
@@ -15,6 +15,7 @@ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.databinding.ActivitySmscommunicatorOtpBinding
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
@@ -31,6 +32,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var otp: OneTimePassword
+ @Inject lateinit var uel: UserEntryLogger
private lateinit var binding: ActivitySmscommunicatorOtpBinding
@@ -70,6 +72,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
resourceHelper.gs(R.string.smscommunicator_otp_reset_title),
resourceHelper.gs(R.string.smscommunicator_otp_reset_prompt),
Runnable {
+ uel.log("OTP RESET")
otp.ensureKey(true)
updateGui()
ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_reset_successful))
@@ -85,6 +88,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
val clip = ClipData.newPlainText("OTP Secret", otp.provisioningSecret())
clipboard.primaryClip = clip
ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_export_successful))
+ uel.log("OTP EXPORT")
})
true
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt
index 3da7ec902b..a1126eafcb 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt
@@ -14,7 +14,7 @@ import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolD
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolResetData
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolUpdateGUI
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt
index c3b6573060..24efde91d7 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt
@@ -30,7 +30,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt
index 667541c99b..2fbdbe6360 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt
@@ -8,6 +8,10 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.dana.DanaPump
+import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
+import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
+import info.nightscout.androidaps.danar.DanaRPlugin
+import info.nightscout.androidaps.danars.DanaRSPlugin
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
@@ -18,23 +22,23 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
-import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
+import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
-import info.nightscout.androidaps.danar.DanaRPlugin
-import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
-import info.nightscout.androidaps.danars.DanaRSPlugin
-import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.wizard.BolusWizard
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import java.text.DateFormat
import java.text.DecimalFormat
import java.text.SimpleDateFormat
@@ -46,6 +50,7 @@ import javax.inject.Singleton
class ActionStringHandler @Inject constructor(
private val sp: SP,
private val rxBus: RxBusWrapper,
+ aapsSchedulers: AapsSchedulers,
private val resourceHelper: ResourceHelper,
private val injector: HasAndroidInjector,
private val context: Context,
@@ -53,6 +58,7 @@ class ActionStringHandler @Inject constructor(
private val profileFunction: ProfileFunction,
private val loopPlugin: LoopPlugin,
private val wearPlugin: WearPlugin,
+ private val fabricPrivacy: FabricPrivacy,
private val commandQueue: CommandQueueProvider,
private val activePlugin: ActivePluginProvider,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
@@ -73,10 +79,18 @@ class ActionStringHandler @Inject constructor(
private var lastConfirmActionString: String? = null
private var lastBolusWizard: BolusWizard? = null
- // TODO Adrian use RxBus instead of Lazy + cross dependency
+ private val disposable = CompositeDisposable()
+
+ init {
+ disposable += rxBus
+ .toObservable(EventWearDoAction::class.java)
+ .observeOn(aapsSchedulers.main)
+ .subscribe({ handleInitiate(it.action) }, fabricPrivacy::logException)
+ }
+
@Synchronized
- fun handleInitiate(actionString: String) {
- if (!sp.getBoolean("wearcontrol", false)) return
+ private fun handleInitiate(actionString: String) {
+ if (!sp.getBoolean(R.string.key_wear_control, false)) return
lastBolusWizard = null
var rTitle = "CONFIRM" //TODO: i18n
var rMessage = ""
@@ -248,7 +262,7 @@ class ActionStringHandler @Inject constructor(
rAction = "statusmessage"
rMessage = "OLD DATA - "
//if pump is not busy: try to fetch data
- if (activePump.isBusy) {
+ if (activePump.isBusy()) {
rMessage += resourceHelper.gs(R.string.pumpbusy)
} else {
rMessage += "trying to fetch data from pump."
@@ -459,7 +473,7 @@ class ActionStringHandler @Inject constructor(
@Synchronized
fun handleConfirmation(actionString: String) {
- if (!sp.getBoolean("wearcontrol", false)) return
+ if (!sp.getBoolean(R.string.key_wear_control, false)) return
//Guard from old or duplicate confirmations
if (lastConfirmActionString == null) return
if (lastConfirmActionString != actionString) return
@@ -614,13 +628,5 @@ class ActionStringHandler @Inject constructor(
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;
}
-*/
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/events/EventWearDoAction.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/events/EventWearDoAction.kt
new file mode 100644
index 0000000000..7d8bb75403
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/events/EventWearDoAction.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.plugins.general.wear.events
+
+import info.nightscout.androidaps.events.Event
+
+class EventWearDoAction (val action: String) : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java
index ae00054fe7..9f0c38d1a6 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java
@@ -45,9 +45,10 @@ import info.nightscout.androidaps.interfaces.ProfileFunction;
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.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
-import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
+import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
@@ -65,6 +66,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
@Inject public WearPlugin wearPlugin;
@Inject public ResourceHelper resourceHelper;
@Inject public SP sp;
+ @Inject public RxBusWrapper rxBus;
@Inject public ProfileFunction profileFunction;
@Inject public DefaultValueHelper defaultValueHelper;
@Inject public NSDeviceStatus nsDeviceStatus;
@@ -72,7 +74,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
@Inject public LoopPlugin loopPlugin;
@Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin;
@Inject public TreatmentsPlugin treatmentsPlugin;
- @Inject public ActionStringHandler actionStringHandler;
@Inject public AppRepository repository;
@Inject ReceiverStatusStore receiverStatusStore;
@Inject Config config;
@@ -260,13 +261,13 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
if (event != null && event.getPath().equals(WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
String actionstring = new String(event.getData());
aapsLogger.debug(LTag.WEAR, "Wear: " + actionstring);
- actionStringHandler.handleInitiate(actionstring);
+ rxBus.send(new EventWearDoAction(actionstring));
}
if (event != null && event.getPath().equals(WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
String actionstring = new String(event.getData());
aapsLogger.debug(LTag.WEAR, "Wear Confirm: " + actionstring);
- actionStringHandler.handleConfirmation(actionstring);
+ rxBus.send(new EventWearDoAction(actionstring));
}
}
}
@@ -288,10 +289,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
if (wearIntegration()) {
final DataMap dataMap = dataMapSingleBG(lastBG, glucoseStatus);
- if (dataMap == null) {
- ToastUtils.showToastInUiThread(this, resourceHelper.gs(R.string.noprofile));
- return;
- }
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dataMap);
}
@@ -323,9 +320,9 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
dataMap.putString("delta", "--");
dataMap.putString("avgDelta", "--");
} else {
- dataMap.putString("slopeArrow", slopeArrow(glucoseStatus.delta));
- dataMap.putString("delta", deltastring(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units));
- dataMap.putString("avgDelta", deltastring(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units));
+ dataMap.putString("slopeArrow", slopeArrow(glucoseStatus.getDelta()));
+ dataMap.putString("delta", deltastring(glucoseStatus.getDelta(), glucoseStatus.getDelta() * Constants.MGDL_TO_MMOLL, units));
+ dataMap.putString("avgDelta", deltastring(glucoseStatus.getAvgDelta(), glucoseStatus.getAvgDelta() * Constants.MGDL_TO_MMOLL, units));
}
dataMap.putLong("sgvLevel", sgvLevel);
dataMap.putDouble("sgvDouble", lastBG.getValue());
@@ -743,12 +740,12 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
private void sendPreferences() {
if (googleApiClient != null && googleApiClient.isConnected()) {
- boolean wearcontrol = sp.getBoolean("wearcontrol", false);
+ boolean wearcontrol = sp.getBoolean(R.string.key_wear_control, false);
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH);
//unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
- dataMapRequest.getDataMap().putBoolean("wearcontrol", wearcontrol);
+ dataMapRequest.getDataMap().putBoolean(resourceHelper.gs(R.string.key_wear_control), wearcontrol);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt
index 63ada549fb..7dd387b89a 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt
@@ -19,7 +19,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorP
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.java b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.java
deleted file mode 100644
index ee682272a1..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package info.nightscout.androidaps.plugins.insulin;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.util.AttributeSet;
-
-import com.jjoe64.graphview.GraphView;
-import com.jjoe64.graphview.series.DataPoint;
-import com.jjoe64.graphview.series.LineGraphSeries;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import info.nightscout.androidaps.data.Iob;
-import info.nightscout.androidaps.db.Treatment;
-import info.nightscout.androidaps.interfaces.InsulinInterface;
-
-/**
- * Created by mike on 21.04.2017.
- */
-
-public class ActivityGraph extends GraphView {
- Context context;
-
- public ActivityGraph(Context context) {
- super(context);
- this.context = context;
- }
-
- public ActivityGraph(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.context = context;
- }
-
- public void show(InsulinInterface insulin) {
- removeAllSeries();
- mSecondScale = null;
- double dia = insulin.getDia();
- int hours = (int) Math.floor(dia + 1);
-
- Treatment t = new Treatment();
- t.date = 0;
- t.insulin = 1d;
-
- LineGraphSeries activitySeries = null;
- LineGraphSeries iobSeries = null;
- List activityArray = new ArrayList<>();
- List iobArray = new ArrayList<>();
-
- for (long time = 0; time <= hours * 60 * 60 * 1000; time += 5 * 60 * 1000L) {
- Iob iob = t.iobCalc(time, dia);
- activityArray.add(new DataPoint(time / 60.0 / 1000, iob.activityContrib));
- iobArray.add(new DataPoint(time / 60.0 / 1000, iob.iobContrib));
- }
-
- DataPoint[] activityDataPoints = new DataPoint[activityArray.size()];
- activityDataPoints = activityArray.toArray(activityDataPoints);
- addSeries(activitySeries = new LineGraphSeries<>(activityDataPoints));
- activitySeries.setThickness(8);
-
- getViewport().setXAxisBoundsManual(true);
- getViewport().setMinX(0);
- getViewport().setMaxX(hours * 60);
- getGridLabelRenderer().setNumHorizontalLabels(hours + 1);
- getGridLabelRenderer().setHorizontalAxisTitle("[min]");
- getGridLabelRenderer().setVerticalLabelsColor(activitySeries.getColor());
-
- DataPoint[] iobDataPoints = new DataPoint[iobArray.size()];
- iobDataPoints = iobArray.toArray(iobDataPoints);
- getSecondScale().addSeries(iobSeries = new LineGraphSeries<>(iobDataPoints));
- iobSeries.setDrawBackground(true);
- iobSeries.setColor(Color.MAGENTA);
- iobSeries.setBackgroundColor(Color.argb(70, 255, 0, 255));
- getSecondScale().setMinY(0);
- getSecondScale().setMaxY(1);
- getGridLabelRenderer().setVerticalLabelsSecondScaleColor(Color.MAGENTA);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.kt
new file mode 100644
index 0000000000..a6575c1886
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.kt
@@ -0,0 +1,56 @@
+package info.nightscout.androidaps.plugins.insulin
+
+import android.content.Context
+import android.graphics.Color
+import android.util.AttributeSet
+import com.jjoe64.graphview.GraphView
+import com.jjoe64.graphview.series.DataPoint
+import com.jjoe64.graphview.series.LineGraphSeries
+import info.nightscout.androidaps.db.Treatment
+import info.nightscout.androidaps.interfaces.InsulinInterface
+import info.nightscout.androidaps.utils.T
+import java.util.*
+import kotlin.math.floor
+
+class ActivityGraph : GraphView {
+
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ fun show(insulin: InsulinInterface) {
+ removeAllSeries()
+ mSecondScale = null
+ val hours = floor(insulin.dia + 1).toLong()
+ val t = Treatment().also {
+ it.date = 0
+ it.insulin = 1.0
+ }
+ val activityArray: MutableList = ArrayList()
+ val iobArray: MutableList = ArrayList()
+ var time: Long = 0
+ while (time <= T.hours(hours).msecs()) {
+ val iob = t.iobCalc(time, insulin.dia)
+ activityArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.activityContrib))
+ iobArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.iobContrib))
+ time += T.mins(5).msecs()
+ }
+ addSeries(LineGraphSeries(Array(activityArray.size) { i -> activityArray[i] }).also {
+ it.thickness = 8
+ gridLabelRenderer.verticalLabelsColor = it.color
+ })
+ viewport.isXAxisBoundsManual = true
+ viewport.setMinX(0.0)
+ viewport.setMaxX((hours * 60).toDouble())
+ gridLabelRenderer.numHorizontalLabels = (hours + 1).toInt()
+ gridLabelRenderer.horizontalAxisTitle = "[min]"
+ secondScale.addSeries(LineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also {
+ it.isDrawBackground = true
+ it.color = Color.MAGENTA
+ it.backgroundColor = Color.argb(70, 255, 0, 255)
+ })
+ secondScale.minY = 0.0
+ secondScale.maxY = 1.0
+ gridLabelRenderer.verticalLabelsSecondScaleColor = Color.MAGENTA
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.java
deleted file mode 100644
index a4fa66fee1..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package info.nightscout.androidaps.plugins.iob.iobCobCalculator;
-
-/**
- * Created by mike on 10.06.2017.
- */
-
-public class BasalData {
- public double basal;
- public double tempBasalAbsolute;
- public boolean isTempBasalRunning;
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.kt
new file mode 100644
index 0000000000..ffeb031b95
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.kt
@@ -0,0 +1,8 @@
+package info.nightscout.androidaps.plugins.iob.iobCobCalculator
+
+class BasalData {
+
+ var basal = 0.0
+ var tempBasalAbsolute = 0.0
+ var isTempBasalRunning = false
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/CobInfo.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/CobInfo.java
deleted file mode 100644
index fb99067008..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/CobInfo.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package info.nightscout.androidaps.plugins.iob.iobCobCalculator;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import info.nightscout.androidaps.utils.DecimalFormatter;
-
-public class CobInfo {
- /** All COB up to now, including carbs not yet processed by IobCob calculation. */
- @Nullable
- public final Double displayCob;
- public final double futureCarbs;
-
- public CobInfo(@Nullable Double displayCob, double futureCarbs) {
- this.displayCob = displayCob;
- this.futureCarbs = futureCarbs;
- }
-
- @NonNull
- public String generateCOBString() {
- String cobStringResult = "--g";
- if (displayCob != null) {
- cobStringResult = DecimalFormatter.to0Decimal(displayCob);
- if (futureCarbs > 0) {
- cobStringResult += "(" + DecimalFormatter.to0Decimal(futureCarbs) + ")";
- }
- cobStringResult += "g";
- }
- return cobStringResult;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/CobInfo.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/CobInfo.kt
new file mode 100644
index 0000000000..2676fde7b6
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/CobInfo.kt
@@ -0,0 +1,18 @@
+package info.nightscout.androidaps.plugins.iob.iobCobCalculator
+
+import info.nightscout.androidaps.utils.DecimalFormatter
+
+/** All COB up to now, including carbs not yet processed by IobCob calculation. */
+class CobInfo(val displayCob: Double?, val futureCarbs: Double) {
+
+ fun generateCOBString(): String {
+ var cobStringResult = "--g"
+ if (displayCob != null) {
+ cobStringResult = DecimalFormatter.to0Decimal(displayCob)
+ if (futureCarbs > 0)
+ cobStringResult += "(${DecimalFormatter.to0Decimal(futureCarbs)})"
+ cobStringResult += "g"
+ }
+ return cobStringResult
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java
deleted file mode 100644
index 268f09eaa9..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package info.nightscout.androidaps.plugins.iob.iobCobCalculator;
-
-import androidx.annotation.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.database.entities.GlucoseValue;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.DecimalFormatter;
-import info.nightscout.androidaps.utils.Round;
-
-/**
- * Created by mike on 04.01.2017.
- */
-
-public class GlucoseStatus {
- @Inject public AAPSLogger aapsLogger;
- @Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin;
-
- private final HasAndroidInjector injector;
-
- public double glucose = 0d;
- public double noise = 0d;
- public double delta = 0d;
- public double avgdelta = 0d;
- public double short_avgdelta = 0d;
- public double long_avgdelta = 0d;
- public long date = 0L;
-
-
- public String log() {
- return "Glucose: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl " +
- "Noise: " + DecimalFormatter.to0Decimal(noise) + " " +
- "Delta: " + DecimalFormatter.to0Decimal(delta) + " mg/dl" +
- "Short avg. delta: " + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl " +
- "Long avg. delta: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
- }
-
- public GlucoseStatus(HasAndroidInjector injector) {
- injector.androidInjector().inject(this);
- this.injector = injector;
- }
-
- public GlucoseStatus round() {
- this.glucose = Round.roundTo(this.glucose, 0.1);
- this.noise = Round.roundTo(this.noise, 0.01);
- this.delta = Round.roundTo(this.delta, 0.01);
- this.avgdelta = Round.roundTo(this.avgdelta, 0.01);
- this.short_avgdelta = Round.roundTo(this.short_avgdelta, 0.01);
- this.long_avgdelta = Round.roundTo(this.long_avgdelta, 0.01);
- return this;
- }
-
-
- @Nullable
- public GlucoseStatus getGlucoseStatusData() {
- return getGlucoseStatusData(false);
- }
-
- @Nullable
- public GlucoseStatus getGlucoseStatusData(boolean allowOldData) {
- // load 45min
- //long fromtime = DateUtil.now() - 60 * 1000L * 45;
- //List data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false);
-
- synchronized (iobCobCalculatorPlugin.getDataLock()) {
-
- List data = iobCobCalculatorPlugin.getBgReadings();
-
- if (data == null) {
- aapsLogger.debug(LTag.GLUCOSE, "data=null");
- return null;
- }
-
- int sizeRecords = data.size();
- if (sizeRecords == 0) {
- aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0");
- return null;
- }
-
- if (data.get(0).getTimestamp() < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
- aapsLogger.debug(LTag.GLUCOSE, "olddata");
- return null;
- }
-
- GlucoseValue now = data.get(0);
- long now_date = now.getTimestamp();
- double change;
-
- if (sizeRecords == 1) {
- GlucoseStatus status = new GlucoseStatus(injector);
- status.glucose = now.getValue();
- status.noise = 0d;
- status.short_avgdelta = 0d;
- status.delta = 0d;
- status.long_avgdelta = 0d;
- status.avgdelta = 0d; // for OpenAPS MA
- status.date = now_date;
- aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==1");
- return status.round();
- }
-
- ArrayList now_value_list = new ArrayList<>();
- ArrayList last_deltas = new ArrayList<>();
- ArrayList short_deltas = new ArrayList<>();
- ArrayList long_deltas = new ArrayList<>();
-
- // Use the latest sgv value in the now calculations
- now_value_list.add(now.getValue());
-
- for (int i = 1; i < sizeRecords; i++) {
- if (data.get(i).getValue() > 38) {
- GlucoseValue then = data.get(i);
- long then_date = then.getTimestamp();
- double avgdelta;
- long minutesago;
-
- minutesago = Math.round((now_date - then_date) / (1000d * 60));
- // multiply by 5 to get the same units as delta, i.e. mg/dL/5m
- change = now.getValue() - then.getValue();
- avgdelta = change / minutesago * 5;
-
- aapsLogger.debug(LTag.GLUCOSE, then.toString() + " minutesago=" + minutesago + " avgdelta=" + avgdelta);
-
- // use the average of all data points in the last 2.5m for all further "now" calculations
- if (0 < minutesago && minutesago < 2.5) {
- // Keep and average all values within the last 2.5 minutes
- now_value_list.add(then.getValue());
- now.setValue(average(now_value_list));
- // short_deltas are calculated from everything ~5-15 minutes ago
- } else if (2.5 < minutesago && minutesago < 17.5) {
- //console.error(minutesago, avgdelta);
- short_deltas.add(avgdelta);
- // last_deltas are calculated from everything ~5 minutes ago
- if (2.5 < minutesago && minutesago < 7.5) {
- last_deltas.add(avgdelta);
- }
- // long_deltas are calculated from everything ~20-40 minutes ago
- } else if (17.5 < minutesago && minutesago < 42.5) {
- long_deltas.add(avgdelta);
- } else {
- // Do not process any more records after >= 42.5 minutes
- break;
- }
- }
- }
-
- GlucoseStatus status = new GlucoseStatus(injector);
- status.glucose = now.getValue();
- status.date = now_date;
- status.noise = 0d; //for now set to nothing as not all CGMs report noise
-
- status.short_avgdelta = average(short_deltas);
-
- if (last_deltas.isEmpty()) {
- status.delta = status.short_avgdelta;
- } else {
- status.delta = average(last_deltas);
- }
-
- status.long_avgdelta = average(long_deltas);
- status.avgdelta = status.short_avgdelta; // for OpenAPS MA
-
- aapsLogger.debug(LTag.GLUCOSE, status.log());
- return status.round();
- }
- }
-
- public static double average(ArrayList array) {
- double sum = 0d;
-
- if (array.size() == 0)
- return 0d;
-
- for (Double value : array) {
- sum += value;
- }
- return sum / array.size();
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.kt
new file mode 100644
index 0000000000..d6a6c1ff7a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatus.kt
@@ -0,0 +1,146 @@
+package info.nightscout.androidaps.plugins.iob.iobCobCalculator
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.DecimalFormatter
+import info.nightscout.androidaps.utils.Round
+import java.util.*
+import javax.inject.Inject
+import kotlin.math.roundToLong
+
+class GlucoseStatus(private val injector: HasAndroidInjector) {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
+
+ var glucose = 0.0
+ var noise = 0.0
+ var delta = 0.0
+ var avgDelta = 0.0
+ var shortAvgDelta = 0.0
+ var longAvgDelta = 0.0
+ var date = 0L
+
+ init {
+ injector.androidInjector().inject(this)
+ }
+
+ fun log(): String {
+ return "Glucose: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl " +
+ "Noise: " + DecimalFormatter.to0Decimal(noise) + " " +
+ "Delta: " + DecimalFormatter.to0Decimal(delta) + " mg/dl" +
+ "Short avg. delta: " + " " + DecimalFormatter.to2Decimal(shortAvgDelta) + " mg/dl " +
+ "Long avg. delta: " + DecimalFormatter.to2Decimal(longAvgDelta) + " mg/dl"
+ }
+
+ fun round(): GlucoseStatus {
+ glucose = Round.roundTo(glucose, 0.1)
+ noise = Round.roundTo(noise, 0.01)
+ delta = Round.roundTo(delta, 0.01)
+ avgDelta = Round.roundTo(avgDelta, 0.01)
+ shortAvgDelta = Round.roundTo(shortAvgDelta, 0.01)
+ longAvgDelta = Round.roundTo(longAvgDelta, 0.01)
+ return this
+ }
+
+ val glucoseStatusData: GlucoseStatus?
+ get() = getGlucoseStatusData(false)
+
+ fun getGlucoseStatusData(allowOldData: Boolean): GlucoseStatus? {
+ synchronized(iobCobCalculatorPlugin.dataLock) {
+ val data = iobCobCalculatorPlugin.bgReadings
+ val sizeRecords = data.size
+ if (sizeRecords == 0) {
+ aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0")
+ return null
+ }
+ if (data[0].timestamp < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
+ aapsLogger.debug(LTag.GLUCOSE, "oldData")
+ return null
+ }
+ val now = data[0]
+ val nowDate = now.timestamp
+ var change: Double
+ if (sizeRecords == 1) {
+ val status = GlucoseStatus(injector)
+ status.glucose = now.value
+ status.noise = 0.0
+ status.shortAvgDelta = 0.0
+ status.delta = 0.0
+ status.longAvgDelta = 0.0
+ status.avgDelta = 0.0 // for OpenAPS MA
+ status.date = nowDate
+ aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==1")
+ return status.round()
+ }
+ val nowValueList = ArrayList()
+ val lastDeltas = ArrayList()
+ val shortDeltas = ArrayList()
+ val longDeltas = ArrayList()
+
+ // Use the latest sgv value in the now calculations
+ nowValueList.add(now.value)
+ for (i in 1 until sizeRecords) {
+ if (data[i].value > 38) {
+ val then = data[i]
+ val thenDate = then.timestamp
+
+ val minutesAgo = ((nowDate - thenDate) / (1000.0 * 60)).roundToLong()
+ // multiply by 5 to get the same units as delta, i.e. mg/dL/5m
+ change = now.value - then.value
+ val avgDel = change / minutesAgo * 5
+ aapsLogger.debug(LTag.GLUCOSE, "$then minutesAgo=$minutesAgo avgDelta=$avgDel")
+
+ // use the average of all data points in the last 2.5m for all further "now" calculations
+ if (0 < minutesAgo && minutesAgo < 2.5) {
+ // Keep and average all values within the last 2.5 minutes
+ nowValueList.add(then.value)
+ now.value = average(nowValueList)
+ // short_deltas are calculated from everything ~5-15 minutes ago
+ } else if (2.5 < minutesAgo && minutesAgo < 17.5) {
+ //console.error(minutesAgo, avgDelta);
+ shortDeltas.add(avgDel)
+ // last_deltas are calculated from everything ~5 minutes ago
+ if (2.5 < minutesAgo && minutesAgo < 7.5) {
+ lastDeltas.add(avgDel)
+ }
+ // long_deltas are calculated from everything ~20-40 minutes ago
+ } else if (17.5 < minutesAgo && minutesAgo < 42.5) {
+ longDeltas.add(avgDel)
+ } else {
+ // Do not process any more records after >= 42.5 minutes
+ break
+ }
+ }
+ }
+ val status = GlucoseStatus(injector)
+ status.glucose = now.value
+ status.date = nowDate
+ status.noise = 0.0 //for now set to nothing as not all CGMs report noise
+ status.shortAvgDelta = average(shortDeltas)
+ if (lastDeltas.isEmpty()) {
+ status.delta = status.shortAvgDelta
+ } else {
+ status.delta = average(lastDeltas)
+ }
+ status.longAvgDelta = average(longDeltas)
+ status.avgDelta = status.shortAvgDelta // for OpenAPS MA
+ aapsLogger.debug(LTag.GLUCOSE, status.log())
+ return status.round()
+ }
+ }
+
+ companion object {
+
+ fun average(array: ArrayList): Double {
+ var sum = 0.0
+ if (array.size == 0) return 0.0
+ for (value in array) {
+ sum += value
+ }
+ return sum / array.size
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java
deleted file mode 100644
index 59fdd1ccff..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java
+++ /dev/null
@@ -1,968 +0,0 @@
-package info.nightscout.androidaps.plugins.iob.iobCobCalculator;
-
-import android.os.SystemClock;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.collection.LongSparseArray;
-
-import org.json.JSONArray;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.IobTotal;
-import info.nightscout.androidaps.data.MealData;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.database.AppRepository;
-import info.nightscout.androidaps.database.entities.GlucoseValue;
-import info.nightscout.androidaps.db.TemporaryBasal;
-import info.nightscout.androidaps.db.Treatment;
-import info.nightscout.androidaps.events.Event;
-import info.nightscout.androidaps.events.EventAppInitialized;
-import info.nightscout.androidaps.events.EventConfigBuilderChange;
-import info.nightscout.androidaps.events.EventNewBG;
-import info.nightscout.androidaps.events.EventNewBasalProfile;
-import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
-import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginDescription;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.DecimalFormatter;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.T;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.rx.AapsSchedulers;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-import io.reactivex.disposables.CompositeDisposable;
-
-import static info.nightscout.androidaps.utils.DateUtil.now;
-
-@Singleton
-public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculatorInterface {
- private final HasAndroidInjector injector;
- private final AapsSchedulers aapsSchedulers;
- private final SP sp;
- private final RxBusWrapper rxBus;
- private final ResourceHelper resourceHelper;
- private final ProfileFunction profileFunction;
- private final ActivePluginProvider activePlugin;
- private final TreatmentsPlugin treatmentsPlugin;
- private final SensitivityOref1Plugin sensitivityOref1Plugin;
- private final SensitivityAAPSPlugin sensitivityAAPSPlugin;
- private final SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin;
- private final FabricPrivacy fabricPrivacy;
- private final DateUtil dateUtil;
- private final AppRepository repository;
-
- private final CompositeDisposable disposable = new CompositeDisposable();
-
- private LongSparseArray iobTable = new LongSparseArray<>(); // oldest at index 0
- private LongSparseArray absIobTable = new LongSparseArray<>(); // oldest at index 0, absolute insulin in the body
- private LongSparseArray autosensDataTable = new LongSparseArray<>(); // oldest at index 0
- private LongSparseArray basalDataTable = new LongSparseArray<>(); // oldest at index 0
-
- private volatile List bgReadings = null; // newest at index 0
- private volatile List bucketed_data = null;
-
- // we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values
- // once referenceTime != null all bucketed data should be (x * 5min) from referenceTime
- Long referenceTime = null;
- private Boolean lastUsed5minCalculation = null; // true if used 5min bucketed data
-
- private final Object dataLock = new Object();
-
- boolean stopCalculationTrigger = false;
- private Thread thread = null;
-
- @Inject
- public IobCobCalculatorPlugin(
- HasAndroidInjector injector,
- AAPSLogger aapsLogger,
- AapsSchedulers aapsSchedulers,
- RxBusWrapper rxBus,
- SP sp,
- ResourceHelper resourceHelper,
- ProfileFunction profileFunction,
- ActivePluginProvider activePlugin,
- TreatmentsPlugin treatmentsPlugin,
- SensitivityOref1Plugin sensitivityOref1Plugin,
- SensitivityAAPSPlugin sensitivityAAPSPlugin,
- SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin,
- FabricPrivacy fabricPrivacy,
- DateUtil dateUtil,
- AppRepository repository
- ) {
- super(new PluginDescription()
- .mainType(PluginType.GENERAL)
- .pluginName(R.string.iobcobcalculator)
- .showInList(false)
- .neverVisible(true)
- .alwaysEnabled(true),
- aapsLogger, resourceHelper, injector
- );
- this.injector = injector;
- this.aapsSchedulers = aapsSchedulers;
- this.sp = sp;
- this.rxBus = rxBus;
- this.resourceHelper = resourceHelper;
- this.profileFunction = profileFunction;
- this.activePlugin = activePlugin;
- this.treatmentsPlugin = treatmentsPlugin;
- this.sensitivityOref1Plugin = sensitivityOref1Plugin;
- this.sensitivityAAPSPlugin = sensitivityAAPSPlugin;
- this.sensitivityWeightedAveragePlugin = sensitivityWeightedAveragePlugin;
- this.fabricPrivacy = fabricPrivacy;
- this.dateUtil = dateUtil;
- this.repository = repository;
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- // EventConfigBuilderChange
- disposable.add(rxBus
- .toObservable(EventConfigBuilderChange.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> {
- stopCalculation("onEventConfigBuilderChange");
- synchronized (dataLock) {
- getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of configuration change.");
- resetData();
- }
- runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, true, event);
- }, fabricPrivacy::logException)
- );
- // EventNewBasalProfile
- disposable.add(rxBus
- .toObservable(EventNewBasalProfile.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> {
- if (event == null) { // on init no need of reset
- return;
- }
- stopCalculation("onNewProfile");
- synchronized (dataLock) {
- getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of new profile.");
- resetData();
- }
- runCalculation("onNewProfile", System.currentTimeMillis(), false, true, event);
- }, fabricPrivacy::logException)
- );
- // EventNewBG .... cannot be used for invalidating because only event with last BG is fired
- disposable.add(rxBus
- .toObservable(EventNewBG.class)
- .observeOn(aapsSchedulers.getIo())
- .debounce(1L, TimeUnit.SECONDS)
- .subscribe(event -> {
- stopCalculation("onEventNewBG");
- runCalculation("onEventNewBG", System.currentTimeMillis(), true, true, event);
- }, fabricPrivacy::logException)
- );
- // EventPreferenceChange
- disposable.add(rxBus
- .toObservable(EventPreferenceChange.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> {
- if (event.isChanged(resourceHelper, R.string.key_openapsama_autosens_period) ||
- event.isChanged(resourceHelper, R.string.key_age) ||
- event.isChanged(resourceHelper, R.string.key_absorption_maxtime) ||
- event.isChanged(resourceHelper, R.string.key_openapsama_min_5m_carbimpact) ||
- event.isChanged(resourceHelper, R.string.key_absorption_cutoff) ||
- event.isChanged(resourceHelper, R.string.key_openapsama_autosens_max) ||
- event.isChanged(resourceHelper, R.string.key_openapsama_autosens_min) ||
- event.isChanged(resourceHelper, R.string.key_insulin_oref_peak)
- ) {
- stopCalculation("onEventPreferenceChange");
- synchronized (dataLock) {
- getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of preference change.");
- resetData();
- }
- runCalculation("onEventPreferenceChange", System.currentTimeMillis(), false, true, event);
- }
- }, fabricPrivacy::logException)
- );
- // EventAppInitialized
- disposable.add(rxBus
- .toObservable(EventAppInitialized.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), true, true, event), fabricPrivacy::logException)
- );
- // EventNewHistoryData
- disposable.add(rxBus
- .toObservable(EventNewHistoryData.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> newHistoryData(event, false), fabricPrivacy::logException)
- );
- // EventNewHistoryBgData
- disposable.add(rxBus
- .toObservable(EventNewHistoryBgData.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> newHistoryData(new EventNewHistoryData(event.getTimestamp()), true), fabricPrivacy::logException)
- );
- }
-
- @Override
- protected void onStop() {
- disposable.clear();
- super.onStop();
- }
-
- public LongSparseArray getAutosensDataTable() {
- return autosensDataTable;
- }
-
- public List getBgReadings() {
- return bgReadings;
- }
-
- public void setBgReadings(List bgReadings) {
- this.bgReadings = bgReadings;
- }
-
- public List getBucketedData() {
- return bucketed_data;
- }
-
- public Object getDataLock() {
- return dataLock;
- }
-
- // roundup to whole minute
- public static long roundUpTime(long time) {
- if (time % 60000 == 0)
- return time;
- long rounded = (time / 60000 + 1) * 60000;
- return rounded;
- }
-
- long adjustToReferenceTime(long someTime) {
- if (referenceTime == null) {
- referenceTime = someTime;
- return someTime;
- }
- long diff = Math.abs(someTime - referenceTime);
- diff %= T.mins(5).msecs();
- if (diff > T.mins(2).plus(T.secs(30)).msecs())
- diff = diff - T.mins(5).msecs();
- long newTime = someTime + diff;
- return newTime;
- }
-
- void loadBgData(long to) {
- Profile profile = profileFunction.getProfile(to);
- double dia = Constants.defaultDIA;
- if (profile != null) dia = profile.getDia();
- long start = to - T.hours((long) (24 + dia)).msecs();
- if (DateUtil.isCloseToNow(to)) {
- // if close to now expect there can be some readings with time in close future (caused by wrong time setting)
- // so read all records
- bgReadings = repository.compatGetBgReadingsDataFromTime(start, false).blockingGet();
- getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start));
- } else {
- bgReadings = repository.compatGetBgReadingsDataFromTime(start, to, false).blockingGet();
- getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to));
- }
- }
-
- public boolean isAbout5minData() {
- synchronized (dataLock) {
- if (bgReadings == null || bgReadings.size() < 3) {
- return true;
- }
- long totalDiff = 0;
- for (int i = 1; i < bgReadings.size(); ++i) {
- long bgTime = bgReadings.get(i).getTimestamp();
- long lastbgTime = bgReadings.get(i - 1).getTimestamp();
- long diff = lastbgTime - bgTime;
- diff %= T.mins(5).msecs();
- if (diff > T.mins(2).plus(T.secs(30)).msecs())
- diff = diff - T.mins(5).msecs();
- totalDiff += diff;
- diff = Math.abs(diff);
- if (diff > T.secs(30).msecs()) {
- getAapsLogger().debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size() + " diff: " + (diff / 1000) + "[s] is5minData: " + false);
- return false;
- }
- }
- long averageDiff = totalDiff / bgReadings.size() / 1000;
- boolean is5mindata = averageDiff < 1;
- getAapsLogger().debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size() + " averageDiff: " + averageDiff + "[s] is5minData: " + is5mindata);
- return is5mindata;
- }
- }
-
- private void resetData() {
- synchronized (dataLock) {
- iobTable = new LongSparseArray<>();
- autosensDataTable = new LongSparseArray<>();
- basalDataTable = new LongSparseArray<>();
- absIobTable = new LongSparseArray<>();
- }
- }
-
- public void createBucketedData() {
- boolean fiveMinData = isAbout5minData();
- if (lastUsed5minCalculation != null && lastUsed5minCalculation != fiveMinData) {
- // changing mode => clear cache
- getAapsLogger().debug("Invalidating cached data because of changed mode.");
- resetData();
- }
- lastUsed5minCalculation = fiveMinData;
- if (isAbout5minData())
- createBucketedData5min();
- else
- createBucketedDataRecalculated();
- }
-
- @Nullable
- public GlucoseValue findNewer(long time) {
- GlucoseValue lastFound = bgReadings.get(0);
- if (lastFound.getTimestamp() < time) return null;
- for (int i = 1; i < bgReadings.size(); ++i) {
- if (bgReadings.get(i).getTimestamp() == time) return bgReadings.get(i);
- if (bgReadings.get(i).getTimestamp() > time) continue;
- lastFound = bgReadings.get(i - 1);
- if (bgReadings.get(i).getTimestamp() < time) break;
- }
- return lastFound;
- }
-
- @Nullable
- public GlucoseValue findOlder(long time) {
- GlucoseValue lastFound = bgReadings.get(bgReadings.size() - 1);
- if (lastFound.getTimestamp() > time) return null;
- for (int i = bgReadings.size() - 2; i >= 0; --i) {
- if (bgReadings.get(i).getTimestamp() == time) return bgReadings.get(i);
- if (bgReadings.get(i).getTimestamp() < time) continue;
- lastFound = bgReadings.get(i + 1);
- if (bgReadings.get(i).getTimestamp() > time) break;
- }
- return lastFound;
- }
-
- private void createBucketedDataRecalculated() {
- if (bgReadings == null || bgReadings.size() < 3) {
- bucketed_data = null;
- return;
- }
-
- bucketed_data = new ArrayList<>();
- long currentTime = bgReadings.get(0).getTimestamp() - bgReadings.get(0).getTimestamp() % T.mins(5).msecs();
- currentTime = adjustToReferenceTime(currentTime);
- getAapsLogger().debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime));
- //log.debug("First reading: " + new Date(currentTime).toLocaleString());
-
- while (true) {
- // test if current value is older than current time
- GlucoseValue newer = findNewer(currentTime);
- GlucoseValue older = findOlder(currentTime);
- if (newer == null || older == null)
- break;
-
- if (older.getTimestamp() == newer.getTimestamp()) { // direct hit
- bucketed_data.add(new InMemoryGlucoseValue(newer));
- } else {
- double bgDelta = newer.getValue() - older.getValue();
- long timeDiffToNew = newer.getTimestamp() - currentTime;
-
- double currentBg = newer.getValue() - (double) timeDiffToNew / (newer.getTimestamp() - older.getTimestamp()) * bgDelta;
- InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(currentTime, Math.round(currentBg), true);
- bucketed_data.add(newBgreading);
- //log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
- }
- currentTime -= T.mins(5).msecs();
-
- }
- }
-
-
- private void createBucketedData5min() {
- if (bgReadings == null || bgReadings.size() < 3) {
- bucketed_data = null;
- return;
- }
-
- bucketed_data = new ArrayList<>();
- bucketed_data.add(new InMemoryGlucoseValue(bgReadings.get(0)));
- getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgReadings.get(0).getTimestamp()) + " lastbgTime: " + "none-first-value" + " " + bgReadings.get(0).toString());
- int j = 0;
- for (int i = 1; i < bgReadings.size(); ++i) {
- long bgTime = bgReadings.get(i).getTimestamp();
- long lastbgTime = bgReadings.get(i - 1).getTimestamp();
- //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
- if (bgReadings.get(i).getValue() < 39 || bgReadings.get(i - 1).getValue() < 39) {
- throw new IllegalStateException("<39");
- }
-
- long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
- if (Math.abs(elapsed_minutes) > 8) {
- // interpolate missing data points
- double lastbg = bgReadings.get(i - 1).getValue();
- elapsed_minutes = Math.abs(elapsed_minutes);
- //console.error(elapsed_minutes);
- long nextbgTime;
- while (elapsed_minutes > 5) {
- nextbgTime = lastbgTime - 5 * 60 * 1000;
- j++;
- double gapDelta = bgReadings.get(i).getValue() - lastbg;
- //console.error(gapDelta, lastbg, elapsed_minutes);
- double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
- InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(nextbgTime, Math.round(nextbg), true);
- //console.error("Interpolated", bucketed_data[j]);
- bucketed_data.add(newBgreading);
- getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
-
- elapsed_minutes = elapsed_minutes - 5;
- lastbg = nextbg;
- lastbgTime = nextbgTime;
- }
- j++;
- InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).getValue());
- bucketed_data.add(newBgreading);
- getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
- } else if (Math.abs(elapsed_minutes) > 2) {
- j++;
- InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).getValue());
- bucketed_data.add(newBgreading);
- getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
- } else {
- bucketed_data.get(j).setValue((bucketed_data.get(j).getValue() + bgReadings.get(i).getValue()) / 2);
- //log.error("***** Average");
- }
- }
-
- // Normalize bucketed data
- InMemoryGlucoseValue oldest = bucketed_data.get(bucketed_data.size() - 1);
- oldest.setTimestamp(adjustToReferenceTime(oldest.getTimestamp()));
- getAapsLogger().debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(oldest.getTimestamp()));
- for (int i = bucketed_data.size() - 2; i >= 0; i--) {
- InMemoryGlucoseValue current = bucketed_data.get(i);
- InMemoryGlucoseValue previous = bucketed_data.get(i + 1);
- long msecDiff = current.getTimestamp() - previous.getTimestamp();
- long adjusted = (msecDiff - T.mins(5).msecs()) / 1000;
- getAapsLogger().debug(LTag.AUTOSENS, "Adjusting bucketed data time. Current: " + dateUtil.dateAndTimeAndSecondsString(current.getTimestamp()) + " to: " + dateUtil.dateAndTimeAndSecondsString(previous.getTimestamp() + T.mins(5).msecs()) + " by " + adjusted + " sec");
- if (Math.abs(adjusted) > 90) {
- // too big adjustment, fallback to non 5 min data
- getAapsLogger().debug(LTag.AUTOSENS, "Fallback to non 5 min data");
- createBucketedDataRecalculated();
- return;
- }
- current.setTimestamp(previous.getTimestamp() + T.mins(5).msecs());
- }
-
- getAapsLogger().debug(LTag.AUTOSENS, "Bucketed data created. Size: " + bucketed_data.size());
- }
-
- long calculateDetectionStart(long from, boolean limitDataToOldestAvailable) {
- Profile profile = profileFunction.getProfile(from);
- double dia = Constants.defaultDIA;
- if (profile != null) dia = profile.getDia();
-
- long oldestDataAvailable = treatmentsPlugin.oldestDataAvailable();
- long getBGDataFrom;
- if (limitDataToOldestAvailable) {
- getBGDataFrom = Math.max(oldestDataAvailable, (long) (from - T.hours(1).msecs() * (24 + dia)));
- if (getBGDataFrom == oldestDataAvailable)
- getAapsLogger().debug(LTag.AUTOSENS, "Limiting data to oldest available temps: " + dateUtil.dateAndTimeAndSecondsString(oldestDataAvailable));
- } else
- getBGDataFrom = (long) (from - T.hours(1).msecs() * (24 + dia));
- return getBGDataFrom;
- }
-
- public IobTotal calculateFromTreatmentsAndTempsSynchronized(long time, Profile profile) {
- synchronized (dataLock) {
- return calculateFromTreatmentsAndTemps(time, profile);
- }
- }
-
- private IobTotal calculateFromTreatmentsAndTempsSynchronized(long time, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) {
- synchronized (dataLock) {
- return calculateFromTreatmentsAndTemps(time, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget);
- }
- }
-
- IobTotal calculateFromTreatmentsAndTemps(long time, Profile profile) {
- long now = System.currentTimeMillis();
- time = roundUpTime(time);
- if (time < now && iobTable.get(time) != null) {
- //og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
- return iobTable.get(time);
- } else {
- //log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
- }
- IobTotal bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round();
- IobTotal basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, true, now).round();
- // OpenAPSSMB only
- // Add expected zero temp basal for next 240 mins
- IobTotal basalIobWithZeroTemp = basalIob.copy();
- TemporaryBasal t = new TemporaryBasal(injector)
- .date(now + 60 * 1000L)
- .duration(240)
- .absolute(0);
- if (t.date < time) {
- IobTotal calc = t.iobCalc(time, profile);
- basalIobWithZeroTemp.plus(calc);
- }
-
- basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round();
-
- IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
- if (time < System.currentTimeMillis()) {
- iobTable.put(time, iobTotal);
- }
- return iobTotal;
- }
-
- public IobTotal calculateAbsInsulinFromTreatmentsAndTempsSynchronized(long time, Profile profile) {
- synchronized (dataLock) {
- long now = System.currentTimeMillis();
- time = roundUpTime(time);
- if (time < now && absIobTable.get(time) != null) {
- //og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
- return absIobTable.get(time);
- } else {
- //log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
- }
- IobTotal bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round();
- IobTotal basalIob = treatmentsPlugin.getAbsoluteIOBTempBasals(time).round();
-
- IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round();
- if (time < System.currentTimeMillis()) {
- absIobTable.put(time, iobTotal);
- }
- return iobTotal;
- }
- }
-
- private IobTotal calculateFromTreatmentsAndTemps(long time, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) {
- long now = DateUtil.now();
-
- IobTotal bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round();
- IobTotal basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, now, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget).round();
- // OpenAPSSMB only
- // Add expected zero temp basal for next 240 mins
- IobTotal basalIobWithZeroTemp = basalIob.copy();
- TemporaryBasal t = new TemporaryBasal(injector)
- .date(now + 60 * 1000L)
- .duration(240)
- .absolute(0);
- if (t.date < time) {
- Profile profile = profileFunction.getProfile(t.date);
- if (profile != null) {
- IobTotal calc = t.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget);
- basalIobWithZeroTemp.plus(calc);
- }
- }
-
- basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round();
-
- return IobTotal.combine(bolusIob, basalIob).round();
- }
-
- @Nullable
- public Long findPreviousTimeFromBucketedData(long time) {
- if (bucketed_data == null)
- return null;
- for (int index = 0; index < bucketed_data.size(); index++) {
- if (bucketed_data.get(index).getTimestamp() <= time)
- return bucketed_data.get(index).getTimestamp();
- }
- return null;
- }
-
- public BasalData getBasalData(Profile profile, long time) {
- synchronized (dataLock) {
- long now = System.currentTimeMillis();
- time = roundUpTime(time);
- BasalData retval = basalDataTable.get(time);
- if (retval == null) {
- retval = new BasalData();
- TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(time);
- retval.basal = profile.getBasal(time);
- if (tb != null) {
- retval.isTempBasalRunning = true;
- retval.tempBasalAbsolute = tb.tempBasalConvertedToAbsolute(time, profile);
- } else {
- retval.isTempBasalRunning = false;
- retval.tempBasalAbsolute = retval.basal;
- }
- if (time < now) {
- basalDataTable.append(time, retval);
- }
- //log.debug(">>> getBasalData Cache miss " + new Date(time).toLocaleString());
- } else {
- //log.debug(">>> getBasalData Cache hit " + new Date(time).toLocaleString());
- }
- return retval;
- }
- }
-
- @Nullable
- public AutosensData getAutosensData(long time) {
- synchronized (dataLock) {
- long now = System.currentTimeMillis();
- if (time > now) {
- return null;
- }
- Long previous = findPreviousTimeFromBucketedData(time);
- if (previous == null) {
- return null;
- }
- time = roundUpTime(previous);
- AutosensData data = autosensDataTable.get(time);
- if (data != null) {
- //log.debug(">>> AUTOSENSDATA Cache hit " + data.toString());
- return data;
- } else {
- //log.debug(">>> AUTOSENSDATA Cache miss " + new Date(time).toLocaleString());
- return null;
- }
- }
- }
-
- @Nullable
- public AutosensData getLastAutosensDataSynchronized(String reason) {
- if (thread != null && thread.isAlive()) {
- getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: " + reason);
- try {
- thread.join(5000);
- } catch (InterruptedException ignored) {
- }
- getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA finished waiting for calculation thread: " + reason);
- }
- synchronized (dataLock) {
- return getLastAutosensData(reason);
- }
- }
-
-
- @NonNull
- public CobInfo getCobInfo(boolean _synchronized, String reason) {
- AutosensData autosensData = _synchronized ? getLastAutosensDataSynchronized(reason) : getLastAutosensData(reason);
- Double displayCob = null;
- double futureCarbs = 0;
- long now = now();
- List treatments = treatmentsPlugin.getTreatmentsFromHistory();
-
- if (autosensData != null) {
- displayCob = autosensData.cob;
- for (Treatment treatment : treatments) {
- if (!treatment.isValid) continue;
- if (IobCobCalculatorPlugin.roundUpTime(treatment.date) > IobCobCalculatorPlugin.roundUpTime(autosensData.time)
- && treatment.date <= now && treatment.carbs > 0) {
- displayCob += treatment.carbs;
- }
- }
- }
- for (Treatment treatment : treatments) {
- if (!treatment.isValid) continue;
- if (treatment.date > now && treatment.carbs > 0) {
- futureCarbs += treatment.carbs;
- }
- }
- return new CobInfo(displayCob, futureCarbs);
- }
-
- public double slowAbsorptionPercentage(int timeInMinutes) {
- double sum = 0;
- int count = 0;
- int valuesToProcess = timeInMinutes / 5;
- synchronized (dataLock) {
- for (int i = autosensDataTable.size() - 1; i >= 0 && count < valuesToProcess; i--) {
- if (autosensDataTable.valueAt(i).failoverToMinAbsorbtionRate)
- sum++;
- count++;
- }
- }
- return sum / count;
- }
-
- @Nullable
- public AutosensData getLastAutosensData(String reason) {
- if (autosensDataTable.size() < 1) {
- getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA null: autosensDataTable empty (" + reason + ")");
- return null;
- }
- AutosensData data;
- try {
- data = autosensDataTable.valueAt(autosensDataTable.size() - 1);
- } catch (Exception e) {
- // data can be processed on the background
- // in this rare case better return null and do not block UI
- // APS plugin should use getLastAutosensDataSynchronized where the blocking is not an issue
- getAapsLogger().error("AUTOSENSDATA null: Exception catched (" + reason + ")");
- return null;
- }
- if (data == null) {
- getAapsLogger().error("AUTOSENSDATA null: data==null");
- return null;
- }
- if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) {
- getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + dateUtil.dateAndTimeAndSecondsString(data.time));
- return null;
- } else {
- getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA (" + reason + ") " + data.toString());
- return data;
- }
- }
-
- @Override
- public String lastDataTime() {
- if (autosensDataTable.size() > 0)
- return dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time);
- else
- return "autosensDataTable empty";
- }
-
- public MealData getMealData() {
- MealData result = new MealData();
-
- Profile profile = profileFunction.getProfile();
- if (profile == null) return result;
-
- long now = System.currentTimeMillis();
- long dia_ago = now - (Double.valueOf(profile.getDia() * T.hours(1).msecs())).longValue();
-
- double maxAbsorptionHours = Constants.DEFAULT_MAX_ABSORPTION_TIME;
- if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) {
- maxAbsorptionHours = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME);
- } else {
- maxAbsorptionHours = sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME);
- }
- long absorptionTime_ago = now - (Double.valueOf(maxAbsorptionHours * T.hours(1).msecs())).longValue();
-
- List treatments = treatmentsPlugin.getTreatmentsFromHistory();
- for (Treatment treatment : treatments) {
- if (!treatment.isValid)
- continue;
- long t = treatment.date;
-
- if (t > dia_ago && t <= now) {
- if (treatment.insulin > 0 && treatment.mealBolus) {
- result.boluses += treatment.insulin;
- }
- }
- if (t > absorptionTime_ago && t <= now) {
- if (treatment.carbs >= 1) {
- result.carbs += treatment.carbs;
- if (t > result.lastCarbTime)
- result.lastCarbTime = t;
- }
- }
- }
-
- AutosensData autosensData = getLastAutosensDataSynchronized("getMealData()");
- if (autosensData != null) {
- result.mealCOB = autosensData.cob;
- result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation;
- result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation;
- result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact;
- }
- result.lastBolusTime = treatmentsPlugin.getLastBolusTime();
- return result;
- }
-
- public IobTotal[] calculateIobArrayInDia(Profile profile) {
- // predict IOB out to DIA plus 30m
- long time = System.currentTimeMillis();
- time = roundUpTime(time);
- int len = (int) ((profile.getDia() * 60 + 30) / 5);
- IobTotal[] array = new IobTotal[len];
- int pos = 0;
- for (int i = 0; i < len; i++) {
- long t = time + i * 5 * 60000;
- IobTotal iob = calculateFromTreatmentsAndTempsSynchronized(t, profile);
- array[pos] = iob;
- pos++;
- }
- return array;
- }
-
- public IobTotal[] calculateIobArrayForSMB(AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) {
- // predict IOB out to DIA plus 30m
- long now = DateUtil.now();
- int len = (4 * 60) / 5;
- IobTotal[] array = new IobTotal[len];
- int pos = 0;
- for (int i = 0; i < len; i++) {
- long t = now + i * 5 * 60000;
- IobTotal iob = calculateFromTreatmentsAndTempsSynchronized(t, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget);
- array[pos] = iob;
- pos++;
- }
- return array;
- }
-
- public String iobArrayToString(IobTotal[] array) {
- StringBuilder sb = new StringBuilder();
- sb.append("[");
- for (IobTotal i : array) {
- sb.append(DecimalFormatter.to2Decimal(i.iob));
- sb.append(", ");
- }
- sb.append("]");
- return sb.toString();
- }
-
- AutosensResult detectSensitivityWithLock(long fromTime, long toTime) {
- synchronized (dataLock) {
- return activePlugin.getActiveSensitivity().detectSensitivity(this, fromTime, toTime);
- }
- }
-
- public static JSONArray convertToJSONArray(IobTotal[] iobArray) {
- JSONArray array = new JSONArray();
- for (int i = 0; i < iobArray.length; i++) {
- array.put(iobArray[i].determineBasalJson());
- }
- return array;
- }
-
- public void stopCalculation(String from) {
- if (thread != null && thread.getState() != Thread.State.TERMINATED) {
- stopCalculationTrigger = true;
- getAapsLogger().debug(LTag.AUTOSENS, "Stopping calculation thread: " + from);
- while (thread.getState() != Thread.State.TERMINATED) {
- SystemClock.sleep(100);
- }
- getAapsLogger().debug(LTag.AUTOSENS, "Calculation thread stopped: " + from);
- }
- }
-
- public void runCalculation(String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) {
- getAapsLogger().debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeAndSecondsString(end));
- if (thread == null || thread.getState() == Thread.State.TERMINATED) {
- if (sensitivityOref1Plugin.isEnabled())
- thread = new IobCobOref1Thread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause);
- else
- thread = new IobCobThread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause);
- thread.start();
- }
- }
-
- // When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
- private void newHistoryData(EventNewHistoryData ev, boolean bgDataReload) {
- //log.debug("Locking onNewHistoryData");
- stopCalculation("onEventNewHistoryData");
- synchronized (dataLock) {
- // clear up 5 min back for proper COB calculation
- long time = ev.getTime() - 5 * 60 * 1000L;
- getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data to: " + dateUtil.dateAndTimeAndSecondsString(time));
- for (int index = iobTable.size() - 1; index >= 0; index--) {
- if (iobTable.keyAt(index) > time) {
- getAapsLogger().debug(LTag.AUTOSENS, "Removing from iobTable: " + dateUtil.dateAndTimeAndSecondsString(iobTable.keyAt(index)));
- iobTable.removeAt(index);
- } else {
- break;
- }
- }
- for (int index = absIobTable.size() - 1; index >= 0; index--) {
- if (absIobTable.keyAt(index) > time) {
- getAapsLogger().debug(LTag.AUTOSENS, "Removing from absIobTable: " + dateUtil.dateAndTimeAndSecondsString(absIobTable.keyAt(index)));
- absIobTable.removeAt(index);
- } else {
- break;
- }
- }
- for (int index = autosensDataTable.size() - 1; index >= 0; index--) {
- if (autosensDataTable.keyAt(index) > time) {
- getAapsLogger().debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + dateUtil.dateAndTimeAndSecondsString(autosensDataTable.keyAt(index)));
- autosensDataTable.removeAt(index);
- } else {
- break;
- }
- }
- for (int index = basalDataTable.size() - 1; index >= 0; index--) {
- if (basalDataTable.keyAt(index) > time) {
- getAapsLogger().debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index)));
- basalDataTable.removeAt(index);
- } else {
- break;
- }
- }
- }
- runCalculation("onEventNewHistoryData", System.currentTimeMillis(), bgDataReload, true, ev);
- //log.debug("Releasing onNewHistoryData");
- }
-
- public void clearCache() {
- synchronized (dataLock) {
- getAapsLogger().debug(LTag.AUTOSENS, "Clearing cached data.");
- iobTable = new LongSparseArray<>();
- autosensDataTable = new LongSparseArray<>();
- basalDataTable = new LongSparseArray<>();
- }
- }
-
- /*
- * Return last BgReading from database or null if db is empty
- */
- @Nullable
- public GlucoseValue lastBg() {
- List bgList = getBgReadings();
-
- if (bgList == null)
- return null;
-
- for (int i = 0; i < bgList.size(); i++)
- if (bgList.get(i).getValue() >= 39)
- return bgList.get(i);
- return null;
- }
-
- /*
- * Return bg reading if not old ( <9 min )
- * or null if older
- */
- @Nullable
- public GlucoseValue actualBg() {
- GlucoseValue lastBg = lastBg();
-
- if (lastBg == null)
- return null;
-
- if (lastBg.getTimestamp() > System.currentTimeMillis() - 9 * 60 * 1000)
- return lastBg;
-
- return null;
- }
-
-
- // From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
- // Returns the value at a given percentile in a sorted numeric array.
- // "Linear interpolation between closest ranks" method
- public static double percentile(Double[] arr, double p) {
- if (arr.length == 0) return 0;
- if (p <= 0) return arr[0];
- if (p >= 1) return arr[arr.length - 1];
-
- double index = arr.length * p,
- lower = Math.floor(index),
- upper = lower + 1,
- weight = index % 1;
-
- if (upper >= arr.length) return arr[(int) lower];
- return arr[(int) lower] * (1 - weight) + arr[(int) upper] * weight;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt
new file mode 100644
index 0000000000..de1c931ccb
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt
@@ -0,0 +1,799 @@
+package info.nightscout.androidaps.plugins.iob.iobCobCalculator
+
+import android.os.SystemClock
+import androidx.collection.LongSparseArray
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.IobTotal
+import info.nightscout.androidaps.data.MealData
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.entities.GlucoseValue
+import info.nightscout.androidaps.db.TemporaryBasal
+import info.nightscout.androidaps.events.*
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.DecimalFormatter
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.T
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.rx.AapsSchedulers
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import io.reactivex.disposables.CompositeDisposable
+import org.json.JSONArray
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.math.abs
+import kotlin.math.floor
+import kotlin.math.max
+import kotlin.math.roundToLong
+
+@Singleton
+open class IobCobCalculatorPlugin @Inject constructor(
+ injector: HasAndroidInjector,
+ aapsLogger: AAPSLogger,
+ private val aapsSchedulers: AapsSchedulers,
+ private val rxBus: RxBusWrapper,
+ private val sp: SP,
+ resourceHelper: ResourceHelper,
+ private val profileFunction: ProfileFunction,
+ private val activePlugin: ActivePluginProvider,
+ private val treatmentsPlugin: TreatmentsPlugin,
+ private val sensitivityOref1Plugin: SensitivityOref1Plugin,
+ private val sensitivityAAPSPlugin: SensitivityAAPSPlugin,
+ private val sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin,
+ private val fabricPrivacy: FabricPrivacy,
+ private val dateUtil: DateUtil,
+ private val repository: AppRepository
+) : PluginBase(PluginDescription()
+ .mainType(PluginType.GENERAL)
+ .pluginName(R.string.iobcobcalculator)
+ .showInList(false)
+ .neverVisible(true)
+ .alwaysEnabled(true),
+ aapsLogger, resourceHelper, injector
+), IobCobCalculatorInterface {
+
+ private val disposable = CompositeDisposable()
+ private var iobTable = LongSparseArray() // oldest at index 0
+ private var absIobTable = LongSparseArray() // oldest at index 0, absolute insulin in the body
+ private var autosensDataTable = LongSparseArray() // oldest at index 0
+ private var basalDataTable = LongSparseArray() // oldest at index 0
+ @Volatile var bgReadings: List = listOf() // newest at index 0
+ @Volatile var bucketedData: MutableList? = null
+
+ // we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values
+ // once referenceTime != null all bucketed data should be (x * 5min) from referenceTime
+ var referenceTime: Long = -1
+ private var lastUsed5minCalculation: Boolean? = null // true if used 5min bucketed data
+ val dataLock = Any()
+ var stopCalculationTrigger = false
+ private var thread: Thread? = null
+
+ override fun onStart() {
+ super.onStart()
+ // EventConfigBuilderChange
+ disposable.add(rxBus
+ .toObservable(EventConfigBuilderChange::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event ->
+ stopCalculation("onEventConfigBuilderChange")
+ synchronized(dataLock) {
+ aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data because of configuration change.")
+ resetData()
+ }
+ runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event)
+ }, fabricPrivacy::logException)
+ )
+ // EventNewBasalProfile
+ disposable.add(rxBus
+ .toObservable(EventNewBasalProfile::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event ->
+ stopCalculation("onNewProfile")
+ synchronized(dataLock) {
+ aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data because of new profile.")
+ resetData()
+ }
+ runCalculation("onNewProfile", System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event)
+ }, fabricPrivacy::logException)
+ )
+ // EventNewBG .... cannot be used for invalidating because only event with last BG is fired
+ disposable.add(rxBus
+ .toObservable(EventNewBG::class.java)
+ .observeOn(aapsSchedulers.io)
+ .debounce(1L, TimeUnit.SECONDS)
+ .subscribe({ event ->
+ stopCalculation("onEventNewBG")
+ runCalculation("onEventNewBG", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event)
+ }, fabricPrivacy::logException)
+ )
+ // EventPreferenceChange
+ disposable.add(rxBus
+ .toObservable(EventPreferenceChange::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event ->
+ if (event.isChanged(resourceHelper, R.string.key_openapsama_autosens_period) ||
+ event.isChanged(resourceHelper, R.string.key_age) ||
+ event.isChanged(resourceHelper, R.string.key_absorption_maxtime) ||
+ event.isChanged(resourceHelper, R.string.key_openapsama_min_5m_carbimpact) ||
+ event.isChanged(resourceHelper, R.string.key_absorption_cutoff) ||
+ event.isChanged(resourceHelper, R.string.key_openapsama_autosens_max) ||
+ event.isChanged(resourceHelper, R.string.key_openapsama_autosens_min) ||
+ event.isChanged(resourceHelper, R.string.key_insulin_oref_peak)) {
+ stopCalculation("onEventPreferenceChange")
+ synchronized(dataLock) {
+ aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data because of preference change.")
+ resetData()
+ }
+ runCalculation("onEventPreferenceChange", System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event)
+ }
+ }, fabricPrivacy::logException)
+ )
+ // EventAppInitialized
+ disposable.add(rxBus
+ .toObservable(EventAppInitialized::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event) }, fabricPrivacy::logException)
+ )
+ // EventNewHistoryData
+ disposable.add(rxBus
+ .toObservable(EventNewHistoryData::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event -> newHistoryData(event, false) }, fabricPrivacy::logException)
+ )
+ // EventNewHistoryBgData
+ disposable.add(rxBus
+ .toObservable(EventNewHistoryBgData::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event -> newHistoryData(EventNewHistoryData(event.timestamp), true) }, fabricPrivacy::logException)
+ )
+ }
+
+ override fun onStop() {
+ disposable.clear()
+ super.onStop()
+ }
+
+ override fun getAutosensDataTable(): LongSparseArray {
+ return autosensDataTable
+ }
+
+ fun adjustToReferenceTime(someTime: Long): Long {
+ if (referenceTime == -1L) {
+ referenceTime = someTime
+ return someTime
+ }
+ var diff = abs(someTime - referenceTime)
+ diff %= T.mins(5).msecs()
+ if (diff > T.mins(2).plus(T.secs(30)).msecs()) diff -= T.mins(5).msecs()
+ return someTime + diff
+ }
+
+ fun loadBgData(to: Long) {
+ val profile = profileFunction.getProfile(to)
+ var dia = Constants.defaultDIA
+ if (profile != null) dia = profile.dia
+ val start = to - T.hours((24 + dia).toLong()).msecs()
+ if (DateUtil.isCloseToNow(to)) {
+ // if close to now expect there can be some readings with time in close future (caused by wrong time setting)
+ // so read all records
+ bgReadings = repository.compatGetBgReadingsDataFromTime(start, false).blockingGet()
+ aapsLogger.debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size + " Start date: " + dateUtil.dateAndTimeString(start))
+ } else {
+ bgReadings = repository.compatGetBgReadingsDataFromTime(start, to, false).blockingGet()
+ aapsLogger.debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to))
+ }
+ }
+
+ val isAbout5minData: Boolean
+ get() {
+ synchronized(dataLock) {
+ if (bgReadings.size < 3) return true
+
+ var totalDiff: Long = 0
+ for (i in 1 until bgReadings.size) {
+ val bgTime = bgReadings[i].timestamp
+ val lastBgTime = bgReadings[i - 1].timestamp
+ var diff = lastBgTime - bgTime
+ diff %= T.mins(5).msecs()
+ if (diff > T.mins(2).plus(T.secs(30)).msecs()) diff -= T.mins(5).msecs()
+ totalDiff += diff
+ diff = abs(diff)
+ if (diff > T.secs(30).msecs()) {
+ aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " diff: " + diff / 1000 + "[s] is5minData: " + false)
+ return false
+ }
+ }
+ val averageDiff = totalDiff / bgReadings.size / 1000
+ val is5minData = averageDiff < 1
+ aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " averageDiff: " + averageDiff + "[s] is5minData: " + is5minData)
+ return is5minData
+ }
+ }
+
+ private fun resetData() {
+ synchronized(dataLock) {
+ iobTable = LongSparseArray()
+ autosensDataTable = LongSparseArray()
+ basalDataTable = LongSparseArray()
+ absIobTable = LongSparseArray()
+ }
+ }
+
+ fun createBucketedData() {
+ val fiveMinData = isAbout5minData
+ if (lastUsed5minCalculation != null && lastUsed5minCalculation != fiveMinData) {
+ // changing mode => clear cache
+ aapsLogger.debug("Invalidating cached data because of changed mode.")
+ resetData()
+ }
+ lastUsed5minCalculation = fiveMinData
+ if (isAbout5minData) createBucketedData5min() else createBucketedDataRecalculated()
+ }
+
+ fun findNewer(time: Long): GlucoseValue? {
+ var lastFound = bgReadings[0]
+ if (lastFound.timestamp < time) return null
+ for (i in 1 until bgReadings.size) {
+ if (bgReadings[i].timestamp == time) return bgReadings[i]
+ if (bgReadings[i].timestamp > time) continue
+ lastFound = bgReadings[i - 1]
+ if (bgReadings[i].timestamp < time) break
+ }
+ return lastFound
+ }
+
+ fun findOlder(time: Long): GlucoseValue? {
+ var lastFound = bgReadings[bgReadings.size - 1]
+ if (lastFound.timestamp > time) return null
+ for (i in bgReadings.size - 2 downTo 0) {
+ if (bgReadings[i].timestamp == time) return bgReadings[i]
+ if (bgReadings[i].timestamp < time) continue
+ lastFound = bgReadings[i + 1]
+ if (bgReadings[i].timestamp > time) break
+ }
+ return lastFound
+ }
+
+ private fun createBucketedDataRecalculated() {
+ if (bgReadings.size < 3) {
+ bucketedData = null
+ return
+ }
+ bucketedData = ArrayList()
+ var currentTime = bgReadings[0].timestamp - bgReadings[0].timestamp % T.mins(5).msecs()
+ currentTime = adjustToReferenceTime(currentTime)
+ aapsLogger.debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime))
+ //log.debug("First reading: " + new Date(currentTime).toLocaleString());
+ while (true) {
+ // test if current value is older than current time
+ val newer = findNewer(currentTime)
+ val older = findOlder(currentTime)
+ if (newer == null || older == null) break
+ if (older.timestamp == newer.timestamp) { // direct hit
+ bucketedData?.add(InMemoryGlucoseValue(newer))
+ } else {
+ val bgDelta = newer.value - older.value
+ val timeDiffToNew = newer.timestamp - currentTime
+ val currentBg = newer.value - timeDiffToNew.toDouble() / (newer.timestamp - older.timestamp) * bgDelta
+ val newBgReading = InMemoryGlucoseValue(currentTime, currentBg.roundToLong().toDouble(), true)
+ bucketedData?.add(newBgReading)
+ //log.debug("BG: " + newBgReading.value + " (" + new Date(newBgReading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
+ }
+ currentTime -= T.mins(5).msecs()
+ }
+ }
+
+ private fun createBucketedData5min() {
+ if (bgReadings.size < 3) {
+ bucketedData = null
+ return
+ }
+ val bData: MutableList = ArrayList()
+ bData.add(InMemoryGlucoseValue(bgReadings[0]))
+ aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgReadings[0].timestamp) + " lastBgTime: " + "none-first-value" + " " + bgReadings[0].toString())
+ var j = 0
+ for (i in 1 until bgReadings.size) {
+ val bgTime = bgReadings[i].timestamp
+ var lastBgTime = bgReadings[i - 1].timestamp
+ //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastBgTime).toString() + " " + bgReadings.get(i - 1).value);
+ check(!(bgReadings[i].value < 39 || bgReadings[i - 1].value < 39)) { "<39" }
+ var elapsedMinutes = (bgTime - lastBgTime) / (60 * 1000)
+ when {
+ abs(elapsedMinutes) > 8 -> {
+ // interpolate missing data points
+ var lastBg = bgReadings[i - 1].value
+ elapsedMinutes = abs(elapsedMinutes)
+ //console.error(elapsed_minutes);
+ var nextBgTime: Long
+ while (elapsedMinutes > 5) {
+ nextBgTime = lastBgTime - 5 * 60 * 1000
+ j++
+ val gapDelta = bgReadings[i].value - lastBg
+ //console.error(gapDelta, lastBg, elapsed_minutes);
+ val nextBg = lastBg + 5.0 / elapsedMinutes * gapDelta
+ val newBgReading = InMemoryGlucoseValue(nextBgTime, nextBg.roundToLong().toDouble(), true)
+ //console.error("Interpolated", bData[j]);
+ bData.add(newBgReading)
+ aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastBgTime: " + DateUtil.toISOString(lastBgTime) + " " + newBgReading.toString())
+ elapsedMinutes -= 5
+ lastBg = nextBg
+ lastBgTime = nextBgTime
+ }
+ j++
+ val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value)
+ bData.add(newBgReading)
+ aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastBgTime: " + DateUtil.toISOString(lastBgTime) + " " + newBgReading.toString())
+ }
+
+ abs(elapsedMinutes) > 2 -> {
+ j++
+ val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value)
+ bData.add(newBgReading)
+ aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastBgTime: " + DateUtil.toISOString(lastBgTime) + " " + newBgReading.toString())
+ }
+
+ else -> {
+ bData[j].value = (bData[j].value + bgReadings[i].value) / 2
+ //log.error("***** Average");
+ }
+ }
+ }
+
+ // Normalize bucketed data
+ val oldest = bData[bData.size - 1]
+ oldest.timestamp = adjustToReferenceTime(oldest.timestamp)
+ aapsLogger.debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(oldest.timestamp))
+ for (i in bData.size - 2 downTo 0) {
+ val current = bData[i]
+ val previous = bData[i + 1]
+ val mSecDiff = current.timestamp - previous.timestamp
+ val adjusted = (mSecDiff - T.mins(5).msecs()) / 1000
+ aapsLogger.debug(LTag.AUTOSENS, "Adjusting bucketed data time. Current: " + dateUtil.dateAndTimeAndSecondsString(current.timestamp) + " to: " + dateUtil.dateAndTimeAndSecondsString(previous.timestamp + T.mins(5).msecs()) + " by " + adjusted + " sec")
+ if (abs(adjusted) > 90) {
+ // too big adjustment, fallback to non 5 min data
+ aapsLogger.debug(LTag.AUTOSENS, "Fallback to non 5 min data")
+ createBucketedDataRecalculated()
+ return
+ }
+ current.timestamp = previous.timestamp + T.mins(5).msecs()
+ }
+ aapsLogger.debug(LTag.AUTOSENS, "Bucketed data created. Size: " + bData.size)
+ bucketedData = bData
+ }
+
+ fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long {
+ val profile = profileFunction.getProfile(from)
+ var dia = Constants.defaultDIA
+ if (profile != null) dia = profile.dia
+ val oldestDataAvailable = treatmentsPlugin.oldestDataAvailable()
+ val getBGDataFrom: Long
+ if (limitDataToOldestAvailable) {
+ getBGDataFrom = max(oldestDataAvailable, (from - T.hours(1).msecs() * (24 + dia)).toLong())
+ if (getBGDataFrom == oldestDataAvailable) aapsLogger.debug(LTag.AUTOSENS, "Limiting data to oldest available temps: " + dateUtil.dateAndTimeAndSecondsString(oldestDataAvailable))
+ } else getBGDataFrom = (from - T.hours(1).msecs() * (24 + dia)).toLong()
+ return getBGDataFrom
+ }
+
+ fun calculateFromTreatmentsAndTempsSynchronized(time: Long, profile: Profile?): IobTotal {
+ synchronized(dataLock) { return calculateFromTreatmentsAndTemps(time, profile) }
+ }
+
+ private fun calculateFromTreatmentsAndTempsSynchronized(time: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal {
+ synchronized(dataLock) { return calculateFromTreatmentsAndTemps(time, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget) }
+ }
+
+ fun calculateFromTreatmentsAndTemps(fromTime: Long, profile: Profile?): IobTotal {
+ val now = System.currentTimeMillis()
+ val time = roundUpTime(fromTime)
+ val cacheHit = iobTable[time]
+ if (time < now && cacheHit != null) {
+ //og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
+ return cacheHit
+ } // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
+ val bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round()
+ val basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, true, now).round()
+ // OpenAPSSMB only
+ // Add expected zero temp basal for next 240 minutes
+ val basalIobWithZeroTemp = basalIob.copy()
+ val t = TemporaryBasal(injector)
+ .date(now + 60 * 1000L)
+ .duration(240)
+ .absolute(0.0)
+ if (t.date < time) {
+ val calc = t.iobCalc(time, profile)
+ basalIobWithZeroTemp.plus(calc)
+ }
+ basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round()
+ val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
+ if (time < System.currentTimeMillis()) {
+ iobTable.put(time, iobTotal)
+ }
+ return iobTotal
+ }
+
+ fun calculateAbsInsulinFromTreatmentsAndTempsSynchronized(fromTime: Long): IobTotal {
+ synchronized(dataLock) {
+ val now = System.currentTimeMillis()
+ val time = roundUpTime(fromTime)
+ val cacheHit = absIobTable[time]
+ if (time < now && cacheHit != null) {
+ //log.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
+ return cacheHit
+ } // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
+ val bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round()
+ val basalIob = treatmentsPlugin.getAbsoluteIOBTempBasals(time).round()
+ val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
+ if (time < System.currentTimeMillis()) {
+ absIobTable.put(time, iobTotal)
+ }
+ return iobTotal
+ }
+ }
+
+ private fun calculateFromTreatmentsAndTemps(time: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal {
+ val now = DateUtil.now()
+ val bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round()
+ val basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, now, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget).round()
+ // OpenAPSSMB only
+ // Add expected zero temp basal for next 240 minutes
+ val basalIobWithZeroTemp = basalIob.copy()
+ val t = TemporaryBasal(injector)
+ .date(now + 60 * 1000L)
+ .duration(240)
+ .absolute(0.0)
+ if (t.date < time) {
+ val profile = profileFunction.getProfile(t.date)
+ if (profile != null) {
+ val calc = t.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget)
+ basalIobWithZeroTemp.plus(calc)
+ }
+ }
+ basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round()
+ return IobTotal.combine(bolusIob, basalIob).round()
+ }
+
+ fun findPreviousTimeFromBucketedData(time: Long): Long? {
+ val bData = bucketedData ?: return null
+ for (index in bData.indices) {
+ if (bData[index].timestamp <= time) return bData[index].timestamp
+ }
+ return null
+ }
+
+ fun getBasalData(profile: Profile, fromTime: Long): BasalData {
+ synchronized(dataLock) {
+ val now = System.currentTimeMillis()
+ val time = roundUpTime(fromTime)
+ var retVal = basalDataTable[time]
+ if (retVal == null) {
+ //log.debug(">>> getBasalData Cache miss " + new Date(time).toLocaleString());
+ retVal = BasalData()
+ val tb = treatmentsPlugin.getTempBasalFromHistory(time)
+ retVal.basal = profile.getBasal(time)
+ if (tb != null) {
+ retVal.isTempBasalRunning = true
+ retVal.tempBasalAbsolute = tb.tempBasalConvertedToAbsolute(time, profile)
+ } else {
+ retVal.isTempBasalRunning = false
+ retVal.tempBasalAbsolute = retVal.basal
+ }
+ if (time < now) {
+ basalDataTable.append(time, retVal)
+ }
+ } //else log.debug(">>> getBasalData Cache hit " + new Date(time).toLocaleString());
+ return retVal
+ }
+ }
+
+ override fun getAutosensData(fromTime: Long): AutosensData? {
+ var time = fromTime
+ synchronized(dataLock) {
+ val now = System.currentTimeMillis()
+ if (time > now) {
+ return null
+ }
+ val previous = findPreviousTimeFromBucketedData(time) ?: return null
+ time = roundUpTime(previous)
+ return autosensDataTable[time]
+ }
+ }
+
+ fun getLastAutosensDataSynchronized(reason: String): AutosensData? {
+ if (thread?.isAlive == true) {
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: $reason")
+ try {
+ thread?.join(5000)
+ } catch (ignored: InterruptedException) {
+ }
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA finished waiting for calculation thread: $reason")
+ }
+ synchronized(dataLock) { return getLastAutosensData(reason) }
+ }
+
+ fun getCobInfo(_synchronized: Boolean, reason: String): CobInfo {
+ val autosensData = if (_synchronized) getLastAutosensDataSynchronized(reason) else getLastAutosensData(reason)
+ var displayCob: Double? = null
+ var futureCarbs = 0.0
+ val now = DateUtil.now()
+ val treatments = treatmentsPlugin.treatmentsFromHistory
+ if (autosensData != null) {
+ displayCob = autosensData.cob
+ for (treatment in treatments) {
+ if (!treatment.isValid) continue
+ if (roundUpTime(treatment.date) > roundUpTime(autosensData.time) && treatment.date <= now && treatment.carbs > 0) {
+ displayCob += treatment.carbs
+ }
+ }
+ }
+ for (treatment in treatments) {
+ if (!treatment.isValid) continue
+ if (treatment.date > now && treatment.carbs > 0) {
+ futureCarbs += treatment.carbs
+ }
+ }
+ return CobInfo(displayCob, futureCarbs)
+ }
+
+ fun slowAbsorptionPercentage(timeInMinutes: Int): Double {
+ var sum = 0.0
+ var count = 0
+ val valuesToProcess = timeInMinutes / 5
+ synchronized(dataLock) {
+ var i = autosensDataTable.size() - 1
+ while (i >= 0 && count < valuesToProcess) {
+ if (autosensDataTable.valueAt(i).failoverToMinAbsorbtionRate) sum++
+ count++
+ i--
+ }
+ }
+ return sum / count
+ }
+
+ fun getLastAutosensData(reason: String): AutosensData? {
+ if (autosensDataTable.size() < 1) {
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: autosensDataTable empty ($reason)")
+ return null
+ }
+ val data: AutosensData? = try {
+ autosensDataTable.valueAt(autosensDataTable.size() - 1)
+ } catch (e: Exception) {
+ // data can be processed on the background
+ // in this rare case better return null and do not block UI
+ // APS plugin should use getLastAutosensDataSynchronized where the blocking is not an issue
+ aapsLogger.error("AUTOSENSDATA null: Exception caught ($reason)")
+ return null
+ }
+ if (data == null) {
+ aapsLogger.error("AUTOSENSDATA null: data==null")
+ return null
+ }
+ return if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) {
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastData=" + dateUtil.dateAndTimeAndSecondsString(data.time))
+ null
+ } else {
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA ($reason) $data")
+ data
+ }
+ }
+
+ override fun lastDataTime(): String {
+ return if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time) else "autosensDataTable empty"
+ }
+
+ val mealData: MealData
+ get() {
+ val result = MealData()
+ val profile = profileFunction.getProfile() ?: return result
+ val now = System.currentTimeMillis()
+ val diaAgo = now - java.lang.Double.valueOf(profile.dia * T.hours(1).msecs()).toLong()
+ val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) {
+ sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME)
+ } else {
+ sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME)
+ }
+ val absorptionTimeAgo = now - java.lang.Double.valueOf(maxAbsorptionHours * T.hours(1).msecs()).toLong()
+ val treatments = treatmentsPlugin.treatmentsFromHistory
+ for (treatment in treatments) {
+ if (!treatment.isValid) continue
+ val t = treatment.date
+ if (t in (diaAgo + 1)..now) {
+ if (treatment.insulin > 0 && treatment.mealBolus) {
+ result.boluses += treatment.insulin
+ }
+ }
+ if (t in (absorptionTimeAgo + 1)..now) {
+ if (treatment.carbs >= 1) {
+ result.carbs += treatment.carbs
+ if (t > result.lastCarbTime) result.lastCarbTime = t
+ }
+ }
+ }
+ val autosensData = getLastAutosensDataSynchronized("getMealData()")
+ if (autosensData != null) {
+ result.mealCOB = autosensData.cob
+ result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation
+ result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation
+ result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact
+ }
+ result.lastBolusTime = treatmentsPlugin.lastBolusTime
+ return result
+ }
+
+ override fun calculateIobArrayInDia(profile: Profile): Array {
+ // predict IOB out to DIA plus 30m
+ var time = System.currentTimeMillis()
+ time = roundUpTime(time)
+ val len = ((profile.dia * 60 + 30) / 5).toInt()
+ val array = Array(len) { IobTotal(0) }
+ for ((pos, i) in (0 until len).withIndex()) {
+ val t = time + i * 5 * 60000
+ val iob = calculateFromTreatmentsAndTempsSynchronized(t, profile)
+ array[pos] = iob
+ }
+ return array
+ }
+
+ fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array {
+ // predict IOB out to DIA plus 30m
+ val now = DateUtil.now()
+ val len = 4 * 60 / 5
+ val array = Array(len) { IobTotal(0) }
+ for ((pos, i) in (0 until len).withIndex()) {
+ val t = now + i * 5 * 60000
+ val iob = calculateFromTreatmentsAndTempsSynchronized(t, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget)
+ array[pos] = iob
+ }
+ return array
+ }
+
+ fun iobArrayToString(array: Array): String {
+ val sb = StringBuilder()
+ sb.append("[")
+ for (i in array) {
+ sb.append(DecimalFormatter.to2Decimal(i.iob))
+ sb.append(", ")
+ }
+ sb.append("]")
+ return sb.toString()
+ }
+
+ fun detectSensitivityWithLock(fromTime: Long, toTime: Long): AutosensResult {
+ synchronized(dataLock) { return activePlugin.activeSensitivity.detectSensitivity(this, fromTime, toTime) }
+ }
+
+ fun stopCalculation(from: String) {
+ if (thread?.state != Thread.State.TERMINATED) {
+ stopCalculationTrigger = true
+ aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from")
+ while (thread?.state != Thread.State.TERMINATED) {
+ SystemClock.sleep(100)
+ }
+ aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from")
+ }
+ }
+
+ fun runCalculation(from: String, end: Long, bgDataReload: Boolean, limitDataToOldestAvailable: Boolean, cause: Event) {
+ aapsLogger.debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeAndSecondsString(end))
+ if (thread == null || thread?.state == Thread.State.TERMINATED) {
+ thread = if (sensitivityOref1Plugin.isEnabled()) IobCobOref1Thread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause) else IobCobThread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause)
+ thread?.start()
+ }
+ }
+
+ // When historical data is changed (coming from NS etc) finished calculations after this date must be invalidated
+ private fun newHistoryData(ev: EventNewHistoryData, bgDataReload: Boolean) {
+ //log.debug("Locking onNewHistoryData");
+ stopCalculation("onEventNewHistoryData")
+ synchronized(dataLock) {
+
+ // clear up 5 min back for proper COB calculation
+ val time = ev.time - 5 * 60 * 1000L
+ aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data to: " + dateUtil.dateAndTimeAndSecondsString(time))
+ for (index in iobTable.size() - 1 downTo 0) {
+ if (iobTable.keyAt(index) > time) {
+ aapsLogger.debug(LTag.AUTOSENS, "Removing from iobTable: " + dateUtil.dateAndTimeAndSecondsString(iobTable.keyAt(index)))
+ iobTable.removeAt(index)
+ } else {
+ break
+ }
+ }
+ for (index in absIobTable.size() - 1 downTo 0) {
+ if (absIobTable.keyAt(index) > time) {
+ aapsLogger.debug(LTag.AUTOSENS, "Removing from absIobTable: " + dateUtil.dateAndTimeAndSecondsString(absIobTable.keyAt(index)))
+ absIobTable.removeAt(index)
+ } else {
+ break
+ }
+ }
+ for (index in autosensDataTable.size() - 1 downTo 0) {
+ if (autosensDataTable.keyAt(index) > time) {
+ aapsLogger.debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + dateUtil.dateAndTimeAndSecondsString(autosensDataTable.keyAt(index)))
+ autosensDataTable.removeAt(index)
+ } else {
+ break
+ }
+ }
+ for (index in basalDataTable.size() - 1 downTo 0) {
+ if (basalDataTable.keyAt(index) > time) {
+ aapsLogger.debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index)))
+ basalDataTable.removeAt(index)
+ } else {
+ break
+ }
+ }
+ }
+ runCalculation("onEventNewHistoryData", System.currentTimeMillis(), bgDataReload, true, ev)
+ //log.debug("Releasing onNewHistoryData");
+ }
+
+ fun clearCache() {
+ synchronized(dataLock) {
+ aapsLogger.debug(LTag.AUTOSENS, "Clearing cached data.")
+ iobTable = LongSparseArray()
+ autosensDataTable = LongSparseArray()
+ basalDataTable = LongSparseArray()
+ }
+ }
+
+ /*
+ * Return last BgReading from database or null if db is empty
+ */
+ fun lastBg(): GlucoseValue? {
+ val bgList = bgReadings
+ for (i in bgList.indices) if (bgList[i].value >= 39) return bgList[i]
+ return null
+ }
+
+ /*
+ * Return bg reading if not old ( <9 min )
+ * or null if older
+ */
+ fun actualBg(): GlucoseValue? {
+ val lastBg = lastBg() ?: return null
+ return if (lastBg.timestamp > System.currentTimeMillis() - 9 * 60 * 1000) lastBg else null
+ }
+
+ companion object {
+
+ // roundup to whole minute
+ fun roundUpTime(time: Long): Long {
+ return if (time % 60000 == 0L) time else (time / 60000 + 1) * 60000
+ }
+
+ fun convertToJSONArray(iobArray: Array): JSONArray {
+ val array = JSONArray()
+ for (i in iobArray.indices) {
+ array.put(iobArray[i].determineBasalJson())
+ }
+ return array
+ }
+
+ // From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
+ // Returns the value at a given percentile in a sorted numeric array.
+ // "Linear interpolation between closest ranks" method
+ fun percentile(arr: Array, p: Double): Double {
+ if (arr.isEmpty()) return 0.0
+ if (p <= 0) return arr[0]
+ if (p >= 1) return arr[arr.size - 1]
+ val index = arr.size * p
+ val lower = floor(index)
+ val upper = lower + 1
+ val weight = index % 1
+ return if (upper >= arr.size) arr[lower.toInt()] else arr[lower.toInt()] * (1 - weight) + arr[upper.toInt()] * weight
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.java
deleted file mode 100644
index ad68c3acc6..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.java
+++ /dev/null
@@ -1,399 +0,0 @@
-package info.nightscout.androidaps.plugins.iob.iobCobCalculator;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.os.SystemClock;
-
-import androidx.collection.LongSparseArray;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.IobTotal;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.db.TempTarget;
-import info.nightscout.androidaps.db.Treatment;
-import info.nightscout.androidaps.events.Event;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
-import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.DecimalFormatter;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.MidnightTime;
-import info.nightscout.androidaps.utils.Profiler;
-import info.nightscout.androidaps.utils.T;
-import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-import static info.nightscout.androidaps.utils.DateUtil.now;
-import static java.util.Calendar.MINUTE;
-
-/**
- * Created by mike on 23.01.2018.
- */
-
-public class IobCobOref1Thread extends Thread {
- private final Event cause;
-
- @Inject AAPSLogger aapsLogger;
- @Inject SP sp;
- @Inject RxBusWrapper rxBus;
- @Inject ResourceHelper resourceHelper;
- @Inject ProfileFunction profileFunction;
- @Inject Context context;
- @Inject SensitivityAAPSPlugin sensitivityAAPSPlugin;
- @Inject SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin;
- @Inject BuildHelper buildHelper;
- @Inject Profiler profiler;
- @Inject FabricPrivacy fabricPrivacy;
- @Inject DateUtil dateUtil;
-
- private final HasAndroidInjector injector;
- private final IobCobCalculatorPlugin iobCobCalculatorPlugin; // cannot be injected : HistoryBrowser uses different instance
- private final TreatmentsPlugin treatmentsPlugin; // cannot be injected : HistoryBrowser uses different instance
- private final boolean bgDataReload;
- private final boolean limitDataToOldestAvailable;
- private final String from;
- private final long end;
-
- private PowerManager.WakeLock mWakeLock;
-
- IobCobOref1Thread(HasAndroidInjector injector, IobCobCalculatorPlugin iobCobCalculatorPlugin, TreatmentsPlugin treatmentsPlugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) {
- super();
- injector.androidInjector().inject(this);
- this.injector = injector;
- this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
- this.treatmentsPlugin = treatmentsPlugin;
-
- this.bgDataReload = bgDataReload;
- this.limitDataToOldestAvailable = limitDataToOldestAvailable;
- this.from = from;
- this.cause = cause;
- this.end = end;
-
- PowerManager powerManager = (PowerManager) context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
- if (powerManager != null)
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, resourceHelper.gs(R.string.app_name) + ":iobCobThread");
- }
-
- @Override
- public final void run() {
- long start = DateUtil.now();
- if (mWakeLock != null)
- mWakeLock.acquire(T.mins(10).msecs());
- try {
- aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: " + from);
- if (!profileFunction.isProfileValid("IobCobThread")) {
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): " + from);
- return; // app still initializing
- }
- //log.debug("Locking calculateSensitivityData");
-
- long oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable);
-
- synchronized (iobCobCalculatorPlugin.getDataLock()) {
- if (bgDataReload) {
- iobCobCalculatorPlugin.loadBgData(end);
- iobCobCalculatorPlugin.createBucketedData();
- rxBus.send(new EventAutosensBgLoaded(cause));
- }
- List bucketed_data = iobCobCalculatorPlugin.getBucketedData();
- LongSparseArray autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
-
- if (bucketed_data == null || bucketed_data.size() < 3) {
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): " + from);
- return;
- }
-
- long prevDataTime = IobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).getTimestamp());
- aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime));
- AutosensData previous = autosensDataTable.get(prevDataTime);
- // start from oldest to be able sub cob
- for (int i = bucketed_data.size() - 4; i >= 0; i--) {
- String progress = i + (buildHelper.isDev() ? " (" + from + ")" : "");
- rxBus.send(new EventIobCalculationProgress(progress));
-
- if (iobCobCalculatorPlugin.stopCalculationTrigger) {
- iobCobCalculatorPlugin.stopCalculationTrigger = false;
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): " + from);
- return;
- }
- // check if data already exists
- long bgTime = bucketed_data.get(i).getTimestamp();
- bgTime = IobCobCalculatorPlugin.roundUpTime(bgTime);
- if (bgTime > IobCobCalculatorPlugin.roundUpTime(now()))
- continue;
-
- AutosensData existing;
- if ((existing = autosensDataTable.get(bgTime)) != null) {
- previous = existing;
- continue;
- }
-
- Profile profile = profileFunction.getProfile(bgTime);
- if (profile == null) {
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): " + from);
- return; // profile not set yet
- }
-
- aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
-
- double sens = profile.getIsfMgdl(bgTime);
-
- AutosensData autosensData = new AutosensData(injector);
- autosensData.time = bgTime;
- if (previous != null)
- autosensData.activeCarbsList = previous.cloneCarbsList();
- else
- autosensData.activeCarbsList = new ArrayList<>();
-
- //console.error(bgTime , bucketed_data[i].glucose);
- double bg;
- double avgDelta;
- double delta;
- bg = bucketed_data.get(i).getValue();
- if (bg < 39 || bucketed_data.get(i + 3).getValue() < 39) {
- aapsLogger.error("! value < 39");
- continue;
- }
- autosensData.bg = bg;
- delta = (bg - bucketed_data.get(i + 1).getValue());
- avgDelta = (bg - bucketed_data.get(i + 3).getValue()) / 3;
-
- IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile);
-
- double bgi = -iob.activity * sens * 5;
- double deviation = delta - bgi;
- double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000d;
-
- double slopeFromMaxDeviation = 0;
- double slopeFromMinDeviation = 999;
- double maxDeviation = 0;
- double minDeviation = 999;
-
- // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
- if (i < bucketed_data.size() - 16) { // we need 1h of data to calculate minDeviationSlope
- long hourago = bgTime + 10 * 1000 - 60 * 60 * 1000L;
- AutosensData hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourago);
- if (hourAgoData != null) {
- int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time);
- aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + hourAgoData.toString());
- int past = 1;
- try {
- for (; past < 12; past++) {
- AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
- aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
- if (ad == null) {
- aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString());
- aapsLogger.debug(LTag.AUTOSENS, bucketed_data.toString());
- aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadings().toString());
- Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
- rxBus.send(new EventNewNotification(notification));
- sp.putBoolean("log_AUTOSENS", true);
- break;
- }
- // let it here crash on NPE to get more data as i cannot reproduce this bug
- double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
- if (ad.avgDeviation > maxDeviation) {
- slopeFromMaxDeviation = Math.min(0, deviationSlope);
- maxDeviation = ad.avgDeviation;
- }
- if (ad.avgDeviation < minDeviation) {
- slopeFromMinDeviation = Math.max(0, deviationSlope);
- minDeviation = ad.avgDeviation;
- }
-
- //if (Config.isEnabled(L.AUTOSENS))
- // log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation);
- }
- } catch (Exception e) {
- aapsLogger.error("Unhandled exception", e);
- fabricPrivacy.logException(e);
- aapsLogger.debug(autosensDataTable.toString());
- aapsLogger.debug(bucketed_data.toString());
- aapsLogger.debug(iobCobCalculatorPlugin.getBgReadings().toString());
- Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
- rxBus.send(new EventNewNotification(notification));
- sp.putBoolean("log_AUTOSENS", true);
- break;
- }
- } else {
- aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + "null");
- }
- }
-
- List recentCarbTreatments = treatmentsPlugin.getCarbTreatments5MinBackFromHistory(bgTime);
- for (Treatment recentCarbTreatment : recentCarbTreatments) {
- autosensData.carbsFromBolus += recentCarbTreatment.carbs;
- boolean isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled();
- autosensData.activeCarbsList.add(autosensData.new CarbsInPast(recentCarbTreatment, isAAPSOrWeighted));
- autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.carbs) + "g]";
- }
-
-
- // if we are absorbing carbs
- if (previous != null && previous.cob > 0) {
- // calculate sum of min carb impact from all active treatments
- double totalMinCarbsImpact = 0d;
-// if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
- //when the impact depends on a max time, sum them up as smaller carb sizes make them smaller
-// for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
-// AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
-// totalMinCarbsImpact += c.min5minCarbImpact;
-// }
-// } else {
- //Oref sensitivity
- totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
-// }
-
- // figure out how many carbs that represents
- // but always assume at least 3mg/dL/5m (default) absorption per active treatment
- double ci = Math.max(deviation, totalMinCarbsImpact);
- if (ci != deviation)
- autosensData.failoverToMinAbsorbtionRate = true;
- autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
- // and add that to the running total carbsAbsorbed
- autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
- autosensData.mealCarbs = previous.mealCarbs;
- autosensData.substractAbosorbedCarbs();
- autosensData.usedMinCarbsImpact = totalMinCarbsImpact;
- autosensData.absorbing = previous.absorbing;
- autosensData.mealStartCounter = previous.mealStartCounter;
- autosensData.type = previous.type;
- autosensData.uam = previous.uam;
- }
-
- boolean isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled();
- autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted);
- autosensData.cob += autosensData.carbsFromBolus;
- autosensData.mealCarbs += autosensData.carbsFromBolus;
- autosensData.deviation = deviation;
- autosensData.bgi = bgi;
- autosensData.delta = delta;
- autosensData.avgDelta = avgDelta;
- autosensData.avgDeviation = avgDeviation;
- autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation;
- autosensData.slopeFromMinDeviation = slopeFromMinDeviation;
-
-
- // If mealCOB is zero but all deviations since hitting COB=0 are positive, exclude from autosens
- if (autosensData.cob > 0 || autosensData.absorbing || autosensData.mealCarbs > 0) {
- autosensData.absorbing = deviation > 0;
- // stop excluding positive deviations as soon as mealCOB=0 if meal has been absorbing for >5h
- if (autosensData.mealStartCounter > 60 && autosensData.cob < 0.5) {
- autosensData.absorbing = false;
- }
- if (!autosensData.absorbing && autosensData.cob < 0.5) {
- autosensData.mealCarbs = 0;
- }
- // check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag
- if (!autosensData.type.equals("csf")) {
-// process.stderr.write("(");
- autosensData.mealStartCounter = 0;
- }
- autosensData.mealStartCounter++;
- autosensData.type = "csf";
- } else {
- // check previous "type" value, and if it was csf, set a mealAbsorption end flag
- if (autosensData.type.equals("csf")) {
-// process.stderr.write(")");
- }
-
- double currentBasal = profile.getBasal(bgTime);
- // always exclude the first 45m after each carb entry
- //if (iob.iob > currentBasal || uam ) {
- if (iob.iob > 2 * currentBasal || autosensData.uam || autosensData.mealStartCounter < 9) {
- autosensData.mealStartCounter++;
- autosensData.uam = deviation > 0;
- if (!autosensData.type.equals("uam")) {
-// process.stderr.write("u(");
- }
- autosensData.type = "uam";
- } else {
- if (autosensData.type.equals("uam")) {
-// process.stderr.write(")");
- }
- autosensData.type = "non-meal";
- }
- }
-
- // Exclude meal-related deviations (carb absorption) from autosens
- if (autosensData.type.equals("non-meal")) {
- if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
- autosensData.pastSensitivity += "=";
- autosensData.validDeviation = true;
- } else if (deviation > 0) {
- autosensData.pastSensitivity += "+";
- autosensData.validDeviation = true;
- } else {
- autosensData.pastSensitivity += "-";
- autosensData.validDeviation = true;
- }
- } else if (autosensData.type.equals("uam")) {
- autosensData.pastSensitivity += "u";
- } else {
- autosensData.pastSensitivity += "x";
- }
- //log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
-
- // add an extra negative deviation if a high temptarget is running and exercise mode is set
- // TODO AS-FIX
- if (false && sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) {
- TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(bgTime);
- if (tempTarget != null && tempTarget.target() >= 100) {
- autosensData.extraDeviation.add(-(tempTarget.target() - 100) / 20);
- }
- }
-
- // add one neutral deviation every 2 hours to help decay over long exclusion periods
- GregorianCalendar calendar = new GregorianCalendar();
- calendar.setTimeInMillis(bgTime);
- int min = calendar.get(MINUTE);
- int hours = calendar.get(Calendar.HOUR_OF_DAY);
- if (min >= 0 && min < 5 && hours % 2 == 0)
- autosensData.extraDeviation.add(0d);
-
- previous = autosensData;
- if (bgTime < now())
- autosensDataTable.put(bgTime, autosensData);
- aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime());
- AutosensResult sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime);
- aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: " + sensitivity.toString());
- autosensData.autosensResult = sensitivity;
- aapsLogger.debug(LTag.AUTOSENS, autosensData.toString());
- }
- }
- new Thread(() -> {
- SystemClock.sleep(1000);
- rxBus.send(new EventAutosensCalculationFinished(cause));
- }).start();
- } finally {
- if (mWakeLock != null)
- mWakeLock.release();
- rxBus.send(new EventIobCalculationProgress(""));
- aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: " + from);
- aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log());
- profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start);
- }
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt
new file mode 100644
index 0000000000..5bb64109ae
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt
@@ -0,0 +1,328 @@
+package info.nightscout.androidaps.plugins.iob.iobCobCalculator
+
+import android.content.Context
+import android.os.PowerManager
+import android.os.SystemClock
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.events.Event
+import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.roundUpTime
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.*
+import info.nightscout.androidaps.utils.buildHelper.BuildHelper
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import java.util.*
+import javax.inject.Inject
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.roundToLong
+
+class IobCobOref1Thread internal constructor(
+ private val injector: HasAndroidInjector,
+ private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance
+ private val treatmentsPlugin: TreatmentsPlugin, // cannot be injected : HistoryBrowser uses different instance
+ private val from: String,
+ private val end: Long,
+ private val bgDataReload: Boolean,
+ private val limitDataToOldestAvailable: Boolean,
+ private val cause: Event
+) : Thread() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var sp: SP
+ @Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var resourceHelper: ResourceHelper
+ @Inject lateinit var profileFunction: ProfileFunction
+ @Inject lateinit var context: Context
+ @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin
+ @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin
+ @Inject lateinit var buildHelper: BuildHelper
+ @Inject lateinit var profiler: Profiler
+ @Inject lateinit var fabricPrivacy: FabricPrivacy
+ @Inject lateinit var dateUtil: DateUtil
+
+ private var mWakeLock: PowerManager.WakeLock? = null
+
+ init {
+ injector.androidInjector().inject(this)
+ mWakeLock = (context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, resourceHelper.gs(R.string.app_name) + ":iobCobThread")
+ }
+
+ override fun run() {
+ val start = DateUtil.now()
+ mWakeLock?.acquire(T.mins(10).msecs())
+ try {
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from")
+ if (!profileFunction.isProfileValid("IobCobThread")) {
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): $from")
+ return // app still initializing
+ }
+ //log.debug("Locking calculateSensitivityData");
+ val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
+ synchronized(iobCobCalculatorPlugin.dataLock) {
+ if (bgDataReload) {
+ iobCobCalculatorPlugin.loadBgData(end)
+ iobCobCalculatorPlugin.createBucketedData()
+ rxBus.send(EventAutosensBgLoaded(cause))
+ }
+ val bucketedData = iobCobCalculatorPlugin.bucketedData
+ val autosensDataTable = iobCobCalculatorPlugin.autosensDataTable
+ if (bucketedData == null || bucketedData.size < 3) {
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
+ return
+ }
+ val prevDataTime = roundUpTime(bucketedData[bucketedData.size - 3].timestamp)
+ aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime))
+ var previous = autosensDataTable[prevDataTime]
+ // start from oldest to be able sub cob
+ for (i in bucketedData.size - 4 downTo 0) {
+ val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
+ rxBus.send(EventIobCalculationProgress(progress))
+ if (iobCobCalculatorPlugin.stopCalculationTrigger) {
+ iobCobCalculatorPlugin.stopCalculationTrigger = false
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
+ return
+ }
+ // check if data already exists
+ var bgTime = bucketedData[i].timestamp
+ bgTime = roundUpTime(bgTime)
+ if (bgTime > roundUpTime(DateUtil.now())) continue
+ var existing: AutosensData?
+ if (autosensDataTable[bgTime].also { existing = it } != null) {
+ previous = existing
+ continue
+ }
+ val profile = profileFunction.getProfile(bgTime)
+ if (profile == null) {
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from")
+ return // profile not set yet
+ }
+ aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")")
+ val sens = profile.getIsfMgdl(bgTime)
+ val autosensData = AutosensData(injector)
+ autosensData.time = bgTime
+ if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList()
+
+ //console.error(bgTime , bucketed_data[i].glucose);
+ var avgDelta: Double
+ var delta: Double
+ val bg: Double = bucketedData[i].value
+ if (bg < 39 || bucketedData[i + 3].value < 39) {
+ aapsLogger.error("! value < 39")
+ continue
+ }
+ autosensData.bg = bg
+ delta = bg - bucketedData[i + 1].value
+ avgDelta = (bg - bucketedData[i + 3].value) / 3
+ val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile)
+ val bgi = -iob.activity * sens * 5
+ val deviation = delta - bgi
+ val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0
+ var slopeFromMaxDeviation = 0.0
+ var slopeFromMinDeviation = 999.0
+
+ // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
+ if (i < bucketedData.size - 16) { // we need 1h of data to calculate minDeviationSlope
+ @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0
+ @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0
+ val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L
+ val hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourAgo)
+ if (hourAgoData != null) {
+ val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time)
+ aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString())
+ var past = 1
+ try {
+ while (past < 12) {
+ val ad = autosensDataTable.valueAt(initialIndex + past)
+ aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + ad?.toString())
+ if (ad == null) {
+ aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString())
+ aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString())
+ aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString())
+ val notification = Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
+ rxBus.send(EventNewNotification(notification))
+ sp.putBoolean("log_AUTOSENS", true)
+ break
+ }
+ // let it here crash on NPE to get more data as i cannot reproduce this bug
+ val deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5
+ if (ad.avgDeviation > maxDeviation) {
+ slopeFromMaxDeviation = min(0.0, deviationSlope)
+ maxDeviation = ad.avgDeviation
+ }
+ if (ad.avgDeviation < minDeviation) {
+ slopeFromMinDeviation = max(0.0, deviationSlope)
+ minDeviation = ad.avgDeviation
+ }
+ past++
+ }
+ } catch (e: Exception) {
+ aapsLogger.error("Unhandled exception", e)
+ fabricPrivacy.logException(e)
+ aapsLogger.debug(autosensDataTable.toString())
+ aapsLogger.debug(bucketedData.toString())
+ aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString())
+ val notification = Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
+ rxBus.send(EventNewNotification(notification))
+ sp.putBoolean("log_AUTOSENS", true)
+ break
+ }
+ } else {
+ aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null")
+ }
+ }
+ val recentCarbTreatments = treatmentsPlugin.getCarbTreatments5MinBackFromHistory(bgTime)
+ for (recentCarbTreatment in recentCarbTreatments) {
+ autosensData.carbsFromBolus += recentCarbTreatment.carbs
+ val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()
+ autosensData.activeCarbsList.add(autosensData.CarbsInPast(recentCarbTreatment, isAAPSOrWeighted))
+ autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.carbs) + "g]"
+ }
+
+ // if we are absorbing carbs
+ if (previous != null && previous.cob > 0) {
+ // calculate sum of min carb impact from all active treatments
+ val totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact)
+
+ // figure out how many carbs that represents
+ // but always assume at least 3mg/dL/5m (default) absorption per active treatment
+ val ci = max(deviation, totalMinCarbsImpact)
+ if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true
+ autosensData.absorbed = ci * profile.getIc(bgTime) / sens
+ // and add that to the running total carbsAbsorbed
+ autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0)
+ autosensData.mealCarbs = previous.mealCarbs
+ autosensData.substractAbosorbedCarbs()
+ autosensData.usedMinCarbsImpact = totalMinCarbsImpact
+ autosensData.absorbing = previous.absorbing
+ autosensData.mealStartCounter = previous.mealStartCounter
+ autosensData.type = previous.type
+ autosensData.uam = previous.uam
+ }
+ val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()
+ autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted)
+ autosensData.cob += autosensData.carbsFromBolus
+ autosensData.mealCarbs += autosensData.carbsFromBolus
+ autosensData.deviation = deviation
+ autosensData.bgi = bgi
+ autosensData.delta = delta
+ autosensData.avgDelta = avgDelta
+ autosensData.avgDeviation = avgDeviation
+ autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation
+ autosensData.slopeFromMinDeviation = slopeFromMinDeviation
+
+ // If mealCOB is zero but all deviations since hitting COB=0 are positive, exclude from autosens
+ if (autosensData.cob > 0 || autosensData.absorbing || autosensData.mealCarbs > 0) {
+ autosensData.absorbing = deviation > 0
+ // stop excluding positive deviations as soon as mealCOB=0 if meal has been absorbing for >5h
+ if (autosensData.mealStartCounter > 60 && autosensData.cob < 0.5) {
+ autosensData.absorbing = false
+ }
+ if (!autosensData.absorbing && autosensData.cob < 0.5) {
+ autosensData.mealCarbs = 0.0
+ }
+ // check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag
+ if (autosensData.type != "csf") {
+// process.stderr.write("(");
+ autosensData.mealStartCounter = 0
+ }
+ autosensData.mealStartCounter++
+ autosensData.type = "csf"
+ } else {
+ // check previous "type" value, and if it was csf, set a mealAbsorption end flag
+ val currentBasal = profile.getBasal(bgTime)
+ // always exclude the first 45m after each carb entry
+ //if (iob.iob > currentBasal || uam ) {
+ if (iob.iob > 2 * currentBasal || autosensData.uam || autosensData.mealStartCounter < 9) {
+ autosensData.mealStartCounter++
+ autosensData.uam = deviation > 0
+ autosensData.type = "uam"
+ } else {
+ autosensData.type = "non-meal"
+ }
+ }
+
+ // Exclude meal-related deviations (carb absorption) from autosens
+ when (autosensData.type) {
+ "non-meal" -> {
+ when {
+ abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL -> {
+ autosensData.pastSensitivity += "="
+ autosensData.validDeviation = true
+ }
+
+ deviation > 0 -> {
+ autosensData.pastSensitivity += "+"
+ autosensData.validDeviation = true
+ }
+
+ else -> {
+ autosensData.pastSensitivity += "-"
+ autosensData.validDeviation = true
+ }
+ }
+ }
+
+ "uam" -> {
+ autosensData.pastSensitivity += "u"
+ }
+
+ else -> {
+ autosensData.pastSensitivity += "x"
+ }
+ }
+
+ // add an extra negative deviation if a high temptarget is running and exercise mode is set
+ // TODO AS-FIX
+ @Suppress("SimplifyBooleanWithConstants")
+ if (false && sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) {
+ val tempTarget = treatmentsPlugin.getTempTargetFromHistory(bgTime)
+ if (tempTarget != null && tempTarget.target() >= 100) {
+ autosensData.extraDeviation.add(-(tempTarget.target() - 100) / 20)
+ }
+ }
+
+ // add one neutral deviation every 2 hours to help decay over long exclusion periods
+ val calendar = GregorianCalendar()
+ calendar.timeInMillis = bgTime
+ val min = calendar[Calendar.MINUTE]
+ val hours = calendar[Calendar.HOUR_OF_DAY]
+ if (min in 0..4 && hours % 2 == 0) autosensData.extraDeviation.add(0.0)
+ previous = autosensData
+ if (bgTime < DateUtil.now()) autosensDataTable.put(bgTime, autosensData)
+ aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime())
+ val sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime)
+ aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity")
+ autosensData.autosensResult = sensitivity
+ aapsLogger.debug(LTag.AUTOSENS, autosensData.toString())
+ }
+ }
+ Thread {
+ SystemClock.sleep(1000)
+ rxBus.send(EventAutosensCalculationFinished(cause))
+ }.start()
+ } finally {
+ mWakeLock?.release()
+ rxBus.send(EventIobCalculationProgress(""))
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
+ aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log())
+ profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java
deleted file mode 100644
index 0c7a9444d0..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java
+++ /dev/null
@@ -1,330 +0,0 @@
-package info.nightscout.androidaps.plugins.iob.iobCobCalculator;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.os.SystemClock;
-
-import androidx.collection.LongSparseArray;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.IobTotal;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.db.Treatment;
-import info.nightscout.androidaps.events.Event;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
-import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.DecimalFormatter;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.MidnightTime;
-import info.nightscout.androidaps.utils.Profiler;
-import info.nightscout.androidaps.utils.T;
-import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-import static info.nightscout.androidaps.utils.DateUtil.now;
-
-/**
- * Created by mike on 23.01.2018.
- */
-
-public class IobCobThread extends Thread {
- private final Event cause;
-
- @Inject AAPSLogger aapsLogger;
- @Inject SP sp;
- @Inject RxBusWrapper rxBus;
- @Inject ResourceHelper resourceHelper;
- @Inject ProfileFunction profileFunction;
- @Inject Context context;
- @Inject SensitivityAAPSPlugin sensitivityAAPSPlugin;
- @Inject SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin;
- @Inject BuildHelper buildHelper;
- @Inject Profiler profiler;
- @Inject FabricPrivacy fabricPrivacy;
- @Inject DateUtil dateUtil;
-
- private final HasAndroidInjector injector;
- private final IobCobCalculatorPlugin iobCobCalculatorPlugin; // cannot be injected : HistoryBrowser uses different instance
- private final TreatmentsPlugin treatmentsPlugin; // cannot be injected : HistoryBrowser uses different instance
- private final boolean bgDataReload;
- private final boolean limitDataToOldestAvailable;
- private final String from;
- private final long end;
-
- private PowerManager.WakeLock mWakeLock;
-
- @Inject IobCobThread(HasAndroidInjector injector, IobCobCalculatorPlugin iobCobCalculatorPlugin, TreatmentsPlugin treatmentsPlugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) {
- super();
- injector.androidInjector().inject(this);
- this.injector = injector;
- this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
- this.treatmentsPlugin = treatmentsPlugin;
-
- this.bgDataReload = bgDataReload;
- this.limitDataToOldestAvailable = limitDataToOldestAvailable;
- this.from = from;
- this.cause = cause;
- this.end = end;
-
- PowerManager powerManager = (PowerManager) context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
- if (powerManager != null)
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, resourceHelper.gs(R.string.app_name) + ":iobCobThread");
- }
-
- @Override
- public final void run() {
- long start = DateUtil.now();
- if (mWakeLock != null)
- mWakeLock.acquire(T.mins(10).msecs());
- try {
- aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: " + from);
- if (!profileFunction.isProfileValid("IobCobThread")) {
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): " + from);
- return; // app still initializing
- }
- //log.debug("Locking calculateSensitivityData");
-
- long oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable);
-
- synchronized (iobCobCalculatorPlugin.getDataLock()) {
- if (bgDataReload) {
- iobCobCalculatorPlugin.loadBgData(end);
- iobCobCalculatorPlugin.createBucketedData();
- rxBus.send(new EventAutosensBgLoaded(cause));
- }
- List bucketed_data = iobCobCalculatorPlugin.getBucketedData();
- LongSparseArray autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
-
- if (bucketed_data == null || bucketed_data.size() < 3) {
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): " + from);
- return;
- }
-
- long prevDataTime = IobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).getTimestamp());
- aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime));
- AutosensData previous = autosensDataTable.get(prevDataTime);
- // start from oldest to be able sub cob
- for (int i = bucketed_data.size() - 4; i >= 0; i--) {
- String progress = i + (buildHelper.isDev() ? " (" + from + ")" : "");
- rxBus.send(new EventIobCalculationProgress(progress));
-
- if (iobCobCalculatorPlugin.stopCalculationTrigger) {
- iobCobCalculatorPlugin.stopCalculationTrigger = false;
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): " + from);
- return;
- }
- // check if data already exists
- long bgTime = bucketed_data.get(i).getTimestamp();
- bgTime = IobCobCalculatorPlugin.roundUpTime(bgTime);
- if (bgTime > IobCobCalculatorPlugin.roundUpTime(now()))
- continue;
-
- AutosensData existing;
- if ((existing = autosensDataTable.get(bgTime)) != null) {
- previous = existing;
- continue;
- }
-
- Profile profile = profileFunction.getProfile(bgTime);
- if (profile == null) {
- aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): " + from);
- return; // profile not set yet
- }
-
- aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
-
- double sens = profile.getIsfMgdl(bgTime);
-
- AutosensData autosensData = new AutosensData(injector);
- autosensData.time = bgTime;
- if (previous != null)
- autosensData.activeCarbsList = previous.cloneCarbsList();
- else
- autosensData.activeCarbsList = new ArrayList<>();
-
- //console.error(bgTime , bucketed_data[i].glucose);
- double bg;
- double avgDelta;
- double delta;
- bg = bucketed_data.get(i).getValue();
- if (bg < 39 || bucketed_data.get(i + 3).getValue() < 39) {
- aapsLogger.error("! value < 39");
- continue;
- }
- autosensData.bg = bg;
- delta = (bg - bucketed_data.get(i + 1).getValue());
- avgDelta = (bg - bucketed_data.get(i + 3).getValue()) / 3;
-
- IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile);
-
- double bgi = -iob.activity * sens * 5;
- double deviation = delta - bgi;
- double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000d;
-
- double slopeFromMaxDeviation = 0;
- double slopeFromMinDeviation = 999;
- double maxDeviation = 0;
- double minDeviation = 999;
-
- // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
- if (i < bucketed_data.size() - 16) { // we need 1h of data to calculate minDeviationSlope
- long hourago = bgTime + 10 * 1000 - 60 * 60 * 1000L;
- AutosensData hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourago);
- if (hourAgoData != null) {
- int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time);
- aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + hourAgoData.toString());
- int past = 1;
- try {
- for (; past < 12; past++) {
- AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
- aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
- if (ad == null) {
- aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString());
- aapsLogger.debug(LTag.AUTOSENS, bucketed_data.toString());
- aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadings().toString());
- Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
- rxBus.send(new EventNewNotification(notification));
- sp.putBoolean("log_AUTOSENS", true);
- break;
- }
- // let it here crash on NPE to get more data as i cannot reproduce this bug
- double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
- if (ad.avgDeviation > maxDeviation) {
- slopeFromMaxDeviation = Math.min(0, deviationSlope);
- maxDeviation = ad.avgDeviation;
- }
- if (ad.avgDeviation < minDeviation) {
- slopeFromMinDeviation = Math.max(0, deviationSlope);
- minDeviation = ad.avgDeviation;
- }
-
- //if (Config.isEnabled(L.AUTOSENS))
- // log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation);
- }
- } catch (Exception e) {
- aapsLogger.error("Unhandled exception", e);
- fabricPrivacy.logException(e);
- aapsLogger.debug(autosensDataTable.toString());
- aapsLogger.debug(bucketed_data.toString());
- aapsLogger.debug(iobCobCalculatorPlugin.getBgReadings().toString());
- Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
- rxBus.send(new EventNewNotification(notification));
- sp.putBoolean("log_AUTOSENS", true);
- break;
- }
- } else {
- aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + "null");
- }
- }
-
- List recentCarbTreatments = treatmentsPlugin.getCarbTreatments5MinBackFromHistory(bgTime);
- for (Treatment recentCarbTreatment : recentCarbTreatments) {
- autosensData.carbsFromBolus += recentCarbTreatment.carbs;
- boolean isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled();
- autosensData.activeCarbsList.add(autosensData.new CarbsInPast(recentCarbTreatment, isAAPSOrWeighted));
- autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.carbs) + "g]";
- }
-
-
- // if we are absorbing carbs
- if (previous != null && previous.cob > 0) {
- // calculate sum of min carb impact from all active treatments
- double totalMinCarbsImpact = 0d;
- if (sensitivityAAPSPlugin.isEnabled(PluginType.SENSITIVITY) || sensitivityWeightedAveragePlugin.isEnabled(PluginType.SENSITIVITY)) {
- //when the impact depends on a max time, sum them up as smaller carb sizes make them smaller
- for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
- AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
- totalMinCarbsImpact += c.min5minCarbImpact;
- }
- } else {
- //Oref sensitivity
- totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
- }
-
- // figure out how many carbs that represents
- // but always assume at least 3mg/dL/5m (default) absorption per active treatment
- double ci = Math.max(deviation, totalMinCarbsImpact);
- if (ci != deviation)
- autosensData.failoverToMinAbsorbtionRate = true;
- autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
- // and add that to the running total carbsAbsorbed
- autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
- autosensData.substractAbosorbedCarbs();
- autosensData.usedMinCarbsImpact = totalMinCarbsImpact;
- }
- boolean isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled();
- autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted);
- autosensData.cob += autosensData.carbsFromBolus;
- autosensData.deviation = deviation;
- autosensData.bgi = bgi;
- autosensData.delta = delta;
- autosensData.avgDelta = avgDelta;
- autosensData.avgDeviation = avgDeviation;
- autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation;
- autosensData.slopeFromMinDeviation = slopeFromMinDeviation;
-
-
- // calculate autosens only without COB
- if (autosensData.cob <= 0) {
- if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
- autosensData.pastSensitivity += "=";
- autosensData.validDeviation = true;
- } else if (deviation > 0) {
- autosensData.pastSensitivity += "+";
- autosensData.validDeviation = true;
- } else {
- autosensData.pastSensitivity += "-";
- autosensData.validDeviation = true;
- }
- } else {
- autosensData.pastSensitivity += "C";
- }
- //log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
-
- previous = autosensData;
- if (bgTime < now())
- autosensDataTable.put(bgTime, autosensData);
- aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime());
- AutosensResult sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime);
- aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: " + sensitivity.toString());
- autosensData.autosensResult = sensitivity;
- aapsLogger.debug(LTag.AUTOSENS, autosensData.toString());
- }
- }
- new Thread(() -> {
- SystemClock.sleep(1000);
- rxBus.send(new EventAutosensCalculationFinished(cause));
- }).start();
- } finally {
- if (mWakeLock != null)
- mWakeLock.release();
- rxBus.send(new EventIobCalculationProgress(""));
- aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: " + from);
- aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log());
- profiler.log(LTag.AUTOSENS, "IobCobThread", start);
- }
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt
new file mode 100644
index 0000000000..1f67032978
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt
@@ -0,0 +1,277 @@
+package info.nightscout.androidaps.plugins.iob.iobCobCalculator
+
+import android.content.Context
+import android.os.PowerManager
+import android.os.SystemClock
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.events.Event
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.roundUpTime
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.*
+import info.nightscout.androidaps.utils.buildHelper.BuildHelper
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import java.util.*
+import javax.inject.Inject
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.roundToLong
+
+class IobCobThread @Inject internal constructor(
+ private val injector: HasAndroidInjector,
+ private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance
+ private val treatmentsPlugin: TreatmentsPlugin, // cannot be injected : HistoryBrowser uses different instance
+ private val from: String,
+ private val end: Long,
+ private val bgDataReload: Boolean,
+ private val limitDataToOldestAvailable: Boolean,
+ private val cause: Event
+) : Thread() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var sp: SP
+ @Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var resourceHelper: ResourceHelper
+ @Inject lateinit var profileFunction: ProfileFunction
+ @Inject lateinit var context: Context
+ @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin
+ @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin
+ @Inject lateinit var buildHelper: BuildHelper
+ @Inject lateinit var profiler: Profiler
+ @Inject lateinit var fabricPrivacy: FabricPrivacy
+ @Inject lateinit var dateUtil: DateUtil
+
+ private var mWakeLock: PowerManager.WakeLock? = null
+
+ init {
+ injector.androidInjector().inject(this)
+ mWakeLock = (context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, resourceHelper.gs(R.string.app_name) + ":iobCobThread")
+ }
+
+ override fun run() {
+ val start = DateUtil.now()
+ mWakeLock?.acquire(T.mins(10).msecs())
+ try {
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from")
+ if (!profileFunction.isProfileValid("IobCobThread")) {
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): $from")
+ return // app still initializing
+ }
+ //log.debug("Locking calculateSensitivityData");
+ val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
+ synchronized(iobCobCalculatorPlugin.dataLock) {
+ if (bgDataReload) {
+ iobCobCalculatorPlugin.loadBgData(end)
+ iobCobCalculatorPlugin.createBucketedData()
+ rxBus.send(EventAutosensBgLoaded(cause))
+ }
+ val bucketedData = iobCobCalculatorPlugin.bucketedData
+ val autosensDataTable = iobCobCalculatorPlugin.autosensDataTable
+ if (bucketedData == null || bucketedData.size < 3) {
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
+ return
+ }
+ val prevDataTime = roundUpTime(bucketedData[bucketedData.size - 3].timestamp)
+ aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime))
+ var previous = autosensDataTable[prevDataTime]
+ // start from oldest to be able sub cob
+ for (i in bucketedData.size - 4 downTo 0) {
+ val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
+ rxBus.send(EventIobCalculationProgress(progress))
+ if (iobCobCalculatorPlugin.stopCalculationTrigger) {
+ iobCobCalculatorPlugin.stopCalculationTrigger = false
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
+ return
+ }
+ // check if data already exists
+ var bgTime = bucketedData[i].timestamp
+ bgTime = roundUpTime(bgTime)
+ if (bgTime > roundUpTime(DateUtil.now())) continue
+ var existing: AutosensData?
+ if (autosensDataTable[bgTime].also { existing = it } != null) {
+ previous = existing
+ continue
+ }
+ val profile = profileFunction.getProfile(bgTime)
+ if (profile == null) {
+ aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from")
+ return // profile not set yet
+ }
+ aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")")
+ val sens = profile.getIsfMgdl(bgTime)
+ val autosensData = AutosensData(injector)
+ autosensData.time = bgTime
+ if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList()
+
+ //console.error(bgTime , bucketed_data[i].glucose);
+ var avgDelta: Double
+ var delta: Double
+ val bg: Double = bucketedData[i].value
+ if (bg < 39 || bucketedData[i + 3].value < 39) {
+ aapsLogger.error("! value < 39")
+ continue
+ }
+ autosensData.bg = bg
+ delta = bg - bucketedData[i + 1].value
+ avgDelta = (bg - bucketedData[i + 3].value) / 3
+ val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile)
+ val bgi = -iob.activity * sens * 5
+ val deviation = delta - bgi
+ val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0
+ var slopeFromMaxDeviation = 0.0
+ var slopeFromMinDeviation = 999.0
+
+ // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
+ if (i < bucketedData.size - 16) { // we need 1h of data to calculate minDeviationSlope
+ @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0
+ @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0
+ val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L
+ val hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourAgo)
+ if (hourAgoData != null) {
+ val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time)
+ aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString())
+ var past = 1
+ try {
+ while (past < 12) {
+ val ad = autosensDataTable.valueAt(initialIndex + past)
+ aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + ad?.toString())
+ if (ad == null) {
+ aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString())
+ aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString())
+ aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString())
+ val notification = Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
+ rxBus.send(EventNewNotification(notification))
+ sp.putBoolean("log_AUTOSENS", true)
+ break
+ }
+ // let it here crash on NPE to get more data as i cannot reproduce this bug
+ val deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5
+ if (ad.avgDeviation > maxDeviation) {
+ slopeFromMaxDeviation = min(0.0, deviationSlope)
+ maxDeviation = ad.avgDeviation
+ }
+ if (ad.avgDeviation < minDeviation) {
+ slopeFromMinDeviation = max(0.0, deviationSlope)
+ minDeviation = ad.avgDeviation
+ }
+ past++
+ }
+ } catch (e: Exception) {
+ aapsLogger.error("Unhandled exception", e)
+ fabricPrivacy.logException(e)
+ aapsLogger.debug(autosensDataTable.toString())
+ aapsLogger.debug(bucketedData.toString())
+ aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString())
+ val notification = Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
+ rxBus.send(EventNewNotification(notification))
+ sp.putBoolean("log_AUTOSENS", true)
+ break
+ }
+ } else {
+ aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null")
+ }
+ }
+ val recentCarbTreatments = treatmentsPlugin.getCarbTreatments5MinBackFromHistory(bgTime)
+ for (recentCarbTreatment in recentCarbTreatments) {
+ autosensData.carbsFromBolus += recentCarbTreatment.carbs
+ val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()
+ autosensData.activeCarbsList.add(autosensData.CarbsInPast(recentCarbTreatment, isAAPSOrWeighted))
+ autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.carbs) + "g]"
+ }
+
+ // if we are absorbing carbs
+ if (previous != null && previous.cob > 0) {
+ // calculate sum of min carb impact from all active treatments
+ var totalMinCarbsImpact = 0.0
+ if (sensitivityAAPSPlugin.isEnabled(PluginType.SENSITIVITY) || sensitivityWeightedAveragePlugin.isEnabled(PluginType.SENSITIVITY)) {
+ //when the impact depends on a max time, sum them up as smaller carb sizes make them smaller
+ for (ii in autosensData.activeCarbsList.indices) {
+ val c = autosensData.activeCarbsList[ii]
+ totalMinCarbsImpact += c.min5minCarbImpact
+ }
+ } else {
+ //Oref sensitivity
+ totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact)
+ }
+
+ // figure out how many carbs that represents
+ // but always assume at least 3mg/dL/5m (default) absorption per active treatment
+ val ci = max(deviation, totalMinCarbsImpact)
+ if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true
+ autosensData.absorbed = ci * profile.getIc(bgTime) / sens
+ // and add that to the running total carbsAbsorbed
+ autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0)
+ autosensData.substractAbosorbedCarbs()
+ autosensData.usedMinCarbsImpact = totalMinCarbsImpact
+ }
+ val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()
+ autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted)
+ autosensData.cob += autosensData.carbsFromBolus
+ autosensData.deviation = deviation
+ autosensData.bgi = bgi
+ autosensData.delta = delta
+ autosensData.avgDelta = avgDelta
+ autosensData.avgDeviation = avgDeviation
+ autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation
+ autosensData.slopeFromMinDeviation = slopeFromMinDeviation
+
+ // calculate autosens only without COB
+ if (autosensData.cob <= 0) {
+ when {
+ abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL -> {
+ autosensData.pastSensitivity += "="
+ autosensData.validDeviation = true
+ }
+
+ deviation > 0 -> {
+ autosensData.pastSensitivity += "+"
+ autosensData.validDeviation = true
+ }
+
+ else -> {
+ autosensData.pastSensitivity += "-"
+ autosensData.validDeviation = true
+ }
+ }
+ } else {
+ autosensData.pastSensitivity += "C"
+ }
+ previous = autosensData
+ if (bgTime < DateUtil.now()) autosensDataTable.put(bgTime, autosensData)
+ aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime())
+ val sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime)
+ aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity")
+ autosensData.autosensResult = sensitivity
+ aapsLogger.debug(LTag.AUTOSENS, autosensData.toString())
+ }
+ }
+ Thread {
+ SystemClock.sleep(1000)
+ rxBus.send(EventAutosensCalculationFinished(cause))
+ }.start()
+ } finally {
+ mWakeLock?.release()
+ rxBus.send(EventIobCalculationProgress(""))
+ aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
+ aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log())
+ profiler.log(LTag.AUTOSENS, "IobCobThread", start)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt
index 88a623a091..368df27e4b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt
@@ -16,11 +16,12 @@ import info.nightscout.androidaps.databinding.LocalprofileFragmentBinding
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
@@ -38,6 +39,7 @@ class LocalProfileFragment : DaggerFragment() {
@Inject lateinit var hardLimits: HardLimits
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private var disposable: CompositeDisposable = CompositeDisposable()
@@ -80,6 +82,7 @@ class LocalProfileFragment : DaggerFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// activate DIA tab
+ processVisibilityOnClick(binding.diaTab)
binding.diaPlaceholder.visibility = View.VISIBLE
// setup listeners
binding.diaTab.setOnClickListener {
@@ -159,6 +162,7 @@ class LocalProfileFragment : DaggerFragment() {
if (localProfilePlugin.isEdited) {
activity?.let { OKDialog.show(it, "", resourceHelper.gs(R.string.saveorresetchangesfirst)) }
} else {
+ uel.log("NEW PROFILE")
localProfilePlugin.addNewProfile()
build()
}
@@ -168,6 +172,7 @@ class LocalProfileFragment : DaggerFragment() {
if (localProfilePlugin.isEdited) {
activity?.let { OKDialog.show(it, "", resourceHelper.gs(R.string.saveorresetchangesfirst)) }
} else {
+ uel.log("CLONE PROFILE", localProfilePlugin.currentProfile()?.name ?: "")
localProfilePlugin.cloneProfile()
build()
}
@@ -176,6 +181,7 @@ class LocalProfileFragment : DaggerFragment() {
binding.profileRemove.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.deletecurrentprofile), {
+ uel.log("REMOVE PROFILE", localProfilePlugin.currentProfile()?.name ?: "")
localProfilePlugin.removeCurrentProfile()
build()
}, null)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt
index 07be4da165..e8d5dba65d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt
@@ -9,6 +9,7 @@ import info.nightscout.androidaps.events.EventProfileStoreChanged
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.DateUtil
@@ -32,7 +33,8 @@ class LocalProfilePlugin @Inject constructor(
resourceHelper: ResourceHelper,
private val sp: SP,
private val profileFunction: ProfileFunction,
- private val nsUpload: NSUpload
+ private val nsUpload: NSUpload,
+ private val uel: UserEntryLogger
) : PluginBase(PluginDescription()
.mainType(PluginType.PROFILE)
.fragmentClass(LocalProfileFragment::class.java.name)
@@ -113,6 +115,7 @@ class LocalProfilePlugin @Inject constructor(
createAndStoreConvertedProfile()
isEdited = false
aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString())
+ uel.log("STORE PROFILE")
rxBus.send(EventProfileStoreChanged())
var namesOK = true
profiles.forEach {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt
index b3c8a98dd8..f8c8c0ed25 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt
@@ -10,6 +10,7 @@ import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.NsprofileFragmentBinding
import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
@@ -17,7 +18,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
@@ -32,6 +33,7 @@ class NSProfileFragment : DaggerFragment() {
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private var disposable: CompositeDisposable = CompositeDisposable()
@@ -59,6 +61,7 @@ class NSProfileFragment : DaggerFragment() {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.nsprofile),
resourceHelper.gs(R.string.activate_profile) + ": " + name + " ?", Runnable {
+ uel.log("PROFILE SWITCH", name, i1 = 100)
treatmentsPlugin.doProfileSwitch(store, name, 0, 100, 0, DateUtil.now())
})
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt
index a47e53afe1..5109f6811c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt
@@ -17,6 +17,8 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
+import info.nightscout.androidaps.receivers.BundleStore
+import info.nightscout.androidaps.receivers.DataReceiver
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONObject
@@ -87,13 +89,16 @@ class NSProfilePlugin @Inject constructor(
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var bundleStore: BundleStore
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
override fun doWork(): Result {
- inputData.getString("profile")?.let { profileString ->
+ val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1))
+ ?: return Result.failure()
+ bundle.getString("profile")?.let { profileString ->
nsProfilePlugin.profile = ProfileStore(injector, JSONObject(profileString))
nsProfilePlugin.storeNSProfile()
if (nsProfilePlugin.isEnabled()) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java
index cee77a2303..354468f7aa 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java
@@ -41,13 +41,11 @@ import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.PumpPluginBase;
+import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.common.ManufacturerType;
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
-import info.nightscout.androidaps.queue.commands.CustomCommand;
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress;
@@ -83,7 +81,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
private final ResourceHelper resourceHelper;
private final ProfileFunction profileFunction;
- private final TreatmentsPlugin treatmentsPlugin;
+ private final TreatmentsInterface treatmentsPlugin;
private final info.nightscout.androidaps.utils.sharedPreferences.SP sp;
private RxBusWrapper rxBus;
private final CommandQueueProvider commandQueue;
@@ -139,7 +137,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
RxBusWrapper rxBus,
ResourceHelper resourceHelper,
ProfileFunction profileFunction,
- TreatmentsPlugin treatmentsPlugin,
+ TreatmentsInterface treatmentsPlugin,
SP sp,
CommandQueueProvider commandQueue,
Context context
@@ -224,11 +222,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
}
@Override
- public void finishHandshaking() {
- }
-
- @Override
- public void connect(String reason) {
+ public void connect(@NonNull String reason) {
// ruffyscripter establishes a connection as needed.
// ComboPlugin.runCommand performs on connect checks if needed, thus needs info on
// whether a connection is there.
@@ -240,7 +234,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
}
@Override
- public void disconnect(String reason) {
+ public void disconnect(@NonNull String reason) {
getAapsLogger().debug(LTag.PUMP, "Disconnect called with reason: " + reason);
ruffyScripter.disconnect();
}
@@ -251,7 +245,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
}
@NonNull @Override
- public synchronized PumpEnactResult setNewBasalProfile(Profile profile) {
+ public synchronized PumpEnactResult setNewBasalProfile(@NonNull Profile profile) {
if (!isInitialized()) {
// note that this should not happen anymore since the queue is present, which
// issues a READSTATE when starting to issue commands which initializes the pump
@@ -294,7 +288,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
}
@Override
- public boolean isThisProfileSet(Profile profile) {
+ public boolean isThisProfileSet(@NonNull Profile profile) {
if (!isInitialized()) {
/* This might be called too soon during boot. Return true to prevent a request
to update the profile. KeepAlive is called every Constants.keepalivems
@@ -338,7 +332,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
* Runs pump initialization if needed and reads the pump state from the main screen.
*/
@Override
- public synchronized void getPumpStatus(String reason) {
+ public synchronized void getPumpStatus(@NonNull String reason) {
getAapsLogger().debug(LTag.PUMP, "getPumpStatus called");
if (!pump.initialized) {
initializePump();
@@ -720,7 +714,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
* the new value (and thus still has the old duration of e.g. 1 min) expires?)
*/
@NonNull @Override
- public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean force) {
+ public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean force) {
getAapsLogger().debug(LTag.PUMP, "setTempBasalAbsolute called with a rate of " + absoluteRate + " for " + durationInMinutes + " min.");
int unroundedPercentage = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
int roundedPercentage = (int) (Math.round(absoluteRate / getBaseBasalRate() * 10) * 10);
@@ -738,7 +732,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
* is or isn't running at the moment
*/
@NonNull @Override
- public PumpEnactResult setTempBasalPercent(Integer percent, final Integer durationInMinutes, Profile profile, boolean forceNew) {
+ public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean forceNew) {
return setTempBasalPercent(percent, durationInMinutes);
}
@@ -794,7 +788,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
}
@NonNull @Override
- public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
+ public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
return OPERATION_NOT_SUPPORTED;
}
@@ -853,6 +847,10 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
}
}
+ @Override public int waitForDisconnectionInSeconds() {
+ return 0;
+ }
+
private interface CommandExecution {
CommandResult execute();
}
@@ -1388,19 +1386,6 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
return maxIob;
}
- @Override
- public List getCustomActions() {
- return null;
- }
-
- @Override
- public void executeCustomAction(CustomActionType customActionType) {
- }
-
- @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) {
- return null;
- }
-
@Override
public boolean canHandleDST() {
return false;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java
index 2459c7a4fa..638439e728 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java
@@ -11,7 +11,6 @@ import android.os.IBinder;
import android.os.Looper;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import org.json.JSONException;
import org.json.JSONObject;
@@ -50,12 +49,11 @@ import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.PumpPluginBase;
+import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.common.ManufacturerType;
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue;
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
@@ -132,8 +130,6 @@ import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_erro
import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_errors.NoActiveTBRToCanceLException;
import info.nightscout.androidaps.plugins.pump.insight.utils.ExceptionTranslator;
import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.queue.commands.CustomCommand;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.TimeChangeType;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
@@ -145,7 +141,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private final AAPSLogger aapsLogger;
private final RxBusWrapper rxBus;
private final ResourceHelper resourceHelper;
- private final TreatmentsPlugin treatmentsPlugin;
+ private final TreatmentsInterface treatmentsPlugin;
private final SP sp;
private final CommandQueueProvider commandQueue;
private final ProfileFunction profileFunction;
@@ -207,7 +203,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
AAPSLogger aapsLogger,
RxBusWrapper rxBus,
ResourceHelper resourceHelper,
- TreatmentsPlugin treatmentsPlugin,
+ TreatmentsInterface treatmentsPlugin,
SP sp,
CommandQueueProvider commandQueue,
ProfileFunction profileFunction,
@@ -343,11 +339,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
return false;
}
- @Override
- public void finishHandshaking() {
-
- }
-
@Override
public void connect(String reason) {
if (connectionService != null && alertService != null)
@@ -709,7 +700,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
}
@NonNull @Override
- public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
+ public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(getInjector());
if (activeBasalRate == null) return result;
if (activeBasalRate.getActiveBasalRate() == 0) return result;
@@ -759,7 +750,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
}
@NonNull @Override
- public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
+ public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(getInjector());
percent = (int) Math.round(((double) percent) / 10d) * 10;
if (percent == 100) return cancelTempBasal(true);
@@ -798,7 +789,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
}
@NonNull @Override
- public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
+ public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
PumpEnactResult result = cancelExtendedBolusOnly();
if (result.success)
result = setExtendedBolusOnly(insulin, durationInMinutes, sp.getBoolean(R.string.key_disable_vibration, false));
@@ -987,11 +978,11 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
}
@NonNull @Override
- public JSONObject getJSONStatus(Profile profile, String profileName, String version) {
+ public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) {
long now = System.currentTimeMillis();
- if (connectionService == null) return null;
+ if (connectionService == null) return new JSONObject();
if (System.currentTimeMillis() - connectionService.getLastConnected() > (60 * 60 * 1000)) {
- return null;
+ return new JSONObject();
}
final JSONObject pump = new JSONObject();
@@ -1165,19 +1156,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
return new PumpEnactResult(getInjector()).success(true);
}
- @Override
- public List getCustomActions() {
- return null;
- }
-
- @Override
- public void executeCustomAction(CustomActionType customActionType) {
- }
-
- @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) {
- return null;
- }
-
private void readHistory() {
try {
PumpTime pumpTime = connectionService.requestMessage(new GetDateTimeMessage()).await().getPumpTime();
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java
deleted file mode 100644
index c3aedab567..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java
+++ /dev/null
@@ -1,304 +0,0 @@
-package info.nightscout.androidaps.plugins.pump.mdi;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.DetailedBolusInfo;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.data.PumpEnactResult;
-import info.nightscout.androidaps.interfaces.CommandQueueProvider;
-import info.nightscout.androidaps.interfaces.PluginDescription;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.PumpDescription;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.interfaces.PumpPluginBase;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.common.ManufacturerType;
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
-import info.nightscout.androidaps.queue.commands.CustomCommand;
-import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.InstanceId;
-import info.nightscout.androidaps.utils.TimeChangeType;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-
-
-/**
- * Created by mike on 05.08.2016.
- */
-@Singleton
-public class MDIPlugin extends PumpPluginBase implements PumpInterface {
-
- private final TreatmentsPlugin treatmentsPlugin;
- private final PumpDescription pumpDescription = new PumpDescription();
-
- @Inject
- public MDIPlugin(
- HasAndroidInjector injector,
- AAPSLogger aapsLogger,
- RxBusWrapper rxBus,
- ResourceHelper resourceHelper,
- CommandQueueProvider commandQueue,
- TreatmentsPlugin treatmentsPlugin
- ) {
- super(new PluginDescription()
- .mainType(PluginType.PUMP)
- .pluginIcon(R.drawable.ic_ict)
- .pluginName(R.string.mdi)
- .description(R.string.description_pump_mdi),
- injector, aapsLogger, resourceHelper, commandQueue
- );
- this.treatmentsPlugin = treatmentsPlugin;
-
- pumpDescription.isBolusCapable = true;
- pumpDescription.bolusStep = 0.5d;
-
- pumpDescription.isExtendedBolusCapable = false;
- pumpDescription.isTempBasalCapable = false;
- pumpDescription.isSetBasalProfileCapable = false;
- pumpDescription.isRefillingCapable = false;
- pumpDescription.isBatteryReplaceable = false;
- }
-
- @Override
- public boolean isFakingTempsByExtendedBoluses() {
- return false;
- }
-
- @NonNull @Override
- public PumpEnactResult loadTDDs() {
- //no result, could read DB in the future?
- PumpEnactResult result = new PumpEnactResult(getInjector());
- return result;
- }
-
- @Override
- public boolean isInitialized() {
- return true;
- }
-
- @Override
- public boolean isSuspended() {
- return false;
- }
-
- @Override
- public boolean isBusy() {
- return false;
- }
-
- @Override
- public boolean isConnected() {
- return true;
- }
-
- @Override
- public boolean isConnecting() {
- return false;
- }
-
- @Override
- public boolean isHandshakeInProgress() {
- return false;
- }
-
- @Override
- public void finishHandshaking() {
- }
-
- @Override
- public void connect(String reason) {
- }
-
- @Override
- public void disconnect(String reason) {
- }
-
- @Override
- public void stopConnecting() {
- }
-
- @Override
- public void getPumpStatus(String reason) {
- }
-
- @NonNull @Override
- public PumpEnactResult setNewBasalProfile(Profile profile) {
- // Do nothing here. we are using ConfigBuilderPlugin.getPlugin().getActiveProfile().getProfile();
- PumpEnactResult result = new PumpEnactResult(getInjector());
- result.success = true;
- return result;
- }
-
- @Override
- public boolean isThisProfileSet(Profile profile) {
- return false;
- }
-
- @Override
- public long lastDataTime() {
- return System.currentTimeMillis();
- }
-
- @Override
- public double getBaseBasalRate() {
- return 0d;
- }
-
- @Override
- public double getReservoirLevel() {
- return -1;
- }
-
- @Override
- public int getBatteryLevel() {
- return -1;
- }
-
- @NonNull @Override
- public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
- PumpEnactResult result = new PumpEnactResult(getInjector());
- result.success = true;
- result.bolusDelivered = detailedBolusInfo.insulin;
- result.carbsDelivered = detailedBolusInfo.carbs;
- result.comment = getResourceHelper().gs(R.string.virtualpump_resultok);
- treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false);
- return result;
- }
-
- @Override
- public void stopBolusDelivering() {
- }
-
- @NonNull @Override
- public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
- PumpEnactResult result = new PumpEnactResult(getInjector());
- result.success = false;
- result.comment = getResourceHelper().gs(R.string.pumperror);
- getAapsLogger().debug(LTag.PUMPBTCOMM, "Setting temp basal absolute: " + result);
- return result;
- }
-
- @NonNull @Override
- public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
- PumpEnactResult result = new PumpEnactResult(getInjector());
- result.success = false;
- result.comment = getResourceHelper().gs(R.string.pumperror);
- getAapsLogger().debug(LTag.PUMPBTCOMM, "Settings temp basal percent: " + result);
- return result;
- }
-
- @NonNull @Override
- public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
- PumpEnactResult result = new PumpEnactResult(getInjector());
- result.success = false;
- result.comment = getResourceHelper().gs(R.string.pumperror);
- getAapsLogger().debug(LTag.PUMPBTCOMM, "Setting extended bolus: " + result);
- return result;
- }
-
- @NonNull @Override
- public PumpEnactResult cancelTempBasal(boolean force) {
- PumpEnactResult result = new PumpEnactResult(getInjector());
- result.success = false;
- result.comment = getResourceHelper().gs(R.string.pumperror);
- getAapsLogger().debug(LTag.PUMPBTCOMM, "Cancel temp basal: " + result);
- return result;
- }
-
- @NonNull @Override
- public PumpEnactResult cancelExtendedBolus() {
- PumpEnactResult result = new PumpEnactResult(getInjector());
- result.success = false;
- result.comment = getResourceHelper().gs(R.string.pumperror);
- getAapsLogger().debug(LTag.PUMPBTCOMM, "Canceling extended bolus: " + result);
- return result;
- }
-
- @NonNull @Override
- public JSONObject getJSONStatus(Profile profile, String profileName, String version) {
- long now = System.currentTimeMillis();
- JSONObject pump = new JSONObject();
- JSONObject status = new JSONObject();
- JSONObject extended = new JSONObject();
- try {
- status.put("status", "normal");
- extended.put("Version", version);
- try {
- extended.put("ActiveProfile", profileName);
- } catch (Exception e) {
- }
- status.put("timestamp", DateUtil.toISOString(now));
-
- pump.put("status", status);
- pump.put("extended", extended);
- pump.put("clock", DateUtil.toISOString(now));
- } catch (JSONException e) {
- }
- return pump;
- }
-
- @NonNull @Override
- public ManufacturerType manufacturer() {
- return ManufacturerType.AndroidAPS;
- }
-
- @NonNull @Override
- public PumpType model() {
- return PumpType.MDI;
- }
-
- @NonNull @Override
- public String serialNumber() {
- return InstanceId.INSTANCE.instanceId();
- }
-
- @NonNull @Override
- public PumpDescription getPumpDescription() {
- return pumpDescription;
- }
-
- @NonNull @Override
- public String shortStatus(boolean veryShort) {
- return model().getModel();
- }
-
- @Override
- public List getCustomActions() {
- return null;
- }
-
- @Override
- public void executeCustomAction(CustomActionType customActionType) {
- }
-
- @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) {
- return null;
- }
-
- @Override
- public boolean canHandleDST() {
- return true;
- }
-
- @Override
- public void timezoneOrDSTChanged(TimeChangeType changeType) {
-
- }
-
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.kt
new file mode 100644
index 0000000000..ea7b47f332
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.kt
@@ -0,0 +1,145 @@
+package info.nightscout.androidaps.plugins.pump.mdi
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.DetailedBolusInfo
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.data.PumpEnactResult
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.common.ManufacturerType
+import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.InstanceId.instanceId
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import org.json.JSONException
+import org.json.JSONObject
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class MDIPlugin @Inject constructor(
+ injector: HasAndroidInjector,
+ aapsLogger: AAPSLogger,
+ resourceHelper: ResourceHelper,
+ commandQueue: CommandQueueProvider,
+ private val treatmentsPlugin: TreatmentsPlugin
+) : PumpPluginBase(PluginDescription()
+ .mainType(PluginType.PUMP)
+ .pluginIcon(R.drawable.ic_ict)
+ .pluginName(R.string.mdi)
+ .description(R.string.description_pump_mdi),
+ injector, aapsLogger, resourceHelper, commandQueue
+), PumpInterface {
+
+ override val pumpDescription = PumpDescription()
+
+ init {
+ pumpDescription.isBolusCapable = true
+ pumpDescription.bolusStep = 0.5
+ pumpDescription.isExtendedBolusCapable = false
+ pumpDescription.isTempBasalCapable = false
+ pumpDescription.isSetBasalProfileCapable = false
+ pumpDescription.isRefillingCapable = false
+ pumpDescription.isBatteryReplaceable = false
+ }
+
+ override val isFakingTempsByExtendedBoluses: Boolean = false
+
+ override fun loadTDDs(): PumpEnactResult = PumpEnactResult(injector)
+ override fun isInitialized(): Boolean = true
+ override fun isSuspended(): Boolean = false
+ override fun isBusy(): Boolean = false
+ override fun isConnected(): Boolean = true
+ override fun isConnecting(): Boolean = false
+ override fun isHandshakeInProgress(): Boolean = false
+ override fun connect(reason: String) {}
+ override fun disconnect(reason: String) {}
+ override fun waitForDisconnectionInSeconds(): Int = 0
+ override fun stopConnecting() {}
+ override fun getPumpStatus(reason: String) {}
+ override fun setNewBasalProfile(profile: Profile): PumpEnactResult = PumpEnactResult(injector).success(true)
+ override fun isThisProfileSet(profile: Profile): Boolean = false
+ override fun lastDataTime(): Long = System.currentTimeMillis()
+ override val baseBasalRate: Double = 0.0
+ override val reservoirLevel: Double = -1.0
+ override val batteryLevel: Int = -1
+
+ override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
+ val result = PumpEnactResult(injector)
+ result.success = true
+ result.bolusDelivered = detailedBolusInfo.insulin
+ result.carbsDelivered = detailedBolusInfo.carbs
+ result.comment = resourceHelper.gs(R.string.virtualpump_resultok)
+ treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false)
+ return result
+ }
+
+ override fun stopBolusDelivering() {}
+ override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult {
+ val result = PumpEnactResult(injector)
+ result.success = false
+ result.comment = resourceHelper.gs(R.string.pumperror)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Setting temp basal absolute: $result")
+ return result
+ }
+
+ override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult {
+ val result = PumpEnactResult(injector)
+ result.success = false
+ result.comment = resourceHelper.gs(R.string.pumperror)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Settings temp basal percent: $result")
+ return result
+ }
+
+ override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
+ val result = PumpEnactResult(injector)
+ result.success = false
+ result.comment = resourceHelper.gs(R.string.pumperror)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Setting extended bolus: $result")
+ return result
+ }
+
+ override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
+ val result = PumpEnactResult(injector)
+ result.success = false
+ result.comment = resourceHelper.gs(R.string.pumperror)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Cancel temp basal: $result")
+ return result
+ }
+
+ override fun cancelExtendedBolus(): PumpEnactResult {
+ val result = PumpEnactResult(injector)
+ result.success = false
+ result.comment = resourceHelper.gs(R.string.pumperror)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Canceling extended bolus: $result")
+ return result
+ }
+
+ override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
+ val now = System.currentTimeMillis()
+ val pump = JSONObject()
+ val status = JSONObject()
+ val extended = JSONObject()
+ try {
+ status.put("status", "normal")
+ extended.put("Version", version)
+ extended.put("ActiveProfile", profileName)
+ status.put("timestamp", DateUtil.toISOString(now))
+ pump.put("status", status)
+ pump.put("extended", extended)
+ pump.put("clock", DateUtil.toISOString(now))
+ } catch (e: JSONException) {
+ aapsLogger.error("Exception: ", e)
+ }
+ return pump
+ }
+
+ override fun manufacturer(): ManufacturerType = ManufacturerType.AndroidAPS
+ override fun model(): PumpType = PumpType.MDI
+ override fun serialNumber(): String = instanceId()
+ override fun shortStatus(veryShort: Boolean): String = model().model
+ override fun canHandleDST(): Boolean = true
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt
index b6f92b6c79..bdbc298ff5 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt
@@ -15,7 +15,7 @@ import info.nightscout.androidaps.plugins.pump.virtual.events.EventVirtualPumpUp
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt
index b9af60afcf..50af5cb9f0 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt
@@ -18,24 +18,21 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.common.ManufacturerType
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.virtual.events.EventVirtualPumpUpdateGui
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
-import info.nightscout.androidaps.queue.commands.CustomCommand
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.InstanceId.instanceId
import info.nightscout.androidaps.utils.TimeChangeType
-import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
@@ -75,7 +72,7 @@ class VirtualPumpPlugin @Inject constructor(
var pumpType: PumpType? = null
private set
private var lastDataTime: Long = 0
- private val pumpDescription = PumpDescription()
+ override val pumpDescription = PumpDescription()
init {
pumpDescription.isBolusCapable = true
@@ -129,57 +126,29 @@ class VirtualPumpPlugin @Inject constructor(
uploadStatus.isVisible = !config.NSCLIENT
}
- override fun isFakingTempsByExtendedBoluses(): Boolean {
- return config.NSCLIENT && getFakingStatus()
- }
+ override val isFakingTempsByExtendedBoluses: Boolean
+ get() = config.NSCLIENT && getFakingStatus()
override fun loadTDDs(): PumpEnactResult { //no result, could read DB in the future?
return PumpEnactResult(injector)
}
- override fun getCustomActions(): List? {
- return null
- }
+ override fun isInitialized(): Boolean = true
+ override fun isSuspended(): Boolean = false
+ override fun isBusy(): Boolean = false
+ override fun isConnected(): Boolean = true
+ override fun isConnecting(): Boolean = false
+ override fun isHandshakeInProgress(): Boolean = false
- override fun executeCustomAction(customActionType: CustomActionType) {}
-
- override fun executeCustomCommand(customCommand: CustomCommand?): PumpEnactResult? {
- return null
- }
-
- override fun isInitialized(): Boolean {
- return true
- }
-
- override fun isSuspended(): Boolean {
- return false
- }
-
- override fun isBusy(): Boolean {
- return false
- }
-
- override fun isConnected(): Boolean {
- return true
- }
-
- override fun isConnecting(): Boolean {
- return false
- }
-
- override fun isHandshakeInProgress(): Boolean {
- return false
- }
-
- override fun finishHandshaking() {}
override fun connect(reason: String) {
//if (!Config.NSCLIENT) NSUpload.uploadDeviceStatus()
lastDataTime = System.currentTimeMillis()
}
+ override fun waitForDisconnectionInSeconds(): Int = 0
override fun disconnect(reason: String) {}
override fun stopConnecting() {}
- override fun getPumpStatus(reason: String?) {
+ override fun getPumpStatus(reason: String) {
lastDataTime = System.currentTimeMillis()
}
@@ -201,17 +170,14 @@ class VirtualPumpPlugin @Inject constructor(
return lastDataTime
}
- override fun getBaseBasalRate(): Double {
- return profileFunction.getProfile()?.basal ?: 0.0
- }
+ override val baseBasalRate: Double
+ get() = profileFunction.getProfile()?.basal ?: 0.0
- override fun getReservoirLevel(): Double {
- return reservoirInUnits.toDouble()
- }
+ override val reservoirLevel: Double
+ get() = reservoirInUnits.toDouble()
- override fun getBatteryLevel(): Int {
- return batteryPercent
- }
+ override val batteryLevel: Int
+ get() = batteryPercent
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
val result = PumpEnactResult(injector)
@@ -305,7 +271,7 @@ class VirtualPumpPlugin @Inject constructor(
return result
}
- override fun cancelTempBasal(force: Boolean): PumpEnactResult {
+ override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
val result = PumpEnactResult(injector)
result.success = true
result.isTempCancel = true
@@ -392,10 +358,6 @@ class VirtualPumpPlugin @Inject constructor(
return instanceId()
}
- override fun getPumpDescription(): PumpDescription {
- return pumpDescription
- }
-
override fun shortStatus(veryShort: Boolean): String {
return "Virtual Pump"
}
@@ -405,15 +367,15 @@ class VirtualPumpPlugin @Inject constructor(
}
fun refreshConfiguration() {
- val pumptype = sp.getString(R.string.key_virtualpump_type, PumpType.GenericAAPS.description)
- val pumpTypeNew = PumpType.getByDescription(pumptype)
- aapsLogger.debug(LTag.PUMP, "Pump in configuration: $pumptype, PumpType object: $pumpTypeNew")
- if (pumpType == pumpTypeNew) return
- aapsLogger.debug(LTag.PUMP, "New pump configuration found ($pumpTypeNew), changing from previous ($pumpType)")
+ val pumpType = sp.getString(R.string.key_virtualpump_type, PumpType.GenericAAPS.description)
+ val pumpTypeNew = PumpType.getByDescription(pumpType)
+ aapsLogger.debug(LTag.PUMP, "Pump in configuration: $pumpType, PumpType object: $pumpTypeNew")
+ if (this.pumpType == pumpTypeNew) return
+ aapsLogger.debug(LTag.PUMP, "New pump configuration found ($pumpTypeNew), changing from previous (${this.pumpType})")
pumpDescription.setPumpDescription(pumpTypeNew)
- pumpType = pumpTypeNew
+ this.pumpType = pumpTypeNew
}
- override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType?) {}
+ override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.java
index 500518a419..55e61bb5c6 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.java
@@ -24,13 +24,12 @@ import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
+import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.interfaces.ProfileFunction;
-import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
@@ -161,7 +160,7 @@ public class SensitivityAAPSPlugin extends AbstractSensitivityPlugin {
Arrays.sort(deviations);
- double percentile = IobCobCalculatorPlugin.percentile(deviations, 0.50);
+ double percentile = IobCobCalculatorPlugin.Companion.percentile(deviations, 0.50);
double basalOff = percentile * (60.0 / 5.0) / sens;
double ratio = 1 + (basalOff / profile.getMaxDailyBasal());
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.java
index 233cd675d0..fbc1baa5e1 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.java
@@ -207,8 +207,8 @@ public class SensitivityOref1Plugin extends AbstractSensitivityPlugin {
getAapsLogger().debug(LTag.AUTOSENS, "Records: " + index + " " + pastSensitivity);
Arrays.sort(deviations);
- double pSensitive = IobCobCalculatorPlugin.percentile(deviations, 0.50);
- double pResistant = IobCobCalculatorPlugin.percentile(deviations, 0.50);
+ double pSensitive = IobCobCalculatorPlugin.Companion.percentile(deviations, 0.50);
+ double pResistant = IobCobCalculatorPlugin.Companion.percentile(deviations, 0.50);
double basalOff = 0;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt
index 84999eb388..07038a50e5 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt
@@ -17,6 +17,7 @@ import info.nightscout.androidaps.databinding.BgsourceItemBinding
import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
@@ -42,6 +43,7 @@ class BGSourceFragment : DaggerFragment() {
@Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var repository: AppRepository
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable()
private val millsToThePast = T.hours(12).msecs()
@@ -126,6 +128,7 @@ class BGSourceFragment : DaggerFragment() {
activity?.let { activity ->
val text = dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits())
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
+ uel.log("BG REMOVED", dateUtil.dateAndTimeString(glucoseValue.timestamp))
disposable += repository.runTransaction(InvalidateGlucoseValueTransaction(glucoseValue.id)).subscribe()
})
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/CarbsGenerator.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/CarbsGenerator.kt
index 8dc1fc859d..4ac7446474 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/CarbsGenerator.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/CarbsGenerator.kt
@@ -1,7 +1,6 @@
package info.nightscout.androidaps.plugins.treatments
import android.content.Context
-import android.content.Intent
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo
@@ -47,12 +46,7 @@ class CarbsGenerator @Inject constructor(
commandQueue.bolus(carbInfo, object : Callback() {
override fun run() {
if (!result.success) {
- val i = Intent(context, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- context.startActivity(i)
+ ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
}
}
})
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java
index 49d1070b7d..a4f85e3882 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java
@@ -16,6 +16,7 @@ import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
@@ -39,6 +40,8 @@ import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.events.EventReloadTreatmentData;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
+import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
+import info.nightscout.androidaps.interfaces.UpdateReturn;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@@ -57,7 +60,7 @@ import io.reactivex.disposables.CompositeDisposable;
* Created by mike on 24.09.2017.
*/
-public class TreatmentService extends OrmLiteBaseService {
+public class TreatmentService extends OrmLiteBaseService implements TreatmentServiceInterface {
@Inject AAPSLogger aapsLogger;
@Inject FabricPrivacy fabricPrivacy;
@@ -471,7 +474,7 @@ public class TreatmentService extends OrmLiteBaseService {
}
- public UpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) {
+ @NotNull public UpdateReturn createOrUpdateMedtronic(@NotNull Treatment treatment, boolean fromNightScout) {
if (MedtronicHistoryData.doubleBolusDebug)
aapsLogger.debug(LTag.DATATREATMENTS, "DoubleBolusDebug: createOrUpdateMedtronic:: originalTreatment={}, fromNightScout={}", treatment, fromNightScout);
@@ -821,22 +824,4 @@ public class TreatmentService extends OrmLiteBaseService {
return null;
}
- public class UpdateReturn {
- public UpdateReturn(boolean success, boolean newRecord) {
- this.success = success;
- this.newRecord = newRecord;
- }
-
- boolean newRecord;
- boolean success;
-
- @Override
- public String toString() {
- return "UpdateReturn [" +
- "newRecord=" + newRecord +
- ", success=" + success +
- ']';
- }
- }
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt
index b3e48679cb..3855202408 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt
@@ -14,7 +14,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.treatments.fragments.*
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.extensions.plusAssign
+import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
@@ -68,6 +68,10 @@ class TreatmentsFragment : DaggerFragment() {
setFragment(TreatmentsCareportalFragment())
setBackgroundColorOnSelected(it)
}
+ binding.userentry.setOnClickListener {
+ setFragment(TreatmentsUserEntryFragment())
+ setBackgroundColorOnSelected(it)
+ }
setFragment(TreatmentsBolusFragment())
setBackgroundColorOnSelected(binding.treatments)
}
@@ -109,6 +113,7 @@ class TreatmentsFragment : DaggerFragment() {
binding.tempTargets.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
binding.profileSwitches.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
binding.careportal.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
+ binding.userentry.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
selected.setBackgroundColor(resourceHelper.gc(R.color.tabBgColorSelected))
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java
index b1a02ce819..41e3673493 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java
@@ -1,7 +1,6 @@
package info.nightscout.androidaps.plugins.treatments;
import android.content.Context;
-import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
@@ -47,7 +46,9 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.ProfileStore;
import info.nightscout.androidaps.interfaces.PumpInterface;
+import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
+import info.nightscout.androidaps.interfaces.UpdateReturn;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@@ -83,7 +84,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
private final CompositeDisposable disposable = new CompositeDisposable();
- protected TreatmentService service;
+ protected TreatmentServiceInterface service;
private IobTotal lastTreatmentCalculation;
private IobTotal lastTempBasalsCalculation;
@@ -181,7 +182,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
super.onStop();
}
- public TreatmentService getService() {
+ @Override
+ public TreatmentServiceInterface getService() {
return this.service;
}
@@ -621,9 +623,9 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
public TreatmentUpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) {
- TreatmentService.UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout);
+ UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout);
- return new TreatmentUpdateReturn(resultRecord.success, resultRecord.newRecord);
+ return new TreatmentUpdateReturn(resultRecord.getSuccess(), resultRecord.getNewRecord());
}
// return true if new record is created
@@ -644,7 +646,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
treatment.carbs = detailedBolusInfo.carbs;
treatment.mealBolus = treatment.carbs > 0;
treatment.boluscalc = detailedBolusInfo.boluscalc != null ? detailedBolusInfo.boluscalc.toString() : null;
- TreatmentService.UpdateReturn creatOrUpdateResult;
+ UpdateReturn creatOrUpdateResult;
getAapsLogger().debug(medtronicPump && MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::treatment={} " + treatment);
@@ -653,7 +655,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
else
creatOrUpdateResult = getService().createOrUpdateMedtronic(treatment, false);
- boolean newRecordCreated = creatOrUpdateResult.newRecord;
+ boolean newRecordCreated = creatOrUpdateResult.getNewRecord();
//log.debug("Adding new Treatment record" + treatment.toString());
if (detailedBolusInfo.carbTime != 0) {
@@ -674,17 +676,12 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
if (newRecordCreated && detailedBolusInfo.isValid)
nsUpload.uploadTreatmentRecord(detailedBolusInfo);
- if (!allowUpdate && !creatOrUpdateResult.success) {
+ if (!allowUpdate && !creatOrUpdateResult.getSuccess()) {
getAapsLogger().error("Treatment could not be added to DB", new Exception());
String status = String.format(resourceHelper.gs(R.string.error_adding_treatment_message), treatment.insulin, (int) treatment.carbs, dateUtil.dateAndTimeString(treatment.date));
- Intent i = new Intent(context, ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.error);
- i.putExtra("title", resourceHelper.gs(R.string.error_adding_treatment_title));
- i.putExtra("status", status);
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(i);
+ ErrorHelperActivity.Companion.runAlarm(context, status, resourceHelper.gs(R.string.error_adding_treatment_title), R.raw.error);
Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.ITEM_LIST_ID, "TreatmentClash");
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt
index 7c7c6dd579..d830ca5414 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt
@@ -16,6 +16,7 @@ import info.nightscout.androidaps.db.Treatment
import info.nightscout.androidaps.dialogs.WizardInfoDialog
import info.nightscout.androidaps.events.EventTreatmentChange
import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
@@ -48,6 +49,7 @@ class TreatmentsBolusFragment : DaggerFragment() {
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private var _binding: TreatmentsBolusFragmentBinding? = null
@@ -66,6 +68,7 @@ class TreatmentsBolusFragment : DaggerFragment() {
binding.refreshFromNightscout.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.refresheventsfromnightscout) + "?") {
+ uel.log("TREAT NS REFRESH")
treatmentsPlugin.service.resetTreatments()
rxBus.send(EventNSClientRestart())
}
@@ -74,6 +77,7 @@ class TreatmentsBolusFragment : DaggerFragment() {
binding.deleteFutureTreatments.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), resourceHelper.gs(R.string.deletefuturetreatments) + "?", Runnable {
+ uel.log("DELETE FUTURE TREATMENTS")
val futureTreatments = treatmentsPlugin.service.getTreatmentDataFromTime(DateUtil.now() + 1000, true)
for (treatment in futureTreatments) {
if (NSUpload.isIdValid(treatment._id))
@@ -170,6 +174,7 @@ class TreatmentsBolusFragment : DaggerFragment() {
resourceHelper.gs(R.string.carbs) + ": " + resourceHelper.gs(R.string.format_carbs, treatment.carbs.toInt()) + "\n" +
resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(treatment.date)
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
+ uel.log("REMOVED TREATMENT", text)
if (treatment.source == Source.PUMP) {
treatment.isValid = false
treatmentsPlugin.service.update(treatment)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt
index 54fc2f592d..58269316be 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt
@@ -14,6 +14,7 @@ import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBindin
import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.events.EventCareportalEventChange
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
@@ -44,6 +45,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private var _binding: TreatmentsCareportalFragmentBinding? = null
@@ -62,6 +64,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
binding.refreshFromNightscout.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", Runnable {
+ uel.log("CAREPORTAL NS REFRESH")
MainApp.getDbHelper().resetCareportalEvents()
rxBus.send(EventNSClientRestart())
})
@@ -70,6 +73,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
binding.removeAndroidapsStartedEvents.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.careportal_removestartedevents), Runnable {
+ uel.log("REMOVED RESTART EVENTS")
val events = MainApp.getDbHelper().getCareportalEvents(false)
for (i in events.indices) {
val careportalEvent = events[i]
@@ -150,6 +154,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + careportalEvent.notes + "\n" +
resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(careportalEvent.date)
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
+ uel.log("REMOVED CAREP", text)
if (NSUpload.isIdValid(careportalEvent._id))
nsUpload.removeCareportalEntryFromNS(careportalEvent._id)
else
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt
index f3a47b88ce..e223fd150a 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt
@@ -20,6 +20,7 @@ import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.events.EventExtendedBolusChange
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
@@ -27,7 +28,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutos
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
@@ -46,6 +47,7 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private var _binding: TreatmentsExtendedbolusFragmentBinding? = null
@@ -114,16 +116,17 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
binding.remove.setOnClickListener { v: View ->
val extendedBolus = v.tag as ExtendedBolus
context?.let {
- showConfirmation(it, resourceHelper.gs(R.string.removerecord),
+ OKDialog.showConfirmation(it, resourceHelper.gs(R.string.removerecord),
"""
${resourceHelper.gs(R.string.extended_bolus)}
${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(extendedBolus.date)}
- """.trimIndent(), DialogInterface.OnClickListener { _: DialogInterface, _: Int ->
+ """.trimIndent(), { _: DialogInterface, _: Int ->
+ uel.log("REMOVED EB")
val id = extendedBolus._id
- if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
- else uploadQueue.removeID("dbAdd", id)
- MainApp.getDbHelper().delete(extendedBolus)
- }, null)
+ if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
+ else uploadQueue.removeID("dbAdd", id)
+ MainApp.getDbHelper().delete(extendedBolus)
+ }, null)
}
}
binding.remove.paintFlags = binding.remove.paintFlags or Paint.UNDERLINE_TEXT_FLAG
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt
index 2ab82a8a36..1d7ba6041d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt
@@ -16,6 +16,7 @@ import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.events.EventProfileNeedsUpdate
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
@@ -49,6 +50,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private var _binding: TreatmentsProfileswitchFragmentBinding? = null
@@ -67,6 +69,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
binding.refreshFromNightscout.setOnClickListener {
activity?.let { activity ->
+ uel.log("PROFILE SWITCH NS REFRESH")
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.refresheventsfromnightscout) + "?") {
MainApp.getDbHelper().resetProfileSwitch()
rxBus.send(EventNSClientRestart())
@@ -143,6 +146,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord),
resourceHelper.gs(R.string.careportal_profileswitch) + ": " + profileSwitch.profileName +
"\n" + resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(profileSwitch.date), Runnable {
+ uel.log("REMOVED PROFILE SWITCH", profileSwitch.profileName + " " + dateUtil.dateAndTimeString(profileSwitch.date))
val id = profileSwitch._id
if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
else uploadQueue.removeID("dbAdd", id)
@@ -155,6 +159,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
val profileSwitch = it.tag as ProfileSwitch
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), resourceHelper.gs(R.string.copytolocalprofile) + "\n" + profileSwitch.customizedName + "\n" + dateUtil.dateAndTimeString(profileSwitch.date), Runnable {
profileSwitch.profileObject?.let {
+ uel.log("PROFILE SWITCH CLONE", profileSwitch.profileName + " " + dateUtil.dateAndTimeString(profileSwitch.date))
val nonCustomized = it.convertToNonCustomizedProfile()
if (nonCustomized.isValid(resourceHelper.gs(R.string.careportal_profileswitch, false))) {
localProfilePlugin.addProfile(localProfilePlugin.copyFrom(nonCustomized, profileSwitch.customizedName + " " + dateUtil.dateAndTimeString(profileSwitch.date).replace(".", "_")))
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt
index 9b41d72243..3265275e36 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt
@@ -20,6 +20,7 @@ import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.events.EventTempTargetChange
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
@@ -27,7 +28,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
@@ -48,6 +49,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable()
@@ -66,7 +68,8 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
binding.recyclerview.adapter = RecyclerViewAdapter(activePlugin.activeTreatments.tempTargetsFromHistory)
binding.refreshFromNightscout.setOnClickListener {
context?.let { context ->
- showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", {
+ OKDialog.showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", {
+ uel.log("TT NS REFRESH")
MainApp.getDbHelper().resetTempTargets()
rxBus.send(EventNSClientRestart())
})
@@ -152,12 +155,13 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
binding.remove.setOnClickListener { v: View ->
val tempTarget = v.tag as TempTarget
context?.let { context ->
- showConfirmation(context, resourceHelper.gs(R.string.removerecord),
+ OKDialog.showConfirmation(context, resourceHelper.gs(R.string.removerecord),
"""
${resourceHelper.gs(R.string.careportal_temporarytarget)}: ${tempTarget.friendlyDescription(profileFunction.getUnits(), resourceHelper)}
${dateUtil.dateAndTimeString(tempTarget.date)}
""".trimIndent(),
{ _: DialogInterface?, _: Int ->
+ uel.log("TT REMOVE", tempTarget.friendlyDescription(profileFunction.getUnits(), resourceHelper))
val id = tempTarget._id
if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
else uploadQueue.removeID("dbAdd", id)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt
index 82c500db21..b17933471c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt
@@ -19,13 +19,14 @@ import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.events.EventTempBasalChange
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
@@ -42,6 +43,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private var _binding: TreatmentsTempbasalsFragmentBinding? = null
@@ -155,12 +157,13 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
binding.remove.setOnClickListener { v: View ->
val tempBasal = v.tag as TemporaryBasal
context?.let {
- showConfirmation(it, resourceHelper.gs(R.string.removerecord),
+ OKDialog.showConfirmation(it, resourceHelper.gs(R.string.removerecord),
"""
${resourceHelper.gs(R.string.tempbasal_label)}: ${tempBasal.toStringFull()}
${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(tempBasal.date)}
""".trimIndent(),
- DialogInterface.OnClickListener { _: DialogInterface?, _: Int ->
+ { _: DialogInterface?, _: Int ->
+ uel.log("REMOVED TT", dateUtil.dateAndTimeString(tempBasal.date))
activePlugin.activeTreatments.removeTempBasal(tempBasal)
}, null)
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt
new file mode 100644
index 0000000000..0e4f7cc200
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt
@@ -0,0 +1,82 @@
+package info.nightscout.androidaps.plugins.treatments.fragments
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import dagger.android.support.DaggerFragment
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.entities.UserEntry
+import info.nightscout.androidaps.databinding.TreatmentsUserEntryFragmentBinding
+import info.nightscout.androidaps.databinding.TreatmentsUserEntryItemBinding
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.rx.AapsSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
+import javax.inject.Inject
+
+class TreatmentsUserEntryFragment : DaggerFragment() {
+
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var dateUtil: DateUtil
+
+ private val disposable = CompositeDisposable()
+
+ private var _binding: TreatmentsUserEntryFragmentBinding? = null
+
+ // This property is only valid between onCreateView and
+ // onDestroyView.
+ private val binding get() = _binding!!
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ TreatmentsUserEntryFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.recyclerview.setHasFixedSize(true)
+ binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
+
+ disposable += repository
+ .getAllUserEntries()
+ .observeOn(aapsSchedulers.main)
+ .subscribe { list -> binding.recyclerview.swapAdapter(UserEntryAdapter(list), true) }
+ }
+
+ @Synchronized
+ override fun onDestroyView() {
+ super.onDestroyView()
+ disposable.clear()
+ _binding = null
+ }
+
+ inner class UserEntryAdapter internal constructor(var entries: List) : RecyclerView.Adapter() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserEntryViewHolder {
+ val view: View = LayoutInflater.from(parent.context).inflate(R.layout.treatments_user_entry_item, parent, false)
+ return UserEntryViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: UserEntryViewHolder, position: Int) {
+ val current = entries[position]
+ holder.binding.date.text = dateUtil.dateAndTimeAndSecondsString(current.timestamp)
+ holder.binding.action.text = current.action
+ if (current.s != "") holder.binding.s.text = current.s else holder.binding.s.visibility = View.GONE
+ if (current.d1 != 0.0) holder.binding.d1.text = current.d1.toString() else holder.binding.d1.visibility = View.GONE
+ if (current.d2 != 0.0) holder.binding.d2.text = current.d2.toString() else holder.binding.d2.visibility = View.GONE
+ if (current.i1 != 0) holder.binding.i1.text = current.i1.toString() else holder.binding.i1.visibility = View.GONE
+ if (current.i2 != 0) holder.binding.i2.text = current.i2.toString() else holder.binding.i2.visibility = View.GONE
+ }
+
+ inner class UserEntryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ val binding = TreatmentsUserEntryItemBinding.bind(itemView)
+ }
+
+ override fun getItemCount(): Int = entries.size
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt
index a94806bd5e..20ffdf8425 100644
--- a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt
+++ b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt
@@ -84,7 +84,7 @@ import javax.inject.Singleton
*/
@Singleton
-class CommandQueue @Inject constructor(
+open class CommandQueue @Inject constructor(
private val injector: HasAndroidInjector,
private val aapsLogger: AAPSLogger,
private val rxBus: RxBusWrapper,
@@ -116,12 +116,7 @@ class CommandQueue @Inject constructor(
setProfile(it, object : Callback() {
override fun run() {
if (!result.success) {
- val i = Intent(context, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.failedupdatebasalprofile))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- context.startActivity(i)
+ ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.failedupdatebasalprofile), R.raw.boluserror)
}
if (result.enacted) rxBus.send(EventNewBasalProfile())
}
@@ -150,7 +145,7 @@ class CommandQueue @Inject constructor(
@Suppress("SameParameterValue")
@Synchronized
- private fun isLastScheduled(type: CommandType): Boolean {
+ fun isLastScheduled(type: CommandType): Boolean {
synchronized(queue) {
if (queue.size > 0 && queue[queue.size - 1].commandType == type) {
return true
@@ -192,11 +187,8 @@ class CommandQueue @Inject constructor(
// After new command added to the queue
// start thread again if not already running
@Synchronized
- private fun notifyAboutNewCommand() {
- while (thread != null && thread!!.state != Thread.State.TERMINATED && thread!!.waitingForDisconnect) {
- aapsLogger.debug(LTag.PUMPQUEUE, "Waiting for previous thread finish")
- SystemClock.sleep(500)
- }
+ open fun notifyAboutNewCommand() {
+ waitForFinishedThread()
if (thread == null || thread!!.state == Thread.State.TERMINATED) {
thread = QueueThread(this, context, aapsLogger, rxBus, activePlugin.get(), resourceHelper, sp)
thread!!.start()
@@ -206,6 +198,15 @@ class CommandQueue @Inject constructor(
}
}
+ fun waitForFinishedThread() {
+ thread?.let { thread ->
+ while (thread.state != Thread.State.TERMINATED && thread.waitingForDisconnect) {
+ aapsLogger.debug(LTag.PUMPQUEUE, "Waiting for previous thread finish")
+ SystemClock.sleep(500)
+ }
+ }
+ }
+
override fun independentConnect(reason: String, callback: Callback?) {
aapsLogger.debug(LTag.PUMPQUEUE, "Starting new queue")
val tempCommandQueue = CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, activePlugin, context, sp, buildHelper, fabricPrivacy)
@@ -459,12 +460,12 @@ class CommandQueue @Inject constructor(
// returns true if command is queued
override fun loadTDDs(callback: Callback?): Boolean {
- if (isRunning(CommandType.LOAD_HISTORY)) {
+ if (isRunning(CommandType.LOAD_TDD)) {
callback?.result(executingNowError())?.run()
return false
}
// remove all unfinished
- removeAll(CommandType.LOAD_HISTORY)
+ removeAll(CommandType.LOAD_TDD)
// add new command to queue
add(CommandLoadTDDs(injector, callback))
notifyAboutNewCommand()
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java
deleted file mode 100644
index 9dbd2c3ef4..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package info.nightscout.androidaps.queue;
-
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.os.PowerManager;
-import android.os.SystemClock;
-
-import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.events.EventPumpStatusChanged;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning;
-import info.nightscout.androidaps.queue.events.EventQueueChanged;
-import info.nightscout.androidaps.utils.T;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-/**
- * Created by mike on 09.11.2017.
- */
-
-public class QueueThread extends Thread {
- private final CommandQueue queue;
- private final AAPSLogger aapsLogger;
- private final RxBusWrapper rxBus;
- private final ActivePluginProvider activePlugin;
- private final ResourceHelper resourceHelper;
- private final SP sp;
-
- private boolean connectLogged = false;
- boolean waitingForDisconnect = false;
-
- private PowerManager.WakeLock mWakeLock;
-
- QueueThread(CommandQueue queue, Context context, AAPSLogger aapsLogger, RxBusWrapper rxBus, ActivePluginProvider activePlugin, ResourceHelper resourceHelper, SP sp) {
- super();
-
- this.queue = queue;
- this.aapsLogger = aapsLogger;
- this.rxBus = rxBus;
- this.activePlugin = activePlugin;
- this.resourceHelper = resourceHelper;
- this.sp = sp;
-
- PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- if (powerManager != null)
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:QueueThread");
- }
-
- @Override
- public final void run() {
- if (mWakeLock != null)
- mWakeLock.acquire(T.mins(10).msecs());
- rxBus.send(new EventQueueChanged());
- long lastCommandTime;
- long connectionStartTime = lastCommandTime = System.currentTimeMillis();
-
- try {
- while (true) {
- long secondsElapsed = (System.currentTimeMillis() - connectionStartTime) / 1000;
- PumpInterface pump = activePlugin.getActivePump();
- if (!pump.isConnected() && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) {
- rxBus.send(new EventDismissBolusProgressIfRunning(null));
- rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.connectiontimedout)));
- aapsLogger.debug(LTag.PUMPQUEUE, "timed out");
- pump.stopConnecting();
-
- //BLUETOOTH-WATCHDOG
- boolean watchdog = sp.getBoolean(R.string.key_btwatchdog, false);
- long last_watchdog = sp.getLong(R.string.key_btwatchdog_lastbark, 0L);
- watchdog = watchdog && System.currentTimeMillis() - last_watchdog > (Constants.MIN_WATCHDOG_INTERVAL_IN_SECONDS * 1000);
- if (watchdog) {
- aapsLogger.debug(LTag.PUMPQUEUE, "BT watchdog - toggeling the phonest bluetooth");
- //write time
- sp.putLong(R.string.key_btwatchdog_lastbark, System.currentTimeMillis());
- //toggle BT
- pump.stopConnecting();
- pump.disconnect("watchdog");
- SystemClock.sleep(1000);
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if (bluetoothAdapter != null) {
- bluetoothAdapter.disable();
- SystemClock.sleep(1000);
- bluetoothAdapter.enable();
- SystemClock.sleep(1000);
- }
- //start over again once after watchdog barked
- //Notification notification = new Notification(Notification.OLD_NSCLIENT, "Watchdog", Notification.URGENT);
- //rxBus.send(new EventNewNotification(notification));
- connectionStartTime = lastCommandTime = System.currentTimeMillis();
- pump.connect("watchdog");
- } else {
- queue.clear();
- aapsLogger.debug(LTag.PUMPQUEUE, "no connection possible");
- rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING));
- pump.disconnect("Queue empty");
- rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED));
- return;
- }
- }
-
- if (pump.isHandshakeInProgress()) {
- aapsLogger.debug(LTag.PUMPQUEUE, "handshaking " + secondsElapsed);
- rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.HANDSHAKING, (int) secondsElapsed));
- SystemClock.sleep(100);
- continue;
- }
-
- if (pump.isConnecting()) {
- aapsLogger.debug(LTag.PUMPQUEUE, "connecting " + secondsElapsed);
- rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, (int) secondsElapsed));
- SystemClock.sleep(1000);
- continue;
- }
-
- if (!pump.isConnected()) {
- aapsLogger.debug(LTag.PUMPQUEUE, "connect");
- rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, (int) secondsElapsed));
- pump.connect("Connection needed");
- SystemClock.sleep(1000);
- continue;
- }
-
- if (queue.performing() == null) {
- if (!connectLogged) {
- connectLogged = true;
- aapsLogger.debug(LTag.PUMPQUEUE, "connection time " + secondsElapsed + "s");
- }
- // Pickup 1st command and set performing variable
- if (queue.size() > 0) {
- queue.pickup();
- if (queue.performing() != null) {
- aapsLogger.debug(LTag.PUMPQUEUE, "performing " + queue.performing().status());
- rxBus.send(new EventQueueChanged());
- queue.performing().execute();
- queue.resetPerforming();
- rxBus.send(new EventQueueChanged());
- lastCommandTime = System.currentTimeMillis();
- SystemClock.sleep(100);
- continue;
- }
- }
- }
-
- if (queue.size() == 0 && queue.performing() == null) {
- long secondsFromLastCommand = (System.currentTimeMillis() - lastCommandTime) / 1000;
- if (secondsFromLastCommand >= 5) {
- waitingForDisconnect = true;
- aapsLogger.debug(LTag.PUMPQUEUE, "queue empty. disconnect");
- rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING));
- pump.disconnect("Queue empty");
- rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED));
- aapsLogger.debug(LTag.PUMPQUEUE, "disconnected");
- return;
- } else {
- aapsLogger.debug(LTag.PUMPQUEUE, "waiting for disconnect");
- SystemClock.sleep(1000);
- }
- }
- }
- } finally {
- if (mWakeLock != null && mWakeLock.isHeld())
- mWakeLock.release();
- aapsLogger.debug(LTag.PUMPQUEUE, "thread end");
- }
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt
new file mode 100644
index 0000000000..c1b4fa7aa5
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt
@@ -0,0 +1,148 @@
+package info.nightscout.androidaps.queue
+
+import android.bluetooth.BluetoothAdapter
+import android.content.Context
+import android.os.PowerManager
+import android.os.SystemClock
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.events.EventPumpStatusChanged
+import info.nightscout.androidaps.interfaces.ActivePluginProvider
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
+import info.nightscout.androidaps.queue.events.EventQueueChanged
+import info.nightscout.androidaps.utils.T
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+
+class QueueThread internal constructor(
+ private val queue: CommandQueue,
+ context: Context,
+ private val aapsLogger: AAPSLogger,
+ private val rxBus: RxBusWrapper,
+ private val activePlugin: ActivePluginProvider,
+ private val resourceHelper: ResourceHelper,
+ private val sp: SP
+) : Thread() {
+
+ private var connectLogged = false
+ var waitingForDisconnect = false
+ private var mWakeLock: PowerManager.WakeLock? = null
+
+ init {
+ mWakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, resourceHelper.gs(R.string.app_name) + ":QueueThread")
+ }
+
+ override fun run() {
+ mWakeLock?.acquire(T.mins(10).msecs())
+ rxBus.send(EventQueueChanged())
+ var lastCommandTime: Long
+ lastCommandTime = System.currentTimeMillis()
+ var connectionStartTime = lastCommandTime
+ try {
+ while (true) {
+ val secondsElapsed = (System.currentTimeMillis() - connectionStartTime) / 1000
+ val pump = activePlugin.activePump
+ if (!pump.isConnected() && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) {
+ rxBus.send(EventDismissBolusProgressIfRunning(null))
+ rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.connectiontimedout)))
+ aapsLogger.debug(LTag.PUMPQUEUE, "timed out")
+ pump.stopConnecting()
+
+ //BLUETOOTH-WATCHDOG
+ var watchdog = sp.getBoolean(R.string.key_btwatchdog, false)
+ val lastWatchdog = sp.getLong(R.string.key_btwatchdog_lastbark, 0L)
+ watchdog = watchdog && System.currentTimeMillis() - lastWatchdog > Constants.MIN_WATCHDOG_INTERVAL_IN_SECONDS * 1000
+ if (watchdog) {
+ aapsLogger.debug(LTag.PUMPQUEUE, "BT watchdog - toggling the phone bluetooth")
+ //write time
+ sp.putLong(R.string.key_btwatchdog_lastbark, System.currentTimeMillis())
+ //toggle BT
+ pump.stopConnecting()
+ pump.disconnect("watchdog")
+ SystemClock.sleep(1000)
+ val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
+ if (bluetoothAdapter != null) {
+ bluetoothAdapter.disable()
+ SystemClock.sleep(1000)
+ bluetoothAdapter.enable()
+ SystemClock.sleep(1000)
+ }
+ //start over again once after watchdog barked
+ //Notification notification = new Notification(Notification.OLD_NSCLIENT, "Watchdog", Notification.URGENT);
+ //rxBus.send(new EventNewNotification(notification));
+ lastCommandTime = System.currentTimeMillis()
+ connectionStartTime = lastCommandTime
+ pump.connect("watchdog")
+ } else {
+ queue.clear()
+ aapsLogger.debug(LTag.PUMPQUEUE, "no connection possible")
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
+ pump.disconnect("Queue empty")
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
+ return
+ }
+ }
+ if (pump.isHandshakeInProgress()) {
+ aapsLogger.debug(LTag.PUMPQUEUE, "handshaking $secondsElapsed")
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.HANDSHAKING, secondsElapsed.toInt()))
+ SystemClock.sleep(100)
+ continue
+ }
+ if (pump.isConnecting()) {
+ aapsLogger.debug(LTag.PUMPQUEUE, "connecting $secondsElapsed")
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, secondsElapsed.toInt()))
+ SystemClock.sleep(1000)
+ continue
+ }
+ if (!pump.isConnected()) {
+ aapsLogger.debug(LTag.PUMPQUEUE, "connect")
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, secondsElapsed.toInt()))
+ pump.connect("Connection needed")
+ SystemClock.sleep(1000)
+ continue
+ }
+ if (queue.performing() == null) {
+ if (!connectLogged) {
+ connectLogged = true
+ aapsLogger.debug(LTag.PUMPQUEUE, "connection time " + secondsElapsed + "s")
+ }
+ // Pickup 1st command and set performing variable
+ if (queue.size() > 0) {
+ queue.pickup()
+ if (queue.performing() != null) {
+ aapsLogger.debug(LTag.PUMPQUEUE, "performing " + queue.performing()?.status())
+ rxBus.send(EventQueueChanged())
+ queue.performing()?.execute()
+ queue.resetPerforming()
+ rxBus.send(EventQueueChanged())
+ lastCommandTime = System.currentTimeMillis()
+ SystemClock.sleep(100)
+ continue
+ }
+ }
+ }
+ if (queue.size() == 0 && queue.performing() == null) {
+ val secondsFromLastCommand = (System.currentTimeMillis() - lastCommandTime) / 1000
+ if (secondsFromLastCommand >= pump.waitForDisconnectionInSeconds()) {
+ waitingForDisconnect = true
+ aapsLogger.debug(LTag.PUMPQUEUE, "queue empty. disconnect")
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
+ pump.disconnect("Queue empty")
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
+ aapsLogger.debug(LTag.PUMPQUEUE, "disconnected")
+ return
+ } else {
+ aapsLogger.debug(LTag.PUMPQUEUE, "waiting for disconnect")
+ SystemClock.sleep(1000)
+ }
+ }
+ }
+ } finally {
+ if (mWakeLock?.isHeld == true) mWakeLock?.release()
+ aapsLogger.debug(LTag.PUMPQUEUE, "thread end")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt
index 96f1834c35..9bf4a1ab7d 100644
--- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt
+++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt
@@ -9,7 +9,7 @@ import javax.inject.Inject
class CommandLoadTDDs(
injector: HasAndroidInjector,
callback: Callback?
-) : Command(injector, CommandType.LOAD_HISTORY, callback) {
+) : Command(injector, CommandType.LOAD_TDD, callback) {
@Inject lateinit var activePlugin: ActivePluginProvider
diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt
index 2c5fd55041..8bfdbb73b7 100644
--- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt
+++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt
@@ -14,7 +14,7 @@ class CommandTempBasalPercent(
private val enforceNew: Boolean,
private val profile: Profile,
callback: Callback?
-) : Command(injector, CommandType.BASAL_PROFILE, callback) {
+) : Command(injector, CommandType.TEMPBASAL, callback) {
@Inject lateinit var activePlugin: ActivePluginProvider
diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt
index e764f35b2d..3d4d04dbf7 100644
--- a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt
+++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt
@@ -61,9 +61,7 @@ open class DataReceiver : DaggerBroadcastReceiver() {
}.build()).build()
Intents.ACTION_NEW_PROFILE ->
OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker::class.java)
- .setInputData(Data.Builder().also {
- it.copyString("profile", bundle, null)
- }.build()).build()
+ .setInputData(bundleInputData(bundle, intent)).build()
Intents.ACTION_NEW_SGV ->
OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker::class.java)
.setInputData(Data.Builder().also {
diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt
index d97ab4f7a9..eb20d8acb4 100644
--- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt
+++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt
@@ -29,6 +29,7 @@ import javax.inject.Inject
import kotlin.math.abs
class KeepAliveReceiver : DaggerBroadcastReceiver() {
+
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var activePlugin: ActivePluginProvider
@@ -44,6 +45,7 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
@Inject lateinit var dateUtil: DateUtil
companion object {
+
private val KEEP_ALIVE_MILLISECONDS = T.mins(5).msecs()
private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs()
private val IOB_UPDATE_FREQUENCY_IN_MINS = 5L
@@ -128,10 +130,10 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
}
if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) {
rxBus.send(EventProfileNeedsUpdate())
- } else if (isStatusOutdated && !pump.isBusy) {
+ } else if (isStatusOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Status outdated.", null)
- } else if (isBasalOutdated && !pump.isBusy) {
+ } else if (isBasalOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Basal outdated.", null)
}
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt
index 0cc0a8c9e6..55ed268dfe 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt
@@ -74,11 +74,11 @@ class SWDefinition @Inject constructor(
}
private val screenSetupWizard = SWScreen(injector, R.string.nav_setupwizard)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.welcometosetupwizard))
private val screenEula = SWScreen(injector, R.string.end_user_license_agreement)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.end_user_license_agreement_text))
.add(SWBreak(injector))
.add(SWButton(injector)
@@ -112,7 +112,7 @@ class SWDefinition @Inject constructor(
.comment(R.string.high_mark_comment))
private val screenPermissionBattery = SWScreen(injector, R.string.permission)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(resourceHelper.gs(R.string.needwhitelisting, resourceHelper.gs(R.string.app_name))))
.add(SWBreak(injector))
.add(SWButton(injector)
@@ -123,7 +123,7 @@ class SWDefinition @Inject constructor(
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) }
private val screenPermissionBt = SWScreen(injector, R.string.permission)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(resourceHelper.gs(R.string.needlocationpermission)))
.add(SWBreak(injector))
.add(SWButton(injector)
@@ -134,7 +134,7 @@ class SWDefinition @Inject constructor(
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) }
private val screenPermissionStore = SWScreen(injector, R.string.permission)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(resourceHelper.gs(R.string.needstoragepermission)))
.add(SWBreak(injector))
.add(SWButton(injector)
@@ -144,7 +144,7 @@ class SWDefinition @Inject constructor(
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
private val screenImport = SWScreen(injector, R.string.nav_import)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.storedsettingsfound))
.add(SWBreak(injector))
.add(SWButton(injector)
@@ -153,7 +153,7 @@ class SWDefinition @Inject constructor(
.visibility { importExportPrefs.prefsFileExists() && !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
private val screenNsClient = SWScreen(injector, R.string.nsclientinternal_title)
.skippable(true)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.nsclientinfotext))
.add(SWBreak(injector))
.add(SWButton(injector)
@@ -183,19 +183,19 @@ class SWDefinition @Inject constructor(
.visibility { !(nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth) }
private val screenPatientName = SWScreen(injector, R.string.patient_name)
.skippable(true)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.patient_name_summary))
.add(SWEditString(injector)
.validator(SWTextValidator(String::isNotEmpty))
.preferenceId(R.string.key_patient_name))
private val screenMasterPassword = SWScreen(injector, R.string.master_password)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.master_password))
.add(SWEditEncryptedPassword(injector, cryptoUtil)
.preferenceId(R.string.key_master_password))
.add(SWBreak(injector))
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.master_password_summary))
.validator { !cryptoUtil.checkPassword("", sp.getString(R.string.key_master_password, "")) }
private val screenAge = SWScreen(injector, R.string.patientage)
@@ -206,7 +206,22 @@ class SWDefinition @Inject constructor(
.preferenceId(R.string.key_age)
.label(R.string.patientage)
.comment(R.string.patientage_summary))
- .validator { sp.contains(R.string.key_age) }
+ .add(SWBreak(injector))
+ .add(SWEditNumber(injector, 3.0, 0.1, 25.0)
+ .preferenceId(R.string.key_treatmentssafety_maxbolus)
+ .updateDelay(5)
+ .label(R.string.treatmentssafety_maxbolus_title)
+ .comment(R.string.common_values))
+ .add(SWEditNumber(injector, 48.0, 1.0, 100.0)
+ .preferenceId(R.string.key_treatmentssafety_maxcarbs)
+ .updateDelay(5)
+ .label(R.string.treatmentssafety_maxcarbs_title)
+ .comment(R.string.common_values))
+ .validator {
+ sp.contains(R.string.key_age)
+ && sp.getDouble(R.string.key_treatmentssafety_maxbolus, 0.0) > 0
+ && sp.getDouble(R.string.key_treatmentssafety_maxcarbs, 0.0) > 0
+ }
private val screenInsulin = SWScreen(injector, R.string.configbuilder_insulin)
.skippable(false)
.add(SWPlugin(injector, this)
@@ -214,7 +229,7 @@ class SWDefinition @Inject constructor(
.makeVisible(false)
.label(R.string.configbuilder_insulin))
.add(SWBreak(injector))
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.diawarning))
private val screenBgSource = SWScreen(injector, R.string.configbuilder_bgsource)
.skippable(false)
@@ -224,7 +239,7 @@ class SWDefinition @Inject constructor(
.add(SWBreak(injector))
private val screenProfile = SWScreen(injector, R.string.configbuilder_profile)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.setupwizard_profile_description))
.add(SWBreak(injector))
.add(SWPlugin(injector, this)
@@ -232,7 +247,7 @@ class SWDefinition @Inject constructor(
.label(R.string.configbuilder_profile))
private val screenNsProfile = SWScreen(injector, R.string.nsprofile)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.adjustprofileinns))
.add(SWFragment(injector, this)
.add(NSProfileFragment()))
@@ -246,7 +261,7 @@ class SWDefinition @Inject constructor(
.visibility { localProfilePlugin.isEnabled(PluginType.PROFILE) }
private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.profileswitch_ismissing))
.add(SWButton(injector)
.text(R.string.doprofileswitch)
@@ -259,11 +274,11 @@ class SWDefinition @Inject constructor(
.option(PluginType.PUMP, R.string.configbuilder_pump_description)
.label(R.string.configbuilder_pump))
.add(SWBreak(injector))
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.setupwizard_pump_pump_not_initialized)
.visibility { !isPumpInitialized() })
.add( // Omnipod only
- SWInfotext(injector)
+ SWInfoText(injector)
.label(R.string.setupwizard_pump_waiting_for_riley_link_connection)
.visibility {
val activePump = activePlugin.activePump
@@ -290,12 +305,12 @@ class SWDefinition @Inject constructor(
// For Omnipod, consider the pump initialized when a RL has been configured successfully
// Users will be prompted to activate a Pod after completing the setup wizard.
- return activePump.isInitialized || (activePump is OmnipodErosPumpPlugin && activePump.isRileyLinkReady)
+ return activePump.isInitialized() || (activePump is OmnipodErosPumpPlugin && activePump.isRileyLinkReady)
}
private val screenAps = SWScreen(injector, R.string.configbuilder_aps)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.setupwizard_aps_description))
.add(SWBreak(injector))
.add(SWPlugin(injector, this)
@@ -314,7 +329,7 @@ class SWDefinition @Inject constructor(
.validator { sp.contains(R.string.key_aps_mode) }
private val screenLoop = SWScreen(injector, R.string.configbuilder_loop)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.setupwizard_loop_description))
.add(SWBreak(injector))
.add(SWButton(injector)
@@ -328,7 +343,7 @@ class SWDefinition @Inject constructor(
.visibility { !loopPlugin.isEnabled(PluginType.LOOP) && config.APS }
private val screenSensitivity = SWScreen(injector, R.string.configbuilder_sensitivity)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.setupwizard_sensitivity_description))
.add(SWHtmlLink(injector)
.label(R.string.setupwizard_sensitivity_url))
@@ -338,7 +353,7 @@ class SWDefinition @Inject constructor(
.label(R.string.configbuilder_sensitivity))
private val getScreenObjectives = SWScreen(injector, R.string.objectives)
.skippable(false)
- .add(SWInfotext(injector)
+ .add(SWInfoText(injector)
.label(R.string.startobjective))
.add(SWBreak(injector))
.add(SWFragment(injector, this)
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt
index 0313207d37..78b21df59d 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt
@@ -12,6 +12,7 @@ import info.nightscout.androidaps.databinding.ActivitySetupwizardBinding
import info.nightscout.androidaps.events.EventProfileNeedsUpdate
import info.nightscout.androidaps.events.EventProfileStoreChanged
import info.nightscout.androidaps.events.EventPumpStatusChanged
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
@@ -19,7 +20,7 @@ import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDevic
import info.nightscout.androidaps.setupwizard.elements.SWItem
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.locale.LocaleHelper.update
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
@@ -37,6 +38,7 @@ class SetupWizardActivity : NoSplashAppCompatActivity() {
@Inject lateinit var sp: SP
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable()
private lateinit var screens: List
@@ -143,13 +145,13 @@ class SetupWizardActivity : NoSplashAppCompatActivity() {
}
override fun onBackPressed() {
- if (currentWizardPage == 0) showConfirmation(this, resourceHelper.gs(R.string.exitwizard), Runnable { finish() }) else showPreviousPage(null)
+ if (currentWizardPage == 0) OKDialog.showConfirmation(this, resourceHelper.gs(R.string.exitwizard)) { finish() } else showPreviousPage(null)
}
@Suppress("UNUSED_PARAMETER")
fun exitPressed(view: View?) {
sp.putBoolean(R.string.key_setupwizard_processed, true)
- showConfirmation(this, resourceHelper.gs(R.string.exitwizard), Runnable { finish() })
+ OKDialog.showConfirmation(this, resourceHelper.gs(R.string.exitwizard)) { finish() }
}
@Suppress("UNUSED_PARAMETER")
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWBreak.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWBreak.kt
index 775d5b72d0..2d6f4926a3 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWBreak.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWBreak.kt
@@ -6,7 +6,7 @@ import android.widget.TextView
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.setupwizard.SWValidator
-class SWBreak(injector: HasAndroidInjector) : SWItem(injector, Type.TEXT) {
+class SWBreak(injector: HasAndroidInjector) : SWItem(injector, Type.BREAK) {
private var l: TextView? = null
private var visibilityValidator: SWValidator? = null
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditNumber.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditNumber.kt
new file mode 100644
index 0000000000..f29f7a1328
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditNumber.kt
@@ -0,0 +1,60 @@
+package info.nightscout.androidaps.setupwizard.elements
+
+import android.graphics.Typeface
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.View
+import android.widget.LinearLayout
+import android.widget.TextView
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.setupwizard.SWNumberValidator
+import info.nightscout.androidaps.utils.SafeParse
+import info.nightscout.androidaps.utils.ui.NumberPicker
+import java.text.DecimalFormat
+
+class SWEditNumber(injector: HasAndroidInjector, private val init: Double, private val min: Double, private val max: Double) : SWItem(injector, Type.DECIMAL_NUMBER) {
+
+ private val validator: SWNumberValidator = SWNumberValidator { value -> value in min..max }
+ private var updateDelay = 0
+
+ override fun generateDialog(layout: LinearLayout) {
+ val context = layout.context
+ val watcher: TextWatcher = object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ if (validator.isValid(SafeParse.stringToDouble(s.toString())))
+ save(s.toString(), updateDelay.toLong())
+ }
+
+ override fun afterTextChanged(s: Editable) {}
+ }
+
+ val l = TextView(context)
+ l.id = View.generateViewId()
+ label?.let { l.setText(it) }
+ l.setTypeface(l.typeface, Typeface.BOLD)
+ layout.addView(l)
+ val initValue = sp.getDouble(preferenceId, init)
+ val numberPicker = NumberPicker(context)
+ numberPicker.setParams(initValue, min, max, 0.1, DecimalFormat("0.0"), false, null, watcher)
+
+ layout.addView(numberPicker)
+ val c = TextView(context)
+ c.id = View.generateViewId()
+ comment?.let { c.setText(it) }
+ c.setTypeface(c.typeface, Typeface.ITALIC)
+ layout.addView(c)
+ super.generateDialog(layout)
+ }
+
+ fun preferenceId(preferenceId: Int): SWEditNumber {
+ this.preferenceId = preferenceId
+ return this
+ }
+
+ fun updateDelay(updateDelay: Int): SWEditNumber {
+ this.updateDelay = updateDelay
+ return this
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditNumberWithUnits.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditNumberWithUnits.kt
index 2d49eb3a97..7f9934f2c8 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditNumberWithUnits.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditNumberWithUnits.kt
@@ -16,11 +16,11 @@ import info.nightscout.androidaps.utils.SafeParse
import java.text.DecimalFormat
import javax.inject.Inject
-class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Double, private val min: Double, private val max: Double) : SWItem(injector, Type.UNITNUMBER) {
+class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Double, private val min: Double, private val max: Double) : SWItem(injector, Type.UNIT_NUMBER) {
@Inject lateinit var profileFunction: ProfileFunction
- private val validator: SWNumberValidator? = SWNumberValidator { value -> value >= min && value <= max }
+ private val validator: SWNumberValidator = SWNumberValidator { value -> value in min..max }
private var updateDelay = 0
override fun generateDialog(layout: LinearLayout) {
@@ -28,7 +28,7 @@ class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Doub
val watcher: TextWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
- if (validator != null && validator.isValid(SafeParse.stringToDouble(s.toString())))
+ if (validator.isValid(SafeParse.stringToDouble(s.toString())))
save(s.toString(), updateDelay.toLong())
}
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditUrl.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditUrl.kt
index cc9f38ff43..90647b51cf 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditUrl.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWEditUrl.kt
@@ -38,7 +38,7 @@ class SWEditUrl(injector: HasAndroidInjector) : SWItem(injector, Type.URL) {
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
- if (Patterns.WEB_URL.matcher(s).matches()) save(s.toString(), updateDelay.toLong()) else rxBus.send(EventSWLabel(resourceHelper.gs(R.string.error_url_not_valid)))
+ if (Patterns.WEB_URL.matcher(s).matches()) save(s.toString(), updateDelay) else rxBus.send(EventSWLabel(resourceHelper.gs(R.string.error_url_not_valid)))
}
override fun afterTextChanged(s: Editable) {}
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWHtmlLink.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWHtmlLink.kt
index fe5b34241e..73bb625537 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWHtmlLink.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWHtmlLink.kt
@@ -8,7 +8,7 @@ import androidx.annotation.StringRes
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.setupwizard.SWValidator
-class SWHtmlLink(injector: HasAndroidInjector) : SWItem(injector, Type.HTMLLINK) {
+class SWHtmlLink(injector: HasAndroidInjector) : SWItem(injector, Type.HTML_LINK) {
private var textLabel: String? = null
private var l: TextView? = null
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWInfotext.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWInfoText.kt
similarity index 82%
rename from app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWInfotext.kt
rename to app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWInfoText.kt
index ca9b3b829f..9a8e0f00cd 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWInfotext.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWInfoText.kt
@@ -6,22 +6,22 @@ import android.widget.TextView
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.setupwizard.SWValidator
-class SWInfotext(injector: HasAndroidInjector) : SWItem(injector, Type.TEXT) {
+class SWInfoText(injector: HasAndroidInjector) : SWItem(injector, Type.TEXT) {
private var textLabel: String? = null
private var l: TextView? = null
private var visibilityValidator: SWValidator? = null
- override fun label(label: Int): SWInfotext {
+ override fun label(label: Int): SWInfoText {
this.label = label
return this
}
- fun label(newLabel: String): SWInfotext {
+ fun label(newLabel: String): SWInfoText {
textLabel = newLabel
return this
}
- fun visibility(visibilityValidator: SWValidator): SWInfotext {
+ fun visibility(visibilityValidator: SWValidator): SWInfoText {
this.visibilityValidator = visibilityValidator
return this
}
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWItem.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWItem.kt
index 48e40868c3..c6cc3f9620 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWItem.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWItem.kt
@@ -27,25 +27,18 @@ open class SWItem(val injector: HasAndroidInjector, var type: Type) {
private var scheduledEventPost: ScheduledFuture<*>? = null
init {
+ @Suppress("LeakingThis")
injector.androidInjector().inject(this)
}
enum class Type {
- NONE, TEXT, HTMLLINK, BREAK, LISTENER, URL, STRING, NUMBER, DECIMALNUMBER, CHECKBOX, RADIOBUTTON, PLUGIN, BUTTON, FRAGMENT, UNITNUMBER
+ NONE, TEXT, HTML_LINK, BREAK, LISTENER, URL, STRING, NUMBER, DECIMAL_NUMBER, RADIOBUTTON, PLUGIN, BUTTON, FRAGMENT, UNIT_NUMBER
}
var label: Int? = null
var comment: Int? = null
var preferenceId = 0
- fun getLabel(): String {
- return label?.let { resourceHelper.gs(it) } ?: ""
- }
-
- fun getComment(): String {
- return comment?.let { resourceHelper.gs(it) } ?: ""
- }
-
open fun label(@StringRes label: Int): SWItem {
this.label = label
return this
@@ -72,6 +65,7 @@ open class SWItem(val injector: HasAndroidInjector, var type: Type) {
fun scheduleChange(updateDelay: Long) {
class PostRunnable : Runnable {
+
override fun run() {
aapsLogger.debug(LTag.CORE, "Firing EventPreferenceChange")
rxBus.send(EventPreferenceChange(resourceHelper, preferenceId))
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWPlugin.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWPlugin.kt
index 60702978e9..76c140d708 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWPlugin.kt
@@ -89,7 +89,7 @@ class SWPlugin(injector: HasAndroidInjector, val definition: SWDefinition) : SWI
super.generateDialog(layout)
}
- fun addConfiguration(layout: LinearLayout, plugin: PluginBase) {
+ private fun addConfiguration(layout: LinearLayout, plugin: PluginBase) {
if (plugin.preferencesId != -1) {
fragment = MyPreferenceFragment()
fragment?.arguments = Bundle().also { it.putInt("id", plugin.preferencesId) }
diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWRadioButton.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWRadioButton.kt
index 7201c47342..979bfe52fc 100644
--- a/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWRadioButton.kt
+++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/elements/SWRadioButton.kt
@@ -29,12 +29,12 @@ class SWRadioButton(injector: HasAndroidInjector) : SWItem(injector, Type.RADIOB
override fun generateDialog(layout: LinearLayout) {
val context = layout.context
- val pdesc = TextView(context)
- pdesc.text = getComment()
+ val desc = TextView(context)
+ comment?.let { desc.setText(it) }
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
params.setMargins(0, 0, 0, 40)
- pdesc.layoutParams = params
- layout.addView(pdesc)
+ desc.layoutParams = params
+ layout.addView(desc)
// Get if there is already value in SP
val previousValue = sp.getString(preferenceId, "none")
@@ -43,12 +43,12 @@ class SWRadioButton(injector: HasAndroidInjector) : SWItem(injector, Type.RADIOB
radioGroup?.orientation = LinearLayout.VERTICAL
radioGroup?.visibility = View.VISIBLE
for (i in labels().indices) {
- val rdbtn = RadioButton(context)
- rdbtn.id = View.generateViewId()
- rdbtn.text = labels()[i]
- if (previousValue == values()[i]) rdbtn.isChecked = true
- rdbtn.tag = i
- radioGroup!!.addView(rdbtn)
+ val rdBtn = RadioButton(context)
+ rdBtn.id = View.generateViewId()
+ rdBtn.text = labels()[i]
+ if (previousValue == values()[i]) rdBtn.isChecked = true
+ rdBtn.tag = i
+ radioGroup!!.addView(rdBtn)
}
radioGroup!!.setOnCheckedChangeListener { group: RadioGroup, checkedId: Int ->
val i = group.findViewById(checkedId).tag as Int
diff --git a/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt b/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt
index 4ac9b7885f..323f52f05b 100644
--- a/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt
+++ b/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt
@@ -22,7 +22,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton
@@ -58,7 +58,7 @@ class AndroidPermission @Inject constructor(
activity.callForBatteryOptimization.launch(null)
} catch (e: ActivityNotFoundException) {
permissionBatteryOptimizationFailed = true
- show(activity, resourceHelper.gs(R.string.permission), resourceHelper.gs(R.string.alert_dialog_permission_battery_optimization_failed), Runnable { activity.recreate() })
+ OKDialog.show(activity, resourceHelper.gs(R.string.permission), resourceHelper.gs(R.string.alert_dialog_permission_battery_optimization_failed), Runnable { activity.recreate() })
}
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/utils/CarbTimer.kt b/app/src/main/java/info/nightscout/androidaps/utils/CarbTimer.kt
new file mode 100644
index 0000000000..c029b01af2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/utils/CarbTimer.kt
@@ -0,0 +1,63 @@
+package info.nightscout.androidaps.utils
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
+import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
+import info.nightscout.androidaps.plugins.general.automation.actions.ActionAlarm
+import info.nightscout.androidaps.plugins.general.automation.elements.Comparator
+import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta
+import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg
+import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
+import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import java.text.DecimalFormat
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class CarbTimer @Inject constructor(
+ private val injector: HasAndroidInjector,
+ private val resourceHelper: ResourceHelper,
+ private val automationPlugin: AutomationPlugin,
+ private val timerUtil: TimerUtil
+) {
+
+ fun scheduleReminder(time: Long, text: String? = null) =
+ timerUtil.scheduleReminder(time, text ?: resourceHelper.gs(R.string.timetoeat))
+
+ fun scheduleEatReminder() {
+ val event = AutomationEvent(injector).apply {
+ title = resourceHelper.gs(R.string.bolusadvisor)
+ readOnly = true
+ systemAction = true
+ autoRemove = true
+ trigger = TriggerConnector(injector, TriggerConnector.Type.OR).apply {
+
+ // Bg under 180 mgdl and dropping by 15 mgdl
+ list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
+ list.add(TriggerBg(injector, 180.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
+ list.add(TriggerDelta(injector, InputDelta(injector, -15.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
+ list.add(TriggerDelta(injector, InputDelta(injector, -8.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
+ })
+ // Bg under 160 mgdl and dropping by 9 mgdl
+ list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
+ list.add(TriggerBg(injector, 160.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
+ list.add(TriggerDelta(injector, InputDelta(injector, -9.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
+ list.add(TriggerDelta(injector, InputDelta(injector, -5.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
+ })
+ // Bg under 145 mgdl and dropping
+ list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
+ list.add(TriggerBg(injector, 145.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
+ list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
+ list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
+ })
+ }
+ actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.time_to_eat)))
+ }
+
+ automationPlugin.addIfNotExists(event)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TimerUtil.kt b/app/src/main/java/info/nightscout/androidaps/utils/TimerUtil.kt
new file mode 100644
index 0000000000..b62f00df54
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/utils/TimerUtil.kt
@@ -0,0 +1,27 @@
+package info.nightscout.androidaps.utils
+
+import android.content.Context
+import android.content.Intent
+import android.provider.AlarmClock
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class TimerUtil @Inject constructor(
+ private val context: Context,
+ private val resourceHelper: ResourceHelper,
+) {
+
+ fun scheduleReminder(time: Long, text: String? = null) {
+ Intent(AlarmClock.ACTION_SET_TIMER).apply {
+ val length: Int = ((time - DateUtil.now()) / 1000).toInt()
+ flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK
+ putExtra(AlarmClock.EXTRA_LENGTH, length)
+ putExtra(AlarmClock.EXTRA_SKIP_UI, true)
+ putExtra(AlarmClock.EXTRA_MESSAGE, text ?: resourceHelper.gs(R.string.app_name))
+ context.startActivity(this)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt b/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt
index ff11dfb096..2eafc12ebb 100644
--- a/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt
+++ b/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt
@@ -8,13 +8,13 @@ import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class BuildHelper @Inject constructor(private val config: Config) {
+class BuildHelper @Inject constructor(private val config: Config, loggerUtils: LoggerUtils) {
private var devBranch = false
private var engineeringMode = false
init {
- val extFilesDir = LoggerUtils.getLogDirectory()
+ val extFilesDir = loggerUtils.logDirectory
val engineeringModeSemaphore = File(extFilesDir, "engineering__mode")
engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile
diff --git a/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt b/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt
index ce53f3d670..37fccabd8c 100644
--- a/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt
+++ b/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt
@@ -6,7 +6,6 @@ import android.text.Spanned
import com.google.common.base.Joiner
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config
-import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo
@@ -18,21 +17,14 @@ import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
-import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
-import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
-import info.nightscout.androidaps.plugins.general.automation.actions.ActionAlarm
-import info.nightscout.androidaps.plugins.general.automation.elements.Comparator
-import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta
-import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg
-import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
-import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta
-import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.CarbTimer
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.Round
@@ -43,7 +35,6 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
-import java.text.DecimalFormat
import java.util.*
import javax.inject.Inject
import kotlin.math.abs
@@ -62,9 +53,10 @@ class BolusWizard @Inject constructor(
@Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
- @Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var config: Config
+ @Inject lateinit var uel: UserEntryLogger
+ @Inject lateinit var carbTimer: CarbTimer
init {
injector.androidInjector().inject(this)
@@ -192,7 +184,7 @@ class BolusWizard @Inject constructor(
glucoseStatus = GlucoseStatus(injector).glucoseStatusData
glucoseStatus?.let {
if (useTrend) {
- trend = it.short_avgdelta
+ trend = it.shortAvgDelta
insulinFromTrend = Profile.fromMgdlToUnits(trend, profileFunction.getUnits()) * 3 / sens
}
}
@@ -354,19 +346,14 @@ class BolusWizard @Inject constructor(
boluscalc = nsJSON()
source = Source.USER
notes = this@BolusWizard.notes
- aapsLogger.debug("USER ENTRY: BOLUS ADVISOR insulin $insulinAfterConstraints")
+ uel.log("BOLUS ADVISOR", d1 = insulinAfterConstraints)
if (insulin > 0) {
commandQueue.bolus(this, object : Callback() {
override fun run() {
if (!result.success) {
- val i = Intent(ctx, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- ctx.startActivity(i)
+ ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
} else
- scheduleEatReminder()
+ carbTimer.scheduleEatReminder()
}
})
}
@@ -382,7 +369,7 @@ class BolusWizard @Inject constructor(
OKDialog.showConfirmation(ctx, resourceHelper.gs(R.string.boluswizard), confirmMessage, {
if (insulinAfterConstraints > 0 || carbs > 0) {
if (useSuperBolus) {
- aapsLogger.debug("USER ENTRY: SUPERBOLUS TBR")
+ uel.log("SUPERBOLUS TBR")
if (loopPlugin.isEnabled(PluginType.LOOP)) {
loopPlugin.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000)
rxBus.send(EventRefreshOverview("WizardDialog"))
@@ -392,12 +379,7 @@ class BolusWizard @Inject constructor(
commandQueue.tempBasalAbsolute(0.0, 120, true, profile, object : Callback() {
override fun run() {
if (!result.success) {
- val i = Intent(ctx, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- ctx.startActivity(i)
+ ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
}
}
})
@@ -407,9 +389,9 @@ class BolusWizard @Inject constructor(
override fun run() {
if (!result.success) {
val i = Intent(ctx, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
+ i.putExtra(ErrorHelperActivity.SOUND_ID, R.raw.boluserror)
+ i.putExtra(ErrorHelperActivity.STATUS, result.comment)
+ i.putExtra(ErrorHelperActivity.TITLE, resourceHelper.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
ctx.startActivity(i)
}
@@ -428,17 +410,12 @@ class BolusWizard @Inject constructor(
boluscalc = nsJSON()
source = Source.USER
notes = this@BolusWizard.notes
- aapsLogger.debug("USER ENTRY: BOLUS WIZARD insulin $insulinAfterConstraints carbs: $carbs")
+ uel.log("BOLUS WIZARD", "", insulinAfterConstraints, carbs)
if (insulin > 0 || pump.pumpDescription.storesCarbInfo) {
commandQueue.bolus(this, object : Callback() {
override fun run() {
if (!result.success) {
- val i = Intent(ctx, ErrorHelperActivity::class.java)
- i.putExtra("soundid", R.raw.boluserror)
- i.putExtra("status", result.comment)
- i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- ctx.startActivity(i)
+ ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
}
}
})
@@ -447,57 +424,9 @@ class BolusWizard @Inject constructor(
}
}
if (useAlarm && carbs > 0 && carbTime > 0) {
- scheduleReminder(dateUtil._now() + T.mins(carbTime.toLong()).msecs())
+ carbTimer.scheduleReminder(dateUtil._now() + T.mins(carbTime.toLong()).msecs())
}
}
})
}
-
- private fun scheduleEatReminder() {
- val event = AutomationEvent(injector).apply {
- title = resourceHelper.gs(R.string.bolusadvisor)
- readOnly = true
- systemAction = true
- autoRemove = true
- trigger = TriggerConnector(injector, TriggerConnector.Type.OR).apply {
-
- // Bg under 180 mgdl and dropping by 15 mgdl
- list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
- list.add(TriggerBg(injector, 180.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
- list.add(TriggerDelta(injector, InputDelta(injector, -15.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
- list.add(TriggerDelta(injector, InputDelta(injector, -8.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
- })
- // Bg under 160 mgdl and dropping by 9 mgdl
- list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
- list.add(TriggerBg(injector, 160.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
- list.add(TriggerDelta(injector, InputDelta(injector, -9.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
- list.add(TriggerDelta(injector, InputDelta(injector, -5.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
- })
- // Bg under 145 mgdl and dropping
- list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
- list.add(TriggerBg(injector, 145.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
- list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
- list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
- })
- }
- actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.time_to_eat)))
- }
-
- automationPlugin.addIfNotExists(event)
- }
-
- private fun scheduleReminder(time: Long) {
- val event = AutomationEvent(injector).apply {
- title = resourceHelper.gs(R.string.timetoeat)
- readOnly = true
- systemAction = true
- autoRemove = true
- trigger = TriggerConnector(injector, TriggerConnector.Type.AND).apply {
- list.add(TriggerTime(injector, time))
- }
- actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.timetoeat)))
- }
-
- automationPlugin.addIfNotExists(event)
- }
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt b/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt
index abfe8b4bd9..39da06c1f5 100644
--- a/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt
+++ b/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt
@@ -112,9 +112,9 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
var trend = false
if (useTrend() == YES) {
trend = true
- } else if (useTrend() == POSITIVE_ONLY && glucoseStatus != null && glucoseStatus.short_avgdelta > 0) {
+ } else if (useTrend() == POSITIVE_ONLY && glucoseStatus != null && glucoseStatus.shortAvgDelta > 0) {
trend = true
- } else if (useTrend() == NEGATIVE_ONLY && glucoseStatus != null && glucoseStatus.short_avgdelta < 0) {
+ } else if (useTrend() == NEGATIVE_ONLY && glucoseStatus != null && glucoseStatus.shortAvgDelta < 0) {
trend = true
}
val percentage = sp.getDouble(R.string.key_boluswizard_percentage, 100.0)
diff --git a/app/src/main/jniLibs/README.md b/app/src/main/jniLibs/README.md
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so b/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so
deleted file mode 100644
index 69e283b5fe..0000000000
Binary files a/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so b/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so
deleted file mode 100644
index 0c717bc3e8..0000000000
Binary files a/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/armeabi/libBleCommandUtil.so b/app/src/main/jniLibs/armeabi/libBleCommandUtil.so
deleted file mode 100644
index a51a8c7d9a..0000000000
Binary files a/app/src/main/jniLibs/armeabi/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/mips/libBleCommandUtil.so b/app/src/main/jniLibs/mips/libBleCommandUtil.so
deleted file mode 100644
index fcff5eb6b2..0000000000
Binary files a/app/src/main/jniLibs/mips/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/mips64/libBleCommandUtil.so b/app/src/main/jniLibs/mips64/libBleCommandUtil.so
deleted file mode 100644
index a8a292ea13..0000000000
Binary files a/app/src/main/jniLibs/mips64/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/x86/libBleCommandUtil.so b/app/src/main/jniLibs/x86/libBleCommandUtil.so
deleted file mode 100644
index 638a9def95..0000000000
Binary files a/app/src/main/jniLibs/x86/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/jniLibs/x86_64/libBleCommandUtil.so b/app/src/main/jniLibs/x86_64/libBleCommandUtil.so
deleted file mode 100644
index 94873d3732..0000000000
Binary files a/app/src/main/jniLibs/x86_64/libBleCommandUtil.so and /dev/null differ
diff --git a/app/src/main/res/layout/activity_preferences.xml b/app/src/main/res/layout/activity_preferences.xml
index 00b72e0b74..eef88c7bad 100644
--- a/app/src/main/res/layout/activity_preferences.xml
+++ b/app/src/main/res/layout/activity_preferences.xml
@@ -34,7 +34,7 @@
+ android:layout_height="wrap_content" />
diff --git a/app/src/main/res/layout/dialog_carbs.xml b/app/src/main/res/layout/dialog_carbs.xml
index 66c58a61bf..f0f306c6ff 100644
--- a/app/src/main/res/layout/dialog_carbs.xml
+++ b/app/src/main/res/layout/dialog_carbs.xml
@@ -75,107 +75,160 @@
-
+ android:paddingEnd="5dp">
-
+
-
+
-
+
-
+
-
+
+
-
+
-
+
-
+
-
+
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -45,8 +45,8 @@
android:id="@+id/temp_basals"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="6dp"
- android:paddingEnd="6dp"
+ android:paddingStart="1dp"
+ android:paddingEnd="1dp"
android:layout_weight="1"
android:contentDescription="@string/tempbasal_label"
android:scaleX="0.7"
@@ -57,8 +57,8 @@
android:id="@+id/temp_targets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="6dp"
- android:paddingEnd="6dp"
+ android:paddingStart="1dp"
+ android:paddingEnd="1dp"
android:layout_weight="1"
android:contentDescription="@string/careportal_temporarytarget"
android:scaleX="0.7"
@@ -69,8 +69,8 @@
android:id="@+id/profile_switches"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="6dp"
- android:paddingEnd="6dp"
+ android:paddingStart="1dp"
+ android:paddingEnd="1dp"
android:layout_weight="1"
android:contentDescription="@string/careportal_profileswitch"
android:scaleX="0.7"
@@ -81,14 +81,26 @@
android:id="@+id/careportal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="6dp"
- android:paddingEnd="6dp"
+ android:paddingStart="1dp"
+ android:paddingEnd="1dp"
android:layout_weight="1"
android:contentDescription="@string/careportal"
android:scaleX="0.7"
android:scaleY="0.7"
app:srcCompat="@drawable/ic_cp_note" />
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/treatments_user_entry_item.xml b/app/src/main/res/layout/treatments_user_entry_item.xml
new file mode 100644
index 0000000000..a3c3870c9a
--- /dev/null
+++ b/app/src/main/res/layout/treatments_user_entry_item.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml
index c358fbbabd..7d83f9f64f 100644
--- a/app/src/main/res/values-cs-rCZ/strings.xml
+++ b/app/src/main/res/values-cs-rCZ/strings.xml
@@ -420,6 +420,7 @@
BAZ
ODCH
AKT
+ -BGI
ABS
DEVSLOPE
O aplikaci
@@ -627,6 +628,7 @@
Automaticky doplňovat chybějící glykémie z NS
SMB provedené pumpou
Aktivita
+ Vliv na hladinu glukózy
Citlivost
Odchylky
Zbývající sacharidy
@@ -1156,4 +1158,8 @@
Graf
Možnosti grafu
Vymazat filtr
+ Šipka trendu
+ Kanyla
+ Vstup uživatele
+ Použijte hodnoty pro největší jídlo, jaké obvykle jíte\n
diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml
index 71befb0e60..106f34a0af 100644
--- a/app/src/main/res/values-de-rDE/strings.xml
+++ b/app/src/main/res/values-de-rDE/strings.xml
@@ -420,6 +420,7 @@
BAS
DEV
ACT
+ -BGI
ABS
DEVSLOPE
Über
@@ -627,6 +628,7 @@
Lade fehlende Blutzuckerwerte automatisch aus Nightscout nach.
SMB von der Pumpe abgegeben
Aktivität
+ Blutzuckerwirkung
Sensitivität
Abweichungen
Aktive Kohlenhydrate
@@ -1157,4 +1159,8 @@ Unerwartetes Verhalten.
Diagramm
Diagrammmenü
Filter löschen
+ Trendpfeil
+ Kanüle
+ Benutzereingabe
+ Verwende die Werte der größten Mahlzeit, die Du normalerweise zu Dir nimmst\n
diff --git a/app/src/main/res/values-fr-rFR/objectives.xml b/app/src/main/res/values-fr-rFR/objectives.xml
index 288de82bbb..54809e4ba5 100644
--- a/app/src/main/res/values-fr-rFR/objectives.xml
+++ b/app/src/main/res/values-fr-rFR/objectives.xml
@@ -21,7 +21,7 @@
Activation de fonctionnalités supplémentaires pour l\'utilisation en journée, telles que la fonction SMB
Activation de l\'automatisation
Lisez le wiki et augmentez le maxIA pour que les SMBs fonctionnent correctement ! Un bon début est maxIA = moyenne des Bolus Repas + 3 x maximum débit Basal quotidien
- Lisez la documentation comment l\'automatisation fonctionne. Configurez vos premières règles simples. Au lieu de mettre une action, configurez une notification. Quand vous êtes sûr que l\'automatisation est déclenchée au bon moment, remplacez la notification par une action réelle. (https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Usage/Automation.html)
+ Lisez la documentation comment l\'automatisation fonctionne. Configurez vos premières règles simples. Au lieu de mettre une action, configurez une notification. Quand vous êtes sûr que l\'automatisation est déclenchée au bon moment, remplacez la notification par une action réelle. (https://androidaps.readthedocs.io/fr/latest/Usage/Automation.html)
Glycémie disponible sur NS
Statut de la pompe disponible sur NS
Activation manuelle
@@ -36,7 +36,7 @@
Affichage du contenu du plugin Boucle
Modification de l\'échelle du graphique par un appui long sur la courbe de glycémie
Entrer
- Si vous avez au moins 3 mois d\'expérience de boucle fermée avec d\'autres systèmes, vous pourriez avoir droit à un code permettant d\'ignorer les objectifs. Voir https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Usage/Objectives.html#ignorer-les-objectifs pour plus de détails.
+ Si vous avez au moins 3 mois d\'expérience de boucle fermée avec d\'autres systèmes, vous pourriez avoir droit à un code permettant d\'ignorer les objectifs. Voir https://androidaps.readthedocs.io/fr/latest/Usage/Objectives.html#ignorer-les-objectifs pour plus de détails.
Code accepté
Code invalide
Prouver ses connaissances
@@ -46,10 +46,10 @@
Prochain non terminé
Code requis : %1$s
(Sélectionnez toutes les bonnes réponses)
- https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/FAQ.html#what-to-do-when-taking-a-shower-or-bath
- https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/Screenshots.html#the-homescreen
- https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/Screenshots.html#config-builder
- https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/Screenshots.html#the-homescreen
+ https://androidaps.readthedocs.io/fr/latest/Getting-Started/FAQ.html#que-faire-pour-prendre-une-douche-ou-un-bain
+ https://androidaps.readthedocs.io/fr/latest/Getting-Started/Screenshots.html
+ https://androidaps.readthedocs.io/fr/latest/Configuration/Config-Builder.html
+ https://androidaps.readthedocs.io/fr/latest/Getting-Started/Screenshots.html
Non connecté à Internet
Échec de la récupération de l\'heure
Exigences de l\'objectif non atteintes
diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml
index e6f22226eb..959da11884 100644
--- a/app/src/main/res/values-fr-rFR/strings.xml
+++ b/app/src/main/res/values-fr-rFR/strings.xml
@@ -421,6 +421,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
BAS
DEV
ACT
+ -IGly
ABS
PENTEDEV
À propos
@@ -628,6 +629,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
Remplissage automatique des glycémies manquantes en utilisant NS
SMB défini par la pompe
Activité
+ Impact glycémique
Sensibilité
Déviations
Glucides actifs
@@ -1159,4 +1161,6 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
Effacer le filtre
Flèche de tendance
Canule
+ Entrées utilisateur
+ Utilisez les valeurs qui correspondent à vos plus gros repas\n
diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml
index dff77d5813..8bfdf04a07 100644
--- a/app/src/main/res/values-it-rIT/strings.xml
+++ b/app/src/main/res/values-it-rIT/strings.xml
@@ -420,6 +420,7 @@
BAS
DEV
ATT
+ -BGI
ASS
PENDEV
Informazioni su
@@ -627,6 +628,7 @@
Riempimento automatico glicemie mancanti da NS
SMB impostato dal micro
Attività
+ Impatto glicemia (BGI)
Sensibilità
Deviazioni
CHO attivi
@@ -1158,4 +1160,6 @@
Cancella filtro
Freccia trend
Cannula
+ Inserimento utente
+ Usa i valori del cibo più abbondante che mangi di solito\n
diff --git a/app/src/main/res/values-iw-rIL/objectives.xml b/app/src/main/res/values-iw-rIL/objectives.xml
index f91928315d..14e4f06937 100644
--- a/app/src/main/res/values-iw-rIL/objectives.xml
+++ b/app/src/main/res/values-iw-rIL/objectives.xml
@@ -16,7 +16,7 @@
כוונון הלולאה הסגורה, תוך העלאה של ערך ה- IOB מעל 0 ובסופו של דבר הורדת ערכי המטרה של רמת הסוכר
לפני הורדת ערך רמת הסוכר, הפעל במשך מס\' ימים, עם לפחות לילה אחד ללא התרעת רמת סוכר נמוכה
במידת הצורך, בצעו התאמת בזאלי ויחסים, ולאחר מכן הפעילו את Autosens
- שבוע של הפעלה מוצלחת של הלולאה במשך היום, עם הוספת ערכי פחמימות רגילים
+ שבוע של הפעלה מוצלחת של הלולאה במשך שעות היום, עם הוספת ערכי פחמימות רגילים
הפעלת פונקציות נוספות לשימוש במשך היום, לדוגמה AMA (סיוע ארוחות מתקדם)
הפעלת פונקציות נוספות לשימוש במשך היום, כגון סופר מיקרו בולוסים (SMB)
הפעלת אוטומציה
diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml
index a555ec6d77..2b8d794200 100644
--- a/app/src/main/res/values-iw-rIL/strings.xml
+++ b/app/src/main/res/values-iw-rIL/strings.xml
@@ -156,7 +156,7 @@
יבא הגדרות
מינון בזאלי זמני מקסימלי (יח\'\\שעה)
ערך זה נקרא בזאלי מרבי ב-OpenAPS
- בזאלי פעיל מרבי ש-OpenAPS יכול לספק [U]
+ בזאלי פעיל מרבי ש-OpenAPS יכול לספק (יחידות)
ערך זה נקרא אינסולין פעיל מקסימלי (Max IOB) ב-OpenAPS. זהו מקסימום האינסולין הפעיל ב-[U] ש-APS מאפשר.
אתם תתבקשו למלא סיסמה ראשית שתשמש להצפנת ההעדפות המיוצאות.
אתם תתבקשו למלא סיסמה ראשית שתשמש לפיענוח ההעדפות המיובאות.
@@ -180,7 +180,7 @@
שמור
טעינה מחדש של הפרופיל
תקשורת SMS
- מספרי טלפון מותרים
+ מספרי טלפון מורשים
+ XXXXXXXXXX; + YYYYYYYYYY
לאישור מתן בולוס %1$.2f יחידות יש להשיב עם הקוד %2$s
למתן %1$.2f יחידות בולוס ארוחה יש להשיב עם הקוד %2$s
@@ -217,7 +217,7 @@
פקודה מרוחקת אינה מותרת
בולוס מרחוק אינו זמין. נסו שוב מאוחר יותר.
להפעלת בזאלי %1$.2f יח\' לשעה למשך %2$d דקות יש להשיב עם הקוד %3$s
- להחלפת פרופיל ל- %1$s %2$d % הקש קוד %3$s
+ להחלפת פרופיל ל- %1$s %2$d %% הקש את הקוד %3$s
למתן בולוס ממושך %1$.2f יח\' למשך %2$d דקות יש להשיב עם הקוד %3$s
למתן %1$d גר\' ב-%2$s יש להשיב עם הקוד %3$s
להפעלת בזאלי %1$d%% למשך %2$d דקות הקש קוד %3$s
@@ -312,7 +312,7 @@
ערך ברירת מחדל: 4 זהו החצי השני של מנגנון הגנה עיקרי של OpenAPS, והחצי השני של \"3x max daily; 4x current\" במנגנוני ההגנה. המשמעות היא שהמינון הבזאלי, ללא קשר למקסימום שנקבע במשאבה, אינו יכול להיות גבוה יותר ממספר זה כפול הקצב הבזאלי הנוכחי. מיועד למנוע כניסה לתחומים מסוכנים ע\"י קביעת קצב בזאלי גבוה לפני הבנה של פעולת האלגוריתם. שוב: ברירת המחדל היא x4, רוב המשתמשים לעולם אינם צריכים לשנות ערך זה ואם הם מרגישים שמנגנון הגנה זה מפריע להם, הפתרון הוא בשינוי של הגדרות אחרות.
ערך ברירת מחדל: 1.2\nזוהי מגבלת המכפיל של autosens (ובקרוב autotune) שמגדירה 20%% כיחס מקסימלי של autosens, אשר קובע בתורו את גובה הבזאלי המקסימלי, גובהו המינימלי של יחס התיקון, ואת המינימום של ערכי המטרה האפשריים.
ערך ברירת מחדל: 0.7\nבצד השני של מגבלות הבטיחות של autosens, ערך זה מגביל את יכולתו של autosens להוריד את הערכים הבזאליים ועד כמה יכול להעלות את יחס התיקון ואת ערכי מטרת הסוכר בדם.
- Autosens מווסת גם את ערכי המטרה
+ וויסות ערכי מטרה ע\"י Autosens
ערך ברירת מחדל: התאמה מדויקת\n נועד לאפשר ל-Autosens לשנות את המטרה של ערכי הסוכר, בנוסף ליחס התיקון והבזאלים.
ערך ברירת מחדל: 2\n מעכב בולוס מופעל אחרי שאתם מזריקים בולוס ארוחה, כך שהלולאה לא תפצה ע\"י בזאלי זמני נמוך אחרי הארוחה. הדוגמה כאן וברירת המחדל היא 2; כך שהגדרה של משך פעילות אינסולין של 3 שעות משמעה שהעיכוב יחלוף בהדרגה בתוך 1.5 שעות (3 ש\' לחלק ל-2).
ערך ברירת מחדל: 3.0 (AMA) או 8.0 (SMB). זוהי הגדרת ברירת מחדל לספיגת פחמימות ב-5 דקות. ברירת המחדל היא 3mg/dL/5min. פעולה זו משפיעה על קצב הדעיכה של פחמ\' פעילות, ועל הנחת קצב ספיגת הפחמ\' בחישוב רמות סוכר עתידיות כשהן בירידה מהירה מהצפוי או עליה איטית מהצפוי.
@@ -420,6 +420,7 @@
בזאל\'
סטייה
פעילות
+ השפעה
אבס\'
שיפוע
אודות
@@ -627,6 +628,7 @@
לטעינת הנתונים האוטומטית חסרים נתוני סוכר מ-Nightscout
SMB מוגדר באמצעות משאבה
פעילות
+ השפעת הסוכר בדם
רגישות
חריגות
פחמימות פעילות
@@ -676,7 +678,7 @@
SMB אינו פעיל במצב לולאה פתוחה
מזון
איפוס
- מינון אינסולין פעיל מרבי ממנו OpenAPS לא יחרוג [U]
+ מינון אינסולין פעיל מרבי ממנו OpenAPS לא יחרוג (יחידות)
ב-OpenAPS ערך זה נקרא מקסימום אינסולין פעיל (maxIOB). \nלא יוזרק עוד אינסולין אם כמות האינסולין הפעיל הנוכחי גדול מערך זה
המשאבה נעצרה
המשאבה הופעלה
@@ -702,8 +704,8 @@
הגדרות חיבור
SSID מורשים (מופרדים בנקודה-פסיק)
אפשר חיבור בנדידה
- יחס autosens מקסימלי
- יחס autosens מינימלי
+ יחס Autosens מקסימלי
+ יחס Autosens מינימלי
נמנום בולוס - מחלק משך פעילות אינסולין
מכפלת בטיחות בזאלי יומי מירבי
מכפלת בטיחות בזאלי נוכחי
@@ -771,7 +773,7 @@
מחק רישומים
לא ניתן להוסיף טיפול (אינסולין: %1$.2f, פחמ\': %2$d, בשעה: %3$s) לטיפולים. נא לבדוק ולהוסיף רשומה באופן ידני כנדרש.
פחמימות ממושכות: %1$d גר\' (%2$d ש\'), עיכוב %3$d דק\'
- אין נתוני autosens זמינים
+ אין נתוני Autosens זמינים
הגדרות יומן רישום
אפס לברירת המחדל
תקלה ב-NSClient. שקלו להפעיל את Nightscout ו-NSClient מחדש.
@@ -1158,4 +1160,6 @@
נקה סינון
חץ מגמה
צינורית
+ קלט המשתמש
+ השתמשו בערכים הגבוהים ביותר של מזונות שאתם אוכלים בדרך כלל\n
diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml
index a44ff5fcc9..e87337521a 100644
--- a/app/src/main/res/values-no-rNO/strings.xml
+++ b/app/src/main/res/values-no-rNO/strings.xml
@@ -420,6 +420,7 @@
BAS
DEV
AKT
+ -BGI
ABS
DEVSLOPE
Om
@@ -627,6 +628,7 @@
Hente manglende BS data fra NS
SMB satt med pumpe
Aktivitet
+ Blodsukkerpåvirkning
Sensitivitet
Avvik
Aktive KH (COB)
@@ -1158,4 +1160,6 @@
Nullstill filtre
Trend pil
Kanyle
+ Bruker registrering
+ Bruk verdiene for det største måltidet du normalt spiser\n
diff --git a/app/src/main/res/values-pt-rPT/exam.xml b/app/src/main/res/values-pt-rPT/exam.xml
index d34c7bc14b..5dbbe3b464 100644
--- a/app/src/main/res/values-pt-rPT/exam.xml
+++ b/app/src/main/res/values-pt-rPT/exam.xml
@@ -96,7 +96,7 @@
Seleccione todas as respostas correctas.
Precisa ter Git instalado e configurado no computador.
Quando as versões actualizadas do AndroidAPS são lançadas, as versões anteriores podem ser remotamente limitadas após um tempo específico.
- Deve guardar e anotar a localização da sua keystore e usar a mesma chave de assinatura para actualizações como para a instalação anterior.
+ Deve guardar e anotar a localização da sua keystore e utilizar a mesma chave de assinatura para actualizações como para a instalação anterior.
Nunca actualize se o sistema estiver a funcionar bem.
Se tiver dificuldade em construir o apk, pode instalar um apk que foi construído por um amigo.
https://androidaps.readthedocs.io/en/latest/EN/Installing-AndroidAPS/Update-to-new-version.html#update-to-a-new-version-or-branch
@@ -110,7 +110,7 @@
https://www.facebook.com/groups/AndroidAPSUsers/
https://gitter.im/MilosKozak/AndroidAPS
Plugins de Insulina
- Qual insulina deve usar com o plugin Ultra-Rapid Oref?
+ Qual insulina deve utilizar com o plugin Ultra-Rapid Oref?
Fiasp®
NovoRapid®/Novolog®
Humalog ®
@@ -148,7 +148,7 @@
Se os níveis de glicose no sangue estiverem fora dos valores aceitáveis (muito baixos ou muito altos) a calculadora de bólus pode ser usada para fornecer sugestões para correções de hidratos ou insulina.
https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#insulin-to-carb-ratio-ic-g-u
hidratos-e
- Para que poderia usar os hidratos-e (hidratos estendidos)?
+ Para que poderia utilizar os hidratos-e (hidratos estendidos)?
Para agendar hidratos no futuro, possivelmente distribuídos num intervalo (semelhante a um bólus estendido que distribui insulina por um intervalo).
Para registar hidratos \'livres\' ingeridos em exercícios que deseja esconder do AndroidAPS.
Os hidratos-e (distribuídos no futuro) podem ajudar o AndroidAPS a lidar com comidas gorduras/proteínas elevadas.
@@ -169,7 +169,7 @@
A alteração do valor do FSI no seu perfil é suficiente para aplicar a mudança.
https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#insulin-sensitivity-factor-isf-mmol-l-u-or-mg-dl-u
https://androidaps.readthedocs.io/en/latest/EN/Usage/Profiles.html
- Pode usar mais de um valor para o rácio I:HC no seu perfil.
+ Pode utilizar mais de um valor para o rácio I:HC no seu perfil.
Se alterar o seu FSI no perfil, também deve mudar a taxa de I:HC.
Rácio Insulina por Hidratos de Carbono (Rácio I:HC)
Rácios I:HC mais altos levam a menos insulina administrada para uma dada quantidade de hidratos.
@@ -211,5 +211,5 @@
Facebook
Outra Medicação. Por favor, leia declaração abaixo e marque a caixa para aceitá-la.
AndroidAPS reduz as taxas de basal ou suspende a administração de insulina para aumentar a quantidade de açúcar no sangue. Os medicamentos da classe inibidores SGLT2 (gliflozins) podem evitar aumentos da glicose no sangue e, por conseguinte, podem produzir uma perigosa deficiência de insulina que leva à DKA.
-\nOs nomes comuns são: Invokana®, Forxiga®, Jardiance®, Steglatro®, Suglat®, Apleway®, Deberza®, Synjardy®, Vokanamet®, Xigduo®,\n\nPrometo pelo presente que não tomarei tal medicação ao usar o AndroidAPS ou que desactivarei o loop antes de usar tais medicamentos.
+\nOs nomes comuns são: Invokana®, Forxiga®, Jardiance®, Steglatro®, Suglat®, Apleway®, Deberza®, Synjardy®, Vokanamet®, Xigduo®,\n\nPrometo pelo presente que não tomarei tal medicação ao U«ytilizar o AndroidAPS ou que desactivarei o loop antes de usar tais medicamentos.