This commit is contained in:
Milos Kozak 2018-01-29 13:28:36 +01:00
commit 1eba5b79b8
41 changed files with 1441 additions and 2377 deletions

View file

@ -7,12 +7,15 @@ android:
components:
- platform-tools
- tools
- build-tools-26.0.2
- build-tools-27.0.2
- android-23
- extra-google-m2repository
- extra-android-m2repository
- extra-google-google_play_services
before_install:
- yes | sdkmanager "platforms;android-27"
script:
# Unit Test
- ./gradlew test jacocoTestReport

View file

@ -12,9 +12,10 @@ buildscript {
apply plugin: "com.android.application"
apply plugin: "io.fabric"
apply plugin: "jacoco-android"
apply plugin: 'com.jakewharton.butterknife'
ext {
supportLibraryVersion = "23.4.0"
supportLibraryVersion = "27.0.2"
ormLiteVersion = "4.46"
powermockVersion = "1.7.3"
dexmakerVersion = "1.2"
@ -47,8 +48,8 @@ def generateGitBuild = { ->
}
android {
compileSdkVersion 23
buildToolsVersion "26.0.2"
compileSdkVersion 27
buildToolsVersion "${supportLibraryVersion}"
defaultConfig {
applicationId "info.nightscout.androidaps"
@ -65,6 +66,13 @@ android {
}
}
lintOptions {
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0
// has been upgraded (requiring significant code changes), which currently fails release
// build with a deprecation warning
//abortOnError false
// (disabled entirely to avoid reports on the error, which would still be displayed
// and it's easy to overlook that it's ignored)
checkReleaseBuilds false
disable 'MissingTranslation'
disable 'ExtraTranslation'
}
@ -204,6 +212,9 @@ dependencies {
compile "net.danlew:android.joda:2.9.9.1"
api "com.jakewharton:butterknife:8.8.1"
annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"
testCompile "junit:junit:4.12"
testCompile "org.json:json:20140107"
testCompile "org.mockito:mockito-core:2.7.22"

View file

@ -233,6 +233,10 @@ public class MainApp extends Application {
return sResources.getString(id);
}
public static String gs(int id, Object... args) {
return sResources.getString(id, args);
}
public static MainApp instance() {
return sInstance;
}

View file

@ -35,4 +35,6 @@ public class PumpDescription {
public double basalMinimumRate = 0.04d;
public boolean isRefillingCapable = false;
public boolean storesCarbInfo = true;
}

View file

@ -2,9 +2,12 @@ package info.nightscout.androidaps.plugins.Common;
import android.support.v4.app.Fragment;
import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp;
abstract public class SubscriberFragment extends Fragment {
protected Unbinder unbinder;
@Override
public void onPause() {
super.onPause();
@ -18,5 +21,12 @@ abstract public class SubscriberFragment extends Fragment {
updateGUI();
}
@Override public void onDestroyView() {
super.onDestroyView();
if (unbinder != null)
unbinder.unbind();
}
protected abstract void updateGUI();
}

View file

@ -6,7 +6,7 @@ import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.NotificationCompat;
import android.support.v4.app.NotificationCompat;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent;

View file

@ -159,19 +159,23 @@ public class NewTreatmentDialog extends DialogFragment implements OnClickListene
detailedBolusInfo.carbs = finalCarbsAfterConstraints;
detailedBolusInfo.context = context;
detailedBolusInfo.source = Source.USER;
ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
if (detailedBolusInfo.insulin > 0 || ConfigBuilderPlugin.getActivePump().getPumpDescription().storesCarbInfo) {
ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
}
}
});
});
} else {
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
}
Answers.getInstance().logCustom(new CustomEvent("Bolus"));
}
}

View file

@ -365,19 +365,23 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com
detailedBolusInfo.carbTime = carbTime;
detailedBolusInfo.boluscalc = boluscalcJSON;
detailedBolusInfo.source = Source.USER;
ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
if (detailedBolusInfo.insulin > 0 || ConfigBuilderPlugin.getActivePump().getPumpDescription().storesCarbInfo) {
ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
}
}
});
});
} else {
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
}
Answers.getInstance().logCustom(new CustomEvent("Wizard"));
}
}

View file

@ -7,7 +7,7 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.NotificationCompat;
import android.support.v4.app.NotificationCompat;
import com.squareup.otto.Subscribe;

View file

@ -0,0 +1,557 @@
package info.nightscout.androidaps.plugins.PumpDanaR;
import android.support.annotation.Nullable;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.DanaRInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractDanaRExecutionService;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
/**
* Created by mike on 28.01.2018.
*/
public abstract class AbstractDanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
protected Logger log;
protected boolean mPluginPumpEnabled = false;
protected boolean mPluginProfileEnabled = false;
protected boolean mFragmentPumpVisible = true;
protected AbstractDanaRExecutionService sExecutionService;
protected DanaRPump pump = DanaRPump.getInstance();
protected boolean useExtendedBoluses = false;
public PumpDescription pumpDescription = new PumpDescription();
@Override
public String getFragmentClass() {
return DanaRFragment.class.getName();
}
// Plugin base interface
@Override
public int getType() {
return PluginBase.PUMP;
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.danarpump_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
if (type == PluginBase.PROFILE) return mPluginProfileEnabled && mPluginPumpEnabled;
else if (type == PluginBase.PUMP) return mPluginPumpEnabled;
else if (type == PluginBase.CONSTRAINTS) return mPluginPumpEnabled;
return false;
}
@Override
public boolean isVisibleInTabs(int type) {
if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
else if (type == PluginBase.PUMP) return mFragmentPumpVisible;
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return type == PUMP;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == PluginBase.PROFILE)
mPluginProfileEnabled = fragmentEnabled;
else if (type == PluginBase.PUMP)
mPluginPumpEnabled = fragmentEnabled;
// if pump profile was enabled need to switch to another too
if (type == PluginBase.PUMP && !fragmentEnabled && mPluginProfileEnabled) {
setFragmentEnabled(PluginBase.PROFILE, false);
setFragmentVisible(PluginBase.PROFILE, false);
NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
}
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == PluginBase.PUMP)
mFragmentPumpVisible = fragmentVisible;
}
@Override
public boolean isSuspended() {
return pump.pumpSuspended;
}
@Override
public boolean isBusy() {
if (sExecutionService == null) return false;
return sExecutionService.isConnected() || sExecutionService.isConnecting();
}
// Pump interface
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
PumpEnactResult result = new PumpEnactResult();
if (sExecutionService == null) {
log.error("setNewBasalProfile sExecutionService is null");
result.comment = "setNewBasalProfile sExecutionService is null";
return result;
}
if (!isInitialized()) {
log.error("setNewBasalProfile not initialized");
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
}
if (!sExecutionService.updateBasalsInPump(profile)) {
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.sResources.getString(R.string.profile_set_ok), Notification.INFO, 60);
MainApp.bus().post(new EventNewNotification(notification));
result.success = true;
result.enacted = true;
result.comment = "OK";
return result;
}
}
@Override
public boolean isThisProfileSet(Profile profile) {
if (!isInitialized())
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
if (pump.pumpProfiles == null)
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
int basalValues = pump.basal48Enable ? 48 : 24;
int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
if (profileValue == null) return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
return false;
}
}
return true;
}
@Override
public Date lastDataTime() {
return new Date(pump.lastConnection);
}
@Override
public double getBaseBasalRate() {
return pump.currentBasal;
}
@Override
public void stopBolusDelivering() {
if (sExecutionService == null) {
log.error("stopBolusDelivering sExecutionService is null");
return;
}
sExecutionService.bolusStop();
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult();
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
percent = configBuilderPlugin.applyBasalConstraints(percent);
if (percent < 0) {
result.isTempCancel = false;
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
log.error("setTempBasalPercent: Invalid input");
return result;
}
if (percent > getPumpDescription().maxTempPercent)
percent = getPumpDescription().maxTempPercent;
TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
if (runningTB != null && runningTB.percentRate == percent && !enforceNew) {
result.enacted = false;
result.success = true;
result.isTempCancel = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = pump.tempBasalRemainingMin;
result.percent = pump.tempBasalPercent;
result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: Correct value already set");
return result;
}
int durationInHours = Math.max(durationInMinutes / 60, 1);
boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = pump.tempBasalRemainingMin;
result.percent = pump.tempBasalPercent;
result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.tempbasaldeliveryerror);
log.error("setTempBasalPercent: Failed to set temp basal");
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
insulin = configBuilderPlugin.applyBolusConstraints(insulin);
// needs to be rounded
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = false;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.isPercent = false;
result.isTempCancel = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
return result;
}
boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.bolusDelivered = pump.extendedBolusAmount;
result.isPercent = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("setExtendedBolus: Failed to extended bolus");
return result;
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null) {
sExecutionService.extendedBolusStop();
result.enacted = true;
result.isTempCancel = true;
}
if (!pump.isExtendedInProgress) {
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpActions)
log.debug("cancelExtendedBolus: OK");
return result;
} else {
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("cancelExtendedBolus: Failed to cancel extended bolus");
return result;
}
}
@Override
public void connect(String from) {
if (sExecutionService != null) {
sExecutionService.connect();
pumpDescription.basalStep = pump.basalStep;
pumpDescription.bolusStep = pump.bolusStep;
}
}
@Override
public boolean isConnected() {
return sExecutionService != null && sExecutionService.isConnected();
}
@Override
public boolean isConnecting() {
return sExecutionService != null && sExecutionService.isConnecting();
}
@Override
public void disconnect(String from) {
if (sExecutionService != null) sExecutionService.disconnect(from);
}
@Override
public void stopConnecting() {
if (sExecutionService != null) sExecutionService.stopConnecting();
}
@Override
public void getPumpStatus() {
if (sExecutionService != null) sExecutionService.getPumpStatus();
}
@Override
public JSONObject getJSONStatus() {
if (pump.lastConnection + 5 * 60 * 1000L < System.currentTimeMillis()) {
return null;
}
JSONObject pumpjson = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
battery.put("percent", pump.batteryRemaining);
status.put("status", pump.pumpSuspended ? "suspended" : "normal");
status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
extended.put("PumpIOB", pump.iob);
if (pump.lastBolusTime.getTime() != 0) {
extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
extended.put("LastBolusAmount", pump.lastBolusAmount);
}
TemporaryBasal tb = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
if (tb != null) {
extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
}
ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (eb != null) {
extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
}
extended.put("BaseBasalRate", getBaseBasalRate());
try {
extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
} catch (Exception e) {
}
pumpjson.put("battery", battery);
pumpjson.put("status", status);
pumpjson.put("extended", extended);
pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
pumpjson.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return pumpjson;
}
@Override
public String deviceID() {
return pump.serialNumber;
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
/**
* DanaR interface
*/
@Override
public PumpEnactResult loadHistory(byte type) {
return sExecutionService.loadHistory(type);
}
/**
* Constraint interface
*/
@Override
public boolean isLoopEnabled() {
return true;
}
@Override
public boolean isClosedModeEnabled() {
return true;
}
@Override
public boolean isAutosensModeEnabled() {
return true;
}
@Override
public boolean isAMAModeEnabled() {
return true;
}
@Override
public boolean isSMBModeEnabled() {
return true;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBasalConstraints(Double absoluteRate) {
double origAbsoluteRate = absoluteRate;
if (pump != null) {
if (absoluteRate > pump.maxBasal) {
absoluteRate = pump.maxBasal;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
}
}
return absoluteRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Integer applyBasalConstraints(Integer percentRate) {
Integer origPercentRate = percentRate;
if (percentRate < 0) percentRate = 0;
if (percentRate > getPumpDescription().maxTempPercent)
percentRate = getPumpDescription().maxTempPercent;
if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
return percentRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBolusConstraints(Double insulin) {
double origInsulin = insulin;
if (pump != null) {
if (insulin > pump.maxBolus) {
insulin = pump.maxBolus;
if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
}
}
return insulin;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
@Nullable
@Override
public ProfileStore getProfile() {
if (pump.lastSettingsRead == 0)
return null; // no info now
return pump.createConvertedProfile();
}
@Override
public String getUnits() {
return pump.getUnits();
}
@Override
public String getProfileName() {
return pump.createConvertedProfileName();
}
// Reply for sms communicator
public String shortStatus(boolean veryShort) {
String ret = "";
if (pump.lastConnection != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (pump.lastBolusTime.getTime() != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
ret += "Temp: " + MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
}
if (!veryShort) {
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
}
ret += "IOB: " + pump.iob + "U\n";
ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
ret += "Batt: " + pump.batteryRemaining + "\n";
return ret;
}
// TODO: daily total constraint
}

View file

@ -21,6 +21,12 @@ import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventExtendedBolusChange;
@ -49,27 +55,24 @@ public class DanaRFragment extends SubscriberFragment {
}
};
TextView lastConnectionView;
TextView btConnectionView;
TextView lastBolusView;
TextView dailyUnitsView;
TextView basaBasalRateView;
TextView tempBasalView;
TextView extendedBolusView;
TextView batteryView;
TextView reservoirView;
TextView iobView;
TextView firmwareView;
TextView basalStepView;
TextView bolusStepView;
TextView serialNumberView;
TextView queueView;
Button viewProfileButton;
Button historyButton;
Button statsButton;
@BindView(R.id.danar_lastconnection) TextView lastConnectionView;
@BindView(R.id.danar_btconnection) TextView btConnectionView;
@BindView(R.id.danar_lastbolus) TextView lastBolusView;
@BindView(R.id.danar_dailyunits) TextView dailyUnitsView;
@BindView(R.id.danar_basabasalrate) TextView basaBasalRateView;
@BindView(R.id.danar_tempbasal) TextView tempBasalView;
@BindView(R.id.danar_extendedbolus) TextView extendedBolusView;
@BindView(R.id.danar_battery) TextView batteryView;
@BindView(R.id.danar_reservoir) TextView reservoirView;
@BindView(R.id.danar_iob) TextView iobView;
@BindView(R.id.danar_firmware) TextView firmwareView;
@BindView(R.id.danar_basalstep) TextView basalStepView;
@BindView(R.id.danar_bolusstep) TextView bolusStepView;
@BindView(R.id.danar_serialnumber) TextView serialNumberView;
@BindView(R.id.danar_queue) TextView queueView;
LinearLayout pumpStatusLayout;
TextView pumpStatusView;
@BindView(R.id.overview_pumpstatuslayout) LinearLayout pumpStatusLayout;
@BindView(R.id.overview_pumpstatus) TextView pumpStatusView;
public DanaRFragment() {
}
@ -91,61 +94,10 @@ public class DanaRFragment extends SubscriberFragment {
Bundle savedInstanceState) {
try {
View view = inflater.inflate(R.layout.danar_fragment, container, false);
btConnectionView = (TextView) view.findViewById(R.id.danar_btconnection);
lastConnectionView = (TextView) view.findViewById(R.id.danar_lastconnection);
lastBolusView = (TextView) view.findViewById(R.id.danar_lastbolus);
dailyUnitsView = (TextView) view.findViewById(R.id.danar_dailyunits);
basaBasalRateView = (TextView) view.findViewById(R.id.danar_basabasalrate);
tempBasalView = (TextView) view.findViewById(R.id.danar_tempbasal);
extendedBolusView = (TextView) view.findViewById(R.id.danar_extendedbolus);
batteryView = (TextView) view.findViewById(R.id.danar_battery);
reservoirView = (TextView) view.findViewById(R.id.danar_reservoir);
iobView = (TextView) view.findViewById(R.id.danar_iob);
firmwareView = (TextView) view.findViewById(R.id.danar_firmware);
viewProfileButton = (Button) view.findViewById(R.id.danar_viewprofile);
historyButton = (Button) view.findViewById(R.id.danar_history);
statsButton = (Button) view.findViewById(R.id.danar_stats);
basalStepView = (TextView) view.findViewById(R.id.danar_basalstep);
bolusStepView = (TextView) view.findViewById(R.id.danar_bolusstep);
serialNumberView = (TextView) view.findViewById(R.id.danar_serialnumber);
queueView = (TextView) view.findViewById(R.id.danar_queue);
unbinder = ButterKnife.bind(this, view);
pumpStatusView = (TextView) view.findViewById(R.id.overview_pumpstatus);
pumpStatusView.setBackgroundColor(MainApp.sResources.getColor(R.color.colorInitializingBorder));
pumpStatusLayout = (LinearLayout) view.findViewById(R.id.overview_pumpstatuslayout);
viewProfileButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager manager = getFragmentManager();
ProfileViewDialog profileViewDialog = new ProfileViewDialog();
profileViewDialog.show(manager, "ProfileViewDialog");
}
});
historyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
}
});
statsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getContext(), DanaRStatsActivity.class));
}
});
btConnectionView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
log.debug("Clicked connect to pump");
ConfigBuilderPlugin.getCommandQueue().readStatus("Clicked connect to pump", null);
}
});
updateGUI();
return view;
} catch (Exception e) {
Crashlytics.logException(e);
@ -154,6 +106,26 @@ public class DanaRFragment extends SubscriberFragment {
return null;
}
@OnClick(R.id.danar_history) void onHistoryClick() {
startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
}
@OnClick(R.id.danar_viewprofile) void onViewProfileClick() {
FragmentManager manager = getFragmentManager();
ProfileViewDialog profileViewDialog = new ProfileViewDialog();
profileViewDialog.show(manager, "ProfileViewDialog");
}
@OnClick(R.id.danar_stats) void onStatsClick() {
startActivity(new Intent(getContext(), DanaRStatsActivity.class));
}
@OnClick(R.id.danar_btconnection) void onBtConnectionClick() {
log.debug("Clicked connect to pump");
DanaRPump.getInstance().lastConnection = 0;
ConfigBuilderPlugin.getCommandQueue().readStatus("Clicked connect to pump", null);
}
@Subscribe
public void onStatusEvent(final EventPumpStatusChanged c) {
Activity activity = getActivity();
@ -212,8 +184,8 @@ public class DanaRFragment extends SubscriberFragment {
@Override
public void run() {
DanaRPump pump = DanaRPump.getInstance();
if (pump.lastConnection.getTime() != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
if (pump.lastConnection != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
int agoMin = (int) (agoMsec / 60d / 1000d);
lastConnectionView.setText(DateUtil.timeString(pump.lastConnection) + " (" + String.format(MainApp.sResources.getString(R.string.minago), agoMin) + ")");
SetWarnColor.setColor(lastConnectionView, agoMin, 16d, 31d);

View file

@ -5,69 +5,30 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.DanaRInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
/**
* Created by mike on 05.08.2016.
*/
public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
private static Logger log = LoggerFactory.getLogger(DanaRPlugin.class);
@Override
public String getFragmentClass() {
return DanaRFragment.class.getName();
}
private static boolean fragmentPumpEnabled = false;
private static boolean fragmentProfileEnabled = false;
private static boolean fragmentPumpVisible = true;
private static DanaRExecutionService sExecutionService;
private static DanaRPump pump = DanaRPump.getInstance();
private static boolean useExtendedBoluses = false;
public class DanaRPlugin extends AbstractDanaRPlugin {
private static DanaRPlugin plugin = null;
@ -77,9 +38,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
return plugin;
}
public static PumpDescription pumpDescription = new PumpDescription();
public DanaRPlugin() {
log = LoggerFactory.getLogger(DanaRPlugin.class);
useExtendedBoluses = SP.getBoolean("danar_useextended", false);
Context context = MainApp.instance().getApplicationContext();
@ -110,6 +70,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
pumpDescription.basalMinimumRate = 0.04d;
pumpDescription.isRefillingCapable = true;
pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@ -145,83 +107,17 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
}
// Plugin base interface
@Override
public int getType() {
return PluginBase.PUMP;
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.danarpump);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.danarpump_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
return false;
}
@Override
public boolean isVisibleInTabs(int type) {
if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
else if (type == PluginBase.PUMP) return fragmentPumpVisible;
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return type == PUMP;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == PluginBase.PROFILE)
fragmentProfileEnabled = fragmentEnabled;
else if (type == PluginBase.PUMP)
fragmentPumpEnabled = fragmentEnabled;
// if pump profile was enabled need to switch to another too
if (type == PluginBase.PUMP && !fragmentEnabled && fragmentProfileEnabled) {
setFragmentEnabled(PluginBase.PROFILE, false);
setFragmentVisible(PluginBase.PROFILE, false);
NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
}
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == PluginBase.PUMP)
fragmentPumpVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_danar;
}
// Pump interface
@Override
public boolean isFakingTempsByExtendedBoluses() {
return useExtendedBoluses;
@ -229,82 +125,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
@Override
public boolean isInitialized() {
return pump.lastConnection.getTime() > 0 && pump.isExtendedBolusEnabled && pump.maxBasal > 0;
}
@Override
public boolean isSuspended() {
return pump.pumpSuspended;
}
@Override
public boolean isBusy() {
if (sExecutionService == null) return false;
return sExecutionService.isConnected() || sExecutionService.isConnecting();
}
// Pump interface
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
PumpEnactResult result = new PumpEnactResult();
if (sExecutionService == null) {
log.error("setNewBasalProfile sExecutionService is null");
result.comment = "setNewBasalProfile sExecutionService is null";
return result;
}
if (!isInitialized()) {
log.error("setNewBasalProfile not initialized");
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
}
if (!sExecutionService.updateBasalsInPump(profile)) {
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
result.success = true;
result.enacted = true;
result.comment = "OK";
return result;
}
}
@Override
public boolean isThisProfileSet(Profile profile) {
if (!isInitialized())
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
if (pump.pumpProfiles == null)
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
int basalValues = pump.basal48Enable ? 48 : 24;
int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
if (profileValue == null) return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
return false;
}
}
return true;
}
@Override
public Date lastDataTime() {
return pump.lastConnection;
}
@Override
public double getBaseBasalRate() {
return pump.currentBasal;
return pump.lastConnection > 0 && pump.isExtendedBolusEnabled && pump.maxBasal > 0;
}
@Override
@ -314,7 +135,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
Treatment t = new Treatment();
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, t);
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, detailedBolusInfo.carbTime, t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@ -337,15 +158,6 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
}
}
@Override
public void stopBolusDelivering() {
if (sExecutionService == null) {
log.error("stopBolusDelivering sExecutionService is null");
return;
}
sExecutionService.bolusStop();
}
// This is called from APS
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) {
@ -498,100 +310,6 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
return result;
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult();
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
percent = configBuilderPlugin.applyBasalConstraints(percent);
if (percent < 0) {
result.isTempCancel = false;
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
log.error("setTempBasalPercent: Invalid input");
return result;
}
if (percent > getPumpDescription().maxTempPercent)
percent = getPumpDescription().maxTempPercent;
TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
if (runningTB != null && runningTB.percentRate == percent && !enforceNew) {
result.enacted = false;
result.success = true;
result.isTempCancel = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = pump.tempBasalRemainingMin;
result.percent = pump.tempBasalPercent;
result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: Correct value already set");
return result;
}
int durationInHours = Math.max(durationInMinutes / 60, 1);
boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = pump.tempBasalRemainingMin;
result.percent = pump.tempBasalPercent;
result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.tempbasaldeliveryerror);
log.error("setTempBasalPercent: Failed to set temp basal");
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
insulin = configBuilderPlugin.applyBolusConstraints(insulin);
// needs to be rounded
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = false;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.isPercent = false;
result.isTempCancel = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
return result;
}
boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.bolusDelivered = pump.extendedBolusAmount;
result.isPercent = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("setExtendedBolus: Failed to extended bolus");
return result;
}
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress())
@ -632,257 +350,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C
}
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null) {
sExecutionService.extendedBolusStop();
result.enacted = true;
result.isTempCancel = true;
}
if (!pump.isExtendedInProgress) {
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpActions)
log.debug("cancelExtendedBolus: OK");
return result;
} else {
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("cancelExtendedBolus: Failed to cancel extended bolus");
return result;
}
}
@Override
public void connect(String from) {
if (sExecutionService != null) {
sExecutionService.connect(from);
pumpDescription.basalStep = pump.basalStep;
pumpDescription.bolusStep = pump.bolusStep;
}
}
@Override
public boolean isConnected() {
return sExecutionService != null && sExecutionService.isConnected();
}
@Override
public boolean isConnecting() {
return sExecutionService != null && sExecutionService.isConnecting();
}
@Override
public void disconnect(String from) {
if (sExecutionService != null) sExecutionService.disconnect(from);
}
@Override
public void stopConnecting() {
if (sExecutionService != null) sExecutionService.stopConnecting();
}
@Override
public void getPumpStatus() {
if (sExecutionService != null) sExecutionService.getPumpStatus();
}
@Override
public JSONObject getJSONStatus() {
if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
return null;
}
JSONObject pumpjson = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
battery.put("percent", pump.batteryRemaining);
status.put("status", pump.pumpSuspended ? "suspended" : "normal");
status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
extended.put("PumpIOB", pump.iob);
if (pump.lastBolusTime.getTime() != 0) {
extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
extended.put("LastBolusAmount", pump.lastBolusAmount);
}
TemporaryBasal tb = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
if (tb != null) {
extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
}
ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (eb != null) {
extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
}
extended.put("BaseBasalRate", getBaseBasalRate());
try {
extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
} catch (Exception e) {
}
pumpjson.put("battery", battery);
pumpjson.put("status", status);
pumpjson.put("extended", extended);
pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
pumpjson.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return pumpjson;
}
@Override
public String deviceID() {
return pump.serialNumber;
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
/**
* DanaR interface
*/
@Override
public PumpEnactResult loadHistory(byte type) {
return sExecutionService.loadHistory(type);
}
@Override
public PumpEnactResult loadEvents() {
return null; // no history, not needed
}
/**
* Constraint interface
*/
@Override
public boolean isLoopEnabled() {
return true;
}
@Override
public boolean isClosedModeEnabled() {
return true;
}
@Override
public boolean isAutosensModeEnabled() {
return true;
}
@Override
public boolean isAMAModeEnabled() {
return true;
}
@Override
public boolean isSMBModeEnabled() {
return true;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBasalConstraints(Double absoluteRate) {
double origAbsoluteRate = absoluteRate;
if (pump != null) {
if (absoluteRate > pump.maxBasal) {
absoluteRate = pump.maxBasal;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
}
}
return absoluteRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Integer applyBasalConstraints(Integer percentRate) {
Integer origPercentRate = percentRate;
if (percentRate < 0) percentRate = 0;
if (percentRate > getPumpDescription().maxTempPercent)
percentRate = getPumpDescription().maxTempPercent;
if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
return percentRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBolusConstraints(Double insulin) {
double origInsulin = insulin;
if (pump != null) {
if (insulin > pump.maxBolus) {
insulin = pump.maxBolus;
if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
}
}
return insulin;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
@Nullable
@Override
public ProfileStore getProfile() {
if (pump.lastSettingsRead.getTime() == 0)
return null; // no info now
return pump.createConvertedProfile();
}
@Override
public String getUnits() {
return pump.getUnits();
}
@Override
public String getProfileName() {
return pump.createConvertedProfileName();
}
// Reply for sms communicator
public String shortStatus(boolean veryShort) {
String ret = "";
if (pump.lastConnection.getTime() != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (pump.lastBolusTime.getTime() != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
ret += "Temp: " + MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
}
if (!veryShort) {
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
}
ret += "IOB: " + pump.iob + "U\n";
ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
ret += "Batt: " + pump.batteryRemaining + "\n";
return ret;
}
// TODO: daily total constraint
}

View file

@ -56,8 +56,8 @@ public class DanaRPump {
public static final int CARBS = 14;
public static final int PRIMECANNULA = 15;
public Date lastConnection = new Date(0);
public Date lastSettingsRead = new Date(0);
public long lastConnection = 0;
public long lastSettingsRead =0;
// Info
public String serialNumber = "";

View file

@ -13,12 +13,13 @@ import java.io.OutputStream;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageHashTable;
import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractSerialIOThread;
import info.nightscout.utils.CRC;
/**
* Created by mike on 17.07.2016.
*/
public class SerialIOThread extends Thread {
public class SerialIOThread extends AbstractSerialIOThread {
private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
private InputStream mInputStream = null;
@ -28,10 +29,10 @@ public class SerialIOThread extends Thread {
private boolean mKeepRunning = true;
private byte[] mReadBuff = new byte[0];
MessageBase processedMessage;
private MessageBase processedMessage;
public SerialIOThread(BluetoothSocket rfcommSocket) {
super(SerialIOThread.class.toString());
super();
mRfCommSocket = rfcommSocket;
try {
@ -137,6 +138,7 @@ public class SerialIOThread extends Thread {
}
}
@Override
public synchronized void sendMessage(MessageBase message) {
if (!mRfCommSocket.isConnected()) {
log.error("Socket not connected on sendMessage");
@ -172,6 +174,7 @@ public class SerialIOThread extends Thread {
}
}
@Override
public void disconnect(String reason) {
mKeepRunning = false;
try {

View file

@ -35,8 +35,8 @@ public class MsgInitConnStatusTime extends MessageBase {
MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).setFragmentVisible(PluginBase.PUMP, true);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentEnabled(PluginBase.PUMP, false);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentVisible(PluginBase.PUMP, false);
DanaRPump.getInstance().lastConnection = new Date(0); // mark not initialized
DanaRPump.getInstance().lastConnection = 0; // mark not initialized
//If profile coming from pump, switch it as well
if(MainApp.getSpecificPlugin(DanaRPlugin.class).isEnabled(PluginBase.PROFILE)){
(MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentEnabled(PluginBase.PROFILE, false);

View file

@ -23,7 +23,7 @@ public class MsgSettingBasal extends MessageBase {
pump.pumpProfiles[pump.activeProfile] = new double[24];
for (int index = 0; index < 24; index++) {
int basal = intFromBuff(bytes, 2 * index, 2);
if (basal < DanaRPlugin.pumpDescription.basalMinimumRate) basal = 0;
if (basal < DanaRPlugin.getPlugin().pumpDescription.basalMinimumRate) basal = 0;
pump.pumpProfiles[pump.activeProfile][index] = basal / 100d;
}

View file

@ -6,10 +6,12 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
/**
* Created by mike on 13.12.2016.
@ -40,6 +42,11 @@ public class MsgSettingMeal extends MessageBase {
log.debug("Is Config U/d: " + pump.isConfigUD);
}
// DanaRKorean is not possible to set to 0.01 but it works when controlled from AAPS
if (DanaRKoreanPlugin.getPlugin().isEnabled(PluginBase.PUMP)) {
pump.basalStep = 0.01d;
}
if (pump.basalStep != 0.01d) {
Notification notification = new Notification(Notification.WRONGBASALSTEP, MainApp.sResources.getString(R.string.danar_setbasalstep001), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));

View file

@ -0,0 +1,225 @@
package info.nightscout.androidaps.plugins.PumpDanaR.services;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import org.slf4j.Logger;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.SerialIOThread;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryAlarm;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBasalHour;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBolus;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryCarbo;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDailyInsulin;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDone;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryError;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryGlucose;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryRefill;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistorySuspend;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
/**
* Created by mike on 28.01.2018.
*/
public abstract class AbstractDanaRExecutionService extends Service {
protected Logger log;
protected String mDevName;
protected BluetoothSocket mRfcommSocket;
protected BluetoothDevice mBTDevice;
protected DanaRPump mDanaRPump = DanaRPump.getInstance();
protected Treatment mBolusingTreatment = null;
protected Boolean mConnectionInProgress = false;
protected AbstractSerialIOThread mSerialIOThread;
protected IBinder mBinder;
protected final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
public abstract boolean updateBasalsInPump(final Profile profile);
public abstract void connect();
public abstract void getPumpStatus();
public abstract PumpEnactResult loadEvents();
public abstract boolean bolus(double amount, int carbs, long carbtime, final Treatment t);
public abstract boolean highTempBasal(int percent); // Rv2 only
public abstract boolean tempBasal(int percent, int durationInHours);
public abstract boolean tempBasalStop();
public abstract boolean extendedBolus(double insulin, int durationInHalfHours);
public abstract boolean extendedBolusStop();
protected BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
log.debug("Device was disconnected " + device.getName());//Device was disconnected
if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
if (mSerialIOThread != null) {
mSerialIOThread.disconnect("BT disconnection broadcast");
}
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
}
}
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public boolean isConnected() {
return mRfcommSocket != null && mRfcommSocket.isConnected();
}
public boolean isConnecting() {
return mConnectionInProgress;
}
public void disconnect(String from) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect(from);
}
public void stopConnecting() {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("stopConnecting");
}
protected void getBTSocketForSelectedPump() {
mDevName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
if (mDevName.equals(device.getName())) {
mBTDevice = device;
try {
mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
log.error("Error creating socket: ", e);
}
break;
}
}
} else {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
}
if (mBTDevice == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
}
}
public void bolusStop() {
if (Config.logDanaBTComm)
log.debug("bolusStop >>>>> @ " + (mBolusingTreatment == null ? "" : mBolusingTreatment.insulin));
MsgBolusStop stop = new MsgBolusStop();
stop.forced = true;
if (isConnected()) {
mSerialIOThread.sendMessage(stop);
while (!stop.stopped) {
mSerialIOThread.sendMessage(stop);
SystemClock.sleep(200);
}
} else {
stop.stopped = true;
}
}
public PumpEnactResult loadHistory(byte type) {
PumpEnactResult result = new PumpEnactResult();
if (!isConnected()) return result;
MessageBase msg = null;
switch (type) {
case RecordTypes.RECORD_TYPE_ALARM:
msg = new MsgHistoryAlarm();
break;
case RecordTypes.RECORD_TYPE_BASALHOUR:
msg = new MsgHistoryBasalHour();
break;
case RecordTypes.RECORD_TYPE_BOLUS:
msg = new MsgHistoryBolus();
break;
case RecordTypes.RECORD_TYPE_CARBO:
msg = new MsgHistoryCarbo();
break;
case RecordTypes.RECORD_TYPE_DAILY:
msg = new MsgHistoryDailyInsulin();
break;
case RecordTypes.RECORD_TYPE_ERROR:
msg = new MsgHistoryError();
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
msg = new MsgHistoryGlucose();
break;
case RecordTypes.RECORD_TYPE_REFILL:
msg = new MsgHistoryRefill();
break;
case RecordTypes.RECORD_TYPE_SUSPEND:
msg = new MsgHistorySuspend();
break;
}
MsgHistoryDone done = new MsgHistoryDone();
mSerialIOThread.sendMessage(new MsgPCCommStart());
SystemClock.sleep(400);
mSerialIOThread.sendMessage(msg);
while (!done.received && mRfcommSocket.isConnected()) {
SystemClock.sleep(100);
}
SystemClock.sleep(200);
mSerialIOThread.sendMessage(new MsgPCCommStop());
result.success = true;
result.comment = "OK";
return result;
}
}

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps.plugins.PumpDanaR.services;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
/**
* Created by mike on 28.01.2018.
*/
public abstract class AbstractSerialIOThread extends Thread {
public abstract void sendMessage(MessageBase message);
public abstract void disconnect(String reason);
}

View file

@ -1,41 +1,33 @@
package info.nightscout.androidaps.plugins.PumpDanaR.services;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.SerialIOThread;
@ -45,18 +37,6 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgCheckValue;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryAlarm;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBasalHour;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBolus;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryCarbo;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDailyInsulin;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDone;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryError;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryGlucose;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryRefill;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistorySuspend;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetActivateBasalProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetBasalProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetCarbsEntry;
@ -67,9 +47,9 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTempBasalStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTime;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingActiveProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingBasal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMeal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingGlucose;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMaxValues;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMeal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatios;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatiosAll;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingPumpTime;
@ -78,51 +58,18 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatus;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBasic;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBolusExtended;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusTempBasal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRNewStatus;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
public class DanaRExecutionService extends Service {
private static Logger log = LoggerFactory.getLogger(DanaRExecutionService.class);
private String devName;
private SerialIOThread mSerialIOThread;
private BluetoothSocket mRfcommSocket;
private BluetoothDevice mBTDevice;
private IBinder mBinder = new LocalBinder();
private DanaRPump danaRPump = DanaRPump.getInstance();
private Treatment bolusingTreatment = null;
private static Boolean connectionInProgress = false;
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
log.debug("Device was disconnected " + device.getName());//Device was disconnected
if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
if (mSerialIOThread != null) {
mSerialIOThread.disconnect("BT disconnection broadcast");
}
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
}
}
}
};
public class DanaRExecutionService extends AbstractDanaRExecutionService{
public DanaRExecutionService() {
log = LoggerFactory.getLogger(DanaRExecutionService.class);
mBinder = new LocalBinder();
registerBus();
MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
}
@ -133,17 +80,6 @@ public class DanaRExecutionService extends Service {
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
private void registerBus() {
try {
MainApp.bus().unregister(this);
@ -154,49 +90,27 @@ public class DanaRExecutionService extends Service {
}
@Subscribe
public void onStatusEvent(EventAppExit event) {
if (Config.logFunctionCalls)
log.debug("EventAppExit received");
public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("Application exit");
MainApp.instance().getApplicationContext().unregisterReceiver(receiver);
stopSelf();
if (Config.logFunctionCalls)
log.debug("EventAppExit finished");
mSerialIOThread.disconnect("EventPreferenceChange");
}
public boolean isConnected() {
return mRfcommSocket != null && mRfcommSocket.isConnected();
}
public boolean isConnecting() {
return connectionInProgress;
}
public void disconnect(String from) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect(from);
}
public void connect(String from) {
if (danaRPump.password != -1 && danaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
public void connect() {
if (mDanaRPump.password != -1 && mDanaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
return;
}
if (connectionInProgress)
if (mConnectionInProgress)
return;
new Thread(new Runnable() {
@Override
public void run() {
connectionInProgress = true;
mConnectionInProgress = true;
getBTSocketForSelectedPump();
if (mRfcommSocket == null || mBTDevice == null) {
connectionInProgress = false;
mConnectionInProgress = false;
return; // Device not found
}
@ -217,48 +131,11 @@ public class DanaRExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED, 0));
}
connectionInProgress = false;
mConnectionInProgress = false;
}
}).start();
}
public void stopConnecting() {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("stopConnecting");
}
private void getBTSocketForSelectedPump() {
devName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
if (devName.equals(device.getName())) {
mBTDevice = device;
try {
mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
log.error("Error creating socket: ", e);
}
break;
}
}
} else {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
}
if (mBTDevice == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
}
}
@Subscribe
public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("EventPreferenceChange");
}
public void getPumpStatus() {
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpstatus)));
@ -268,7 +145,7 @@ public class DanaRExecutionService extends Service {
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
MsgCheckValue checkValue = new MsgCheckValue();
if (danaRPump.isNewPump) {
if (mDanaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@ -283,8 +160,8 @@ public class DanaRExecutionService extends Service {
mSerialIOThread.sendMessage(exStatusMsg);
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus)));
Date now = new Date();
if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRPlugin.class).isInitialized()) {
long now = System.currentTimeMillis();
if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRPlugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
@ -298,26 +175,26 @@ public class DanaRExecutionService extends Service {
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
danaRPump.lastSettingsRead = now;
mDanaRPump.lastSettingsRead = now;
}
danaRPump.lastConnection = now;
mDanaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
}
} catch (Exception e) {
log.error("Unhandled exception", e);
@ -326,10 +203,10 @@ public class DanaRExecutionService extends Service {
public boolean tempBasal(int percent, int durationInHours) {
if (!isConnected()) return false;
if (danaRPump.isTempBasalInProgress) {
if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
waitMsec(500);
SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
@ -365,11 +242,16 @@ public class DanaRExecutionService extends Service {
return true;
}
public boolean bolus(double amount, int carbs, final Treatment t) {
@Override
public PumpEnactResult loadEvents() {
return null;
}
public boolean bolus(double amount, int carbs, long carbtime, final Treatment t) {
if (!isConnected()) return false;
if (BolusProgressDialog.stopPressed) return false;
bolusingTreatment = t;
mBolusingTreatment = t;
int preferencesSpeed = SP.getInt(R.string.key_danars_bolusspeed, 0);
MessageBase start;
if (preferencesSpeed == 0)
@ -379,7 +261,7 @@ public class DanaRExecutionService extends Service {
MsgBolusStop stop = new MsgBolusStop(amount, t);
if (carbs > 0) {
mSerialIOThread.sendMessage(new MsgSetCarbsEntry(System.currentTimeMillis(), carbs));
mSerialIOThread.sendMessage(new MsgSetCarbsEntry(carbtime, carbs));
}
MsgBolusProgress progress = new MsgBolusProgress(amount, t); // initialize static variables
@ -392,20 +274,20 @@ public class DanaRExecutionService extends Service {
return false;
}
while (!stop.stopped && !start.failed) {
waitMsec(100);
SystemClock.sleep(100);
if ((System.currentTimeMillis() - progress.lastReceive) > 15 * 1000L) { // if i didn't receive status for more than 15 sec expecting broken comm
stop.stopped = true;
stop.forced = true;
log.debug("Communication stopped");
}
}
waitMsec(300);
SystemClock.sleep(300);
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
bolusingEvent.t = t;
bolusingEvent.percent = 99;
bolusingTreatment = null;
mBolusingTreatment = null;
int speed = 12;
switch (preferencesSpeed) {
@ -437,11 +319,11 @@ public class DanaRExecutionService extends Service {
ConfigBuilderPlugin.getCommandQueue().independentConnect("bolusingInterrupted", new Callback() {
@Override
public void run() {
if (danaRPump.lastBolusTime.getTime() > System.currentTimeMillis() - 60 * 1000L) { // last bolus max 1 min old
t.insulin = danaRPump.lastBolusAmount;
log.debug("Used bolus amount from history: " + danaRPump.lastBolusAmount);
if (mDanaRPump.lastBolusTime.getTime() > System.currentTimeMillis() - 60 * 1000L) { // last bolus max 1 min old
t.insulin = mDanaRPump.lastBolusAmount;
log.debug("Used bolus amount from history: " + mDanaRPump.lastBolusAmount);
} else {
log.debug("Bolus amount in history too old: " + danaRPump.lastBolusTime.toLocaleString());
log.debug("Bolus amount in history too old: " + mDanaRPump.lastBolusTime.toLocaleString());
}
synchronized (o) {
o.notify();
@ -460,22 +342,6 @@ public class DanaRExecutionService extends Service {
return true;
}
public void bolusStop() {
if (Config.logDanaBTComm)
log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
MsgBolusStop stop = new MsgBolusStop();
stop.forced = true;
if (isConnected()) {
mSerialIOThread.sendMessage(stop);
while (!stop.stopped) {
mSerialIOThread.sendMessage(stop);
waitMsec(200);
}
} else {
stop.stopped = true;
}
}
public boolean carbsEntry(int amount) {
if (!isConnected()) return false;
MsgSetCarbsEntry msg = new MsgSetCarbsEntry(System.currentTimeMillis(), amount);
@ -483,51 +349,9 @@ public class DanaRExecutionService extends Service {
return true;
}
public PumpEnactResult loadHistory(byte type) {
PumpEnactResult result = new PumpEnactResult();
if (!isConnected()) return result;
MessageBase msg = null;
switch (type) {
case RecordTypes.RECORD_TYPE_ALARM:
msg = new MsgHistoryAlarm();
break;
case RecordTypes.RECORD_TYPE_BASALHOUR:
msg = new MsgHistoryBasalHour();
break;
case RecordTypes.RECORD_TYPE_BOLUS:
msg = new MsgHistoryBolus();
break;
case RecordTypes.RECORD_TYPE_CARBO:
msg = new MsgHistoryCarbo();
break;
case RecordTypes.RECORD_TYPE_DAILY:
msg = new MsgHistoryDailyInsulin();
break;
case RecordTypes.RECORD_TYPE_ERROR:
msg = new MsgHistoryError();
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
msg = new MsgHistoryGlucose();
break;
case RecordTypes.RECORD_TYPE_REFILL:
msg = new MsgHistoryRefill();
break;
case RecordTypes.RECORD_TYPE_SUSPEND:
msg = new MsgHistorySuspend();
break;
}
MsgHistoryDone done = new MsgHistoryDone();
mSerialIOThread.sendMessage(new MsgPCCommStart());
waitMsec(400);
mSerialIOThread.sendMessage(msg);
while (!done.received && mRfcommSocket.isConnected()) {
waitMsec(100);
}
waitMsec(200);
mSerialIOThread.sendMessage(new MsgPCCommStop());
result.success = true;
result.comment = "OK";
return result;
@Override
public boolean highTempBasal(int percent) {
return false;
}
public boolean updateBasalsInPump(final Profile profile) {
@ -538,13 +362,25 @@ public class DanaRExecutionService extends Service {
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
danaRPump.lastSettingsRead = new Date(0); // force read full settings
mDanaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
}
private void waitMsec(long msecs) {
SystemClock.sleep(msecs);
@Subscribe
public void onStatusEvent(EventAppExit event) {
if (Config.logFunctionCalls)
log.debug("EventAppExit received");
if (mSerialIOThread != null)
mSerialIOThread.disconnect("Application exit");
MainApp.instance().getApplicationContext().unregisterReceiver(receiver);
stopSelf();
if (Config.logFunctionCalls)
log.debug("EventAppExit finished");
}
}

View file

@ -5,71 +5,31 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.DanaRInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRFragment;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
/**
* Created by mike on 05.08.2016.
*/
public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
private static Logger log = LoggerFactory.getLogger(DanaRKoreanPlugin.class);
@Override
public String getFragmentClass() {
return DanaRFragment.class.getName();
}
private static boolean fragmentPumpEnabled = false;
private static boolean fragmentProfileEnabled = false;
private static boolean fragmentPumpVisible = true;
private static DanaRKoreanExecutionService sExecutionService;
private static DanaRPump pump = DanaRPump.getInstance();
private boolean useExtendedBoluses = false;
public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
private static DanaRKoreanPlugin plugin = null;
@ -79,9 +39,8 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
return plugin;
}
public static PumpDescription pumpDescription = new PumpDescription();
public DanaRKoreanPlugin() {
log = LoggerFactory.getLogger(DanaRKoreanPlugin.class);
useExtendedBoluses = SP.getBoolean("danar_useextended", false);
Context context = MainApp.instance().getApplicationContext();
@ -112,6 +71,8 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
pumpDescription.basalMinimumRate = 0.1d;
pumpDescription.isRefillingCapable = true;
pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@ -147,83 +108,17 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
}
// Plugin base interface
@Override
public int getType() {
return PluginBase.PUMP;
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.danarkoreanpump);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.danarpump_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
return false;
}
@Override
public boolean isVisibleInTabs(int type) {
if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
else if (type == PluginBase.PUMP) return fragmentPumpVisible;
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return type == PUMP;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == PluginBase.PROFILE)
fragmentProfileEnabled = fragmentEnabled;
else if (type == PluginBase.PUMP)
fragmentPumpEnabled = fragmentEnabled;
// if pump profile was enabled need to switch to another too
if (type == PluginBase.PUMP && !fragmentEnabled && fragmentProfileEnabled) {
setFragmentEnabled(PluginBase.PROFILE, false);
setFragmentVisible(PluginBase.PROFILE, false);
NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
}
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == PluginBase.PUMP)
fragmentPumpVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_danarkorean;
}
// Pump interface
@Override
public boolean isFakingTempsByExtendedBoluses() {
return useExtendedBoluses;
@ -231,82 +126,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
@Override
public boolean isInitialized() {
return pump.lastConnection.getTime() > 0 && pump.maxBasal > 0 && !pump.isConfigUD && !pump.isEasyModeEnabled && pump.isExtendedBolusEnabled;
}
@Override
public boolean isSuspended() {
return pump.pumpSuspended;
}
@Override
public boolean isBusy() {
if (sExecutionService == null) return false;
return sExecutionService.isConnected() || sExecutionService.isConnecting();
}
// Pump interface
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
PumpEnactResult result = new PumpEnactResult();
if (sExecutionService == null) {
log.error("setNewBasalProfile sExecutionService is null");
result.comment = "setNewBasalProfile sExecutionService is null";
return result;
}
if (!isInitialized()) {
log.error("setNewBasalProfile not initialized");
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
}
if (!sExecutionService.updateBasalsInPump(profile)) {
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
result.success = true;
result.enacted = true;
result.comment = "OK";
return result;
}
}
@Override
public boolean isThisProfileSet(Profile profile) {
if (!isInitialized())
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
if (pump.pumpProfiles == null)
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
int basalValues = pump.basal48Enable ? 48 : 24;
int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
if (profileValue == null) return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
return false;
}
}
return true;
}
@Override
public Date lastDataTime() {
return pump.lastConnection;
}
@Override
public double getBaseBasalRate() {
return pump.currentBasal;
return pump.lastConnection > 0 && pump.maxBasal > 0 && !pump.isConfigUD && !pump.isEasyModeEnabled && pump.isExtendedBolusEnabled;
}
@Override
@ -316,7 +136,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
Treatment t = new Treatment();
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, t);
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, detailedBolusInfo.carbTime, t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@ -339,15 +159,6 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
}
}
@Override
public void stopBolusDelivering() {
if (sExecutionService == null) {
log.error("stopBolusDelivering sExecutionService is null");
return;
}
sExecutionService.bolusStop();
}
// This is called from APS
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) {
@ -500,100 +311,6 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
return result;
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult();
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
percent = configBuilderPlugin.applyBasalConstraints(percent);
if (percent < 0) {
result.isTempCancel = false;
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
log.error("setTempBasalPercent: Invalid input");
return result;
}
if (percent > getPumpDescription().maxTempPercent)
percent = getPumpDescription().maxTempPercent;
TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
if (runningTB != null && runningTB.percentRate == percent && enforceNew) {
result.enacted = false;
result.success = true;
result.isTempCancel = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = pump.tempBasalRemainingMin;
result.percent = pump.tempBasalPercent;
result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: Correct value already set");
return result;
}
int durationInHours = Math.max(durationInMinutes / 60, 1);
boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = pump.tempBasalRemainingMin;
result.percent = pump.tempBasalPercent;
result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory();
result.isPercent = true;
if (Config.logPumpActions)
log.debug("setTempBasalPercent: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("setTempBasalPercent: Failed to set temp basal");
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
insulin = configBuilderPlugin.applyBolusConstraints(insulin);
// needs to be rounded
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = false;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.isPercent = false;
result.isTempCancel = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
return result;
}
boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.bolusDelivered = pump.extendedBolusAmount;
result.isPercent = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("setExtendedBolus: Failed to extended bolus");
return result;
}
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress())
@ -634,257 +351,8 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf
}
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null) {
sExecutionService.extendedBolusStop();
result.enacted = true;
result.isTempCancel = true;
}
if (!pump.isExtendedInProgress) {
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpActions)
log.debug("cancelExtendedBolus: OK");
return result;
} else {
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("cancelExtendedBolus: Failed to cancel extended bolus");
return result;
}
}
@Override
public void connect(String from) {
if (sExecutionService != null) {
sExecutionService.connect(from);
pumpDescription.basalStep = pump.basalStep;
pumpDescription.bolusStep = pump.bolusStep;
}
}
@Override
public boolean isConnected() {
return sExecutionService != null && sExecutionService.isConnected();
}
@Override
public boolean isConnecting() {
return sExecutionService != null && sExecutionService.isConnecting();
}
@Override
public void disconnect(String from) {
if (sExecutionService != null) sExecutionService.disconnect(from);
}
@Override
public void stopConnecting() {
if (sExecutionService != null) sExecutionService.stopConnecting();
}
@Override
public void getPumpStatus() {
if (sExecutionService != null) sExecutionService.getPumpStatus();
}
@Override
public JSONObject getJSONStatus() {
if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
return null;
}
JSONObject pumpjson = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
battery.put("percent", pump.batteryRemaining);
status.put("status", pump.pumpSuspended ? "suspended" : "normal");
status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
extended.put("PumpIOB", pump.iob);
if (pump.lastBolusTime.getTime() != 0) {
extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
extended.put("LastBolusAmount", pump.lastBolusAmount);
}
TemporaryBasal tb = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis());
if (tb != null) {
extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
}
ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (eb != null) {
extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
}
extended.put("BaseBasalRate", getBaseBasalRate());
try {
extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
} catch (Exception e) {
}
pumpjson.put("battery", battery);
pumpjson.put("status", status);
pumpjson.put("extended", extended);
pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
pumpjson.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return pumpjson;
}
@Override
public String deviceID() {
return pump.serialNumber;
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
/**
* DanaR interface
*/
@Override
public PumpEnactResult loadHistory(byte type) {
return sExecutionService.loadHistory(type);
}
@Override
public PumpEnactResult loadEvents() {
return null; // no history, not needed
}
/**
* Constraint interface
*/
@Override
public boolean isLoopEnabled() {
return true;
}
@Override
public boolean isClosedModeEnabled() {
return true;
}
@Override
public boolean isAutosensModeEnabled() {
return true;
}
@Override
public boolean isAMAModeEnabled() {
return true;
}
@Override
public boolean isSMBModeEnabled() {
return true;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBasalConstraints(Double absoluteRate) {
double origAbsoluteRate = absoluteRate;
if (pump != null) {
if (absoluteRate > pump.maxBasal) {
absoluteRate = pump.maxBasal;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
}
}
return absoluteRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Integer applyBasalConstraints(Integer percentRate) {
Integer origPercentRate = percentRate;
if (percentRate < 0) percentRate = 0;
if (percentRate > getPumpDescription().maxTempPercent)
percentRate = getPumpDescription().maxTempPercent;
if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
return percentRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBolusConstraints(Double insulin) {
double origInsulin = insulin;
if (pump != null) {
if (insulin > pump.maxBolus) {
insulin = pump.maxBolus;
if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
}
}
return insulin;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
@Nullable
@Override
public ProfileStore getProfile() {
if (pump.lastSettingsRead.getTime() == 0)
return null; // no info now
return pump.createConvertedProfile();
}
@Override
public String getUnits() {
return pump.getUnits();
}
@Override
public String getProfileName() {
return pump.createConvertedProfileName();
}
// Reply for sms communicator
public String shortStatus(boolean veryShort) {
String ret = "";
if (pump.lastConnection.getTime() != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (pump.lastBolusTime.getTime() != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
ret += "Temp: " + MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
}
if (!veryShort) {
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
}
ret += "IOB: " + pump.iob + "U\n";
ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
ret += "Batt: " + pump.batteryRemaining + "\n";
return ret;
}
// TODO: daily total constraint
}

View file

@ -13,13 +13,14 @@ import java.io.OutputStream;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractSerialIOThread;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MessageHashTable_k;
import info.nightscout.utils.CRC;
/**
* Created by mike on 17.07.2016.
*/
public class SerialIOThread extends Thread {
public class SerialIOThread extends AbstractSerialIOThread {
private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
private InputStream mInputStream = null;
@ -29,10 +30,10 @@ public class SerialIOThread extends Thread {
private boolean mKeepRunning = true;
private byte[] mReadBuff = new byte[0];
MessageBase processedMessage;
private MessageBase processedMessage;
public SerialIOThread(BluetoothSocket rfcommSocket) {
super(SerialIOThread.class.toString());
super();
mRfCommSocket = rfcommSocket;
try {
@ -138,6 +139,7 @@ public class SerialIOThread extends Thread {
}
}
@Override
public synchronized void sendMessage(MessageBase message) {
if (!mRfCommSocket.isConnected()) {
log.error("Socket not connected on sendMessage");
@ -173,6 +175,7 @@ public class SerialIOThread extends Thread {
}
}
@Override
public void disconnect(String reason) {
mKeepRunning = false;
try {

View file

@ -37,7 +37,7 @@ public class MsgInitConnStatusTime_k extends MessageBase {
MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).setFragmentVisible(PluginBase.PUMP, false);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentEnabled(PluginBase.PUMP, true);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentVisible(PluginBase.PUMP, true);
DanaRPump.getInstance().lastConnection = new Date(0); // mark not initialized
DanaRPump.getInstance().lastConnection = 0; // mark not initialized
//If profile coming from pump, switch it as well
if (MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isEnabled(PluginBase.PROFILE)) {

View file

@ -24,7 +24,7 @@ public class MsgSettingBasal_k extends MessageBase {
pump.pumpProfiles[pump.activeProfile] = new double[24];
for (int index = 0; index < 24; index++) {
int basal = intFromBuff(bytes, 2 * index, 2);
if (basal < DanaRKoreanPlugin.pumpDescription.basalMinimumRate) basal = 0;
if (basal < DanaRKoreanPlugin.getPlugin().pumpDescription.basalMinimumRate) basal = 0;
pump.pumpProfiles[pump.activeProfile][index] = basal / 100d;
}

View file

@ -1,58 +1,36 @@
package info.nightscout.androidaps.plugins.PumpDanaRKorean.services;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusProgress;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryAlarm;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBasalHour;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryBolus;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryCarbo;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDailyInsulin;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryDone;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryError;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryGlucose;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryRefill;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistorySuspend;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgPCCommStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetCarbsEntry;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStop;
@ -68,56 +46,23 @@ import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingPumpTime;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingShippingInfo;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBolusExtended;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusTempBasal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRNewStatus;
import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractDanaRExecutionService;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.SerialIOThread;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgCheckValue_k;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgSettingBasal_k;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgStatusBasic_k;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
public class DanaRKoreanExecutionService extends Service {
private static Logger log = LoggerFactory.getLogger(DanaRKoreanExecutionService.class);
private String devName;
private SerialIOThread mSerialIOThread;
private BluetoothSocket mRfcommSocket;
private BluetoothDevice mBTDevice;
private IBinder mBinder = new LocalBinder();
private DanaRPump danaRPump = DanaRPump.getInstance();
private Treatment bolusingTreatment = null;
private static Boolean connectionInProgress = false;
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
log.debug("Device was disconnected " + device.getName());//Device was disconnected
if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
if (mSerialIOThread != null) {
mSerialIOThread.disconnect("BT disconnection broadcast");
}
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
}
}
}
};
public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
public DanaRKoreanExecutionService() {
log = LoggerFactory.getLogger(DanaRKoreanExecutionService.class);
mBinder = new LocalBinder();
registerBus();
MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
}
@ -128,17 +73,6 @@ public class DanaRKoreanExecutionService extends Service {
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
private void registerBus() {
try {
MainApp.bus().unregister(this);
@ -163,35 +97,28 @@ public class DanaRKoreanExecutionService extends Service {
log.debug("EventAppExit finished");
}
public boolean isConnected() {
return mRfcommSocket != null && mRfcommSocket.isConnected();
}
public boolean isConnecting() {
return connectionInProgress;
}
public void disconnect(String from) {
@Subscribe
public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect(from);
mSerialIOThread.disconnect("EventPreferenceChange");
}
public void connect(String from) {
if (danaRPump.password != -1 && danaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
public void connect() {
if (mDanaRPump.password != -1 && mDanaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
return;
}
if (connectionInProgress)
if (mConnectionInProgress)
return;
new Thread(new Runnable() {
@Override
public void run() {
connectionInProgress = true;
mConnectionInProgress = true;
getBTSocketForSelectedPump();
if (mRfcommSocket == null || mBTDevice == null) {
connectionInProgress = false;
mConnectionInProgress = false;
return; // Device not found
}
@ -212,48 +139,11 @@ public class DanaRKoreanExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED, 0));
}
connectionInProgress = false;
mConnectionInProgress = false;
}
}).start();
}
public void stopConnecting() {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("stopConnecting");
}
private void getBTSocketForSelectedPump() {
devName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
if (devName.equals(device.getName())) {
mBTDevice = device;
try {
mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
log.error("Error creating socket: ", e);
}
break;
}
}
} else {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
}
if (mBTDevice == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
}
}
@Subscribe
public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("EventPreferenceChange");
}
public void getPumpStatus() {
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpstatus)));
@ -263,7 +153,7 @@ public class DanaRKoreanExecutionService extends Service {
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
MsgCheckValue_k checkValue = new MsgCheckValue_k();
if (danaRPump.isNewPump) {
if (mDanaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@ -278,8 +168,8 @@ public class DanaRKoreanExecutionService extends Service {
mSerialIOThread.sendMessage(exStatusMsg);
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus)));
Date now = new Date();
if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isInitialized()) {
long now = System.currentTimeMillis();
if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingMeal());
@ -290,39 +180,38 @@ public class DanaRKoreanExecutionService extends Service {
mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
danaRPump.lastSettingsRead = now;
mDanaRPump.lastSettingsRead = now;
}
danaRPump.lastConnection = now;
mDanaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return;
}
public boolean tempBasal(int percent, int durationInHours) {
if (!isConnected()) return false;
if (danaRPump.isTempBasalInProgress) {
if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
waitMsec(500);
SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
@ -358,16 +247,21 @@ public class DanaRKoreanExecutionService extends Service {
return true;
}
public boolean bolus(double amount, int carbs, final Treatment t) {
@Override
public PumpEnactResult loadEvents() {
return null;
}
public boolean bolus(double amount, int carbs, long carbtime, final Treatment t) {
if (!isConnected()) return false;
if (BolusProgressDialog.stopPressed) return false;
bolusingTreatment = t;
mBolusingTreatment = t;
MsgBolusStart start = new MsgBolusStart(amount);
MsgBolusStop stop = new MsgBolusStop(amount, t);
if (carbs > 0) {
mSerialIOThread.sendMessage(new MsgSetCarbsEntry(System.currentTimeMillis(), carbs));
mSerialIOThread.sendMessage(new MsgSetCarbsEntry(carbtime, carbs));
}
MsgBolusProgress progress = new MsgBolusProgress(amount, t); // initialize static variables
@ -380,37 +274,21 @@ public class DanaRKoreanExecutionService extends Service {
return false;
}
while (!stop.stopped && !start.failed) {
waitMsec(100);
SystemClock.sleep(100);
if ((System.currentTimeMillis() - progress.lastReceive) > 15 * 1000L) { // if i didn't receive status for more than 15 sec expecting broken comm
stop.stopped = true;
stop.forced = true;
log.debug("Communication stopped");
}
}
waitMsec(300);
SystemClock.sleep(300);
bolusingTreatment = null;
mBolusingTreatment = null;
ConfigBuilderPlugin.getCommandQueue().readStatus("bolusOK", null);
return true;
}
public void bolusStop() {
if (Config.logDanaBTComm)
log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
MsgBolusStop stop = new MsgBolusStop();
stop.forced = true;
if (isConnected()) {
mSerialIOThread.sendMessage(stop);
while (!stop.stopped) {
mSerialIOThread.sendMessage(stop);
waitMsec(200);
}
} else {
stop.stopped = true;
}
}
public boolean carbsEntry(int amount) {
if (!isConnected()) return false;
MsgSetCarbsEntry msg = new MsgSetCarbsEntry(System.currentTimeMillis(), amount);
@ -418,51 +296,9 @@ public class DanaRKoreanExecutionService extends Service {
return true;
}
public PumpEnactResult loadHistory(byte type) {
PumpEnactResult result = new PumpEnactResult();
if (!isConnected()) return result;
MessageBase msg = null;
switch (type) {
case RecordTypes.RECORD_TYPE_ALARM:
msg = new MsgHistoryAlarm();
break;
case RecordTypes.RECORD_TYPE_BASALHOUR:
msg = new MsgHistoryBasalHour();
break;
case RecordTypes.RECORD_TYPE_BOLUS:
msg = new MsgHistoryBolus();
break;
case RecordTypes.RECORD_TYPE_CARBO:
msg = new MsgHistoryCarbo();
break;
case RecordTypes.RECORD_TYPE_DAILY:
msg = new MsgHistoryDailyInsulin();
break;
case RecordTypes.RECORD_TYPE_ERROR:
msg = new MsgHistoryError();
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
msg = new MsgHistoryGlucose();
break;
case RecordTypes.RECORD_TYPE_REFILL:
msg = new MsgHistoryRefill();
break;
case RecordTypes.RECORD_TYPE_SUSPEND:
msg = new MsgHistorySuspend();
break;
}
MsgHistoryDone done = new MsgHistoryDone();
mSerialIOThread.sendMessage(new MsgPCCommStart());
waitMsec(400);
mSerialIOThread.sendMessage(msg);
while (!done.received && mRfcommSocket.isConnected()) {
waitMsec(100);
}
waitMsec(200);
mSerialIOThread.sendMessage(new MsgPCCommStop());
result.success = true;
result.comment = "OK";
return result;
@Override
public boolean highTempBasal(int percent) {
return false;
}
public boolean updateBasalsInPump(final Profile profile) {
@ -471,13 +307,10 @@ public class DanaRKoreanExecutionService extends Service {
double[] basal = DanaRPump.buildDanaRProfileRecord(profile);
MsgSetSingleBasalProfile msgSet = new MsgSetSingleBasalProfile(basal);
mSerialIOThread.sendMessage(msgSet);
danaRPump.lastSettingsRead = new Date(0); // force read full settings
mDanaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
}
private void waitMsec(long msecs) {
SystemClock.sleep(msecs);
}
}

View file

@ -189,6 +189,8 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
pumpDescription.basalMinimumRate = 0.04d;
pumpDescription.isRefillingCapable = true;
pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@ -346,7 +348,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Nullable
@Override
public ProfileStore getProfile() {
if (pump.lastSettingsRead.getTime() == 0)
if (pump.lastSettingsRead == 0)
return null; // no info now
return pump.createConvertedProfile();
}
@ -365,7 +367,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public boolean isInitialized() {
return pump.lastConnection.getTime() > 0 && pump.maxBasal > 0;
return pump.lastConnection > 0 && pump.maxBasal > 0;
}
@Override
@ -436,7 +438,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public Date lastDataTime() {
return pump.lastConnection;
return new Date(pump.lastConnection);
}
@Override
@ -477,7 +479,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
Treatment t = new Treatment();
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || carbs > 0)
connectionOK = danaRSService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000 + 1000, t); // +1000 to make the record different
connectionOK = danaRSService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000 + 30000, t); // +30s to make the record different
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@ -751,7 +753,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public JSONObject getJSONStatus() {
if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
if (pump.lastConnection + 5 * 60 * 1000L < System.currentTimeMillis()) {
return null;
}
JSONObject pumpjson = new JSONObject();
@ -810,8 +812,8 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public String shortStatus(boolean veryShort) {
String ret = "";
if (pump.lastConnection.getTime() != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
if (pump.lastConnection != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}

View file

@ -131,8 +131,8 @@ public class DanaRSService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingtempbasalstatus)));
bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State());
Date now = new Date();
if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()) {
long now = System.currentTimeMillis();
if (danaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
bleComm.sendMessage(new DanaRS_Packet_General_Get_Shipping_Information()); // serial no
bleComm.sendMessage(new DanaRS_Packet_General_Get_Pump_Check()); // firmware
@ -357,7 +357,7 @@ public class DanaRSService extends Service {
bleComm.sendMessage(msgSet);
DanaRS_Packet_Basal_Set_Profile_Number msgActivate = new DanaRS_Packet_Basal_Set_Profile_Number(0);
bleComm.sendMessage(msgActivate);
danaRPump.lastSettingsRead = new Date(0); // force read full settings
danaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;

View file

@ -5,68 +5,31 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.DanaRInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRFragment;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.services.DanaRv2ExecutionService;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
/**
* Created by mike on 05.08.2016.
*/
public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
private static Logger log = LoggerFactory.getLogger(DanaRv2Plugin.class);
@Override
public String getFragmentClass() {
return DanaRFragment.class.getName();
}
private static boolean fragmentPumpEnabled = false;
private static boolean fragmentProfileEnabled = false;
private static boolean fragmentPumpVisible = true;
private static DanaRv2ExecutionService sExecutionService;
public class DanaRv2Plugin extends AbstractDanaRPlugin {
private static DanaRv2Plugin plugin = null;
@ -76,11 +39,10 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
return plugin;
}
private static DanaRPump pump = DanaRPump.getInstance();
private static PumpDescription pumpDescription = new PumpDescription();
private DanaRv2Plugin() {
log = LoggerFactory.getLogger(DanaRv2Plugin.class);
useExtendedBoluses = false;
Context context = MainApp.instance().getApplicationContext();
Intent intent = new Intent(context, DanaRv2ExecutionService.class);
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
@ -109,6 +71,8 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
pumpDescription.basalMinimumRate = 0.04d;
pumpDescription.isRefillingCapable = true;
pumpDescription.storesCarbInfo = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@ -132,78 +96,11 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
}
// Plugin base interface
@Override
public int getType() {
return PluginBase.PUMP;
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.danarv2pump);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.danarpump_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
return false;
}
@Override
public boolean isVisibleInTabs(int type) {
if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
else if (type == PluginBase.PUMP) return fragmentPumpVisible;
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return type == PUMP;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == PluginBase.PROFILE)
fragmentProfileEnabled = fragmentEnabled;
else if (type == PluginBase.PUMP)
fragmentPumpEnabled = fragmentEnabled;
// if pump profile was enabled need to switch to another too
if (type == PluginBase.PUMP && !fragmentEnabled && fragmentProfileEnabled) {
setFragmentEnabled(PluginBase.PROFILE, false);
setFragmentVisible(PluginBase.PROFILE, false);
NSProfilePlugin.getPlugin().setFragmentEnabled(PluginBase.PROFILE, true);
NSProfilePlugin.getPlugin().setFragmentVisible(PluginBase.PROFILE, true);
}
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == PluginBase.PUMP)
fragmentPumpVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_danarv2;
@ -216,86 +113,10 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public boolean isInitialized() {
return pump.lastConnection.getTime() > 0 && pump.maxBasal > 0;
}
@Override
public boolean isSuspended() {
return pump.pumpSuspended;
}
@Override
public boolean isBusy() {
if (sExecutionService == null) return false;
return sExecutionService.isConnected() || sExecutionService.isConnecting();
return pump.lastConnection > 0 && pump.maxBasal > 0;
}
// Pump interface
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
PumpEnactResult result = new PumpEnactResult();
if (sExecutionService == null) {
log.error("setNewBasalProfile sExecutionService is null");
result.comment = "setNewBasalProfile sExecutionService is null";
return result;
}
if (!isInitialized()) {
log.error("setNewBasalProfile not initialized");
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
}
if (!sExecutionService.updateBasalsInPump(profile)) {
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.sResources.getString(R.string.failedupdatebasalprofile);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.sResources.getString(R.string.profile_set_ok), Notification.INFO, 60);
MainApp.bus().post(new EventNewNotification(notification));
result.success = true;
result.enacted = true;
result.comment = "OK";
return result;
}
}
@Override
public boolean isThisProfileSet(Profile profile) {
if (!isInitialized())
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
if (pump.pumpProfiles == null)
return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
int basalValues = pump.basal48Enable ? 48 : 24;
int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasal((Integer) (h * basalIncrement));
if (profileValue == null) return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
return false;
}
}
return true;
}
@Override
public Date lastDataTime() {
return pump.lastConnection;
}
@Override
public double getBaseBasalRate() {
return pump.currentBasal;
}
@Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
@ -329,7 +150,7 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
Treatment t = new Treatment();
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || carbs > 0)
connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000 + 1000, t); // +1000 to make the record different
connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000 + 30000, t); // +30s to make the record different
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK;
result.bolusDelivered = t.insulin;
@ -511,49 +332,6 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
insulin = configBuilderPlugin.applyBolusConstraints(insulin);
// needs to be rounded
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep);
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = false;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.isPercent = false;
result.isTempCancel = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
return result;
}
boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = true;
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
result.isTempCancel = false;
result.duration = pump.extendedBolusRemainingMinutes;
result.absolute = pump.extendedBolusAbsoluteRate;
result.bolusDelivered = pump.extendedBolusAmount;
result.isPercent = false;
if (Config.logPumpActions)
log.debug("setExtendedBolus: OK");
return result;
}
result.enacted = false;
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("setExtendedBolus: Failed to extended bolus");
return result;
}
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
PumpEnactResult result = new PumpEnactResult();
@ -579,257 +357,8 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface,
}
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (runningEB != null) {
sExecutionService.extendedBolusStop();
result.enacted = true;
result.isTempCancel = true;
}
if (!pump.isExtendedInProgress) {
result.success = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpActions)
log.debug("cancelExtendedBolus: OK");
return result;
} else {
result.success = false;
result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
log.error("cancelExtendedBolus: Failed to cancel extended bolus");
return result;
}
}
@Override
public void connect(String from) {
if (sExecutionService != null) {
sExecutionService.connect(from);
pumpDescription.basalStep = pump.basalStep;
pumpDescription.bolusStep = pump.bolusStep;
}
}
@Override
public boolean isConnected() {
return sExecutionService != null && sExecutionService.isConnected();
}
@Override
public boolean isConnecting() {
return sExecutionService != null && sExecutionService.isConnecting();
}
@Override
public void disconnect(String from) {
if (sExecutionService != null) sExecutionService.disconnect(from);
}
@Override
public void stopConnecting() {
if (sExecutionService != null) sExecutionService.stopConnecting();
}
@Override
public void getPumpStatus() {
if (sExecutionService != null) sExecutionService.getPumpStatus();
}
@Override
public JSONObject getJSONStatus() {
if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) {
return null;
}
JSONObject pumpjson = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
battery.put("percent", pump.batteryRemaining);
status.put("status", pump.pumpSuspended ? "suspended" : "normal");
status.put("timestamp", DateUtil.toISOString(pump.lastConnection));
extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
extended.put("PumpIOB", pump.iob);
if (pump.lastBolusTime.getTime() != 0) {
extended.put("LastBolus", pump.lastBolusTime.toLocaleString());
extended.put("LastBolusAmount", pump.lastBolusAmount);
}
TemporaryBasal tb = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
if (tb != null) {
extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis()));
extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date));
extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes());
}
ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis());
if (eb != null) {
extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate());
extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date));
extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes());
}
extended.put("BaseBasalRate", getBaseBasalRate());
try {
extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
} catch (Exception e) {
}
pumpjson.put("battery", battery);
pumpjson.put("status", status);
pumpjson.put("extended", extended);
pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
pumpjson.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return pumpjson;
}
@Override
public String deviceID() {
return pump.serialNumber;
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
/**
* DanaR interface
*/
@Override
public PumpEnactResult loadHistory(byte type) {
return sExecutionService.loadHistory(type);
}
@Override
public PumpEnactResult loadEvents() {
return sExecutionService.loadEvents();
}
/**
* Constraint interface
*/
@Override
public boolean isLoopEnabled() {
return true;
}
@Override
public boolean isClosedModeEnabled() {
return true;
}
@Override
public boolean isAutosensModeEnabled() {
return true;
}
@Override
public boolean isAMAModeEnabled() {
return true;
}
@Override
public boolean isSMBModeEnabled() {
return true;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBasalConstraints(Double absoluteRate) {
double origAbsoluteRate = absoluteRate;
if (pump != null) {
if (absoluteRate > pump.maxBasal) {
absoluteRate = pump.maxBasal;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
}
}
return absoluteRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Integer applyBasalConstraints(Integer percentRate) {
Integer origPercentRate = percentRate;
if (percentRate < 0) percentRate = 0;
if (percentRate > getPumpDescription().maxTempPercent)
percentRate = getPumpDescription().maxTempPercent;
if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
return percentRate;
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public Double applyBolusConstraints(Double insulin) {
double origInsulin = insulin;
if (pump != null) {
if (insulin > pump.maxBolus) {
insulin = pump.maxBolus;
if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
}
}
return insulin;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
@Nullable
@Override
public ProfileStore getProfile() {
if (pump.lastSettingsRead.getTime() == 0)
return null; // no info now
return pump.createConvertedProfile();
}
@Override
public String getUnits() {
return pump.getUnits();
}
@Override
public String getProfileName() {
return pump.createConvertedProfileName();
}
// Reply for sms communicator
public String shortStatus(boolean veryShort) {
String ret = "";
if (pump.lastConnection.getTime() != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection.getTime();
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (pump.lastBolusTime.getTime() != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) {
ret += "Temp: " + MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()).toStringFull() + "\n";
}
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) {
ret += "Extended: " + MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString() + "\n";
}
if (!veryShort) {
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
}
ret += "IOB: " + pump.iob + "U\n";
ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
ret += "Batt: " + pump.batteryRemaining + "\n";
return ret;
}
// TODO: daily total constraint
}

View file

@ -13,13 +13,14 @@ import java.io.OutputStream;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractSerialIOThread;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MessageHashTable_v2;
import info.nightscout.utils.CRC;
/**
* Created by mike on 17.07.2016.
*/
public class SerialIOThread extends Thread {
public class SerialIOThread extends AbstractSerialIOThread {
private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
private InputStream mInputStream = null;
@ -29,10 +30,10 @@ public class SerialIOThread extends Thread {
private boolean mKeepRunning = true;
private byte[] mReadBuff = new byte[0];
MessageBase processedMessage;
private MessageBase processedMessage;
public SerialIOThread(BluetoothSocket rfcommSocket) {
super(SerialIOThread.class.toString());
super();
mRfCommSocket = rfcommSocket;
try {
@ -138,6 +139,7 @@ public class SerialIOThread extends Thread {
}
}
@Override
public synchronized void sendMessage(MessageBase message) {
if (!mRfCommSocket.isConnected()) {
log.error("Socket not connected on sendMessage");
@ -173,6 +175,7 @@ public class SerialIOThread extends Thread {
}
}
@Override
public void disconnect(String reason) {
mKeepRunning = false;
try {

View file

@ -40,6 +40,7 @@ public class MsgCheckValue_v2 extends MessageBase {
pump.protocol = intFromBuff(bytes, 1, 1);
pump.productCode = intFromBuff(bytes, 2, 1);
if (pump.model != DanaRPump.EXPORT_MODEL) {
pump.lastConnection = 0;
Notification notification = new Notification(Notification.WRONG_DRIVER, MainApp.sResources.getString(R.string.pumpdrivercorrected), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
MainApp.getSpecificPlugin(DanaRPlugin.class).disconnect("Wrong Model");
@ -48,7 +49,7 @@ public class MsgCheckValue_v2 extends MessageBase {
MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).setFragmentVisible(PluginBase.PUMP, true);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentEnabled(PluginBase.PUMP, false);
MainApp.getSpecificPlugin(DanaRPlugin.class).setFragmentVisible(PluginBase.PUMP, false);
DanaRPump.getInstance().lastConnection = new Date(0); // mark not initialized
DanaRPump.getInstance().lastConnection = 0; // mark not initialized
//If profile coming from pump, switch it as well
if(MainApp.getSpecificPlugin(DanaRPlugin.class).isEnabled(PluginBase.PROFILE)){
@ -63,6 +64,7 @@ public class MsgCheckValue_v2 extends MessageBase {
}
if (pump.protocol != 2) {
pump.lastConnection = 0;
Notification notification = new Notification(Notification.WRONG_DRIVER, MainApp.sResources.getString(R.string.pumpdrivercorrected), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
DanaRKoreanPlugin.getPlugin().disconnect("Wrong Model");

View file

@ -1,52 +1,66 @@
package info.nightscout.androidaps.plugins.PumpDanaRv2.services;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.*;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusProgress;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetActivateBasalProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetBasalProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetCarbsEntry;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetExtendedBolusStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTempBasalStart;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTempBasalStop;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetTime;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingActiveProfile;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingBasal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingGlucose;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMaxValues;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingMeal;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatios;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingProfileRatiosAll;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingPumpTime;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingShippingInfo;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatus;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusBasic;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRNewStatus;
import info.nightscout.androidaps.plugins.PumpDanaR.services.AbstractDanaRExecutionService;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.SerialIOThread;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgCheckValue_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgHistoryEvents_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgSetAPSTempBasalStart_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgSetHistoryEntry_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgCheckValue_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgStatusBolusExtended_v2;
import info.nightscout.androidaps.plugins.PumpDanaRv2.comm.MsgStatusTempBasal_v2;
import info.nightscout.androidaps.queue.Callback;
@ -54,47 +68,16 @@ import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
public class DanaRv2ExecutionService extends Service {
private static Logger log = LoggerFactory.getLogger(DanaRv2ExecutionService.class);
private String devName;
private SerialIOThread mSerialIOThread;
private BluetoothSocket mRfcommSocket;
private BluetoothDevice mBTDevice;
private IBinder mBinder = new LocalBinder();
private DanaRPump danaRPump;
private Treatment bolusingTreatment = null;
private static Boolean connectionInProgress = false;
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
private long lastHistoryFetched = 0;
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
log.debug("Device was disconnected " + device.getName());//Device was disconnected
if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
if (mSerialIOThread != null) {
mSerialIOThread.disconnect("BT disconnection broadcast");
}
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED));
}
}
}
};
public DanaRv2ExecutionService() {
log = LoggerFactory.getLogger(DanaRv2ExecutionService.class);
mBinder = new LocalBinder();
registerBus();
MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
danaRPump = DanaRPump.getInstance();
}
public class LocalBinder extends Binder {
@ -103,17 +86,6 @@ public class DanaRv2ExecutionService extends Service {
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
private void registerBus() {
try {
MainApp.bus().unregister(this);
@ -138,35 +110,28 @@ public class DanaRv2ExecutionService extends Service {
log.debug("EventAppExit finished");
}
public boolean isConnected() {
return mRfcommSocket != null && mRfcommSocket.isConnected();
}
public boolean isConnecting() {
return connectionInProgress;
}
public void disconnect(String from) {
@Subscribe
public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect(from);
mSerialIOThread.disconnect("EventPreferenceChange");
}
public void connect(String from) {
if (danaRPump.password != -1 && danaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
public void connect() {
if (mDanaRPump.password != -1 && mDanaRPump.password != SP.getInt(R.string.key_danar_password, -1)) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
return;
}
if (connectionInProgress)
if (mConnectionInProgress)
return;
new Thread(new Runnable() {
@Override
public void run() {
connectionInProgress = true;
mConnectionInProgress = true;
getBTSocketForSelectedPump();
if (mRfcommSocket == null || mBTDevice == null) {
connectionInProgress = false;
mConnectionInProgress = false;
return; // Device not found
}
@ -187,48 +152,11 @@ public class DanaRv2ExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED, 0));
}
connectionInProgress = false;
mConnectionInProgress = false;
}
}).start();
}
public void stopConnecting() {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("stopConnecting");
}
private void getBTSocketForSelectedPump() {
devName = SP.getString(MainApp.sResources.getString(R.string.key_danar_bt_name), "");
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
if (devName.equals(device.getName())) {
mBTDevice = device;
try {
mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
log.error("Error creating socket: ", e);
}
break;
}
}
} else {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
}
if (mBTDevice == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
}
}
@Subscribe
public void onStatusEvent(final EventPreferenceChange pch) {
if (mSerialIOThread != null)
mSerialIOThread.disconnect("EventPreferenceChange");
}
public void getPumpStatus() {
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpstatus)));
@ -238,7 +166,7 @@ public class DanaRv2ExecutionService extends Service {
MsgStatusBolusExtended_v2 exStatusMsg = new MsgStatusBolusExtended_v2();
MsgCheckValue_v2 checkValue = new MsgCheckValue_v2();
if (danaRPump.isNewPump) {
if (mDanaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@ -253,8 +181,8 @@ public class DanaRv2ExecutionService extends Service {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingextendedbolusstatus)));
mSerialIOThread.sendMessage(exStatusMsg);
Date now = new Date();
if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) {
long now = System.currentTimeMillis();
if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
@ -268,28 +196,28 @@ public class DanaRv2ExecutionService extends Service {
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
danaRPump.lastSettingsRead = now;
mDanaRPump.lastSettingsRead = now;
}
loadEvents();
danaRPump.lastConnection = now;
mDanaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
}
} catch (Exception e) {
log.error("Unhandled exception", e);
@ -299,10 +227,10 @@ public class DanaRv2ExecutionService extends Service {
public boolean tempBasal(int percent, int durationInHours) {
if (!isConnected()) return false;
if (danaRPump.isTempBasalInProgress) {
if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
waitMsec(500);
SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
@ -314,10 +242,10 @@ public class DanaRv2ExecutionService extends Service {
public boolean highTempBasal(int percent) {
if (!isConnected()) return false;
if (danaRPump.isTempBasalInProgress) {
if (mDanaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
waitMsec(500);
SystemClock.sleep(500);
}
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetAPSTempBasalStart_v2(percent));
@ -362,7 +290,7 @@ public class DanaRv2ExecutionService extends Service {
if (BolusProgressDialog.stopPressed) return false;
MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.startingbolus)));
bolusingTreatment = t;
mBolusingTreatment = t;
final int preferencesSpeed = SP.getInt(R.string.key_danars_bolusspeed, 0);
MessageBase start;
if (preferencesSpeed == 0)
@ -390,7 +318,7 @@ public class DanaRv2ExecutionService extends Service {
return false;
}
while (!stop.stopped && !start.failed) {
waitMsec(100);
SystemClock.sleep(100);
if ((System.currentTimeMillis() - progress.lastReceive) > 15 * 1000L) { // if i didn't receive status for more than 15 sec expecting broken comm
stop.stopped = true;
stop.forced = true;
@ -403,7 +331,7 @@ public class DanaRv2ExecutionService extends Service {
bolusingEvent.t = t;
bolusingEvent.percent = 99;
bolusingTreatment = null;
mBolusingTreatment = null;
int speed = 12;
switch (preferencesSpeed) {
case 0:
@ -440,14 +368,14 @@ public class DanaRv2ExecutionService extends Service {
public void bolusStop() {
if (Config.logDanaBTComm)
log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
log.debug("bolusStop >>>>> @ " + (mBolusingTreatment == null ? "" : mBolusingTreatment.insulin));
MsgBolusStop stop = new MsgBolusStop();
stop.forced = true;
if (isConnected()) {
mSerialIOThread.sendMessage(stop);
while (!stop.stopped) {
mSerialIOThread.sendMessage(stop);
waitMsec(200);
SystemClock.sleep(200);
}
} else {
stop.stopped = true;
@ -464,57 +392,10 @@ public class DanaRv2ExecutionService extends Service {
return true;
}
public PumpEnactResult loadHistory(byte type) {
PumpEnactResult result = new PumpEnactResult();
if (!isConnected()) return result;
MessageBase msg = null;
switch (type) {
case RecordTypes.RECORD_TYPE_ALARM:
msg = new MsgHistoryAlarm();
break;
case RecordTypes.RECORD_TYPE_BASALHOUR:
msg = new MsgHistoryBasalHour();
break;
case RecordTypes.RECORD_TYPE_BOLUS:
msg = new MsgHistoryBolus();
break;
case RecordTypes.RECORD_TYPE_CARBO:
msg = new MsgHistoryCarbo();
break;
case RecordTypes.RECORD_TYPE_DAILY:
msg = new MsgHistoryDailyInsulin();
break;
case RecordTypes.RECORD_TYPE_ERROR:
msg = new MsgHistoryError();
break;
case RecordTypes.RECORD_TYPE_GLUCOSE:
msg = new MsgHistoryGlucose();
break;
case RecordTypes.RECORD_TYPE_REFILL:
msg = new MsgHistoryRefill();
break;
case RecordTypes.RECORD_TYPE_SUSPEND:
msg = new MsgHistorySuspend();
break;
}
MsgHistoryDone done = new MsgHistoryDone();
mSerialIOThread.sendMessage(new MsgPCCommStart());
waitMsec(400);
mSerialIOThread.sendMessage(msg);
while (!done.received && mRfcommSocket.isConnected()) {
waitMsec(100);
}
waitMsec(200);
mSerialIOThread.sendMessage(new MsgPCCommStop());
result.success = true;
result.comment = "OK";
return result;
}
public PumpEnactResult loadEvents() {
if (!isConnected())
return new PumpEnactResult().success(false);
waitMsec(300);
SystemClock.sleep(300);
MsgHistoryEvents_v2 msg;
if (lastHistoryFetched == 0) {
msg = new MsgHistoryEvents_v2();
@ -525,9 +406,9 @@ public class DanaRv2ExecutionService extends Service {
}
mSerialIOThread.sendMessage(msg);
while (!msg.done && mRfcommSocket.isConnected()) {
waitMsec(100);
SystemClock.sleep(100);
}
waitMsec(200);
SystemClock.sleep(200);
if (MsgHistoryEvents_v2.lastEventTimeLoaded != 0)
lastHistoryFetched = MsgHistoryEvents_v2.lastEventTimeLoaded - 45 * 60 * 1000L; //always load last 45 min;
else
@ -543,13 +424,10 @@ public class DanaRv2ExecutionService extends Service {
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
danaRPump.lastSettingsRead = new Date(0); // force read full settings
mDanaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
}
private void waitMsec(long msecs) {
SystemClock.sleep(msecs);
}
}

View file

@ -445,7 +445,6 @@
<string name="openapsama_bolussnooze_dia_divisor_summary">По подразбиране: 2\nBolus snooze се активира след като поставите болус за основно хранене, така Loop няма да пуснка/намаля базалите веднага след като сте се хранили. Примерът тук е с 2; така при 3 часа DIA това ще означава че bolus snooze ще бъде внимателно изместен 1.5 часа (3DIA/2).</string>
<string name="openapsama_min_5m_carbimpact_summary">По подразбиране: 3.0\nТова е настройка на количеството на покачване на КЗ при усвояване на въглехидратите за всеки 5 минути. По подразбиране 3мг/дл/5мин. Това се отразява на това колко бързо се усвояват COB според алгоритъма, и как това се отразява в предвиждането на КЗ, когато тя не се покачва или пада с различен темп от очакваното.</string>
<string name="openapsama_link_to_preferncejson_doc_txt">Внимание! Обикновено Вие не трябва да променяте тези стойности. Моля НАТИСНЕТЕ ТУК, прочетете текста и бъдете сигурни, че го РАЗБИРАТЕ преди да направите каквито и да е промени!</string>
<string name="openapsama_link_to_preferncejson_doc">http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html</string>
<string name="error_only_numeric_digits_allowed">Позволени са само числа</string>
<string name="error_only_numeric_digits_range_allowed" formatted="false">Позволени са числа между %1$s - %2$s</string>
<string name="error_field_must_not_be_empty">Полето не може да бъде празно</string>
@ -677,4 +676,64 @@
<string name="wear_settings">Настройки на часовник</string>
<string name="wearcontrol_summary">Задаване временни цели и въвеждане Лечения от часовник Android wear</string>
<string name="wearcontrol_title">Контролиране от часовник</string>
<string name="closedmodeenabled">Closed Loop е позволен</string>
<string name="combo_activity_reading_pump_history">Чете историята на помпата</string>
<string name="combo_activity_setting_basal_profile">Настройва базалният профил</string>
<string name="combo_error_bolus_recovery_progress">Опитва се да възстанови връзката</string>
<string name="combo_error_bolus_verification_failed">Доставянето на болуса и проверката на историята на помпата са неуспешни, моля, проверете помпата и ако е доставен болус го добавете като запис през Careportal</string>
<string name="customapp">Модифицирано приложение за изтегляне</string>
<string name="danar_setbasalstep001">Задайте стъпка на базала 0.01 Е</string>
<string name="DexcomG5">Dexcom G5 приложение (модифицирано)</string>
<string name="dexcomg5_nsupload_title">Качвай данните за КЗ в NS</string>
<string name="dexcomg5_xdripupload_summary">В xDrip+ изберете 640g/Eversense за източник на данни</string>
<string name="dexcomg5_xdripupload_title">Изпращай данни за КЗ към xDrip+</string>
<string name="enable_missed_bg_readings_alert">Аларма при липса на данни за КЗ</string>
<string name="enable_pump_unreachable_alert">Аларма при недостъпна помпа</string>
<string name="executingrightnow">Командата се изпълнява в момента</string>
<string name="extendedbolusdeliveryerror">Грешка при доставяне на удължен болус</string>
<string name="food">Храна</string>
<string name="hasbgdata">Има данни за КЗ от избрания източник</string>
<string name="info">ИНФО</string>
<string name="localalertsettings_title">Локални аларми</string>
<string name="loopenabled">Loop разрешен</string>
<string name="maxiobset">Максимален IOB е зададен правилно</string>
<string name="minimalbasalvaluereplaced">Базалната стойност е заместена от минимално подържаната</string>
<string name="missed_bg_readings">Липсват данни за КЗ</string>
<string name="negativeonly">Само отрицателни</string>
<string name="no">Не</string>
<string name="none"><![CDATA[<празно>]]></string>
<string name="nsclientbg">КЗ от NS</string>
<string name="nsclienthaswritepermission">NSClient има права за запис</string>
<string name="overview_editquickwizard_usebasaliob">Калкулиране на базален IOB</string>
<string name="overview_editquickwizard_usebg">Калкулиране на КЗ</string>
<string name="overview_editquickwizard_usebolusiob">Калкулиране на Болус IOB</string>
<string name="overview_editquickwizard_usecob">Калкулиране на COB</string>
<string name="overview_editquickwizard_usesuperbolus">Калкулиране суперболус</string>
<string name="overview_editquickwizard_usetemptarget">Калкулиране на временни цели</string>
<string name="overview_editquickwizard_usetrend">Калкулиране на тенденция КЗ</string>
<string name="positiveonly">Само положителни</string>
<string name="processinghistory">Обработва се събитие</string>
<string name="pump_unreachable">Помпата е недостъпна</string>
<string name="pump_unreachable_threshold">Лимит за недостъпна помпа [мин]</string>
<string name="pumpdrivercorrected">Драйверът за помпата е коригиран</string>
<string name="remaininsulinalert">Оставащ инсулин</string>
<string name="startingbolus">Стартира доставка на болус</string>
<string name="unsupportedfirmware">Неподдържан фърмуер на помпата</string>
<string name="urgent_alarm">Спешна аларма</string>
<string name="waitingforestimatedbolusend" formatted="false">Очаква края на болуса. Остават %d сек.</string>
<string name="wear_detailed_delta_summary">Показвай делта с още един десетичен знак</string>
<string name="wear_detailed_delta_title">Показвай подробна делта</string>
<string name="yes">Да</string>
<string name="zerovalueinprofile" formatted="false">Невалиден профил: %s</string>
<string name="shortenergy">En</string>
<string name="raise_notifications_as_android_notifications">Използвай системни известия за аларми и съобщения</string>
<string name="combo_warning">Внимание</string>
<string name="combo_tdd_minimum" formatted="false">Минимум: %3.1f U</string>
<string name="combo_tdd_maximum" formatted="false">Максимум: %3.1f U</string>
<string name="combo_tdd_average" formatted="false">Средно: %3.1f U</string>
<string name="combo_reservoir_normal">Нормално</string>
<string name="combo_reservoir_low">Ниско</string>
<string name="combo_reservoir_level_insufficient_for_bolus">Няма достатъчно инсулин в резервоара</string>
<string name="combo_reservoir_empty">Празен</string>
<string name="combo_refresh">Обнови</string>
</resources>

View file

@ -276,7 +276,7 @@
<string name="objectives_4_objective">Zapnout uzavřenou smyčku, zvyšovat max IOB nad 0 a snižovat cílovou glykémii</string>
<string name="objectives_5_gate">Jeden týden úspěšného používání s běžným příjmem sacharidů</string>
<string name="objectives_5_objective">Upravit bazály a koeficinty, když bude potřeba a povolit automatickou detekci citlivosti na inzulín</string>
<string name="objectives_6_objective">Povolit další fukce pro běžné používání jako AMA</string>
<string name="objectives_6_objective">Povolit další funkce pro běžné používání jako AMA</string>
<string name="youareonallowedlimit">Dosaženo limitu</string>
<string name="bolusdelivering" formatted="false">Aplikováno %.2fU</string>
<string name="smscommunicator_loophasbeendisabled">Smyčka byla zakázána</string>
@ -670,4 +670,113 @@
<string name="ultrafastactinginsulincomment">Fiasp</string>
<string name="ultrarapid_oref">Ultra rychlý - Oref</string>
<string name="waitingforestimatedbolusend" formatted="false">Čekání na konec bolusu. Zbývá %d sek.</string>
<string name="objectives_7_objective">Povolit další funkce pro běžné používání jako SMB</string>
<string name="openapsama_max_daily_safety_multiplier_summary">Výchozí hodnota: 3 Toto je klíčová hodnota zabezpečení. Říká, že maximánlní nastavitelný bazál je trojnásobkem maximálního denního bazálu. Patrně to nebudete muset měnit, případně si přečtete o tématu \"3x max denní; 4x aktuální\"</string>
<string name="openapsama_current_basal_safety_multiplier_summary">Výchozí hodnota: 4 Toto je druhá klíčová hodnota. Říká, že maximální hodnota dočasného bazálu nikdy nebude větší, než čtyřnásobek aktuálního bazálu. Je to proto, aby se lidé nedostali do hodnot nebezpečných bazálu dříve, než pochpí jak OpenAPS pracuje. Znovy vychozí hodnota je 4 a většina lidí ji nidky nebude muset změnit. Pokud nestačí, obvykle je problém někde jinde.</string>
<string name="openapsama_autosens_max_summary">Výchozí hodnota: 1.2 Toto je bezpečnostní nastavení pro detekci sensitivity. Říká, že autosens může zvýšit bazály, snížit ISF a snížit cílovou hodnotu glykémie o 20%</string>
<string name="openapsama_autosens_min_summary">Výchozí hodnota: 0.7 Toto je bezpečnostní nastavení pro detekci sensitivity. Říká, že autosens může snížit bazály, zvýšit ISF a zvýšit cílovou hodnotu glykémie na 70%</string>
<string name="openapsama_autosens_adjusttargets_summary">Výchozí hodnota: zapnuto Toto nastavení říká, že autosens může měnit také cílové hodnoty glykémií.</string>
<string name="openapsama_bolussnooze_dia_divisor_summary">Výchozí hodnota: 2 Toto nastavení říká, po jakou část z hodnoty DIA smyčka po bolusu čeká a nereaguje na změny glykémií (zde 3DIA/2 = 1,5h)</string>
<string name="openapsama_min_5m_carbimpact_summary">Výchozí hodnota: 3.0 Tato hodnota definuje minimální část strávených sacharidů za každých 5 min. Výchozí hodnota je 3mg/dl/5min. Tato hodnota ovlivňuje výpočet COB</string>
<string name="openapsama_link_to_preferncejson_doc_txt">Pozor! Za normálních okolností tyto hodnoty nemusíte měnit. Klikněte ZDE, PŘEČTĚTE si informace a UJISTĚTE se, že jim rozumíte dříve, než je začnete měnit.</string>
<string name="openapsama_autosens_period">Interval pro detekci senzitivity [h]</string>
<string name="openapsama_autosens_period_summary">Počet hodin do minulosti pro detekci senzitivity</string>
<string name="food">Jídlo</string>
<string name="shortgramm">g</string>
<string name="none"><![CDATA[<prázdný>]]></string>
<string name="shortkilojoul">kJ</string>
<string name="shortenergy">En</string>
<string name="shortprotein">Pr</string>
<string name="shortfat">Tuk</string>
<string name="executingrightnow">Příkaz je právě prováděn</string>
<string name="pumpdrivercorrected">Ovladač pumpy opraven</string>
<string name="pump_unreachable">Pumpa nedostupná</string>
<string name="missed_bg_readings">Chybějící glykémie</string>
<string name="raise_notifications_as_android_notifications">Používat systémové notifikace pro výstrahy a oznámení</string>
<string name="localalertsettings_title">Místní výstrahy</string>
<string name="enable_missed_bg_readings_alert">Výstraha při nedostupných glykémiích</string>
<string name="enable_pump_unreachable_alert">Výstraha při nedostupné pumpě</string>
<string name="pump_unreachable_threshold">Limit pro nedostupnost pumpy [min]</string>
<string name="urgent_alarm">Urgetní alarm</string>
<string name="info">INFO</string>
<string name="bluetooth">Bluetooth</string>
<string name="btwatchdog_title">Hlídač BT</string>
<string name="btwatchdog_summary">Vypne na 1 sek bluetooth v telefonu, pokud se nedaří připojit k pumpě. Může to pomoci u telefonů, které mají problémy s BT</string>
<string name="DexcomG5">DexcomG5 aplikace (upravená)</string>
<string name="dexcomg5_nsupload_title">Nahrávat data do NS</string>
<string name="dexcomg5_upload">Nastavení nahrávání z G5</string>
<string name="customapp">Upravená aplikace pro stažení</string>
<string name="wear_detailed_delta_title">Zobrazovat detailní změny</string>
<string name="wear_detailed_delta_summary">Zobrazovat rozdíl s jedním desetinným místem navíc</string>
<string name="unsupportedfirmware">Nepodporovaný firmware v pumpě</string>
<string name="dexcomg5_xdripupload_title">Odesílat data do xDrip+</string>
<string name="dexcomg5_xdripupload_summary">V xDrip+ vyberte zdroj dat 640g/Eversense</string>
<string name="nsclientbg">Glykémie z NS</string>
<string name="minimalbasalvaluereplaced">Hodnota bazálu nahrazena minimální možnou</string>
<string name="overview_editquickwizard_usebg">Kalkulace glykémie</string>
<string name="overview_editquickwizard_usebolusiob">Kalkulace bolusového IOB</string>
<string name="overview_editquickwizard_usebasaliob">Kalkulace bazálního IOB</string>
<string name="overview_editquickwizard_usetrend">Kalkulace trendu</string>
<string name="overview_editquickwizard_usesuperbolus">Kalkulace superbolusu</string>
<string name="yes">Ano</string>
<string name="no">No</string>
<string name="positiveonly">Pouze kladné</string>
<string name="negativeonly">Pouze záporné</string>
<string name="overview_editquickwizard_usecob">Kalkulace COB</string>
<string name="overview_editquickwizard_usetemptarget">Kalkulace s dočasným cílem</string>
<string name="loopenabled">Smyčka povolena</string>
<string name="apsselected">APS vybráno</string>
<string name="nsclienthaswritepermission">NSClient má povolení k zápisu</string>
<string name="closedmodeenabled">Uzavřená smyčka povolena</string>
<string name="maxiobset">Maximální IOB nastaveno správně</string>
<string name="hasbgdata">Glykémie dostupné z vybraného zdroje</string>
<string name="basalprofilenotaligned" formatted="false">Bazální hodnoty nejsou zarovnané na celé hodiny: %s</string>
<string name="zerovalueinprofile" formatted="false">Chybný profil: %s</string>
<string name="combo_programming_bolus">Programování pumpy pro bolus</string>
<string name="combo_refresh">Obnovit</string>
<string name="combo_pump_state_label">Stav</string>
<string name="combo_pump_activity_label">Aktivita</string>
<string name="combo_no_pump_connection" formatted="false">Žádné spojení %d min</string>
<string name="combo_tbr_remaining" formatted="false">%d%% (%d min zbývá)</string>
<string name="combo_pump_action_initializing">Inicializace</string>
<string name="combo_pump_state_disconnected">Odpojeno</string>
<string name="combo_pump_state_suspended_due_to_error">Vypnuto díky chybě</string>
<string name="combo_pump_state_suspended_by_user">Vypnuto uživatelem</string>
<string name="combo_pump_state_running">Beží</string>
<string name="combo_pump_action_cancelling_tbr">Rušení dočasného bazálu</string>
<string name="combo_pump_action_setting_tbr" formatted="false">Nastavování doč. bazálu (%d%% / %d min)</string>
<string name="combo_pump_action_bolusing" formatted="false">Bolus (%.1f U)</string>
<string name="combo_pump_action_refreshing">Obnovování</string>
<string name="combo_pump_never_connected">Nikdy</string>
<string name="combo_pump_unsupported_operation">Požadovaná operace není pumpou podporována</string>
<string name="combo_low_suspend_forced_notification">Nebezpečné použití: extended nebo multiwave bolus je aktivní. Pumpa byla vypnuta jen na 6 hodin. Povolené jsou pouze normální bolusy.</string>
<string name="combo_force_disabled_notification">Nebezpečné použití: pumpa má nastavený jiný bazální profil než první. Smyčka byla zakázána. Nastavete první profil a znovu načtěte.</string>
<string name="bolus_frequency_exceeded">Bolus stejné velikosti už byl během poslední minuty požadován. Jako preventivní ochrana před zdvojeným bolusem byla operace zakázána.</string>
<string name="combo_pump_connected_now">Teď</string>
<string name="combo_activity_reading_pump_history">Načítáni historie pumpy</string>
<string name="combo_pump_alerts">Výstrahy</string>
<string name="combo_activity_setting_basal_profile">Nastavení bazálního profilu</string>
<string name="combo_pump_cartridge_low_warrning">V zásobníku je málo inzulínu</string>
<string name="combo_pump_battery_low_warrning">Slabá baterie v pumpě</string>
<string name="combo_is_in_error_state" formatted="false">Pumpa hlásí chybu E%d: %s</string>
<string name="combo_error_bolus_recovery_progress">Pokouším se obnovit spojení</string>
<string name="combo_error_bolus_verification_failed">Provádění bolusu a čtení historie selhalo. Zkontrolujte pumpu a zadejte bolus přes péči</string>
<string name="combo_error_no_bolus_delivered">Provádění bolusu selhalo. Zdá se, že žádný bolus nebyl podán. Zkontrolujte pumpu a případně pošlete bolus znovu. Jako bezpečnostní opatření podání bolusu není opakováno.</string>
<string name="combo_error_partial_bolus_delivered" formatted="false">Pouze %.2f U z bolusu %.2f bylo podáno díky chybě. Zkontrolujte pumpu a proveďte nápravu.</string>
<string name="combo_history">Historie</string>
<string name="combo_pump_tbr_cancelled_warrning">Varování o ukončeném dočasném bazálu bylo potvrzeno.</string>
<string name="combo_warning">Varování</string>
<string name="combo_reservoir_empty">Prázdný</string>
<string name="combo_reservoir_low">Nízký</string>
<string name="combo_reservoir_normal">Normální</string>
<string name="combo_tdd_average" formatted="false">Průměr: %3.1f U</string>
<string name="combo_tdd_maximum" formatted="false">Maximum: %3.1f U</string>
<string name="combo_tdd_minimum" formatted="false">Minimum: %3.1f U</string>
<string name="combo_no_alert_data_note">Pro přečtení historie chyb dlouze stiskněte tlačítko ALERTS. Varování: může to způsobit chybu, že pumpa bude odmítat všechny připojení a je pak vyžadováno stisknutí tlačítka na pumpě pro obnovení komunikace.</string>
<string name="combo_notification_check_time_date">Je vyžadována aktualizace času na pumpě</string>
<string name="combo_no_tdd_data_note">Pro přečtení celkových denních dávek dlouze stikněte na pumpě tlačítko TDDS. Varování: může to způsobit chybu, že pumpa bude odmítat všechny připojení a je pak vyžadováno stisknutí tlačítka na pumpě pro obnovení komunikace.</string>
<string name="combo_read_full_history_warning">Toto načte kompletní historii pumpy a stavy. Všechno v My Data a hodnoty bazálů. Bolusy a dočasné bazály budou přidány do ošetření, pokud neexistují. Může to způsobit duplicity díky nepřesnosti času v pumpě. Neporučuje se pokud používáte smyčku a je určeno pouze pro speciální připady. Varování: může to způsobit chybu, že pumpa bude odmítat všechny připojení a je pak vyžadováno stisknutí tlačítka na pumpě pro obnovení komunikace.</string>
<string name="combo_read_full_history_confirmation">Opravdu chcete přečíst historii z pumpy a nést důsledky z toho vyplývající?</string>
<string name="combo_reservoir_level_insufficient_for_bolus">Nedostatek inzulínu pro takovýto bolus</string>
<string name="extendedbolusdeliveryerror">Chyba spuštění extended bolusu</string>
</resources>

View file

@ -711,9 +711,6 @@
<string name="combo_pump_activity_label">Aktivität</string>
<string name="combo_tbr_remaining">%d%% (%d Min. verbleibend)</string>
<string name="combo_no_pump_connection">Keine Verbindung zur Pumpe seit %d Min.</string>
<string name="bolusstopped">Bolusabgabe gestoppt</string>
<string name="bolusstopping">Bolusabgabe wird abgebrochen</string>
<string name="pump_errors_history">Fehlerprotokol</string>
<string name="combo_pump_state_label">Status</string>
<string name="combo_pump_state_disconnected">Keine Verbindung zur Pumpe</string>
<string name="combo_pump_state_suspended_by_user">Gestoppt (Benutzer)</string>
@ -727,7 +724,6 @@
<string name="alert_dialog_storage_permission_text">Bitte starte dein Telefon neu oder starte AndroidAPS in den System-Einstellungen neu. Andernfalls wird AndroidAPS nicht protokolliert (wichtig zum Nachverfolgen und Verifizieren, dass der Algorithmus korrekt funktioniert)</string>
<string name="pump_tempbasal_label">TBR</string>
<string name="combo_last_bolus">%.1f IE (%s, %s)</string>
<string name="raise_urgent_alarms_as_android_notification">Nutze System-Benachrichtigungen für Alarme</string>
<string name="bolus_frequency_exceeded">Ein gleich großer Bolus wurde in der letzten Minute angefordert. Dies ist nicht zulässig, um ungewollte Doppelboli zu verhindern und vor eventuellen Bugs zu schützen.</string>
<string name="combo_activity_reading_pump_history">Historie wird gelesen</string>
<string name="combo_activity_setting_basal_profile">Basalratenprofil wird aktualisiert</string>

View file

@ -231,8 +231,8 @@
<string name="smscommunicator_allowednumbers_summary">XXXXXXXXXX +; + YYYYYYYYYY</string>
<string formatted="false" name="smscommunicator_bolusreplywithcode">Para entregar bolo% .2fU responder con código% s</string>
<string name="smscommunicator_bolusfailed">Bolo falló</string>
<string formatted="false" name="bolusdelivered">Bolo% .2fU entregado con éxito</string>
<string formatted="false" name="bolusdelivering">Entregando% .2fU</string>
<string formatted="false" name="bolusdelivered">Bolo %.2fU entregado con éxito</string>
<string formatted="false" name="bolusdelivering">Entregando %.2fU</string>
<string name="smscommunicator_remotebolusnotallowed">Bolo remoto no permitido</string>
<string name="glucosetype_finger">Dedo</string>
<string name="glucosetype_sensor">Sensor</string>

View file

@ -129,9 +129,9 @@
<string name="apsmode_title">APS 모드</string>
<string name="closedloop">Closed Loop</string>
<string name="openloop">Open Loop</string>
<string name="disabledloop">Loop 비활성화</string>
<string name="disableloop">Loop 비활성화하기</string>
<string name="enableloop">Loop 활성화하기</string>
<string name="disabledloop">Loop 중지</string>
<string name="disableloop">Loop 중지하기</string>
<string name="enableloop">Loop 실행하기</string>
<string name="openloop_newsuggestion">새로운 제안이 있습니다</string>
<string name="unsupportedclientver">지원하지 않는 NSClient 버전입니다</string>
<string name="unsupportednsversion">지원하지 않는 Nightscout 버전입니다</string>
@ -183,7 +183,7 @@
<string name="overview_tempbasal_button">임시기초주입</string>
<string name="overview_extendedbolus_button">확장식사주입</string>
<string name="configbuilder_nightscoutversion_label">Nightscout 버전:</string>
<string name="send">보내</string>
<string name="send">전송하</string>
<string name="missing">Missing</string>
<string name="enabled">사용</string>
<string name="visible">보이기</string>
@ -252,13 +252,12 @@
<string name="glucosetype_finger">Finger</string>
<string name="glucosetype_sensor">Sensor</string>
<string name="manual">Manual</string>
<string name="careportal_temporarytarget">임시 목표</string>
<string name="careportal_temporarytargetcancel">임시 목표 취소</string>
<string name="careportal_temporarytarget">임시목표</string>
<string name="careportal_temporarytargetcancel">임시목표 취소</string>
<string name="danarprofile">DanaR 프로파일 설정</string>
<string name="danarprofile_dia">인슐린활동시간(DIA) [h]</string>
<string name="danarprofile_dia_summary">Duration of Insulin Activity</string>
<string name="failedupdatebasalprofile">기초주입 프로파일 갱신 실패</string>
<string name="danar_history">과거기록</string>
<string name="danar_historyreload">새로고침</string>
<string name="uploading">업로드중</string>
<string name="danar_ebolus">E bolus</string>
@ -306,14 +305,15 @@
<string name="objectives_5_objective">필요하면 기초주입과 비율을 조절하고, auto-sens를 활성화한다.</string>
<string name="objectives_5_gate">평소의 탄수화물을 입력하면서 1주일동안 낮시간대에 loop를 성공적으로 사용해본다.</string>
<string name="objectives_6_objective">AMA(Advanced Meal Assist)같은 낮시간대를 위한 추가적인 기능들을 실행하여 본다.</string>
<string name="objectives_7_objective">낮시간대에 SMB(Super Micro Bolus)같은 추가기능을 활성화해 사용해본다.</string>
<string name="youareonallowedlimit">허용된 제한값에 도달하였습니다</string>
<string name="noprofileselected">프로파일이 선택되지 않았습니다</string>
<string name="smscommunicator_loophasbeendisabled">Loop가 중지되었습니다.</string>
<string name="smscommunicator_loophasbeenenabled">Loop가 실행되었습니다.</string>
<string name="smscommunicator_loopisdisabled">Loop가 중지중입니다.</string>
<string name="smscommunicator_loopisenabled">Loop가 실행중입니다.</string>
<string name="openapsma_valuelimitedto" formatted="false">%.2f limited to %.2f</string>
<string name="openapsma_valueoutofrange" formatted="false">값 %s 은 하드리밋(Hard Limit)를 벗어났습니다</string>
<string name="openapsma_valuelimitedto" formatted="false">%.2f, %.2f으로 제한됨</string>
<string name="openapsma_valueoutofrange" formatted="false">%s값이 하드리밋(Hard Limit)를 벗어났습니다</string>
<string name="smscommunicator_remotebasalnotallowed">원격 기초주입설정이 허가되지 않았습니다</string>
<string name="smscommunicator_remotecommandnotallowed">원격 명령이 허가되지 않았습니다</string>
<string name="smscommunicator_basalreplywithcode" formatted="false">기초주입 %.2fU/h 을 실행하려면 %s 를 입력하고 답장하세요</string>
@ -385,20 +385,20 @@
<string name="MM640g">MM640g</string>
<string name="ongoingnotificaction">연속 알림</string>
<string name="old_data">OLD DATA</string>
<string name="minago">%d분전</string>
<string name="sms_minago">%dmin ago</string>
<string name="minago" formatted="false">%d분전</string>
<string name="sms_minago" formatted="false">%dmin ago</string>
<string name="localprofile">Local Profile</string>
<string name="openapsama">OpenAPS AMA</string>
<string name="short_avgdelta">Short avg. delta</string>
<string name="long_avgdelta">Long avg. delta</string>
<string name="array_of_elements">Array of %d elements.\nActual value:</string>
<string name="array_of_elements" formatted="false">Array of %d elements.\nActual value:</string>
<string name="openapsma_autosensdata_label">Autosens 정보</string>
<string name="openapsma_scriptdebugdata_label">Script debug</string>
<string name="openapsama_useautosens">AMA autosens 기능 사용하기</string>
<string name="refresheventsfromnightscout">NS에서 이벤트 새로고침</string>
<string name="eatingsoon">Eating Soon</string>
<string name="activity">Activity</string>
<string name="removerecord">Remove record:</string>
<string name="removerecord">기록 삭제:</string>
<string name="danar_stats">DanaR 통계</string>
<string name="danar_stats_cumulative_tdd">누적 일총량</string>
<string name="danar_stats_expweight">지수가중 일총량</string>
@ -437,7 +437,7 @@
<string name="always_use_shortavg">단순델타값 대신 단기평균델타값을 항상 사용합니다.</string>
<string name="always_use_shortavg_summary">xDrip의 혈당데이터에 노이즈가 심할경우 유용합니다.</string>
<string name="advancedsettings_title">고급 설정</string>
<string name="danar_model" formatted="false">Model: %02X Protocol: %02X Code: %02X</string>
<string name="danar_model" formatted="false">모델: %02X 프로토콜: %02X 코드: %02X</string>
<string name="profile">프로파일</string>
<string name="openapsama_max_daily_safety_multiplier_summary">기본값: 3\n이 값은 중요한 OpenAPS 안전장치입니다. 이 값의 역할은 펌프에 설정되어 있는 최대기초주입량보다 3배를 초과할 수 없게 제한하는 것입니다. 이 값을 변경할 필요는 없을 것이지만, 안전을 위해 "3x max daily; 4x current"이 의미하는 바를 알고 있어야 합니다.</string>
<string name="openapsama_current_basal_safety_multiplier_summary">기본값: 4\n이 값은 "3x max daily; 4x current"의 나머지 절반에 해당하는 또 다른 중요한 OpenAPS 안전장치입니다. 이 값은 펌프에 설정된 최대기초주입량과 관계없이, 설정된 현재시간의 기초주입량에 이 값을 곱한 양을 초과할 수 없게됩니다. 이는 알고리즘의 작동 방식을 이해하기 전에 과도하게 높은 최대 기본을 설정하여 위험한 상황에 빠지지 않도록 보호하기 위한 것입니다. 다시한번, 기본 값은 4배인 것을 알아두세요; 일반적으로 이것을 조정할 필요는 전혀 없으며, 대신 이 안전장치를 변경해야할것처럼 생각이 된다면, 다른 설정을 변경해야 할 가능성이 더 큽니다.</string>
@ -449,12 +449,12 @@
<string name="openapsama_link_to_preferncejson_doc_txt">주의!\n보통의 경우 아래의 값을 변경하면 안됩니다. 이 값들을 변경하기 전에 반드시 이곳을 클릭하고 글을 정독해서 확실하게 이해를 하여야 합니다.</string>
<string name="openapsama_link_to_preferncejson_doc">http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html</string>
<string name="error_only_numeric_digits_allowed">숫자만 입력가능합니다.</string>
<string name="error_only_numeric_digits_range_allowed">이 범위(%1$s - %2$s)안에 해당하는 숫자만 입력가능합니다.</string>
<string name="error_only_numeric_digits_range_allowed" formatted="false">이 범위(%1$s - %2$s)안에 해당하는 숫자만 입력가능합니다.</string>
<string name="error_field_must_not_be_empty">필수 입력 항목입니다.</string>
<string name="error_phone_not_valid">폰번호가 유효하지 않습니다</string>
<string name="smscommunicator_invalidphonennumber">SMS폰번호가 유효하지 않습니다</string>
<string name="copy_to_clipboard">Copy To Clipboard</string>
<string name="copied_to_clipboard">Copied to clipboard</string>
<string name="copy_to_clipboard">클립보드에 복사</string>
<string name="copied_to_clipboard">클립보드에 복사되었습니다</string>
<string name="nav_show_logcat">로그 보기</string>
<string name="overview_calibration">보정</string>
<string name="overview_calibration_bg_label">혈당 보정</string>
@ -476,7 +476,7 @@
<string name="disconnecting">연결끊기중</string>
<string name="executing">실행중</string>
<string name="virtualpump_settings">가상펌프 설정</string>
<string name="virtualpump_uploadstatus_title">Upload status to NS</string>
<string name="virtualpump_uploadstatus_title">NS에 상태 업로드하기</string>
<string name="wrongpassword">잘못된 비밀번호</string>
<string name="settings_password">설정 비밀번호</string>
<string name="unlock_settings">설정 잠금해제</string>
@ -484,7 +484,7 @@
<string name="nsclientinternal">내장 NSClient</string>
<string name="nsclientinternal_shortname">NSCI</string>
<string name="nsclientinternal_url">URL:</string>
<string name="nsclientinternal_autoscroll">Autoscroll</string>
<string name="nsclientinternal_autoscroll">자동스크롤</string>
<string name="restart">Restart</string>
<string name="nsclientinternal_title">내장 NSClient</string>
<string name="nsclientinternal_url_title">Nightscout URL</string>
@ -500,13 +500,13 @@
<string name="show_queue">Show queue</string>
<string name="queue">Queue:</string>
<string name="status">Status:</string>
<string name="paused">Paused</string>
<string name="paused">일시중지</string>
<string name="clearlog">Clear log</string>
<string name="nowritepermission">NSCLIENT이 쓰기 권한이 없습니다. 잘못된 API secret인지 확인해보세요</string>
<string name="wear_settings">웨어 설정</string>
<string name="wear_detailedIOB_title">IOB 자세하게 보여주기</string>
<string name="wear_detailedIOB_summary">워치페이스에 IOB를 식사주입IOB와 기초주입IOB로 나누어서 보여줍니다.</string>
<string name="nosuccess">not successful - please check phone</string>
<string name="nosuccess">성공하지 못했습니다. 폰을 확인하세요</string>
<string name="notavailable">알수없음</string>
<string name="patientage">나이</string>
<string name="child">어린이</string>
@ -516,10 +516,9 @@
<string name="Glimp">Glimp</string>
<string name="batteryoptimalizationerror">Device does not appear to support battery optimization whitelisting!</string>
<string name="pleaseallowpermission">권한을 허용하세요.</string>
<string name="needwhitelisting">%s needs battery optimalization whitelisting for proper performance</string>
<string name="loopsuspended">Loop 일시중지</string>
<string name="loopsuspendedfor" formatted="false">일시중지중 (%d분)</string>
<string name="loopsuperbolusfor" formatted="false">Superbolus (%d분)</string>
<string name="loopsuperbolusfor" formatted="false">수퍼 식사주입 (%d분)</string>
<string name="loopmenu">Loop 메뉴</string>
<string name="suspendloopfor1h">1시간동안 Loop 일시중지</string>
<string name="suspendloopfor2h">2시간동안 Loop 일시중지</string>
@ -530,24 +529,24 @@
<string name="disconnectpumpfor2h">2시간동안 펌프 일시중지</string>
<string name="disconnectpumpfor3h">3시간동안 펌프 일시중지</string>
<string name="disconnectpumpfor10h">10시간동안 펌프 일시중지</string>
<string name="resume">시작</string>
<string name="resume">실행</string>
<string name="smscommunicator_wrongduration">기간이 잘못되었습니다.</string>
<string name="smscommunicator_loopsuspended">Loop가 일시중지되었습니다.</string>
<string name="smscommunicator_loopresumed">Loop가 재시작되었습니다.</string>
<string name="smscommunicator_loopsuspended">Loop가 일시중지 되었습니다.</string>
<string name="smscommunicator_loopresumed">Loop가 재실행 되었습니다.</string>
<string name="treatments_wizard_bgtrend_label">15분 추이</string>
<string name="treatments_wizard_cob_label">COB</string>
<string name="superbolus">Superbolus</string>
<string name="superbolus">수퍼 식사주입</string>
<string name="ns_logappstartedevent">앱시작을 NS에 기록하기</string>
<string name="restartingapp">설정을 적용하기위해 앱을 종료합니다.</string>
<string name="danarv2pump">다나Rv2</string>
<string name="configbuilder_insulin">인슐린</string>
<string name="fastactinginsulin">Fast Acting Insulin</string>
<string name="fastactinginsulincomment">Novorapid, Novolog, Humalog</string>
<string name="ultrafastactinginsulincomment">Fiasp</string>
<string name="fastactinginsulincomment">노보래피드, 휴마로그, 에피드라</string>
<string name="ultrafastactinginsulincomment">피아스프(Fiasp)</string>
<string name="insulin_shortname">INS</string>
<string name="fastactinginsulinprolonged">Fast Acting Insulin Prolonged</string>
<string name="enablesuperbolus">마법사에서 Superbolus 활성화하기</string>
<string name="enablesuperbolus_summary">마법사에서 Superbolus 기능을 활성화합니다. 어떤 기능인지 확실히 알기전까지 활성화 하지 마세요. 제대로 알지 못하고 사용하면 일슐린이 과다 주입될 수 있습니다!</string>
<string name="enablesuperbolus">마법사에서 수퍼 식사주입 활성화하기</string>
<string name="enablesuperbolus_summary">마법사에서 수퍼 식사주입 기능을 활성화합니다. 어떤 기능인지 확실히 알기전까지 활성화 하지 마세요. 제대로 알지 못하고 사용하면 일슐린이 과다 주입될 수 있습니다!</string>
<string name="iob">IOB</string>
<string name="cob">COB</string>
<string name="predictionshortlabel">PRE</string>
@ -584,15 +583,15 @@
<string name="careportal_pbage_label">펌프배터리사용기간</string>
<string name="careportal_pumpbatterychange">펌프 배터리 교체</string>
<string name="ns_alarmoptions">알람 옵션</string>
<string name="nsalarm_urgenthigh">Urgent high</string>
<string name="nsalarm_high">High</string>
<string name="nsalarm_low">Low</string>
<string name="nsalarm_urgentlow">Urgent low</string>
<string name="nsalarm_urgenthigh">위험 고혈당</string>
<string name="nsalarm_high">고혈당</string>
<string name="nsalarm_low">저혈당</string>
<string name="nsalarm_urgentlow">위험 저혈당</string>
<string name="nsalarm_summary" formatted="false">Currently set to %f</string>
<string name="nsalarm_staledata">Stale data</string>
<string name="nsalarm_urgentstaledata">Urgent stale data</string>
<string name="nsalarm_staledatavalue_label">Stale data threshold [min]</string>
<string name="nsalarm_urgent_staledatavalue_label">Urgent stale data threshold [min]</string>
<string name="nsalarm_staledata">누락 데이터</string>
<string name="nsalarm_urgentstaledata">위험 누락 데이터</string>
<string name="nsalarm_staledatavalue_label">누락 데이터 기준값[분]</string>
<string name="nsalarm_urgent_staledatavalue_label">위험 누락 데이터 기준값[분]</string>
<string name="openapsama_autosens_period">autosens 시간 [h]</string>
<string name="openapsama_autosens_period_summary">민감도를 감지하기 위해 계산될 총 시간 (탄수화물 흡수 시간은 제외됩니다.)</string>
<string name="ratio_short">SEN</string>
@ -604,8 +603,8 @@
<string name="uploader">Uploader</string>
<string name="configbuilder_sensitivity">민감도 감지</string>
<string name="sensitivity_shortname">SENS</string>
<string name="sensitivityoref0">Sensitivity Oref0</string>
<string name="sensitivityaaps">Sensitivity AAPS</string>
<string name="sensitivityoref0">민감도 Oref0</string>
<string name="sensitivityaaps">민감도 AAPS</string>
<string name="absorptionsettings_title">흡수 설정</string>
<string name="absorption_maxtime_title">식사 최대 흡수 시간 [h]</string>
<string name="absorption_maxtime_summary">식사로 섭취한 탄수화물이 모두 흡수될기까지 예상되는 시간</string>
@ -621,7 +620,7 @@
<string name="lock_screen">화면 잠금</string>
<string name="lock_screen_short">잠금</string>
<string name="sensitivity_warning">Autosense 기능을 켜면 모든 섭취된 탄수화물양을 입력하십시오. 그렇지 않으면 탄수화물 편차(deviations)가 민감도 변화로 잘못 인식될것입니다!!</string>
<string name="sensitivityweightedaverage">Sensitivity WeightedAverage</string>
<string name="sensitivityweightedaverage">민감도 가중평균</string>
<string name="mdtp_ok">OK</string>
<string name="mdtp_cancel">Cancel</string>
<string name="cpp_sync_setting_missing">needs to be activated to send values to the pump!</string>
@ -637,13 +636,13 @@
<string name="careportal_pump_label">펌프</string>
<string name="overview_newtempbasal_basalabsolute">Basal value [U/h]</string>
<string name="careportal_newnstreatment_duration_min_label">Duration [min]</string>
<string name="insulin_oref_peak">IOB Curve Peak Time</string>
<string name="insulin_peak_time">Peak Time [min]</string>
<string name="insulin_oref_peak">IOB 커브 피크 시간</string>
<string name="insulin_peak_time">피크 시간[분]</string>
<string name="free_peak_oref">Free-Peak Oref</string>
<string name="rapid_acting_oref">Rapid-Acting Oref</string>
<string name="ultrarapid_oref">Ultra-Rapid Oref</string>
<string name="dia_too_short" formatted="false">"DIA of %s too short - using %s instead!"</string>
<string name="activate_profile">ACTIVATE PROFILE</string>
<string name="dia_too_short" formatted="false">"DIA %s는 너무 짧습니다. 대신 %s을 사용하세요!"</string>
<string name="activate_profile">프로파일 활성화하기</string>
<string name="date">Date</string>
<string name="invalid">INVALID</string>
<string name="waitingforpairing">펌프연동 대기중</string>
@ -678,4 +677,60 @@
<string name="wearcontrol_title">워치로 작동하기</string>
<string name="wearcontrol_summary">임시목표와 관리입력을 워치로 설정합니다.</string>
<string name="connectiontimedout">연결시간초과</string>
<string name="food">음식</string>
<string name="shortgramm">g</string>
<string name="none"><![CDATA[<none>]]></string>
<string name="shortkilojoul">kJ</string>
<string name="shortenergy">En</string>
<string name="shortprotein">Pr</string>
<string name="shortfat">Fat</string>
<string name="active"><![CDATA[<Active>]]></string>
<string name="waitingforestimatedbolusend" formatted="false">식사주입 종료를 기다리고 있습니다. %d초 남았습니다.</string>
<string name="processinghistory">이벤트 처리중</string>
<string name="startingbolus">식사주입을 시작합니다.</string>
<string name="executingrightnow">명령을 지금 실행합니다.</string>
<string name="pumpdrivercorrected">펌프 드라이버가 수정되었습니다.</string>
<string name="pump_unreachable">펌프에 연결할 수 없습니다.</string>
<string name="missed_bg_readings">혈당 읽기가 누락되었습니다.</string>
<string name="raise_notifications_as_android_notifications">경고와 알림시 시스템 알림 사용하기</string>
<string name="localalertsettings_title">자체 경고 기능</string>
<string name="enable_missed_bg_readings_alert">혈당 데이터 누락시 경고하기</string>
<string name="enable_pump_unreachable_alert">펌프와 연결불가시 경고하기</string>
<string name="pump_unreachable_threshold">펌프 연결불가 기준시간[분]</string>
<string name="urgent_alarm">긴급 알람</string>
<string name="info">정보</string>
<string name="bluetooth">블루투스</string>
<string name="btwatchdog_title">블루투스 감시기능</string>
<string name="btwatchdog_summary">펌프에 연결이 되지 않을때 폰의 블루투스를 1초간 껐다 켭니다. 블루투스 스택이 정지되는 일부폰에 이 기능이 도움이 됩니다.</string>
<string name="DexcomG5">(패치된) DexcomG5 앱</string>
<string name="dexcomg5_nsupload_title">NS에 혈당데이터 업로드하기</string>
<string name="dexcomg5_upload">G5업로드 세팅</string>
<string name="customapp">Customized APK for download</string>
<string name="wear_detailed_delta_title">델타(혈당증분값) 자세히 보여주기</string>
<string name="wear_detailed_delta_summary">소수점 한자리 더 추가된 델타 보여주기</string>
<string name="unsupportedfirmware">지원되지 않는 펌프 펌웨어</string>
<string name="dexcomg5_xdripupload_title">혈당 데이터를 xDrip+에 전송하기</string>
<string name="dexcomg5_xdripupload_summary">xDrip+ 데이터 소스에서 640g/Eversense을 선택하세요</string>
<string name="minimalbasalvaluereplaced">지원되는 최소값으로 기초주입량이 대체되었습니다.</string>
<string name="overview_editquickwizard_usebg">혈당 계산</string>
<string name="overview_editquickwizard_usebolusiob">식사주입 IOB 계산</string>
<string name="overview_editquickwizard_usebasaliob">기초주입 IOB 계산</string>
<string name="overview_editquickwizard_usetrend">추세계산</string>
<string name="overview_editquickwizard_usesuperbolus">수퍼 식사주입 계산</string>
<string name="yes"></string>
<string name="no">아니오</string>
<string name="positiveonly">양수만</string>
<string name="negativeonly">음수만</string>
<string name="overview_editquickwizard_usecob">COB 계산</string>
<string name="overview_editquickwizard_usetemptarget">임시목표 계산</string>
<string name="loopenabled">Loop 활성화됨</string>
<string name="apsselected">APS 선택됨</string>
<string name="nsclienthaswritepermission">NSClient가 쓰기권한이 있습니다</string>
<string name="closedmodeenabled">Closed 모드가 활성화됨</string>
<string name="maxiobset">최대 IOB가 바르게 설정됨</string>
<string name="hasbgdata">선택한 소스에서 혈당이 들어옵니다.</string>
<string name="basalprofilenotaligned" formatted="false">기초주입값이 시간단위로 설정되지 않았습니다: %s</string>
<string name="zerovalueinprofile" formatted="false">유효하지 않은 프로파일: %s</string>
<string name="danar_history">펌프 이력</string>
<string name="extendedbolusdeliveryerror">확장식사주입 에러</string>
</resources>

View file

@ -676,16 +676,12 @@
<string name="wearcontrol_title">Bedieningen via horloge</string>
<string name="emptyreservoir">Ampull leeg</string>
<string name="waitingforpairing">Wachten op koppelen van de pomp</string>
<string name="pump_errors_history">Storingen</string>
<string name="profileswitch">Wijzigingen van profiel</string>
<string name="bluetooth">Bluetooth</string>
<string name="food">Voeding</string>
<string name="enable_pump_unreachable_alert">Waarschuwing bij niet bereikbare pomp</string>
<string name="bolus_frequency_exceeded">Een bolus met dezelfde hoeveelheid was gevraagd binnen de minuut. Om accidentiële of door bugs veroorzaakte dubbele bolussen te vermijden is deze bolus geannuleerd</string>
<string name="bolusstopping">estopt Bolus toediening wordt</string>
<string name="shortfat">Vet</string>
<string name="bolusstopped">Bolus toediening gestopt</string>
<string name="raise_urgent_alarms_as_android_notification">Gebruik systeem notificaties voor waarschuwingen</string>
<string name="wear_detailed_delta_title">Toon gedetaillieerde delta</string>
<string name="unsupportedfirmware">Niet ondersteune pomp firmware</string>
<string name="DexcomG5">DexcomG5 App (aangepast)</string>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name"></string>
</resources>

View file

@ -20,6 +20,7 @@
<item>@string/el_lang</item>
<item>@string/it_lang</item>
<item>@string/ko_lang</item>
<item>@string/ro_lang</item>
<item>@string/ru_lang</item>
<item>@string/sv_lang</item>
</string-array>
@ -33,6 +34,7 @@
<item>el</item>
<item>it</item>
<item>ko</item>
<item>ro</item>
<item>ru</item>
<item>sv</item>
</string-array>

View file

@ -209,6 +209,7 @@
<string name="es_lang">Spanish</string>
<string name="el_lang">Greek</string>
<string name="it_lang">Italian</string>
<string name="ro_lang">Romanian</string>
<string name="ru_lang">Russian</string>
<string name="sv_lang">Swedish</string>
<string name="openapsma_maxbasal_title">Max U/hr a Temp Basal can be set to</string>
@ -268,7 +269,6 @@
<string name="danarprofile_dia">DIA [h]</string>
<string name="danarprofile_dia_summary">Duration of Insulin Activity</string>
<string name="failedupdatebasalprofile">Failed to update basal profile</string>
<string name="pump_errors_history">Errors</string>
<string name="danar_historyreload">Reload</string>
<string name="uploading">Uploading</string>
<string name="danar_ebolus">E bolus</string>
@ -452,9 +452,9 @@
<string name="danar_model" formatted="false">Model: %02X Protocol: %02X Code: %02X</string>
<string name="profile">Profile</string>
<string name="openapsama_max_daily_safety_multiplier" translatable="false">max_daily_safety_multiplier</string>
<string name="openapsama_max_daily_safety_multiplier_summary">Default value: 3\nThis is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware thats what is discussed about “3x max daily; 4x current” for safety caps.</string>
<string name="openapsama_max_daily_safety_multiplier_summary">Default value: 3 This is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware thats what is discussed about “3x max daily; 4x current” for safety caps.</string>
<string name="openapsama_current_basal_safety_multiplier" translatable="false">current_basal_safety_multiplier</string>
<string name="openapsama_current_basal_safety_multiplier_summary">Default value: 4\nThis is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.</string>
<string name="openapsama_current_basal_safety_multiplier_summary">Default value: 4 This is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.</string>
<string name="openapsama_autosens_max" translatable="false">autosens_max</string>
<string name="openapsama_autosens_max_summary">Default value: 1.2\nThis is a multiplier cap for autosens (and soon autotune) to set a 20% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target.</string>
<string name="openapsama_autosens_min" translatable="false">autosens_min</string>
@ -464,9 +464,9 @@
<string name="openapsama_bolussnooze_dia_divisor" translatable="false">bolussnooze_dia_divisor</string>
<string name="openapsama_bolussnooze_dia_divisor_summary">Default value: 2\nBolus snooze is enacted after you do a meal bolus, so the loop wont counteract with low temps when youve just eaten. The example here and default is 2; so a 3 hour DIA means that bolus snooze will be gradually phased out over 1.5 hours (3DIA/2).</string>
<string name="openapsama_min_5m_carbimpact" translatable="false">min_5m_carbimpact</string>
<string name="openapsama_min_5m_carbimpact_summary">Default value: 3.0\nThis is a setting for default carb absorption impact per 5 minutes. The default is an expected 3mg/dl/5min. This affects how fast COB are decayed, and how much carb absorption is assumed in calculating future predicted BG, when BG is falling more than expected, or not rising as much as expected.</string>
<string name="openapsama_min_5m_carbimpact_summary">Default value: 3.0 This is a setting for default carb absorption impact per 5 minutes. The default is an expected 3mg/dl/5min. This affects how fast COB are decayed, and how much carb absorption is assumed in calculating future predicted BG, when BG is falling more than expected, or not rising as much as expected.</string>
<string name="openapsama_link_to_preferncejson_doc_txt">Attention!\nNormally you do not have to change these values below. Please CLICK HERE and READ the text and make sure you UNDERSTAND it before change any of these values.</string>
<string name="openapsama_link_to_preferncejson_doc">http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html</string>
<string name="openapsama_link_to_preferncejson_doc" translatable="false">http://openaps.readthedocs.io/en/latest/docs/walkthrough/phase-3/beyond-low-glucose-suspend.html</string>
<string name="error_only_numeric_digits_allowed">Only numeric digits are allowed.</string>
<string name="error_only_numeric_digits_range_allowed">Only numeric digits within the range %1$s - %2$s are allowed.</string>
<string name="error_field_must_not_be_empty">The field must not be empty</string>
@ -781,7 +781,7 @@
<string name="btwatchdog_summary">Switches off the phone\'s bluetooth for one second if no connection to the pump is possible. This may help on some phones where the bluetooth stack freezes.</string>
<string name="DexcomG5">DexcomG5 App (patched)</string>
<string name="dexcomg5_nsupload_title">Upload BG data to NS</string>
<string name="key_dexcomg5_nsupload">dexcomg5_nsupload</string>
<string name="key_dexcomg5_nsupload" translatable="false">dexcomg5_nsupload</string>
<string name="dexcomg5_upload">G5 upload settings</string>
<string name="customapp">Customized APK for download</string>
<string name="wear_detailed_delta_title">Show detailed delta</string>
@ -818,7 +818,7 @@
<string name="combo_pump_activity_label">Activity</string>
<string name="combo_no_pump_connection">No connection for %d min</string>
<string name="combo_tbr_remaining">%d%% (%d min remaining)</string>
<string name="combo_last_bolus">%.1f U (%s, %s)</string>
<string name="combo_last_bolus" translatable="false">%.1f U (%s, %s)</string>
<string name="combo_pump_action_initializing">Initializing</string>
<string name="combo_pump_state_disconnected">Disconnected</string>
<string name="combo_pump_state_suspended_due_to_error">Suspended due to error</string>
@ -852,7 +852,7 @@
<string name="combo_notification_check_time_date">Pump clock update needed</string>
<string name="combo_history">History</string>
<string name="combo_warning">Warning</string>
<string name="combo_read_full_history_warning">This will read the full history and state of the pump. Everything in \"My Data\" and the basal rate. Boluses and TBRs will be added to Treatments if they don\'t already exist. This can cause entries to be duplicated because the pump\'s time is imprecise. Using this when normally looping with the pump is highly discouraged and reserved for special circumstances. If you still want to do this, long press this button again.\n\nWARNING: this can trigger a bug which causes the pump to reject all connection attempts and requires pressing a button on the pump to recover and should therefore be avoided.</string>
<string name="combo_read_full_history_warning">This will read the full history and state of the pump. Everything in My Data and the basal rate. Boluses and TBRs will be added to Treatments if they don\'t already exist. This can cause entries to be duplicated because the pump\'s time is imprecise. Using this when normally looping with the pump is highly discouraged and reserved for special circumstances. If you still want to do this, long press this button again. WARNING: this can trigger a bug which causes the pump to reject all connection attempts and requires pressing a button on the pump to recover and should therefore be avoided.</string>
<string name="combo_read_full_history_confirmation">Are you really sure you want to read all pump data and take the consequences of this action?</string>
<string name="combo_pump_tbr_cancelled_warrning">TBR CANCELLED warning was confirmed</string>
<string name="combo_error_no_bolus_delivered">Bolus delivery failed. It appears no bolus was delivered. To be sure, please check the pump to avoid a double bolus and then bolus again. To guard against bugs, boluses are not automatically retried.</string>

View file

@ -10,12 +10,17 @@ buildscript {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0'
}
}
allprojects {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
}