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..91ced93606
--- /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..97a6079e4a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt
@@ -0,0 +1,172 @@
+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.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 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: TreatmentsPlugin,
+ 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..f1245810f0
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt
@@ -0,0 +1,202 @@
+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.plugins.treatments.TreatmentsPlugin
+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: TreatmentsPlugin,
+ 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