Merge pull request #19 from jotomo/combo-scripter-v2

jan 21
This commit is contained in:
Simon Pauwels 2018-01-21 13:28:33 +01:00 committed by GitHub
commit 4d0a226084
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 376 additions and 171 deletions

View file

@ -12,6 +12,7 @@ Hardware requirements:
Roche sends out Smartpix devices and the configuration software
free of charge to their customers upon request.
- A compatible phone: An Android phone with a phone running LineageOS 14.1 (formerly CyanogenMod) or Android 8.1 (Oreo).
Be aware that while Android 8.1 allows communicating with the Combo, there are still issues with AAPS on 8.1.
For advanced users, it is possible to perform the pairing on a rooted phone and transfer it to another rooted
phone to use with ruffy/AAPS, which must also be rooted. This allows using phones with Android < 8.1 but
has not been widely tested: https://github.com/gregorybel/combo-pairing/blob/master/README.md
@ -57,6 +58,9 @@ Setup:
- Disable end of TBR alert
- Set TBR duration step-size to 15 min
- Set low cartridge alarm to your liking
- Configure a max bolus suited for your therapy to protect against bugs in the software
- Similarly, configure maximum TBR duration as a safeguard. Allow at least 3 hours, since
the option to disconnect the pump for 3 hours sets a 0% for 3 hours.
- Enable keylock (can also be set on the pump directly, see usage section on reasoning)
- Get Android Studio 3 https://developer.android.com/studio/index.html
- Follow the link http://ruffy.AndroidAPS.org and clone via git (branch `combo-scripter-v2`)

View file

@ -56,7 +56,7 @@ android {
targetSdkVersion 23
multiDexEnabled true
versionCode 1500
version "1.56-combo-csv2-test"
version "1.57-combo-csv2-test"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", generateGitBuild()
@ -91,6 +91,7 @@ android {
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "true"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
}
openloop {
dimension "standard"
@ -104,6 +105,7 @@ android {
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
}
pumpcontrol {
dimension "standard"
@ -117,6 +119,7 @@ android {
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "true"
}
nsclient {
dimension "standard"
@ -130,6 +133,7 @@ android {
buildConfigField "boolean", "NSCLIENTOLNY", "true"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
}
g5uploader {
dimension "standard"
@ -143,6 +147,7 @@ android {
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "true"
buildConfigField "boolean", "PUMPCONTROL", "false"
}
}
compileOptions {

View file

@ -11,6 +11,7 @@ public class Config {
// PLUGINS
public static final boolean NSCLIENT = BuildConfig.NSCLIENTOLNY;
public static final boolean G5UPLOADER = BuildConfig.G5UPLOADER;
public static final boolean PUMPCONTROL = BuildConfig.PUMPCONTROL;
public static final boolean COMBO = true && BuildConfig.PUMPDRIVERS;
public static final boolean DANAR = BuildConfig.PUMPDRIVERS;

View file

@ -167,10 +167,16 @@ public class MainApp extends Application {
MainApp.getConfigBuilder().initialize();
}
NSUpload.uploadAppStart();
if (MainApp.getConfigBuilder().isClosedModeEnabled())
if (Config.NSCLIENT)
Answers.getInstance().logCustom(new CustomEvent("AppStart-NSClient"));
else if (Config.G5UPLOADER)
Answers.getInstance().logCustom(new CustomEvent("AppStart-G5Uploader"));
else if (Config.PUMPCONTROL)
Answers.getInstance().logCustom(new CustomEvent("AppStart-PumpControl"));
else if (MainApp.getConfigBuilder().isClosedModeEnabled())
Answers.getInstance().logCustom(new CustomEvent("AppStart-ClosedLoop"));
else
Answers.getInstance().logCustom(new CustomEvent("AppStart"));
Answers.getInstance().logCustom(new CustomEvent("AppStart-OpenLoop"));
new Thread(new Runnable() {
@Override
@ -225,6 +231,10 @@ public class MainApp extends Application {
return sBus;
}
public static String gs(int id) {
return sResources.getString(id);
}
public static MainApp instance() {
return sInstance;
}

View file

@ -120,7 +120,7 @@ public class Profile {
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.invalidprofile));
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.invalidprofile));
}
}
@ -386,6 +386,8 @@ public class Profile {
}
public BasalValue[] getBasalValues() {
if (basal_v == null)
basal_v = convertToSparseArray(basal);
BasalValue[] ret = new BasalValue[basal_v.size()];
for (Integer index = 0; index < basal_v.size(); index++) {

View file

@ -69,7 +69,7 @@ public class QuickWizardEntry {
return Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo();
}
public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading lastBG) {
public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading lastBG, boolean _synchronized) {
BolusWizard wizard = new BolusWizard();
//BG
@ -80,7 +80,12 @@ public class QuickWizardEntry {
// COB
double cob = 0d;
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData();
AutosensData autosensData;
if (_synchronized)
autosensData = IobCobCalculatorPlugin.getLastAutosensDataSynchronized("QuickWizard COB");
else
autosensData = IobCobCalculatorPlugin.getLastAutosensData("QuickWizard COB");
if (autosensData != null && useCOB() == YES) {
cob = autosensData.cob;
}

View file

@ -421,23 +421,6 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr
}
/*
@Override
public PumpDescription getPumpDescription() {
if (activePump != null)
return activePump.getPumpDescription();
else {
PumpDescription emptyDescription = new PumpDescription();
emptyDescription.isBolusCapable = false;
emptyDescription.isExtendedBolusCapable = false;
emptyDescription.isSetBasalProfileCapable = false;
emptyDescription.isTempBasalCapable = true; // needs to be true before real driver is selected
emptyDescription.isRefillingCapable = false;
return emptyDescription;
}
}
*/
/**
* Constraints interface
**/

View file

@ -547,7 +547,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
} else {
if (time > now) {
// data may not be calculated yet, use last data
return getLastAutosensData();
return getLastAutosensData("getAutosensData");
}
//log.debug(">>> getAutosensData Cache miss " + new Date(time).toLocaleString());
return null;
@ -556,13 +556,35 @@ public class IobCobCalculatorPlugin implements PluginBase {
}
@Nullable
public static AutosensData getLastAutosensData() {
if (autosensDataTable.size() < 1)
public static AutosensData getLastAutosensDataSynchronized(String reason) {
synchronized (dataLock) {
return getLastAutosensData(reason);
}
}
@Nullable
public static AutosensData getLastAutosensData(String reason) {
if (autosensDataTable.size() < 1) {
log.debug("AUTOSENSDATA null: autosensDataTable empty (" + reason + ")");
return null;
AutosensData data = autosensDataTable.valueAt(autosensDataTable.size() - 1);
}
AutosensData data = null;
try {
data = autosensDataTable.valueAt(autosensDataTable.size() - 1);
} catch (Exception e) {
// data can be processed on the background
// in this rare case better return null and do not block UI
// APS plugin should use getLastAutosensDataSynchronized where the blocking is not an issue
log.debug("AUTOSENSDATA null: Exception catched (" + reason + ")");
return null;
}
if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) {
log.debug("AUTOSENSDATA null: data is old (" + reason + ")");
return null;
} else {
if (data == null)
log.debug("AUTOSENSDATA null: data == null (" + " " + reason + ")");
return data;
}
}

View file

@ -55,6 +55,7 @@ import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui;
@ -151,6 +152,18 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com
});
}
@Subscribe
public void onStatusEvent(final EventAutosensCalculationFinished e) {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
calculateInsulin();
}
});
}
final private TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
@ -459,7 +472,7 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com
// COB
Double c_cob = 0d;
if (cobCheckbox.isChecked()) {
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData();
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData("Wizard COB");
if(autosensData != null) {
c_cob = autosensData.cob;

View file

@ -641,7 +641,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
final QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive();
if (quickWizardEntry != null && actualBg != null) {
quickWizardButton.setVisibility(View.VISIBLE);
final BolusWizard wizard = quickWizardEntry.doCalc(profile, tempTarget, actualBg);
final BolusWizard wizard = quickWizardEntry.doCalc(profile, tempTarget, actualBg, true);
final JSONObject boluscalcJSON = new JSONObject();
try {
@ -1136,7 +1136,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
if (quickWizardEntry != null && lastBG != null && pump.isInitialized() && !pump.isSuspended()) {
quickWizardButton.setVisibility(View.VISIBLE);
String text = quickWizardEntry.buttonText() + "\n" + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g";
BolusWizard wizard = quickWizardEntry.doCalc(profile, tempTarget, lastBG);
BolusWizard wizard = quickWizardEntry.doCalc(profile, tempTarget, lastBG, false);
text += " " + DecimalFormatter.to2Decimal(wizard.calculatedTotalInsulin) + "U";
quickWizardButton.setText(text);
if (wizard.calculatedTotalInsulin <= 0)
@ -1200,7 +1200,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// cob
if (cobView != null) { // view must not exists
String cobText = "";
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData();
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData("Overview COB");
if (autosensData != null)
cobText = (int) autosensData.cob + " g";
cobView.setText(cobText);

View file

@ -258,6 +258,7 @@ public class DanaRSService extends Service {
MainApp.bus().post(bolusingEvent);
SystemClock.sleep(1000);
}
// do not call loadEvents() directly, reconnection may be needed
ConfigBuilderPlugin.getCommandQueue().loadEvents(new Callback() {
@Override
public void run() {

View file

@ -424,6 +424,7 @@ public class DanaRv2ExecutionService extends Service {
MainApp.bus().post(bolusingEvent);
SystemClock.sleep(1000);
}
// do not call loadEvents() directly, reconnection may be needed
ConfigBuilderPlugin.getCommandQueue().loadEvents(new Callback() {
@Override
public void run() {

View file

@ -212,6 +212,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
@Override
public void getPumpStatus() {
lastDataTime = new Date();
}
@Override

View file

@ -118,7 +118,7 @@ public class SensitivityAAPSPlugin implements PluginBase, SensitivityInterface{
return new AutosensResult();
}
AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime);
AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
if (current == null) {
log.debug("No autosens data available");
return new AutosensResult();

View file

@ -118,7 +118,7 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
return new AutosensResult();
}
AutosensData current = IobCobCalculatorPlugin.getLastAutosensData();
AutosensData current = IobCobCalculatorPlugin.getLastAutosensData("SensitivityOref0"); // this is running inside lock already
if (current == null) {
log.debug("No current autosens data available");
return new AutosensResult();

View file

@ -116,7 +116,7 @@ public class SensitivityWeightedAveragePlugin implements PluginBase, Sensitivity
return new AutosensResult();
}
AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime);
AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime); // this is running inside lock already
if (current == null) {
if (Config.logAutosensData)
log.debug("No autosens data available");

View file

@ -251,7 +251,7 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
}
}
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData();
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensDataSynchronized("getMealData()");
if (autosensData != null) {
result.mealCOB = autosensData.cob;
}

View file

@ -654,7 +654,7 @@ public class WatchUpdaterService extends WearableListenerService implements
private String generateCOBString() {
String cobStringResult = "--";
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData();
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData("WatcherUpdaterService");
if (autosensData != null) {
cobStringResult = (int) autosensData.cob + "g";
}

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.queue;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
@ -37,42 +38,41 @@ import info.nightscout.androidaps.queue.commands.CommandTempBasalPercent;
/**
* Created by mike on 08.11.2017.
*
* <p>
* DATA FLOW:
* ---------
*
* <p>
* (request) - > ConfigBuilder.getCommandQueue().bolus(...)
*
* <p>
* app no longer waits for result but passes Callback
*
* <p>
* request is added to queue, if another request of the same type already exists in queue, it's removed prior adding
* but if request of the same type is currently executed (probably important only for bolus which is running long time), new request is declined
* new QueueThread is created and started if current if finished
* CommandReadStatus is added automatically before command if queue is empty
*
* <p>
* biggest change is we don't need exec pump commands in Handler because it's finished immediately
* command queueing if not realized by stacking in different Handlers and threads anymore but by internal queue with better control
*
* <p>
* QueueThread calls ConfigBuilder#connect which is passed to getActivePump().connect
* connect should be executed on background and return immediately. afterwards isConnecting() is expected to be true
*
* <p>
* while isConnecting() == true GUI is updated by posting connection progress
*
* <p>
* if connect is successful: isConnected() becomes true, isConnecting() becomes false
* CommandQueue starts calling execute() of commands. execute() is expected to be blocking (return after finish).
* callback with result is called after finish automatically
* CommandQueue starts calling execute() of commands. execute() is expected to be blocking (return after finish).
* callback with result is called after finish automatically
* if connect failed: isConnected() becomes false, isConnecting() becomes false
* connect() is called again
*
* connect() is called again
* <p>
* when queue is empty, disconnect is called
*
*/
public class CommandQueue {
private static Logger log = LoggerFactory.getLogger(CommandQueue.class);
private LinkedList<Command> queue = new LinkedList<>();
private Command performing;
protected Command performing;
private QueueThread thread = null;
@ -94,10 +94,19 @@ public class CommandQueue {
}
}
private synchronized boolean isLastScheduled(Command.CommandType type) {
if (queue.size() > 0 && queue.get(queue.size() - 1).commandType == type) {
return true;
}
return false;
}
private synchronized void inject(Command command) {
// inject as a first command
queue.addFirst(command);
}
private synchronized void add(Command command) {
// inject reading of status when adding first command to the queue
if (queue.size() == 0 && command.commandType != Command.CommandType.READSTATUS)
queue.add(new CommandReadStatus("Queue", null));
queue.add(command);
}
@ -128,7 +137,7 @@ public class CommandQueue {
// After new command added to the queue
// start thread again if not already running
private synchronized void notifyAboutNewCommand() {
protected synchronized void notifyAboutNewCommand() {
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new QueueThread(this);
thread.start();
@ -166,17 +175,7 @@ public class CommandQueue {
MainApp.bus().post(new EventBolusRequested(detailedBolusInfo.insulin));
// Bring up bolus progress dialog
if (detailedBolusInfo.context != null) {
BolusProgressDialog bolusProgressDialog = new BolusProgressDialog();
bolusProgressDialog.setInsulin(detailedBolusInfo.insulin);
bolusProgressDialog.show(((AppCompatActivity) detailedBolusInfo.context).getSupportFragmentManager(), "BolusProgress");
} else {
Intent i = new Intent();
i.putExtra("insulin", detailedBolusInfo.insulin);
i.setClass(MainApp.instance(), BolusProgressHelperActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
showBolusProgressDialog(detailedBolusInfo.insulin, detailedBolusInfo.context);
return true;
}
@ -231,7 +230,7 @@ public class CommandQueue {
return false;
}
Double rateAfterConstraints = MainApp.getConfigBuilder().applyBolusConstraints(insulin);
Double rateAfterConstraints = MainApp.getConfigBuilder().applyBolusConstraints(insulin);
// remove all unfinished
removeAll(Command.CommandType.EXTENDEDBOLUS);
@ -326,11 +325,12 @@ public class CommandQueue {
// returns true if command is queued
public boolean readStatus(String reason, Callback callback) {
//if (isRunning(Command.CommandType.READSTATUS)) {
// if (callback != null)
// callback.result(executingNowError()).run();
// return false;
//}
if (isLastScheduled(Command.CommandType.READSTATUS)) {
log.debug("QUEUE: READSTATUS " + reason + " ignored as duplicated");
if (callback != null)
callback.result(executingNowError()).run();
return false;
}
// remove all unfinished
//removeAll(Command.CommandType.READSTATUS);
@ -409,4 +409,18 @@ public class CommandQueue {
} else return true;
}
protected void showBolusProgressDialog(Double insulin, Context context) {
if (context != null) {
BolusProgressDialog bolusProgressDialog = new BolusProgressDialog();
bolusProgressDialog.setInsulin(insulin);
bolusProgressDialog.show(((AppCompatActivity) context).getSupportFragmentManager(), "BolusProgress");
} else {
Intent i = new Intent();
i.putExtra("insulin", insulin);
i.setClass(MainApp.instance(), BolusProgressHelperActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
}
}

View file

@ -29,7 +29,7 @@ public abstract class Command {
public void cancel() {
PumpEnactResult result = new PumpEnactResult();
result.success = false;
result.comment = MainApp.sResources.getString(R.string.connectiontimedout);
result.comment = MainApp.gs(R.string.connectiontimedout);
if (callback != null)
callback.result(result).run();
}

View file

@ -27,6 +27,6 @@ public class CommandReadStatus extends Command {
@Override
public String status() {
return "READSTATUS";
return "READSTATUS " + reason;
}
}

View file

@ -245,6 +245,13 @@
android:orientation="horizontal"
android:paddingTop="5dp">
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:id="@+id/overview_showprediction_label"
android:layout_width="wrap_content"
@ -255,22 +262,6 @@
android:textColor="@color/prediction"
android:textStyle="bold"/>
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showbasals"
android:layout_width="wrap_content"
@ -282,9 +273,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/iob"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iob"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
@ -298,11 +289,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/cob"
android:text="@string/iob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/cob"
android:textColor="@color/iob"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showcob"
android:layout_width="wrap_content"
@ -314,9 +306,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/dev"
android:text="@string/cob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textColor="@color/cob"
android:textStyle="bold" />
<CheckBox
@ -330,8 +322,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:text="@string/dev"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textStyle="bold" />
<CheckBox
@ -340,6 +333,14 @@
android:layout_height="wrap_content"
android:layout_gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout

View file

@ -474,6 +474,13 @@
android:orientation="horizontal"
android:paddingTop="5dp">
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:id="@+id/overview_showprediction_label"
android:layout_width="wrap_content"
@ -484,22 +491,6 @@
android:textColor="@color/prediction"
android:textStyle="bold"/>
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showbasals"
android:layout_width="wrap_content"
@ -511,9 +502,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/iob"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iob"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
@ -527,11 +518,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/cob"
android:text="@string/iob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/cob"
android:textColor="@color/iob"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showcob"
android:layout_width="wrap_content"
@ -543,9 +535,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/dev"
android:text="@string/cob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textColor="@color/cob"
android:textStyle="bold" />
<CheckBox
@ -559,8 +551,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:text="@string/dev"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textStyle="bold" />
<CheckBox
@ -569,6 +562,14 @@
android:layout_height="wrap_content"
android:layout_gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout

View file

@ -558,6 +558,13 @@
android:orientation="horizontal"
android:paddingTop="5dp">
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:id="@+id/overview_showprediction_label"
android:layout_width="wrap_content"
@ -568,22 +575,6 @@
android:textColor="@color/prediction"
android:textStyle="bold"/>
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showbasals"
android:layout_width="wrap_content"
@ -595,9 +586,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/iob"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iob"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
@ -611,11 +602,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/cob"
android:text="@string/iob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/cob"
android:textColor="@color/iob"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showcob"
android:layout_width="wrap_content"
@ -627,9 +619,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/dev"
android:text="@string/cob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textColor="@color/cob"
android:textStyle="bold" />
<CheckBox
@ -643,8 +635,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:text="@string/dev"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textStyle="bold" />
<CheckBox
@ -653,6 +646,14 @@
android:layout_height="wrap_content"
android:layout_gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout

View file

@ -240,6 +240,13 @@
android:orientation="horizontal"
android:paddingTop="5dp">
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:id="@+id/overview_showprediction_label"
android:layout_width="wrap_content"
@ -250,22 +257,6 @@
android:textColor="@color/prediction"
android:textStyle="bold"/>
<CheckBox
android:id="@+id/overview_showprediction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:buttonTint="@color/prediction" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showbasals"
android:layout_width="wrap_content"
@ -277,9 +268,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/iob"
android:text="@string/basalshortlabel"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iob"
android:textColor="@color/basal"
android:textStyle="bold" />
<CheckBox
@ -293,11 +284,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/cob"
android:text="@string/iob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/cob"
android:textColor="@color/iob"
android:textStyle="bold" />
<CheckBox
android:id="@+id/overview_showcob"
android:layout_width="wrap_content"
@ -309,9 +301,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/dev"
android:text="@string/cob"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textColor="@color/cob"
android:textStyle="bold" />
<CheckBox
@ -325,8 +317,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:text="@string/dev"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/deviations"
android:textStyle="bold" />
<CheckBox
@ -335,6 +328,14 @@
android:layout_height="wrap_content"
android:layout_gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/ratio_short"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout

View file

@ -0,0 +1,143 @@
package info.nightscout.androidaps.queue;
import android.content.Context;
import android.text.Html;
import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer;
import junit.framework.Assert;
import org.json.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.utils.ToastUtils;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Created by mike on 14.01.2018.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class})
public class CommandQueueTest extends CommandQueue {
String profileJson = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}";
@Test
public void doTests() throws Exception {
prepareMock(0d, 0);
// start with empty queue
Assert.assertEquals(0, size());
// add bolus command
bolus(new DetailedBolusInfo(), null);
Assert.assertEquals(1, size());
// add READSTATUS
readStatus("anyString", null);
Assert.assertEquals(2, size());
// adding another bolus should remove the first one (size still == 2)
bolus(new DetailedBolusInfo(), null);
Assert.assertEquals(2, size());
// clear the queue should reset size
clear();
Assert.assertEquals(0, size());
// add tempbasal
tempBasalAbsolute(0, 30, true, null);
Assert.assertEquals(1, size());
// add tempbasal percent. it should replace previous TEMPBASAL
tempBasalPercent(0, 30, true, null);
Assert.assertEquals(1, size());
// add extended bolus
extendedBolus(1, 30, null);
Assert.assertEquals(2, size());
// add cancel temp basal should remove previous 2 temp basal setting
extendedBolus(1, 30, null);
Assert.assertEquals(2, size());
// cancel extended bolus should replace previous extended
extendedBolus(1, 30, null);
Assert.assertEquals(2, size());
// add setProfile
setProfile(new Profile(new JSONObject(profileJson), Constants.MGDL), null);
Assert.assertEquals(3, size());
// add loadHistory
loadHistory((byte) 0, null);
Assert.assertEquals(4, size());
// add loadEvents
loadEvents(null);
Assert.assertEquals(5, size());
clear();
tempBasalAbsolute(0, 30, true, null);
pickup();
Assert.assertEquals(0, size());
Assert.assertNotNull(performing);
Assert.assertEquals(Command.CommandType.TEMPBASAL, performing.commandType);
resetPerforming();
Assert.assertNull(performing);
}
private void prepareMock(Double insulin, Integer carbs) throws Exception {
ConfigBuilderPlugin configBuilderPlugin = mock(ConfigBuilderPlugin.class);
when(configBuilderPlugin.applyBolusConstraints(insulin)).thenReturn(insulin);
when(configBuilderPlugin.applyCarbsConstraints(carbs)).thenReturn(carbs);
PowerMockito.mockStatic(ConfigBuilderPlugin.class);
PumpInterface pump = MDIPlugin.getPlugin();
when(ConfigBuilderPlugin.getActivePump()).thenReturn(pump);
PowerMockito.mockStatic(MainApp.class);
MainApp mainApp = mock(MainApp.class);
when(MainApp.getConfigBuilder()).thenReturn(configBuilderPlugin);
when(MainApp.instance()).thenReturn(mainApp);
PowerMockito.mockStatic(ToastUtils.class);
Context context = mock(Context.class);
String message = null;
PowerMockito.doNothing().when(ToastUtils.class, "showToastInUiThread", context, message);
Bus bus = new Bus(ThreadEnforcer.ANY);
when(MainApp.bus()).thenReturn(bus);
when(MainApp.gs(0)).thenReturn("");
}
@Override
protected synchronized void notifyAboutNewCommand() {
}
@Override
protected void showBolusProgressDialog(Double insulin, Context context) {
}
@Override
public boolean isThisProfileSet(Profile profile) {
return false;
}
}

View file

@ -39,8 +39,8 @@ public class BolusCommand extends BaseCommand {
public List<String> validateArguments() {
List<String> violations = new ArrayList<>();
if (bolus <= 0 || bolus > 25) {
violations.add("Requested bolus " + bolus + " out of limits (0-25)");
if (bolus <= 0) {
violations.add("Requested bolus non-positive: " + bolus);
}
return violations;

View file

@ -47,10 +47,6 @@ public class SetTbrCommand extends BaseCommand {
}
}
if (percentage == 0 && duration > 180) {
violations.add("Max allowed zero-temp duration is 3h");
}
return violations;
}